\f
* Changes in Oort Gnus
+** gnus-agent
+
+The Gnus Agent is now enabled by default. This means that, e.g.,
+headers are not downloaded from agentized servers by default (agentize
+servers by using `J a' in the server buffer). Gnus will not start to
+download articles unless you instruct it to do so, though, by using
+e.g. J u or J s from the group buffer. Revert to the old behaviour
+with `(setq gnus-agent nil)'. Note that putting (gnus-agentize) in
+~/.gnus is not needed any more.
+
** gnus-summary-line-format
The default value changed to "%U%R%z%I%(%[%4L: %-23,23f%]%) %s\n".
("^han\\>" euc-kr) -> ("\\(^\\|:\\)han\\>" euc-kr)
-** Gnus supports PGP (RFC 1991/2440), PGP-MIME (RFC 2015/3156) and
-SMIME.
+** Gnus supports PGP (RFC 1991/2440), PGP/MIME (RFC 2015/3156) and
+S/MIME (RFC 2630-2633).
** Gnus inlines external parts (message/external).
+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.
--- /dev/null
+;;; hashcash.el --- Add hashcash payments to email
+
+;; $Revision: 1.1.1.1 $
+;; Copyright (C) 1997,2001 Paul E. Foley
+
+;; Maintainer: Paul Foley <mycroft@actrix.gen.nz>
+;; Keywords: mail, hashcash
+
+;; Released under the GNU General Public License
+
+;;; Commentary:
+
+;; The hashcash binary is at http://www.cypherspace.org/hashcash/
+;;
+;; Call mail-add-payment to add a hashcash payment to a mail message
+;; in the current buffer.
+;;
+;; To automatically add payments to all outgoing mail:
+;; (add-hook 'message-send-hook 'mail-add-payment)
+
+;;; Code:
+
+(defcustom hashcash-default-payment 0
+ "*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)
+
+(defcustom hashcash-payment-alist nil
+ "*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.")
+
+(defcustom hashcash "hashcash"
+ "*The path to the hashcash binary.")
+
+(require 'mail-utils)
+
+(defun hashcash-strip-quoted-names (addr)
+ (setq addr (mail-strip-quoted-names addr))
+ (if (and addr (string-match "^[^+@]+\\(\\+[^@]*\\)@" addr))
+ (concat (subseq addr 0 (match-beginning 1)) (subseq addr (match-end 1)))
+ addr))
+
+(defun hashcash-payment-required (addr)
+ "Return the hashcash payment value required for the given address."
+ (let ((val (assoc addr hashcash-payment-alist)))
+ (if val
+ (if (cddr val)
+ (caddr val)
+ (cadr 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)))
+ (if val
+ (if (cddr val)
+ (cadr val)
+ (car val))
+ addr)))
+
+(defun hashcash-generate-payment (str val)
+ "Generate a hashcash payment by finding a VAL-bit collison on STR."
+ (if (> val 0)
+ (save-excursion
+ (set-buffer (get-buffer-create " *hashcash*"))
+ (erase-buffer)
+ (call-process hashcash nil t nil (concat "-b " (number-to-string val))
+ str)
+ (goto-char (point-min))
+ (buffer-substring (point-at-bol) (point-at-eol)))
+ nil))
+
+(defun hashcash-insert-payment (arg)
+ "Insert an X-Hashcash header with a payment for ARG"
+ (interactive "sPay to: ")
+ (let ((pay (hashcash-generate-payment (hashcash-payment-to arg)
+ (hashcash-payment-required arg))))
+ (when pay
+ (insert-before-markers "X-Hashcash: " pay "\n"))))
+
+;;;###autoload
+(defun mail-add-payment (&optional arg)
+ "Add an X-Hashcash: header with a hashcash payment for each recipient address
+Prefix arg sets default payment temporarily."
+ (interactive "P")
+ (let ((hashcash-default-payment (if arg (prefix-numeric-value arg)
+ hashcash-default-payment))
+ (addrlist nil))
+ (save-excursion
+ (save-restriction
+ (goto-char (point-min))
+ (search-forward mail-header-separator)
+ (beginning-of-line)
+ (narrow-to-region (point-min) (point))
+ (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 ng
+ (setq addrlist (nconc addrlist (split-string ng ",[ \t\n]*")))))
+ (when addrlist
+ (mapc #'hashcash-insert-payment addrlist)))))
+ t)
+
+(provide 'hashcash)
+
+;;; hashcash.el ends here
+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 Simon Josefsson <jas@extundo.com>
+
+ * gnus-logic.el (gnus-advanced-integer): Swap arguments in
+ funcall. From Scott A Crosby <scrosby@cs.rice.edu>.
+
+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 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+ From 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 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+ From Nevin Kapur <nevin@jhu.edu>.
+
+ * nnmail.el (nnmail-fancy-expiry-target): Treat nonexisting
+ headers as empty headers.
+
+2002-07-21 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+ From Jochen Hein <jochen@jochen.org>.
+
+ * gnus-art.el (gnus-emphasis-alist): Add strikethrough and
+ correct typo.
+ (gnus-emphasis-strikethru): New face.
+
+2002-07-20 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+ From 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 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+ From Ted 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 Simon Josefsson <jas@extundo.com>
+
+ * nnimap.el (nnimap-split-to-groups): Allow group string to be a
+ function. From KANEMATSU Daiji <kdaiji@bea.com>.
+
+2002-07-09 Nevin Kapur <Nevin Kapur <nevin@jhu.edu>
+
+ * gnus-sum.el (gnus-summary-delete-article): Respect group
+ parameters while expiring.
+
+2002-07-08 Simon Josefsson <jas@extundo.com>
+
+ * gnus-art.el (article-make-date-line): Fix string. From Henrik
+ Enberg.
+
+2002-07-08 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-art.el (article-unsplit-urls): Only display MIME when this
+ function is called interactively. From Niklas Morberg.
+
+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 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-art.el (article-unsplit-urls): Keep URL buttonized after
+ unsplitting. From Niklas Morberg <niklas.morberg@axis.com>.
+
+2002-07-01 Kai Gro\e,b_\e(Bjohann <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 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * 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.
+ From Katsumi Yamaoka <yamaoka@jpl.org>.
+
+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\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * message.el (message-font-lock-keywords): Revert 2002-06-22
+ change.
+
+2002-06-24 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * message.el (message-font-lock-keywords): Put colon in header
+ name match.
+
+2002-06-22 Kai Gro\e,b_\e(Bjohann <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\e,b_\e(Bjohann <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 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-start.el (gnus-clear-system, gnus-read-newsrc-file): Make
+ sure to write byte-compiled versions of gnus-*-format-alist to
+ .newsrc.eld. From Simon Josefsson.
+
+2002-06-16 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * 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...)).
+ From Bj\e,Ax\e(Brn Mork <bmork@dod.no>.
+
+2002-06-16 Simon Josefsson <jas@extundo.com>
+
+ * gnus-cache.el (gnus-cache-remove-article): n is &optional. From
+ Reiner Steib <4uce.02.r.steib@gmx.net>.
+
+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.
+
+ * nnweb.el (nnweb-google-create-mapping): Honors the value of
+ nnweb-max-hits. From Niklas Morberg <niklas.morberg@axis.com>.
+
+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\e,b_\e(Bjohann <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\e,b_\e(Bjohann <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 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-msg.el (gnus-inews-yank-articles): Merge split header lines
+ so that code reading them won't be surprised. From Jesper Harder
+ <harder@ifa.au.dk>.
+
+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 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus-msg.el (gnus-inews-yank-articles): Unfold headers of
+ original article before yanking. From Jesper Harder
+ <harder@ifa.au.dk>.
+
+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 unecessary
+ 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 Simon Josefsson <jas@extundo.com>
+
+ * gnus-msg.el (gnus-confirm-mail-reply-to-news): Typo. Trivial
+ change from Benjamin Rutt <rutt+news@cis.ohio-state.edu>.
+
+ * nnweb.el (nnweb-type): Remove dejanewsold. Trivial change from
+ Niklas Morberg <niklas.morberg@axis.com>.
+
+2002-05-22 Simon Josefsson <jas@extundo.com>
+
+ * sieve.el (sieve-change-region): Define it before it is used.
+
+ * gnus-msg.el (gnus-confirm-mail-reply-to-news)
+ (gnus-summary-reply): Ask for confirmation when replying to news.
+ Defaults to not ask. From Benjamin Rutt
+ <rutt+news@cis.ohio-state.edu>.
+
+ * 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 <jbaker@cs.utah.edu>
+
+ * 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 Josh Huber <huber@alum.wpi.edu>
+
+ * mml.el (mml-generate-mime-1): Fix mml generation for signed only
+ messages. From Hans de Graaff <hans@degraaff.org>.
+ * 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 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+ From 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\e,b_\e(Bjohann <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 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * nnmail.el (nnmail-cache-insert): Prefer group-art over group
+ when intuiting the group the message is written to. From Josh
+ Huber <huber@alum.wpi.edu>.
+
+2002-05-06 Simon Josefsson <jas@extundo.com>
+
+ * gnus-topic.el (gnus-group-topic-parameters): Work when group
+ buffer doesn't show group. From Matt Armstrong <matt@lickey.com>.
+
+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 <>
+2002-05-01 Lars Magne Ingebrigtsen <larsi@gnus.org>
* lpath.el: Bind url-package-version.
Trivial change from Karl Pfl\e,Ad\e(Bsterer <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.
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 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2002-04-24 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
From Dan Christensen <jdc+news@uwo.ca>.
* nndoc.el (nndoc-type-alist, nndoc-lanl-gov-announce-type-p)
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
+ Make URL rephrasing regexp more flexible, to match current
format.
2002-04-23 Simon Josefsson <jas@extundo.com>
(gnus-netrc-get, gnus-netrc-machine, gnus-parse-netrc): Aliased to
new code in netrc.el.
-2002-04-23 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2002-04-23 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-msg.el (gnus-summary-resend-message-edit): Remove
message-ignored-resent-headers, too. From Matthieu Moy
* 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 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2002-04-17 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
From Ted Zlatanov <teodor.zlatanov@divine.com>.
* spam.el (spam-whitelist, spam-blacklist, spam-enter-whitelist):
* gnus.el (gnus-summary-line-format): Fixing links to Info.
Trivial change from Bj\e,Av\e(Brn Torkelsson <torkel@pdc.kth.se>.
-2002-03-29 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2002-03-29 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-sum.el (gnus-summary-move-article)
(gnus-summary-copy-article): Mention `gnus-move-split-methods' in
(nnmaildir--edit-prep): New function.
(Local Variables): Use it.
-2002-03-26 Pavel@Janik.cz (Pavel Jan\e,Bm\e(Bk)
+2002-03-26 Pavel@Janik.cz (Pavel Jan\e,Am\e(Bk)
* gnus-sum.el (gnus-summary-make-menu-bar): Fix typo.
tags.
* gnus-sum.el (gnus-print-buffer): Remove gnus-decoration.
- Trivial change from lorentey@elte.hu (L\e,Bu\e(Brentey K\e,Ba\e(Broly)
+ Trivial change from lorentey@elte.hu (L\e,Bu\e(Brentey K\e,Aa\e(Broly)
2002-03-20 Katsumi Yamaoka <yamaoka@jpl.org>
* gnus-group.el (gnus-group-process-prefix): Make sure there is a mark.
-2002-03-19 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2002-03-19 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-sum.el (gnus-sum-thread-tree-root)
(gnus-sum-thread-tree-single-indent)
2002-03-13 Simon Josefsson <jas@extundo.com>
* pop3.el (pop3-open-server): Revert multibyte change. From
- Pavel@Janik.cz (Pavel Jan\e,Bm\e(Bk).
+ Pavel@Janik.cz (Pavel Jan\e,Am\e(Bk).
* message.el (message-send-mail-with-qmail): Make it work. From
- Pavel@Janik.cz (Pavel Jan\e,Bm\e(Bk).
+ Pavel@Janik.cz (Pavel Jan\e,Am\e(Bk).
2002-03-13 Josh Huber <huber@alum.wpi.edu>
(gnus-article-reply-with-original): Ditto.
* binhex.el (binhex-decoder-switches): Fix doc. From
- Pavel@Janik.cz (Pavel Jan\e,Bm\e(Bk).
+ Pavel@Janik.cz (Pavel Jan\e,Am\e(Bk).
2002-02-04 ShengHuo ZHU <zsh@cs.rochester.edu>
* flow-fill.el (fill-flowed-display-column)
(fill-flowed-encode-columnq): New variables. Suggested by
- Kai.Grossjohann@CS.Uni-Dortmund.DE (Kai Gro\e,A_\e(Bjohann).
+ Kai.Grossjohann@CS.Uni-Dortmund.DE (Kai Gro\e,b_\e(Bjohann).
(fill-flowed-encode, fill-flowed): Use them.
* message.el (message-send-news, message-send-mail): Use
* gnus-agent.el (gnus-agent-fetch-session): Run hook.
-2002-01-03 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2002-01-03 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-start.el (gnus-read-init-file): Don't force coding system
for ~/.gnus. From Dave Love <fx@gnu.org>.
(gnus-picon-transform-address): Insert spec backward, due to the
incompatibility of gnus-xmas-put-image.
-2002-01-02 Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+2002-01-02 Pavel Jan\e,Am\e(Bk <Pavel@Janik.cz>
* gnus-fun.el (gnus-convert-pbm-to-x-face-command): Doc fix.
* gnus-art.el, gnus-picon.el, gnus-sieve.el, gnus-sum.el:
* gnus-xmas.el, imap.el, mailcap.el, mm-util.el, nnfolder.el:
* nnheader.el, nnmail.el: Nil/NIL vs. nil.
- From Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+ From Pavel Jan\e,Am\e(Bk <Pavel@Janik.cz>
2001-12-20 15:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
* mm-url.el (executable-find): autoload.
-2001-12-12 Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+2001-12-12 Pavel Jan\e,Am\e(Bk <Pavel@Janik.cz>
* gnus-mlspl.el (gnus-group-split-fancy): Doc fix (add reference
to variable, follow doc-string conventions).
* message.el (message-tab-body-function): Set to nil.
(message-tab): Use text-mode-map or global-map.
- Suggested by Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>.
+ Suggested by Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>.
2001-11-30 Simon Josefsson <jas@extundo.com>
* gnus-agent.el (gnus-agent-write-active): Make sure sym is a cons
of integers.
-2001-11-29 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-11-29 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* message.el (message-newgroups-header-regexp)
(message-completion-alist, message-tab-body-function): Use
(gnus-summary-limit-to-extra): Ditto.
(gnus-summary-find-matching): Support not-matching argument.
-2001-11-25 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-11-25 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* message.el (message-wash-subject): Use `insert' rather than
`insert-string', which is deprecated.
2001-11-09 Simon Josefsson <jas@extundo.com>
- * gnus.el (gnus-local-domain): Fix doc. From Pavel Jan\e,Bm\e(Bk
+ * gnus.el (gnus-local-domain): Fix doc. From Pavel Jan\e,Am\e(Bk
<Pavel@Janik.cz>.
-2001-11-09 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-11-09 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* message.el (message-point-in-header-p): New function.
(message-do-auto-fill): Use it.
(nnweb-type-definition): Add google as alias of dejanews.
(nnweb-google-parse-1): Forward 1 line.
-2001-10-26 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-10-26 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-msg.el (gnus-summary-mail-forward): Doc fix: add pointer to
variable `message-forward-ignored-headers'.
* gnus-msg.el (gnus-extended-version): Include
system-configuration.
- Suggested by Kai.Grossjohann@CS.Uni-Dortmund.DE (Kai Gro\e,A_\e(Bjohann).
+ Suggested by Kai.Grossjohann@CS.Uni-Dortmund.DE (Kai Gro\e,b_\e(Bjohann).
2001-10-22 Per Abrahamsen <abraham@dina.kvl.dk>
(nnimap-split-inbox, nnimap-expunge-search-string)
(nnimap-importantize-dormant): Remove "*" from doc.
-2001-10-20 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-10-20 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-sum.el (gnus-summary-limit-to-score): Prompt for score if
not supplied via prefix arg. From Lisp, make arg mandatory.
* message.el (message-do-auto-fill): Avoid calling
'rfc822-goto-eoh'.
-2001-10-20 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-10-20 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
From Paul Jarc <prj@po.cwru.edu>.
* message.el (message-get-reply-headers): Restructure the logic
* gnus-msg.el (gnus-post-method): Changed two instances of
`active' to `current' and one `null' to `not'.
-2001-10-16 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-10-16 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
From Katsumi Yamaoka <yamaoka@jpl.org>.
* message.el (message-setup-fill-variables): Use
(mml2015-gpg-decrypt-1): Decanonicalize decrypted MIME
body. (Mailcrypt seem to do this, but gpg.el doesn't.)
-2001-10-16 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-10-16 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
Patch by Oliver Scholz <oscholz@my.gnus.org>.
* gnus-draft.el (gnus-draft-edit-message): Add text property
* message.el (message-do-auto-fill): Use gnus-point-at-bol.
(autoload): Add some autoloads.
-2001-10-12 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-10-12 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
Suggested by Oliver Scholz <epameinondas@gmx.de>.
* message.el (message-do-auto-fill): New function. Like
* gnus-sum.el (gnus-summary-extract-address-component): New function.
(gnus-summary-from-or-to-or-newsgroups): Optimize.
-2001-09-29 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-09-29 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* message.el (message-mode-map): Keybinding for `gnus-delay-article'.
(message-mode-menu): Menu item for same.
* gnus-group.el (gnus-group-catchup): Update expire marks in
backend. Also, if ALL also set expire marks on tick/dormant.
-2001-09-20 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-09-20 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* message.el (message-tab-body-function): New variable.
* message.el (message-tab): Use it.
* gnus-draft.el (gnus-draft-setup): Don't set mark when there
isn't an article to set it on (e.g. when you `a' in a group).
-2001-09-12 Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+2001-09-12 Pavel Jan\e,Am\e(Bk <Pavel@Janik.cz>
* mm-util.el (mm-charset-synonym-alist): add windows-1250 so we
can read e-mails from Microsoft Outlook users not using ISO
* gnus-sum.el (gnus-summary-insert-line): Insert forwarded, recent
and unseen marks.
-2001-09-05 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-09-05 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* nnmail.el (nnmail-split-fancy): Document `junk'.
* gnus-spec.el (gnus-correct-substring): Stopped one character
before we wanted.
-2001-08-19 Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+2001-08-19 Pavel Jan\e,Am\e(Bk <Pavel@Janik.cz>
* earcon.el (earcon-auto-play): Remove unused option.
* gnus-srvr.el (gnus-server-browse-in-group-buffer): Default to
nil.
-2001-08-15 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-08-15 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-delay.el (gnus-delay-article): Allow "01:23" time spec,
which specifies a time today or tomorrow.
2001-08-15 Simon Josefsson <jas@extundo.com>
- From Pavel@Janik.cz (Pavel Jan\e,Bm\e(Bk)
+ From Pavel@Janik.cz (Pavel Jan\e,Am\e(Bk)
* gnus-agent.el (gnus-agent-make-mode-line-string)
(gnus-agent-toggle-plugged): Use new API.
-2001-08-14 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-08-14 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-delay.el (gnus-delay-send-drafts): Fix check whether
deadline has expired.
* gnus-spec.el (gnus-format-specs): %n is 23 chars.
2001-08-11 09:40:00 Karl Kleinpaste <karl@charcoal.com>
- Committed by Kai Gro\e,A_\e(Bjohann.
+ Committed by Kai Gro\e,b_\e(Bjohann.
* gnus-score.el (gnus-score-string): Fix `match' regexp
for `extra' header case.
(nndoc-oe-dbx-dissection): New function.
(nndoc-oe-dbx-generate-article): New function.
-2001-08-11 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-08-11 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-delay.el (gnus-delay-send-drafts): Cleaner way to check
whether deadline has been reached. Patch from Dan Nicolaescu
before remove.
(gnus-mime-security-show-details): Ditto.
-2001-08-04 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-08-04 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* nnmail.el (nnmail-split-fancy-with-parent): Correct `mapconcat'
syntax. Protect string-match against nil string and regexp.
* gnus-msg.el (gnus-post-method): Refer to `gnus-parameters'.
2001-07-31 17:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
- Originally from Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+ Originally from Pavel Jan\e,Am\e(Bk <Pavel@Janik.cz>
* gnus-agent.el (gnus-agent-make-mode-line-string): New function.
(gnus-agent-toggle-plugged): Use it.
(gnus-read-newsrc-el-file, gnus-save-newsrc-file)
(gnus-slave-save-newsrc): Use it.
-2001-07-31 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-07-31 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-delay.el (gnus-delay-initialize): Use standard define-key
syntax.
calls widen. Thanks to Christoph Conrad
<christoph.conrad@gmx.de>.
-2001-07-29 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-07-29 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus.el (gnus-summary-line-format): Mention `gnus-sum-thread-*'
for %B spec.
* nnheader.el (nnheader-translate-file-chars): cygwin32 is running
in M$Windows too.
-2001-07-26 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-07-26 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-delay.el (gnus-delay-send-drafts): Don't `error'.
* mm-decode.el (mm-remove-part): Don't murder the current window (nil).
(mm-display-external): Use display-term configure.
-2001-07-24 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-07-24 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-delay.el (gnus-delay-default-hour): New variable.
(gnus-delay-article): Allow specific date in YYYY-MM-DD format.
`gnus-check-bogus-newsgroups' just after the native server is
opened.
-2001-07-23 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-07-23 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* nnmail.el (nnmail-do-request-post): Util function to be used by
`nnchoke-request-post' for all nnmail-derived backends.
* gnus-msg.el (gnus-setup-message): make-local-hook.
-2001-07-22 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-07-22 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-delay.el (gnus-delay-article): Fix `read-string' for
XEmacs. Allow more units. Submitted by Karl Kleinpaste
whether the groups exist, check the right server based on
`gnus-post-method'.
-2001-07-21 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-07-21 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-delay.el: New file.
(article-de-base64-unreadable, article-wash-html):
(gnus-mime-inline-part, gnus-mime-view-part-as-charset): Ditto.
-2001-07-21 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-07-21 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* nnml.el (nnml-request-post): New function. Can be used for
annotations in nnml groups.
* gnus-art.el (gnus-article-edit-mode): Use define-derived-mode.
-2001-07-16 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-07-16 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* message.el (message-citation-line-function): Refer to
gnus-cite-attribution-suffix.
-2001-07-15 Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+2001-07-15 Pavel Jan\e,Am\e(Bk <Pavel@Janik.cz>
* gnus-art.el,...: Error convention changes.
* gnus-setup.el (gnus-use-installed-gnus): Typo.
* Cleanup files.
- From Pavel@Janik.cz (Pavel Jan\e,Bm\e(Bk).
+ From Pavel@Janik.cz (Pavel Jan\e,Am\e(Bk).
2001-07-13 08:00:00 ShengHuo ZHU <zsh@cs.rochester.edu>
* gnus-draft.el (gnus-draft-edit-message): Remove Date here.
(gnus-draft-setup): Remove backlog.
-2001-07-10 Pavel Jan\e,Bm\e(Bk <Pavel@Janik.cz>
+2001-07-10 Pavel Jan\e,Am\e(Bk <Pavel@Janik.cz>
* gnus-logic.el, gnus-srvr.el, gnus-vm.el, nnheaderxm.el, nnoo.el:
Cleanup.
* gnus-sum.el (gnus-summary-catchup): New argument.
(gnus-summary-catchup-from-here): New function.
-2001-05-30 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-05-30 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* mm-view.el (mm-inline-image-xemacs): Insert newline, then move
back, then insert glyph. (Before, the glyph was inserted first,
it is not possible to insert a character after a glyph which is at
the end of a buffer. Patch by Lloyd Zusman <ljz@asfast.com>.
-2001-05-28 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-05-28 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
From Jaap-Henk Hoepman (jhh@xs4all.nl).
mm-destroy-postponed-undisplay-list): New functions.
(mm-display-external): Use them.
-2001-05-27 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-05-27 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-salt.el (gnus-tree-highlight-node): Bind `default-high' and
`default-low' when evaluating `gnus-summary-highlight'.
as details.
(mml2015-mailcrypt-clear-verify): Ditto.
-2001-05-24 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-05-24 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
From Nevin Kapur <nevin@jhu.edu>.
* gnus-sum.el (gnus-summary-default-high-score,
matching subjects.
(gnus-offer-save-summaries): Clean up.
-2001-04-13 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-04-13 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* nnmail.el (nnmail-split-fancy-with-parent): Add docstring.
supported. Suggest by Jim Meyering <jim@meyering.net>.
2001-04-02 Nevin Kapur <nevin@jhu.edu>
- Committed by Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>.
+ Committed by Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>.
* nnmail.el (nnmail-split-it): Added check for .* at the end of
regexp in nnmail-split-fancy.
`nnimap-use-nov-p' (it really tested the negative).
(nnimap-retrieve-headers): Use it.
-2001-03-11 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-03-11 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* message.el (message-generate-headers-first): Update doc.
* gnus-draft.el (gnus-draft-reminder): "Confirm to exit?"
-2001-02-19 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-02-19 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-sum.el (gnus-thread-sort-functions): Doc fix. Refer to
gnus-article-sort-functions.
(gnus-subscribe-hierarchically): Return gnus-subscribe-newsgroup's
return .
-2001-02-12 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-02-12 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-cus.el (gnus-score-customize): Doc fix.
* gnus-uu.el (gnus-uu-grab-articles): Shoot down original article
buffer.
-2001-02-07 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2001-02-07 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* message.el (message-generate-headers-first): Doc fix.
* message.el (message-forward): Save-restriction.
-2000-12-21 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2000-12-21 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-art.el (article-treat-dumbquotes): More doc, provided by
Paul Stevenson <p.stevenson@surrey.ac.uk>
* message.el (message-font-lock-keywords): use
message-cite-prefix-regexp.
-2000-11-15 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2000-11-15 Kai Gro\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
* gnus-group.el (gnus-group-jump-to-group-prompt): New variable by
Stein Arild Str\e,Ax\e(Bmme.
* gnus-art.el (gnus-mime-display-alternative): Show button if no
preferred part.
-2000-11-07 Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+2000-11-07 Kai Gro\e,b_\e(Bjohann <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
;(push "/usr/share/emacs/site-lisp" load-path)
(unless (featurep 'xemacs)
- (define-compiler-macro last (&whole form x &optional n)
- (if (and (fboundp 'last)
- (subrp (symbol-function 'last)))
- form
- (if n
- `(let* ((x ,x)
- (n ,n)
- (m 0)
- (p x))
- (while (consp p)
- (incf m)
- (pop p))
- (if (<= n 0)
- p
- (if (< n m)
- (nthcdr (- m n) x)
- x)))
- `(let ((x ,x))
- (while (consp (cdr x))
- (pop x))
- x))))
-
- (define-compiler-macro coerce (&whole form x type)
- (if (and (fboundp 'coerce)
- (subrp (symbol-function 'coerce)))
- form
- `(let ((x ,x)
- (type ,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)
- (= (length (symbol-name x)) 1))
- (aref (symbol-name x) 0))
- ((eq type 'float) (float x))
- ((typep x type) x)
- (t (error "Can't coerce %s to type %s" x type))))))
-
(define-compiler-macro merge (&whole form type seq1 seq2 pred &rest keys)
(if (and (fboundp 'merge)
(subrp (symbol-function 'merge)))
(push (pop seq1) res)))
(coerce (nconc (nreverse res) seq1 seq2) type)))))
- (define-compiler-macro subseq (&whole form seq start &optional end)
- (if (and (fboundp 'subseq)
- (subrp (symbol-function 'subseq)))
- form
- (if end
- `(let ((seq ,seq)
- (start ,start)
- (end ,end))
- (if (stringp seq)
- (substring seq start end)
- (let (len)
- (if (< end 0)
- (setq end (+ end (setq len (length seq)))))
- (if (< start 0)
- (setq start (+ start (or len (setq len (length seq))))))
- (cond ((listp seq)
- (if (> start 0)
- (setq seq (nthcdr start seq)))
- (let ((res nil))
- (while (>= (setq end (1- end)) start)
- (push (pop seq) res))
- (nreverse res)))
- (t
- (let ((res (make-vector (max (- end start) 0) nil))
- (i 0))
- (while (< start end)
- (aset res i (aref seq start))
- (setq i (1+ i)
- start (1+ start)))
- res))))))
- `(let ((seq ,seq)
- (start ,start))
- (if (stringp seq)
- (substring seq start)
- (let (len)
- (if (< start 0)
- (setq start (+ start (or len (setq len (length seq))))))
- (cond ((listp seq)
- (if (> start 0)
- (setq seq (nthcdr start seq)))
- (copy-sequence seq))
- (t
- (let* ((end (or len (length seq)))
- (res (make-vector (max (- end start) 0) nil))
- (i 0))
- (while (< start end)
- (aset res i (aref seq start))
- (setq i (1+ i)
- start (1+ start)))
- res)))))))))
-
(define-compiler-macro copy-list (&whole form list)
(if (and (fboundp 'copy-list)
(subrp (symbol-function 'copy-list)))
(while (consp list) (push (pop list) res))
(prog1 (nreverse res) (setcdr res list)))
(car list)))))
- )
+
+ (define-compiler-macro remove (&whole form item seq)
+ (if (>= emacs-major-version 21)
+ form
+ `(delete ,item (copy-sequence ,seq)))))
;; If we are building w3 in a different directory than the source
;; directory, we must read *.el from source directory and write *.elc
(backward-delete-char -1)
(end-of-line))
(unless sig
- (let ((fill-prefix (when quote (concat quote " ")))
- (fill-column (eval fill-flowed-display-column)))
- (fill-region (fill-flowed-point-at-bol)
- (min (1+ (fill-flowed-point-at-eol)) (point-max))
- 'left 'nosqueeze))))))))
+ (condition-case nil
+ (let ((fill-prefix (when quote (concat quote " ")))
+ (fill-column (eval fill-flowed-display-column))
+ filladapt-mode)
+ (fill-region (fill-flowed-point-at-bol)
+ (min (1+ (fill-flowed-point-at-eol)) (point-max))
+ 'left 'nosqueeze))
+ (error nil))))))))
(provide 'flow-fill)
(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"))))
+ (mapcar (lambda (m)
+ (gnus-server-get-method
+ nil
+ (or m "native")))
+ (gnus-agent-read-file
+ (nnheader-concat gnus-agent-directory "lib/servers")))))
(defun gnus-agent-write-servers ()
"Write the alist of covered servers."
(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)))))
+ (prin1 (mapcar 'gnus-method-simplify gnus-agent-covered-methods)
+ (current-buffer)))))
;;;
;;; Summary commands
(or (gnus-gethash group gnus-category-group-cache)
(assq 'default gnus-category-alist)))
-(defun gnus-agent-expire ()
- "Expire all old articles."
+(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. Setting ARTICLES
+and GROUP without FORCE is not supported."
(interactive)
- (let ((methods gnus-agent-covered-methods)
+ (let ((methods (if group
+ (list (gnus-find-method-for-group group))
+ gnus-agent-covered-methods))
(day (if (numberp gnus-agent-expire-days)
(- (time-to-days (current-time)) gnus-agent-expire-days)
nil))
(current-day (time-to-days (current-time)))
- gnus-command-method sym group articles
+ gnus-command-method sym arts pos
history overview file histories elem art nov-file low info
unreads marked article orig lowest highest found days)
(save-excursion
(setq gnus-agent-current-history
(setq history (gnus-agent-history-buffer))))
(goto-char (point-min))
- (when (> (buffer-size) 1)
- (goto-char (point-min))
- (while (not (eobp))
- (skip-chars-forward "^\t")
- (if (let ((fetch-date (read (current-buffer))))
- (if (numberp fetch-date)
- ;; We now have the arrival day, so we see
- ;; whether it's old enough to be expired.
- (if (numberp day)
- (> fetch-date day)
- (skip-chars-forward "\t")
- (setq found nil
- days gnus-agent-expire-days)
- (while (and (not found)
- days)
- (when (looking-at (caar days))
- (setq found (cadar days)))
- (pop days))
- (> fetch-date (- current-day found)))
- ;; History file is corrupted.
- (gnus-message
- 5
- (format "File %s is corrupted!"
- (gnus-agent-lib-file "history")))
- (sit-for 1)
- ;; Ignore it
- t))
- ;; New article; we don't expire it.
- (forward-line 1)
- ;; Old article. Schedule it for possible nuking.
- (while (not (eolp))
- (setq sym (let ((obarray expiry-hashtb) s)
- (setq s (read (current-buffer)))
- (if (stringp s) (intern s) s)))
- (if (boundp sym)
- (set sym (cons (cons (read (current-buffer)) (point))
- (symbol-value sym)))
- (set sym (list (cons (read (current-buffer)) (point)))))
- (skip-chars-forward " "))
- (forward-line 1)))
- ;; We now have all articles that can possibly be expired.
- (mapatoms
- (lambda (sym)
- (setq group (symbol-name sym)
- articles (sort (symbol-value sym) 'car-less-than-car)
- low (car (gnus-active group))
- info (gnus-get-info group)
- unreads (ignore-errors
- (gnus-list-of-unread-articles group))
- marked (nconc
- (gnus-uncompress-range
- (cdr (assq 'tick (gnus-info-marks info))))
- (gnus-uncompress-range
- (cdr (assq 'dormant
- (gnus-info-marks info)))))
- nov-file (gnus-agent-article-name ".overview" group)
- lowest nil
- highest nil)
- (gnus-agent-load-alist group)
- (gnus-message 5 "Expiring articles in %s" group)
- (set-buffer overview)
- (erase-buffer)
- (when (file-exists-p nov-file)
- (nnheader-insert-file-contents nov-file))
- (goto-char (point-min))
- (setq article 0)
- (while (setq elem (pop articles))
- (setq article (car elem))
- (when (or (null low)
- (< article low)
- gnus-agent-expire-all
- (and (not (memq article unreads))
- (not (memq article marked))))
- ;; Find and nuke the NOV line.
- (while (and (not (eobp))
- (or (not (numberp
- (setq art (read (current-buffer)))))
- (< art article)))
- (if (and (numberp art)
- (file-exists-p
- (gnus-agent-article-name
- (number-to-string art) group)))
- (progn
- (unless lowest
- (setq lowest art))
- (setq highest art)
- (forward-line 1))
- ;; Remove old NOV lines that have no articles.
- (gnus-delete-line)))
- (if (or (eobp)
- (/= art article))
- (beginning-of-line)
- (gnus-delete-line))
- ;; Nuke the article.
- (when (file-exists-p
- (setq file (gnus-agent-article-name
- (number-to-string article)
- group)))
- (delete-file file))
- ;; Schedule the history line for nuking.
- (push (cdr elem) histories)))
- (gnus-make-directory (file-name-directory nov-file))
- (let ((coding-system-for-write
- gnus-agent-file-coding-system))
- (write-region (point-min) (point-max) nov-file nil 'silent))
- ;; Delete the unwanted entries in the alist.
- (setq gnus-agent-article-alist
- (sort gnus-agent-article-alist 'car-less-than-car))
- (let* ((alist gnus-agent-article-alist)
- (prev (cons nil alist))
- (first prev)
- expired)
- (while (and alist
- (<= (caar alist) article))
- (if (or (not (cdar alist))
- (not (file-exists-p
- (gnus-agent-article-name
- (number-to-string
- (caar alist))
- group))))
+ (if (and articles group force) ;; point usless without art+group
+ (while (setq article (pop articles))
+ ;; try to find history entries for articles
+ (goto-char (point-min))
+ (if (re-search-forward
+ (concat "^[^\t]*\t[^\t]*\t\(.* ?\)"
+ (format "%S" (gnus-group-prefixed-name
+ group gnus-command-method))
+ " "
+ (number-to-string article)
+ " $")
+ nil t)
+ (setq pos (point))
+ (setq pos nil))
+ (setq sym (let ((obarray expiry-hashtb) s)
+ (intern group)))
+ (if (boundp sym)
+ (set sym (cons (cons article pos)
+ (symbol-value sym)))
+ (set sym (list (cons article pos)))))
+ ;; go through history file to find eligble articles
+ (when (> (buffer-size) 1)
+ (goto-char (point-min))
+ (while (not (eobp))
+ (skip-chars-forward "^\t")
+ (if (let ((fetch-date (read (current-buffer))))
+ (if (numberp fetch-date)
+ ;; We now have the arrival day, so we see
+ ;; whether it's old enough to be expired.
+ (if (numberp day)
+ (> fetch-date day)
+ (skip-chars-forward "\t")
+ (setq found nil
+ days gnus-agent-expire-days)
+ (while (and (not found)
+ days)
+ (when (looking-at (caar days))
+ (setq found (cadar days)))
+ (pop days))
+ (> fetch-date (- current-day found)))
+ ;; History file is corrupted.
+ (gnus-message
+ 5
+ (format "File %s is corrupted!"
+ (gnus-agent-lib-file "history")))
+ (sit-for 1)
+ ;; Ignore it
+ t))
+ ;; New article; we don't expire it.
+ (forward-line 1)
+ ;; Old article. Schedule it for possible nuking.
+ (while (not (eolp))
+ (setq sym (let ((obarray expiry-hashtb) s)
+ (setq s (read (current-buffer)))
+ (if (stringp s) (intern s) s)))
+ (if (boundp sym)
+ (set sym (cons (cons (read (current-buffer)) (point))
+ (symbol-value sym)))
+ (set sym (list (cons (read (current-buffer))
+ (point)))))
+ (skip-chars-forward " "))
+ (forward-line 1)))))
+ ;; We now have all articles that can possibly be expired.
+ (mapatoms
+ (lambda (sym)
+ (setq group (symbol-name sym)
+ arts (sort (symbol-value sym) 'car-less-than-car)
+ low (car (gnus-active group))
+ info (gnus-get-info group)
+ unreads (ignore-errors
+ (gnus-list-of-unread-articles group))
+ marked (nconc
+ (gnus-uncompress-range
+ (cdr (assq 'tick (gnus-info-marks info))))
+ (gnus-uncompress-range
+ (cdr (assq 'dormant
+ (gnus-info-marks info)))))
+ nov-file (gnus-agent-article-name ".overview" group)
+ lowest nil
+ highest nil)
+ (gnus-agent-load-alist group)
+ (gnus-message 5 "Expiring articles in %s" group)
+ (set-buffer overview)
+ (erase-buffer)
+ (when (file-exists-p nov-file)
+ (nnheader-insert-file-contents nov-file))
+ (goto-char (point-min))
+ (setq article 0)
+ (while (setq elem (pop arts))
+ (setq article (car elem))
+ (when (or (null low)
+ (< article low)
+ gnus-agent-expire-all
+ (and (not (memq article unreads))
+ (not (memq article marked)))
+ force)
+ ;; Find and nuke the NOV line.
+ (while (and (not (eobp))
+ (or (not (numberp
+ (setq art (read (current-buffer)))))
+ (< art article)))
+ (if (and (numberp art)
+ (file-exists-p
+ (gnus-agent-article-name
+ (number-to-string art) group)))
(progn
- (push (caar alist) expired)
- (setcdr prev (setq alist (cdr alist))))
- (setq prev alist
- alist (cdr alist))))
- (setq gnus-agent-article-alist (cdr first))
- (gnus-agent-save-alist group)
- ;; Mark all articles up to the first article
- ;; in `gnus-article-alist' as read.
- (when (and info (caar gnus-agent-article-alist))
- (setcar (nthcdr 2 info)
- (gnus-range-add
- (nth 2 info)
- (cons 1 (- (caar gnus-agent-article-alist) 1)))))
- ;; Maybe everything has been expired from
- ;; `gnus-article-alist' and so the above marking as
- ;; read could not be conducted, or there are
- ;; expired article within the range of the alist.
- (when (and info
- expired
- (or (not (caar gnus-agent-article-alist))
- (> (car expired)
- (caar gnus-agent-article-alist))))
- (setcar (nthcdr 2 info)
- (gnus-add-to-range
- (nth 2 info)
- (nreverse expired))))
- (gnus-dribble-enter
- (concat "(gnus-group-set-info '"
- (gnus-prin1-to-string info)
- ")")))
- (when lowest
- (if (gnus-gethash group orig)
- (setcar (gnus-gethash group orig) lowest)
- (gnus-sethash group (cons lowest highest) orig))))
- expiry-hashtb)
- (set-buffer history)
- (setq histories (nreverse (sort histories '<)))
- (while histories
- (goto-char (pop histories))
- (gnus-delete-line))
- (gnus-agent-save-history)
- (gnus-agent-close-history)
- (gnus-write-active-file
- (gnus-agent-lib-file "active") orig))
- (gnus-message 4 "Expiry...done")))))))
+ (unless lowest
+ (setq lowest art))
+ (setq highest art)
+ (forward-line 1))
+ ;; Remove old NOV lines that have no articles.
+ (gnus-delete-line)))
+ (if (or (eobp)
+ (/= art article))
+ (beginning-of-line)
+ (gnus-delete-line))
+ ;; Nuke the article.
+ (when (file-exists-p
+ (setq file (gnus-agent-article-name
+ (number-to-string article)
+ group)))
+ (delete-file file))
+ ;; Schedule the history line for nuking.
+ (if (cdr elem)
+ (push (cdr elem) histories))))
+ (gnus-make-directory (file-name-directory nov-file))
+ (let ((coding-system-for-write
+ gnus-agent-file-coding-system))
+ (write-region (point-min) (point-max) nov-file nil 'silent))
+ ;; Delete the unwanted entries in the alist.
+ (setq gnus-agent-article-alist
+ (sort gnus-agent-article-alist 'car-less-than-car))
+ (let* ((alist gnus-agent-article-alist)
+ (prev (cons nil alist))
+ (first prev)
+ expired)
+ (while (and alist
+ (<= (caar alist) article))
+ (if (or (not (cdar alist))
+ (not (file-exists-p
+ (gnus-agent-article-name
+ (number-to-string
+ (caar alist))
+ group))))
+ (progn
+ (push (caar alist) expired)
+ (setcdr prev (setq alist (cdr alist))))
+ (setq prev alist
+ alist (cdr alist))))
+ (setq gnus-agent-article-alist (cdr first))
+ (gnus-agent-save-alist group)
+ ;; Mark all articles up to the first article
+ ;; in `gnus-agent-article-alist' as read.
+ (when (and info (caar gnus-agent-article-alist))
+ (setcar (nthcdr 2 info)
+ (gnus-range-add
+ (nth 2 info)
+ (cons 1 (- (caar gnus-agent-article-alist) 1)))))
+ ;; Maybe everything has been expired from
+ ;; `gnus-agent-article-alist' and so the above marking as
+ ;; read could not be conducted, or there are
+ ;; expired article within the range of the alist.
+ (when (and info
+ expired
+ (or (not (caar gnus-agent-article-alist))
+ (> (car expired)
+ (caar gnus-agent-article-alist))))
+ (setcar (nthcdr 2 info)
+ (gnus-add-to-range
+ (nth 2 info)
+ (nreverse expired))))
+ (gnus-dribble-enter
+ (concat "(gnus-group-set-info '"
+ (gnus-prin1-to-string info)
+ ")")))
+ (when lowest
+ (if (gnus-gethash group orig)
+ (setcar (gnus-gethash group orig) lowest)
+ (gnus-sethash group (cons lowest highest) orig))))
+ expiry-hashtb)
+ (set-buffer history)
+ (setq histories (nreverse (sort histories '<)))
+ (while histories
+ (goto-char (pop histories))
+ (gnus-delete-line))
+ (gnus-agent-save-history)
+ (gnus-agent-close-history)
+ (gnus-write-active-file
+ (gnus-agent-lib-file "active") orig))
+ (gnus-message 4 "Expiry...done"))))))
;;;###autoload
(defun gnus-agent-batch ()
'(("\\*" "\\*" bold)
("_" "_" underline)
("/" "/" italic)
+ ("-" "-" strikethru)
("_/" "/_" underline-italic)
("_\\*" "\\*_" underline-bold)
("\\*/" "/\\*" bold-italic)
(defface gnus-emphasis-underline-bold-italic
'((t (:bold t :italic t :underline t)))
"Face used for displaying underlined bold italic emphasized text.
-Esample: (_/*word*/_)."
+Example: (_/*word*/_)."
+ :group 'gnus-article-emphasis)
+
+(defface gnus-emphasis-strikethru '((t (:strikethru t)))
+ "Face used for displaying strike-through text (-word-)."
:group 'gnus-article-emphasis)
(defface gnus-emphasis-highlight-words
(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)
+ (modify-syntax-entry ?> ")<" table)
+ (modify-syntax-entry ?< "(>" table)
table)
"Syntax table used in article mode buffers.
Initialized from `text-mode-syntax-table.")
(goto-char (point-min))
(while (re-search-forward
"^\\(\\(https?\\|ftp\\)://\\S-+\\) *\n\\(\\S-+\\)" nil t)
- (replace-match "\\1\\3" t)))))
+ (replace-match "\\1\\3" t)))
+ (when (and gnus-display-mime-function (interactive-p))
+ (funcall gnus-display-mime-function))))
+
(defun article-wash-html (&optional read-charset)
"Format an html article.
":"
(format "%02d" (nth 1 dtime)))))))
(error
- (format "Date: %s (from Oort)" date))))
+ (format "Date: %s (from Gnus)" date))))
(defun article-date-local (&optional highlight)
"Convert the current article date to the local timezone."
(let ((gnus-override-method gnus-override-method)
(methods (and (stringp article)
gnus-refer-article-method))
+ (backend (car (gnus-find-method-for-group
+ gnus-newsgroup-name)))
result
(buffer-read-only nil))
(if (or (not (listp methods))
(gnus-kill-all-overlays)
(let ((gnus-newsgroup-name group))
(gnus-check-group-server))
- (when (gnus-request-article article group (current-buffer))
+ (cond
+ ((gnus-request-article article group (current-buffer))
(when (numberp article)
(gnus-async-prefetch-next group article
gnus-summary-buffer)
(gnus-backlog-enter-article
group article (current-buffer))))
(setq result 'article))
- (if (not result)
- (if methods
- (setq gnus-override-method (pop methods))
- (setq result 'done))))
+ (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)))
(gnus-summary-position-point)
(nreverse out)))
-(defun gnus-cache-remove-article (n)
+(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."
;;; gnus-cite.el --- parse citations in articles for Gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
;; Free Software Foundation, Inc.
;; Author: Per Abhiddenware
: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)
+
;;; Internal Variables:
(defvar gnus-cite-article nil)
end (set-marker (make-marker) end))
(gnus-add-text-properties-when 'article-type nil beg end props)
(goto-char beg)
- (unless (save-excursion (search-backward "\n\n" nil t))
+ (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))
(interactive)
(save-excursion
(let* ((group (format "nndraft:%s" gnus-delay-group))
+ (message-send-hook (copy-sequence message-send-hook))
articles
article deadline)
(when (gnus-gethash group gnus-newsrc-hashtb)
(gnus-activate-group group)
+ (add-hook 'message-send-hook
+ '(lambda ()
+ (message-remove-header gnus-delay-header)))
(setq articles (nndraft-articles))
(while (setq article (pop articles))
(gnus-request-head article group)
(defvar gnus-mouse-face-prop 'mouse-face
"Property used for highlighting mouse regions.")))
-(eval-and-compile
- (let ((case-fold-search t))
- (cond
- ((string-match "windows-nt\\|os/2\\|emx\\|cygwin32"
- (symbol-name system-type))
- (setq nnheader-file-name-translation-alist
- (append nnheader-file-name-translation-alist
- (mapcar (lambda (c) (cons c ?_))
- '(?: ?* ?\" ?< ?> ??))
- (if (string-match "windows-nt\\|cygwin32"
- (symbol-name system-type))
- nil
- '((?+ . ?-)))))))))
-
(defvar gnus-tmp-unread)
(defvar gnus-tmp-replied)
(defvar gnus-tmp-score-char)
%E Icon as defined by `gnus-group-icon-list'.
%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 buffer just like information from any other
- group specifier.
+ 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
(gnus-cache-request-article article group))
(setq res (cons group article)
clean-up t))
+ ;; Check the agent cache.
((and gnus-agent gnus-agent-cache gnus-plugged
(numberp article)
(gnus-agent-request-article article group))
info (nth 1 gnus-command-method))))
(defun gnus-request-expire-articles (articles group &optional force)
- (let ((gnus-command-method (gnus-find-method-for-group group)))
- (funcall (gnus-get-function gnus-command-method 'request-expire-articles)
- articles (gnus-group-real-name group) (nth 1 gnus-command-method)
- force)))
-
-(defun gnus-request-move-article
- (article group server accept-function &optional last)
- (let ((gnus-command-method (gnus-find-method-for-group group)))
- (funcall (gnus-get-function gnus-command-method 'request-move-article)
- article (gnus-group-real-name group)
- (nth 1 gnus-command-method) accept-function last)))
-
+ (let* ((gnus-command-method (gnus-find-method-for-group group))
+ (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-cache
+ (gnus-sorted-difference articles not-deleted))
+ (gnus-agent-expire (gnus-sorted-difference articles not-deleted)
+ group 'force))
+ not-deleted))
+
+(defun gnus-request-move-article (article group server accept-function &optional last)
+ (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)))
+ (when (and result gnus-agent gnus-agent-cache)
+ (gnus-agent-expire (list article) group 'force))
+ result))
+
(defun gnus-request-accept-article (group &optional gnus-command-method last
no-encode)
;; Make sure there's a newline at the end of the article.
(defun gnus-advanced-integer (index match type)
(if (not (memq type '(< > <= >= =)))
(error "No such integer score type: %s" type)
- (funcall type match (or (aref gnus-advanced-headers index) 0))))
+ (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
:type 'boolean)
(defcustom gnus-message-replysignencrypted
- nil
+ t
"Setting this causes automatically encryped messages to also be signed."
:group 'gnus-message
:type 'boolean)
+(defcustom gnus-confirm-mail-reply-to-news nil
+ "If non-nil, Gnus requests confirmation when replying to news.
+This is done because new users often reply by mistake when reading
+news."
+ :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'."
+ :group 'gnus-message
+ :type 'boolean)
+
;;; Internal variables.
(defvar gnus-inhibit-posting-styles nil
;; 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
;; 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
(completing-read "Newsgroup: " gnus-active-hashtb nil
(gnus-read-active-file-p))
(gnus-group-group-name))
- "")))
+ ""))
+ ;; make sure last viewed article doesn't affect posting styles:
+ (gnus-article-copy))
(gnus-post-news 'post gnus-newsgroup-name)))
(defun gnus-summary-mail-other-window (&optional arg)
;; 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
;; 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
(completing-read "Newsgroup: " gnus-active-hashtb nil
(gnus-read-active-file-p))
"")
- gnus-newsgroup-name)))
+ gnus-newsgroup-name))
+ ;; make sure last viewed article doesn't affect posting styles:
+ (gnus-article-copy))
(gnus-post-news 'post gnus-newsgroup-name)))
;; Send a followup.
(gnus-post-news nil gnus-newsgroup-name
headers gnus-article-buffer
- yank nil force-news)))
+ 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."
(message-reply-headers
;; The headers are decoded.
(with-current-buffer gnus-article-copy
- (nnheader-parse-head t))))
+ (save-restriction
+ (nnheader-narrow-to-headers)
+ (ietf-drums-unfold-fws)
+ (nnheader-parse-head t)))))
(message-yank-original)
(setq beg (or beg (mark t))))
(when articles
(interactive
(list (and current-prefix-arg
(gnus-summary-work-articles 1))))
- (let* ((article
- (if (listp (car yank))
- (caar yank)
- (car yank)))
- (gnus-article-reply (or article (gnus-summary-article-number)))
- (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)
- (save-excursion
- (set-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)
+ ;; Allow user to require confirmation before replying by mail to the
+ ;; author of a news article.
+ (when (or (not (gnus-news-group-p gnus-newsgroup-name))
+ (not gnus-confirm-mail-reply-to-news)
+ (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)))
+ (headers ""))
+ ;; Stripping headers should be specified with mail-yank-ignored-headers.
(when yank
- (gnus-inews-yank-articles yank))
- (when (or gnus-message-replysign gnus-message-replyencrypt)
- (let (signed encrypted)
- (save-excursion
- (set-buffer gnus-article-buffer)
- (setq signed (memq 'signed gnus-article-wash-types))
- (setq encrypted (memq 'encrypted gnus-article-wash-types)))
- (cond ((and gnus-message-replysign signed)
- (mml-secure-message mml-default-sign-method 'sign))
- ((and gnus-message-replyencrypt encrypted)
- (mml-secure-message mml-default-encrypt-method
- (if gnus-message-replysignencrypted
- 'signencrypt
- 'encrypt)))))))))
+ (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)
+ (save-excursion
+ (set-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)
+ (save-excursion
+ (set-buffer gnus-article-buffer)
+ (setq signed (memq 'signed gnus-article-wash-types))
+ (setq encrypted (memq 'encrypted gnus-article-wash-types)))
+ (cond ((and gnus-message-replysign signed)
+ (mml-secure-message mml-default-sign-method 'sign))
+ ((and gnus-message-replyencrypt encrypted)
+ (mml-secure-message mml-default-encrypt-method
+ (if gnus-message-replysignencrypted
+ 'signencrypt
+ 'encrypt)))))))
(defun gnus-summary-reply-with-original (n &optional wide)
"Start composing a reply mail to the current message.
(interactive
(list (message-read-from-minibuffer
"Resend message(s) to: "
- (when (gnus-buffer-live-p gnus-original-article-buffer)
+ (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.
(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 'automatic))
+ (let ((gnus-view-pseudos (or gnus-view-pseudos 'automatic)))
(gnus-uu-decode-uu))))
(defun gnus-binary-show-article (&optional arg)
"Guess a sieve rule based on RFC822 article in buffer.
Return nil if no rule could be guessed."
(when (message-fetch-field "sender")
- `(sieve address "sender" ,(regexp-quote (message-fetch-field "sender")))))
+ `(sieve address "sender" ,(message-fetch-field "sender"))))
;;;###autoload
(defun gnus-sieve-article-add-rule ()
(defun gnus-clear-system ()
"Clear all variables and buffers."
;; Clear Gnus variables.
- (let ((variables (delete 'gnus-format-specs gnus-variable-list)))
+ (let ((variables (remove 'gnus-format-specs gnus-variable-list)))
(while variables
(set (car variables) nil)
(setq variables (cdr variables))))
(set-buffer gnus-dribble-buffer)
(goto-char (point-max))
(insert string "\n")
- (set-window-point (get-buffer-window (current-buffer)) (point-max))
+ ;; 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)
(save-excursion
(set-buffer gnus-group-buffer)
"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 (delete 'gnus-format-specs gnus-variable-list)))
+ (let ((variables (remove 'gnus-format-specs gnus-variable-list)))
(while variables
(set (car variables) nil)
(setq variables (cdr variables))))
(autoload 'gnus-mailing-list-insinuate "gnus-ml" nil t)
(autoload 'turn-on-gnus-mailing-list-mode "gnus-ml" nil t)
(autoload 'mm-uu-dissect "mm-uu")
-(autoload 'gnus-article-outlook-deuglify-article "deuglify"
+(autoload 'gnus-article-outlook-deuglify-article "deuglify"
"Deuglify broken Outlook (Express) articles and redisplay."
t)
"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' and `gnus-simplify-whitespace'."
+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))
:type 'boolean)
(defcustom gnus-auto-expirable-marks
- (list gnus-spam-mark gnus-killed-mark gnus-del-mark gnus-catchup-mark
+ (list gnus-killed-mark gnus-del-mark gnus-catchup-mark
gnus-low-score-mark gnus-ancient-mark gnus-read-mark
gnus-souped-mark gnus-duplicate-mark)
"*The list of marks converted into expiration if a group is auto-expirable."
Ready-made functions include `gnus-article-sort-by-number',
`gnus-article-sort-by-author', `gnus-article-sort-by-subject',
-`gnus-article-sort-by-date' and `gnus-article-sort-by-score'.
+`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."
(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"))))
(defcustom gnus-thread-sort-functions '(gnus-thread-sort-by-number)
`gnus-thread-sort-by-author', `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', and
+`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
(function-item gnus-thread-sort-by-date)
(function-item gnus-thread-sort-by-score)
(function-item gnus-thread-sort-by-total-score)
+ (function-item gnus-thread-sort-by-random)
(function :tag "other"))))
(defcustom gnus-thread-score-function '+
(?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)
(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.")
gnus-newsgroup-last-folder gnus-newsgroup-last-file
gnus-newsgroup-auto-expire 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-recent
(setq mystr (substring mystr 0 (match-beginning 0))))
mystr))
+(defun gnus-simplify-all-whitespace (str)
+ "Remove all whitespace from STR."
+ (let ((mystr str))
+ (while (string-match "[ \t\n]+" mystr)
+ (setq mystr (replace-match "" nil nil mystr)))
+ mystr))
+
(defsubst gnus-simplify-subject-re (subject)
"Remove \"Re:\" from subject lines."
(if (string-match message-subject-re-regexp subject)
"\C-c\C-s\C-d" gnus-summary-sort-by-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
(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)
["Show picons in mail headers" gnus-treat-mail-picon t]
["Show picons in news headers" gnus-treat-newsgroups-picon t]
("View as different encoding"
- ,@(mapcar
- (lambda (cs)
- ;; Since easymenu under FSF Emacs doesn't allow lambda
- ;; forms for menu commands, we should provide intern'ed
- ;; function symbols.
- (let ((command (intern (format "\
+ ,@(gnus-summary-menu-split
+ (mapcar
+ (lambda (cs)
+ ;; Since easymenu under FSF 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))
- (lambda (a b)
- (string< (symbol-name a)
- (symbol-name b)))))))
+ (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))
+ (lambda (a b)
+ (string< (symbol-name a)
+ (symbol-name b))))))))
("Washing"
("Remove Blanks"
["Leading" gnus-article-strip-leading-blank-lines 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"
["Fetch group FAQ" gnus-summary-fetch-faq t]
(defun gnus-article-read-p (article)
"Say whether ARTICLE is read or not."
(not (or (memq article gnus-newsgroup-marked)
+ (memq article gnus-newsgroup-spam-marked)
(memq article gnus-newsgroup-unreads)
(memq article gnus-newsgroup-unselected)
(memq article gnus-newsgroup-dormant))))
((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))
(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)
(set-buffer gnus-group-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
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)))
- ref ref-dep ref-header replaced)
+ parent-id ref ref-dep ref-header replaced)
;; Enter this `header' in the `dependencies' table.
(cond
((not id-dep)
(when (and header (not replaced))
;; First check that we are not creating a References loop.
- (setq ref (gnus-parent-id (mail-header-references header)))
+ (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)
;; root article.
(progn
(mail-header-set-references (car (symbol-value id-dep)) "none")
- (setq ref nil))
+ (setq ref nil)
+ (setq parent-id nil))
(setq ref (gnus-parent-id (mail-header-references ref-header)))))
- (setq ref (gnus-parent-id (mail-header-references header)))
- (setq ref-dep (intern (or ref "none") dependencies))
+ (setq ref-dep (intern (or parent-id "none") dependencies))
(if (boundp ref-dep)
(setcdr (symbol-value ref-dep)
(nconc (cdr (symbol-value ref-dep))
(gnus-article-sort-by-number
(gnus-thread-header h1) (gnus-thread-header h2)))
+(defsubst gnus-article-sort-by-random (h1 h2)
+ "Sort articles by article number."
+ (zerop (random 2)))
+
+(defun gnus-thread-sort-by-random (h1 h2)
+ "Sort threads by root article number."
+ (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)
(default-score (or gnus-summary-default-score 0))
(gnus-visual-p (gnus-visual-p 'summary-highlight 'highlight))
thread number subject stack state gnus-tmp-gathered beg-match
- new-roots gnus-tmp-new-adopts thread-end
+ new-roots gnus-tmp-new-adopts thread-end simp-subject
gnus-tmp-header gnus-tmp-unread
gnus-tmp-replied gnus-tmp-subject-or-nil
gnus-tmp-dummy gnus-tmp-indentation gnus-tmp-lines gnus-tmp-score
(setq gnus-tmp-level -1)))
(setq number (mail-header-number gnus-tmp-header)
- subject (mail-header-subject 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
((and (null gnus-thread-ignore-subject)
(not (zerop gnus-tmp-level))
gnus-tmp-prev-subject
- (not (inline
- (gnus-subject-equal gnus-tmp-prev-subject 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))
(cond
((and gnus-thread-ignore-subject
gnus-tmp-prev-subject
- (not (inline (gnus-subject-equal
- gnus-tmp-prev-subject 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
- (inline (gnus-subject-equal
- gnus-tmp-prev-subject subject)))
+ (string= gnus-tmp-prev-subject simp-subject))
gnus-summary-same-subject
subject))
(t gnus-summary-same-subject)))
(gnus-run-hooks 'gnus-summary-update-hook)
(forward-line 1))
- (setq gnus-tmp-prev-subject subject)))
+ (setq gnus-tmp-prev-subject simp-subject)))
(when (nth 1 thread)
(push (list (max 0 gnus-tmp-level)
(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)
(numberp gnus-large-newsgroup)
(> number gnus-large-newsgroup))
(let* ((cursor-in-echo-area nil)
- (initial (gnus-parameter-large-newsgroup-initial
+ (initial (gnus-parameter-large-newsgroup-initial
gnus-newsgroup-name))
(input
(read-string
(interactive)
(let ((mm-verify-option 'known)
(mm-decrypt-option 'known)
- (gnus-buttonized-mime-types (append (list "multipart/signed"
+ (gnus-buttonized-mime-types (append (list "multipart/signed"
"multipart/encrypted")
gnus-buttonized-mime-types)))
(gnus-summary-select-article nil 'force)))
(set-buffer gnus-original-article-buffer)
;; Have the digest group inherit the main mail address of
;; the parent article.
- (when (setq to-address (or (message-fetch-field "reply-to")
- (message-fetch-field "from")))
+ (when (setq to-address (or (gnus-fetch-field "reply-to")
+ (gnus-fetch-field "from")))
(setq params (append
(list (cons 'to-address
(funcall gnus-decode-encoded-word-function
If ARG is a positive number, show the entire header.
If ARG is a negative number, hide the unwanted header lines."
(interactive "P")
- (save-excursion
- (set-buffer gnus-article-buffer)
- (save-restriction
- (let* ((buffer-read-only nil)
- (inhibit-point-motion-hooks t)
- hidden s e)
- (save-restriction
- (article-narrow-to-head)
- (setq e (point-max)
- hidden (if (numberp arg)
+ (let ((window (and (gnus-buffer-live-p gnus-article-buffer)
+ (get-buffer-window gnus-article-buffer t))))
+ (when window
+ (with-current-buffer gnus-article-buffer
+ (widen)
+ (article-narrow-to-head)
+ (let* ((buffer-read-only nil)
+ (inhibit-point-motion-hooks t)
+ (hidden (if (numberp arg)
(>= arg 0)
- (gnus-article-hidden-text-p 'headers))))
- (delete-region (point-min) e)
- (goto-char (point-min))
- (with-current-buffer gnus-original-article-buffer
- (goto-char (setq s (point-min)))
- (setq e (search-forward "\n\n" nil t)
- e (if e (1- e) (point-max))))
- (insert-buffer-substring gnus-original-article-buffer s e)
- (save-restriction
- (narrow-to-region (point-min) (point))
+ (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)
(article-decode-encoded-words)
- (if hidden
+ (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)))
- (gnus-set-mode-line 'article)))))
+ (gnus-treat-article 'head))
+ (widen)
+ (set-window-start window (goto-char (point-min)))
+ (setq gnus-page-broken
+ (when gnus-break-pages
+ (gnus-narrow-to-page)
+ t))
+ (gnus-set-mode-line 'article))))))
(defun gnus-summary-show-all-headers ()
"Make all header lines visible."
(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
(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.
(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-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
(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)))
;; 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.
(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))
(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)))
(progn
(when all
(setq gnus-newsgroup-marked nil
+ gnus-newsgroup-spam-marked nil
gnus-newsgroup-dormant nil))
(setq gnus-newsgroup-unreads gnus-newsgroup-downloadable))
;; We actually mark all articles as canceled, which we
(interactive "P")
(gnus-summary-sort '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.
(if (and (numberp gnus-large-newsgroup)
(> len gnus-large-newsgroup))
(let* ((cursor-in-echo-area nil)
- (initial (gnus-parameter-large-newsgroup-initial
+ (initial (gnus-parameter-large-newsgroup-initial
gnus-newsgroup-name))
(input
(read-string
i new)
(setq gnus-newsgroup-active
(gnus-activate-group gnus-newsgroup-name 'scan))
- (setq i (1+ (cdr old-active)))
- (while (<= i (cdr gnus-newsgroup-active))
+ (setq i (cdr gnus-newsgroup-active))
+ (while (> i (cdr old-active))
(push i new)
- (incf i))
+ (decf i))
(if (not new)
(message "No gnus is bad news.")
- (setq new (nreverse new))
(gnus-summary-insert-articles new)
(setq gnus-newsgroup-unreads
(gnus-sorted-nunion gnus-newsgroup-unreads new))
"Compute the group parameters for GROUP taking into account inheritance from topics."
(let ((params-list (copy-sequence (gnus-group-get-parameter group))))
(save-excursion
- (gnus-group-goto-group group)
(nconc params-list
- (gnus-topic-hierarchical-parameters (gnus-current-topic))))))
+ (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)))))))
(defun gnus-topic-hierarchical-parameters (topic)
"Return a topic list computed for TOPIC."
(gnus-topic-kill-group)
(push (cdar gnus-topic-killed-topics) gnus-topic-alist)
(gnus-topic-create-topic
- topic parent nil (cdaar gnus-topic-killed-topics))
+ 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))))))
(push (cdar gnus-topic-killed-topics) gnus-topic-alist)
(gnus-topic-create-topic
topic grandparent (gnus-topic-next-topic parent)
- (cdaar gnus-topic-killed-topics))
+ (cdar (car gnus-topic-killed-topics)))
(pop gnus-topic-killed-topics)
(gnus-topic-goto-topic topic))))
:link '(custom-manual "(gnus)Exiting Gnus")
:group 'gnus)
-(defconst gnus-version-number "0.06"
+(defconst gnus-version-number "0.07"
"Version number for this version of Gnus.")
(defconst gnus-version (format "Oort Gnus v%s" gnus-version-number)
confirmation is required for selecting the newsgroup.
If it is `nil', no confirmation is required."
:group 'gnus-group-select
- :type 'integer)
+ :type '(choice (const :tag "No limit" nil)
+ integer))
(defcustom gnus-use-long-file-name (not (memq system-type '(usg-unix-v xenix)))
"*Non-nil means that the default name of a file to save articles in is the group name.
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."
+ :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
"Whether Gnus is plugged or not.")
(defcustom gnus-agent-cache t
- "Whether Gnus use agent cache."
+ "Whether Gnus use agent cache.
+You also need to enable `gnus-agent'."
:version "21.3"
:group 'gnus-agent
:type 'boolean)
:type 'symbol
:group 'gnus-charset)
-(defcustom gnus-agent nil
+(defcustom gnus-agent t
"Whether we want to use the Gnus agent or not.
Putting (gnus-agentize) in ~/.gnus is obsolete by (setq gnus-agent t)."
:version "21.3"
(let (group address addresses)
(dolist (entry (cdr gnus-newsrc-alist))
(setq group (car entry))
- (when (gnus-group-find-parameter group 'subscribed)
+ (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
- (push address addresses))))
+ (add-to-list 'addresses address))))
(when addresses
(list (mapconcat 'regexp-quote addresses "\\|")))))
(funcall function source callback)
(error
(unless (yes-or-no-p
- (format "Mail source error (%s). Continue? "
+ (format "Mail source %s error (%s). Continue? "
+ source
(cadr err)))
(error "Cannot get new mail"))
0)))))))))
:type 'string
:group 'message-various)
-(defcustom message-interactive nil
+(defcustom message-interactive t
"Non-nil means when sending a message wait for and display errors.
nil means let mailer mail back a message to report errors."
:group 'message-sending
"Face used for displaying MML."
:group 'message-faces)
+(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?"))
- `((,(concat "^\\([Tt]o:\\)" content)
+ `((,(message-font-lock-make-header-matcher
+ (concat "^\\([Tt]o:\\)" content))
(1 'message-header-name-face)
(2 'message-header-to-face nil t))
- (,(concat "^\\(^[GBF]?[Cc][Cc]:\\|^[Rr]eply-[Tt]o:\\)" content)
+ (,(message-font-lock-make-header-matcher
+ (concat "^\\(^[GBF]?[Cc][Cc]:\\|^[Rr]eply-[Tt]o:\\)" content))
(1 'message-header-name-face)
(2 'message-header-cc-face nil t))
- (,(concat "^\\([Ss]ubject:\\)" content)
+ (,(message-font-lock-make-header-matcher
+ (concat "^\\([Ss]ubject:\\)" content))
(1 'message-header-name-face)
(2 'message-header-subject-face nil t))
- (,(concat "^\\([Nn]ewsgroups:\\|Followup-[Tt]o:\\)" content)
+ (,(message-font-lock-make-header-matcher
+ (concat "^\\([Nn]ewsgroups:\\|Followup-[Tt]o:\\)" content))
(1 'message-header-name-face)
(2 'message-header-newsgroups-face nil t))
- (,(concat "^\\([A-Z][^: \n\t]+:\\)" content)
+ (,(message-font-lock-make-header-matcher
+ (concat "^\\([A-Z][^: \n\t]+:\\)" content))
(1 'message-header-name-face)
(2 'message-header-other-face nil t))
- (,(concat "^\\(X-[A-Za-z0-9-]+\\|In-Reply-To\\):" content)
+ (,(message-font-lock-make-header-matcher
+ (concat "^\\(X-[A-Za-z0-9-]+:\\|In-Reply-To:\\)" content))
(1 'message-header-name-face)
(2 'message-header-name-face))
,@(if (and mail-header-separator
(0 'message-mml-face))))
"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))
(1+ max)))))
(message-sort-headers-1))))
+
\f
;;;
" sendmail errors")
0))
resend-to-addresses delimline)
- (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
- (save-excursion
- (set-buffer errbuf)
- (erase-buffer))))
- (let ((default-directory "/")
- (coding-system-for-write message-send-coding-system))
- (apply 'call-process-region
- (append (list (point-min) (point-max)
- (if (boundp 'sendmail-program)
- sendmail-program
- "/usr/lib/sendmail")
- nil errbuf nil "-oi")
- ;; 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.
- (if (null message-sendmail-f-is-evil)
- (list "-f" (message-make-address)))
- ;; 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")))))
- (when message-interactive
- (save-excursion
- (set-buffer errbuf)
- (goto-char (point-min))
- (while (re-search-forward "\n\n* *" nil t)
- (replace-match "; "))
- (if (not (zerop (buffer-size)))
- (error "Sending...failed to %s"
- (buffer-substring (point-min) (point-max)))))
+ (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
+ (save-excursion
+ (set-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)
+ (if (boundp 'sendmail-program)
+ sendmail-program
+ "/usr/lib/sendmail")
+ nil errbuf nil "-oi")
+ ;; 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.
+ (if (null message-sendmail-f-is-evil)
+ (list "-f" (message-make-address)))
+ ;; 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) (zerop cpr))
+ (error "Sending...failed with exit value %d" cpr)))
+ (when message-interactive
+ (save-excursion
+ (set-buffer errbuf)
+ (goto-char (point-min))
+ (while (re-search-forward "\n\n* *" nil t)
+ (replace-match "; "))
+ (if (not (zerop (buffer-size)))
+ (error "Sending...failed to %s"
+ (buffer-substring (point-min) (point-max)))))))
(when (bufferp errbuf)
(kill-buffer errbuf)))))
(defun message-beginning-of-line (&optional n)
"Move point to beginning of header value or to beginning of line."
(interactive "p")
+ (let ((zrs 'zmacs-region-stays))
+ (when (and (interactive-p) (boundp zrs))
+ (set zrs t)))
(if (message-point-in-header-p)
(let* ((here (point))
(bol (progn (beginning-of-line n) (point)))
(or (search-forward "\n\n" nil t) (point)))
(delete-region (point-min) (point-max)))
(when (and (not current-prefix-arg)
- message-forward-ignored-headers)
+ message-forward-ignored-headers
+ ;; don't remove CTE, X-Gnus etc when doing "raw" forward:
+ message-forward-show-mml)
(save-restriction
(narrow-to-region b e)
(goto-char b)
(defcustom mm-inline-text-html-with-images nil
"If non-nil, Gnus will allow retrieving images in the HTML contents
-with <img> tags. It has no effect on Emacs/w3. For emacs-w3m, the
-value of the option `w3m-display-inline-images' will be bound with
-this value. In addition, the variable `w3m-safe-url-regexp' will be
-bound with the value nil if it is non-nil to make emacs-w3m show all
-images, however this behavior may be changed in the future."
+with <img> tags. It has no effect on Emacs/w3. See also
+the documentation for the option `mm-w3m-safe-url-regexp'."
:type 'boolean
:group 'mime-display)
+(defcustom mm-w3m-safe-url-regexp "\\`cid:"
+ "Regexp that matches safe url names. Some HTML mails might have a
+trick of spammers using <img> tags. It is likely to be intended to
+verify whether you have read the mail. You can prevent your personal
+informations from leaking by setting this to the regexp which matches
+the safe url names. The value of the variable `w3m-safe-url-regexp'
+will be bound with this value. You may set this value to nil if you
+consider all the urls to be safe."
+ :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."
:type 'boolean
;; We create a private sub-directory where we store our files.
(set-file-modes dir 448)
(if filename
- (setq file (expand-file-name
+ (setq file (expand-file-name
(gnus-map-function mm-file-name-rewrite-functions
- (file-name-nondirectory filename))
+ (file-name-nondirectory filename))
dir))
(setq file (mm-make-temp-file (expand-file-name "mm." dir))))
(let ((coding-system-for-write mm-binary-coding-system))
(eval-and-compile
(autoload 'mm-body-7-or-8 "mm-bodies"))
-(defvar mm-content-transfer-encoding-defaults
+(defcustom mm-content-transfer-encoding-defaults
'(("text/x-patch" 8bit)
("text/.*" qp-or-base64)
("message/rfc822" 8bit)
(".*" 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.")
+or base64 will be used, depending on what is more efficient."
+ :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)
(defvar mm-use-ultra-safe-encoding nil
"If non-nil, use encodings aimed at Procrustean bed survival.
args (append mm-url-arguments (list url))))
(apply 'call-process program nil t nil args)))
+(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."
- (if follow-refresh
- (save-restriction
- (narrow-to-region (point) (point))
- (mm-url-insert-file-contents url)
- (goto-char (point-min))
- (when (re-search-forward
- "<meta[ \t\r\n]*http-equiv=\"Refresh\"[^>]*URL=\\([^\"]+\\)\"" nil t)
- (let ((url (match-string 1)))
- (delete-region (point-min) (point-max))
- (mm-url-insert url t))))
- (mm-url-insert-file-contents url)))
+ (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."
mm-iso-8859-15-compatible))
"A table of the difference character between ISO-8859-X and ISO-8859-15.")
-(defvar mm-coding-system-priorities nil
+(defcustom mm-coding-system-priorities nil
"Preferred coding systems for encoding outgoing mails.
More than one suitable coding systems may be found for some texts. By
prefer iso-2022-jp to japanese-shift-jis:
\(setq mm-coding-system-priorities
- '(iso-2022-jp iso-2022-jp-2 japanese-shift-jis utf-8))
-")
+ '(iso-2022-jp iso-2022-jp-2 japanese-shift-jis iso-latin-1 utf-8))
+"
+ :type '(repeat (coding-system :tag "Coding system"))
+ :group 'mime)
(defvar mm-use-find-coding-systems-region
(fboundp 'find-coding-systems-region)
(when charset
(delete-region (point-min) (point-max))
(insert (mm-decode-string text charset)))
- (let ((w3m-safe-url-regexp (if mm-inline-text-html-with-images
- nil
- "\\`cid:"))
+ (let ((w3m-safe-url-regexp mm-w3m-safe-url-regexp)
(w3m-display-inline-images mm-inline-text-html-with-images)
w3m-force-redisplay)
(w3m-region (point-min) (point-max)))
(defvar mml-default-encrypt-method (caar mml-encrypt-alist)
"Default encryption method.")
+(defvar mml-signencrypt-style-alist
+ '(("smime" separate)
+ ("pgp" separate)
+ ("pgpmime" separate))
+ "Alist specifying whether or not a single sign & encrypt
+operation should be perfomed when requesting signencrypt.
+Note that combined sign & encrypt is NOT supported by pgp v2!
+Also note that you should access this with mml-signencrypt-style")
+
+;;; 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)"
+ (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))
+ (gnus-message 3 "Warning, attempt to set invalid signencrypt-style"))))
+
;;; Security functions
(defun mml-smime-sign-buffer (cont)
(or (mml2015-sign cont)
(error "Signing failed... inspect message logs for errors")))
-(defun mml-pgpmime-encrypt-buffer (cont)
- (or (mml2015-encrypt cont)
+(defun mml-pgpmime-encrypt-buffer (cont &optional sign)
+ (or (mml2015-encrypt cont sign)
(error "Encryption failed... inspect message logs for errors")))
(defun mml-secure-part (method &optional sign)
(interactive "P")
(mml-secure-message "smime" (if dontsign 'encrypt 'signencrypt)))
-;;; NOTE: this should be switched to use signencrypt
-;;; once it does something sensible
(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 'encrypt)))
+ (mml-secure-message "pgp" (if dontsign 'encrypt 'signencrypt)))
-;;; NOTE: this should be switched to use signencrypt
-;;; once it does something sensible
(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 'encrypt)))
+ (mml-secure-message "pgpmime" (if dontsign 'encrypt 'signencrypt)))
(provide 'mml-sec)
(insert "\n--" mml-boundary "--\n")))))
(t
(error "Invalid element: %S" cont)))
- (let ((item (assoc (cdr (assq 'sign cont)) mml-sign-alist))
+ ;; 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 item
+ (when (or sign-item encrypt-item)
(if (setq sender (cdr (assq 'sender cont)))
(message-options-set 'message-sender sender))
(if (setq recipients (cdr (assq 'recipients cont)))
(message-options-set 'message-recipients recipients))
- (funcall (nth 1 item) cont)))
- (let ((item (assoc (cdr (assq 'encrypt cont)) mml-encrypt-alist))
- sender recipients)
- (when item
- (if (setq sender (cdr (assq 'sender cont)))
- (message-options-set 'message-sender sender))
- (if (setq recipients (cdr (assq 'recipients cont)))
- (message-options-set 'message-recipients recipients))
- (funcall (nth 1 item) cont))))))
+ (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."
"*MIME preview of ") (buffer-name))))
(erase-buffer)
(insert-buffer buf)
+ (let ((message-deletable-headers (if (message-news-p)
+ nil
+ message-deletable-headers)))
+ (message-generate-headers
+ (copy-sequence (if (message-news-p)
+ message-required-news-headers
+ message-required-mail-headers))))
(if (re-search-forward
(concat "^" (regexp-quote mail-header-separator) "\n") nil t)
(replace-match "\n"))
(let ((gnus-newsgroup-charset (car message-posting-charset))
gnus-article-prepare-hook gnus-original-article-buffer)
(run-hooks 'gnus-article-decode-hook)
- (let ((gnus-newsgroup-name "dummy"))
+ (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)
;;; Commentary:
-;; RCS: $Id: mml1991.el,v 1.1.1.2 2002-05-06 23:49:24 yamaoka Exp $
+;; RCS: $Id: mml1991.el,v 1.1.1.3 2002-08-06 12:41:35 yamaoka Exp $
;;; Code:
mml1991-mailcrypt-encrypt)
(gpg mml1991-gpg-sign
mml1991-gpg-encrypt))
- "Alist of PGP/MIME functions.")
+ "Alist of PGP functions.")
;;; mailcrypt wrapper
(insert (format "--%s--\n" boundary))
(goto-char (point-max))))
-(defun mml2015-mailcrypt-encrypt (cont)
+(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
(autoload 'gpg-verify-cleartext "gpg")
(autoload 'gpg-sign-detached "gpg")
(autoload 'gpg-sign-encrypt "gpg")
+ (autoload 'gpg-encrypt "gpg")
(autoload 'gpg-passphrase-read "gpg"))
(defun mml2015-gpg-passphrase ()
(defun mml2015-gpg-extract-signature-details ()
(goto-char (point-min))
(if (boundp 'gpg-unabbrev-trust-alist)
- (let* ((signer (and (re-search-forward
- "^\\[GNUPG:\\] GOODSIG [0-9A-Za-z]* \\(.*\\)$"
+ (let* ((expired (re-search-forward
+ "^\\[GNUPG:\\] SIGEXPIRED$"
+ nil t))
+ (signer (and (re-search-forward
+ "^\\[GNUPG:\\] GOODSIG \\([0-9A-Za-z]*\\) \\(.*\\)$"
nil t)
- (match-string 1)))
+ (cons (match-string 1) (match-string 2))))
(fprint (and (re-search-forward
"^\\[GNUPG:\\] VALIDSIG \\([0-9a-zA-Z]*\\) "
nil t)
(trust-good-enough-p
(cdr (assoc (cdr (assoc trust gpg-unabbrev-trust-alist))
mml2015-trust-boundaries-alist))))
- (if (and signer trust fprint)
- (concat signer
- (unless trust-good-enough-p
- (concat "\nUntrusted, Fingerprint: "
- (mml2015-gpg-pretty-print-fpr fprint))))
- "From unknown user"))
+ (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)))))
+ (t
+ "From unknown user")))
(if (re-search-forward "^gpg: Good signature from \"\\(.*\\)\"$" nil t)
(match-string 1)
"From unknown user")))
(insert (format "--%s--\n" boundary))
(goto-char (point-max)))))
-(defun mml2015-gpg-encrypt (cont)
+(defun mml2015-gpg-encrypt (cont &optional sign)
(let ((boundary
(funcall mml-boundary-function (incf mml-multipart-number)))
(text (current-buffer))
cipher)
(mm-with-unibyte-current-buffer-mule4
(with-temp-buffer
- (unless (gpg-sign-encrypt
- text (setq cipher (current-buffer))
- mml2015-result-buffer
- (split-string
- (or
- (message-options-get 'message-recipients)
- (message-options-set 'message-recipients
- (read-string "Recipients: ")))
- "[ \f\t\n\r\v,]+")
- nil
- (message-options-get 'message-sender)
- t t) ; armor & textmode
- (unless (> (point-max) (point-min))
- (pop-to-buffer mml2015-result-buffer)
- (error "Encrypt error")))
+ ;; set up a function to call the correct gpg encrypt routine
+ ;; with the right arguments. (FIXME: this should be done
+ ;; differently.)
+ (flet ((gpg-encrypt-func
+ (sign plaintext ciphertext result recipients &optional
+ passphrase sign-with-key armor textmode)
+ (if sign
+ (gpg-sign-encrypt
+ plaintext ciphertext result recipients passphrase
+ sign-with-key armor textmode)
+ (gpg-encrypt
+ plaintext ciphertext result recipients passphrase
+ armor textmode))))
+ (unless (gpg-encrypt-func
+ sign ; passed in when using signencrypt
+ text (setq cipher (current-buffer))
+ mml2015-result-buffer
+ (split-string
+ (or
+ (message-options-get 'message-recipients)
+ (message-options-set 'message-recipients
+ (read-string "Recipients: ")))
+ "[ \f\t\n\r\v,]+")
+ nil
+ (message-options-get 'message-sender)
+ t t) ; armor & textmode
+ (unless (> (point-max) (point-min))
+ (pop-to-buffer mml2015-result-buffer)
+ (error "Encrypt error"))))
(goto-char (point-min))
(while (re-search-forward "\r+$" nil t)
(replace-match "" t t))
mml2015-use)
;;;###autoload
-(defun mml2015-encrypt (cont)
+(defun mml2015-encrypt (cont &optional sign)
(mml2015-clean-buffer)
(let ((func (nth 2 (assq mml2015-use mml2015-function-alist))))
(if func
- (funcall func cont)
+ (funcall func cont sign)
(error "Cannot find encrypt function"))))
;;;###autoload
(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")))
+ (nnmail-cache-insert (nnmail-fetch-field "message-id") group))
(setq result
(if (stringp group)
(list (cons group (nnbabyl-active-number group)))
(insert-buffer-substring buf)
(when last
(when nnmail-cache-accepted-message-ids
- (nnmail-cache-insert (nnmail-fetch-field "message-id")))
+ (nnmail-cache-insert (nnmail-fetch-field "message-id") group))
(save-buffer)
(nnmail-save-active nnbabyl-group-alist nnbabyl-active-file))
result))))
(when (nndiary-schedule)
(let (result)
(when nnmail-cache-accepted-message-ids
- (nnmail-cache-insert (nnmail-fetch-field "message-id")))
+ (nnmail-cache-insert (nnmail-fetch-field "message-id") group))
(if (stringp group)
(and
(nnmail-activate 'nndiary)
(cons 'body-begin "^ ?\n")
(cons 'article-begin b-delimiter)
(cons 'body-end-function 'nndoc-digest-body-end)
- (cons 'file-end (concat "\n--" boundary-id "--[ \t]*$"))))
+ (cons 'file-end (concat "^--" boundary-id "--[ \t]*$"))))
t)))
(defun nndoc-standard-digest-type-p ()
(save-excursion
(set-buffer nntp-server-buffer)
(erase-buffer)
- (let (article start stop)
+ (let (article start stop num)
(nnfolder-possibly-change-group group server)
(when nnfolder-current-buffer
(set-buffer nnfolder-current-buffer)
(nnfolder-existing-articles)))
(while (setq article (pop articles))
(set-buffer nnfolder-current-buffer)
- (when (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")))
+ (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-int
+ (buffer-substring
+ (point) (progn (end-of-line) (point)))))
+ (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-int
+ (buffer-substring
+ (point) (progn (end-of-line) (point)))))
+ (> 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))))))
(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")))
+ (nnmail-cache-insert (nnmail-fetch-field "message-id") group))
(setq result (if (stringp group)
(list (cons group (nnfolder-active-number group)))
(setq art-group
(defvar nnheader-head-chop-length 2048
"*Length of each read operation when trying to fetch HEAD headers.")
-(defvar nnheader-file-name-translation-alist nil
+(defvar nnheader-file-name-translation-alist
+ (let ((case-fold-search t))
+ (cond
+ ((string-match "windows-nt\\|os/2\\|emx\\|cygwin32"
+ (symbol-name system-type))
+ (append (mapcar (lambda (c) (cons c ?_))
+ '(?: ?* ?\" ?< ?> ??))
+ (if (string-match "windows-nt\\|cygwin32"
+ (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:
;; o What about Gnus's article editing, can we support it? NO!
;; o Use \Draft to support the draft group??
;; o Duplicate suppression
+;; o Rewrite UID SEARCH UID X as UID FETCH X (UID) for those with slow servers
;;; Code:
(defvoo nnimap-nov-file-name-suffix ".novcache"
"Suffix for NOV cache base filename.")
-(defvoo nnimap-nov-is-evil nil
- "If non-nil, nnimap will never generate or use a local nov database for this backend.
-Using nov databases will speed up header fetching considerably.
+(defvoo nnimap-nov-is-evil gnus-agent
+ "If non-nil, never generate or use a local nov database for this backend.
+Using nov databases should speed up header fetching considerably.
+However, it will invoke a UID SEARCH UID command on the server, and
+some servers implement this command inefficiently by opening each and
+every message in the group, thus making it quite slow.
Unlike other backends, you do not need to take special care if you
flip this variable.")
;; Internal variables:
-(defvoo nnimap-mailbox-info (gnus-make-hashtable 997))
+(defvar nnimap-mailbox-info (gnus-make-hashtable 997))
(defvar nnimap-debug nil
"Name of buffer to record debugging info.
For example: (setq nnimap-debug \"*nnimap-debug*\")")
(setq slowgroups groups)
(dolist (group groups)
(gnus-message 7 "nnimap: Checking mailbox %s" group)
- (add-to-list (if (gnus-gethash-safe group nnimap-mailbox-info)
+ (add-to-list (if (gnus-gethash-safe (concat server group)
+ nnimap-mailbox-info)
'asyncgroups
'slowgroups)
(list group (imap-mailbox-status-asynch
new old)
(when (imap-ok-p (imap-wait-for-tag tag nnimap-server-buffer))
(if (nnimap-string-lessp-numerical
- (car (gnus-gethash group nnimap-mailbox-info))
+ (car (gnus-gethash
+ (concat server group) nnimap-mailbox-info))
(imap-mailbox-get 'uidnext group nnimap-server-buffer))
(push (list group) slowgroups)
- (insert (cdr (gnus-gethash group nnimap-mailbox-info))))))))
+ (insert (cdr (gnus-gethash (concat server group)
+ nnimap-mailbox-info))))))))
(dolist (group slowgroups)
(if nnimap-retrieve-groups-asynchronous
(setq group (car group)))
(insert str)
(when nnimap-retrieve-groups-asynchronous
(gnus-sethash
- group
+ (concat server group)
(cons (or (imap-mailbox-get
'uidnext group nnimap-server-buffer)
(imap-mailbox-status
(goto-char (point-min))
(when (and (if (stringp regexp)
(progn
- (setq regrepp (string-match "\\\\[0-9&]" group))
+ (if (not (stringp group))
+ (setq group (eval group))
+ (setq regrepp
+ (string-match "\\\\[0-9&]" group)))
(re-search-forward regexp nil t))
(funcall regexp group))
;; Don't enter the article into the same group twice.
(setq removeorig t)
(when nnmail-cache-accepted-message-ids
(with-current-buffer nntp-server-buffer
- (nnmail-cache-insert (nnmail-fetch-field
- "message-id") to-group)))
+ (let (msgid)
+ (and (setq msgid
+ (nnmail-fetch-field "message-id"))
+ (nnmail-cache-insert msgid to-group)))))
;; Add the group-art list to the history list.
(push (list (cons to-group 0)) nnmail-split-history))
(t
(while (search-forward "\n" nil t)
(replace-match "\r\n"))
(when nnmail-cache-accepted-message-ids
- (nnmail-cache-insert (nnmail-fetch-field "message-id"))))
+ (nnmail-cache-insert (nnmail-fetch-field "message-id")
+ group)))
(when (and last nnmail-cache-accepted-message-ids)
(nnmail-cache-close))
;; this 'or' is for Cyrus server bug
This variable can also have a function as its value."
:group 'nnmail-split
- :type '(choice (repeat :tag "Alist" (group (string :tag "Name") regexp))
+ :type '(choice (repeat :tag "Alist" (group (string :tag "Name")
+ (choice regexp function)))
(function-item nnmail-split-fancy)
(function :tag "Other")))
(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."
+ :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.
:group 'nnmail
:type 'symbol)
+(defcustom nnmail-mail-splitting-decodes nil
+ "Whether the nnmail splitting functionality should MIME decode headers."
+ :group 'nnmail
+ :type 'boolean)
+
;;; Internal variables.
(defvar nnmail-article-buffer " *nnmail incoming*"
start
(if (search-forward "\n\n" nil t)
(1- (point))
- ;; This will never happen, but just to be on the safe side --
- ;; if there is no head-body delimiter, we search a bit manually.
+ ;; This will never happen, but just to be on the safe side --
+ ;; if there is no head-body delimiter, we search a bit manually.
(while (and (looking-at "From \\|[^ \t]+:")
(not (eobp)))
(forward-line 1))
(goto-char (point-max))
(widen)
(setq head-end (point))
- ;; We try the Content-Length value. The idea: skip over the header
- ;; separator, then check what happens content-length bytes into the
- ;; message body. This should be either the end ot the buffer, the
- ;; message separator or a blank line followed by the separator.
- ;; The blank line should probably be deleted. If neither of the
- ;; three is met, the content-length header is probably invalid.
+ ;; We try the Content-Length value. The idea: skip over the header
+ ;; separator, then check what happens content-length bytes into the
+ ;; message body. This should be either the end ot the buffer, the
+ ;; message separator or a blank line followed by the separator.
+ ;; The blank line should probably be deleted. If neither of the
+ ;; three is met, the content-length header is probably invalid.
(when content-length
(forward-line 1)
(setq skip (+ (point) content-length))
;; Copy the headers into the work buffer.
(insert-buffer-substring obuf beg end)
;; Decode MIME headers and charsets.
- (let ((mail-parse-charset nnmail-mail-splitting-charset))
- (mail-decode-encoded-word-region (point-min) (point-max)))
+ (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)
(defvar group)
(defvar group-art-list)
(defvar group-art)
-(defun nnmail-cache-insert (id &optional grp)
+(defun nnmail-cache-insert (id grp)
(when nnmail-treat-duplicates
;; Store some information about the group this message is written
- ;; to. This function might have been called from various places.
- ;; Sometimes, a function up in the calling sequence has an
- ;; argument GROUP which is bound to a string, the group name. At
- ;; other times, there is a function up in the calling sequence
- ;; which has an argument GROUP-ART which is a list of pairs, and
- ;; the car of a pair is a group name. Should we check that the
- ;; length of the list is equal to 1? -- kai
- (let ((g nil))
- (cond (grp
- (setq g grp))
- ((and (boundp 'group) group)
- (setq g group))
- ((and (boundp 'group-art-list) group-art-list
- (listp group-art-list))
- (setq g (caar group-art-list)))
- ((and (boundp 'group-art) group-art (listp group-art))
- (setq g (caar group-art)))
- (t (setq g "")))
- (unless (gnus-buffer-live-p nnmail-cache-buffer)
- (nnmail-cache-open))
- (save-excursion
- (set-buffer nnmail-cache-buffer)
- (goto-char (point-max))
- (if (and g (not (string= "" g))
- (gnus-methods-equal-p gnus-command-method
- (nnmail-cache-primary-mail-backend)))
- (insert id "\t" g "\n")
- (insert id "\n"))))))
+ ;; 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))
+ (save-excursion
+ (set-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))
((not duplication)
(funcall func (setq group-art
(nreverse (nnmail-article-group artnum-func))))
- (nnmail-cache-insert message-id))
+ (nnmail-cache-insert message-id (caar group-art)))
((eq action 'delete)
(setq group-art nil))
((eq action 'warn)
(setq target (format-time-string (caddr regexp-target-pair) date)))
((and (not (equal header 'to-from))
(string-match (cadr regexp-target-pair)
- (message-fetch-field header)))
+ (or
+ (message-fetch-field header)
+ "")))
(setq target
(format-time-string (caddr regexp-target-pair) date)))))))
(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 (nnmail-fetch-field "message-id")))
+ (nnmail-cache-insert (nnmail-fetch-field "message-id") group))
(setq result (if (stringp group)
(list (cons group (nnmbox-active-number group)))
(nnmail-article-group 'nnmbox-active-number)))
(nnmh-possibly-change-directory group server)
(nnmail-check-syntax)
(when nnmail-cache-accepted-message-ids
- (nnmail-cache-insert (nnmail-fetch-field "message-id")))
+ (nnmail-cache-insert (nnmail-fetch-field "message-id") group))
(nnheader-init-server-buffer)
(prog1
(if (stringp group)
(nnmail-check-syntax)
(let (result)
(when nnmail-cache-accepted-message-ids
- (nnmail-cache-insert (nnmail-fetch-field "message-id")))
+ (nnmail-cache-insert (nnmail-fetch-field "message-id") group))
(if (stringp group)
(and
(nnmail-activate 'nnml)
(defvoo nnslashdot-backslash-url "http://slashdot.org/slashdot.xml"
"Where nnslashdot will fetch the stories from.")
+(defvoo nnslashdot-use-front-page nil
+ "Use the front page in addition to the backslash page.")
+
(defvoo nnslashdot-threshold -1
"The article threshold.")
(deffoo nnslashdot-request-list (&optional server)
(nnslashdot-possibly-change-server nil server)
(let ((number 0)
+ (first nnslashdot-use-front-page)
sid elem description articles gname)
(condition-case why
;; First we do the Ultramode to get info on all the latest groups.
(goto-char (point-max))
(widen)))
;; Then do the older groups.
- (while (> (- nnslashdot-group-number number) 0)
+ (while (or first
+ (> (- nnslashdot-group-number number) 0))
+ (setq first nil)
(mm-with-unibyte-buffer
(let ((case-fold-search t))
(mm-url-insert (format nnslashdot-active-url number) t)
(goto-char (point-min))
(while (re-search-forward
- "article.pl\\?sid=\\([^&]+\\).*<b>\\([^<]+\\)</b>"
+ "article.pl\\?sid=\\([^&]+\\).*>\\([^<]+\\)</a>"
nil t)
(setq sid (match-string 1)
description
(mm-url-decode-entities-string (match-string 2)))
(forward-line 1)
- (when (re-search-forward "<b>\\([0-9]+\\)</b>" nil t)
- (setq articles (string-to-number (match-string 1))))
+ (when (re-search-forward "with \\([0-9]+\\) comment" nil t)
+ (setq articles (1+ (string-to-number (match-string 1)))))
(setq gname (concat description " (" sid ")"))
(if (setq elem (assoc gname nnslashdot-groups))
(setcar (cdr elem) articles)
;; articles in SEQUENCE come from.
(while (and areas sequence)
;; Peel off areas that are below sequence.
- (while (and areas (< (cdaar areas) (car sequence)))
+ (while (and areas (< (cdar (car areas)) (car sequence)))
(setq areas (cdr areas)))
(when areas
;; This is a useful area.
(setq use-nov nil))
;; We assign the portion of `sequence' that is relevant to
;; this MSG packet to this packet.
- (while (and sequence (<= (car sequence) (cdaar areas)))
+ (while (and sequence (<= (car sequence) (cdar (car areas))))
(push (car sequence) this-area-seq)
(setq sequence (cdr sequence)))
(setcar useful-areas (cons (nreverse this-area-seq)
;; Try to guess the type based on the first article in the group.
(when (not article)
(setq article
- (cdaar (cddr (assoc group nnsoup-group-alist)))))
+ (cdar (car (cddr (assoc group nnsoup-group-alist))))))
(if (not article)
'unknown
(let ((kind (gnus-soup-encoding-kind
(setq min (caaar e))
(while (cdr e)
(setq e (cdr e)))
- (setq max (cdaar e))
+ (setq max (cdar (car e)))
(setcdr entry (cons (cons min max) (cdr entry)))))
(setq nnsoup-group-alist-touched t))
nnsoup-group-alist))
(defun nnsoup-article-to-area (article group)
"Return the area that ARTICLE in GROUP is located in."
(let ((areas (cddr (assoc group nnsoup-group-alist))))
- (while (and areas (< (cdaar areas) article))
+ (while (and areas (< (cdar (car areas)) article))
(setq areas (cdr areas)))
(and areas (car areas))))
This command is used by the `nntp-open-via-rlogin-and-telnet' method.
The default is \"rsh\", but \"ssh\" is a popular alternative.")
+(defvoo nntp-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\") or (\"-C\" \"-t\") 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.")
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-end-of-line'."
(let ((command `(,nntp-via-address
,nntp-telnet-command
- ,@nntp-telnet-switches
- ,nntp-address ,nntp-port-number))
+ ,@nntp-telnet-switches))
proc)
- (and nntp-via-user-name
- (setq command `("-l" ,nntp-via-user-name ,@command)))
+ (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))
(save-excursion
(set-buffer buffer)
+ (nntp-wait-for-string "^r?telnet")
+ (process-send-string proc (concat "open " nntp-address
+ " " nntp-port-number "\n"))
(nntp-wait-for-string "^\r*20[01]")
(beginning-of-line)
(delete-region (point-min) (point))
(defvoo nnweb-type 'google
"What search engine type is being used.
-Valid types include `google', `dejanews', `dejanewsold', `reference',
-and `altavista'.")
+Valid types include `google', `dejanews', and `gmane'.")
(defvar nnweb-type-definition
'((google
(address . "http://groups.google.com/groups")
(identifier . nnweb-google-identity))
(dejanews ;; alias of google
- ;;(article . nnweb-google-wash-article)
- ;;(id . "http://groups.google.com/groups?as_umsgid=%s")
(article . ignore)
(id . "http://groups.google.com/groups?selm=%s&output=gplain")
- ;;(reference . nnweb-google-reference)
(reference . identity)
(map . nnweb-google-create-mapping)
(search . nnweb-google-search)
(address . "http://groups.google.com/groups")
(identifier . nnweb-google-identity))
- (reference
- (article . nnweb-reference-wash-article)
- (map . nnweb-reference-create-mapping)
- (search . nnweb-reference-search)
- (address . "http://www.reference.com/cgi-bin/pn/go")
- (identifier . identity))
- (altavista
- (article . nnweb-altavista-wash-article)
- (map . nnweb-altavista-create-mapping)
- (search . nnweb-altavista-search)
- (address . "http://www.altavista.digital.com/cgi-bin/query")
- (id . "/cgi-bin/news?id@%s")
- (identifier . 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://gmane.org/")
+ (identifier . nnweb-gmane-identity)))
"Type-definition alist.")
(defvoo nnweb-search nil
- "Search string to feed to DejaNews.")
+ "Search string to feed to Google.")
(defvoo nnweb-max-hits 999
"Maximum number of hits to display.")
nnweb-type nnweb-search server))
(current-buffer))))))
-;; (defun nnweb-fetch-url (url)
-;; (let (buf)
-;; (save-excursion
-;; (if (not nnheader-callback-function)
-;; (progn
-;; (with-temp-buffer
-;; (mm-enable-multibyte)
-;; (let ((coding-system-for-read 'binary)
-;; (coding-system-for-write 'binary)
-;; (default-process-coding-system 'binary))
-;; (nnweb-insert url))
-;; (setq buf (buffer-string)))
-;; (erase-buffer)
-;; (insert buf)
-;; t)
-;; (nnweb-url-retrieve-asynch
-;; url 'nnweb-callback (current-buffer) nnheader-callback-function)
-;; t))))
-
-;; (defun nnweb-callback (buffer callback)
-;; (when (gnus-buffer-live-p url-working-buffer)
-;; (save-excursion
-;; (set-buffer url-working-buffer)
-;; (funcall (nnweb-definition 'article))
-;; (nnweb-decode-entities)
-;; (set-buffer buffer)
-;; (goto-char (point-max))
-;; (insert-buffer-substring url-working-buffer))
-;; (funcall callback t)
-;; (gnus-kill-buffer url-working-buffer)))
-
-;; (defun nnweb-url-retrieve-asynch (url callback &rest data)
-;; (let ((url-request-method "GET")
-;; (old-asynch url-be-asynchronous)
-;; (url-request-data nil)
-;; (url-request-extra-headers nil)
-;; (url-working-buffer (generate-new-buffer-name " *nnweb*")))
-;; (setq-default url-be-asynchronous t)
-;; (save-excursion
-;; (set-buffer (get-buffer-create url-working-buffer))
-;; (setq url-current-callback-data data
-;; url-be-asynchronous t
-;; url-current-callback-func callback)
-;; (url-retrieve url nil))
-;; (setq-default url-be-asynchronous old-asynch)))
-
-;; (if (fboundp 'url-retrieve-synchronously)
-;; (defun nnweb-url-retrieve-asynch (url callback &rest data)
-;; (url-retrieve url callback data)))
-
-;;;
-;;; DejaNews functions.
-;;;
-
-(defun nnweb-dejanews-create-mapping ()
- "Perform the search and create an number-to-url alist."
- (save-excursion
- (set-buffer nnweb-buffer)
- (erase-buffer)
- (when (funcall (nnweb-definition 'search) nnweb-search)
- (let ((i 0)
- (more t)
- (case-fold-search t)
- (active (or (cadr (assoc nnweb-group nnweb-group-alist))
- (cons 1 0)))
- subject date from
- map url parse a table group text)
- (while more
- ;; Go through all the article hits on this page.
- (goto-char (point-min))
- (setq parse (w3-parse-buffer (current-buffer))
- table (nth 1 (nnweb-parse-find-all 'table parse)))
- (dolist (row (nth 2 (car (nth 2 table))))
- (setq a (nnweb-parse-find 'a row)
- url (cdr (assq 'href (nth 1 a)))
- text (nreverse (nnweb-text row)))
- (when a
- (setq subject (nth 4 text)
- group (nth 2 text)
- date (nth 1 text)
- from (nth 0 text))
- (if (string-match "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)" date)
- (setq date (format "%s %s 00:00:00 %s"
- (car (rassq (string-to-number
- (match-string 2 date))
- parse-time-months))
- (match-string 3 date)
- (match-string 1 date)))
- (setq date "Jan 1 00:00:00 0000"))
- (incf i)
- (setq url (concat url "&fmt=text"))
- (when (string-match "&context=[^&]+" url)
- (setq url (replace-match "" t t url)))
- (unless (nnweb-get-hashtb url)
- (push
- (list
- (incf (cdr active))
- (make-full-mail-header
- (cdr active) (concat subject " (" group ")") from date
- (concat "<" (nnweb-identifier url) "@dejanews>")
- nil 0 0 url))
- map)
- (nnweb-set-hashtb (cadar map) (car map)))))
- ;; See whether there is a "Get next 20 hits" button here.
- (goto-char (point-min))
- (if (or (not (re-search-forward
- "HREF=\"\\([^\"]+\\)\"[<>b]+Next result" nil t))
- (>= i nnweb-max-hits))
- (setq more nil)
- ;; Yup -- fetch it.
- (setq more (match-string 1))
- (erase-buffer)
- (mm-url-insert more)))
- ;; Return the articles in the right order.
- (setq nnweb-articles
- (sort (nconc nnweb-articles map) 'car-less-than-car))))))
-
-(defun nnweb-dejanews-search (search)
- (mm-url-insert
- (concat
- (nnweb-definition 'address)
- "?"
- (mm-url-encode-www-form-urlencoded
- `(("ST" . "PS")
- ("svcclass" . "dnyr")
- ("QRY" . ,search)
- ("defaultOp" . "AND")
- ("DBS" . "1")
- ("OP" . "dnquery.xp")
- ("LNG" . "ALL")
- ("maxhits" . "100")
- ("threaded" . "0")
- ("format" . "verbose2")
- ("showsort" . "date")
- ("agesign" . "1")
- ("ageweight" . "1")))))
- t)
-
-;; (defun nnweb-dejanewsold-search (search)
-;; (nnweb-fetch-form
-;; (nnweb-definition 'address)
-;; `(("query" . ,search)
-;; ("defaultOp" . "AND")
-;; ("svcclass" . "dnold")
-;; ("maxhits" . "100")
-;; ("format" . "verbose2")
-;; ("threaded" . "0")
-;; ("showsort" . "date")
-;; ("agesign" . "1")
-;; ("ageweight" . "1")))
-;; t)
-
-(defun nnweb-dejanews-identity (url)
- "Return an unique identifier based on URL."
- (if (string-match "AN=\\([0-9]+\\)" url)
- (match-string 1 url)
- url))
-
-;;;
-;;; InReference
-;;;
-
-(defun nnweb-reference-create-mapping ()
- "Perform the search and create an number-to-url alist."
- (save-excursion
- (set-buffer nnweb-buffer)
- (erase-buffer)
- (when (funcall (nnweb-definition 'search) nnweb-search)
- (let ((i 0)
- (more t)
- (case-fold-search t)
- (active (or (cadr (assoc nnweb-group nnweb-group-alist))
- (cons 1 0)))
- Subject Score Date Newsgroups From Message-ID
- map url)
- (while more
- ;; Go through all the article hits on this page.
- (goto-char (point-min))
- (search-forward "</pre><hr>" nil t)
- (delete-region (point-min) (point))
- (goto-char (point-min))
- (while (re-search-forward "^ +[0-9]+\\." nil t)
- (narrow-to-region
- (point)
- (if (re-search-forward "^$" nil t)
- (match-beginning 0)
- (point-max)))
- (goto-char (point-min))
- (when (looking-at ".*href=\"\\([^\"]+\\)\"")
- (setq url (match-string 1)))
- (mm-url-remove-markup)
- (goto-char (point-min))
- (while (search-forward "\t" nil t)
- (replace-match " "))
- (goto-char (point-min))
- (while (re-search-forward "^\\([^:]+\\): \\(.*\\)$" nil t)
- (set (intern (match-string 1)) (match-string 2)))
- (widen)
- (search-forward "</pre>" nil t)
- (incf i)
- (unless (nnweb-get-hashtb url)
- (push
- (list
- (incf (cdr active))
- (make-full-mail-header
- (cdr active) (concat "(" Newsgroups ") " Subject) From Date
- Message-ID
- nil 0 (string-to-int Score) url))
- map)
- (nnweb-set-hashtb (cadar map) (car map))))
- (setq more nil))
- ;; Return the articles in the right order.
- (setq nnweb-articles
- (sort (nconc nnweb-articles map) 'car-less-than-car))))))
-
-(defun nnweb-reference-wash-article ()
- (let ((case-fold-search t))
- (goto-char (point-min))
- (re-search-forward "^</center><hr>" nil t)
- (delete-region (point-min) (point))
- (search-forward "<pre>" nil t)
- (forward-line -1)
- (let ((body (point-marker)))
- (search-forward "</pre>" nil t)
- (delete-region (point) (point-max))
- (mm-url-remove-markup)
- (goto-char (point-min))
- (while (looking-at " *$")
- (gnus-delete-line))
- (narrow-to-region (point-min) body)
- (while (and (re-search-forward "^$" nil t)
- (not (eobp)))
- (gnus-delete-line))
- (goto-char (point-min))
- (while (looking-at "\\(^[^ ]+:\\) *")
- (replace-match "\\1 " t)
- (forward-line 1))
- (goto-char (point-min))
- (when (re-search-forward "^References:" nil t)
- (narrow-to-region
- (point) (if (re-search-forward "^$\\|^[^:]+:" nil t)
- (match-beginning 0)
- (point-max)))
- (goto-char (point-min))
- (while (not (eobp))
- (unless (looking-at "References")
- (insert "\t")
- (forward-line 1)))
- (goto-char (point-min))
- (while (search-forward "," nil t)
- (replace-match " " t t)))
- (widen)
- (mm-url-decode-entities)
- (set-marker body nil))))
-
-(defun nnweb-reference-search (search)
- (mm-url-insert
- (concat
- (nnweb-definition 'address)
- "?"
- (mm-url-encode-www-form-urlencoded
- `(("search" . "advanced")
- ("querytext" . ,search)
- ("subj" . "")
- ("name" . "")
- ("login" . "")
- ("host" . "")
- ("organization" . "")
- ("groups" . "")
- ("keywords" . "")
- ("choice" . "Search")
- ("startmonth" . "Jul")
- ("startday" . "25")
- ("startyear" . "1996")
- ("endmonth" . "Aug")
- ("endday" . "24")
- ("endyear" . "1996")
- ("mode" . "Quick")
- ("verbosity" . "Verbose")
- ("ranking" . "Relevance")
- ("first" . "1")
- ("last" . "25")
- ("score" . "50")))))
- (setq buffer-file-name nil)
- t)
-
-;;;
-;;; Alta Vista
-;;;
-
-(defun nnweb-altavista-create-mapping ()
- "Perform the search and create an number-to-url alist."
- (save-excursion
- (set-buffer nnweb-buffer)
- (erase-buffer)
- (let ((part 0))
- (when (funcall (nnweb-definition 'search) nnweb-search part)
- (let ((i 0)
- (more t)
- (case-fold-search t)
- (active (or (cadr (assoc nnweb-group nnweb-group-alist))
- (cons 1 0)))
- subject date from id group
- map url)
- (while more
- ;; Go through all the article hits on this page.
- (goto-char (point-min))
- (search-forward "<dt>" nil t)
- (delete-region (point-min) (match-beginning 0))
- (goto-char (point-min))
- (while (search-forward "<dt>" nil t)
- (replace-match "\n<blubb>"))
- (mm-url-decode-entities)
- (goto-char (point-min))
- (while (re-search-forward "<blubb>.*href=\"\\([^\"]+\\)\"><strong>\\([^>]*\\)</strong></a><dd>\\([^-]+\\)- <b>\\([^<]+\\)<.*href=\"news:\\([^\"]+\\)\">.*\">\\(.+\\)</a><P>"
- nil t)
- (setq url (match-string 1)
- subject (match-string 2)
- date (match-string 3)
- group (match-string 4)
- id (concat "<" (match-string 5) ">")
- from (match-string 6))
- (incf i)
- (unless (nnweb-get-hashtb url)
- (push
- (list
- (incf (cdr active))
- (make-full-mail-header
- (cdr active) (concat "(" group ") " subject) from date
- id nil 0 0 url))
- map)
- (nnweb-set-hashtb (cadar map) (car map))))
- ;; See if we want more.
- (when (or (not nnweb-articles)
- (>= i nnweb-max-hits)
- (not (funcall (nnweb-definition 'search)
- nnweb-search (incf part))))
- (setq more nil)))
- ;; Return the articles in the right order.
- (setq nnweb-articles
- (sort (nconc nnweb-articles map) 'car-less-than-car)))))))
-
-(defun nnweb-altavista-wash-article ()
- (goto-char (point-min))
- (let ((case-fold-search t))
- (when (re-search-forward "^<strong>" nil t)
- (delete-region (point-min) (match-beginning 0)))
- (goto-char (point-min))
- (while (looking-at "<strong>\\([^ ]+\\) +</strong> +\\(.*\\)$")
- (replace-match "\\1: \\2" t)
- (forward-line 1))
- (when (re-search-backward "^References:" nil t)
- (narrow-to-region (point) (progn (forward-line 1) (point)))
- (goto-char (point-min))
- (while (re-search-forward "<A.*\\?id@\\([^\"]+\\)\">[0-9]+</A>" nil t)
- (replace-match "<\\1> " t)))
- (widen)
- (mm-url-remove-markup)
- (mm-url-decode-entities)))
-
-(defun nnweb-altavista-search (search &optional part)
- (mm-url-insert
- (concat
- (nnweb-definition 'address)
- "?"
- (mm-url-encode-www-form-urlencoded
- `(("pg" . "aq")
- ("what" . "news")
- ,@(when part `(("stq" . ,(int-to-string (* part 30)))))
- ("fmt" . "d")
- ("q" . ,search)
- ("r" . "")
- ("d0" . "")
- ("d1" . "")))))
- (setq buffer-file-name nil)
- t)
-
;;;
;;; Deja bought by google.com
;;;
(set-buffer nnweb-buffer)
(erase-buffer)
(when (funcall (nnweb-definition 'search) nnweb-search)
- (let ((more t))
+ (let ((more t)
+ (i 0))
(while more
(setq nnweb-articles
(nconc nnweb-articles (nnweb-google-parse-1)))
- ;; FIXME: There is more.
- (setq more nil))
+ ;; Check if there are more articles to fetch
+ (goto-char (point-min))
+ (incf i 100)
+ (if (or (not (re-search-forward
+ "<td nowrap><a href=\\([^>]+\\).*<span class=b>Next</span>" nil t))
+ (>= i nnweb-max-hits))
+ (setq more nil)
+ ;; Yup, there are more articles
+ (setq more (concat "http://groups.google.com" (match-string 1)))
+ (when more
+ (erase-buffer)
+ (mm-url-insert more))))
;; Return the articles in the right order.
(setq nnweb-articles
(sort nnweb-articles 'car-less-than-car))))))
url))
;;;
+;;; gmane.org
+;;;
+(defun nnweb-gmane-create-mapping ()
+ "Perform the search and create a number-to-url alist."
+ (save-excursion
+ (set-buffer nnweb-buffer)
+ (erase-buffer)
+ (when (funcall (nnweb-definition 'search) nnweb-search)
+ (let ((more t)
+ (case-fold-search t)
+ (active (or (cadr (assoc nnweb-group nnweb-group-alist))
+ (cons 1 0)))
+ subject group url
+ map)
+ ;; Remove stuff from the beginning of results
+ (goto-char (point-min))
+ (search-forward "Search Results</h1><ul>" nil t)
+ (delete-region (point-min) (point))
+ (goto-char (point-min))
+ ;; Iterate over the actual hits
+ (while (re-search-forward ".*href=\"\\([^\"]+\\)\">\\(.*\\)" nil t)
+ (setq url (concat "http://gmane.org/" (match-string 1)))
+ (setq subject (match-string 2))
+ (unless (nnweb-get-hashtb url)
+ (push
+ (list
+ (incf (cdr active))
+ (make-full-mail-header
+ (cdr active) (concat "(" group ") " subject) nil nil
+ nil nil 0 0 url))
+ map)
+ (nnweb-set-hashtb (cadar map) (car map))))
+ ;; Return the articles in the right order.
+ (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))
+ (re-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)))))
+ (setq buffer-file-name nil)
+ 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/w3 interface utility functions
;;;
mailhost)))
(erase-buffer)
(setq pop3-read-point (point-min))
- (setq process (open-network-stream "POP"(current-buffer) mailhost port))
+ (setq process (open-network-stream "POP" (current-buffer) mailhost port))
(let ((response (pop3-read-response process t)))
(setq pop3-timestamp
(substring response (or (string-match "<" response) 0)
;;
;; `sieve-manage-authenticate'
;; `sieve-manage-listscripts'
+;; `sieve-manage-deletescript'
+;; `sieve-manage-getscript'
;; performs managesieve protocol actions
;;
;; and that's it. Example of a managesieve session in *scratch*:
;; Release history:
;;
;; 2001-10-31 Committed to Oort Gnus.
-;;
-;; $Id: sieve-manage.el,v 1.1.1.2 2002-05-06 23:49:27 yamaoka Exp $
+;; 2002-07-27 Added DELETESCRIPT. Suggested by Ned Ludd.
;;; Code:
(let* ((done (sieve-manage-interactive-login
buffer
(lambda (user passwd)
- (sieve-manage-send "AUTHENTICATE \"CRAM-MD5\" \"\"")
+ (sieve-manage-send "AUTHENTICATE \"CRAM-MD5\"")
(sieve-manage-send
(concat
"\""
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))
;; version 1.1 change file extension into ".siv" (official one)
;; added keymap and menubar to hook into sieve-manage
;; 2001-10-31 version 1.2 committed to Oort Gnus
-;;
-;; $Id: sieve-mode.el,v 1.1.1.2 2002-05-06 23:49:27 yamaoka Exp $
;;; Code:
-(autoload 'sieve-manage "sieve-manage")
-(autoload 'sieve-upload "sieve-manage")
+(autoload 'sieve-manage "sieve")
+(autoload 'sieve-upload "sieve")
(require 'easymenu)
(eval-when-compile
(require 'font-lock))
;; Release history:
;;
;; 2001-10-31 Committed to Oort Gnus.
-;;
-;; $Id: sieve.el,v 1.1.1.2 2002-05-06 23:49:27 yamaoka Exp $
+;; 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:
;;
(define-key sieve-manage-mode-map "f" 'sieve-edit-script)
(define-key sieve-manage-mode-map "o" 'sieve-edit-script-other-window)
(define-key sieve-manage-mode-map "r" 'sieve-remove)
- (define-key sieve-manage-mode-map [mouse-2] 'sieve-edit-script)
- (define-key sieve-manage-mode-map [(down-mouse-3)] 'sieve-menu))
+ (define-key sieve-manage-mode-map [(down-mouse-2)] 'sieve-edit-script)
+ (define-key sieve-manage-mode-map [(down-mouse-3)] 'sieve-manage-mode-menu))
(define-derived-mode sieve-manage-mode fundamental-mode "SIEVE"
"Mode used for sieve script management."
(setq mode-name "SIEVE")
(buffer-disable-undo (current-buffer))
- (setq truncate-lines t))
+ (setq truncate-lines t)
+ (easy-menu-add-item nil nil sieve-manage-mode-menu))
(put 'sieve-manage-mode 'mode-class 'special)
(defun sieve-activate (&optional pos)
(interactive "d")
(let ((name (sieve-script-at-point)) err)
- (unless name
+ (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 "Script %s activated." name)
- (message "Failed to activate script %s: %s" name (nth 2 err)))
- (sieve-refresh-scriptlist)))
+ (message "Deactivating scripts...done")
+ (message "Deactivating scripts...failed" (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")
(sieve-mode)
(message "Press C-c C-l 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
;; would need minor-mode for log-edit-mode
(describe-function 'sieve-mode)
(message (substitute-command-keys
- "`\\[sieve-help]':help `\\[cvs-mode-add]':add `\\[sieve-remove]':remove"))))
+ "`\\[sieve-edit-script]':edit `\\[sieve-activate]':activate `\\[sieve-deactivate]':deactivate `\\[sieve-remove]':remove"))))
(defun sieve-bury-buffer (buf &optional mainbuf)
"Hide the buffer BUF that was temporarily popped up.
(interactive "d")
(get-char-property (or pos (point)) 'script-name))
-(defmacro sieve-change-region (&rest body)
- "Turns off sieve-region before executing BODY, then re-enables it after.
-Used to bracket operations which move point in the sieve-buffer."
- `(progn
- (sieve-highlight nil)
- ,@body
- (sieve-highlight t)))
-(put 'sieve-change-region 'lisp-indent-function 0)
-
(eval-and-compile
(defalias 'sieve-make-overlay (if (fboundp 'make-overlay)
'make-overlay
"relays.visi.com" "rbl.maps.vix.com")
"List of blackhole servers.")
+(defvar spam-split-group "spam" "Default group name for spam-split.")
+
(defun spam-check-blackholes ()
- "Check the Recevieved headers for blackholed relays."
+ "Check the Receieved headers for blackholed relays."
(let ((headers (message-fetch-field "received"))
ips matches)
- (with-temp-buffer
- (insert headers)
- (goto-char (point-min))
- (while (re-search-forward
- "\\[\\([0-9]+.[0-9]+.[0-9]+.[0-9]+\\)\\]" nil t)
- (push (mapconcat 'identity
- (nreverse (split-string (match-string 1) "\\."))
- ".")
- ips)))
- (dolist (server spam-blackhole-servers)
- (dolist (ip ips)
- (when (query-dns (concat ip "." server))
- (push (list ip server (query-dns (concat ip "." server) 'TXT))
- matches))))
- matches))
+ (when headers
+ (with-temp-buffer
+ (insert headers)
+ (goto-char (point-min))
+ (while (re-search-forward
+ "\\[\\([0-9]+.[0-9]+.[0-9]+.[0-9]+\\)\\]" nil t)
+ (message "blackhole search found host IP %s" (match-string 1))
+ (push (mapconcat 'identity
+ (nreverse (split-string (match-string 1) "\\."))
+ ".")
+ ips)))
+ (dolist (server spam-blackhole-servers)
+ (dolist (ip ips)
+ (when (query-dns (concat ip "." server))
+ (push (list ip server (query-dns (concat ip "." server) 'TXT))
+ matches))))
+ matches)))
;;; Black- and white-lists
"The location of the whitelist.
The file format is one regular expression per line.
The regular expression is matched against the address.")
-
+
(defvar spam-blacklist (expand-file-name "blacklist" spam-directory)
"The location of the blacklist.
The file format is one regular expression per line.
(unless (bobp)
(insert "\n"))
(insert address "\n")
- (save-buffer))))
+ (save-buffer)
+ (spam-refresh-list-cache))))
(defun spam-enter-blacklist (address)
"Enter ADDRESS into the blacklist."
(interactive "sAddress: ")
(spam-enter-whitelist address t))
+(eval-and-compile
+ (defalias 'spam-point-at-eol (if (fboundp 'point-at-eol)
+ 'point-at-eol
+ 'line-end-position)))
+
(defun spam-parse-whitelist (&optional blacklist)
(let ((file (if blacklist spam-blacklist spam-whitelist))
contents address)
(with-temp-buffer
(insert-file-contents file)
(while (not (eobp))
- (setq address (buffer-substring (point) (point-at-eol)))
+ (setq address (buffer-substring (point) (spam-point-at-eol)))
(forward-line 1)
(unless (zerop (length address))
(setq address (regexp-quote address))
(setq found t)))
found))
+(defun spam-address-blacklisted-p (address &optional blacklist)
+ (if address
+ (spam-address-whitelisted-p address t)
+ nil))
+
+;; Function for nnmail-split-fancy: returns 'spam' if an article is deemed to be spam
+(defun spam-split ()
+ "Split this message into the `spam' group if it is spam.
+This function can be used as an entry in `nnmail-split-fancy', for
+example like this: (: spam-split)
+
+See the Info node `(gnus)Fancy Mail Splitting' for more details."
+ (interactive)
+
+ ;; refresh the cache if it's necessary
+ (unless spam-whitelist-cache (spam-refresh-list-cache))
+ (unless spam-blacklist-cache (spam-refresh-list-cache))
+
+ (let* ((from (message-fetch-field "from"))
+ (group nil))
+ (when (spam-check-blackholes)
+ (setq group spam-split-group))
+ (unless (spam-address-whitelisted-p from) ; unless the address is whitelisted,
+ (when (spam-address-blacklisted-p from) ; check if it's blacklisted,
+ (setq group spam-split-group)) ; and if so, set the group to spam-split-group
+ group)))
+
(provide 'spam)
;;; spam.el ends here
;; This module defines some utility functions for STARTTLS profiles.
+;; Get "starttls" from ftp://ftp.opaopa.org/pub/elisp/.
+
;; [RFC 2595] "Using TLS with IMAP, POP3 and ACAP"
;; by Chris Newman <chris.newman@innosoft.com> (1999/06)
+2002-08-04 Lars Magne Ingebrigtsen <larsi@gnus.org>
+
+ * gnus.texi (Summary Sorting): Document randomization.
+
+2002-07-28 Kai Gro\e,b_\e(Bjohann <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-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\e,b_\e(Bjohann <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\e,b_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+ * gnus.texi (Washing Mail): Document the shortcoming of
+ nnmail-remove-leading-whitespace.
+
+2002-06-30 Kai Gro\e,b_\e(Bjohann <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\e,b_\e(Bjohann <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\e,b_\e(Bjohann <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\e,A_\e(Bjohann <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
*.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
+ thumbdta.tex xface.tex *.tpt gnus-manual-*.pdf gnus-manual-*.ps.gz
makeinfo:
makeinfo -o gnus gnus.texi
latexboth: gnus-manual-a4.ps.gz gnus-manual-standard.ps.gz
out:
- cp gnus-manual-standard.ps.gz \
- gnus-manual-a4.ps.gz \
- /local/ftp/pub/emacs/gnus/manual
- mv gnus-manual-standard.ps.gz \
- gnus-manual-a4.ps.gz \
- /hom/larsi/www_docs/www.gnus.org/documents
+ scp gnus-manual-*.ps.gz gnus-manual-*.pdf
+ www@quimby:html/gnus/documents
veryclean: clean
rm -f gnus.dvi gnus.ps texi2latex.elc
This manual documents the libraries used to compose and display
@sc{mime} messages.
-This is not a manual meant for users; it's a manual directed at people
-who want to write functions and commands that manipulate @sc{mime}
-elements.
+This manual is directed at users who want to modify the behaviour of
+the MIME encoding/decoding process or want a more detailed picture of
+how the Emacs MIME library works, and people who want to write
+functions and commands that manipulate @sc{mime} elements.
@sc{mime} is short for @dfn{Multipurpose Internet Mail Extensions}.
This standard is documented in a number of RFCs; mainly RFC2045 (Format
read at least RFC2045 and RFC2047.
@menu
-* Interface Functions:: An abstraction over the basic functions.
-* Basic Functions:: Utility and basic parsing functions.
* Decoding and Viewing:: A framework for decoding and viewing.
* Composing:: MML; a language for describing @sc{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.
* Index:: Function and variable index.
@end menu
-@node Interface Functions
-@chapter Interface Functions
-@cindex interface functions
-@cindex mail-parse
+@node Decoding and Viewing
+@chapter Decoding and Viewing
-The @code{mail-parse} library is an abstraction over the actual
-low-level libraries that are described in the next chapter.
+This chapter deals with decoding and viewing @sc{mime} messages on a
+higher level.
-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 ASCII characters in the
-parameter list. RFC2231 expands on RFC2045 syntax to provide a scheme
-for continuation headers and non-ASCII characters.
+The main idea is to first analyze a @sc{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.
-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.
+@menu
+* Dissection:: Analyzing a @sc{mime} message.
+* Non-MIME:: Analyzing a non-@sc{mime} message.
+* Handles:: Handle manipulations.
+* Display:: Displaying handles.
+* Display Customization:: Variables that affect display.
+* New Viewers:: How to write your own viewers.
+@end menu
-The Emacs @sc{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:
+@node Dissection
+@section Dissection
-@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:
+The @code{mm-dissect-buffer} is the function responsible for dissecting
+a @sc{mime} article. If given a multipart message, it will recursively
+descend the message, following the structure, and return a tree of
+@sc{mime} handles that describes the structure of the message.
+
+@node Non-MIME
+@section Non-MIME
+
+Gnus also understands some non-@sc{mime} attachments, such as
+postscript, uuencode, binhex, shar, forward, gnatsweb, pgp. Each of
+these features can be disabled by add an item into
+@code{mm-uu-configure-list}. For example,
@lisp
-("type/subtype"
- (attribute1 . value1)
- (attribute2 . value2)
- ...)
+(require 'mm-uu)
+(add-to-list 'mm-uu-configure-list '(pgp-signed . disabled))
@end lisp
-Here's an example:
+@table @code
+@item postscript
+@findex postscript
+Postscript file.
-@example
-(mail-header-parse-content-type
- "image/gif; name=\"b980912.gif\"")
-@result{} ("image/gif" (name . "b980912.gif"))
-@end example
+@item uu
+@findex uu
+Uuencoded file.
-@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 binhex
+@findex binhex
+Binhex encoded file.
-@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.
+@item shar
+@findex shar
+Shar archive file.
-@example
-(mail-content-type-get
- '("image/gif" (name . "b980912.gif")) 'name)
-@result{} "b980912.gif"
-@end example
+@item forward
+@findex forward
+Non-@sc{mime} forwarded message.
-@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 gnatsweb
+@findex gnatsweb
+Gnatsweb attachment.
-@item mail-header-remove-comments
-@findex mail-header-remove-comments
-Return a comment-free version of a header.
+@item pgp-signed
+@findex pgp-signed
+PGP signed clear text.
-@example
-(mail-header-remove-comments
- "Gnus/5.070027 (Pterodactyl Gnus v0.27) (Finnish Landrace)")
-@result{} "Gnus/5.070027 "
-@end example
+@item pgp-encrypted
+@findex pgp-encrypted
+PGP encrypted clear text.
-@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.
+@item pgp-key
+@findex pgp-key
+PGP public keys.
-@example
-(mail-header-remove-whitespace
- "image/gif; name=\"Name with spaces\"")
-@result{} "image/gif;name=\"Name with spaces\""
-@end example
+@item emacs-sources
+@findex emacs-sources
+Emacs source code. This item works only in the groups matching
+@code{mm-uu-emacs-sources-regexp}.
-@item mail-header-get-comment
-@findex mail-header-get-comment
-Return the last comment in a header.
+@end table
-@example
-(mail-header-get-comment
- "Gnus/5.070027 (Pterodactyl Gnus v0.27) (Finnish Landrace)")
-@result{} "Finnish Landrace"
-@end example
+@node Handles
+@section Handles
-@item mail-header-parse-address
-@findex mail-header-parse-address
-Parse an address and return a list containing the mailbox and the
-plaintext name.
+A @sc{mime} handle is a list that fully describes a @sc{mime}
+component.
-@example
-(mail-header-parse-address
- "Hrvoje Niksic <hniksic@@srce.hr>")
-@result{} ("hniksic@@srce.hr" . "Hrvoje Niksic")
-@end example
+The following macros can be used to access elements in a handle:
-@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.
+@table @code
+@item mm-handle-buffer
+@findex mm-handle-buffer
+Return the buffer that holds the contents of the undecoded @sc{mime}
+part.
-@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 mm-handle-type
+@findex mm-handle-type
+Return the parsed @code{Content-Type} of the part.
-@item mail-header-parse-date
-@findex mail-header-parse-date
-Parse a date string and return an Emacs time structure.
+@item mm-handle-encoding
+@findex mm-handle-encoding
+Return the @code{Content-Transfer-Encoding} of the part.
-@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 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 mail-header-narrow-to-field
-@findex mail-header-narrow-to-field
-Narrow the buffer to the header under point. Understands continuation
-headers.
+@item mm-handle-set-undisplayer
+@findex mm-handle-set-undisplayer
+Set the undisplayer object.
-@item mail-header-fold-field
-@findex mail-header-fold-field
-Fold the header under point.
+@item mm-handle-disposition
+@findex mm-handle-disposition
+Return the parsed @code{Content-Disposition} of the part.
-@item mail-header-unfold-field
-@findex mail-header-unfold-field
-Unfold the header under point.
+@item mm-handle-disposition
+@findex mm-handle-disposition
+Return the description of the part.
-@item mail-header-field-value
-@findex mail-header-field-value
-Return the value of the field under point.
+@item mm-get-content-id
+Returns the handle(s) referred to by @code{Content-ID}.
-@item mail-encode-encoded-word-region
-@findex mail-encode-encoded-word-region
-Encode the non-ASCII words in the region. For instance,
-@samp{Naïve} is encoded as @samp{=?iso-8859-1?q?Na=EFve?=}.
+@end table
-@item mail-encode-encoded-word-buffer
-@findex mail-encode-encoded-word-buffer
-Encode the non-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.
+@node Display
+@section Display
-@example
-(mail-encode-encoded-word-string
- "This is naïve, baby")
-@result{} "This is =?iso-8859-1?q?na=EFve,?= baby"
-@end example
+Functions for displaying, removing and saving.
-@item mail-decode-encoded-word-region
-@findex mail-decode-encoded-word-region
-Decode the encoded words in the region.
+@table @code
+@item mm-display-part
+@findex mm-display-part
+Display the part.
-@item mail-decode-encoded-word-string
-@findex mail-decode-encoded-word-string
-Decode the encoded words in the string and return the result.
+@item mm-remove-part
+@findex mm-remove-part
+Remove the part (if it has been displayed).
-@example
-(mail-decode-encoded-word-string
- "This is =?iso-8859-1?q?na=EFve,?= baby")
-@result{} "This is naïve, baby"
-@end example
+@item mm-inlinable-p
+@findex mm-inlinable-p
+Say whether a @sc{mime} type can be displayed inline.
-@end table
+@item mm-automatic-display-p
+@findex mm-automatic-display-p
+Say whether a @sc{mime} type should be displayed automatically.
-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.
+@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.
-@node Basic Functions
-@chapter Basic Functions
+@item mm-interactively-view-part
+@findex mm-interactively-view-part
+Prompt for a mailcap method to use to view the part.
-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 next chapter
-(@pxref{Decoding and Viewing}).
+@end table
-@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.
-* rfc1843:: Decoding HZ-encoded text.
-* mailcap:: How parts are displayed is specified by the @file{.mailcap} file
-@end menu
+@node Display Customization
+@section Display Customization
-@node rfc2045
-@section rfc2045
+@table @code
-RFC2045 is the ``main'' @sc{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.
+@item mm-inline-media-tests
+This is an alist where the key is a @sc{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.
-So @file{rfc2045.el} has only a single function:
+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.
-@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
+@item 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
+@sc{mime} media types.
+@item 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.
-@node rfc2231
-@section rfc2231
+@item mm-attachment-override-types
+Some @sc{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.)
-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}.
+@item mm-discouraged-alternatives
+List of @sc{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/richtech} parts are somewhat unwanted,
+you could say something like:
-In short, these headers look something like this:
+@lisp
+(setq mm-discouraged-alternatives
+ '("text/html" "text/richtext")
+ mm-automatic-display
+ (remove "text/html" mm-automatic-display))
+@end lisp
-@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
+@item mm-inline-large-images-p
+When displaying inline images that are larger than the window, XEmacs
+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.
-They usually aren't this bad, though.
+@item mm-inline-override-type
+@code{mm-inlined-types} may include regular expressions, for example to
+specify that all @samp{text/.*} parts be displayed inline. If a user
+prefers to have a type that matches such a regular expression be treated
+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.
-The following functions are defined by this library:
+@item mm-inline-text-html-renderer
+This selects the function used to render @sc{html}. The predefined
+renderers are selected by the symbols @code{w3},
+@code{w3m}@footnote{See @uref{http://emacs-w3m.namazu.org/} for more
+information about emacs-w3m}, @code{links}, @code{lynx} or
+@code{html2text}. You can also specify a function, which will be
+called with a @sc{mime} handle as the argument.
-@table @code
-@item rfc2231-parse-string
-@findex rfc2231-parse-string
-Parse a @code{Content-Type} header and return a list describing its
-elements.
+@item mm-inline-text-html-with-images
+Some @sc{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 informations from
+leaking by setting this option to @code{nil} (which is the default).
+It is currently ignored by Emacs/w3. 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.}
-@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 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 rfc2231-get-value
-@findex rfc2231-get-value
-Takes one of the lists on the format above and returns
-the value of the specified attribute.
+@end table
-@item rfc2231-encode-string
-@findex rfc2231-encode-string
-Encode a parameter in headers likes @code{Content-Type} and
-@code{Content-Disposition}.
-@end table
+@node New Viewers
+@section New Viewers
+Here's an example viewer for displaying @code{text/enriched} inline:
-@node ietf-drums
-@section ietf-drums
+@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
-@dfn{drums} is an IETF working group that is working on the replacement
-for RFC822.
+We see that the function takes a @sc{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 functions provided by this library include:
+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.
-@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.
+@node Composing
+@chapter Composing
+@cindex Composing
+@cindex MIME Composing
+@cindex MML
+@cindex MIME Meta Language
-@item ietf-drums-get-comment
-@findex ietf-drums-get-comment
-Return the last most comment from the string.
+Creating a @sc{mime} message is boring and non-trivial. Therefore, a
+library called @code{mml} has been defined that parses a language called
+MML (@sc{mime} Meta Language) and generates @sc{mime} messages.
-@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.
+@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 @sc{mime} message.
-@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.
+@menu
+* Simple MML Example:: An example MML document.
+* MML Definition:: All valid MML elements.
+* Advanced MML Example:: Another example MML document.
+* Encoding Customization:: Variables that affect encoding.
+* Charset Translation:: How charsets are mapped from @sc{mule} to @sc{mime}.
+* Conversion:: Going from @sc{mime} to MML and vice versa.
+* Flowed text:: Soft and hard newlines.
+@end menu
-@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.
+@node Simple MML Example
+@section Simple MML Example
-@end table
+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
-@node rfc2047
-@section rfc2047
+After running this through @code{mml-generate-mime}, we get this:
-RFC2047 (Message Header Extensions for Non-ASCII Text) specifies how
-non-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.
+@example
+Content-Type: multipart/alternative; boundary="=-=-="
-The following variables are tweakable:
-@table @code
-@item rfc2047-default-charset
-@vindex rfc2047-default-charset
-Characters in this charset should not be decoded by this library.
-This defaults to @code{iso-8859-1}.
+--=-=-=
-@item rfc2047-header-encoding-list
-@vindex rfc2047-header-encoding-list
-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}.
+This is a plain text part.
-The values can be either @code{nil}, in which case the header(s) in
-question won't be encoded, or @code{mime}, which means that they will be
-encoded.
+--=-=-=
+Content-Type: text/enriched
-@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-encoding-function-alist
-@vindex rfc2047-encoding-function-alist
-This is an alist of encoding / function pairs. The encodings are
-@code{Q}, @code{B} and @code{nil}.
+<center>This is a centered enriched part</center>
-@item rfc2047-q-encoding-alist
-@vindex rfc2047-q-encoding-alist
-The @code{Q} encoding isn't quite the same for all headers. Some
-headers allow a narrower range of characters, and that is what this
-variable is for. It's an alist of header regexps / allowable character
-ranges.
+--=-=-=--
+@end example
-@item rfc2047-encoded-word-regexp
-@vindex rfc2047-encoded-word-regexp
-When decoding words, this library looks for matches to this regexp.
-@end table
+@node MML Definition
+@section MML Definition
-Those were the variables, and these are this functions:
+The MML language is very simple. It looks a bit like an SGML
+application, but it's not.
-@table @code
-@item rfc2047-narrow-to-field
-@findex rfc2047-narrow-to-field
-Narrow the buffer to the header on the current line.
+The main concept of 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.
-@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}.
+There's also the @samp{<#external ...>} tag. These introduce
+@samp{external/message-body} parts.
-@item rfc2047-encode-region
-@findex rfc2047-encode-region
-Encodes all encodable words in the region specified.
+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.
-@item rfc2047-encode-string
-@findex rfc2047-encode-string
-Encode a string and return the results.
+The following parameters have meaning in MML; parameters that have no
+meaning are ignored. The MML parameter names are the same as the
+@sc{mime} parameter names; the things in the parentheses say which
+header it will be used in.
-@item rfc2047-decode-region
-@findex rfc2047-decode-region
-Decode the encoded words in the region.
+@table @samp
+@item type
+The @sc{mime} type of the part (@code{Content-Type}).
-@item rfc2047-decode-string
-@findex rfc2047-decode-string
-Decode a string and return the results.
+@item filename
+Use the contents of the file in the body of the part
+(@code{Content-Disposition}).
-@end table
+@item charset
+The contents of the body of the part are to be encoded in the character
+set speficied (@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}).
-@node time-date
-@section time-date
+@item disposition
+Valid values are @samp{inline} and @samp{attachment}
+(@code{Content-Disposition}).
-While not really a part of the @sc{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.)
+@item encoding
+Valid values are @samp{7bit}, @samp{8bit}, @samp{quoted-printable} and
+@samp{base64} (@code{Content-Transfer-Encoding}). @xref{Charset
+Translation}.
-These functions convert between five formats: A date string, an Emacs
-time structure, a decoded time list, a second number, and a day number.
+@item description
+A description of the part (@code{Content-Description}).
-Here's a bunch of time/date/second/day examples:
+@item creation-date
+RFC822 date when the part was created (@code{Content-Disposition}).
-@example
-(parse-time-string "Sat Sep 12 12:21:54 1998 +0200")
-@result{} (54 21 12 12 9 1998 6 nil 7200)
+@item modification-date
+RFC822 date when the part was modified (@code{Content-Disposition}).
-(date-to-time "Sat Sep 12 12:21:54 1998 +0200")
-@result{} (13818 19266)
+@item read-date
+RFC822 date when the part was read (@code{Content-Disposition}).
-(time-to-seconds '(13818 19266))
-@result{} 905595714.0
+@item recipients
+Who to encrypt/sign the part to. This field is used to override any
+auto-detection based on the To/CC headers.
-(seconds-to-time 905595714.0)
-@result{} (13818 19266 0)
+@item size
+The size (in octets) of the part (@code{Content-Disposition}).
-(time-to-days '(13818 19266))
-@result{} 729644
+@item sign
+What technology to sign this MML part with (@code{smime}, @code{pgp}
+or @code{pgpmime})
-(days-to-time 729644)
-@result{} (961933 65536)
+@item encrypt
+What technology to encrypt this MML part with (@code{smime},
+@code{pgp} or @code{pgpmime})
-(time-since '(13818 19266))
-@result{} (0 430)
+@end table
-(time-less-p '(13818 19266) '(13818 19145))
-@result{} nil
+Parameters for @samp{application/octet-stream}:
-(subtract-time '(13818 19266) '(13818 19145))
-@result{} (0 121)
+@table @samp
+@item type
+Type of the part; informal---meant for human readers
+(@code{Content-Type}).
+@end table
-(days-between "Sat Sep 12 12:21:54 1998 +0200"
- "Sat Sep 07 12:21:54 1998 +0200")
-@result{} 5
+Parameters for @samp{message/external-body}:
-(date-leap-year-p 2000)
-@result{} t
+@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}.)
-(time-to-day-in-year '(13818 19266))
-@result{} 255
+@item expiration
+The RFC822 date after which the file may no longer be fetched.
+(@code{Content-Type}.)
-(time-to-number-of-days
- (time-since
- (date-to-time "Mon, 01 Jan 2001 02:22:26 GMT")))
-@result{} 4.146122685185185
-@end example
+@item size
+The size (in octets) of the file. (@code{Content-Type}.)
-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.
+@item permission
+Valid values are @samp{read} and @samp{read-write}
+(@code{Content-Type}).
-The five data representations used are the following:
+@end table
-@table @var
-@item date
-An RFC822 (or similar) date string. For instance: @code{"Sat Sep 12
-12:21:54 1998 +0200"}.
+Parameters for @samp{sign=smime}:
-@item time
-An internal Emacs time. For instance: @code{(13818 26466)}.
+@table @samp
-@item seconds
-A floating point representation of the internal Emacs time. For
-instance: @code{905595714.0}.
+@item keyfile
+File containing key and certificate for signer.
-@item days
-An integer number representing the number of days since 00000101. For
-instance: @code{729644}.
+@end table
+
+Parameters for @samp{encrypt=smime}:
+
+@table @samp
+
+@item certfile
+File containing certificate for recipient.
-@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:
+@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 @sc{mime} message:
+
+@example
+Content-Type: multipart/mixed; boundary="=-=-="
+
+
+--=-=-=
-@table @code
-@item date-to-time
-Take a date and return a time.
-@item time-to-seconds
-Take a time and return seconds.
-@item seconds-to-time
-Take seconds and return a time.
+--=-=-=
+Content-Type: image/jpeg;
+ filename="~/rms.jpg"
+Content-Disposition: inline;
+ filename="~/rms.jpg"
+Content-Transfer-Encoding: base64
-@item time-to-days
-Take a time and return days.
+/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==
-@item days-to-time
-Take days and return a time.
+--=-=-=
+Content-Type: multipart/alternative; boundary="==-=-="
-@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" date.
-@item time-less-p
-Take two times and say whether the first time is less (i. e., earlier)
-than the second time.
+This is a plain text part.
-@item time-since
-Take a time and return a time saying how long it was since that time.
+--==-=-=
+Content-Type: text/enriched;
+ name="enriched.txt"
-@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.
+<center>This is a centered enriched part</center>
-@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
+This is a new plain text part.
+--=-=-=
+Content-Disposition: attachment
-@node qp
-@section qp
-This library deals with decoding and encoding Quoted-Printable text.
+This plain text part is an attachment.
-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.
+--=-=-=--
+@end example
-The following functions are defined by the library:
+@node Encoding Customization
+@section Encoding Customization
@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 mm-body-charset-encoding-alist
+@vindex mm-body-charset-encoding-alist
+Mapping from 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 @code{((iso-2022-jp . 7bit) (iso-2022-jp-2 . 7bit))}. 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} 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 nil, which means to use the defaults in Emacs. It is a list of
+coding system symbols (aliases of coding systems does not work, use
+@kbd{M-x describe-coding-system} to make sure you are not specifying
+an alias in this variable). For example, if you have configured Emacs
+to use 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-latin-1)}. You can override this setting on a per-message
+basis by using the @code{charset} MML tag (@pxref{MML Definition}).
+
+@item mm-content-transfer-encoding-defaults
+@vindex mm-content-transfer-encoding-defaults
+Mapping from 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
+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. You can override this setting on a per-message basis by using
+the @code{encoding} MML tag (@pxref{MML Definition}).
+
+@item mm-use-ultra-safe-encoding
+@vindex mm-use-ultra-safe-encoding
+When this is non-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).
-@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.)
+@end table
-@item quoted-printable-encode-string
-@findex quoted-printable-encode-string
-QP-encode all the encodable characters in a string and return the
-results.
+@node Charset Translation
+@section Charset Translation
+@cindex charsets
-@end table
+During translation from MML to @sc{mime}, for each @sc{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-ASCII (8-bit) characters, the @sc{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
+@sc{mime} messages.
+@xref{Various Message Variables, , Various Message Variables, message,
+ Message Manual}, for example.)
+If there are only ASCII characters, the @sc{mime} charset US-ASCII is
+used, of course.
-@node base64
-@section base64
-@cindex base64
+@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 @sc{mime}
+charsets by consulting the variable @code{mm-mime-mule-charset-alist}.
+If this results in a single @sc{mime} charset, this is used to encode
+the part. But if the resulting list of @sc{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 @sc{mime} charset. The part can only be
+split at line boundaries, though---if more than one @sc{mime} charset is
+required to encode a single line, it is not possible to encode the part.
-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.
+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 following functions are defined by this library:
+The charset to be used can be overriden by setting the @code{charset}
+MML tag (@pxref{MML Definition}) when composing the message.
-@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.
+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}).
-@item base64-encode-string
-@findex base64-encode-string
-base64 encode a string and return the result.
+@node Conversion
+@section Conversion
-@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.
+@findex mime-to-mml
+A (multipart) @sc{mime} message can be converted to MML with the
+@code{mime-to-mml} function. It works on the message in the current
+buffer, and substitutes MML markup for @sc{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 MML
+tags.
-@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.
+@findex mml-to-mime
+An MML message can be converted back to @sc{mime} by the
+@code{mml-to-mime} function.
-@end table
+These functions are in certain senses ``lossy''---you will not get back
+an identical message if you run @sc{mime-to-mml} and then
+@sc{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 @sc{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 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:
+@node Flowed text
+@section Flowed text
+@cindex format=flowed
-@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.
+The Emacs @sc{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.
-@end table
+On encoding text, lines terminated by soft newline characters are
+filled together and wrapped after the column decided by
+@code{fill-flowed-encode-column}. This 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.
+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}.
-@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 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 ASCII characters in the
+parameter list. RFC2231 expands on RFC2045 syntax to provide a scheme
+for continuation headers and non-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 @sc{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:
-@node rfc1843
-@section rfc1843
-@cindex rfc1843
-@cindex HZ
-@cindex Chinese
+@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:
-RFC1843 deals with mixing Chinese and ASCII characters in messages. In
-essence, RFC1843 switches between ASCII and Chinese by doing this:
+@lisp
+("type/subtype"
+ (attribute1 . value1)
+ (attribute2 . value2)
+ ...)
+@end lisp
+
+Here's an example:
@example
-This sentence is in ASCII.
-The next sentence is in GB.~@{<:Ky2;S@{#,NpJ)l6HK!#~@}Bye.
+(mail-header-parse-content-type
+ "image/gif; name=\"b980912.gif\"")
+@result{} ("image/gif" (name . "b980912.gif"))
@end example
-Simple enough, and widely used in China.
-
-The following functions are available to handle this encoding:
+@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.
-@table @code
-@item rfc1843-decode-region
-Decode HZ-encoded text in the region.
+@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.
-@item rfc1843-decode-string
-Decode a HZ-encoded string and return the result.
+@example
+(mail-content-type-get
+ '("image/gif" (name . "b980912.gif")) 'name)
+@result{} "b980912.gif"
+@end example
-@end table
+@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.
-@node mailcap
-@section mailcap
+@example
+(mail-header-remove-comments
+ "Gnus/5.070027 (Pterodactyl Gnus v0.27) (Finnish Landrace)")
+@result{} "Gnus/5.070027 "
+@end example
-The @file{~/.mailcap} file is parsed by most @sc{mime}-aware message
-handlers and describes how elements are supposed to be displayed.
-Here's an example file:
+@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
-image/*; gimp -8 %s
-audio/wav; wavplayer %s
-application/msword; catdoc %s ; copiousoutput ; nametemplate=%s.doc
+(mail-header-remove-whitespace
+ "image/gif; name=\"Name with spaces\"")
+@result{} "image/gif;name=\"Name with spaces\""
@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.
+@item mail-header-get-comment
+@findex mail-header-get-comment
+Return the last comment in a header.
-@table @code
-@item mailcap-mime-data
-@vindex mailcap-mime-data
-This variable is an alist of alists containing backup viewing rules.
+@example
+(mail-header-get-comment
+ "Gnus/5.070027 (Pterodactyl Gnus v0.27) (Finnish Landrace)")
+@result{} "Finnish Landrace"
+@end example
-@end table
+@item mail-header-parse-address
+@findex mail-header-parse-address
+Parse an address and return a list containing the mailbox and the
+plaintext name.
-Interface functions:
+@example
+(mail-header-parse-address
+ "Hrvoje Niksic <hniksic@@srce.hr>")
+@result{} ("hniksic@@srce.hr" . "Hrvoje Niksic")
+@end example
-@table @code
-@item mailcap-parse-mailcaps
-@findex mailcap-parse-mailcaps
-Parse the @code{~/.mailcap} file.
+@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.
-@item mailcap-mime-info
-Takes a @sc{mime} type as its argument and returns the matching viewer.
+@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
-@end table
+@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.
-@node Decoding and Viewing
-@chapter Decoding and Viewing
+@item mail-header-unfold-field
+@findex mail-header-unfold-field
+Unfold the header under point.
-This chapter deals with decoding and viewing @sc{mime} messages on a
-higher level.
+@item mail-header-field-value
+@findex mail-header-field-value
+Return the value of the field under point.
-The main idea is to first analyze a @sc{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.
+@item mail-encode-encoded-word-region
+@findex mail-encode-encoded-word-region
+Encode the non-ASCII words in the region. For instance,
+@samp{Naïve} is encoded as @samp{=?iso-8859-1?q?Na=EFve?=}.
-@menu
-* Dissection:: Analyzing a @sc{mime} message.
-* Non-MIME:: Analyzing a non-@sc{mime} message.
-* Handles:: Handle manipulations.
-* Display:: Displaying handles.
-* Customization:: Variables that affect display.
-* New Viewers:: How to write your own viewers.
-@end menu
+@item mail-encode-encoded-word-buffer
+@findex mail-encode-encoded-word-buffer
+Encode the non-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.
-@node Dissection
-@section Dissection
+@example
+(mail-encode-encoded-word-string
+ "This is naïve, baby")
+@result{} "This is =?iso-8859-1?q?na=EFve,?= baby"
+@end example
-The @code{mm-dissect-buffer} is the function responsible for dissecting
-a @sc{mime} article. If given a multipart message, it will recursively
-descend the message, following the structure, and return a tree of
-@sc{mime} handles that describes the structure of the message.
+@item mail-decode-encoded-word-region
+@findex mail-decode-encoded-word-region
+Decode the encoded words in the region.
-@node Non-MIME
-@section Non-MIME
+@item mail-decode-encoded-word-string
+@findex mail-decode-encoded-word-string
+Decode the encoded words in the string and return the result.
-Gnus also understands some non-@sc{mime} attachments, such as
-postscript, uuencode, binhex, shar, forward, gnatsweb, pgp. Each of
-these features can be disabled by add an item into
-@code{mm-uu-configure-list}. For example,
+@example
+(mail-decode-encoded-word-string
+ "This is =?iso-8859-1?q?na=EFve,?= baby")
+@result{} "This is naïve, baby"
+@end example
-@lisp
-(require 'mm-uu)
-(add-to-list 'mm-uu-configure-list '(pgp-signed . disabled))
-@end lisp
+@end table
-@table @code
-@item postscript
-@findex postscript
-Postscript file.
+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.
-@item uu
-@findex uu
-Uuencoded file.
-@item binhex
-@findex binhex
-Binhex encoded file.
-@item shar
-@findex shar
-Shar archive file.
+@node Basic Functions
+@chapter Basic Functions
-@item forward
-@findex forward
-Non-@sc{mime} forwarded message.
+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 next chapter
+(@pxref{Decoding and Viewing}).
-@item gnatsweb
-@findex gnatsweb
-Gnatsweb attachment.
+@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.
+* rfc1843:: Decoding HZ-encoded text.
+* mailcap:: How parts are displayed is specified by the @file{.mailcap} file
+@end menu
-@item pgp-signed
-@findex pgp-signed
-PGP signed clear text.
-@item pgp-encrypted
-@findex pgp-encrypted
-PGP encrypted clear text.
+@node rfc2045
+@section rfc2045
-@item pgp-key
-@findex pgp-key
-PGP public keys.
+RFC2045 is the ``main'' @sc{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.
-@item emacs-sources
-@findex emacs-sources
-Emacs source code. This item works only in the groups matching
-@code{mm-uu-emacs-sources-regexp}.
+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 Handles
-@section Handles
-A @sc{mime} handle is a list that fully describes a @sc{mime}
-component.
+@node rfc2231
+@section rfc2231
-The following macros can be used to access elements in a handle:
+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}.
-@table @code
-@item mm-handle-buffer
-@findex mm-handle-buffer
-Return the buffer that holds the contents of the undecoded @sc{mime}
-part.
+In short, these headers look something like this:
-@item mm-handle-type
-@findex mm-handle-type
-Return the parsed @code{Content-Type} of the part.
+@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
-@item mm-handle-encoding
-@findex mm-handle-encoding
-Return the @code{Content-Transfer-Encoding} of the part.
+They usually aren't this bad, though.
-@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).
+The following functions are defined by this library:
-@item mm-handle-set-undisplayer
-@findex mm-handle-set-undisplayer
-Set the undisplayer object.
+@table @code
+@item rfc2231-parse-string
+@findex rfc2231-parse-string
+Parse a @code{Content-Type} header and return a list describing its
+elements.
-@item mm-handle-disposition
-@findex mm-handle-disposition
-Return the parsed @code{Content-Disposition} of the part.
+@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 mm-handle-disposition
-@findex mm-handle-disposition
-Return the description of the part.
+@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 mm-get-content-id
-Returns the handle(s) referred to by @code{Content-ID}.
+@item rfc2231-encode-string
+@findex rfc2231-encode-string
+Encode a parameter in headers likes @code{Content-Type} and
+@code{Content-Disposition}.
@end table
-@node Display
-@section Display
+@node ietf-drums
+@section ietf-drums
-Functions for displaying, removing and saving.
+@dfn{drums} is an IETF working group that is working on the replacement
+for RFC822.
-@table @code
-@item mm-display-part
-@findex mm-display-part
-Display the part.
+The functions provided by this library include:
-@item mm-remove-part
-@findex mm-remove-part
-Remove the part (if it has been displayed).
+@table @code
+@item ietf-drums-remove-comments
+@findex ietf-drums-remove-comments
+Remove the comments from the argument and return the results.
-@item mm-inlinable-p
-@findex mm-inlinable-p
-Say whether a @sc{mime} type can be displayed inline.
+@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 mm-automatic-display-p
-@findex mm-automatic-display-p
-Say whether a @sc{mime} type should be displayed automatically.
+@item ietf-drums-get-comment
+@findex ietf-drums-get-comment
+Return the last most comment from the string.
-@item mm-destroy-part
-@findex mm-destroy-part
-Free all resources occupied by a part.
+@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 mm-save-part
-@findex mm-save-part
-Offer to save the part in a file.
+@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 mm-pipe-part
-@findex mm-pipe-part
-Offer to pipe the part to some process.
+@item ietf-drums-parse-date
+@findex ietf-drums-parse-date
+Parse a date string and return an Emacs time structure.
-@item mm-interactively-view-part
-@findex mm-interactively-view-part
-Prompt for a mailcap method to use to view the part.
+@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 Customization
-@section Customization
-
-@table @code
-
-@item mm-inline-media-tests
-This is an alist where the key is a @sc{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.
+@node rfc2047
+@section rfc2047
-@item 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
-@sc{mime} media types.
+RFC2047 (Message Header Extensions for Non-ASCII Text) specifies how
+non-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.
-@item 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.
+The following variables are tweakable:
-@item mm-attachment-override-types
-Some @sc{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.)
+@table @code
+@item rfc2047-default-charset
+@vindex rfc2047-default-charset
+Characters in this charset should not be decoded by this library.
+This defaults to @code{iso-8859-1}.
-@item mm-discouraged-alternatives
-List of @sc{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/richtech} parts are somewhat unwanted,
-you could say something like:
+@item rfc2047-header-encoding-list
+@vindex rfc2047-header-encoding-list
+This is an alist of header / encoding-type pairs. Its main purpose is
+to prevent encoding of certain headers.
-@lisp
-(setq mm-discouraged-alternatives
- '("text/html" "text/richtext")
- mm-automatic-display
- (remove "text/html" mm-automatic-display))
-@end lisp
+The keys can either be header regexps, or @code{t}.
-@item mm-inline-large-images-p
-When displaying inline images that are larger than the window, XEmacs
-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.
+The values can be either @code{nil}, in which case the header(s) in
+question won't be encoded, or @code{mime}, which means that they will be
+encoded.
-@item mm-inline-override-type
-@code{mm-inlined-types} may include regular expressions, for example to
-specify that all @samp{text/.*} parts be displayed inline. If a user
-prefers to have a type that matches such a regular expression be treated
-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 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 mm-inline-text-html-renderer
-This selects the function used to render @sc{html}. The predefined
-renderers are selected by the symbols @code{w3},
-@code{w3m}@footnote{See @uref{http://emacs-w3m.namazu.org/} for more
-information about emacs-w3m}, @code{links}, @code{lynx} or
-@code{html2text}. You can also specify a function, which will be
-called with a @sc{mime} handle as the argument.
+@item rfc2047-encoding-function-alist
+@vindex rfc2047-encoding-function-alist
+This is an alist of encoding / function pairs. The encodings are
+@code{Q}, @code{B} and @code{nil}.
-@item mm-inline-text-html-with-images
-Some @sc{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 informations from
-leaking by setting this option to @code{nil} (which is the default).
-It is currently ignored by Emacs/w3. 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 rfc2047-q-encoding-alist
+@vindex rfc2047-q-encoding-alist
+The @code{Q} encoding isn't quite the same for all headers. Some
+headers allow a narrower range of characters, and that is what this
+variable is for. It's an alist of header regexps / allowable character
+ranges.
-@item 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 rfc2047-encoded-word-regexp
+@vindex rfc2047-encoded-word-regexp
+When decoding words, this library looks for matches to this regexp.
@end table
+Those were the variables, and these are this functions:
-@node New Viewers
-@section New Viewers
+@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}.
-Here's an example viewer for displaying @code{text/enriched} inline:
+@item rfc2047-encode-region
+@findex rfc2047-encode-region
+Encodes all encodable words in the region specified.
-@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
+@item rfc2047-encode-string
+@findex rfc2047-encode-string
+Encode a string and return the results.
-We see that the function takes a @sc{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.
+@item rfc2047-decode-region
+@findex rfc2047-decode-region
+Decode the encoded words in the region.
-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.
+@item rfc2047-decode-string
+@findex rfc2047-decode-string
+Decode a string and return the results.
+@end table
-@node Composing
-@chapter Composing
-@cindex Composing
-@cindex MIME Composing
-@cindex MML
-@cindex MIME Meta Language
-Creating a @sc{mime} message is boring and non-trivial. Therefore, a
-library called @code{mml} has been defined that parses a language called
-MML (@sc{mime} Meta Language) and generates @sc{mime} messages.
+@node time-date
+@section time-date
-@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 @sc{mime} message.
+While not really a part of the @sc{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.)
-@menu
-* Simple MML Example:: An example MML document.
-* MML Definition:: All valid MML elements.
-* Advanced MML Example:: Another example MML document.
-* Charset Translation:: How charsets are mapped from @sc{mule} to @sc{mime}.
-* Conversion:: Going from @sc{mime} to MML and vice versa.
-* Flowed text:: Soft and hard newlines.
-@end menu
+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:
-@node Simple MML Example
-@section Simple MML Example
+@example
+(parse-time-string "Sat Sep 12 12:21:54 1998 +0200")
+@result{} (54 21 12 12 9 1998 6 nil 7200)
-Here's a simple @samp{multipart/alternative}:
+(date-to-time "Sat Sep 12 12:21:54 1998 +0200")
+@result{} (13818 19266)
-@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
+(time-to-seconds '(13818 19266))
+@result{} 905595714.0
-After running this through @code{mml-generate-mime}, we get this:
+(seconds-to-time 905595714.0)
+@result{} (13818 19266 0)
-@example
-Content-Type: multipart/alternative; boundary="=-=-="
+(time-to-days '(13818 19266))
+@result{} 729644
+(days-to-time 729644)
+@result{} (961933 65536)
---=-=-=
+(time-since '(13818 19266))
+@result{} (0 430)
+(time-less-p '(13818 19266) '(13818 19145))
+@result{} nil
-This is a plain text part.
+(subtract-time '(13818 19266) '(13818 19145))
+@result{} (0 121)
---=-=-=
-Content-Type: text/enriched
+(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
-<center>This is a centered enriched part</center>
+(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{} 4.146122685185185
@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.
-@node MML Definition
-@section MML Definition
+The five data representations used are the following:
-The MML language is very simple. It looks a bit like an SGML
-application, but it's not.
+@table @var
+@item date
+An RFC822 (or similar) date string. For instance: @code{"Sat Sep 12
+12:21:54 1998 +0200"}.
-The main concept of 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.
+@item time
+An internal Emacs time. For instance: @code{(13818 26466)}.
-There's also the @samp{<#external ...>} tag. These introduce
-@samp{external/message-body} parts.
+@item seconds
+A floating point representation of the internal Emacs time. For
+instance: @code{905595714.0}.
-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.
+@item days
+An integer number representing the number of days since 00000101. For
+instance: @code{729644}.
-The following parameters have meaning in MML; parameters that have no
-meaning are ignored. The MML parameter names are the same as the
-@sc{mime} parameter names; the things in the parentheses say which
-header it will be used in.
+@item decoded time
+A list of decoded time. For instance: @code{(54 21 12 12 9 1998 6 t
+7200)}.
+@end table
-@table @samp
-@item type
-The @sc{mime} type of the part (@code{Content-Type}).
+All the examples above represent the same moment.
-@item filename
-Use the contents of the file in the body of the part
-(@code{Content-Disposition}).
+These are the functions available:
-@item charset
-The contents of the body of the part are to be encoded in the character
-set speficied (@code{Content-Type}).
+@table @code
+@item date-to-time
+Take a date and return a time.
-@item name
-Might be used to suggest a file name if the part is to be saved
-to a file (@code{Content-Type}).
+@item time-to-seconds
+Take a time and return seconds.
-@item disposition
-Valid values are @samp{inline} and @samp{attachment}
-(@code{Content-Disposition}).
+@item seconds-to-time
+Take seconds and return a time.
-@item encoding
-Valid values are @samp{7bit}, @samp{8bit}, @samp{quoted-printable} and
-@samp{base64} (@code{Content-Transfer-Encoding}).
+@item time-to-days
+Take a time and return days.
-@item description
-A description of the part (@code{Content-Description}).
+@item days-to-time
+Take days and return a time.
-@item creation-date
-RFC822 date when the part was created (@code{Content-Disposition}).
+@item date-to-day
+Take a date and return days.
-@item modification-date
-RFC822 date when the part was modified (@code{Content-Disposition}).
+@item time-to-number-of-days
+Take a time and return the number of days that represents.
-@item read-date
-RFC822 date when the part was read (@code{Content-Disposition}).
+@item safe-date-to-time
+Take a date and return a time. If the date is not syntactically valid,
+return a "zero" date.
-@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 time-less-p
+Take two times and say whether the first time is less (i. e., earlier)
+than the second time.
-@item size
-The size (in octets) of the part (@code{Content-Disposition}).
+@item time-since
+Take a time and return a time saying how long it was since that time.
-@item sign
-What technology to sign this MML part with (@code{smime}, @code{pgp}
-or @code{pgpmime})
+@item subtract-time
+Take two times and subtract the second from the first. I. e., return
+the time between the two times.
-@item encrypt
-What technology to encrypt this MML part with (@code{smime},
-@code{pgp} or @code{pgpmime})
+@item days-between
+Take two days and return the number of days between those two days.
-@end table
+@item date-leap-year-p
+Take a year number and say whether it's a leap year.
-Parameters for @samp{application/octet-stream}:
+@item time-to-day-in-year
+Take a time and return the day number within the year that the time is
+in.
-@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}.)
+@node qp
+@section qp
-@item expiration
-The RFC822 date after which the file may no longer be fetched.
-(@code{Content-Type}.)
+This library deals with decoding and encoding Quoted-Printable text.
-@item size
-The size (in octets) of the file. (@code{Content-Type}.)
+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.
-@item permission
-Valid values are @samp{read} and @samp{read-write}
-(@code{Content-Type}).
+The following functions are defined by the library:
-@end table
+@table @code
+@item quoted-printable-decode-region
+@findex quoted-printable-decode-region
+QP-decode all the encoded text in the specified region.
-Parameters for @samp{sign=smime}:
+@item quoted-printable-decode-string
+@findex quoted-printable-decode-string
+Decode the QP-encoded text in a string and return the results.
-@table @samp
+@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 keyfile
-File containing key and certificate for signer.
+@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
-Parameters for @samp{encrypt=smime}:
-
-@table @samp
-
-@item certfile
-File containing certificate for recipient.
-@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.
-@node Advanced MML Example
-@section Advanced MML Example
+The following functions are defined by this library:
-Here's a complex multipart message. It's a @samp{multipart/mixed} that
-contains many parts, one of which is a @samp{multipart/alternative}.
+@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.
-@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
+@item base64-encode-string
+@findex base64-encode-string
+base64 encode a string and return the result.
-And this is the resulting @sc{mime} message:
+@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.
-@example
-Content-Type: multipart/mixed; boundary="=-=-="
+@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:
---=-=-=
-Content-Type: image/jpeg;
- filename="~/rms.jpg"
-Content-Disposition: inline;
- filename="~/rms.jpg"
-Content-Transfer-Encoding: base64
+@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.
-/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==
+@end table
---=-=-=
-Content-Type: multipart/alternative; boundary="==-=-="
+@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:
-This is a plain text part.
+@table @code
+@item uudecode-decode-region
+@findex uudecode-decode-region
+Decode the text in the region.
+@end table
---==-=-=
-Content-Type: text/enriched;
- name="enriched.txt"
+@node rfc1843
+@section rfc1843
+@cindex rfc1843
+@cindex HZ
+@cindex Chinese
-<center>This is a centered enriched part</center>
+RFC1843 deals with mixing Chinese and ASCII characters in messages. In
+essence, RFC1843 switches between ASCII and Chinese by doing this:
---==-=-=--
+@example
+This sentence is in ASCII.
+The next sentence is in GB.~@{<:Ky2;S@{#,NpJ)l6HK!#~@}Bye.
+@end example
---=-=-=
+Simple enough, and widely used in China.
-This is a new plain text part.
+The following functions are available to handle this encoding:
---=-=-=
-Content-Disposition: attachment
+@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.
-This plain text part is an attachment.
+@end table
---=-=-=--
-@end example
-@node Charset Translation
-@section Charset Translation
-@cindex charsets
+@node mailcap
+@section mailcap
-During translation from MML to @sc{mime}, for each @sc{mime} part which
-has been composed inside Emacs, an appropriate charset has to be chosen.
+The @file{~/.mailcap} file is parsed by most @sc{mime}-aware message
+handlers and describes how elements are supposed to be displayed.
+Here's an example file:
-@vindex mail-parse-charset
-If you are running a non-@sc{mule} Emacs, this process is simple: If the
-part contains any non-ASCII (8-bit) characters, the @sc{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
-@sc{mime} messages.
-@xref{Various Message Variables, , Various Message Variables, message,
- Message Manual}, for example.)
-If there are only ASCII characters, the @sc{mime} charset US-ASCII is
-used, of course.
+@example
+image/*; gimp -8 %s
+audio/wav; wavplayer %s
+application/msword; catdoc %s ; copiousoutput ; nametemplate=%s.doc
+@end example
-@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 @sc{mime}
-charsets by consulting the variable @code{mm-mime-mule-charset-alist}.
-If this results in a single @sc{mime} charset, this is used to encode
-the part. But if the resulting list of @sc{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 @sc{mime} charset. The part can only be
-split at line boundaries, though---if more than one @sc{mime} charset is
-required to encode a single line, it is not possible to encode the part.
+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}.
-@node Conversion
-@section Conversion
+The @code{mailcap} library parses this file, and provides functions for
+matching types.
-@findex mime-to-mml
-A (multipart) @sc{mime} message can be converted to MML with the
-@code{mime-to-mml} function. It works on the message in the current
-buffer, and substitutes MML markup for @sc{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 MML
-tags.
+@table @code
+@item mailcap-mime-data
+@vindex mailcap-mime-data
+This variable is an alist of alists containing backup viewing rules.
-@findex mml-to-mime
-An MML message can be converted back to @sc{mime} by the
-@code{mml-to-mime} function.
+@end table
-These functions are in certain senses ``lossy''---you will not get back
-an identical message if you run @sc{mime-to-mml} and then
-@sc{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 @sc{mml-to-mime} may decide to use quoted-printable encoding, and
-so on.
+Interface functions:
-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.
+@table @code
+@item mailcap-parse-mailcaps
+@findex mailcap-parse-mailcaps
+Parse the @code{~/.mailcap} file.
+@item mailcap-mime-info
+Takes a @sc{mime} type as its argument and returns the matching viewer.
-@node Flowed text
-@section Flowed text
-@cindex format=flowed
+@end table
-The Emacs @sc{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, lines terminated by soft newline characters are
-filled together and wrapped after the column decided by
-@code{fill-flowed-encode-column}. This 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.
-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}.
@node Standards
@chapter Standards
\makeindex
\begin{document}
-\newcommand{\gnusversionname}{Oort Gnus v0.06}
+\newcommand{\gnusversionname}{Oort Gnus v0.07}
\newcommand{\gnuschaptername}{}
\newcommand{\gnussectionname}{}
spool or your mbox file. All at the same time, if you want to push your
luck.
-This manual corresponds to Oort Gnus v0.06.
+This manual corresponds to Oort Gnus v0.07.
@end ifinfo
* Hard Picons:: The way you should do it. You'll learn something.
* Picon Useless Configuration:: Other variables you can trash/tweak/munge/play with.
+Thwarting Email Spam
+
+* 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.
+
Appendices
* XEmacs:: Requirements for installing under XEmacs.
(cond (window-system
(setq custom-background-mode 'light)
(defface my-group-face-1
- '((t (:foreground "Red" :bold t))) "First group face")
+ '((t (:foreground "Red" :bold t))) "First group face")
(defface my-group-face-2
- '((t (:foreground "DarkSeaGreen4" :bold t))) "Second group face")
+ '((t (:foreground "DarkSeaGreen4" :bold t))) "Second group face")
(defface my-group-face-3
- '((t (:foreground "Green4" :bold t))) "Third group face")
+ '((t (:foreground "Green4" :bold t))) "Third group face")
(defface my-group-face-4
- '((t (:foreground "SteelBlue" :bold t))) "Fourth group face")
+ '((t (:foreground "SteelBlue" :bold t))) "Fourth group face")
(defface my-group-face-5
- '((t (:foreground "Blue" :bold t))) "Fifth group face")))
+ '((t (:foreground "Blue" :bold t))) "Fifth group face")))
(setq gnus-group-highlight
'(((> unread 200) . my-group-face-1)
@item G w
@kindex G w (Group)
@findex gnus-group-make-web-group
-@cindex DejaNews
-@cindex Alta Vista
-@cindex InReference
+@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{dejanews}, @code{altavista} and @code{reference}.
+include @code{google}, @code{dejanews}, and @code{gmane}.
@xref{Web Searches}.
-If you use the @code{dejanews} search engine, you can limit the search
+If you use the @code{google} search engine, you can limit the search
to a particular group by using a match string like
-@samp{~g alt.sysadmin.recovery shaving}.
+@samp{shaving group:alt.sysadmin.recovery}.
@item G DEL
@kindex G DEL (Group)
@example
if address "sender" "owner-ding@@hpc.uh.edu" @{
- fileinto "INBOX.ding";
- stop;
+ fileinto "INBOX.ding";
+ stop;
@}
@end example
@item n
The name (from the @code{From} header).
@item f
-The name, code @code{To} header or the @code{Newsgroups} header
-(@pxref{To From Newsgroups}).
+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
A related variable is @code{nnmail-extra-headers}, which controls when
to include extra headers when generating overview (@sc{nov}) files. If
you have old overview files, you should regenerate them after changing
-this variable.
+this variable, by entering the server buffer using `^', and then `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
(The values listed above are the default values in Gnus. Alter them
to fit your needs.)
-Now, this is mostly useful for mail groups, where you have control over
+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 @sc{nov} files that are created. However, if you can persuade your
-nntp admin to add:
+nntp admin to add (in the usual implementation, notably INN):
@example
Newsgroups:full
goes out to all people listed in the @code{To}, @code{From} (or
@code{Reply-to}) and @code{Cc} headers.
-@item S V
-@kindex S V (Summary)
+@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
@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 o m
@itemx C-c C-f
@kindex S o m (Summary)
@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.
@findex gnus-thread-sort-by-subject
@findex gnus-thread-sort-by-author
@findex gnus-thread-sort-by-number
+@findex gnus-thread-sort-by-random
@vindex gnus-thread-sort-functions
@findex gnus-thread-sort-by-most-recent-thread
If you are using a threaded summary display, you can sort the threads by
@code{gnus-thread-sort-by-author}, @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} and
+@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
@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
-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}, and @code{gnus-article-sort-by-score}.
+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:
@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
match.
Here's an example setting that will first try the current method, and
-then ask Deja if that fails:
+then ask Google if that fails:
@lisp
(setq gnus-refer-article-method
'(current
- (nnweb "refer" (nnweb-type dejanews))))
+ (nnweb "refer" (nnweb-type google))))
@end lisp
Most of the mail back ends support fetching by @code{Message-ID}, but
(setq gnus-newsgroup-variables
'(message-use-followup-to
(gnus-visible-headers .
- "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^To:")))
+ "^From:\\|^Newsgroups:\\|^Subject:\\|^Date:\\|^To:")))
@end lisp
@end table
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 requests confirmation when replying to news.
+If you find yourself never wanting to reply to mail, but occasionally
+press R anyway, this variable might be for you.
+
@end table
(window-system ;; A value symbol
("X-Window-System" (format "%s" window-system)))
;; If I'm replying to Larsi, set the Organization header.
- ((header "to" "larsi.*org")
+ ((header "from" "larsi.*org")
(Organization "Somewhere, Inc."))
((posting-from-work-p) ;; A user defined function
(signature-file "~/.work-signature")
@sc{Mailcrypt}, you need to install at least one of them. The
@sc{s/mime} support in Gnus requires the external program OpenSSL.
+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 MML to perform security operations on a @sc{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.
@item C-c C-m s s
@kindex C-c C-m s s
-@findex mml-secure-sign-smime
+@findex mml-secure-message-sign-smime
-Digitally sign current @sc{mime} part using @sc{s/mime}.
+Digitally sign current message using @sc{s/mime}.
@item C-c C-m s o
@kindex C-c C-m s o
-@findex mml-secure-sign-pgp
+@findex mml-secure-message-sign-pgp
-Digitally sign current @sc{mime} part using PGP.
+Digitally sign current message using PGP.
@item C-c C-m s p
@kindex C-c C-m s p
-@findex mml-secure-sign-pgp
+@findex mml-secure-message-sign-pgp
-Digitally sign current @sc{mime} part using @sc{pgp/mime}.
+Digitally sign current message using @sc{pgp/mime}.
@item C-c C-m c s
@kindex C-c C-m c s
-@findex mml-secure-encrypt-smime
+@findex mml-secure-message-encrypt-smime
-Digitally encrypt current @sc{mime} part using @sc{s/mime}.
+Digitally encrypt current message using @sc{s/mime}.
@item C-c C-m c o
@kindex C-c C-m c o
-@findex mml-secure-encrypt-pgp
+@findex mml-secure-message-encrypt-pgp
-Digitally encrypt current @sc{mime} part using PGP.
+Digitally encrypt current message using PGP.
@item C-c C-m c p
@kindex C-c C-m c p
-@findex mml-secure-encrypt-pgpmime
+@findex mml-secure-message-encrypt-pgpmime
-Digitally encrypt current @sc{mime} part using @sc{pgp/mime}.
+Digitally encrypt current message using @sc{pgp/mime}.
@item C-c C-m C-n
@kindex C-c C-m C-n
(nntp-via-rlogin-command "ssh")
@end lisp
+See also @code{nntp-via-rlogin-command-switches}.
+
If you're behind a firewall, but have direct access to the outside world
through a wrapper command like "runsocks", you could open a socksified
telnet connection to the news server as follows:
@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 `nntp-via-rlogin-command', you may set this to
+@samp{("-C")} in order to compress all data connections, otherwise set
+this to @samp{("-t")} or @samp{("-C" "-t")} if the telnet command
+requires a pseudo-tty allocation on an intermediate host.
@end table
@item nntp-open-via-telnet-and-telnet
@code{nnmail-split-header-length-limit} are excluded from the split
function.
+@vindex nnmail-mail-splitting-charset
+@vindex nnmail-mail-splitting-decodes
+By default the splitting codes MIME decodes headers so you can match
+on non-ASCII strings. The @code{nnmail-mail-splitting-charset}
+variable specifies the default charset for decoding. The behaviour
+can be turned off completely by binding
+@code{nnmail-mail-splitting-decodes} to nil, which is useful if you
+want to match articles based on the raw header data.
+
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
@item webmail
Get mail from a webmail server, such as @uref{www.hotmail.com},
@uref{webmail.netscape.com}, @uref{www.netaddress.com},
-@uref{www.my-deja.com}.
-
-NOTE: Now @uref{mail.yahoo.com} provides POP3 service, so @sc{pop} mail source
-is suggested.
+@uref{mail.yahoo..com}.
NOTE: Webmail largely depends cookies. A "one-line-cookie" patch is
required for url "4.0pre.46".
-WARNING: Mails may lost. NO WARRANTY.
+WARNING: Mails may be lost. NO WARRANTY.
Keywords:
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
you can include @code{nnmail-split-fancy-with-parent} using the colon
feature, like so:
@lisp
-(setq nnmail-split-fancy
+(setq nnmail-treat-duplicates 'warn ; or 'delete
+ nnmail-cache-accepted-message-ids t
+ nnmail-split-fancy
'(| (: nnmail-split-fancy-with-parent)
;; other splits go here
))
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
(setq nnmail-expiry-target 'nnmail-fancy-expiry-target
nnmail-fancy-expiry-targets
'((to-from "boss" "nnfolder:Work")
- ("subject" "IMPORTANT" "nnfolder:IMPORTANT.%Y.%b")
+ ("subject" "IMPORTANT" "nnfolder:IMPORTANT.%Y.%b")
("from" ".*" "nnfolder:Archive-%Y")))
@end lisp
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
@node Web Searches
@subsection Web Searches
@cindex nnweb
-@cindex DejaNews
-@cindex Alta Vista
-@cindex InReference
+@cindex Google
+@cindex dejanews
+@cindex gmane
@cindex Usenet searches
@cindex searching the Usenet
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 (DejaNews, for instance). The only possible way to keep track
+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.
@item nnweb-type
@vindex nnweb-type
What search engine type is being used. The currently supported types
-are @code{dejanews}, @code{dejanewsold}, @code{altavista} and
-@code{reference}.
+are @code{google}, @code{dejanews}, and @code{gmane}. Note that
+@code{dejanews} is an alias to @code{google}.
@item nnweb-search
@vindex nnweb-search
@item nnweb-max-hits
@vindex nnweb-max-hits
Advisory maximum number of hits per search to display. The default is
-100.
+999.
@item nnweb-type-definition
@vindex nnweb-type-definition
(defun gnus-user-format-function-X (header)
(let ((descr
- (assq nnrss-description-field (mail-header-extra header))))
+ (assq nnrss-description-field (mail-header-extra header))))
(if descr (concat "\n\t" (cdr descr)) "")))
@end lisp
doesn't exist actually does exist. More specifically, @sc{imap} has
this concept of marking articles @code{Deleted} which doesn't actually
delete them, and this (marking them @code{Deleted}, that is) is what
-nnimap does when you delete a article in Gnus (with @kbd{G DEL} or
+nnimap does when you delete a article in Gnus (with @kbd{B DEL} or
similar).
Since the articles aren't really removed when we mark them with the
@item nnimap-importantize-dormant
@vindex nnimap-importantize-dormant
-If non-nil, marks dormant articles as ticked (as well), for other
-@sc{imap} clients. Within Gnus, dormant articles will naturally still
-(only) be marked as ticked. This is to make dormant articles stand
-out, just like ticked articles, in other @sc{imap} clients. (In other
-words, Gnus has two ``Tick'' marks and @sc{imap} has only one.)
+If non-nil (the default), marks dormant articles as ticked (as well),
+for other @sc{imap} clients. Within Gnus, dormant articles will
+naturally still (only) be marked as dormant. This is to make dormant
+articles stand out, just like ticked articles, in other @sc{imap}
+clients. (In other words, Gnus has two ``Tick'' marks and @sc{imap}
+has only one.)
Probably the only reason for frobing this would be if you're trying
enable per-user persistant dormant flags, using something like:
Newsgroups: alt.religion.emacs
@end example
-will get this @code{From} header inserted:
+will get this @code{To} header inserted:
@example
To: alt-religion-emacs@@GATEWAY
(require 'gnus-agent)
(setq gnus-category-predicate-alist
(append gnus-category-predicate-alist
- '((old . my-article-old-p))))
+ '((old . my-article-old-p))))
@end lisp
and simply specify your predicate as:
This is annoying.
-The way to deal with this is having Gnus split out all spam into a
+@menu
+* 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 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
to non-existent domains is yucky, in my opinion.
+
+@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 was sufficient in
+avoiding spam is 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.
+
+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}) follows.
+
+@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 managed 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
+ (let ((buf (or (get-buffer " *nnmail incoming*")
+ (get-buffer " *nnml move*"))))
+ (if (not buf)
+ (progn (message "Oops, cannot find message buffer") nil)
+ (set-buffer buf)
+ (if (eq 1 (call-process-region (point-min) (point-max)
+ "spamc" nil nil nil "-c"))
+ "spam")))))
+@end lisp
+
+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-show-raw-article)
+ (gnus-summary-save-in-pipe "razor-report -f -d")
+ (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 for each message they send. This has the obvious drawback that
+you cannot rely on that everyone in the world uses 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 requires that everyone you communicate with 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.cypherspace.org/~adam/hashcash/}. Even more
+information can be found at @uref{http://www.camram.org/}.
+
+If you wish to call hashcash for each message you send, say something
+like:
+
+@lisp
+(require 'hashcash)
+(add-hook 'message-send-hook 'mail-add-payment)
+@end lisp
+
+The @code{hashcash.el} library can be found at
+@uref{http://users.actrix.gen.nz/mycroft/hashcash.el}, or in the Gnus
+development contrib directory.
+
+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 0, meaning nothing will be
+done. 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{(ADDR AMOUNT)} cells,
+where ADDR is the receiver (email address or newsgroup) and AMOUNT is
+the number of bits in the collision that is needed. It can also
+contain @samp{(ADDR STRING AMOUNT)} cells, where the STRING is the
+string to use (normally the email address or newsgroup name is used).
+
+@item hashcash
+@vindex hashcash
+Where the @code{hashcash} binary is installed.
+
+@end table
+
+Currently there is no built in functionality in Gnus to verify
+hashcash cookies, it is expected that this is performed by your hand
+customized mail filtering scripts. Improvements in this area would be
+a useful contribution, however.
+
@node Various Various
@section Various Various
@cindex mode lines
@lisp
(setq mail-sources
'((directory :path "~/mail/incoming/"
- :suffix ".in")))
+ :suffix ".in")))
@end lisp
More information is available in the info doc at Select Methods ->
message a single part tag will be used. This way, message mode will
do the Right Thing (TM) with signed/encrypted multipart messages.
+By default, when encrypting a message, Gnus will use the "signencrypt"
+mode. If you would like to disable this for a particular message,
+give the mml-secure-message-encrypt-* command a prefix argument. (for
+example, C-u C-c C-m c p). Additionally, by default Gnus will
+separately sign, then encrypt a message which has the mode
+signencrypt. If you would like to change this behavior use the
+@code{mml-signencrypt-style} function. For example
+
+@code{(mml-signencrypt-style "pgpmime" 'combined)}
+
+Will cause Gnus to sign and encrypt in one pass, thus generating a
+single signed and encrypted part.
+
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
@code{optional}, the 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
@vindex sieve-mode-syntax-table
Sieve mode is derived from @code{c-mode}, and is very similar except
for the syntax of comments. The keymap (@code{sieve-mode-map}) is
-inherited from @code{c-mode}, as are the the variables for customizing
+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}).