+2002-02-03 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-forward-rmail-make-body): Directly use
+ rmail-msg-restore-non-pruned-header to avoid calling
+ vertical-motion.
+
2002-01-03 Lars Magne Ingebrigtsen <larsi@gnus.org>
* gnus-start.el (gnus-read-init-file): Cleaned up.
* gnus-start.el (gnus-read-init-file): Don't force coding system
for ~/.gnus. From Dave Love <fx@gnu.org>.
+2002-01-03 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-util.el (mm-charset-to-coding-system): Don't setq charset.
+ * mm-util.el (mm-use-find-coding-systems-region): New variable.
+ (mm-find-mime-charset-region): Use it.
+ * nntp.el (nntp-send-buffer): Use mm-with-unibyte-current-buffer.
+ * nnspool.el (nnspool-request-post): Ditto.
+
+2002-01-01 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el, gnus-art.el, gnus.el, gnus-cite.el:
+ Adapt face definitions to use :weight and :slant.
+
+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).
+
+2001-12-05 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-view.el (mm-inline-text): w3-coding-system-for-mime-charset
+ may not defined. From: Raja R Harinath <harinath@cs.umn.edu>.
+
+ * mm-view.el (mm-inline-message): Insert a newline unless bolp.
+
+ * gnus-sum.el (gnus-summary-save-article): Nix
+ gnus-display-mime-function and gnus-article-prepare-hook.
+
+2001-12-01 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-mail): Add send-actions.
+
+2001-11-28 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * gnus-sum.el (gnus-summary-limit-to-author): Fix the number of
+ arguments.
+
+2001-11-25 Stefan Monnier <monnier@cs.yale.edu>
+
+ * imap.el (imap-interactive-login, imap-open, imap-authenticate):
+ Use make-local-variable rather than make-variable-buffer-local.
+
+2001-11-25 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * message.el (message-forward-rmail-make-body): Use
+ save-window-excursion.
+ (message-encode-message-body): Use noerror when search.
+ (message-setup-1): Convert compose-mail send-actions to
+ message-send-actions.
+
+ * message.el (message-forward-subject-author-subject): Don't use
+ message-news-p, which widens the buffer.
+ (message-forward-make-body): New function.
+ (message-forward): Use it.
+ (message-insinuate-rmail): New function.
+ (message-forward-rmail-make-body): New function.
+
+ * gnus-util.el (gnus-directory-sep-char-regexp): New variable.
+ * gnus-score.el (gnus-score-find-bnews): Use it.
+ * mm-util.el (mm-iso-8859-x-to-15-region): Use
+ insert-before-markers.
+ From Jesper Harder <harder@ifa.au.dk>
+ * mm-util.el (mm-coding-system-priorities): Add backslash in the doc.
+ * mm-util.el (mm-coding-system-priorities): New variable.
+ (mm-sort-coding-systems-predicate): New function.
+ (mm-find-mime-charset-region): Resort coding systems if needed.
+ Suggested by Katsumi Yamaoka <yamaoka@jpl.org>.
+
+ * mm-util.el (mm-iso-8859-15-compatible): Fix doc.
+ (mm-hack-charsets): Fix doc.
+
+ * mm-util.el (mm-iso-8859-15-compatible): Add inconvertible chars.
+ (mm-iso-8859-x-to-15-table): Ditto.
+ (mm-iso-8859-x-to-15-region): Ditto.
+ (mm-find-mime-charset-region): Ditto.
+
+ * gnus-sum.el (gnus-summary-limit-to-subject): An exclusion version.
+ (gnus-summary-limit-to-author): Ditto.
+ (gnus-summary-limit-to-extra): Ditto.
+ (gnus-summary-find-matching): Support not-matching argument.
+
+ * message.el (message-wash-subject): Use `insert' rather than
+ `insert-string', which is deprecated.
+ From Kai Gro\e,A_\e(Bjohann <Kai.Grossjohann@CS.Uni-Dortmund.DE>
+
+2001-11-14 Sam Steingold <sds@gnu.org>
+
+ * gnus-score.el: Fixed some doc strings to properly quote symbols.
+
+2001-11-10 Pavel Jan\e,Al\e(Bk <Pavel@Janik.cz>
+
+ * gnus.el (gnus-local-domain): Reformat the doc-string to refer to
+ function `system-name' instead of both function and variable.
+
+2001-11-07 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mml.el (mml-preview): Bind mail-header-separator.
+
+2001-11-05 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mml.el (mml-generate-mime-1): Use mm-with-unibyte-current-buffer.
+ Suggested by Dave Love <fx@gnu.org>.
+
+2001-11-01 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-util.el (mm-charset-synonym-alist): Revert (some).
+
+2001-10-30 ShengHuo ZHU <zsh@cs.rochester.edu>
+
+ * mm-util.el (mm-iso-8859-x-to-15-region): New function.
+ (mm-hack-charsets): New variable.
+ (mm-iso-8859-15-compatible): New variable.
+ (mm-iso-8859-x-to-15-table): New variable.
+ (mm-find-mime-charset-region): Add parameter hack-charsets.
+
+ * mm-util.el (mm-charset-to-coding-system): Return nil, if charset
+ is nil.
+
+ * nnultimate.el, nnweb.el, nnslashdot.el: Update, because the web
+ pages are changed.
+
+ * mm-util.el (mm-mime-mule-charset-alist): Move down and call
+ mm-coding-system-p. Don't correct it only in XEmacs.
+ (mm-charset-to-coding-system): Use mm-coding-system-p and
+ mm-get-coding-system-list.
+ (mm-emacs-mule, mm-mule4-p): New.
+ (mm-enable-multibyte, mm-disable-multibyte,
+ mm-enable-multibyte-mule4, mm-disable-multibyte-mule4,
+ mm-with-unibyte-current-buffer,
+ mm-with-unibyte-current-buffer-mule4): Use them.
+ (mm-find-mime-charset-region): Treat iso-2022-jp.
+
+ From Dave Love <fx@gnu.org>:
+
+ * mm-util.el (mm-mime-mule-charset-alist): Make it correct by
+ construction.
+ (mm-charset-synonym-alist): Remove windows-125[02]. Make other
+ entries conditional on not having a coding system defined for
+ them.
+ (mm-mule-charset-to-mime-charset): Use
+ find-coding-systems-for-charsets if defined.
+ (mm-charset-to-coding-system): Don't use
+ mm-get-coding-system-list. Look in mm-charset-synonym-alist
+ later. Add last resort search of coding systems.
+ (mm-enable-multibyte-mule4, mm-disable-multibyte-mule4)
+ (mm-with-unibyte-current-buffer-mule4): Just treat Mule 5 like
+ Mule 4.
+ (mm-find-mime-charset-region): Re-write.
+ (mm-with-unibyte-current-buffer): Restore buffer as well as
+ multibyteness.
+
2001-10-30 Simon Josefsson <jas@extundo.com>
* nnimap.el (nnimap-date-days-ago): Defeat locale.
+2001-10-27 Stefan Monnier <monnier@cs.yale.edu>
+
+ * gnus-msg.el (gnus-setup-message): Setup reaper for MML buffers.
+
2001-09-27 Gerd Moellmann <gerd@gnu.org>
* gnus-ems.el (gnus-article-display-xface): Skip over previously
2001-09-19 Sam Steingold <sds@gnu.org>
- * gnus-win.el (gnus-buffer-configuration): Respect
- `gnus-bug-create-help-buffer'.
+ * gnus-win.el (gnus-buffer-configuration):
+ Respect `gnus-bug-create-help-buffer'.
2001-09-18 Pavel Jan\e,Am\e(Bk <Pavel@Janik.cz>
2001-09-18 Gerd Moellmann <gerd@gnu.org>
- * gnus-sum.el (gnus-select-newsgroup): Make
- `gnus-current-select-method' buffer-local.
+ * gnus-sum.el (gnus-select-newsgroup):
+ Make `gnus-current-select-method' buffer-local.
From TSUCHIYA Masatoshi <tsuchiya@pine.kuee.kyoto-u.ac.jp>.
* gnus-art.el (gnus-request-article-this-buffer): Refer to
* gnus-draft.el (gnus-draft-send): Move gnus-draft-setup inside of
let.
-2000-04-26 Pavel Janik ml. <Pavel.Janik@inet.cz>
+2000-04-26 Pavel Jan\e,Al\e(Bk <Pavel@Janik.cz>
* gnus-draft.el (gnus-draft-setup): Fix comments.
* pop3.el: New version.
-1999-07-05 Simon Josefsson
+1999-07-05 Simon Josefsson <jas@pdc.kth.se>
- * gnus-srvr.el (gnus-browse-foreign-server): Use read.
+ * gnus-srvr.el (gnus-browse-foreign-server): Use read.
1999-07-07 Lars Magne Ingebrigtsen <larsi@gnus.org>
;;; gnus-art.el --- article mode commands for Gnus
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(defun gnus-article-check-hidden-text (type arg)
"Return nil if hiding is necessary.
-Arg can be nil or a number. Nil and positive means hide, negative
+Arg can be nil or a number. nil and positive means hide, negative
means show, 0 means toggle."
(save-excursion
(save-restriction
(defun gnus-group-find-new-groups (&optional arg)
"Search for new groups and add them.
-Each new group will be treated with `gnus-subscribe-newsgroup-method.'
+Each new group will be treated with `gnus-subscribe-newsgroup-method'.
With 1 C-u, use the `ask-server' method to query the server for new
groups.
With 2 C-u's, use most complete method possible to query the server
;;;###autoload
(defun gnus-group-split-fancy
(&optional groups no-crosspost catch-all)
- "Uses information from group parameters in order to split mail. It
-can be embedded into nnmail-split-fancy lists with the SPLIT
+ "Uses information from group parameters in order to split mail.
+It can be embedded into `nnmail-split-fancy' lists with the SPLIT
\(: gnus-group-split-fancy GROUPS NO-CROSSPOST CATCH-ALL\)
(let ((mbl1 mml-buffer-list))
(setq mml-buffer-list mbl) ;; Global value
(set (make-local-variable 'mml-buffer-list) mbl1);; Local value
+ (add-hook 'change-major-mode-hook 'mml-destroy-buffers nil t)
(add-hook 'kill-buffer-hook 'mml-destroy-buffers t t))
(mml-destroy-buffers)
(setq mml-buffer-list mbl)))
If the name of a group is matched by REGEXP, the corresponding scorefiles
will be used for that group.
The first match found is used, subsequent matching entries are ignored (to
-use multiple matches, see gnus-score-file-multiple-match-alist).
+use multiple matches, see `gnus-score-file-multiple-match-alist').
These score files are loaded in addition to any files returned by
-gnus-score-find-score-files-function (which see)."
+`gnus-score-find-score-files-function'."
:group 'gnus-score-files
:type '(repeat (cons regexp (repeat file))))
will be used for that group.
If multiple REGEXPs match a group, the score files corresponding to each
match will be used (for only one match to be used, see
-gnus-score-file-single-match-alist).
+`gnus-score-file-single-match-alist').
These score files are loaded in addition to any files returned by
-gnus-score-find-score-files-function (which see)."
+`gnus-score-find-score-files-function'."
:group 'gnus-score-files
:type '(repeat (cons regexp (repeat file))))
Predefined values are:
-gnus-score-find-single: Only apply the group's own score file.
-gnus-score-find-hierarchical: Also apply score files from parent groups.
-gnus-score-find-bnews: Apply score files whose names matches.
+`gnus-score-find-single': Only apply the group's own score file.
+`gnus-score-find-hierarchical': Also apply score files from parent groups.
+`gnus-score-find-bnews': Apply score files whose names matches.
See the documentation to these functions for more information.
CHILD2 ...])' where PARENT is a header array and each CHILD is a list
of the same form as THREAD. The empty list `nil' is valid. For each
article in the tree, the score of the corresponding entry in
-GNUS-NEWSGROUP-SCORED is adjusted by SCORE-ADJUST."
+`gnus-newsgroup-scored' is adjusted by SCORE-ADJUST."
(while thread
(let ((head (car thread)))
(if (listp head)
A root is an article with no references. An orphan is an article
which has references, but is not connected via its references to a
root article. This function finds all the orphans, and adjusts their
-score in GNUS-NEWSGROUP-SCORED by SCORE."
+score in `gnus-newsgroup-scored' by SCORE."
(let ((threads (gnus-make-threads)))
;; gnus-make-threads produces a list, where each entry is a "thread"
;; as described in the gnus-score-lower-thread docs. This function
;; too much.
(delete-char (min (1- (point-max)) klen))
(goto-char (point-max))
- (search-backward (string directory-sep-char))
- (delete-region (1+ (point)) (point-min)))
+ (if (re-search-backward gnus-directory-sep-char-regexp nil t)
+ (delete-region (1+ (point)) (point-min))
+ (gnus-message 1 "Can't find directory separator in %s"
+ (car sfiles))))
;; If short file names were used, we have to translate slashes.
(goto-char (point-min))
(let ((regexp (concat
;; we add this score file to the list of score files
;; applicable to this group.
(when (or (and not-match
- (ignore-errors
+ (ignore-errors
(not (string-match regexp group-trans))))
- (and (not not-match)
- (ignore-errors (string-match regexp group-trans))))
+ (and (not not-match)
+ (ignore-errors (string-match regexp group-trans))))
(push (car sfiles) ofiles)))
(setq sfiles (cdr sfiles)))
(kill-buffer (current-buffer))
(defun gnus-score-find-alist (group)
"Return list of score files for GROUP.
-The list is determined from the variable gnus-score-file-alist."
+The list is determined from the variable `gnus-score-file-alist'."
(let ((alist gnus-score-file-multiple-match-alist)
score-files)
;; if this group has been seen before, return the cached entry
(unless (eq major-mode 'gnus-summary-mode)
(set-buffer gnus-summary-buffer))
(let ((article (or article (gnus-summary-article-number)))
- (all-headers (not (not all-headers))) ;Must be T or NIL.
+ (all-headers (not (not all-headers))) ;Must be t or nil.
gnus-summary-display-article-function)
(and (not pseudo)
(gnus-summary-article-pseudo-p article)
(gnus-summary-limit nil 'pop)
(gnus-summary-position-point)))
-(defun gnus-summary-limit-to-subject (subject &optional header)
- "Limit the summary buffer to articles that have subjects that match a regexp."
- (interactive "sLimit to subject (regexp): ")
+(defun gnus-summary-limit-to-subject (subject &optional header not-matching)
+ "Limit the summary buffer to articles that have subjects that match a regexp.
+If NOT-MATCHING, excluding articles that have subjects that match a regexp."
+ (interactive
+ (list (read-string (if current-prefix-arg
+ "Exclude subject (regexp): "
+ "Limit to subject (regexp): "))
+ nil current-prefix-arg))
(unless header
(setq header "subject"))
(when (not (equal "" subject))
(prog1
(let ((articles (gnus-summary-find-matching
- (or header "subject") subject 'all)))
+ (or header "subject") subject 'all nil nil
+ not-matching)))
(unless articles
(error "Found no matches for \"%s\"" subject))
(gnus-summary-limit articles))
(gnus-summary-position-point))))
-(defun gnus-summary-limit-to-author (from)
- "Limit the summary buffer to articles that have authors that match a regexp."
- (interactive "sLimit to author (regexp): ")
- (gnus-summary-limit-to-subject from "from"))
+(defun gnus-summary-limit-to-author (from &optional not-matching)
+ "Limit the summary buffer to articles that have authors that match a regexp.
+If NOT-MATCHING, excluding articles that have authors that match a regexp."
+ (interactive
+ (list (read-string (if current-prefix-arg
+ "Exclude author (regexp): "
+ "Limit to author (regexp): "))
+ current-prefix-arg))
+ (gnus-summary-limit-to-subject from "from" not-matching))
(defun gnus-summary-limit-to-age (age &optional younger-p)
"Limit the summary buffer to articles that are older than (or equal) AGE days.
(gnus-summary-limit (nreverse articles)))
(gnus-summary-position-point)))
-(defun gnus-summary-limit-to-extra (header regexp)
+(defun gnus-summary-limit-to-extra (header regexp &optional not-matching)
"Limit the summary buffer to articles that match an 'extra' header."
(interactive
(let ((header
(intern
(gnus-completing-read
(symbol-name (car gnus-extra-headers))
- "Limit extra header:"
+ (if current-prefix-arg
+ "Exclude extra header:"
+ "Limit extra header:")
(mapcar (lambda (x)
(cons (symbol-name x) x))
gnus-extra-headers)
nil
t))))
(list header
- (read-string (format "Limit to header %s (regexp): " header)))))
+ (read-string (format "%s header %s (regexp): "
+ (if current-prefix-arg "Exclude" "Limit to")
+ header))
+ current-prefix-arg)))
(when (not (equal "" regexp))
(prog1
(let ((articles (gnus-summary-find-matching
- (cons 'extra header) regexp 'all)))
+ (cons 'extra header) regexp 'all nil nil
+ not-matching)))
(unless articles
(error "Found no matches for \"%s\"" regexp))
(gnus-summary-limit articles))
t)))
(defun gnus-summary-find-matching (header regexp &optional backward unread
- not-case-fold)
+ not-case-fold not-matching)
"Return a list of all articles that match REGEXP on HEADER.
The search stars on the current article and goes forwards unless
BACKWARD is non-nil. If BACKWARD is `all', do all articles.
If UNREAD is non-nil, only unread articles will
be taken into consideration. If NOT-CASE-FOLD, case won't be folded
-in the comparisons."
- (let ((data (if (eq backward 'all) gnus-newsgroup-data
- (gnus-data-find-list
- (gnus-summary-article-number) (gnus-data-list backward))))
- (case-fold-search (not not-case-fold))
+in the comparisons. If NOT-MATCHING, return a list of all articles that
+not match REGEXP on HEADER."
+ (let ((case-fold-search (not not-case-fold))
articles d func)
(if (consp header)
(if (eq (car header) 'extra)
(unless (fboundp (intern (concat "mail-header-" header)))
(error "%s is not a valid header" header))
(setq func `(lambda (h) (,(intern (concat "mail-header-" header)) h))))
- (while data
- (setq d (car data))
- (and (or (not unread) ; We want all articles...
- (gnus-data-unread-p d)) ; Or just unreads.
- (vectorp (gnus-data-header d)) ; It's not a pseudo.
- (string-match regexp (funcall func (gnus-data-header d))) ; Match.
- (push (gnus-data-number d) articles)) ; Success!
- (setq data (cdr data)))
+ (dolist (d (if (eq backward 'all)
+ gnus-newsgroup-data
+ (gnus-data-find-list
+ (gnus-summary-article-number)
+ (gnus-data-list backward))))
+ (when (and (or (not unread) ; We want all articles...
+ (gnus-data-unread-p d)) ; Or just unreads.
+ (vectorp (gnus-data-header d)) ; It's not a pseudo.
+ (if not-matching
+ (not (string-match
+ regexp
+ (funcall func (gnus-data-header d))))
+ (string-match regexp
+ (funcall func (gnus-data-header d)))))
+ (push (gnus-data-number d) articles))) ; Success!
(nreverse articles)))
(defun gnus-summary-execute-command (header regexp command &optional backward)
(gnus-message 1 "Article %d is unsaveable" article))
;; This is a real article.
(save-window-excursion
- (gnus-summary-select-article t nil nil article))
+ (let ((gnus-display-mime-function nil)
+ (gnus-article-prepare-hook nil))
+ (gnus-summary-select-article t nil nil article)))
(save-excursion
(set-buffer save-buffer)
(erase-buffer)
(remove-text-properties start end properties object))
t))
+(defvar gnus-directory-sep-char-regexp "/"
+ "The regexp of directory separator character.
+If you find some problem with the directory separator character, try
+\"[/\\\\\]\" for some systems.")
+
(provide 'gnus-util)
;;; gnus-util.el ends here
;;; gnus.el --- a newsreader for GNU Emacs
-;; Copyright (C) 1987, 1988, 1989, 1990, 1993, 1994, 1995, 1996,
-;; 1997, 1998, 2000, 2001 Free Software Foundation, Inc.
+;; Copyright (C) 1987, 1988, 1989, 1990, 1993, 1994, 1995, 1996, 1997,
+;; 1998, 2000, 2001, 2002 Free Software Foundation, Inc.
;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
;; Lars Magne Ingebrigtsen <larsi@gnus.org>
(defcustom gnus-local-domain nil
"Local domain name without a host name.
The DOMAINNAME environment variable is used instead if it is defined.
-If the `system-name' function returns the full Internet name, there is
+If the function `system-name' returns the full Internet name, there is
no need to set this variable."
:group 'gnus-message
:type '(choice (const :tag "default" nil)
it where sucessful authenticating itself to the server, nil otherwise.
Returns t if login was successful, nil otherwise."
(with-current-buffer buffer
- (make-variable-buffer-local 'imap-username)
- (make-variable-buffer-local 'imap-password)
+ (make-local-variable 'imap-username)
+ (make-local-variable 'imap-password)
(let (user passwd ret)
;; (condition-case ()
(while (or (not user) (not passwd))
(with-current-buffer (get-buffer-create buffer)
(if (imap-opened buffer)
(imap-close buffer))
- (mapcar 'make-variable-buffer-local imap-local-variables)
+ (mapcar 'make-local-variable imap-local-variables)
(imap-disable-multibyte)
(buffer-disable-undo)
(setq imap-server (or server imap-server))
(or (eq imap-state 'auth)
(eq imap-state 'select)
(eq imap-state 'examine))
- (make-variable-buffer-local 'imap-username)
- (make-variable-buffer-local 'imap-password)
+ (make-local-variable 'imap-username)
+ (make-local-variable 'imap-password)
(if user (setq imap-username user))
(if passwd (setq imap-password passwd))
(if (funcall (nth 2 (assq imap-auth imap-authenticator-alist)) buffer)
;;
;; addr-adl = nstring
;; ; Holds route from [RFC-822] route-addr if
-;; ; non-NIL
+;; ; non-nil
;;
;; addr-host = nstring
-;; ; NIL indicates [RFC-822] group syntax.
+;; ; nil indicates [RFC-822] group syntax.
;; ; Otherwise, holds [RFC-822] domain name
;;
;; addr-mailbox = nstring
-;; ; NIL indicates end of [RFC-822] group; if
-;; ; non-NIL and addr-host is NIL, holds
+;; ; nil indicates end of [RFC-822] group; if
+;; ; non-nil and addr-host is nil, holds
;; ; [RFC-822] group name.
;; ; Otherwise, holds [RFC-822] local-part
;; ; after removing [RFC-822] quoting
;;
;; addr-name = nstring
-;; ; If non-NIL, holds phrase from [RFC-822]
+;; ; If non-nil, holds phrase from [RFC-822]
;; ; mailbox after removing [RFC-822] quoting
;;
(push (imap-parse-nstring) body);; body-fld-desc
(imap-forward)
;; next `or' for Sun SIMS bug, it regard body-fld-enc as a
- ;; nstring and return NIL instead of defaulting back to 7BIT
+ ;; nstring and return nil instead of defaulting back to 7BIT
;; as the standard says.
(push (or (imap-parse-nstring) "7BIT") body);; body-fld-enc
(imap-forward)
(defcustom mailcap-download-directory nil
"*Directory to which `mailcap-save-binary-file' downloads files by default.
-Nil means your home directory."
+nil means your home directory."
:type '(choice (const :tag "Home directory" nil)
directory)
:group 'mailcap)
;;; message.el --- composing mail and news messages -*- coding: iso-latin-1 -*-
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(push '(message-mode (encrypt . mc-encrypt-message)
(sign . mc-sign-message))
mc-modes-alist))
- (when actions
- (setq message-send-actions actions))
+ (dolist (action actions)
+ (condition-case nil
+ (add-to-list 'message-send-actions
+ `(apply ',(car action) ',(cdr action)))))
(setq message-reply-buffer replybuffer)
(goto-char (point-min))
;; Insert all the headers.
(nconc
`((To . ,(or to "")) (Subject . ,(or subject "")))
(when other-headers other-headers))
- replybuffer)
+ replybuffer send-actions)
;; FIXME: Should return nil if failure.
t))
"Remove junk like \"Re:\", \"(fwd)\", etc. added to subject string SUBJECT.
Previous forwarders, replyers, etc. may add it."
(with-temp-buffer
- (insert-string subject)
+ (insert subject)
(goto-char (point-min))
;; strip Re/Fwd stuff off the beginning
(while (re-search-forward
the list of newsgroups is was posted to."
(concat "["
(let ((prefix
- (or (message-fetch-field
- (if (message-news-p) "newsgroups" "from"))
+ (or (message-fetch-field "newsgroups")
+ (message-fetch-field "from")
"(nowhere)")))
(if message-forward-decoded-p
prefix
(eval-when-compile
(defvar gnus-article-decoded-p))
+
;;;###autoload
(defun message-forward (&optional news digest)
"Forward the current message via mail.
Optional DIGEST will use digest to forward."
(interactive "P")
(let* ((cur (current-buffer))
- (message-forward-decoded-p
+ (message-forward-decoded-p
(if (local-variable-p 'gnus-article-decoded-p (current-buffer))
- gnus-article-decoded-p ;; In an article buffer.
+ gnus-article-decoded-p ;; In an article buffer.
message-forward-decoded-p))
- (subject (message-make-forward-subject))
- art-beg)
+ (subject (message-make-forward-subject)))
(if news
(message-news nil subject)
(message-mail nil subject))
- ;; Put point where we want it before inserting the forwarded
- ;; message.
- (if message-forward-before-signature
- (message-goto-body)
- (goto-char (point-max)))
- (if message-forward-as-mime
- (if digest
- (insert "\n<#multipart type=digest>\n")
- (if message-forward-show-mml
- (insert "\n\n<#mml type=message/rfc822 disposition=inline>\n")
- (insert "\n\n<#part type=message/rfc822 disposition=inline raw=t>\n")))
- (insert "\n-------------------- Start of forwarded message --------------------\n"))
- (let ((b (point)) e)
+ (message-forward-make-body cur digest)))
+
+;;;###autoload
+(defun message-forward-make-body (forward-buffer &optional digest)
+ ;; Put point where we want it before inserting the forwarded
+ ;; message.
+ (if message-forward-before-signature
+ (message-goto-body)
+ (goto-char (point-max)))
+ (if message-forward-as-mime
(if digest
- (if message-forward-as-mime
- (insert-buffer-substring cur)
- (mml-insert-buffer cur))
- (if (and message-forward-show-mml
- (not message-forward-decoded-p))
- (insert
- (with-temp-buffer
- (mm-disable-multibyte-mule4) ;; Must copy buffer in unibyte mode
+ (insert "\n<#multipart type=digest>\n")
+ (if message-forward-show-mml
+ (insert "\n\n<#mml type=message/rfc822 disposition=inline>\n")
+ (insert "\n\n<#part type=message/rfc822 disposition=inline raw=t>\n")))
+ (insert "\n-------------------- Start of forwarded message --------------------\n"))
+ (let ((b (point)) e)
+ (if digest
+ (if message-forward-as-mime
+ (insert-buffer-substring forward-buffer)
+ (mml-insert-buffer forward-buffer))
+ (if (and message-forward-show-mml
+ (not message-forward-decoded-p))
+ (insert
+ (with-temp-buffer
+ (mm-disable-multibyte-mule4) ;; Must copy buffer in unibyte mode
(insert
- (with-current-buffer cur
+ (with-current-buffer forward-buffer
(mm-string-as-unibyte (buffer-string))))
(mm-enable-multibyte-mule4)
(mime-to-mml)
(when (looking-at "From ")
(replace-match "X-From-Line: "))
(buffer-string)))
- (save-restriction
- (narrow-to-region (point) (point))
- (mml-insert-buffer cur)
- (goto-char (point-min))
- (when (looking-at "From ")
- (replace-match "X-From-Line: "))
- (goto-char (point-max)))))
- (setq e (point))
- (if message-forward-as-mime
- (if digest
- (insert "<#/multipart>\n")
- (if message-forward-show-mml
- (insert "<#/mml>\n")
- (insert "<#/part>\n")))
- (insert "\n-------------------- End of forwarded message --------------------\n"))
- (if (and digest message-forward-as-mime)
- (save-restriction
- (narrow-to-region b e)
- (goto-char b)
- (narrow-to-region (point)
- (or (search-forward "\n\n" nil t) (point)))
- (delete-region (point-min) (point-max)))
- (when (and (not current-prefix-arg)
- message-forward-ignored-headers)
- (save-restriction
- (narrow-to-region b e)
- (goto-char b)
- (narrow-to-region (point)
- (or (search-forward "\n\n" nil t) (point)))
- (message-remove-header message-forward-ignored-headers t)))))
- (message-position-point)))
+ (save-restriction
+ (narrow-to-region (point) (point))
+ (mml-insert-buffer forward-buffer)
+ (goto-char (point-min))
+ (when (looking-at "From ")
+ (replace-match "X-From-Line: "))
+ (goto-char (point-max)))))
+ (setq e (point))
+ (if message-forward-as-mime
+ (if digest
+ (insert "<#/multipart>\n")
+ (if message-forward-show-mml
+ (insert "<#/mml>\n")
+ (insert "<#/part>\n")))
+ (insert "\n-------------------- End of forwarded message --------------------\n"))
+ (if (and digest message-forward-as-mime)
+ (save-restriction
+ (narrow-to-region b e)
+ (goto-char b)
+ (narrow-to-region (point)
+ (or (search-forward "\n\n" nil t) (point)))
+ (delete-region (point-min) (point-max)))
+ (when (and (not current-prefix-arg)
+ message-forward-ignored-headers)
+ (save-restriction
+ (narrow-to-region b e)
+ (goto-char b)
+ (narrow-to-region (point)
+ (or (search-forward "\n\n" nil t) (point)))
+ (message-remove-header message-forward-ignored-headers t)))))
+ (message-position-point))
+
+;;;###autoload
+(defun message-forward-rmail-make-body (forward-buffer)
+ (save-window-excursion
+ (set-buffer forward-buffer)
+ (if (rmail-msg-is-pruned)
+ (rmail-msg-restore-non-pruned-header)))
+ (message-forward-make-body forward-buffer))
+
+;;;###autoload
+(defun message-insinuate-rmail ()
+ "Let RMAIL uses message to forward."
+ (interactive)
+ (setq rmail-enable-mime-composing t)
+ (setq rmail-insert-mime-forwarded-message-function
+ 'message-forward-rmail-make-body))
;;;###autoload
(defun message-resend (address)
;; /usr/bin/mail.
(unless content-type-p
(goto-char (point-min))
- (re-search-forward "^MIME-Version:")
- (forward-line 1)
- (insert "Content-Type: text/plain; charset=us-ascii\n")))))
+ ;; For unknown reason, MIME-Version doesn't exist.
+ (when (re-search-forward "^MIME-Version:" nil t)
+ (forward-line 1)
+ (insert "Content-Type: text/plain; charset=us-ascii\n"))))))
(defun message-read-from-minibuffer (prompt)
"Read from the minibuffer while providing abbrev expansion."
-;;; mm-util.el --- utility functions for MIME things
-;; Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+;;; mm-util.el --- Utility functions for Mule and low level things
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; MORIOKA Tomohiko <morioka@jaist.ac.jp>
(eval-when-compile (require 'cl))
(require 'mail-prsvr)
-(defun mm-coding-system-p (sym)
- "Return non-nil if SYM is a coding system."
- (or (and (fboundp 'coding-system-p) (coding-system-p sym))
- (memq sym (mm-get-coding-system-list))))
-
-(defvar mm-mime-mule-charset-alist
- `((us-ascii ascii)
- (iso-8859-1 latin-iso8859-1)
- (iso-8859-2 latin-iso8859-2)
- (iso-8859-3 latin-iso8859-3)
- (iso-8859-4 latin-iso8859-4)
- (iso-8859-5 cyrillic-iso8859-5)
- ;; Non-mule (X)Emacs uses the last mule-charset for 8bit characters.
- ;; The fake mule-charset, gnus-koi8-r, tells Gnus that the default
- ;; charset is koi8-r, not iso-8859-5.
- (koi8-r cyrillic-iso8859-5 gnus-koi8-r)
- (iso-8859-6 arabic-iso8859-6)
- (iso-8859-7 greek-iso8859-7)
- (iso-8859-8 hebrew-iso8859-8)
- (iso-8859-9 latin-iso8859-9)
- (iso-8859-14 latin-iso8859-14)
- (iso-8859-15 latin-iso8859-15)
- (viscii vietnamese-viscii-lower)
- (iso-2022-jp latin-jisx0201 japanese-jisx0208 japanese-jisx0208-1978)
- (euc-kr korean-ksc5601)
- (gb2312 chinese-gb2312)
- (big5 chinese-big5-1 chinese-big5-2)
- (tibetan tibetan)
- (thai-tis620 thai-tis620)
- (iso-2022-7bit ethiopic arabic-1-column arabic-2-column)
- (iso-2022-jp-2 latin-iso8859-1 greek-iso8859-7
- latin-jisx0201 japanese-jisx0208-1978
- chinese-gb2312 japanese-jisx0208
- korean-ksc5601 japanese-jisx0212
- katakana-jisx0201)
- (iso-2022-int-1 latin-iso8859-1 greek-iso8859-7
- latin-jisx0201 japanese-jisx0208-1978
- chinese-gb2312 japanese-jisx0208
- korean-ksc5601 japanese-jisx0212
- chinese-cns11643-1 chinese-cns11643-2)
- (iso-2022-int-1 latin-iso8859-1 latin-iso8859-2
- cyrillic-iso8859-5 greek-iso8859-7
- latin-jisx0201 japanese-jisx0208-1978
- chinese-gb2312 japanese-jisx0208
- korean-ksc5601 japanese-jisx0212
- chinese-cns11643-1 chinese-cns11643-2
- chinese-cns11643-3 chinese-cns11643-4
- chinese-cns11643-5 chinese-cns11643-6
- chinese-cns11643-7)
- ;; utf-8 comes either from Mule-UCS or Mule 5+.
- ,@(if (mm-coding-system-p 'utf-8)
- (list (cons 'utf-8 (delete 'ascii
- (coding-system-get
- 'mule-utf-8
- 'safe-charsets))))))
- "Alist of MIME-charset/MULE-charsets.")
-
(eval-and-compile
(mapcar
(lambda (elem)
(make-char
. (lambda (charset int)
(int-to-char int)))
- (read-coding-system
- . (lambda (prompt)
- "Prompt the user for a coding system."
- (completing-read
- prompt (mapcar (lambda (s) (list (symbol-name (car s))))
- mm-mime-mule-charset-alist))))
(read-charset
. (lambda (prompt)
"Return a charset."
(mapcar (lambda (e) (list (symbol-name (car e))))
mm-mime-mule-charset-alist)
nil t))))
+ (subst-char-in-string
+ . (lambda (from to string) ;; stolen (and renamed) from nnheader.el
+ "Replace characters in STRING from FROM to TO."
+ (let ((string (substring string 0)) ;Copy string.
+ (len (length string))
+ (idx 0))
+ ;; Replace all occurrences of FROM with TO.
+ (while (< idx len)
+ (when (= (aref string idx) from)
+ (aset string idx to))
+ (setq idx (1+ idx)))
+ string)))
(string-as-unibyte . identity)
- (multibyte-string-p . ignore)
- )))
+ (string-as-multibyte . identity)
+ (multibyte-string-p . ignore))))
(eval-and-compile
(defalias 'mm-char-or-char-int-p
- (cond
+ (cond
((fboundp 'char-or-char-int-p) 'char-or-char-int-p)
- ((fboundp 'char-valid-p) 'char-valid-p)
+ ((fboundp 'char-valid-p) 'char-valid-p)
(t 'identity))))
+(eval-and-compile
+ (defalias 'mm-read-coding-system
+ (cond
+ ((fboundp 'read-coding-system)
+ (if (and (featurep 'xemacs)
+ (<= (string-to-number emacs-version) 21.1))
+ (lambda (prompt &optional default-coding-system)
+ (read-coding-system prompt))
+ 'read-coding-system))
+ (t (lambda (prompt &optional default-coding-system)
+ "Prompt the user for a coding system."
+ (completing-read
+ prompt (mapcar (lambda (s) (list (symbol-name (car s))))
+ mm-mime-mule-charset-alist)))))))
+
(defvar mm-coding-system-list nil)
(defun mm-get-coding-system-list ()
"Get the coding system list."
(or mm-coding-system-list
(setq mm-coding-system-list (mm-coding-system-list))))
+(defun mm-coding-system-p (sym)
+ "Return non-nil if SYM is a coding system."
+ (or (and (fboundp 'coding-system-p) (coding-system-p sym))
+ (memq sym (mm-get-coding-system-list))))
+
(defvar mm-charset-synonym-alist
- `((big5 . cn-big5)
- (gb2312 . cn-gb-2312)
+ `(
+ ;; Perfectly fine? A valid MIME name, anyhow.
+ ,@(unless (mm-coding-system-p 'big5)
+ '((big5 . cn-big5)))
+ ;; Not in XEmacs, but it's not a proper MIME charset anyhow.
+ ,@(unless (mm-coding-system-p 'x-ctext)
+ '((x-ctext . ctext)))
+ ;; Apparently not defined in Emacs 20, but is a valid MIME name.
+ ,@(unless (mm-coding-system-p 'gb2312)
+ '((gb2312 . cn-gb-2312)))
+ ;; ISO-8859-15 is very similar to ISO-8859-1.
+ ,@(unless (mm-coding-system-p 'iso-8859-15) ; Emacs 21 defines it.
+ '((iso-8859-15 . iso-8859-1)))
;; Windows-1252 is actually a superset of Latin-1. See also
;; `gnus-article-dumbquotes-map'.
- ,(unless (mm-coding-system-p 'windows-1252) ; should be defined eventually
- '(windows-1252 . iso-8859-1))
+ ,@(unless (mm-coding-system-p 'windows-1252)
+ (if (mm-coding-system-p 'cp1252)
+ '((windows-1252 . cp1252))
+ '((windows-1252 . iso-8859-1))))
;; Windows-1250 is a variant of Latin-2 heavily used by Microsoft
;; Outlook users in Czech republic. Use this to allow reading of their
;; e-mails. cp1250 should be defined by M-x codepage-setup.
- ,(unless (mm-coding-system-p 'windows-1250) ; should be defined eventually
- '(windows-1250 . cp1250))
- (x-ctext . ctext))
+ ,@(if (and (not (mm-coding-system-p 'windows-1250))
+ (mm-coding-system-p 'cp1250))
+ '((windows-1250 . cp1250)))
+ )
"A mapping from invalid charset names to the real charset names.")
(defvar mm-binary-coding-system
- (cond
+ (cond
((mm-coding-system-p 'binary) 'binary)
((mm-coding-system-p 'no-conversion) 'no-conversion)
(t nil))
"Text coding system for write.")
(defvar mm-auto-save-coding-system
- (cond
+ (cond
((mm-coding-system-p 'emacs-mule)
(if (memq system-type '(windows-nt ms-dos ms-windows))
- (if (mm-coding-system-p 'emacs-mule-dos)
+ (if (mm-coding-system-p 'emacs-mule-dos)
'emacs-mule-dos mm-binary-coding-system)
'emacs-mule))
((mm-coding-system-p 'escape-quoted) 'escape-quoted)
(t mm-binary-coding-system))
"Coding system of auto save file.")
+(defvar mm-universal-coding-system mm-auto-save-coding-system
+ "The universal coding system.")
+
+;; Fixme: some of the cars here aren't valid MIME charsets. That
+;; should only matter with XEmacs, though.
+(defvar mm-mime-mule-charset-alist
+ `((us-ascii ascii)
+ (iso-8859-1 latin-iso8859-1)
+ (iso-8859-2 latin-iso8859-2)
+ (iso-8859-3 latin-iso8859-3)
+ (iso-8859-4 latin-iso8859-4)
+ (iso-8859-5 cyrillic-iso8859-5)
+ ;; Non-mule (X)Emacs uses the last mule-charset for 8bit characters.
+ ;; The fake mule-charset, gnus-koi8-r, tells Gnus that the default
+ ;; charset is koi8-r, not iso-8859-5.
+ (koi8-r cyrillic-iso8859-5 gnus-koi8-r)
+ (iso-8859-6 arabic-iso8859-6)
+ (iso-8859-7 greek-iso8859-7)
+ (iso-8859-8 hebrew-iso8859-8)
+ (iso-8859-9 latin-iso8859-9)
+ (iso-8859-14 latin-iso8859-14)
+ (iso-8859-15 latin-iso8859-15)
+ (viscii vietnamese-viscii-lower)
+ (iso-2022-jp latin-jisx0201 japanese-jisx0208 japanese-jisx0208-1978)
+ (euc-kr korean-ksc5601)
+ (gb2312 chinese-gb2312)
+ (big5 chinese-big5-1 chinese-big5-2)
+ (tibetan tibetan)
+ (thai-tis620 thai-tis620)
+ (iso-2022-7bit ethiopic arabic-1-column arabic-2-column)
+ (iso-2022-jp-2 latin-iso8859-1 greek-iso8859-7
+ latin-jisx0201 japanese-jisx0208-1978
+ chinese-gb2312 japanese-jisx0208
+ korean-ksc5601 japanese-jisx0212
+ katakana-jisx0201)
+ (iso-2022-int-1 latin-iso8859-1 greek-iso8859-7
+ latin-jisx0201 japanese-jisx0208-1978
+ chinese-gb2312 japanese-jisx0208
+ korean-ksc5601 japanese-jisx0212
+ chinese-cns11643-1 chinese-cns11643-2)
+ (iso-2022-int-1 latin-iso8859-1 latin-iso8859-2
+ cyrillic-iso8859-5 greek-iso8859-7
+ latin-jisx0201 japanese-jisx0208-1978
+ chinese-gb2312 japanese-jisx0208
+ korean-ksc5601 japanese-jisx0212
+ chinese-cns11643-1 chinese-cns11643-2
+ chinese-cns11643-3 chinese-cns11643-4
+ chinese-cns11643-5 chinese-cns11643-6
+ chinese-cns11643-7)
+ ,(if (or (not (fboundp 'charsetp)) ;; non-Mule case
+ (charsetp 'unicode-a)
+ (not (mm-coding-system-p 'mule-utf-8)))
+ '(utf-8 unicode-a unicode-b unicode-c unicode-d unicode-e)
+ ;; If we have utf-8 we're in Mule 5+.
+ (append '(utf-8)
+ (delete 'ascii
+ (coding-system-get 'mule-utf-8 'safe-charsets)))))
+ "Alist of MIME-charset/MULE-charsets.")
+
+;; Correct by construction, but should be unnecessary:
+;; XEmacs hates it.
+(when (and (not (featurep 'xemacs))
+ (fboundp 'coding-system-list)
+ (fboundp 'sort-coding-systems))
+ (setq mm-mime-mule-charset-alist
+ (apply
+ 'nconc
+ (mapcar
+ (lambda (cs)
+ (when (and (coding-system-get cs 'mime-charset)
+ (not (eq t (coding-system-get cs 'safe-charsets))))
+ (list (cons (coding-system-get cs 'mime-charset)
+ (delq 'ascii
+ (coding-system-get cs 'safe-charsets))))))
+ (sort-coding-systems (coding-system-list 'base-only))))))
+
+(defvar mm-hack-charsets '(iso-8859-15 iso-2022-jp-2)
+ "A list of special charsets.
+Valid elements include:
+`iso-8859-15' convert ISO-8859-1, -9 to ISO-8859-15 if ISO-8859-15 exists.
+`iso-2022-jp-2' convert ISO-2022-jp to ISO-2022-jp-2 if ISO-2022-jp-2 exists."
+)
+
+(defvar mm-iso-8859-15-compatible
+ '((iso-8859-1 "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE")
+ (iso-8859-9 "\xA4\xA6\xA8\xB4\xB8\xBC\xBD\xBE\xD0\xDD\xDE\xF0\xFD\xFE"))
+ "ISO-8859-15 exchangeable coding systems and inconvertible characters.")
+
+(defvar mm-iso-8859-x-to-15-table
+ (and (fboundp 'coding-system-p)
+ (mm-coding-system-p 'iso-8859-15)
+ (mapcar
+ (lambda (cs)
+ (if (mm-coding-system-p (car cs))
+ (let ((c (string-to-char
+ (decode-coding-string "\341" (car cs)))))
+ (cons (char-charset c)
+ (cons
+ (- (string-to-char
+ (decode-coding-string "\341" 'iso-8859-15)) c)
+ (string-to-list (decode-coding-string (car (cdr cs))
+ (car cs))))))
+ '(gnus-charset 0)))
+ mm-iso-8859-15-compatible))
+ "A table of the difference character between ISO-8859-X and ISO-8859-15.")
+
+(defvar mm-coding-system-priorities nil
+ "Preferred coding systems for encoding outgoing mails.
+
+More than one suitable coding systems may be found for some texts. By
+default, a coding system with the highest priority is used to encode
+outgoing mails (see `sort-coding-systems'). If this variable is set,
+it overrides the default priority. For example, Japanese users may
+prefer iso-2022-jp to japanese-shift-jis:
+
+\(setq mm-coding-system-priorities
+ '(iso-2022-jp iso-2022-jp-2 japanese-shift-jis utf-8))
+")
+
+(defvar mm-use-find-coding-systems-region
+ (fboundp 'find-coding-systems-region)
+ "Use `find-coding-systems-region' to find proper coding systems.")
+
;;; Internal variables:
;;; Functions:
(defun mm-mule-charset-to-mime-charset (charset)
"Return the MIME charset corresponding to the given Mule CHARSET."
- (let ((alist mm-mime-mule-charset-alist)
- out)
- (while alist
- (when (memq charset (cdar alist))
- (setq out (caar alist)
- alist nil))
- (pop alist))
- out))
+ (if (fboundp 'find-coding-systems-for-charsets)
+ (let (mime)
+ (dolist (cs (find-coding-systems-for-charsets (list charset)))
+ (unless mime
+ (when cs
+ (setq mime (coding-system-get cs 'mime-charset)))))
+ mime)
+ (let ((alist mm-mime-mule-charset-alist)
+ out)
+ (while alist
+ (when (memq charset (cdar alist))
+ (setq out (caar alist)
+ alist nil))
+ (pop alist))
+ out)))
(defun mm-charset-to-coding-system (charset &optional lbt)
"Return coding-system corresponding to CHARSET.
used as the line break code type of the coding system."
(when (stringp charset)
(setq charset (intern (downcase charset))))
- (setq charset
- (or (cdr (assq charset mm-charset-synonym-alist))
- charset))
(when lbt
(setq charset (intern (format "%s-%s" charset lbt))))
(cond
+ ((null charset)
+ charset)
;; Running in a non-MULE environment.
((null (mm-get-coding-system-list))
charset)
'ascii)
;; Check to see whether we can handle this charset. (This depends
;; on there being some coding system matching each `mime-charset'
- ;; coding sysytem property defined, as there should be.)
- ((memq charset (mm-get-coding-system-list))
+ ;; property defined, as there should be.)
+ ((and (mm-coding-system-p charset)
+;;; Doing this would potentially weed out incorrect charsets.
+;;; charset
+;;; (eq charset (coding-system-get charset 'mime-charset))
+ )
charset)
- ;; Nope.
- (t
- nil)))
-
-(if (fboundp 'subst-char-in-string)
- (defsubst mm-replace-chars-in-string (string from to)
- (subst-char-in-string from to string))
- (defun mm-replace-chars-in-string (string from to)
- "Replace characters in STRING from FROM to TO."
- (let ((string (substring string 0)) ;Copy string.
- (len (length string))
- (idx 0))
- ;; Replace all occurrences of FROM with TO.
- (while (< idx len)
- (when (= (aref string idx) from)
- (aset string idx to))
- (setq idx (1+ idx)))
- string)))
-
-(defsubst mm-enable-multibyte ()
- "Set the multibyte flag of the current buffer.
+ ;; Translate invalid charsets.
+ ((let ((cs (cdr (assq charset mm-charset-synonym-alist))))
+ (and cs (mm-coding-system-p charset) cs)))
+ ;; Last resort: search the coding system list for entries which
+ ;; have the right mime-charset in case the canonical name isn't
+ ;; defined (though it should be).
+ ((let (cs)
+ ;; mm-get-coding-system-list returns a list of cs without lbt.
+ ;; Do we need -lbt?
+ (dolist (c (mm-get-coding-system-list))
+ (if (and (null cs)
+ (eq charset (coding-system-get c 'mime-charset)))
+ (setq cs c)))
+ cs))))
+
+(defsubst mm-replace-chars-in-string (string from to)
+ (mm-subst-char-in-string from to string))
+
+(eval-and-compile
+ (defvar mm-emacs-mule (and (not (featurep 'xemacs))
+ (boundp 'default-enable-multibyte-characters)
+ default-enable-multibyte-characters
+ (fboundp 'set-buffer-multibyte))
+ "Emacs mule.")
+
+ (defvar mm-mule4-p (and mm-emacs-mule
+ (fboundp 'charsetp)
+ (not (charsetp 'eight-bit-control)))
+ "Mule version 4.")
+
+ (if mm-emacs-mule
+ (defun mm-enable-multibyte ()
+ "Set the multibyte flag of the current buffer.
Only do this if the default value of `enable-multibyte-characters' is
non-nil. This is a no-op in XEmacs."
- (when (and (fboundp 'set-buffer-multibyte)
- (boundp 'enable-multibyte-characters)
- (default-value 'enable-multibyte-characters))
- (set-buffer-multibyte t)))
+ (set-buffer-multibyte t))
+ (defalias 'mm-enable-multibyte 'ignore))
-(defsubst mm-disable-multibyte ()
- "Unset the multibyte flag of in the current buffer.
+ (if mm-emacs-mule
+ (defun mm-disable-multibyte ()
+ "Unset the multibyte flag of in the current buffer.
This is a no-op in XEmacs."
- (when (fboundp 'set-buffer-multibyte)
- (set-buffer-multibyte nil)))
+ (set-buffer-multibyte nil))
+ (defalias 'mm-disable-multibyte 'ignore))
-(defsubst mm-enable-multibyte-mule4 ()
- "Enable multibyte in the current buffer.
+ (if mm-mule4-p
+ (defun mm-enable-multibyte-mule4 ()
+ "Enable multibyte in the current buffer.
Only used in Emacs Mule 4."
- (when (and (fboundp 'set-buffer-multibyte)
- (boundp 'enable-multibyte-characters)
- (default-value 'enable-multibyte-characters)
- (not (charsetp 'eight-bit-control)))
- (set-buffer-multibyte t)))
-
-(defsubst mm-disable-multibyte-mule4 ()
- "Disable multibyte in the current buffer.
+ (set-buffer-multibyte t))
+ (defalias 'mm-enable-multibyte-mule4 'ignore))
+
+ (if mm-mule4-p
+ (defun mm-disable-multibyte-mule4 ()
+ "Disable multibyte in the current buffer.
Only used in Emacs Mule 4."
- (when (and (fboundp 'set-buffer-multibyte)
- (not (charsetp 'eight-bit-control)))
- (set-buffer-multibyte nil)))
+ (set-buffer-multibyte nil))
+ (defalias 'mm-disable-multibyte-mule4 'ignore)))
(defun mm-preferred-coding-system (charset)
;; A typo in some Emacs versions.
- (or (get-charset-property charset 'prefered-coding-system)
- (get-charset-property charset 'preferred-coding-system)))
+ (or (get-charset-property charset 'preferred-coding-system)
+ (get-charset-property charset 'prefered-coding-system)))
(defun mm-charset-after (&optional pos)
"Return charset of a character in current buffer at position POS.
(progn
(setq mail-parse-mule-charset
(and (boundp 'current-language-environment)
- (car (last
- (assq 'charset
- (assoc current-language-environment
- language-info-alist))))))
+ (car (last
+ (assq 'charset
+ (assoc current-language-environment
+ language-info-alist))))))
(if (or (not mail-parse-mule-charset)
(eq mail-parse-mule-charset 'ascii))
(setq mail-parse-mule-charset
(defun mm-mime-charset (charset)
"Return the MIME charset corresponding to the given Mule CHARSET."
+ (if (eq charset 'unknown)
+ (error "The message contains non-printable characters, please use attachment"))
(if (and (fboundp 'coding-system-get) (fboundp 'get-charset-property))
;; This exists in Emacs 20.
(or
(mm-preferred-coding-system charset) 'mime-charset))
(and (eq charset 'ascii)
'us-ascii)
+ (mm-preferred-coding-system charset)
(mm-mule-charset-to-mime-charset charset))
;; This is for XEmacs.
(mm-mule-charset-to-mime-charset charset)))
(setq result (cons head result)))
(nreverse result)))
-(defun mm-find-mime-charset-region (b e)
- "Return the MIME charsets needed to encode the region between B and E."
- (let ((charsets (mapcar 'mm-mime-charset
- (delq 'ascii
- (mm-find-charset-region b e)))))
- (when (memq 'iso-2022-jp-2 charsets)
- (setq charsets (delq 'iso-2022-jp charsets)))
- (setq charsets (mm-delete-duplicates charsets))
- (if (and (> (length charsets) 1)
- (fboundp 'find-coding-systems-region)
- (let ((cs (find-coding-systems-region b e)))
- (or (memq 'utf-8 cs) (memq 'mule-utf-8 cs))))
- '(utf-8)
- charsets)))
-
+;; It's not clear whether this is supposed to mean the global or local
+;; setting. I think it's used inconsistently. -- fx
(defsubst mm-multibyte-p ()
"Say whether multibyte is enabled."
(if (and (not (featurep 'xemacs))
enable-multibyte-characters
(featurep 'mule)))
+(defun mm-iso-8859-x-to-15-region (&optional b e)
+ (if (fboundp 'char-charset)
+ (let (charset item c inconvertible)
+ (save-restriction
+ (if e (narrow-to-region b e))
+ (goto-char (point-min))
+ (skip-chars-forward "\0-\177")
+ (while (not (eobp))
+ (cond
+ ((not (setq item (assq (char-charset (setq c (char-after)))
+ mm-iso-8859-x-to-15-table)))
+ (forward-char))
+ ((memq c (cdr (cdr item)))
+ (setq inconvertible t)
+ (forward-char))
+ (t
+ (insert (prog1 (+ c (car (cdr item))) (delete-char 1))))
+ (skip-chars-forward "\0-\177"))))
+ (not inconvertible))))
+
+(defun mm-sort-coding-systems-predicate (a b)
+ (> (length (memq a mm-coding-system-priorities))
+ (length (memq b mm-coding-system-priorities))))
+
+(defun mm-find-mime-charset-region (b e &optional hack-charsets)
+ "Return the MIME charsets needed to encode the region between B and E.
+nil means ASCII, a single-element list represents an appropriate MIME
+charset, and a longer list means no appropriate charset."
+ (let (charsets)
+ ;; The return possibilities of this function are a mess...
+ (or (and (mm-multibyte-p)
+ mm-use-find-coding-systems-region
+ ;; Find the mime-charset of the most preferred coding
+ ;; system that has one.
+ (let ((systems (find-coding-systems-region b e)))
+ (when mm-coding-system-priorities
+ (setq systems
+ (sort systems 'mm-sort-coding-systems-predicate)))
+ ;; Fixme: The `mime-charset' (`x-ctext') of `compound-text'
+ ;; is not in the IANA list.
+ (setq systems (delq 'compound-text systems))
+ (unless (equal systems '(undecided))
+ (while systems
+ (let ((cs (coding-system-get (pop systems) 'mime-charset)))
+ (if cs
+ (setq systems nil
+ charsets (list cs))))))
+ charsets))
+ ;; Otherwise we're not multibyte, XEmacs or a single coding
+ ;; system won't cover it.
+ (setq charsets
+ (mm-delete-duplicates
+ (mapcar 'mm-mime-charset
+ (delq 'ascii
+ (mm-find-charset-region b e))))))
+ (if (and (memq 'iso-8859-15 charsets)
+ (memq 'iso-8859-15 hack-charsets)
+ (save-excursion (mm-iso-8859-x-to-15-region b e)))
+ (mapcar (lambda (x) (setq charsets (delq (car x) charsets)))
+ mm-iso-8859-15-compatible))
+ (if (and (memq 'iso-2022-jp-2 charsets)
+ (memq 'iso-2022-jp-2 hack-charsets))
+ (setq charsets (delq 'iso-2022-jp charsets)))
+ charsets))
+
(defmacro mm-with-unibyte-buffer (&rest forms)
"Create a temporary buffer, and evaluate FORMS there like `progn'.
Use unibyte mode for this."
"Evaluate FORMS with current current buffer temporarily made unibyte.
Also bind `default-enable-multibyte-characters' to nil.
Equivalent to `progn' in XEmacs"
- (let ((multibyte (make-symbol "multibyte")))
- `(if (fboundp 'set-buffer-multibyte)
- (let ((,multibyte enable-multibyte-characters))
+ (let ((multibyte (make-symbol "multibyte"))
+ (buffer (make-symbol "buffer")))
+ `(if mm-emacs-mule
+ (let ((,multibyte enable-multibyte-characters)
+ (,buffer (current-buffer)))
(unwind-protect
(let (default-enable-multibyte-characters)
(set-buffer-multibyte nil)
,@forms)
+ (set-buffer ,buffer)
(set-buffer-multibyte ,multibyte)))
- (progn
+ (let (default-enable-multibyte-characters)
,@forms))))
(put 'mm-with-unibyte-current-buffer 'lisp-indent-function 0)
(put 'mm-with-unibyte-current-buffer 'edebug-form-spec '(body))
(defmacro mm-with-unibyte-current-buffer-mule4 (&rest forms)
"Evaluate FORMS there like `progn' in current buffer.
Mule4 only."
- (let ((multibyte (make-symbol "multibyte")))
- `(if (or (featurep 'xemacs)
- (not (fboundp 'set-buffer-multibyte))
- (charsetp 'eight-bit-control)) ;; For Emacs Mule 4 only.
- (progn
- ,@forms)
- (let ((,multibyte (default-value 'enable-multibyte-characters)))
- (unwind-protect
- (let ((buffer-file-coding-system mm-binary-coding-system)
- (coding-system-for-read mm-binary-coding-system)
- (coding-system-for-write mm-binary-coding-system))
- (set-buffer-multibyte nil)
- (setq-default enable-multibyte-characters nil)
- ,@forms)
- (setq-default enable-multibyte-characters ,multibyte)
- (set-buffer-multibyte ,multibyte))))))
+ (let ((multibyte (make-symbol "multibyte"))
+ (buffer (make-symbol "buffer")))
+ `(if mm-mule4-p
+ (let ((,multibyte enable-multibyte-characters)
+ (,buffer (current-buffer)))
+ (unwind-protect
+ (let (default-enable-multibyte-characters)
+ (set-buffer-multibyte nil)
+ ,@forms)
+ (set-buffer ,buffer)
+ (set-buffer-multibyte ,multibyte)))
+ (let (default-enable-multibyte-characters)
+ ,@forms))))
(put 'mm-with-unibyte-current-buffer-mule4 'lisp-indent-function 0)
(put 'mm-with-unibyte-current-buffer-mule4 'edebug-form-spec '(body))
"Return a list of Emacs charsets in the region B to E."
(cond
((and (mm-multibyte-p)
- (fboundp 'find-charset-region))
+ (fboundp 'find-charset-region))
;; Remove composition since the base charsets have been included.
- (delq 'composition (find-charset-region b e)))
+ ;; Remove eight-bit-*, treat them as ascii.
+ (let ((css (find-charset-region b e)))
+ (mapcar (lambda (cs) (setq css (delq cs css)))
+ '(composition eight-bit-control eight-bit-graphic
+ control-1))
+ css))
(t
;; We are in a unibyte buffer or XEmacs non-mule, so we futz around a bit.
(save-excursion
(let (charset)
(setq charset
(and (boundp 'current-language-environment)
- (car (last (assq 'charset
- (assoc current-language-environment
+ (car (last (assq 'charset
+ (assoc current-language-environment
language-info-alist))))))
(if (eq charset 'ascii) (setq charset nil))
(or charset
(auto-mode-alist (if inhibit nil (mm-auto-mode-alist)))
(default-major-mode 'fundamental-mode)
(enable-local-variables nil)
- (after-insert-file-functions nil)
+ (after-insert-file-functions nil)
(enable-local-eval nil)
(find-file-hooks nil)
- (inhibit-file-name-operation (if inhibit
+ (inhibit-file-name-operation (if inhibit
'insert-file-contents
inhibit-file-name-operation))
(inhibit-file-name-handlers
(if inhibit
- (append mm-inhibit-file-name-handlers
+ (append mm-inhibit-file-name-handlers
inhibit-file-name-handlers)
inhibit-file-name-handlers)))
(insert-file-contents filename visit beg end replace)))
Optional fourth argument specifies the coding system to use when
encoding the file.
If INHIBIT is non-nil, inhibit mm-inhibit-file-name-handlers."
- (let ((coding-system-for-write
- (or codesys mm-text-coding-system-for-write
+ (let ((coding-system-for-write
+ (or codesys mm-text-coding-system-for-write
mm-text-coding-system))
- (inhibit-file-name-operation (if inhibit
+ (inhibit-file-name-operation (if inhibit
'append-to-file
inhibit-file-name-operation))
(inhibit-file-name-handlers
(if inhibit
- (append mm-inhibit-file-name-handlers
+ (append mm-inhibit-file-name-handlers
inhibit-file-name-handlers)
inhibit-file-name-handlers)))
(append-to-file start end filename)))
-(defun mm-write-region (start end filename &optional append visit lockname
+(defun mm-write-region (start end filename &optional append visit lockname
coding-system inhibit)
"Like `write-region'.
If INHIBIT is non-nil, inhibit mm-inhibit-file-name-handlers."
- (let ((coding-system-for-write
- (or coding-system mm-text-coding-system-for-write
+ (let ((coding-system-for-write
+ (or coding-system mm-text-coding-system-for-write
mm-text-coding-system))
- (inhibit-file-name-operation (if inhibit
+ (inhibit-file-name-operation (if inhibit
'write-region
inhibit-file-name-operation))
(inhibit-file-name-handlers
(if inhibit
- (append mm-inhibit-file-name-handlers
+ (append mm-inhibit-file-name-handlers
inhibit-file-name-handlers)
inhibit-file-name-handlers)))
(write-region start end filename append visit lockname)))
+(defun mm-image-load-path (&optional package)
+ (let (dir result)
+ (dolist (path load-path (nreverse result))
+ (if (file-directory-p
+ (setq dir (concat (file-name-directory
+ (directory-file-name path))
+ "etc/" (or package "gnus/"))))
+ (push dir result))
+ (push path result))))
+
(provide 'mm-util)
;;; mm-util.el ends here
`(lambda () (remove-images ,b (1+ ,b))))))
(defun mm-inline-image-xemacs (handle)
+ (insert "\n")
+ (forward-char -1)
(let ((b (point))
(annot (make-annotation (mm-get-image handle) nil 'text))
buffer-read-only)
- (insert "\n")
(mm-handle-set-undisplayer
handle
`(lambda ()
(and (boundp 'w3-meta-charset-content-type-regexp)
(re-search-forward
w3-meta-charset-content-type-regexp nil t)))
- (setq charset (or (w3-coding-system-for-mime-charset
- (buffer-substring-no-properties
- (match-beginning 2)
- (match-end 2)))
- charset)))
+ (setq charset
+ (or (let ((bsubstr (buffer-substring-no-properties
+ (match-beginning 2)
+ (match-end 2))))
+ (if (fboundp 'w3-coding-system-for-mime-charset)
+ (w3-coding-system-for-mime-charset bsubstr)
+ (mm-charset-to-coding-system bsubstr)))
+ charset)))
(delete-region (point-min) (point-max))
(insert (mm-decode-string text charset))
(save-window-excursion
(url-standalone-mode t))
(condition-case var
(w3-region (point-min) (point-max))
- (error)))))
+ (error
+ (delete-region (point-min) (point-max))
+ (let ((b (point))
+ (charset (mail-content-type-get
+ (mm-handle-type handle) 'charset)))
+ (if (or (eq charset 'gnus-decoded)
+ (eq mail-parse-charset 'gnus-decoded))
+ (save-restriction
+ (narrow-to-region (point) (point))
+ (mm-insert-part handle)
+ (goto-char (point-max)))
+ (insert (mm-decode-string (mm-get-part handle)
+ charset))))
+ (message
+ "Error while rendering html; showing as text/plain"))))))
(mm-handle-set-undisplayer
handle
`(lambda ()
'(background background-pixmap foreground)))
(delete-region ,(point-min-marker)
,(point-max-marker)))))))))
- ((or (equal type "enriched")
- (equal type "richtext"))
- (save-excursion
- (mm-with-unibyte-buffer
- (mm-insert-part handle)
- (save-window-excursion
- (enriched-decode (point-min) (point-max))
- (setq text (buffer-string)))))
- (mm-insert-inline handle text))
((equal type "x-vcard")
(mm-insert-inline
handle
(concat "\n-- \n"
- (if (fboundp 'vcard-pretty-print)
- (vcard-pretty-print (mm-get-part handle))
- (vcard-format-string
- (vcard-parse-string (mm-get-part handle)
- 'vcard-standard-filter))))))
+ (ignore-errors
+ (if (fboundp 'vcard-pretty-print)
+ (vcard-pretty-print (mm-get-part handle))
+ (vcard-format-string
+ (vcard-parse-string (mm-get-part handle)
+ 'vcard-standard-filter)))))))
(t
(let ((b (point))
(charset (mail-content-type-get
(mm-handle-type handle) 'charset)))
(if (or (eq charset 'gnus-decoded)
;; This is probably not entirely correct, but
- ;; makes rfc822 parts with embedded multiparts work.
+ ;; makes rfc822 parts with embedded multiparts work.
(eq mail-parse-charset 'gnus-decoded))
- (mm-insert-part handle)
+ (save-restriction
+ (narrow-to-region (point) (point))
+ (mm-insert-part handle)
+ (goto-char (point-max)))
(insert (mm-decode-string (mm-get-part handle) charset)))
(when (and (equal type "plain")
(equal (cdr (assoc 'format (mm-handle-type handle)))
(save-restriction
(narrow-to-region b (point))
(set-text-properties (point-min) (point-max) nil)
+ (when (or (equal type "enriched")
+ (equal type "richtext"))
+ (enriched-decode (point-min) (point-max)))
(mm-handle-set-undisplayer
handle
`(lambda ()
(defun mm-inline-message (handle)
(let ((b (point))
+ (bolp (bolp))
(charset (mail-content-type-get
(mm-handle-type handle) 'charset))
gnus-displaying-mime handles)
(narrow-to-region b b)
(mm-insert-part handle)
(let (gnus-article-mime-handles
- ;; disable prepare hook
- gnus-article-prepare-hook
+ ;; disable prepare hook
+ gnus-article-prepare-hook
(gnus-newsgroup-charset
(or charset gnus-newsgroup-charset)))
(run-hooks 'gnus-article-decode-hook)
(gnus-article-prepare-display)
(setq handles gnus-article-mime-handles))
+ (goto-char (point-min))
+ (unless bolp
+ (insert "\n"))
(goto-char (point-max))
(unless (bolp)
(insert "\n"))
(when (and (not raw) (memq nil charsets))
(if (or (memq 'unknown-encoding mml-confirmation-set)
(prog1 (y-or-n-p
- "\
+ "\
Message contains characters with unknown encoding. Really send?")
(set (make-local-variable 'mml-confirmation-set)
(push 'unknown-encoding mml-confirmation-set))))
"Return the buffer up till the next part, multipart or closing part or multipart.
If MML is non-nil, return the buffer up till the correspondent mml tag."
(let ((beg (point)) (count 1))
- ;; If the tag ended at the end of the line, we go to the next line.
+ ;; If the tag ended at the end of the line, we go to the next line.
(when (looking-at "[ \t]*\n")
(forward-line 1))
(if mml
(setq type (or (cdr (assq 'type cont)) "text/plain"))
(if (and (not raw)
(member (car (split-string type "/")) '("text" "message")))
- (with-temp-buffer
- (cond
- ((cdr (assq 'buffer cont))
- (insert-buffer-substring (cdr (assq 'buffer cont))))
- ((and (setq filename (cdr (assq 'filename cont)))
- (not (equal (cdr (assq 'nofile cont)) "yes")))
- (mm-insert-file-contents filename))
- ((eq 'mml (car cont))
- (insert (cdr (assq 'contents cont))))
- (t
- (save-restriction
- (narrow-to-region (point) (point))
- (insert (cdr (assq 'contents cont)))
- ;; Remove quotes from quoted tags.
- (goto-char (point-min))
- (while (re-search-forward
- "<#!+/?\\(part\\|multipart\\|external\\|mml\\)" nil t)
- (delete-region (+ (match-beginning 0) 2)
- (+ (match-beginning 0) 3))))))
- (cond
- ((eq (car cont) 'mml)
- (let ((mml-boundary (funcall mml-boundary-function
- (incf mml-multipart-number)))
- (mml-generate-default-type "text/plain"))
- (mml-to-mime))
- (let ((mm-7bit-chars (concat mm-7bit-chars "\x1b")))
- ;; ignore 0x1b, it is part of iso-2022-jp
- (setq encoding (mm-body-7-or-8))))
- ((string= (car (split-string type "/")) "message")
- (let ((mm-7bit-chars (concat mm-7bit-chars "\x1b")))
- ;; ignore 0x1b, it is part of iso-2022-jp
- (setq encoding (mm-body-7-or-8))))
- (t
- (setq charset (mm-encode-body))
- (setq encoding (mm-body-encoding
- charset (cdr (assq 'encoding cont))))))
- (setq coded (buffer-string)))
+ (progn
+ (with-temp-buffer
+ (cond
+ ((cdr (assq 'buffer cont))
+ (insert-buffer-substring (cdr (assq 'buffer cont))))
+ ((and (setq filename (cdr (assq 'filename cont)))
+ (not (equal (cdr (assq 'nofile cont)) "yes")))
+ (mm-insert-file-contents filename))
+ ((eq 'mml (car cont))
+ (insert (cdr (assq 'contents cont))))
+ (t
+ (save-restriction
+ (narrow-to-region (point) (point))
+ (insert (cdr (assq 'contents cont)))
+ ;; Remove quotes from quoted tags.
+ (goto-char (point-min))
+ (while (re-search-forward
+ "<#!+/?\\(part\\|multipart\\|external\\|mml\\)" nil t)
+ (delete-region (+ (match-beginning 0) 2)
+ (+ (match-beginning 0) 3))))))
+ (cond
+ ((eq (car cont) 'mml)
+ (let ((mml-boundary (funcall mml-boundary-function
+ (incf mml-multipart-number)))
+ (mml-generate-default-type "text/plain"))
+ (mml-to-mime))
+ (let ((mm-7bit-chars (concat mm-7bit-chars "\x1b")))
+ ;; ignore 0x1b, it is part of iso-2022-jp
+ (setq encoding (mm-body-7-or-8))))
+ ((string= (car (split-string type "/")) "message")
+ (let ((mm-7bit-chars (concat mm-7bit-chars "\x1b")))
+ ;; ignore 0x1b, it is part of iso-2022-jp
+ (setq encoding (mm-body-7-or-8))))
+ (t
+ (setq charset (mm-encode-body))
+ (setq encoding (mm-body-encoding
+ charset (cdr (assq 'encoding cont))))))
+ (setq coded (buffer-string)))
+ (mml-insert-mime-headers cont type charset encoding)
+ (insert "\n")
+ (insert coded))
(mm-with-unibyte-buffer
(cond
((cdr (assq 'buffer cont))
(t
(insert (cdr (assq 'contents cont)))))
(setq encoding (mm-encode-buffer type)
- coded (buffer-string))))
- (mml-insert-mime-headers cont type charset encoding)
- (insert "\n")
- (insert coded)))
+ coded (buffer-string)))
+ (mml-insert-mime-headers cont type charset encoding)
+ (insert "\n")
+ (mm-with-unibyte-current-buffer
+ (insert coded)))))
((eq (car cont) 'external)
(insert "Content-Type: message/external-body")
(let ((parameters (mml-parameter-string
(concat "access-type="
(if (member (nth 0 name) '("ftp@" "anonymous@"))
"anon-ftp"
- "ftp")))))
+ "ftp")))))
(when parameters
(mml-insert-parameter-string
cont '(expiration size permission))))
main))
(easy-menu-define
- mml-menu mml-mode-map ""
- '("MML"
- ("Attach"
- ["File" mml-attach-file t]
- ["Buffer" mml-attach-buffer t]
- ["External" mml-attach-external t])
- ("Insert"
- ["Multipart" mml-insert-multipart t]
- ["Part" mml-insert-part t])
- ;;["Narrow" mml-narrow-to-part t]
- ["Quote" mml-quote-region t]
- ["Validate" mml-validate t]
- ["Preview" mml-preview t]))
+ mml-menu mml-mode-map ""
+ '("MML"
+ ("Attach"
+ ["File" mml-attach-file t]
+ ["Buffer" mml-attach-buffer t]
+ ["External" mml-attach-external t])
+ ("Insert"
+ ["Multipart" mml-insert-multipart t]
+ ["Part" mml-insert-part t])
+ ;;["Narrow" mml-narrow-to-part t]
+ ["Quote" mml-quote-region t]
+ ["Validate" mml-validate t]
+ ["Preview" mml-preview t]))
(defvar mml-mode nil
"Minor mode for editing MML.")
(defun mml-minibuffer-read-file (prompt)
(let ((file (read-file-name prompt nil nil t)))
- ;; Prevent some common errors. This is inspired by similar code in
+ ;; Prevent some common errors. This is inspired by similar code in
;; VM.
(when (file-directory-p file)
(error "%s is a directory, cannot attach" file))
(if (re-search-forward
(concat "^" (regexp-quote mail-header-separator) "\n") nil t)
(replace-match "\n"))
- (mml-to-mime)
+ (let ((mail-header-separator "")) ;; mail-header-separator is removed.
+ (mml-to-mime))
(if raw
(when (fboundp 'set-buffer-multibyte)
(let ((s (buffer-string)))
(defvoo nnfolder-file-coding-system mm-text-coding-system)
(defvoo nnfolder-file-coding-system-for-write nnheader-file-coding-system
"Coding system for save nnfolder file.
-If NIL, NNFOLDER-FILE-CODING-SYSTEM is used.")
+If nil, `nnfolder-file-coding-system' is used.")
\f
\(FIELD VALUE [- RESTRICT [- RESTRICT [...]]] SPLIT): If the message
field FIELD (a regexp) contains VALUE (a regexp), store the messages
as specified by SPLIT. If RESTRICT (a regexp) matches some string
- after FIELD and before the end of the matched VALUE, return NIL,
+ after FIELD and before the end of the matched VALUE, return nil,
otherwise process SPLIT. Multiple RESTRICTs add up, further
restricting the possibility of processing SPLIT.
;;; nnslashdot.el --- interfacing with Slashdot
-;; Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+;; Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
;; Keywords: news
"http://slashdot.org/article.pl?sid=%s&mode=nocomment"
"Where nnslashdot will fetch the article from.")
+(defvoo nnslashdot-backslash-url "http://slashdot.org/slashdot.xml"
+ "Where nnslashdot will fetch the stories from.")
+
(defvoo nnslashdot-threshold -1
"The article threshold.")
(nnslashdot-possibly-change-server group server)
(condition-case why
(unless gnus-nov-is-evil
- (if nnslashdot-threaded
- (nnslashdot-threaded-retrieve-headers articles group)
- (nnslashdot-sane-retrieve-headers articles group)))
+ (nnslashdot-retrieve-headers-1 articles group))
(search-failed (nnslashdot-lose why))))
-(deffoo nnslashdot-threaded-retrieve-headers (articles group)
- (let ((last (car (last articles)))
- (did nil)
- (start 1)
- (sid (caddr (assoc group nnslashdot-groups)))
- (first-comments t)
- (startats '(1))
- headers article subject score from date lines parent point s)
+(deffoo nnslashdot-retrieve-headers-1 (articles group)
+ (let* ((last (car (last articles)))
+ (start (if nnslashdot-threaded 1 (pop articles)))
+ (entry (assoc group nnslashdot-groups))
+ (sid (nth 2 entry))
+ (first-comments t)
+ headers article subject score from date lines parent point cid
+ s startats changed)
(save-excursion
(set-buffer nnslashdot-buffer)
(let ((case-fold-search t))
(nnweb-insert (format nnslashdot-article-url
(nnslashdot-sid-strip sid)) t)
(goto-char (point-min))
- (search-forward "Posted by ")
- (when (looking-at "<a[^>]+>\\([^<]+\\)")
- (setq from (nnweb-decode-entities-string (match-string 1))))
- (search-forward " on ")
+ (re-search-forward "Posted by[ \t\r\n]+")
+ (when (looking-at "\\(<a[^>]+>\\)?[ \t\r\n]*\\([^<\r\n]+\\)")
+ (setq from (nnweb-decode-entities-string (match-string 2))))
+ (search-forward "on ")
(setq date (nnslashdot-date-to-date
(buffer-substring (point) (1- (search-forward "<")))))
(setq lines (/ (- (point)
1 group from date
(concat "<" (nnslashdot-sid-strip sid) "%1@slashdot>")
"" 0 lines nil nil))
- headers))
- (while (and (setq start (pop startats))
- (< start last))
+ headers)
+ (setq start (if nnslashdot-threaded 2 (pop articles))))
+ (while (and start (<= start last))
(setq point (goto-char (point-max)))
(nnweb-insert
(format nnslashdot-comments-url
(nnslashdot-sid-strip sid)
- nnslashdot-threshold 0 start)
+ nnslashdot-threshold 0 (- start 2))
t)
- (when first-comments
+ (when (and nnslashdot-threaded first-comments)
(setq first-comments nil)
(goto-char (point-max))
(while (re-search-backward "startat=\\([0-9]+\\)" nil t)
(unless (memq s startats)
(push s startats)))
(setq startats (sort startats '<)))
+ (setq article (if (and article (< start article)) article start))
(goto-char point)
(while (re-search-forward
"<a name=\"\\([0-9]+\\)\"><\\(b\\|H4\\)>\\([^<]+\\)</\\(b\\|H4\\)>.*score:\\([^)]+\\))"
nil t)
- (setq article (string-to-number (match-string 1))
+ (setq cid (match-string 1)
subject (match-string 3)
score (match-string 5))
+ (unless (assq article (nth 4 entry))
+ (setcar (nthcdr 4 entry) (cons (cons article cid) (nth 4 entry)))
+ (setq changed t))
(when (string-match "^Re: *" subject)
(setq subject (concat "Re: " (substring subject (match-end 0)))))
- (setq subject (nnweb-decode-entities-string subject))
- (forward-line 1)
+ (setq subject (nnweb-decode-entities-string subject))
+ (search-forward "<BR>")
(if (looking-at
- "by <a[^>]+>\\([^<]+\\)</a>[ \t\n]*.*(\\([^)]+\\))")
+ "by[ \t\n]+<a[^>]+>\\([^<]+\\)</a>[ \t\n]*(\\(<[^>]+>\\)*\\([^<>)]+\\))")
(progn
(goto-char (- (match-end 0) 5))
- (setq from (concat
+ (setq from (concat
(nnweb-decode-entities-string (match-string 1))
- " <" (match-string 2) ">")))
+ " <" (match-string 3) ">")))
(setq from "")
- (when (looking-at "by \\(.+\\) on ")
+ (when (looking-at "by \\([^<>]*\\) on ")
(goto-char (- (match-end 0) 5))
(setq from (nnweb-decode-entities-string (match-string 1)))))
(search-forward " on ")
(setq date
(nnslashdot-date-to-date
- (buffer-substring (point) (progn (end-of-line) (point)))))
- (setq lines (/ (abs (- (search-forward "<td ")
+ (buffer-substring (point) (progn (skip-chars-forward "^()<>\n\r") (point)))))
+ (setq lines (/ (abs (- (search-forward "<td")
(search-forward "</td>")))
70))
- (forward-line 4)
- (setq parent
- (if (looking-at ".*cid=\\([0-9]+\\)")
- (match-string 1)
- nil))
- (setq did t)
+ (if (not
+ (re-search-forward ".*cid=\\([0-9]+\\)\">Parent</A>" nil t))
+ (setq parent nil)
+ (setq parent (match-string 1))
+ (when (string= parent "0")
+ (setq parent nil)))
(push
(cons
- (1+ article)
+ article
(make-full-mail-header
- (1+ article)
+ article
(concat subject " (" score ")")
from date
- (concat "<" (nnslashdot-sid-strip sid) "%"
- (number-to-string (1+ article))
- "@slashdot>")
+ (concat "<" (nnslashdot-sid-strip sid) "%" cid "@slashdot>")
(if parent
- (concat "<" (nnslashdot-sid-strip sid) "%"
- (number-to-string (1+ (string-to-number parent)))
- "@slashdot>")
+ (concat "<" (nnslashdot-sid-strip sid) "%"
+ parent "@slashdot>")
"")
0 lines nil nil))
- headers)))))
+ headers)
+ (while (and articles (<= (car articles) article))
+ (pop articles))
+ (setq article (1+ article)))
+ (if nnslashdot-threaded
+ (progn
+ (setq start (pop startats))
+ (if start (setq start (+ start 2))))
+ (setq start (pop articles))))))
+ (if changed (nnslashdot-write-groups))
(setq nnslashdot-headers (sort headers 'car-less-than-car))
(save-excursion
(set-buffer nntp-server-buffer)
(nnheader-insert-nov (cdr header)))))
'nov))
-(deffoo nnslashdot-sane-retrieve-headers (articles group)
- (let ((last (car (last articles)))
- (did nil)
- (start (max (1- (car articles)) 1))
- (sid (caddr (assoc group nnslashdot-groups)))
- headers article subject score from date lines parent point)
- (save-excursion
- (set-buffer nnslashdot-buffer)
- (erase-buffer)
- (when (= start 1)
- (nnweb-insert (format nnslashdot-article-url
- (nnslashdot-sid-strip sid)) t)
- (goto-char (point-min))
- (search-forward "Posted by ")
- (when (looking-at "<a[^>]+>\\([^<]+\\)")
- (setq from (nnweb-decode-entities-string (match-string 1))))
- (search-forward " on ")
- (setq date (nnslashdot-date-to-date
- (buffer-substring (point) (1- (search-forward "<")))))
- (forward-line 2)
- (setq lines (count-lines (point)
- (re-search-forward
- "A href=\"\\(http://slashdot.org\\)?/article")))
- (push
- (cons
- 1
- (make-full-mail-header
- 1 group from date (concat "<" (nnslashdot-sid-strip sid)
- "%1@slashdot>")
- "" 0 lines nil nil))
- headers))
- (while (or (not article)
- (and did
- (< article last)))
- (when article
- (setq start (1+ article)))
- (setq point (goto-char (point-max)))
- (nnweb-insert
- (format nnslashdot-comments-url (nnslashdot-sid-strip sid)
- nnslashdot-threshold 4 start)
- t)
- (goto-char point)
- (while (re-search-forward
- "<a name=\"\\([0-9]+\\)\"><\\(b\\|H4\\)>\\([^<]+\\)</\\(b\\|H4\\)>.*score:\\([^)]+\\))"
- nil t)
- (setq article (string-to-number (match-string 1))
- subject (match-string 3)
- score (match-string 5))
- (when (string-match "^Re: *" subject)
- (setq subject (concat "Re: " (substring subject (match-end 0)))))
- (setq subject (nnweb-decode-entities-string subject))
- (forward-line 1)
- (if (looking-at
- "by <a[^>]+>\\([^<]+\\)</a>[ \t\n]*.*(\\([^)]+\\))")
- (progn
- (goto-char (- (match-end 0) 5))
- (setq from (concat
- (nnweb-decode-entities-string (match-string 1))
- " <" (match-string 2) ">")))
- (setq from "")
- (when (looking-at "by \\(.+\\) on ")
- (goto-char (- (match-end 0) 5))
- (setq from (nnweb-decode-entities-string (match-string 1)))))
- (search-forward " on ")
- (setq date
- (nnslashdot-date-to-date
- (buffer-substring (point) (progn (end-of-line) (point)))))
- (setq lines (/ (abs (- (search-forward "<td ")
- (search-forward "</td>")))
- 70))
- (forward-line 2)
- (setq parent
- (if (looking-at ".*cid=\\([0-9]+\\)")
- (match-string 1)
- nil))
- (setq did t)
- (push
- (cons
- (1+ article)
- (make-full-mail-header
- (1+ article) (concat subject " (" score ")")
- from date
- (concat "<" (nnslashdot-sid-strip sid) "%"
- (number-to-string (1+ article))
- "@slashdot>")
- (if parent
- (concat "<" (nnslashdot-sid-strip sid) "%"
- (number-to-string (1+ (string-to-number parent)))
- "@slashdot>")
- "")
- 0 lines nil nil))
- headers))))
- (setq nnslashdot-headers
- (sort headers (lambda (s1 s2) (< (car s1) (car s2)))))
- (save-excursion
- (set-buffer nntp-server-buffer)
- (erase-buffer)
- (mm-with-unibyte-current-buffer
- (dolist (header nnslashdot-headers)
- (nnheader-insert-nov (cdr header)))))
- 'nov))
-
(deffoo nnslashdot-request-group (group &optional server dont-check)
(nnslashdot-possibly-change-server nil server)
(let ((elem (assoc group nnslashdot-groups)))
(deffoo nnslashdot-request-article (article &optional group server buffer)
(nnslashdot-possibly-change-server group server)
- (let (contents)
+ (let (contents cid)
(condition-case why
(save-excursion
(set-buffer nnslashdot-buffer)
(goto-char (point-min))
(when (and (stringp article)
(string-match "%\\([0-9]+\\)@" article))
- (setq article (string-to-number (match-string 1 article))))
+ (setq cid (match-string 1 article))
+ (let ((map (nth 4 (assoc group nnslashdot-groups))))
+ (while map
+ (if (equal (cdar map) cid)
+ (setq article (caar map)
+ map nil)
+ (setq map (cdr map))))))
(when (numberp article)
(if (= article 1)
(progn
- (re-search-forward "Posted by *<[^>]+>[^>]*<[^>]+> *on ")
+ (re-search-forward
+ "Posted by")
(search-forward "<BR>")
(setq contents
(buffer-substring
(point)
(progn
(re-search-forward
- "<p>.*A href=\"\\(http://slashdot.org\\)?/article")
+ "< [ \t\r\n]*<A HREF=\"\\(\\(http:\\)?//slashdot\\.org\\)?/article")
(match-beginning 0)))))
- (search-forward (format "<a name=\"%d\">" (1- article)))
+ (setq cid (cdr (assq article
+ (nth 4 (assoc group nnslashdot-groups)))))
+ (search-forward (format "<a name=\"%s\">" cid))
(setq contents
(buffer-substring
- (re-search-forward "<td[^>]+>")
+ (re-search-forward "<td[^>]*>")
(search-forward "</td>")))))))
(search-failed (nnslashdot-lose why)))
(let ((number 0)
sid elem description articles gname)
(condition-case why
- ;; First we do the Ultramode to get info on all the latest groups.
- (progn
+ ;; First we do the Ultramode to get info on all the latest groups.
+ (progn
(mm-with-unibyte-buffer
- (nnweb-insert "http://slashdot.org/slashdot.xml" t)
+ (nnweb-insert nnslashdot-backslash-url t)
(goto-char (point-min))
(while (search-forward "<story>" nil t)
(narrow-to-region (point) (search-forward "</story>"))
(setq gname (concat description " (" sid ")"))
(if (setq elem (assoc gname nnslashdot-groups))
(setcar (cdr elem) articles)
- (push (list gname articles sid) nnslashdot-groups))
+ (push (list gname articles sid (current-time) nil)
+ nnslashdot-groups))
(goto-char (point-max))
(widen)))
;; Then do the older groups.
(setq gname (concat description " (" sid ")"))
(if (setq elem (assoc gname nnslashdot-groups))
(setcar (cdr elem) articles)
- (push (list gname articles sid) nnslashdot-groups)))))
+ (push (list gname articles sid (current-time) nil)
+ nnslashdot-groups)))))
(incf number 30)))
(search-failed (nnslashdot-lose why)))
(nnslashdot-write-groups)
(nnslashdot-generate-active)
t))
-
+
(deffoo nnslashdot-request-newgroups (date &optional server)
(nnslashdot-possibly-change-server nil server)
(nnslashdot-generate-active)
(setq nnslashdot-headers nil
nnslashdot-groups nil))
+(deffoo nnslashdot-request-expire-articles
+ (articles group &optional server force)
+ (nnslashdot-possibly-change-server group server)
+ (let ((item (assoc group nnslashdot-groups)))
+ (when item
+ (if (fourth item)
+ (when (and (>= (length articles) (cadr item)) ;; All are expirable.
+ (nnmail-expired-article-p
+ group
+ (fourth item)
+ force))
+ (setq nnslashdot-groups (delq item nnslashdot-groups))
+ (nnslashdot-write-groups)
+ (setq articles nil)) ;; all expired.
+ (setcdr (cddr item) (list (current-time)))
+ (nnslashdot-write-groups))))
+ articles)
+
(nnoo-define-skeleton nnslashdot)
;;; Internal functions
(unless nnslashdot-groups
(nnslashdot-read-groups)))
+(defun nnslashdot-make-tuple (tuple n)
+ (prog1
+ tuple
+ (while (> n 1)
+ (unless (cdr tuple)
+ (setcdr tuple (list nil)))
+ (setq tuple (cdr tuple)
+ n (1- n)))))
+
(defun nnslashdot-read-groups ()
(let ((file (expand-file-name "groups" nnslashdot-directory)))
(when (file-exists-p file)
(mm-with-unibyte-buffer
(insert-file-contents file)
(goto-char (point-min))
- (setq nnslashdot-groups (read (current-buffer)))))))
+ (setq nnslashdot-groups (read (current-buffer))))
+ (if (and nnslashdot-groups (< (length (car nnslashdot-groups)) 5))
+ (let ((groups nnslashdot-groups))
+ (while groups
+ (nnslashdot-make-tuple (car groups) 5)
+ (setq groups (cdr groups))))))))
(defun nnslashdot-write-groups ()
(with-temp-file (expand-file-name "groups" nnslashdot-directory)
- (prin1 nnslashdot-groups (current-buffer))))
-
+ (gnus-prin1 nnslashdot-groups)))
+
(defun nnslashdot-init (server)
"Initialize buffers and such."
(unless (file-exists-p nnslashdot-directory)
(setq nnslashdot-buffer
(save-excursion
(nnheader-set-temp-buffer
- (format " *nnslashdot %s*" server))))))
+ (format " *nnslashdot %s*" server))))
+ (push nnslashdot-buffer gnus-buffers)))
(defun nnslashdot-date-to-date (sdate)
(condition-case err
(defun nnslashdot-lose (why)
(error "Slashdot HTML has changed; please get a new version of nnslashdot"))
-;(defun nnslashdot-sid-strip (sid)
-; (if (string-match "^00/" sid)
-; (substring sid (match-end 0))
-; sid))
-
(defalias 'nnslashdot-sid-strip 'identity)
(provide 'nnslashdot)
;;; nnspool.el --- spool access for GNU Emacs
;; Copyright (C) 1988, 1989, 1990, 1993, 1994, 1995, 1996, 1997, 1998,
-;; 2000 Free Software Foundation, Inc.
+;; 2000, 2002
+;; Free Software Foundation, Inc.
;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
;; Lars Magne Ingebrigtsen <larsi@gnus.org>
()
(nnheader-report 'nnspool "")
(set-process-sentinel proc 'nnspool-inews-sentinel)
- (process-send-region proc (point-min) (point-max))
+ (mm-with-unibyte-current-buffer
+ (process-send-region proc (point-min) (point-max)))
;; We slap a condition-case around this, because the process may
;; have exited already...
(ignore-errors
;;; nntp.el --- nntp access for Gnus
;; Copyright (C) 1987, 1988, 1989, 1990, 1992, 1993, 1994, 1995, 1996,
-;; 1997, 1998, 2000, 2001
+;; 1997, 1998, 2000, 2001, 2002
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(set-buffer (nntp-find-connection-buffer nntp-server-buffer))
(erase-buffer)))
(nntp-encode-text)
- (process-send-region (nntp-find-connection nntp-server-buffer)
- (point-min) (point-max))
+ (mm-with-unibyte-current-buffer
+ ;; Some encoded unicode text contains character 0x80-0x9f e.g. Euro.
+ (process-send-region (nntp-find-connection nntp-server-buffer)
+ (point-min) (point-max)))
(nntp-retrieve-data
nil nntp-address nntp-port-number nntp-server-buffer
wait-for nnheader-callback-function))
(defvoo nnultimate-groups nil)
(defvoo nnultimate-headers nil)
(defvoo nnultimate-articles nil)
+(defvar nnultimate-table-regexp
+ "postings.*editpost\\|forumdisplay\\|Forum[0-9]+/HTML\\|getbio")
;;; Interface functions
(old-total (or (nth 6 entry) 1))
(furl "forumdisplay.cgi?action=topics&number=%d&DaysPrune=1000")
(furls (list (concat nnultimate-address (format furl sid))))
+ (nnultimate-table-regexp
+ "postings.*editpost\\|forumdisplay\\|getbio")
headers article subject score from date lines parent point
contents tinfo fetchers map elem a href garticles topic old-max
- inc datel table string current-page total-contents pages
+ inc datel table current-page total-contents pages
farticles forum-contents parse furl-fetched mmap farticle)
(setq map mapping)
(while (and (setq article (car articles))
map)
+ ;; Skip past the articles in the map until we reach the
+ ;; article we're looking for.
(while (and map
(or (> article (caar map))
(< (cadar map) (caar map))))
fetchers))
(pop articles)
(setq article (car articles)))))
- ;; Now we have the mapping from/to Gnus/nnultimate article numbers,
+ ;; Now we have the mapping from/to Gnus/nnultimate article numbers,
;; so we start fetching the topics that we need to satisfy the
;; request.
(if (not fetchers)
(setq contents
(ignore-errors (w3-parse-buffer (current-buffer))))
(setq table (nnultimate-find-forum-table contents))
- (setq string (mapconcat 'identity (nnweb-text table) ""))
- (when (string-match "topic is \\([0-9]\\) pages" string)
- (setq pages (string-to-number (match-string 1 string)))
- (setcdr table nil)
- (setq table (nnultimate-find-forum-table contents)))
+ (goto-char (point-min))
+ (when (re-search-forward "topic is \\([0-9]+\\) pages" nil t)
+ (setq pages (string-to-number (match-string 1))))
(setq contents (cdr (nth 2 (car (nth 2 table)))))
(setq total-contents (nconc total-contents contents))
(incf current-page))
- ;;(setq total-contents (nreverse total-contents))
- (dolist (art (cdr elem))
- (if (not (nth (1- (cdr art)) total-contents))
- () ;(debug)
- (push (list (car art)
- (nth (1- (cdr art)) total-contents)
- subject)
- nnultimate-articles)))))
+ (when t
+ (let ((i 0))
+ (dolist (co total-contents)
+ (push (list (or (nnultimate-topic-article-to-article
+ group (car elem) (incf i))
+ 1)
+ co subject)
+ nnultimate-articles))))
+ (when nil
+ (dolist (art (cdr elem))
+ (when (nth (1- (cdr art)) total-contents)
+ (push (list (car art)
+ (nth (1- (cdr art)) total-contents)
+ subject)
+ nnultimate-articles))))))
(setq nnultimate-articles
(sort nnultimate-articles 'car-less-than-car))
;; Now we have all the articles, conveniently in an alist
(setq date (substring (car datel) (match-end 0))
datel nil))
(pop datel))
- (setq date (delete "" (split-string date "[- \n\t\r ]")))
- (if (or (member "AM" date)
- (member "PM" date))
+ (when date
+ (setq date (delete "" (split-string
+ date "[-, \n\t\r ]")))
+ (if (or (member "AM" date)
+ (member "PM" date))
+ (setq date (format
+ "%s %s %s %s"
+ (nth 1 date)
+ (if (and (>= (length (nth 0 date)) 3)
+ (assoc (downcase
+ (substring (nth 0 date) 0 3))
+ parse-time-months))
+ (substring (nth 0 date) 0 3)
+ (car (rassq (string-to-number (nth 0 date))
+ parse-time-months)))
+ (nth 2 date) (nth 3 date)))
(setq date (format "%s %s %s %s"
- (car (rassq (string-to-number (nth 0 date))
+ (car (rassq (string-to-number (nth 1 date))
parse-time-months))
- (nth 1 date) (nth 2 date) (nth 3 date)))
- (setq date (format "%s %s %s %s"
- (car (rassq (string-to-number (nth 1 date))
- parse-time-months))
- (nth 0 date) (nth 2 date) (nth 3 date))))
+ (nth 0 date) (nth 2 date) (nth 3 date)))))
(push
(cons
article
from (or date "")
(concat "<" (number-to-string sid) "%"
(number-to-string article)
- "@ultimate>")
+ "@ultimate." server ">")
"" 0
(/ (length (mapconcat
'identity
(nnheader-insert-nov (cdr header))))))
'nov)))
+(defun nnultimate-topic-article-to-article (group topic article)
+ (catch 'found
+ (dolist (elem (nth 5 (assoc group nnultimate-groups)))
+ (when (and (= topic (nth 2 elem))
+ (>= article (nth 3 elem))
+ (< article (+ (- (nth 1 elem) (nth 0 elem)) 1
+ (nth 3 elem))))
+ (throw 'found
+ (+ (nth 0 elem) (- article (nth 3 elem))))))))
+
(deffoo nnultimate-request-group (group &optional server dont-check)
(nnultimate-possibly-change-server nil server)
(when (not nnultimate-groups)
;; the group is entered, there's 2 new articles in topic one
;; and 1 in topic three. Then Gnus article number 8-9 be 5-6
;; in topic one and 10 will be the 2 in topic three.
- (dolist (row (reverse forum-contents))
+ (dolist (row (nreverse forum-contents))
(setq row (nth 2 row))
(when (setq a (nnweb-parse-find 'a row))
(setq subject (car (last (nnweb-text a)))
nnultimate-groups-alist)
(with-temp-file (expand-file-name "groups" nnultimate-directory)
(prin1 nnultimate-groups-alist (current-buffer))))
-
+
(defun nnultimate-init (server)
"Initialize buffers and such."
(unless (file-exists-p nnultimate-directory)
(nth 2 parse))))
(let ((href (cdr (assq 'href (nth 1 (nnweb-parse-find 'a parse 20)))))
case-fold-search)
- (when (and href (string-match
- "postings\\|forumdisplay\\|Forum[0-9]+/HTML\\|getbio"
- href))
+ (when (and href (string-match nnultimate-table-regexp href))
t))))
(provide 'nnultimate)
;;; nnweb.el --- retrieving articles via web search engines
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
;; Free Software Foundation, Inc.
;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
(defvoo nnweb-directory (nnheader-concat gnus-directory "nnweb/")
"Where nnweb will save its files.")
-(defvoo nnweb-type 'dejanews
+(defvoo nnweb-type 'google
"What search engine type is being used.
-Valid types include `dejanews', `dejanewsold', `reference',
+Valid types include `google', `dejanews', `dejanewsold', `reference',
and `altavista'.")
(defvar nnweb-type-definition
- '((dejanews
+ '(
+ (google
+ ;;(article . nnweb-google-wash-article)
+ ;;(id . "http://groups.google.com/groups?as_umsgid=%s")
(article . ignore)
- (id . "http://search.dejanews.com/msgid.xp?MID=%s&fmt=text")
- (map . nnweb-dejanews-create-mapping)
- (search . nnweb-dejanews-search)
- (address . "http://www.deja.com/=dnc/qs.xp")
- (identifier . nnweb-dejanews-identity))
- (dejanewsold
+ (id . "http://groups.google.com/groups?selm=%s&output=gplain")
+ ;;(reference . nnweb-google-reference)
+ (reference . identity)
+ (map . nnweb-google-create-mapping)
+ (search . nnweb-google-search)
+ (address . "http://groups.google.com/groups")
+ (identifier . nnweb-google-identity))
+ (dejanews ;; alias of google
+ ;;(article . nnweb-google-wash-article)
+ ;;(id . "http://groups.google.com/groups?as_umsgid=%s")
(article . ignore)
- (map . nnweb-dejanews-create-mapping)
- (search . nnweb-dejanewsold-search)
- (address . "http://www.deja.com/dnquery.xp")
- (identifier . nnweb-dejanews-identity))
+ (id . "http://groups.google.com/groups?selm=%s&output=gplain")
+ ;;(reference . nnweb-google-reference)
+ (reference . identity)
+ (map . nnweb-google-create-mapping)
+ (search . nnweb-google-search)
+ (address . "http://groups.google.com/groups")
+ (identifier . nnweb-google-identity))
+;;; (dejanews
+;;; (article . ignore)
+;;; (id . "http://search.dejanews.com/msgid.xp?MID=%s&fmt=text")
+;;; (map . nnweb-dejanews-create-mapping)
+;;; (search . nnweb-dejanews-search)
+;;; (address . "http://www.deja.com/=dnc/qs.xp")
+;;; (identifier . nnweb-dejanews-identity))
+;;; (dejanewsold
+;;; (article . ignore)
+;;; (map . nnweb-dejanews-create-mapping)
+;;; (search . nnweb-dejanewsold-search)
+;;; (address . "http://www.deja.com/dnquery.xp")
+;;; (identifier . nnweb-dejanews-identity))
(reference
(article . nnweb-reference-wash-article)
(map . nnweb-reference-create-mapping)
(deffoo nnweb-request-scan (&optional group server)
(nnweb-possibly-change-server group server)
+ (if nnweb-ephemeral-p
+ (setq nnweb-hashtb (gnus-make-hashtable 4095)))
(funcall (nnweb-definition 'map))
(unless nnweb-ephemeral-p
(nnweb-write-active)
(when (and group
(not (equal group nnweb-group))
(not nnweb-ephemeral-p))
+ (setq nnweb-group group
+ nnweb-articles nil)
(let ((info (assoc group nnweb-group-alist)))
(when info
- (setq nnweb-group group)
(setq nnweb-type (nth 2 info))
(setq nnweb-search (nth 3 info))
(unless dont-check
(and (stringp article)
(nnweb-definition 'id t)
(let ((fetch (nnweb-definition 'id))
- art)
+ art active)
(when (string-match "^<\\(.*\\)>$" article)
(setq art (match-string 1 article)))
- (and fetch
- art
- (mm-with-unibyte-current-buffer
- (nnweb-fetch-url
- (format fetch article)))))))
+ (when (and fetch art)
+ (setq url (format fetch art))
+ (mm-with-unibyte-current-buffer
+ (nnweb-fetch-url url))
+ (if (nnweb-definition 'reference t)
+ (setq article
+ (funcall (nnweb-definition
+ 'reference) article)))))))
(unless nnheader-callback-function
- (funcall (nnweb-definition 'article))
- (nnweb-decode-entities))
+ (funcall (nnweb-definition 'article)))
(nnheader-report 'nnweb "Fetched article %s" article)
(cons group (and (numberp article) article))))))
(nnweb-open-server server)))
(unless nnweb-group-alist
(nnweb-read-active))
+ (unless nnweb-hashtb
+ (setq nnweb-hashtb (gnus-make-hashtable 4095)))
(when group
(when (and (not nnweb-ephemeral-p)
- (not (equal group nnweb-group)))
- (setq nnweb-hashtb (gnus-make-hashtable 4095))
+ (equal group nnweb-group))
(nnweb-request-group group nil t))))
(defun nnweb-init (server)
(car (rassq (string-to-number
(match-string 2 date))
parse-time-months))
- (match-string 3 date)
+ (match-string 3 date)
(match-string 1 date)))
(setq date "Jan 1 00:00:00 0000"))
(incf i)
(while (search-forward "," nil t)
(replace-match " " t t)))
(widen)
+ (nnweb-decode-entities)
(set-marker body nil))))
(defun nnweb-reference-search (search)
(while (re-search-forward "<A.*\\?id@\\([^\"]+\\)\">[0-9]+</A>" nil t)
(replace-match "<\\1> " t)))
(widen)
- (nnweb-remove-markup)))
+ (nnweb-remove-markup)
+ (nnweb-decode-entities)))
(defun nnweb-altavista-search (search &optional part)
(url-insert-file-contents
(setq buffer-file-name nil)
t)
+;;;
+;;; Deja bought by google.com
+;;;
+
+(defun nnweb-google-wash-article ()
+ (let ((case-fold-search t) url)
+ (goto-char (point-min))
+ (re-search-forward "^<pre>" nil t)
+ (narrow-to-region (point-min) (point))
+ (search-backward "<table " nil t 2)
+ (delete-region (point-min) (point))
+ (if (re-search-forward "Search Result [0-9]+" nil t)
+ (replace-match ""))
+ (if (re-search-forward "View complete thread ([0-9]+ articles?)" nil t)
+ (replace-match ""))
+ (goto-char (point-min))
+ (while (search-forward "<br>" nil t)
+ (replace-match "\n"))
+ (nnweb-remove-markup)
+ (goto-char (point-min))
+ (while (re-search-forward "^[ \t]*\n" nil t)
+ (replace-match ""))
+ (goto-char (point-max))
+ (insert "\n")
+ (widen)
+ (narrow-to-region (point) (point-max))
+ (search-forward "</pre>" nil t)
+ (delete-region (point) (point-max))
+ (nnweb-remove-markup)
+ (widen)))
+
+(defun nnweb-google-parse-1 (&optional Message-ID)
+ (let ((i 0)
+ (case-fold-search t)
+ (active (cadr (assoc nnweb-group nnweb-group-alist)))
+ Subject Score Date Newsgroups From
+ map url mid)
+ (unless active
+ (push (list nnweb-group (setq active (cons 1 0))
+ nnweb-type nnweb-search)
+ nnweb-group-alist))
+ ;; Go through all the article hits on this page.
+ (goto-char (point-min))
+ (while (re-search-forward
+ "a href=/groups\\(\\?[^ \">]*selm=\\([^ &\">]+\\)\\)" nil t)
+ (setq mid (match-string 2)
+ url (format
+ "http://groups.google.com/groups?selm=%s&output=gplain" mid))
+ (narrow-to-region (search-forward ">" nil t)
+ (search-forward "</a>" nil t))
+ (nnweb-remove-markup)
+ (nnweb-decode-entities)
+ (setq Subject (buffer-string))
+ (goto-char (point-max))
+ (widen)
+ (forward-line 1)
+ (when (looking-at "<br><font[^>]+>")
+ (goto-char (match-end 0)))
+ (if (not (looking-at "<a[^>]+>"))
+ (skip-chars-forward " \t")
+ (narrow-to-region (point)
+ (search-forward "</a>" nil t))
+ (nnweb-remove-markup)
+ (nnweb-decode-entities)
+ (setq Newsgroups (buffer-string))
+ (goto-char (point-max))
+ (widen)
+ (skip-chars-forward "- \t"))
+ (when (looking-at
+ "\\([0-9]+[/ ][A-Za-z]+[/ ][0-9]+\\)[ \t]*by[ \t]*\\([^<]*\\) - <a")
+ (setq From (match-string 2)
+ Date (match-string 1)))
+ (forward-line 1)
+ (incf i)
+ (unless (nnweb-get-hashtb url)
+ (push
+ (list
+ (incf (cdr active))
+ (make-full-mail-header
+ (cdr active) (if Newsgroups
+ (concat "(" Newsgroups ") " Subject)
+ Subject)
+ From Date (or Message-ID mid)
+ nil 0 0 url))
+ map)
+ (nnweb-set-hashtb (cadar map) (car map))))
+ map))
+
+(defun nnweb-google-reference (id)
+ (let ((map (nnweb-google-parse-1 id)) header)
+ (setq nnweb-articles
+ (nconc nnweb-articles map))
+ (when (setq header (cadar map))
+ (mm-with-unibyte-current-buffer
+ (nnweb-fetch-url (mail-header-xref header)))
+ (caar map))))
+
+(defun nnweb-google-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 ((more t))
+ (while more
+ (setq nnweb-articles
+ (nconc nnweb-articles (nnweb-google-parse-1)))
+ ;; FIXME: There is more.
+ (setq more nil))
+ ;; Return the articles in the right order.
+ (setq nnweb-articles
+ (sort nnweb-articles 'car-less-than-car))))))
+
+(defun nnweb-google-search (search)
+ (nnweb-insert
+ (concat
+ (nnweb-definition 'address)
+ "?"
+ (nnweb-encode-www-form-urlencoded
+ `(("q" . ,search)
+ ("num". "100")
+ ("hq" . "")
+ ("hl" . "")
+ ("lr" . "")
+ ("safe" . "off")
+ ("sites" . "groups")))))
+ t)
+
+(defun nnweb-google-identity (url)
+ "Return an unique identifier based on URL."
+ (if (string-match "selm=\\([^ &>]+\\)" url)
+ (match-string 1 url)
+ url))
+
;;;
;;; General web/w3 interface utility functions
;;;
(defun nnweb-insert-html (parse)
"Insert HTML based on a w3 parse tree."
(if (stringp parse)
- (insert parse)
+ (insert (nnheader-string-as-multibyte parse))
(insert "<" (symbol-name (car parse)) " ")
(insert (mapconcat
(lambda (param)
(while (re-search-forward "&\\(#[0-9]+\\|[a-z]+\\);" nil t)
(let ((elem (if (eq (aref (match-string 1) 0) ?\#)
(let ((c
- (string-to-number (substring
+ (string-to-number (substring
(match-string 1) 1))))
(if (mm-char-or-char-int-p c) c 32))
(or (cdr (assq (intern (match-string 1))
(setq elem (char-to-string elem)))
(replace-match elem t t))))
-(defun nnweb-decode-entities-string (str)
+(defun nnweb-decode-entities-string (string)
(with-temp-buffer
- (insert str)
+ (insert string)
(nnweb-decode-entities)
(buffer-substring (point-min) (point-max))))
"Insert the contents from an URL in the current buffer.
If FOLLOW-REFRESH is non-nil, redirect refresh url in META."
(let ((name buffer-file-name))
- (if follow-refresh
+ (if follow-refresh
(save-restriction
(narrow-to-region (point) (point))
(url-insert-file-contents url)
(goto-char (point-min))
- (when (re-search-forward
+ (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))
(listp (cdr element)))
(nnweb-text-1 element)))))
+(defun nnweb-replace-in-string (string match newtext)
+ (while (string-match match string)
+ (setq string (replace-match newtext t t string)))
+ string)
+
(provide 'nnweb)
;;; nnweb.el ends here