aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGnus developers2010-12-02 22:21:31 +0000
committerKatsumi Yamaoka2010-12-02 22:21:31 +0000
commited797193995dc845b70a32c82eee63a39c40011f (patch)
treeda7623c16afe017ab7e33b2d9116a5f5644c4bb6
parent66feec8bbe23ad4979905e9f6fae807b27cc33de (diff)
downloademacs-ed797193995dc845b70a32c82eee63a39c40011f.tar.gz
emacs-ed797193995dc845b70a32c82eee63a39c40011f.zip
Merge changes made in Gnus trunk.
nnir.el: Batch header retrieval. proto-stream.el: New library to provide protocol-specific TLS/STARTTLS connections for IMAP, NNTP, SMTP, POP3 and similar protocols. nnimap.el (nnimap-open-connection): Use it. proto-stream.el (open-proto-stream): Complete the documentation. nnimap.el (nnimap-open-connection): Check for "OK" from the greeting. nntp.el: Use proto-streams for the relevant connections types. nntp.el (nntp-open-connection): Switch on STARTTLS on supported servers. proto-stream.el (open-proto-stream): Add a way to specify what the end of a command is. proto-stream.el (proto-stream-open-tls): Delete output from openssl if we're using tls.el. proto-stream.el (proto-stream-open-network): If we don't have gnutls-cli or gnutls built in, then don't try to establish a STARTTLS connection. color.el (color-lab->srgb): Fix function call name. proto-stream.el: Fix the syntax in the comment. nntp.el (nntp-open-connection): Fix the STARTTLS command syntax. proto-stream.el (proto-stream-open-starttls): Actually implement the starttls.el STARTTLS. proto-stream.el (proto-stream-always-use-starttls): New variable. proto-stream.el (proto-stream-open-starttls): De-duplicate the starttls code. proto-stream.el (proto-stream-open-starttls): Folded back into the main function. proto-stream.el (proto-stream-command): Refactor out. nnimap.el (nnimap-stream): Change default to `undecided'. nnimap.el (nnimap-open-connection): If `nnimap-stream' is `undecided', try ssl first, and then network. nnimap.el (nnimap-open-connection-1): Respect nnimap-server-port. nnimap.el (nnimap-open-connection): Be more backwards-compatible. proto-stream.el (open-protocol-stream): Renamed from open-proto-stream. proto-stream.el (proto-stream-open-network): When doing opportunistic TLS upgrades we don't really care about the identity of the peer. gnus.texi (Customizing the IMAP Connection): Note the new defaults. gnus.texi (Direct Functions): Note the STARTTLS upgrade. proto-stream.el (proto-stream-open-network): Force starttls.el to use gnutls-cli, since that what we've checked for. proto-stream.el (proto-stream-always-use-starttls): Only default to t if open-gnutls-stream exists. proto-stream.el (proto-stream-open-network): If STARTTLS failed, then just open a normal connection. proto-stream.el (proto-stream-open-network): Wait until the greeting before doing STARTTLS. nnimap.el (nnimap-open-connection-1): Always upgrade to STARTTLS (for backwards compatibility). nnimap.el (nnimap-open-connection-1): Really respect nnimap-server-port. nntp.el (nntp-open-connection): Provide a :success condition. nnimap.el (nnimap-open-connection-1): Ditto. proto-stream.el (proto-stream-open-network): See what the response to the STARTTLS command is. proto-stream.el (proto-stream-open-network): Add some comments. proto-stream.el: Fix example. proto-stream.el (open-protocol-stream): Actually mention the STARTTLS upgrade. nnir.el (nnir-get-active): Skip nnir-ignored-newsgroups when searching. nnir.el (nnir-ignore-newsgroups): Fix default value. nnir.el (nnir-run-gmane): Use mm-delete-duplicates instead of delete-dups that is not available in XEmacs 21.4. mm-util.el (mm-delete-duplicates): Add comment. gnus-sum.el (gnus-summary-delete-article): If delete fails don't change the registry. nnimap.el (nnimap-open-connection-1): w32 open-network-stream doesn't seem to accept strings-with-numbers as port numbers. color.el: fix docstring to use English rather than math notation for intervals. shr.el (shr-find-fill-point): Don't break before apostrophes. nnir.el (nnir-request-move-article): Bail out if no move support in group. color.el (color-rgb->hsv): Fix docstring. nnir.el (nnir-get-active): Improve active list retrieval. shr.el (shr-find-fill-point): Work better for kinsoku chars and apostrophes. gnus-gravatar.el (gnus-gravatar-size): Set gnus-gravatar-size to nil. nnimap.el (nnimap-open-connection-1): Use gnus-string-match-p. nnimap.el (nnimap-open-connection-1): Fix PREAUTH. proto-stream.el (open-protocol-stream): All starttls connections are handled by the network handler. gnus-gravatar.el (gnus-gravatar-insert): Delete unnecessary binding to t of inhibit-read-only since it is inside gnus-with-article-headers. gnus-gravatar.el (gnus-gravatar-transform-address): Use mail-extract-address-components that supports non-ASCII names rather than mail-header-parse-addresses. shr.el (shr-find-fill-point): Don't break line between kinsoku-bol characters. gnus-gravatar.el (gnus-gravatar-insert): Allow LWSP in the middle of names. nnmaildir.el (nnmaildir-request-set-mark): Add article to add-mark funcall. gnus-msg.el: Remove nastygram thing. message.el (message-from-style): Fix comment. message.el (message-user-organization): Do not use gnus-local-organization. gnus.el: Remove gnus-local-organization. rtree.el: New file to handle range trees. nnir.el, gnus-sum.el: Redo the way nnir handles registry updates. rtree.el (rtree-extract): Simplify. gnus-win.el (gnus-configure-windows): Remove Gnus 3.x setting support. gnus-msg.el: Mark gnus-outgoing-message-group as obsolete. gnus.texi (Archived Messages): Remove gnus-outgoing-message-group. gnus-win.el (gnus-configure-frame): Remove old compatibility code. rtree.el (rtree-memq): Rewrite it as a non-recursive function. rtree.el (rtree-add, rtree-delq, rtree-length): Implement. rtree.el (rtree-add): Make code slightly faster. nnir.el: Allow modified summary-line-format in nnir summary buffers.
-rw-r--r--doc/misc/ChangeLog9
-rw-r--r--doc/misc/gnus.texi30
-rw-r--r--lisp/gnus/ChangeLog225
-rw-r--r--lisp/gnus/color.el13
-rw-r--r--lisp/gnus/gnus-gravatar.el47
-rw-r--r--lisp/gnus/gnus-msg.el67
-rw-r--r--lisp/gnus/gnus-sum.el425
-rw-r--r--lisp/gnus/gnus-win.el142
-rw-r--r--lisp/gnus/gnus.el4
-rw-r--r--lisp/gnus/message.el17
-rw-r--r--lisp/gnus/mm-util.el1
-rw-r--r--lisp/gnus/nnimap.el193
-rw-r--r--lisp/gnus/nnir.el424
-rw-r--r--lisp/gnus/nnmaildir.el2
-rw-r--r--lisp/gnus/nntp.el67
-rw-r--r--lisp/gnus/proto-stream.el262
-rw-r--r--lisp/gnus/rtree.el279
-rw-r--r--lisp/gnus/shr.el160
18 files changed, 1532 insertions, 835 deletions
diff --git a/doc/misc/ChangeLog b/doc/misc/ChangeLog
index 91ac5f74b0e..8d47de4f2a0 100644
--- a/doc/misc/ChangeLog
+++ b/doc/misc/ChangeLog
@@ -1,3 +1,12 @@
12010-12-02 Julien Danjou <julien@danjou.info>
2
3 * gnus.texi (Archived Messages): Remove gnus-outgoing-message-group.
4
52010-11-28 Lars Magne Ingebrigtsen <larsi@gnus.org>
6
7 * gnus.texi (Customizing the IMAP Connection): Note the new defaults.
8 (Direct Functions): Note the STARTTLS upgrade.
9
12010-11-27 Glenn Morris <rgm@gnu.org> 102010-11-27 Glenn Morris <rgm@gnu.org>
2 James Clark <none@example.com> 11 James Clark <none@example.com>
3 12
diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi
index ad9be300a1d..9e2e0b817b6 100644
--- a/doc/misc/gnus.texi
+++ b/doc/misc/gnus.texi
@@ -13342,21 +13342,6 @@ case you should set @code{gnus-message-archive-group} to @code{nil};
13342this will disable archiving. 13342this will disable archiving.
13343 13343
13344@table @code 13344@table @code
13345@item gnus-outgoing-message-group
13346@vindex gnus-outgoing-message-group
13347All outgoing messages will be put in this group. If you want to store
13348all your outgoing mail and articles in the group @samp{nnml:archive},
13349you set this variable to that value. This variable can also be a list of
13350group names.
13351
13352If you want to have greater control over what group to put each
13353message in, you can set this variable to a function that checks the
13354current newsgroup name and then returns a suitable group name (or list
13355of names).
13356
13357This variable can be used instead of @code{gnus-message-archive-group},
13358but the latter is the preferred method.
13359
13360@item gnus-gcc-mark-as-read 13345@item gnus-gcc-mark-as-read
13361@vindex gnus-gcc-mark-as-read 13346@vindex gnus-gcc-mark-as-read
13362If non-@code{nil}, automatically mark @code{Gcc} articles as read. 13347If non-@code{nil}, automatically mark @code{Gcc} articles as read.
@@ -14453,7 +14438,9 @@ functions is also affected by commonly understood variables
14453@findex nntp-open-network-stream 14438@findex nntp-open-network-stream
14454@item nntp-open-network-stream 14439@item nntp-open-network-stream
14455This is the default, and simply connects to some port or other on the 14440This is the default, and simply connects to some port or other on the
14456remote system. 14441remote system. If both Emacs and the server supports it, the
14442connection will be upgraded to an encrypted @acronym{STARTTLS}
14443connection automatically.
14457 14444
14458@findex nntp-open-tls-stream 14445@findex nntp-open-tls-stream
14459@item nntp-open-tls-stream 14446@item nntp-open-tls-stream
@@ -14887,12 +14874,17 @@ typical port would be @code{"imap"} or @code{"imaps"}.
14887How @code{nnimap} should connect to the server. Possible values are: 14874How @code{nnimap} should connect to the server. Possible values are:
14888 14875
14889@table @code 14876@table @code
14877@item undecided
14878This is the default, and this first tries the @code{ssl} setting, and
14879then tries the @code{network} setting.
14880
14890@item ssl 14881@item ssl
14891This is the default, and this uses standard 14882This uses standard @acronym{TLS}/@acronym{SSL} connections.
14892@acronym{TLS}/@acronym{SSL} connection.
14893 14883
14894@item network 14884@item network
14895Non-encrypted and unsafe straight socket connection. 14885Non-encrypted and unsafe straight socket connection, but will upgrade
14886to encrypted @acronym{STARTTLS} if both Emacs and the server
14887supports it.
14896 14888
14897@item starttls 14889@item starttls
14898Encrypted @acronym{STARTTLS} over the normal @acronym{IMAP} port. 14890Encrypted @acronym{STARTTLS} over the normal @acronym{IMAP} port.
diff --git a/lisp/gnus/ChangeLog b/lisp/gnus/ChangeLog
index 651cfef7f00..8d4b14fa456 100644
--- a/lisp/gnus/ChangeLog
+++ b/lisp/gnus/ChangeLog
@@ -1,3 +1,228 @@
12010-12-02 Andrew Cohen <cohen@andy.bu.edu>
2
3 * nnir.el (nnir-summary-line-format): New variable.
4 (nnir-mode): Use it.
5 (nnir-artlist-*,nnir-aritem-*): Reimplement as macros.
6 (nnir-article-ids): Reimplement as defsubst.
7 (nnir-retrieve-headers): Don't mangle the subject header.
8 (nnir-run-imap): Use 100 as RSV score.
9 (nnir-run-find-grep): Fix for full server searching.
10 (nnir-run-gmane): Better restriction to gmane groups.
11
12 * gnus-sum.el (gnus-summary-line-format-alist): Add specs for nnir
13 summary buffers.
14
152010-12-02 Julien Danjou <julien@danjou.info>
16
17 * gnus-win.el (gnus-configure-frame): Remove old compatibility code.
18
19 * gnus-msg.el: Mark gnus-outgoing-message-group as obsolete.
20
21 * gnus-win.el (gnus-configure-windows): Remove Gnus 3.x setting
22 support.
23
242010-12-01 Andrew Cohen <cohen@andy.bu.edu>
25
26 * nnir.el: Update to handle the registry better.
27 (autoload): Silence byte-compiler.
28 (nnir-open-server): Add a hook for nnir groups.
29 (nnir-request-move-article): Don't mangle the header. Better to use
30 formating variables (which will be added in the future).
31 (nnir-registry-action): Update the registry using the original article
32 group name.
33 (nnir-mode): Install nnir-specific hooks for updating the registry.
34
35 * gnus-sum.el
36 (gnus-article-original-subject,gnus-newsgroup-original-name): Remove
37 obsolete variables.
38 (gnus-summary-move-article): Remove use of obsolete variables.
39 (gnus-summary-local-variables): Make move and delete hooks local to
40 summary buffers.
41
422010-12-01 Lars Magne Ingebrigtsen <larsi@gnus.org>
43
44 * rtree.el: New file.
45
462010-12-01 Julien Danjou <julien@danjou.info>
47
48 * message.el (message-user-organization): Do not use
49 gnus-local-organization.
50
51 * gnus.el: Remove gnus-local-organization.
52
53 * gnus-msg.el: Remove nastygram thing.
54
552010-12-01 Teodor Zlatanov <tzz@lifelogs.com>
56
57 * nnmaildir.el (nnmaildir-request-set-mark): Add article to add-mark
58 funcall.
59
602010-12-01 Katsumi Yamaoka <yamaoka@jpl.org>
61
62 * gnus-gravatar.el (gnus-gravatar-insert): Allow LWSP in the middle of
63 names.
64
65 * shr.el (shr-find-fill-point): Don't break line between kinsoku-bol
66 characters.
67
68 * gnus-gravatar.el (gnus-gravatar-insert): Delete unnecessary binding
69 to t of inhibit-read-only since it is inside gnus-with-article-headers.
70 Suggested by Štěpán Němec <stepnem@gmail.com>.
71 (gnus-gravatar-transform-address): Use mail-extract-address-components
72 that supports non-ASCII names rather than mail-header-parse-addresses.
73
742010-11-30 Lars Magne Ingebrigtsen <larsi@gnus.org>
75
76 * proto-stream.el (open-protocol-stream): All starttls connections are
77 handled by the network handler.
78
792010-11-30 Julien Danjou <julien@danjou.info>
80
81 * nnimap.el (nnimap-open-connection-1): Use gnus-string-match-p.
82 (nnimap-open-connection-1): Fix PREAUTH.
83
84 * gnus-gravatar.el (gnus-gravatar-size): Set gnus-gravatar-size to nil.
85
862010-11-30 Katsumi Yamaoka <yamaoka@jpl.org>
87
88 * shr.el (shr-char-breakable-p, shr-char-nospace-p)
89 (shr-char-kinsoku-bol-p, shr-char-kinsoku-eol-p): New macros.
90 (shr-insert): Use them.
91 (shr-find-fill-point): Work better for kinsoku chars and apostrophes.
92
932010-11-29 Andrew Cohen <cohen@andy.bu.edu>
94
95 * nnir.el (nnir-request-move-article): Bail out if original group
96 doesn't support article moves.
97 (nnir-get-active): Improve active list retrieval.
98
992010-11-29 Lars Magne Ingebrigtsen <larsi@gnus.org>
100
101 * shr.el (shr-find-fill-point): Don't break before apostrophes.
102
1032010-11-29 Binjo <binjo.cn@gmail.com> (tiny change)
104
105 * nnimap.el (nnimap-open-connection-1): w32 open-network-stream doesn't
106 seem to accept strings-with-numbers as port numbers,
107
1082010-11-29 Andrew Cohen <cohen@andy.bu.edu>
109
110 * gnus-sum.el (gnus-summary-delete-article): If delete fails don't
111 change the registry.
112
1132010-11-29 Katsumi Yamaoka <yamaoka@jpl.org>
114
115 * nnir.el (nnir-run-gmane): Use mm-delete-duplicates instead of
116 delete-dups that is not available in XEmacs 21.4.
117
118 * mm-util.el (mm-delete-duplicates): Add comment.
119
1202010-11-28 Andrew Cohen <cohen@andy.bu.edu>
121
122 * nnir.el (nnir-ignored-newsgroups): New variable.
123 (nnir-get-active): Use it.
124
1252010-11-28 Lars Magne Ingebrigtsen <larsi@gnus.org>
126
127 * proto-stream.el (proto-stream-open-network): Add some comments.
128
129 * nntp.el (nntp-open-connection): Provide a :success condition.
130
131 * nnimap.el (nnimap-open-connection-1): Ditto.
132
133 * proto-stream.el (proto-stream-open-network): See what the response to
134 the STARTTLS command is.
135
136 * nnimap.el (nnimap-open-connection-1): Always upgrade to STARTTLS (for
137 backwards compatibility).
138 (nnimap-open-connection-1): Really respect nnimap-server-port.
139
140 * proto-stream.el (proto-stream-open-network): When doing opportunistic
141 TLS upgrades we don't really care about the identity of the peer.
142 (proto-stream-open-network): Force starttls.el to use gnutls-cli, since
143 that what we've checked for.
144 (proto-stream-always-use-starttls): Only default to t if
145 open-gnutls-stream exists.
146 (proto-stream-open-network): If STARTTLS failed, then just open a
147 normal connection.
148 (proto-stream-open-network): Wait until the greeting before doing
149 STARTTLS.
150
151 * nntp.el (nntp-open-connection): Report what the connection error is.
152
153 * proto-stream.el (open-protocol-stream): Renamed from
154 open-proto-stream.
155
1562010-11-27 Lars Magne Ingebrigtsen <larsi@gnus.org>
157
158 * nnimap.el (nnimap-stream): Change default to `undecided'.
159 (nnimap-open-connection): If `nnimap-stream' is `undecided', try ssl
160 first, and then network.
161 (nnimap-open-connection-1): Respect nnimap-server-port.
162 (nnimap-open-connection): Be more backwards-compatible.
163
164 * proto-stream.el (proto-stream-always-use-starttls): New variable.
165 (proto-stream-open-starttls): De-duplicate the starttls code.
166 (proto-stream-open-starttls): Folded back into the main function.
167 (proto-stream-open-network): Fix typo in the gnutls path.
168 (proto-stream-command): Refactor out.
169
170 * nntp.el (nntp-open-connection): Fix the STARTTLS command syntax.
171
172 * proto-stream.el (proto-stream-open-starttls): Actually implement the
173 starttls.el STARTTLS.
174
175 * color.el (color-lab->srgb): Fix function call name.
176
177 * proto-stream.el (proto-stream-open-tls): Delete output from openssl
178 if we're using tls.el.
179 (proto-stream-open-network): If we don't have gnutls-cli or gnutls
180 built in, then don't try to establish a STARTTLS connection.
181
182 * nntp.el (nntp-open-connection): Switch on STARTTLS on supported
183 servers.
184
185 * proto-stream.el (open-proto-stream): Use network, not stream.
186 (open-proto-stream): Add a way to specify what the end of a command is.
187
188 * nntp.el (nntp-open-connection): Use proto-streams for the relevant
189 connections types.
190 (nntp-open-network-stream): Remove.
191 (nntp-open-ssl-stream): Remove.
192 (nntp-open-tls-stream): Remove.
193 (nntp-ssl-program): Remove.
194
195 * nnimap.el (nnimap-open-connection): Check for "OK" from the greeting.
196
1972010-11-27 Andrew Cohen <cohen@andy.bu.edu>
198
199 * nnir.el: Fix typos.
200 (nnir-retrieve-headers-override-function): Rename variable to reflect
201 new semantics.
202 (nnir-article-group, nnir-article-number, nnir-article-rsv): New helper
203 macros.
204 (nnir-request-article, nnir-request-move-article): Use them.
205 (nnir-categorize): New function.
206 (nnir-run-query): Use it.
207 (nnir-retrieve-headers): Rewrite to batch header retrieval.
208 (nnir-run-gmane): nnir-retrieve-headers now returns the headers already
209 sorted.
210 (nnir-group-full-name): Use gnus-group-full-name instead.
211 (nnir-artlist-artitem-group, nnir-artlist-artitem-number)
212 (nnir-artlist-artitem-rsv, nnir-sort-groups-by-server): Obsolete.
213
2142010-11-27 Lars Magne Ingebrigtsen <larsi@gnus.org>
215
216 * nnimap.el (nnimap-open-connection): Fix typo in STARTTLS command.
217
218 * proto-stream.el: New library to provide protocol-specific
219 TLS/STARTTLS connections for IMAP, NNTP, SMTP, POP3 and similar
220 protocols.
221 (open-proto-stream): Complete the documentation.
222 (proto-stream-open-network): Fix some typos.
223
224 * nnimap.el (nnimap-open-connection): Use it.
225
12010-11-27 Yuri Karaban <tech@askold.net> (tiny change) 2262010-11-27 Yuri Karaban <tech@askold.net> (tiny change)
2 227
3 * pop3.el (pop3-open-server): Read server greeting before starting TLS 228 * pop3.el (pop3-open-server): Read server greeting before starting TLS
diff --git a/lisp/gnus/color.el b/lisp/gnus/color.el
index 4d3718bc8df..07044333c4b 100644
--- a/lisp/gnus/color.el
+++ b/lisp/gnus/color.el
@@ -36,7 +36,7 @@
36 36
37(defun color-rgb->hex (red green blue) 37(defun color-rgb->hex (red green blue)
38 "Return hexadecimal notation for RED GREEN BLUE color. 38 "Return hexadecimal notation for RED GREEN BLUE color.
39RED GREEN BLUE must be values between [0,1]." 39RED GREEN BLUE must be values between 0 and 1 inclusively."
40 (format "#%02x%02x%02x" 40 (format "#%02x%02x%02x"
41 (* red 255) (* green 255) (* blue 255))) 41 (* red 255) (* green 255) (* blue 255)))
42 42
@@ -53,7 +53,8 @@ RED GREEN BLUE must be values between [0,1]."
53 53
54(defun color-rgb->hsv (red green blue) 54(defun color-rgb->hsv (red green blue)
55 "Convert RED GREEN BLUE values to HSV representation. 55 "Convert RED GREEN BLUE values to HSV representation.
56Hue is in radian. Saturation and values are between [0,1]." 56Hue is in radians. Saturation and values are between 0 and 1
57inclusively."
57 (let* ((r (float red)) 58 (let* ((r (float red))
58 (g (float green)) 59 (g (float green))
59 (b (float blue)) 60 (b (float blue))
@@ -80,7 +81,7 @@ Hue is in radian. Saturation and values are between [0,1]."
80 81
81(defun color-rgb->hsl (red green blue) 82(defun color-rgb->hsl (red green blue)
82 "Convert RED GREEN BLUE colors to their HSL representation. 83 "Convert RED GREEN BLUE colors to their HSL representation.
83RED, GREEN and BLUE must be between [0,1]." 84RED, GREEN and BLUE must be between 0 and 1 inclusively."
84 (let* ((r red) 85 (let* ((r red)
85 (g green) 86 (g green)
86 (b blue) 87 (b blue)
@@ -108,7 +109,7 @@ RED, GREEN and BLUE must be between [0,1]."
108 109
109(defun color-srgb->xyz (red green blue) 110(defun color-srgb->xyz (red green blue)
110 "Converts RED GREEN BLUE colors from the sRGB color space to CIE XYZ. 111 "Converts RED GREEN BLUE colors from the sRGB color space to CIE XYZ.
111RED, BLUE and GREEN must be between [0,1]." 112RED, BLUE and GREEN must be between 0 and 1 inclusively."
112 (let ((r (if (<= red 0.04045) 113 (let ((r (if (<= red 0.04045)
113 (/ red 12.95) 114 (/ red 12.95)
114 (expt (/ (+ red 0.055) 1.055) 2.4))) 115 (expt (/ (+ red 0.055) 1.055) 2.4)))
@@ -191,12 +192,12 @@ none is set, `color-d65-xyz' is used."
191 (apply 'color-xyz->lab (color-srgb->xyz red green blue))) 192 (apply 'color-xyz->lab (color-srgb->xyz red green blue)))
192 193
193(defun color-rgb->normalize (color) 194(defun color-rgb->normalize (color)
194 "Normalize a RGB color to values between [0,1]." 195 "Normalize a RGB color to values between 0 and 1 inclusively."
195 (mapcar (lambda (x) (/ x 65535.0)) (x-color-values color))) 196 (mapcar (lambda (x) (/ x 65535.0)) (x-color-values color)))
196 197
197(defun color-lab->srgb (L a b) 198(defun color-lab->srgb (L a b)
198 "Converts CIE L*a*b* to RGB." 199 "Converts CIE L*a*b* to RGB."
199 (apply 'color-xyz->rgb (color-lab->xyz L a b))) 200 (apply 'color-xyz->srgb (color-lab->xyz L a b)))
200 201
201(defun color-cie-de2000 (color1 color2 &optional kL kC kH) 202(defun color-cie-de2000 (color1 color2 &optional kL kC kH)
202 "Computes the CIEDE2000 color distance between COLOR1 and COLOR2. 203 "Computes the CIEDE2000 color distance between COLOR1 and COLOR2.
diff --git a/lisp/gnus/gnus-gravatar.el b/lisp/gnus/gnus-gravatar.el
index fd62f175a2a..27f65c04094 100644
--- a/lisp/gnus/gnus-gravatar.el
+++ b/lisp/gnus/gnus-gravatar.el
@@ -26,13 +26,15 @@
26 26
27(require 'gravatar) 27(require 'gravatar)
28(require 'gnus-art) 28(require 'gnus-art)
29(require 'mail-extr) ;; Because of binding `mail-extr-disable-voodoo'.
29 30
30(defgroup gnus-gravatar nil 31(defgroup gnus-gravatar nil
31 "Gnus Gravatar." 32 "Gnus Gravatar."
32 :group 'gnus-visual) 33 :group 'gnus-visual)
33 34
34(defcustom gnus-gravatar-size 32 35(defcustom gnus-gravatar-size nil
35 "How big should gravatars be displayed." 36 "How big should gravatars be displayed.
37If nil, default to `gravatar-size'."
36 :type 'integer 38 :type 'integer
37 :version "24.1" 39 :version "24.1"
38 :group 'gnus-gravatar) 40 :group 'gnus-gravatar)
@@ -51,30 +53,25 @@
51 53
52(defun gnus-gravatar-transform-address (header category &optional force) 54(defun gnus-gravatar-transform-address (header category &optional force)
53 (gnus-with-article-headers 55 (gnus-with-article-headers
54 (let ((addresses 56 (let* ((mail-extr-disable-voodoo t)
55 (mail-header-parse-addresses 57 (addresses (mail-extract-address-components
56 ;; mail-header-parse-addresses does not work (reliably) on 58 (or (mail-fetch-field header) "") t))
57 ;; decoded headers. 59 (gravatar-size gnus-gravatar-size)
58 (or 60 name)
59 (ignore-errors
60 (mail-encode-encoded-word-string
61 (or (mail-fetch-field header) "")))
62 (mail-fetch-field header))))
63 (gravatar-size gnus-gravatar-size)
64 name)
65 (dolist (address addresses) 61 (dolist (address addresses)
66 (when (setq name (cdr address)) 62 (when (and (setq name (car address))
67 (setcdr address (setq name (mail-decode-encoded-word-string name)))) 63 (string-match "\\` +" name))
64 (setcar address (setq name (substring name (match-end 0)))))
68 (when (or force 65 (when (or force
69 (not (and gnus-gravatar-too-ugly 66 (not (and gnus-gravatar-too-ugly
70 (or (string-match gnus-gravatar-too-ugly 67 (or (string-match gnus-gravatar-too-ugly
71 (car address)) 68 (cadr address))
72 (and name 69 (and name
73 (string-match gnus-gravatar-too-ugly 70 (string-match gnus-gravatar-too-ugly
74 name)))))) 71 name))))))
75 (ignore-errors 72 (ignore-errors
76 (gravatar-retrieve 73 (gravatar-retrieve
77 (car address) 74 (cadr address)
78 'gnus-gravatar-insert 75 'gnus-gravatar-insert
79 (list header address category)))))))) 76 (list header address category))))))))
80 77
@@ -87,12 +84,15 @@ Set image category to CATEGORY."
87 (when (buffer-live-p (current-buffer)) 84 (when (buffer-live-p (current-buffer))
88 (gnus-article-goto-header header) 85 (gnus-article-goto-header header)
89 (mail-header-narrow-to-field) 86 (mail-header-narrow-to-field)
90 (let ((real-name (cdr address)) 87 (let ((real-name (car address))
91 (mail-address (car address))) 88 (mail-address (cadr address)))
92 (when (if real-name 89 (when (if real-name
93 (re-search-forward (concat (regexp-quote real-name) "\\|" 90 (re-search-forward
94 (regexp-quote mail-address)) 91 (concat (gnus-replace-in-string
95 nil t) 92 (regexp-quote real-name) "[\t ]+" "[\t\n ]+")
93 "\\|"
94 (regexp-quote mail-address))
95 nil t)
96 (search-forward mail-address nil t)) 96 (search-forward mail-address nil t))
97 (goto-char (1- (match-beginning 0))) 97 (goto-char (1- (match-beginning 0)))
98 ;; If we're on the " quoting the name, go backward 98 ;; If we're on the " quoting the name, go backward
@@ -103,8 +103,7 @@ Set image category to CATEGORY."
103 ;; example we were fetching someaddress, and then we change to 103 ;; example we were fetching someaddress, and then we change to
104 ;; another mail with the same someaddress. 104 ;; another mail with the same someaddress.
105 (unless (memq 'gnus-gravatar (text-properties-at (point))) 105 (unless (memq 'gnus-gravatar (text-properties-at (point)))
106 (let ((inhibit-read-only t) 106 (let ((point (point)))
107 (point (point)))
108 (unless (featurep 'xemacs) 107 (unless (featurep 'xemacs)
109 (setq gravatar (append gravatar gnus-gravatar-properties))) 108 (setq gravatar (append gravatar gnus-gravatar-properties)))
110 (gnus-put-image gravatar nil category) 109 (gnus-put-image gravatar nil category)
diff --git a/lisp/gnus/gnus-msg.el b/lisp/gnus/gnus-msg.el
index 544aa7776a8..d77abfa1c61 100644
--- a/lisp/gnus/gnus-msg.el
+++ b/lisp/gnus/gnus-msg.el
@@ -55,7 +55,7 @@ method to use when posting."
55 (sexp :tag "Methods" ,gnus-select-method))) 55 (sexp :tag "Methods" ,gnus-select-method)))
56 56
57(defcustom gnus-outgoing-message-group nil 57(defcustom gnus-outgoing-message-group nil
58 "*All outgoing messages will be put in this group. 58 "All outgoing messages will be put in this group.
59If you want to store all your outgoing mail and articles in the group 59If you want to store all your outgoing mail and articles in the group
60\"nnml:archive\", you set this variable to that value. This variable 60\"nnml:archive\", you set this variable to that value. This variable
61can also be a list of group names. 61can also be a list of group names.
@@ -70,6 +70,8 @@ of names)."
70 (string :tag "Group") 70 (string :tag "Group")
71 (repeat :tag "List of groups" (string :tag "Group")))) 71 (repeat :tag "List of groups" (string :tag "Group"))))
72 72
73(make-obsolete-variable 'gnus-outgoing-message-group 'gnus-message-archive-group "24.1")
74
73(defcustom gnus-mailing-list-groups nil 75(defcustom gnus-mailing-list-groups nil
74 "*If non-nil a regexp matching groups that are really mailing lists. 76 "*If non-nil a regexp matching groups that are really mailing lists.
75This is useful when you're reading a mailing list that has been 77This is useful when you're reading a mailing list that has been
@@ -397,7 +399,6 @@ Thank you for your help in stamping out bugs.
397 (message-mode-hook (copy-sequence message-mode-hook))) 399 (message-mode-hook (copy-sequence message-mode-hook)))
398 (setq mml-buffer-list nil) 400 (setq mml-buffer-list nil)
399 (add-hook 'message-header-setup-hook 'gnus-inews-insert-gcc) 401 (add-hook 'message-header-setup-hook 'gnus-inews-insert-gcc)
400 (add-hook 'message-header-setup-hook 'gnus-inews-insert-archive-gcc)
401 ;; message-newsreader and message-mailer were formerly set in 402 ;; message-newsreader and message-mailer were formerly set in
402 ;; gnus-inews-add-send-actions, but this is too late when 403 ;; gnus-inews-add-send-actions, but this is too late when
403 ;; message-generate-headers-first is used. --ansel 404 ;; message-generate-headers-first is used. --ansel
@@ -826,7 +827,6 @@ header line with the old Message-ID."
826 (gnus-summary-mark-as-read ,article gnus-canceled-mark))))) 827 (gnus-summary-mark-as-read ,article gnus-canceled-mark)))))
827 message-send-actions) 828 message-send-actions)
828 ;; Add Gcc header. 829 ;; Add Gcc header.
829 (gnus-inews-insert-archive-gcc)
830 (gnus-inews-insert-gcc)))) 830 (gnus-inews-insert-gcc))))
831 831
832 832
@@ -1294,7 +1294,6 @@ composing a new message."
1294 (goto-char (point-max)) 1294 (goto-char (point-max))
1295 (insert mail-header-separator) 1295 (insert mail-header-separator)
1296 ;; Add Gcc header. 1296 ;; Add Gcc header.
1297 (gnus-inews-insert-archive-gcc)
1298 (gnus-inews-insert-gcc) 1297 (gnus-inews-insert-gcc)
1299 (goto-char (point-min)) 1298 (goto-char (point-min))
1300 (when (re-search-forward "^To:\\|^Newsgroups:" nil 'move) 1299 (when (re-search-forward "^To:\\|^Newsgroups:" nil 'move)
@@ -1307,24 +1306,6 @@ See `gnus-summary-mail-forward' for ARG."
1307 (interactive "P") 1306 (interactive "P")
1308 (gnus-summary-mail-forward arg t)) 1307 (gnus-summary-mail-forward arg t))
1309 1308
1310(defvar gnus-nastygram-message
1311 "The following article was inappropriately posted to %s.\n\n"
1312 "Format string to insert in nastygrams.
1313The current group name will be inserted at \"%s\".")
1314
1315(defun gnus-summary-mail-nastygram (n)
1316 "Send a nastygram to the author of the current article."
1317 (interactive "P")
1318 (when (or gnus-expert-user
1319 (gnus-y-or-n-p
1320 "Really send a nastygram to the author of the current article? "))
1321 (let ((group gnus-newsgroup-name))
1322 (gnus-summary-reply-with-original n)
1323 (set-buffer gnus-message-buffer)
1324 (message-goto-body)
1325 (insert (format gnus-nastygram-message group))
1326 (message-send-and-exit))))
1327
1328(defun gnus-summary-mail-crosspost-complaint (n) 1309(defun gnus-summary-mail-crosspost-complaint (n)
1329 "Send a complaint about crossposting to the current article(s)." 1310 "Send a complaint about crossposting to the current article(s)."
1330 (interactive "P") 1311 (interactive "P")
@@ -1580,7 +1561,6 @@ this is a reply."
1580 (gnus-setup-message 'compose-bounce 1561 (gnus-setup-message 'compose-bounce
1581 (message-bounce) 1562 (message-bounce)
1582 ;; Add Gcc header. 1563 ;; Add Gcc header.
1583 (gnus-inews-insert-archive-gcc)
1584 (gnus-inews-insert-gcc) 1564 (gnus-inews-insert-gcc)
1585 ;; If there are references, we fetch the article we answered to. 1565 ;; If there are references, we fetch the article we answered to.
1586 (when parent 1566 (when parent
@@ -1694,44 +1674,13 @@ this is a reply."
1694 (gnus-group-mark-article-read group (cdr group-art))) 1674 (gnus-group-mark-article-read group (cdr group-art)))
1695 (kill-buffer (current-buffer))))))))) 1675 (kill-buffer (current-buffer)))))))))
1696 1676
1697(defun gnus-inews-insert-gcc () 1677(defun gnus-inews-insert-gcc (&optional group)
1698 "Insert Gcc headers based on `gnus-outgoing-message-group'."
1699 (save-excursion
1700 (save-restriction
1701 (message-narrow-to-headers)
1702 (let* ((group gnus-outgoing-message-group)
1703 (gcc (cond
1704 ((functionp group)
1705 (funcall group))
1706 ((or (stringp group) (listp group))
1707 group))))
1708 (when gcc
1709 (insert "Gcc: "
1710 (if (stringp gcc)
1711 (if (string-match " " gcc)
1712 (concat "\"" gcc "\"")
1713 gcc)
1714 (mapconcat (lambda (group)
1715 (if (string-match " " group)
1716 (concat "\"" group "\"")
1717 group))
1718 gcc " "))
1719 "\n"))))))
1720
1721(defun gnus-inews-insert-archive-gcc (&optional group)
1722 "Insert the Gcc to say where the article is to be archived." 1678 "Insert the Gcc to say where the article is to be archived."
1723 (setq group (cond (group 1679 (let* ((group (or group gnus-newsgroup-name))
1724 (gnus-group-decoded-name group)) 1680 (group (when group (gnus-group-decoded-name group)))
1725 (gnus-newsgroup-name 1681 (var (or gnus-outgoing-message-group gnus-message-archive-group))
1726 (gnus-group-decoded-name gnus-newsgroup-name))
1727 (t
1728 "")))
1729 (let* ((var gnus-message-archive-group)
1730 (gcc-self-val 1682 (gcc-self-val
1731 (and gnus-newsgroup-name 1683 (and group (gnus-group-find-parameter group 'gcc-self)))
1732 (not (equal gnus-newsgroup-name ""))
1733 (gnus-group-find-parameter
1734 gnus-newsgroup-name 'gcc-self)))
1735 result 1684 result
1736 (groups 1685 (groups
1737 (cond 1686 (cond
diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el
index 2d679dab246..840e7d5a000 100644
--- a/lisp/gnus/gnus-sum.el
+++ b/lisp/gnus/gnus-sum.el
@@ -1310,7 +1310,6 @@ the normal Gnus MIME machinery."
1310(defvar gnus-article-decoded-p nil) 1310(defvar gnus-article-decoded-p nil)
1311(defvar gnus-article-charset nil) 1311(defvar gnus-article-charset nil)
1312(defvar gnus-article-ignored-charsets nil) 1312(defvar gnus-article-ignored-charsets nil)
1313(defvar gnus-article-original-subject nil)
1314(defvar gnus-scores-exclude-files nil) 1313(defvar gnus-scores-exclude-files nil)
1315(defvar gnus-page-broken nil) 1314(defvar gnus-page-broken nil)
1316 1315
@@ -1336,7 +1335,6 @@ the normal Gnus MIME machinery."
1336(defvar gnus-current-copy-group nil) 1335(defvar gnus-current-copy-group nil)
1337(defvar gnus-current-crosspost-group nil) 1336(defvar gnus-current-crosspost-group nil)
1338(defvar gnus-newsgroup-display nil) 1337(defvar gnus-newsgroup-display nil)
1339(defvar gnus-newsgroup-original-name nil)
1340 1338
1341(defvar gnus-newsgroup-dependencies nil) 1339(defvar gnus-newsgroup-dependencies nil)
1342(defvar gnus-newsgroup-adaptive nil) 1340(defvar gnus-newsgroup-adaptive nil)
@@ -1363,6 +1361,16 @@ the normal Gnus MIME machinery."
1363 (?c (or (mail-header-chars gnus-tmp-header) 0) ?d) 1361 (?c (or (mail-header-chars gnus-tmp-header) 0) ?d)
1364 (?k (gnus-summary-line-message-size gnus-tmp-header) ?s) 1362 (?k (gnus-summary-line-message-size gnus-tmp-header) ?s)
1365 (?L gnus-tmp-lines ?s) 1363 (?L gnus-tmp-lines ?s)
1364 (?Z (or ,(macroexpand-all
1365 '(nnir-article-rsv (mail-header-number gnus-tmp-header)))
1366 0) ?d)
1367 (?G (or ,(macroexpand-all
1368 '(nnir-article-group (mail-header-number gnus-tmp-header)))
1369 "") ?s)
1370 (?g (or ,(macroexpand-all
1371 '(gnus-group-short-name
1372 (nnir-article-group (mail-header-number gnus-tmp-header))))
1373 "") ?s)
1366 (?O gnus-tmp-downloaded ?c) 1374 (?O gnus-tmp-downloaded ?c)
1367 (?I gnus-tmp-indentation ?s) 1375 (?I gnus-tmp-indentation ?s)
1368 (?T (if (= gnus-tmp-level 0) "" (make-string (frame-width) ? )) ?s) 1376 (?T (if (= gnus-tmp-level 0) "" (make-string (frame-width) ? )) ?s)
@@ -1583,6 +1591,8 @@ This list will always be a subset of gnus-newsgroup-undownloaded.")
1583 gnus-newsgroup-prepared gnus-summary-highlight-line-function 1591 gnus-newsgroup-prepared gnus-summary-highlight-line-function
1584 gnus-current-article gnus-current-headers gnus-have-all-headers 1592 gnus-current-article gnus-current-headers gnus-have-all-headers
1585 gnus-last-article gnus-article-internal-prepare-hook 1593 gnus-last-article gnus-article-internal-prepare-hook
1594 (gnus-summary-article-delete-hook . global)
1595 (gnus-summary-article-move-hook . global)
1586 gnus-newsgroup-dependencies gnus-newsgroup-selected-overlay 1596 gnus-newsgroup-dependencies gnus-newsgroup-selected-overlay
1587 gnus-newsgroup-scored gnus-newsgroup-kill-headers 1597 gnus-newsgroup-scored gnus-newsgroup-kill-headers
1588 gnus-thread-expunge-below 1598 gnus-thread-expunge-below
@@ -9731,210 +9741,203 @@ ACTION can be either `move' (the default), `crosspost' or `copy'."
9731 ;; Set any marks that may have changed in the summary buffer. 9741 ;; Set any marks that may have changed in the summary buffer.
9732 (when gnus-preserve-marks 9742 (when gnus-preserve-marks
9733 (gnus-summary-push-marks-to-backend article)) 9743 (gnus-summary-push-marks-to-backend article))
9734 (let ((gnus-newsgroup-original-name gnus-newsgroup-name) 9744 (setq
9735 (gnus-article-original-subject 9745 art-group
9736 (mail-header-subject 9746 (cond
9737 (gnus-data-header (assoc article (gnus-data-list nil)))))) 9747 ;; Move the article.
9738 (setq 9748 ((eq action 'move)
9739 art-group 9749 ;; Remove this article from future suppression.
9740 (cond 9750 (gnus-dup-unsuppress-article article)
9741 ;; Move the article. 9751 (let* ((from-method (gnus-find-method-for-group
9742 ((eq action 'move) 9752 gnus-newsgroup-name))
9743 ;; Remove this article from future suppression. 9753 (to-method (or select-method
9744 (gnus-dup-unsuppress-article article) 9754 (gnus-find-method-for-group to-newsgroup)))
9745 (let* ((from-method (gnus-find-method-for-group 9755 (move-is-internal (gnus-server-equal from-method to-method)))
9746 gnus-newsgroup-name)) 9756 (gnus-request-move-article
9747 (to-method (or select-method 9757 article ; Article to move
9748 (gnus-find-method-for-group to-newsgroup))) 9758 gnus-newsgroup-name ; From newsgroup
9749 (move-is-internal (gnus-server-equal from-method to-method))) 9759 (nth 1 (gnus-find-method-for-group
9750 (gnus-request-move-article 9760 gnus-newsgroup-name)) ; Server
9751 article ; Article to move 9761 (list 'gnus-request-accept-article
9752 gnus-newsgroup-name ; From newsgroup 9762 to-newsgroup (list 'quote select-method)
9753 (nth 1 (gnus-find-method-for-group 9763 (not articles) t) ; Accept form
9754 gnus-newsgroup-name)) ; Server 9764 (not articles) ; Only save nov last time
9755 (list 'gnus-request-accept-article 9765 (and move-is-internal
9756 to-newsgroup (list 'quote select-method) 9766 to-newsgroup ; Not respooling
9757 (not articles) t) ; Accept form
9758 (not articles) ; Only save nov last time
9759 (and move-is-internal
9760 to-newsgroup ; Not respooling
9761 ; Is this move internal? 9767 ; Is this move internal?
9762 (gnus-group-real-name to-newsgroup))))) 9768 (gnus-group-real-name to-newsgroup)))))
9763 ;; Copy the article. 9769 ;; Copy the article.
9764 ((eq action 'copy) 9770 ((eq action 'copy)
9771 (with-current-buffer copy-buf
9772 (when (gnus-request-article-this-buffer article
9773 gnus-newsgroup-name)
9774 (save-restriction
9775 (nnheader-narrow-to-headers)
9776 (dolist (hdr gnus-copy-article-ignored-headers)
9777 (message-remove-header hdr t)))
9778 (gnus-request-accept-article
9779 to-newsgroup select-method (not articles) t))))
9780 ;; Crosspost the article.
9781 ((eq action 'crosspost)
9782 (let ((xref (message-tokenize-header
9783 (mail-header-xref (gnus-summary-article-header
9784 article))
9785 " ")))
9786 (setq new-xref (concat (gnus-group-real-name gnus-newsgroup-name)
9787 ":" (number-to-string article)))
9788 (unless xref
9789 (setq xref (list (system-name))))
9790 (setq new-xref
9791 (concat
9792 (mapconcat 'identity
9793 (delete "Xref:" (delete new-xref xref))
9794 " ")
9795 " " new-xref))
9765 (with-current-buffer copy-buf 9796 (with-current-buffer copy-buf
9766 (when (gnus-request-article-this-buffer article 9797 ;; First put the article in the destination group.
9767 gnus-newsgroup-name) 9798 (gnus-request-article-this-buffer article gnus-newsgroup-name)
9768 (save-restriction 9799 (when (consp (setq art-group
9769 (nnheader-narrow-to-headers) 9800 (gnus-request-accept-article
9770 (dolist (hdr gnus-copy-article-ignored-headers) 9801 to-newsgroup select-method (not articles)
9771 (message-remove-header hdr t))) 9802 t)))
9772 (gnus-request-accept-article 9803 (setq new-xref (concat new-xref " " (car art-group)
9773 to-newsgroup select-method (not articles) t)))) 9804 ":"
9774 ;; Crosspost the article. 9805 (number-to-string (cdr art-group))))
9775 ((eq action 'crosspost) 9806 ;; Now we have the new Xrefs header, so we insert
9776 (let ((xref (message-tokenize-header 9807 ;; it and replace the new article.
9777 (mail-header-xref (gnus-summary-article-header 9808 (nnheader-replace-header "Xref" new-xref)
9778 article)) 9809 (gnus-request-replace-article
9779 " "))) 9810 (cdr art-group) to-newsgroup (current-buffer) t)
9780 (setq new-xref (concat (gnus-group-real-name gnus-newsgroup-name) 9811 art-group))))))
9781 ":" (number-to-string article))) 9812 (cond
9782 (unless xref 9813 ((not art-group)
9783 (setq xref (list (system-name)))) 9814 (gnus-message 1 "Couldn't %s article %s: %s"
9784 (setq new-xref 9815 (cadr (assq action names)) article
9785 (concat 9816 (nnheader-get-report (car to-method))))
9786 (mapconcat 'identity 9817 ((eq art-group 'junk)
9787 (delete "Xref:" (delete new-xref xref)) 9818 (when (eq action 'move)
9788 " ") 9819 (gnus-summary-mark-article article gnus-canceled-mark)
9789 " " new-xref)) 9820 (gnus-message 4 "Deleted article %s" article)
9790 (with-current-buffer copy-buf 9821 ;; run the delete hook
9791 ;; First put the article in the destination group. 9822 (run-hook-with-args 'gnus-summary-article-delete-hook
9792 (gnus-request-article-this-buffer article gnus-newsgroup-name) 9823 action
9793 (when (consp (setq art-group 9824 (gnus-data-header
9794 (gnus-request-accept-article 9825 (assoc article (gnus-data-list nil)))
9795 to-newsgroup select-method (not articles) 9826 gnus-newsgroup-name nil
9796 t))) 9827 select-method)))
9797 (setq new-xref (concat new-xref " " (car art-group) 9828 (t
9798 ":" 9829 (let* ((pto-group (gnus-group-prefixed-name
9799 (number-to-string (cdr art-group)))) 9830 (car art-group) to-method))
9800 ;; Now we have the new Xrefs header, so we insert 9831 (info (gnus-get-info pto-group))
9801 ;; it and replace the new article. 9832 (to-group (gnus-info-group info))
9802 (nnheader-replace-header "Xref" new-xref) 9833 to-marks)
9803 (gnus-request-replace-article 9834 ;; Update the group that has been moved to.
9804 (cdr art-group) to-newsgroup (current-buffer) t) 9835 (when (and info
9805 art-group)))))) 9836 (memq action '(move copy)))
9806 (cond 9837 (unless (member to-group to-groups)
9807 ((not art-group) 9838 (push to-group to-groups))
9808 (gnus-message 1 "Couldn't %s article %s: %s" 9839
9809 (cadr (assq action names)) article 9840 (unless (memq article gnus-newsgroup-unreads)
9810 (nnheader-get-report (car to-method)))) 9841 (push 'read to-marks)
9811 ((eq art-group 'junk) 9842 (gnus-info-set-read
9812 (when (eq action 'move) 9843 info (gnus-add-to-range (gnus-info-read info)
9813 (gnus-summary-mark-article article gnus-canceled-mark) 9844 (list (cdr art-group)))))
9814 (gnus-message 4 "Deleted article %s" article) 9845
9815 ;; run the delete hook 9846 ;; See whether the article is to be put in the cache.
9816 (run-hook-with-args 'gnus-summary-article-delete-hook 9847 (let* ((expirable (gnus-group-auto-expirable-p to-group))
9817 action 9848 (marks (if expirable
9818 (gnus-data-header 9849 gnus-article-mark-lists
9819 (assoc article (gnus-data-list nil))) 9850 (delete '(expirable . expire)
9820 gnus-newsgroup-original-name nil 9851 (copy-sequence
9821 select-method))) 9852 gnus-article-mark-lists))))
9822 (t 9853 (to-article (cdr art-group)))
9823 (let* ((pto-group (gnus-group-prefixed-name 9854
9824 (car art-group) to-method)) 9855 ;; Enter the article into the cache in the new group,
9825 (info (gnus-get-info pto-group)) 9856 ;; if that is required.
9826 (to-group (gnus-info-group info)) 9857 (when gnus-use-cache
9827 to-marks) 9858 (gnus-cache-possibly-enter-article
9828 ;; Update the group that has been moved to. 9859 to-group to-article
9829 (when (and info 9860 (memq article gnus-newsgroup-marked)
9830 (memq action '(move copy))) 9861 (memq article gnus-newsgroup-dormant)
9831 (unless (member to-group to-groups) 9862 (memq article gnus-newsgroup-unreads)))
9832 (push to-group to-groups)) 9863
9833 9864 (when gnus-preserve-marks
9834 (unless (memq article gnus-newsgroup-unreads) 9865 ;; Copy any marks over to the new group.
9835 (push 'read to-marks) 9866 (when (and (equal to-group gnus-newsgroup-name)
9836 (gnus-info-set-read 9867 (not (memq article gnus-newsgroup-unreads)))
9837 info (gnus-add-to-range (gnus-info-read info) 9868 ;; Mark this article as read in this group.
9838 (list (cdr art-group))))) 9869 (push (cons to-article gnus-read-mark)
9839 9870 gnus-newsgroup-reads)
9840 ;; See whether the article is to be put in the cache. 9871 ;; Increase the active status of this group.
9841 (let* ((expirable (gnus-group-auto-expirable-p to-group)) 9872 (setcdr (gnus-active to-group) to-article)
9842 (marks (if expirable 9873 (setcdr gnus-newsgroup-active to-article))
9843 gnus-article-mark-lists 9874
9844 (delete '(expirable . expire) 9875 (while marks
9845 (copy-sequence 9876 (when (eq (gnus-article-mark-to-type (cdar marks)) 'list)
9846 gnus-article-mark-lists)))) 9877 (when (memq article (symbol-value
9847 (to-article (cdr art-group))) 9878 (intern (format "gnus-newsgroup-%s"
9848 9879 (caar marks)))))
9849 ;; Enter the article into the cache in the new group, 9880 (push (cdar marks) to-marks)
9850 ;; if that is required. 9881 ;; If the other group is the same as this group,
9851 (when gnus-use-cache 9882 ;; then we have to add the mark to the list.
9852 (gnus-cache-possibly-enter-article 9883 (when (equal to-group gnus-newsgroup-name)
9853 to-group to-article 9884 (set (intern (format "gnus-newsgroup-%s"
9854 (memq article gnus-newsgroup-marked) 9885 (caar marks)))
9855 (memq article gnus-newsgroup-dormant) 9886 (cons to-article
9856 (memq article gnus-newsgroup-unreads))) 9887 (symbol-value
9857 9888 (intern (format "gnus-newsgroup-%s"
9858 (when gnus-preserve-marks 9889 (caar marks)))))))
9859 ;; Copy any marks over to the new group. 9890 ;; Copy the marks to other group.
9860 (when (and (equal to-group gnus-newsgroup-name) 9891 (gnus-add-marked-articles
9861 (not (memq article gnus-newsgroup-unreads))) 9892 to-group (cdar marks) (list to-article) info)))
9862 ;; Mark this article as read in this group. 9893 (setq marks (cdr marks)))
9863 (push (cons to-article gnus-read-mark) 9894
9864 gnus-newsgroup-reads) 9895 (when (and expirable
9865 ;; Increase the active status of this group. 9896 gnus-mark-copied-or-moved-articles-as-expirable
9866 (setcdr (gnus-active to-group) to-article) 9897 (not (memq 'expire to-marks)))
9867 (setcdr gnus-newsgroup-active to-article)) 9898 ;; Mark this article as expirable.
9868 9899 (push 'expire to-marks)
9869 (while marks 9900 (when (equal to-group gnus-newsgroup-name)
9870 (when (eq (gnus-article-mark-to-type (cdar marks)) 'list) 9901 (push to-article gnus-newsgroup-expirable))
9871 (when (memq article (symbol-value 9902 ;; Copy the expirable mark to other group.
9872 (intern (format "gnus-newsgroup-%s" 9903 (gnus-add-marked-articles
9873 (caar marks))))) 9904 to-group 'expire (list to-article) info))
9874 (push (cdar marks) to-marks) 9905
9875 ;; If the other group is the same as this group, 9906 (when to-marks
9876 ;; then we have to add the mark to the list. 9907 (gnus-request-set-mark
9877 (when (equal to-group gnus-newsgroup-name) 9908 to-group (list (list (list to-article) 'add to-marks)))))
9878 (set (intern (format "gnus-newsgroup-%s" 9909
9879 (caar marks))) 9910 (gnus-dribble-enter
9880 (cons to-article 9911 (concat "(gnus-group-set-info '"
9881 (symbol-value 9912 (gnus-prin1-to-string (gnus-get-info to-group))
9882 (intern (format "gnus-newsgroup-%s" 9913 ")"))))
9883 (caar marks))))))) 9914
9884 ;; Copy the marks to other group. 9915 ;; Update the Xref header in this article to point to
9885 (gnus-add-marked-articles 9916 ;; the new crossposted article we have just created.
9886 to-group (cdar marks) (list to-article) info))) 9917 (when (eq action 'crosspost)
9887 (setq marks (cdr marks))) 9918 (with-current-buffer copy-buf
9888 9919 (gnus-request-article-this-buffer article gnus-newsgroup-name)
9889 (when (and expirable 9920 (nnheader-replace-header "Xref" new-xref)
9890 gnus-mark-copied-or-moved-articles-as-expirable 9921 (gnus-request-replace-article
9891 (not (memq 'expire to-marks))) 9922 article gnus-newsgroup-name (current-buffer) t)))
9892 ;; Mark this article as expirable. 9923
9893 (push 'expire to-marks) 9924 ;; run the move/copy/crosspost/respool hook
9894 (when (equal to-group gnus-newsgroup-name) 9925 (run-hook-with-args 'gnus-summary-article-move-hook
9895 (push to-article gnus-newsgroup-expirable)) 9926 action
9896 ;; Copy the expirable mark to other group. 9927 (gnus-data-header
9897 (gnus-add-marked-articles 9928 (assoc article (gnus-data-list nil)))
9898 to-group 'expire (list to-article) info)) 9929 gnus-newsgroup-name
9899 9930 to-newsgroup
9900 (when to-marks 9931 select-method))
9901 (gnus-request-set-mark 9932
9902 to-group (list (list (list to-article) 'add to-marks))))) 9933 ;;;!!!Why is this necessary?
9903 9934 (set-buffer gnus-summary-buffer)
9904 (gnus-dribble-enter 9935
9905 (concat "(gnus-group-set-info '" 9936 (when (eq action 'move)
9906 (gnus-prin1-to-string (gnus-get-info to-group)) 9937 (save-excursion
9907 ")")))) 9938 (gnus-summary-goto-subject article)
9908 9939 (gnus-summary-mark-article article gnus-canceled-mark)))))
9909 ;; Update the Xref header in this article to point to 9940 (push article articles-to-update-marks))
9910 ;; the new crossposted article we have just created.
9911 (when (eq action 'crosspost)
9912 (with-current-buffer copy-buf
9913 (gnus-request-article-this-buffer article gnus-newsgroup-name)
9914 (nnheader-replace-header "Xref" new-xref)
9915 (gnus-request-replace-article
9916 article gnus-newsgroup-name (current-buffer) t)))
9917
9918 ;; run the move/copy/crosspost/respool hook
9919 (let ((header (gnus-data-header
9920 (assoc article (gnus-data-list nil)))))
9921 (mail-header-set-subject header gnus-article-original-subject)
9922 (run-hook-with-args 'gnus-summary-article-move-hook
9923 action
9924 (gnus-data-header
9925 (assoc article (gnus-data-list nil)))
9926 gnus-newsgroup-original-name
9927 to-newsgroup
9928 select-method)))
9929
9930 ;;;!!!Why is this necessary?
9931 (set-buffer gnus-summary-buffer)
9932
9933 (when (eq action 'move)
9934 (save-excursion
9935 (gnus-summary-goto-subject article)
9936 (gnus-summary-mark-article article gnus-canceled-mark)))))
9937 (push article articles-to-update-marks)))
9938 9941
9939 (save-excursion 9942 (save-excursion
9940 (apply 'gnus-summary-remove-process-mark articles-to-update-marks)) 9943 (apply 'gnus-summary-remove-process-mark articles-to-update-marks))
@@ -10213,13 +10216,13 @@ confirmation before the articles are deleted."
10213 ;; The backend might not have been able to delete the article 10216 ;; The backend might not have been able to delete the article
10214 ;; after all. 10217 ;; after all.
10215 (unless (memq (car articles) not-deleted) 10218 (unless (memq (car articles) not-deleted)
10216 (gnus-summary-mark-article (car articles) gnus-canceled-mark)) 10219 (gnus-summary-mark-article (car articles) gnus-canceled-mark)
10217 (let* ((article (car articles)) 10220 (let* ((article (car articles))
10218 (ghead (gnus-data-header 10221 (ghead (gnus-data-header
10219 (assoc article (gnus-data-list nil))))) 10222 (assoc article (gnus-data-list nil)))))
10220 (run-hook-with-args 'gnus-summary-article-delete-hook 10223 (run-hook-with-args 'gnus-summary-article-delete-hook
10221 'delete ghead gnus-newsgroup-name nil 10224 'delete ghead gnus-newsgroup-name nil
10222 nil)) 10225 nil)))
10223 (setq articles (cdr articles)))) 10226 (setq articles (cdr articles))))
10224 (when not-deleted 10227 (when not-deleted
10225 (gnus-message 4 "Couldn't delete articles %s" not-deleted))) 10228 (gnus-message 4 "Couldn't delete articles %s" not-deleted)))
diff --git a/lisp/gnus/gnus-win.el b/lisp/gnus/gnus-win.el
index 809e4c339be..652d9fda94c 100644
--- a/lisp/gnus/gnus-win.el
+++ b/lisp/gnus/gnus-win.el
@@ -228,50 +228,6 @@ See the Gnus manual for an explanation of the syntax used.")
228 (pop list)) 228 (pop list))
229 (cadr (assq (car list) gnus-window-configuration))) 229 (cadr (assq (car list) gnus-window-configuration)))
230 230
231(defun gnus-windows-old-to-new (setting)
232 ;; First we take care of the really, really old Gnus 3 actions.
233 (when (symbolp setting)
234 (setq setting
235 ;; Take care of ooold GNUS 3.x values.
236 (cond ((eq setting 'SelectArticle) 'article)
237 ((memq setting '(SelectNewsgroup SelectSubject ExpandSubject))
238 'summary)
239 ((memq setting '(ExitNewsgroup)) 'group)
240 (t setting))))
241 (if (or (listp setting)
242 (not (and gnus-window-configuration
243 (memq setting '(group summary article)))))
244 setting
245 (let* ((elem
246 (cond
247 ((eq setting 'group)
248 (gnus-window-configuration-element
249 '(group newsgroups ExitNewsgroup)))
250 ((eq setting 'summary)
251 (gnus-window-configuration-element
252 '(summary SelectNewsgroup SelectSubject ExpandSubject)))
253 ((eq setting 'article)
254 (gnus-window-configuration-element
255 '(article SelectArticle)))))
256 (total (apply '+ elem))
257 (types '(group summary article))
258 (pbuf (if (eq setting 'newsgroups) 'group 'summary))
259 (i 0)
260 perc out)
261 (while (< i 3)
262 (or (not (numberp (nth i elem)))
263 (zerop (nth i elem))
264 (progn
265 (setq perc (if (= i 2)
266 1.0
267 (/ (float (nth i elem)) total)))
268 (push (if (eq pbuf (nth i types))
269 (list (nth i types) perc 'point)
270 (list (nth i types) perc))
271 out)))
272 (incf i))
273 `(vertical 1.0 ,@(nreverse out)))))
274
275;;;###autoload 231;;;###autoload
276(defun gnus-add-configuration (conf) 232(defun gnus-add-configuration (conf)
277 "Add the window configuration CONF to `gnus-buffer-configuration'." 233 "Add the window configuration CONF to `gnus-buffer-configuration'."
@@ -293,18 +249,9 @@ See the Gnus manual for an explanation of the syntax used.")
293 249
294(defun gnus-configure-frame (split &optional window) 250(defun gnus-configure-frame (split &optional window)
295 "Split WINDOW according to SPLIT." 251 "Split WINDOW according to SPLIT."
296 (let ((current-window 252 (let* ((current-window (or (get-buffer-window (current-buffer)) (selected-window)))
297 (or (get-buffer-window (current-buffer)) (selected-window)))) 253 (window (or window current-window)))
298 (unless window
299 (setq window current-window))
300 (select-window window) 254 (select-window window)
301 ;; This might be an old-style buffer config.
302 (when (vectorp split)
303 (setq split (append split nil)))
304 (when (or (consp (car split))
305 (vectorp (car split)))
306 (push 1.0 split)
307 (push 'vertical split))
308 ;; The SPLIT might be something that is to be evaled to 255 ;; The SPLIT might be something that is to be evaled to
309 ;; return a new SPLIT. 256 ;; return a new SPLIT.
310 (while (and (not (assq (car split) gnus-window-to-buffer)) 257 (while (and (not (assq (car split) gnus-window-to-buffer))
@@ -423,56 +370,55 @@ See the Gnus manual for an explanation of the syntax used.")
423 (set-window-configuration setting) 370 (set-window-configuration setting)
424 (setq gnus-current-window-configuration setting) 371 (setq gnus-current-window-configuration setting)
425 (setq force (or force gnus-always-force-window-configuration)) 372 (setq force (or force gnus-always-force-window-configuration))
426 (setq setting (gnus-windows-old-to-new setting))
427 (let ((split (if (symbolp setting) 373 (let ((split (if (symbolp setting)
428 (cadr (assq setting gnus-buffer-configuration)) 374 (cadr (assq setting gnus-buffer-configuration))
429 setting)) 375 setting))
430 all-visible) 376 all-visible)
431 377
432 (setq gnus-frame-split-p nil) 378 (setq gnus-frame-split-p nil)
433 379
434 (unless split 380 (unless split
435 (error "No such setting in `gnus-buffer-configuration': %s" setting)) 381 (error "No such setting in `gnus-buffer-configuration': %s" setting))
436 382
437 (if (and (setq all-visible (gnus-all-windows-visible-p split)) 383 (if (and (setq all-visible (gnus-all-windows-visible-p split))
438 (not force)) 384 (not force))
439 ;; All the windows mentioned are already visible, so we just 385 ;; All the windows mentioned are already visible, so we just
440 ;; put point in the assigned buffer, and do not touch the 386 ;; put point in the assigned buffer, and do not touch the
441 ;; winconf. 387 ;; winconf.
442 (select-window all-visible) 388 (select-window all-visible)
443 389
444 ;; Make sure "the other" buffer, nntp-server-buffer, is live. 390 ;; Make sure "the other" buffer, nntp-server-buffer, is live.
445 (unless (gnus-buffer-live-p nntp-server-buffer) 391 (unless (gnus-buffer-live-p nntp-server-buffer)
446 (nnheader-init-server-buffer)) 392 (nnheader-init-server-buffer))
447 393
448 ;; Either remove all windows or just remove all Gnus windows. 394 ;; Either remove all windows or just remove all Gnus windows.
449 (let ((frame (selected-frame))) 395 (let ((frame (selected-frame)))
450 (unwind-protect 396 (unwind-protect
451 (if gnus-use-full-window 397 (if gnus-use-full-window
452 ;; We want to remove all other windows. 398 ;; We want to remove all other windows.
453 (if (not gnus-frame-split-p) 399 (if (not gnus-frame-split-p)
454 ;; This is not a `frame' split, so we ignore the 400 ;; This is not a `frame' split, so we ignore the
455 ;; other frames. 401 ;; other frames.
456 (delete-other-windows) 402 (delete-other-windows)
457 ;; This is a `frame' split, so we delete all windows 403 ;; This is a `frame' split, so we delete all windows
458 ;; on all frames. 404 ;; on all frames.
459 (gnus-delete-windows-in-gnusey-frames)) 405 (gnus-delete-windows-in-gnusey-frames))
460 ;; Just remove some windows. 406 ;; Just remove some windows.
461 (gnus-remove-some-windows) 407 (gnus-remove-some-windows)
462 (if (featurep 'xemacs) 408 (if (featurep 'xemacs)
463 (switch-to-buffer nntp-server-buffer) 409 (switch-to-buffer nntp-server-buffer)
464 (set-buffer nntp-server-buffer))) 410 (set-buffer nntp-server-buffer)))
465 (select-frame frame))) 411 (select-frame frame)))
466 412
467 (let (gnus-window-frame-focus) 413 (let (gnus-window-frame-focus)
468 (if (featurep 'xemacs) 414 (if (featurep 'xemacs)
469 (switch-to-buffer nntp-server-buffer) 415 (switch-to-buffer nntp-server-buffer)
470 (set-buffer nntp-server-buffer)) 416 (set-buffer nntp-server-buffer))
471 (gnus-configure-frame split) 417 (gnus-configure-frame split)
472 (run-hooks 'gnus-configure-windows-hook) 418 (run-hooks 'gnus-configure-windows-hook)
473 (when gnus-window-frame-focus 419 (when gnus-window-frame-focus
474 (gnus-select-frame-set-input-focus 420 (gnus-select-frame-set-input-focus
475 (window-frame gnus-window-frame-focus)))))))) 421 (window-frame gnus-window-frame-focus))))))))
476 422
477(defun gnus-delete-windows-in-gnusey-frames () 423(defun gnus-delete-windows-in-gnusey-frames ()
478 "Do a `delete-other-windows' in all frames that have Gnus windows." 424 "Do a `delete-other-windows' in all frames that have Gnus windows."
diff --git a/lisp/gnus/gnus.el b/lisp/gnus/gnus.el
index 20ce72d8855..d32ecac5dc3 100644
--- a/lisp/gnus/gnus.el
+++ b/lisp/gnus/gnus.el
@@ -1401,10 +1401,6 @@ no need to set this variable."
1401 string)) 1401 string))
1402(make-obsolete-variable 'gnus-local-domain nil "Emacs 24.1") 1402(make-obsolete-variable 'gnus-local-domain nil "Emacs 24.1")
1403 1403
1404(defvar gnus-local-organization nil
1405 "String with a description of what organization (if any) the user belongs to.
1406Obsolete variable; use `message-user-organization' instead.")
1407
1408;; Customization variables 1404;; Customization variables
1409 1405
1410(defcustom gnus-refer-article-method 'current 1406(defcustom gnus-refer-article-method 'current
diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el
index 1ee07a2d5ee..feb5102055c 100644
--- a/lisp/gnus/message.el
+++ b/lisp/gnus/message.el
@@ -160,8 +160,12 @@ If this variable is nil, no such courtesy message will be added."
160 :group 'message-interface 160 :group 'message-interface
161 :type 'regexp) 161 :type 'regexp)
162 162
163(defcustom message-from-style mail-from-style 163(defcustom message-from-style 'default
164 "*Specifies how \"From\" headers look. 164 ;; In Emacs 24.1 this defaults to the value of `mail-from-style'
165 ;; that defaults to:
166 ;; `angles' in Emacs 22.1~23.1, XEmacs 21.4, 21.5, and SXEmacs 22.1;
167 ;; `system-default' in Emacs 23.2, and 24.1
168 "Specifies how \"From\" headers look.
165 169
166If nil, they contain just the return address like: 170If nil, they contain just the return address like:
167 king@grassland.com 171 king@grassland.com
@@ -507,14 +511,9 @@ This is used by `message-kill-buffer'."
507 :group 'message-buffers 511 :group 'message-buffers
508 :type 'boolean) 512 :type 'boolean)
509 513
510(defvar gnus-local-organization)
511(defcustom message-user-organization 514(defcustom message-user-organization
512 (or (and (boundp 'gnus-local-organization) 515 (or (getenv "ORGANIZATION") t)
513 (stringp gnus-local-organization) 516 "String to be used as an Organization header.
514 gnus-local-organization)
515 (getenv "ORGANIZATION")
516 t)
517 "*String to be used as an Organization header.
518If t, use `message-user-organization-file'." 517If t, use `message-user-organization-file'."
519 :group 'message-headers 518 :group 'message-headers
520 :type '(choice string 519 :type '(choice string
diff --git a/lisp/gnus/mm-util.el b/lisp/gnus/mm-util.el
index 700c1a6bb64..2f6464d43f2 100644
--- a/lisp/gnus/mm-util.el
+++ b/lisp/gnus/mm-util.el
@@ -974,6 +974,7 @@ If the charset is `composition', return the actual one."
974 ;; This is for XEmacs. 974 ;; This is for XEmacs.
975 (mm-mule-charset-to-mime-charset charset))) 975 (mm-mule-charset-to-mime-charset charset)))
976 976
977;; `delete-dups' is not available in XEmacs 21.4.
977(if (fboundp 'delete-dups) 978(if (fboundp 'delete-dups)
978 (defalias 'mm-delete-duplicates 'delete-dups) 979 (defalias 'mm-delete-duplicates 'delete-dups)
979 (defun mm-delete-duplicates (list) 980 (defun mm-delete-duplicates (list)
diff --git a/lisp/gnus/nnimap.el b/lisp/gnus/nnimap.el
index cb4c9f0108c..a53f9ac468d 100644
--- a/lisp/gnus/nnimap.el
+++ b/lisp/gnus/nnimap.el
@@ -45,6 +45,7 @@
45(require 'tls) 45(require 'tls)
46(require 'parse-time) 46(require 'parse-time)
47(require 'nnmail) 47(require 'nnmail)
48(require 'proto-stream)
48 49
49(eval-when-compile 50(eval-when-compile
50 (require 'gnus-sum)) 51 (require 'gnus-sum))
@@ -62,9 +63,10 @@
62If nnimap-stream is `ssl', this will default to `imaps'. If not, 63If nnimap-stream is `ssl', this will default to `imaps'. If not,
63it will default to `imap'.") 64it will default to `imap'.")
64 65
65(defvoo nnimap-stream 'ssl 66(defvoo nnimap-stream 'undecided
66 "How nnimap will talk to the IMAP server. 67 "How nnimap will talk to the IMAP server.
67Values are `ssl', `network', `starttls' or `shell'.") 68Values are `ssl', `network', `starttls' or `shell'.
69The default is to try `ssl' first, and then `network'.")
68 70
69(defvoo nnimap-shell-program (if (boundp 'imap-shell-program) 71(defvoo nnimap-shell-program (if (boundp 'imap-shell-program)
70 (if (listp imap-shell-program) 72 (if (listp imap-shell-program)
@@ -271,16 +273,6 @@ textual parts.")
271 (push (current-buffer) nnimap-process-buffers) 273 (push (current-buffer) nnimap-process-buffers)
272 (current-buffer))) 274 (current-buffer)))
273 275
274(defun nnimap-open-shell-stream (name buffer host port)
275 (let ((process-connection-type nil))
276 (start-process name buffer shell-file-name
277 shell-command-switch
278 (format-spec
279 nnimap-shell-program
280 (format-spec-make
281 ?s host
282 ?p port)))))
283
284(defun nnimap-credentials (address ports &optional inhibit-create) 276(defun nnimap-credentials (address ports &optional inhibit-create)
285 (let (port credentials) 277 (let (port credentials)
286 ;; Request the credentials from all ports, but only query on the 278 ;; Request the credentials from all ports, but only query on the
@@ -310,111 +302,79 @@ textual parts.")
310 (* 5 60))) 302 (* 5 60)))
311 (nnimap-send-command "NOOP"))))))) 303 (nnimap-send-command "NOOP")))))))
312 304
313(declare-function gnutls-negotiate "gnutls"
314 (proc type &optional priority-string trustfiles keyfiles))
315
316(defun nnimap-open-connection (buffer) 305(defun nnimap-open-connection (buffer)
306 ;; Be backwards-compatible -- the earlier value of nnimap-stream was
307 ;; `ssl' when nnimap-server-port was nil. Sort of.
308 (when (and nnimap-server-port
309 (eq nnimap-stream 'undecided))
310 (setq nnimap-stream 'ssl))
311 (let ((stream
312 (if (eq nnimap-stream 'undecided)
313 (loop for type in '(ssl network)
314 for stream = (let ((nnimap-stream type))
315 (nnimap-open-connection-1 buffer))
316 while (eq stream 'no-connect)
317 finally (return stream))
318 (nnimap-open-connection-1 buffer))))
319 (if (eq stream 'no-connect)
320 nil
321 stream)))
322
323(defun nnimap-open-connection-1 (buffer)
317 (unless nnimap-keepalive-timer 324 (unless nnimap-keepalive-timer
318 (setq nnimap-keepalive-timer (run-at-time (* 60 15) (* 60 15) 325 (setq nnimap-keepalive-timer (run-at-time (* 60 15) (* 60 15)
319 'nnimap-keepalive))) 326 'nnimap-keepalive)))
320 (block nil 327 (with-current-buffer (nnimap-make-process-buffer buffer)
321 (with-current-buffer (nnimap-make-process-buffer buffer) 328 (let* ((coding-system-for-read 'binary)
322 (let* ((coding-system-for-read 'binary) 329 (coding-system-for-write 'binary)
323 (coding-system-for-write 'binary) 330 (port nil)
324 (port nil) 331 (ports
325 (ports
326 (cond
327 ((or (eq nnimap-stream 'network)
328 (and (eq nnimap-stream 'starttls)
329 (fboundp 'open-gnutls-stream)))
330 (nnheader-message 7 "Opening connection to %s..."
331 nnimap-address)
332 (open-network-stream
333 "*nnimap*" (current-buffer) nnimap-address
334 (setq port
335 (or nnimap-server-port
336 (if (netrc-find-service-number "imap")
337 "imap"
338 "143"))))
339 '("143" "imap"))
340 ((eq nnimap-stream 'shell)
341 (nnheader-message 7 "Opening connection to %s via shell..."
342 nnimap-address)
343 (nnimap-open-shell-stream
344 "*nnimap*" (current-buffer) nnimap-address
345 (setq port (or nnimap-server-port "imap")))
346 '("imap"))
347 ((eq nnimap-stream 'starttls)
348 (nnheader-message 7 "Opening connection to %s via starttls..."
349 nnimap-address)
350 (let ((tls-program
351 '("openssl s_client -connect %h:%p -no_ssl2 -ign_eof -starttls imap")))
352 (open-tls-stream
353 "*nnimap*" (current-buffer) nnimap-address
354 (setq port (or nnimap-server-port "imap"))))
355 '("imap"))
356 ((memq nnimap-stream '(ssl tls))
357 (nnheader-message 7 "Opening connection to %s via tls..."
358 nnimap-address)
359 (funcall (if (fboundp 'open-gnutls-stream)
360 'open-gnutls-stream
361 'open-tls-stream)
362 "*nnimap*" (current-buffer) nnimap-address
363 (setq port
364 (or nnimap-server-port
365 (if (netrc-find-service-number "imaps")
366 "imaps"
367 "993"))))
368 '("143" "993" "imap" "imaps"))
369 (t
370 (error "Unknown stream type: %s" nnimap-stream))))
371 connection-result login-result credentials)
372 (setf (nnimap-process nnimap-object)
373 (get-buffer-process (current-buffer)))
374 (if (not (and (nnimap-process nnimap-object)
375 (memq (process-status (nnimap-process nnimap-object))
376 '(open run))))
377 (nnheader-report 'nnimap "Unable to contact %s:%s via %s"
378 nnimap-address port nnimap-stream)
379 (gnus-set-process-query-on-exit-flag
380 (nnimap-process nnimap-object) nil)
381 (if (not (setq connection-result (nnimap-wait-for-connection)))
382 (nnheader-report 'nnimap
383 "%s" (buffer-substring
384 (point) (line-end-position)))
385 ;; Store the greeting (for debugging purposes).
386 (setf (nnimap-greeting nnimap-object)
387 (buffer-substring (line-beginning-position)
388 (line-end-position)))
389 (nnimap-get-capabilities)
390 (when nnimap-server-port
391 (push (format "%s" nnimap-server-port) ports))
392 ;; If this is a STARTTLS-capable server, then sever the
393 ;; connection and start a STARTTLS connection instead.
394 (cond 332 (cond
395 ((and (or (and (eq nnimap-stream 'network) 333 ((or (eq nnimap-stream 'network)
396 (nnimap-capability "STARTTLS")) 334 (eq nnimap-stream 'starttls))
397 (eq nnimap-stream 'starttls)) 335 (nnheader-message 7 "Opening connection to %s..."
398 (fboundp 'open-gnutls-stream)) 336 nnimap-address)
399 (nnimap-command "STARTTLS") 337 '("143" "imap"))
400 (gnutls-negotiate (nnimap-process nnimap-object) nil) 338 ((eq nnimap-stream 'shell)
401 ;; Get the capabilities again -- they may have changed 339 (nnheader-message 7 "Opening connection to %s via shell..."
402 ;; after doing STARTTLS. 340 nnimap-address)
403 (nnimap-get-capabilities)) 341 '("imap"))
404 ((and (eq nnimap-stream 'network) 342 ((memq nnimap-stream '(ssl tls))
405 (nnimap-capability "STARTTLS")) 343 (nnheader-message 7 "Opening connection to %s via tls..."
406 (let ((nnimap-stream 'starttls)) 344 nnimap-address)
407 (let ((tls-process 345 '("143" "993" "imap" "imaps"))
408 (nnimap-open-connection buffer))) 346 (t
409 ;; If the STARTTLS connection was successful, we 347 (error "Unknown stream type: %s" nnimap-stream))))
410 ;; kill our first non-encrypted connection. If it 348 (proto-stream-always-use-starttls t)
411 ;; wasn't successful, we just use our unencrypted 349 login-result credentials)
412 ;; connection. 350 (when nnimap-server-port
413 (when (memq (process-status tls-process) '(open run)) 351 (setq ports (append ports (list nnimap-server-port))))
414 (delete-process (nnimap-process nnimap-object)) 352 (destructuring-bind (stream greeting capabilities)
415 (kill-buffer (current-buffer)) 353 (open-protocol-stream
416 (return tls-process)))))) 354 "*nnimap*" (current-buffer) nnimap-address (car (last ports))
417 (unless (equal connection-result "PREAUTH") 355 :type nnimap-stream
356 :shell-command nnimap-shell-program
357 :capability-command "1 CAPABILITY\r\n"
358 :success " OK "
359 :starttls-function
360 (lambda (capabilities)
361 (when (gnus-string-match-p "STARTTLS" capabilities)
362 "1 STARTTLS\r\n")))
363 (setf (nnimap-process nnimap-object) stream)
364 (if (not stream)
365 (progn
366 (nnheader-report 'nnimap "Unable to contact %s:%s via %s"
367 nnimap-address port nnimap-stream)
368 'no-connect)
369 (gnus-set-process-query-on-exit-flag stream nil)
370 (if (not (gnus-string-match-p "[*.] \\(OK\\|PREAUTH\\)" greeting))
371 (nnheader-report 'nnimap "%s" greeting)
372 ;; Store the greeting (for debugging purposes).
373 (setf (nnimap-greeting nnimap-object) greeting)
374 (setf (nnimap-capabilities nnimap-object)
375 (mapcar #'upcase
376 (split-string capabilities)))
377 (unless (gnus-string-match-p "[*.] PREAUTH" greeting)
418 (if (not (setq credentials 378 (if (not (setq credentials
419 (if (eq nnimap-authenticator 'anonymous) 379 (if (eq nnimap-authenticator 'anonymous)
420 (list "anonymous" 380 (list "anonymous"
@@ -456,13 +416,6 @@ textual parts.")
456 (nnimap-command "ENABLE QRESYNC")) 416 (nnimap-command "ENABLE QRESYNC"))
457 (nnimap-process nnimap-object)))))))) 417 (nnimap-process nnimap-object))))))))
458 418
459(defun nnimap-get-capabilities ()
460 (setf (nnimap-capabilities nnimap-object)
461 (mapcar
462 #'upcase
463 (nnimap-find-parameter
464 "CAPABILITY" (cdr (nnimap-command "CAPABILITY"))))))
465
466(defun nnimap-quote-specials (string) 419(defun nnimap-quote-specials (string)
467 (with-temp-buffer 420 (with-temp-buffer
468 (insert string) 421 (insert string)
@@ -1110,7 +1063,7 @@ textual parts.")
1110 uidvalidity 1063 uidvalidity
1111 modseq) 1064 modseq)
1112 (push 1065 (push
1113 (list (nnimap-send-command "EXAMINE %S (QRESYNC (%s %s))" 1066 (list (nnimap-send-command "EXAMINE %S (QRESYNC (%s %s))"
1114 (utf7-encode group t) 1067 (utf7-encode group t)
1115 uidvalidity modseq) 1068 uidvalidity modseq)
1116 'qresync 1069 'qresync
diff --git a/lisp/gnus/nnir.el b/lisp/gnus/nnir.el
index e5ba3c60620..889d6ff7da5 100644
--- a/lisp/gnus/nnir.el
+++ b/lisp/gnus/nnir.el
@@ -42,7 +42,7 @@
42 42
43;; When looking at the retrieval result (in the Summary buffer) you 43;; When looking at the retrieval result (in the Summary buffer) you
44;; can type `A W' (aka M-x gnus-warp-to-article RET) on an article. You 44;; can type `A W' (aka M-x gnus-warp-to-article RET) on an article. You
45;; will be warped into the group this article came from. Typing `A W' 45;; will be warped into the group this article came from. Typing `A T'
46;; (aka M-x gnus-summary-refer-thread RET) will warp to the group and 46;; (aka M-x gnus-summary-refer-thread RET) will warp to the group and
47;; also show the thread this article is part of. 47;; also show the thread this article is part of.
48 48
@@ -181,7 +181,8 @@
181(eval-when-compile 181(eval-when-compile
182 (autoload 'nnimap-buffer "nnimap") 182 (autoload 'nnimap-buffer "nnimap")
183 (autoload 'nnimap-command "nnimap") 183 (autoload 'nnimap-command "nnimap")
184 (autoload 'nnimap-possibly-change-group "nnimap")) 184 (autoload 'nnimap-possibly-change-group "nnimap")
185 (autoload 'gnus-registry-action "gnus-registry"))
185 186
186(nnoo-declare nnir) 187(nnoo-declare nnir)
187(nnoo-define-basics nnir) 188(nnoo-define-basics nnir)
@@ -198,14 +199,34 @@
198(defcustom nnir-method-default-engines 199(defcustom nnir-method-default-engines
199 '((nnimap . imap) 200 '((nnimap . imap)
200 (nntp . gmane)) 201 (nntp . gmane))
201 "*Alist of default search engines keyed by server method" 202 "*Alist of default search engines keyed by server method."
202 :type '(alist) 203 :type '(alist)
203 :group 'nnir) 204 :group 'nnir)
204 205
206(defcustom nnir-ignored-newsgroups ""
207 "*A regexp to match newsgroups in the active file that should
208 be skipped when searching."
209 :type '(regexp)
210 :group 'nnir)
211
212(defcustom nnir-summary-line-format nil
213 "*The format specification of the lines in an nnir summary buffer.
214
215All the items from `gnus-summary-line-format' are available, along
216with three items unique to nnir summary buffers:
217
218%Z Search retrieval score value (integer)
219%G Article original full group name (string)
220%g Article original short group name (string)
221
222If nil this will use `gnus-summary-line-format'."
223 :type '(regexp)
224 :group 'nnir)
225
205(defcustom nnir-imap-default-search-key "Whole message" 226(defcustom nnir-imap-default-search-key "Whole message"
206 "*The default IMAP search key for an nnir search. Must be one of 227 "*The default IMAP search key for an nnir search. Must be one of
207 the keys in `nnir-imap-search-arguments'. To use raw imap queries 228 the keys in `nnir-imap-search-arguments'. To use raw imap queries
208 by default set this to \"Imap\"" 229 by default set this to \"Imap\"."
209 :type '(string) 230 :type '(string)
210 :group 'nnir) 231 :group 'nnir)
211 232
@@ -423,9 +444,11 @@ needs the variables `nnir-namazu-program',
423 444
424Add an entry here when adding a new search engine.") 445Add an entry here when adding a new search engine.")
425 446
426(defvar nnir-get-article-nov-override-function nil 447(defvar nnir-retrieve-headers-override-function nil
427 "If non-nil, a function that will be passed each search result. This 448 "If non-nil, a function that accepts an article list and group
428should return a message's headers in NOV format. 449and populates the `nntp-server-buffer' with the retrieved
450headers. Must return either 'nov or 'headers indicating the
451retrieved header format.
429 452
430If this variable is nil, or if the provided function returns nil for a search 453If this variable is nil, or if the provided function returns nil for a search
431result, `gnus-retrieve-headers' will be called instead.") 454result, `gnus-retrieve-headers' will be called instead.")
@@ -455,6 +478,68 @@ result, `gnus-retrieve-headers' will be called instead.")
455 478
456;;; Code: 479;;; Code:
457 480
481;;; Helper macros
482
483;; Data type article list.
484
485(defmacro nnir-artlist-length (artlist)
486 "Returns number of articles in artlist."
487 `(length ,artlist))
488
489(defmacro nnir-artlist-article (artlist n)
490 "Returns from ARTLIST the Nth artitem (counting starting at 1)."
491 `(when (> ,n 0)
492 (elt ,artlist (1- ,n))))
493
494(defmacro nnir-artitem-group (artitem)
495 "Returns the group from the ARTITEM."
496 `(elt ,artitem 0))
497
498(defmacro nnir-artitem-number (artitem)
499 "Returns the number from the ARTITEM."
500 `(elt ,artitem 1))
501
502(defmacro nnir-artitem-rsv (artitem)
503 "Returns the Retrieval Status Value (RSV, score) from the ARTITEM."
504 `(elt ,artitem 2))
505
506(defmacro nnir-article-group (article)
507 "Returns the group for ARTICLE"
508 `(nnir-artitem-group (nnir-artlist-article nnir-artlist ,article)))
509
510(defmacro nnir-article-number (article)
511 "Returns the number for ARTICLE"
512 `(nnir-artitem-number (nnir-artlist-article nnir-artlist ,article)))
513
514(defmacro nnir-article-rsv (article)
515 "Returns the rsv for ARTICLE"
516 `(nnir-artitem-rsv (nnir-artlist-article nnir-artlist ,article)))
517
518(defsubst nnir-article-ids (article)
519 "Returns the pair `(nnir id . real id)' of ARTICLE"
520 (cons article (nnir-article-number article)))
521
522(defmacro nnir-categorize (sequence keyfunc &optional valuefunc)
523 "Sorts a sequence into categories and returns a list of the form
524`((key1 (element11 element12)) (key2 (element21 element22))'.
525The category key for a member of the sequence is obtained
526as `(keyfunc member)' and the corresponding element is just
527`member'. If `valuefunc' is non-nil, the element of the list
528is `(valuefunc member)'."
529 `(unless (null ,sequence)
530 (let (value)
531 (mapcar
532 (lambda (member)
533 (let ((y (,keyfunc member))
534 (x ,(if valuefunc
535 `(,valuefunc member)
536 'member)))
537 (if (assoc y value)
538 (push x (cadr (assoc y value)))
539 (push (list y (list x)) value))))
540 ,sequence)
541 value)))
542
458;; Gnus glue. 543;; Gnus glue.
459 544
460(defun gnus-group-make-nnir-group (nnir-extra-parms) 545(defun gnus-group-make-nnir-group (nnir-extra-parms)
@@ -479,6 +564,7 @@ result, `gnus-retrieve-headers' will be called instead.")
479 564
480(deffoo nnir-open-server (server &optional definitions) 565(deffoo nnir-open-server (server &optional definitions)
481 ;; Just set the server variables appropriately. 566 ;; Just set the server variables appropriately.
567 (add-hook 'gnus-summary-mode-hook 'nnir-mode)
482 (nnoo-change-server 'nnir server definitions)) 568 (nnoo-change-server 'nnir server definitions))
483 569
484(deffoo nnir-request-group (group &optional server fast info) 570(deffoo nnir-request-group (group &optional server fast info)
@@ -506,77 +592,76 @@ result, `gnus-retrieve-headers' will be called instead.")
506 group)))) ; group name 592 group)))) ; group name
507 593
508(deffoo nnir-retrieve-headers (articles &optional group server fetch-old) 594(deffoo nnir-retrieve-headers (articles &optional group server fetch-old)
509 (save-excursion 595 (with-current-buffer nntp-server-buffer
510 (let ((artlist (copy-sequence articles)) 596 (let ((gnus-inhibit-demon t)
511 art artitem artgroup artno artrsv artfullgroup 597 (articles-by-group (nnir-categorize
512 novitem novdata foo server) 598 articles nnir-article-group nnir-article-ids))
513 (while (not (null artlist)) 599 headers)
514 (setq art (car artlist)) 600 (while (not (null articles-by-group))
515 (or (numberp art) 601 (let* ((group-articles (pop articles-by-group))
516 (nnheader-report 602 (artgroup (car group-articles))
517 'nnir 603 (articleids (cadr group-articles))
518 "nnir-retrieve-headers doesn't grok message ids: %s" 604 (artlist (sort (mapcar 'cdr articleids) '<))
519 art)) 605 (server (gnus-group-server artgroup))
520 (setq artitem (nnir-artlist-article nnir-artlist art)) 606 (gnus-override-method (gnus-server-to-method server))
521 (setq artrsv (nnir-artitem-rsv artitem)) 607 parsefunc)
522 (setq artfullgroup (nnir-artitem-group artitem)) 608 ;; (or (numberp art)
523 (setq artno (nnir-artitem-number artitem)) 609 ;; (nnheader-report
524 (setq artgroup (gnus-group-real-name artfullgroup)) 610 ;; 'nnir
525 (setq server (gnus-group-server artfullgroup)) 611 ;; "nnir-retrieve-headers doesn't grok message ids: %s"
526 ;; retrieve NOV or HEAD data for this article, transform into 612 ;; art))
527 ;; NOV data and prepend to `novdata' 613 (nnir-possibly-change-server server)
528 (set-buffer nntp-server-buffer) 614 ;; is this needed?
529 (nnir-possibly-change-server server) 615 (erase-buffer)
530 (let ((gnus-override-method 616 (case (setq gnus-headers-retrieved-by
531 (gnus-server-to-method server))) 617 (or
532 ;; if nnir-get-article-nov-override-function is set, use it 618 (and
533 (if nnir-get-article-nov-override-function 619 nnir-retrieve-headers-override-function
534 (setq novitem (funcall nnir-get-article-nov-override-function 620 (funcall nnir-retrieve-headers-override-function
535 artitem)) 621 artlist artgroup))
536 ;; else, set novitem through nnheader-parse-nov/nnheader-parse-head 622 (gnus-retrieve-headers artlist artgroup nil)))
537 (case (setq foo (gnus-retrieve-headers (list artno) 623 (nov
538 artfullgroup nil)) 624 (setq parsefunc 'nnheader-parse-nov))
539 (nov 625 (headers
540 (goto-char (point-min)) 626 (setq parsefunc 'nnheader-parse-head))
541 (setq novitem (nnheader-parse-nov))) 627 (t (error "Unknown header type %s while requesting articles \
542 (headers 628 of group %s" gnus-headers-retrieved-by artgroup)))
543 (goto-char (point-min)) 629 (goto-char (point-min))
544 (setq novitem (nnheader-parse-head))) 630 (while (not (eobp))
545 (t (error "Unknown header type %s while requesting article %s of group %s" 631 (let* ((novitem (funcall parsefunc))
546 foo artno artfullgroup))))) 632 (artno (mail-header-number novitem))
547 ;; replace article number in original group with article number 633 (art (car (rassoc artno articleids))))
548 ;; in nnir group 634 (when art
549 (when novitem 635 (mail-header-set-number novitem art)
550 (mail-header-set-number novitem art) 636 ;; (mail-header-set-subject
551 (mail-header-set-subject 637 ;; novitem
552 novitem 638 ;; (format "[%d: %s/%d] %s"
553 (format "[%d: %s/%d] %s" 639 ;; (nnir-article-rsv art) artgroup artno
554 artrsv artgroup artno 640 ;; (mail-header-subject novitem)))
555 (mail-header-subject novitem))) 641 (push novitem headers))
556 (push novitem novdata) 642 (forward-line 1)))))
557 (setq artlist (cdr artlist)))) 643 (setq headers
558 (setq novdata (nreverse novdata)) 644 (sort headers
559 (set-buffer nntp-server-buffer) (erase-buffer) 645 (lambda (x y)
560 (mapc 'nnheader-insert-nov novdata) 646 (< (mail-header-number x) (mail-header-number y)))))
647 (erase-buffer)
648 (mapc 'nnheader-insert-nov headers)
561 'nov))) 649 'nov)))
562 650
563(deffoo nnir-request-article (article 651(deffoo nnir-request-article (article &optional group server to-buffer)
564 &optional group server to-buffer)
565 (if (stringp article) 652 (if (stringp article)
566 (nnheader-report 653 (nnheader-report
567 'nnir 654 'nnir
568 "nnir-retrieve-headers doesn't grok message ids: %s" 655 "nnir-retrieve-headers doesn't grok message ids: %s"
569 article) 656 article)
570 (save-excursion 657 (save-excursion
571 (let* ((artitem (nnir-artlist-article nnir-artlist 658 (let ((artfullgroup (nnir-article-group article))
572 article)) 659 (artno (nnir-article-number article))
573 (artfullgroup (nnir-artitem-group artitem)) 660 ;; Bug?
574 (artno (nnir-artitem-number artitem)) 661 ;; Why must we bind nntp-server-buffer here? It won't
575 ;; Bug? 662 ;; work if `buf' is used, say. (Of course, the set-buffer
576 ;; Why must we bind nntp-server-buffer here? It won't 663 ;; line below must then be updated, too.)
577 ;; work if `buf' is used, say. (Of course, the set-buffer 664 (nntp-server-buffer (or to-buffer nntp-server-buffer)))
578 ;; line below must then be updated, too.)
579 (nntp-server-buffer (or to-buffer nntp-server-buffer)))
580 (set-buffer nntp-server-buffer) 665 (set-buffer nntp-server-buffer)
581 (erase-buffer) 666 (erase-buffer)
582 (message "Requesting article %d from group %s" 667 (message "Requesting article %d from group %s"
@@ -586,10 +671,8 @@ result, `gnus-retrieve-headers' will be called instead.")
586 671
587(deffoo nnir-request-move-article (article group server accept-form 672(deffoo nnir-request-move-article (article group server accept-form
588 &optional last internal-move-group) 673 &optional last internal-move-group)
589 (let* ((artitem (nnir-artlist-article nnir-artlist 674 (let* ((artfullgroup (nnir-article-group article))
590 article)) 675 (artno (nnir-article-number article))
591 (artfullgroup (nnir-artitem-group artitem))
592 (artno (nnir-artitem-number artitem))
593 (to-newsgroup (nth 1 accept-form)) 676 (to-newsgroup (nth 1 accept-form))
594 (to-method (gnus-find-method-for-group to-newsgroup)) 677 (to-method (gnus-find-method-for-group to-newsgroup))
595 (from-method (gnus-find-method-for-group artfullgroup)) 678 (from-method (gnus-find-method-for-group artfullgroup))
@@ -597,9 +680,9 @@ result, `gnus-retrieve-headers' will be called instead.")
597 (artsubject (mail-header-subject 680 (artsubject (mail-header-subject
598 (gnus-data-header 681 (gnus-data-header
599 (assoc article (gnus-data-list nil)))))) 682 (assoc article (gnus-data-list nil))))))
600 (setq gnus-newsgroup-original-name artfullgroup) 683 (unless (gnus-check-backend-function
601 (string-match "^\\[[0-9]+:.+/[0-9]+\\] " artsubject) 684 'request-move-article artfullgroup)
602 (setq gnus-article-original-subject (substring artsubject (match-end 0))) 685 (error "The group %s does not support article moving" artfullgroup))
603 (gnus-request-move-article 686 (gnus-request-move-article
604 artno 687 artno
605 artfullgroup 688 artfullgroup
@@ -614,8 +697,8 @@ result, `gnus-retrieve-headers' will be called instead.")
614 (let* ((cur (if (> (gnus-summary-article-number) 0) 697 (let* ((cur (if (> (gnus-summary-article-number) 0)
615 (gnus-summary-article-number) 698 (gnus-summary-article-number)
616 (error "This is not a real article."))) 699 (error "This is not a real article.")))
617 (gnus-newsgroup-name (nnir-artlist-artitem-group nnir-artlist cur)) 700 (gnus-newsgroup-name (nnir-article-group cur))
618 (backend-number (nnir-artlist-artitem-number nnir-artlist cur))) 701 (backend-number (nnir-article-number cur)))
619 (gnus-summary-read-group-1 gnus-newsgroup-name t t gnus-summary-buffer 702 (gnus-summary-read-group-1 gnus-newsgroup-name t t gnus-summary-buffer
620 nil (list backend-number)))) 703 nil (list backend-number))))
621 704
@@ -654,7 +737,7 @@ ready to be added to the list of search results."
654 (gnus-replace-in-string dirnam "^[./\\]" "" t) 737 (gnus-replace-in-string dirnam "^[./\\]" "" t)
655 "[/\\]" "." t))) 738 "[/\\]" "." t)))
656 739
657 (vector (nnir-group-full-name group server) 740 (vector (gnus-group-full-name group server)
658 (if (string= (gnus-group-server server) "nnmaildir") 741 (if (string= (gnus-group-server server) "nnmaildir")
659 (nnmaildir-base-name-to-article-number 742 (nnmaildir-base-name-to-article-number
660 (substring article 0 (string-match ":" article)) 743 (substring article 0 (string-match ":" article))
@@ -696,7 +779,7 @@ details on the language and supported extensions"
696 (nnir-imap-make-query 779 (nnir-imap-make-query
697 criteria qstring))))) 780 criteria qstring)))))
698 (mapc 781 (mapc
699 (lambda (artnum) (push (vector group artnum 1) artlist) 782 (lambda (artnum) (push (vector group artnum 100) artlist)
700 (setq arts (1+ arts))) 783 (setq arts (1+ arts)))
701 (and (car result) 784 (and (car result)
702 (delete 0 (mapcar #'string-to-number 785 (delete 0 (mapcar #'string-to-number
@@ -1056,7 +1139,7 @@ Tested with swish-e-2.0.1 on Windows NT 4.0."
1056 ;; Windows "\\" -> "." 1139 ;; Windows "\\" -> "."
1057 (setq group (gnus-replace-in-string group "\\\\" ".")) 1140 (setq group (gnus-replace-in-string group "\\\\" "."))
1058 1141
1059 (push (vector (nnir-group-full-name group server) 1142 (push (vector (gnus-group-full-name group server)
1060 (string-to-number artno) 1143 (string-to-number artno)
1061 (string-to-number score)) 1144 (string-to-number score))
1062 artlist)))) 1145 artlist))))
@@ -1125,7 +1208,7 @@ Tested with swish-e-2.0.1 on Windows NT 4.0."
1125 score (match-string 3)) 1208 score (match-string 3))
1126 (when (string-match prefix dirnam) 1209 (when (string-match prefix dirnam)
1127 (setq dirnam (replace-match "" t t dirnam))) 1210 (setq dirnam (replace-match "" t t dirnam)))
1128 (push (vector (nnir-group-full-name 1211 (push (vector (gnus-group-full-name
1129 (gnus-replace-in-string dirnam "/" ".") server) 1212 (gnus-replace-in-string dirnam "/" ".") server)
1130 (string-to-number artno) 1213 (string-to-number artno)
1131 (string-to-number score)) 1214 (string-to-number score))
@@ -1218,6 +1301,7 @@ Tested with Namazu 2.0.6 on a GNU/Linux system."
1218 (directory (cadr (assoc sym (cddr method)))) 1301 (directory (cadr (assoc sym (cddr method))))
1219 (regexp (cdr (assoc 'query query))) 1302 (regexp (cdr (assoc 'query query)))
1220 (grep-options (cdr (assoc 'grep-options query))) 1303 (grep-options (cdr (assoc 'grep-options query)))
1304 (grouplist (or grouplist (nnir-get-active server)))
1221 artlist) 1305 artlist)
1222 (unless directory 1306 (unless directory
1223 (error "No directory found in method specification of server %s" 1307 (error "No directory found in method specification of server %s"
@@ -1283,7 +1367,7 @@ Tested with Namazu 2.0.6 on a GNU/Linux system."
1283 (nreverse res)) 1367 (nreverse res))
1284 "."))) 1368 ".")))
1285 (push 1369 (push
1286 (vector (nnir-group-full-name group server) art 0) 1370 (vector (gnus-group-full-name group server) art 0)
1287 artlist)) 1371 artlist))
1288 (forward-line 1))) 1372 (forward-line 1)))
1289 (message "Searching %s using find-grep...done" 1373 (message "Searching %s using find-grep...done"
@@ -1297,15 +1381,14 @@ Tested with Namazu 2.0.6 on a GNU/Linux system."
1297;; gmane interface 1381;; gmane interface
1298(defun nnir-run-gmane (query srv &optional groups) 1382(defun nnir-run-gmane (query srv &optional groups)
1299 "Run a search against a gmane back-end server." 1383 "Run a search against a gmane back-end server."
1300 (if (gnus-string-match-p "gmane" srv) 1384 (if (gnus-string-match-p "gmane.org$" srv)
1301 (let* ((case-fold-search t) 1385 (let* ((case-fold-search t)
1302 (qstring (cdr (assq 'query query))) 1386 (qstring (cdr (assq 'query query)))
1303 (server (cadr (gnus-server-to-method srv))) 1387 (server (cadr (gnus-server-to-method srv)))
1304 (groupspec (if groups 1388 (groupspec (if groups
1305 (mapconcat 1389 (mapconcat
1306 (function (lambda (x) 1390 (lambda (x)
1307 (format "group:%s" 1391 (format "group:%s" (gnus-group-short-name x)))
1308 (gnus-group-short-name x))))
1309 groups " ") "")) 1392 groups " ") ""))
1310 (authorspec 1393 (authorspec
1311 (if (assq 'author query) 1394 (if (assq 'author query)
@@ -1341,12 +1424,7 @@ Tested with Namazu 2.0.6 on a GNU/Linux system."
1341 (string-to-number (match-string 2 xref)) xscore) 1424 (string-to-number (match-string 2 xref)) xscore)
1342 artlist))))) 1425 artlist)))))
1343 (forward-line 1))) 1426 (forward-line 1)))
1344 ;; Sort by score 1427 (apply 'vector (nreverse (mm-delete-duplicates artlist))))
1345 (apply 'vector
1346 (sort artlist
1347 (function (lambda (x y)
1348 (> (nnir-artitem-rsv x)
1349 (nnir-artitem-rsv y)))))))
1350 (message "Can't search non-gmane nntp groups") 1428 (message "Can't search non-gmane nntp groups")
1351 nil)) 1429 nil))
1352 1430
@@ -1380,33 +1458,34 @@ Tested with Namazu 2.0.6 on a GNU/Linux system."
1380 (groups (if (string= "all-ephemeral" nserver) 1458 (groups (if (string= "all-ephemeral" nserver)
1381 (with-current-buffer gnus-server-buffer 1459 (with-current-buffer gnus-server-buffer
1382 (list (list (gnus-server-server-name)))) 1460 (list (list (gnus-server-server-name))))
1383 (nnir-sort-groups-by-server 1461 (nnir-categorize
1384 (or gnus-group-marked 1462 (or gnus-group-marked
1385 (if (gnus-group-group-name) 1463 (if (gnus-group-group-name)
1386 (list (gnus-group-group-name)) 1464 (list (gnus-group-group-name))
1387 (cdr (assoc (gnus-group-topic-name) 1465 (cdr (assoc (gnus-group-topic-name)
1388 gnus-topic-alist)))))))) 1466 gnus-topic-alist))))
1467 gnus-group-server))))
1389 (apply 'vconcat 1468 (apply 'vconcat
1390 (mapcar (lambda (x) 1469 (mapcar
1391 (let* ((server (car x)) 1470 (lambda (x)
1392 (nnir-search-engine 1471 (let* ((server (car x))
1393 (or (nnir-read-server-parm 'nnir-search-engine 1472 (nnir-search-engine
1394 server) 1473 (or (nnir-read-server-parm 'nnir-search-engine
1395 (cdr (assoc (car 1474 server)
1396 (gnus-server-to-method server)) 1475 (cdr (assoc (car
1397 nnir-method-default-engines)))) 1476 (gnus-server-to-method server))
1398 search-func) 1477 nnir-method-default-engines))))
1399 (setq search-func (cadr 1478 search-func)
1400 (assoc nnir-search-engine 1479 (setq search-func (cadr (assoc nnir-search-engine
1401 nnir-engines))) 1480 nnir-engines)))
1402 (if search-func 1481 (if search-func
1403 (funcall search-func 1482 (funcall search-func
1404 (if nnir-extra-parms 1483 (if nnir-extra-parms
1405 (nnir-read-parms q nnir-search-engine) 1484 (nnir-read-parms q nnir-search-engine)
1406 q) 1485 q)
1407 server (cdr x)) 1486 server (cadr x))
1408 nil))) 1487 nil)))
1409 groups)))) 1488 groups))))
1410 1489
1411(defun nnir-read-server-parm (key server) 1490(defun nnir-read-server-parm (key server)
1412 "Returns the parameter value of key for the given server, where 1491 "Returns the parameter value of key for the given server, where
@@ -1416,50 +1495,11 @@ server is of form 'backend:name'."
1416 (nth 1 (assq key (cddr method)))) 1495 (nth 1 (assq key (cddr method))))
1417 (t nil)))) 1496 (t nil))))
1418 1497
1419(defun nnir-group-full-name (shortname server)
1420 "For the given group name, return a full Gnus group name.
1421The Gnus backend/server information is added."
1422 (gnus-group-prefixed-name shortname (gnus-server-to-method server)))
1423
1424(defun nnir-possibly-change-server (server) 1498(defun nnir-possibly-change-server (server)
1425 (unless (and server (nnir-server-opened server)) 1499 (unless (and server (nnir-server-opened server))
1426 (nnir-open-server server))) 1500 (nnir-open-server server)))
1427 1501
1428 1502
1429;; Data type article list.
1430
1431(defun nnir-artlist-length (artlist)
1432 "Returns number of articles in artlist."
1433 (length artlist))
1434
1435(defun nnir-artlist-article (artlist n)
1436 "Returns from ARTLIST the Nth artitem (counting starting at 1)."
1437 (elt artlist (1- n)))
1438
1439(defun nnir-artitem-group (artitem)
1440 "Returns the group from the ARTITEM."
1441 (elt artitem 0))
1442
1443(defun nnir-artlist-artitem-group (artlist n)
1444 "Returns from ARTLIST the group of the Nth artitem (counting from 1)."
1445 (nnir-artitem-group (nnir-artlist-article artlist n)))
1446
1447(defun nnir-artitem-number (artitem)
1448 "Returns the number from the ARTITEM."
1449 (elt artitem 1))
1450
1451(defun nnir-artlist-artitem-number (artlist n)
1452 "Returns from ARTLIST the number of the Nth artitem (counting from 1)."
1453 (nnir-artitem-number (nnir-artlist-article artlist n)))
1454
1455(defun nnir-artitem-rsv (artitem)
1456 "Returns the Retrieval Status Value (RSV, score) from the ARTITEM."
1457 (elt artitem 2))
1458
1459(defun nnir-artlist-artitem-rsv (artlist n)
1460 "Returns from ARTLIST the Retrieval Status Value of the Nth
1461artitem (counting from 1)."
1462 (nnir-artitem-rsv (nnir-artlist-article artlist n)))
1463 1503
1464;; unused? 1504;; unused?
1465(defun nnir-artlist-groups (artlist) 1505(defun nnir-artlist-groups (artlist)
@@ -1473,18 +1513,6 @@ artitem (counting from 1)."
1473 with-dups) 1513 with-dups)
1474 res)) 1514 res))
1475 1515
1476(defun nnir-sort-groups-by-server (groups)
1477 "sorts a list of groups into an alist keyed by server"
1478(if (car groups)
1479 (let (value)
1480 (dolist (var groups value)
1481 (let ((server (gnus-group-server var)))
1482 (if (assoc server value)
1483 (nconc (cdr (assoc server value)) (list var))
1484 (push (cons server (list var)) value))))
1485 value)
1486 nil))
1487
1488(defun nnir-get-active (srv) 1516(defun nnir-get-active (srv)
1489 (let ((method (gnus-server-to-method srv)) 1517 (let ((method (gnus-server-to-method srv))
1490 groups) 1518 groups)
@@ -1493,19 +1521,59 @@ artitem (counting from 1)."
1493 (let ((cur (current-buffer)) 1521 (let ((cur (current-buffer))
1494 name) 1522 name)
1495 (goto-char (point-min)) 1523 (goto-char (point-min))
1496 (unless (string= gnus-ignored-newsgroups "") 1524 (unless (string= nnir-ignored-newsgroups "")
1497 (delete-matching-lines gnus-ignored-newsgroups)) 1525 (delete-matching-lines nnir-ignored-newsgroups))
1498 (while (not (eobp)) 1526 (if (eq (car method) 'nntp)
1499 (ignore-errors 1527 (while (not (eobp))
1500 (push (mm-string-as-unibyte 1528 (ignore-errors
1501 (let ((p (point))) 1529 (push (mm-string-as-unibyte
1502 (skip-chars-forward "^ \t\\\\") 1530 (gnus-group-full-name
1503 (setq name (buffer-substring (+ p 1) (- (point) 1))) 1531 (buffer-substring
1504 (gnus-group-full-name name method))) 1532 (point)
1505 groups)) 1533 (progn
1506 (forward-line)))) 1534 (skip-chars-forward "^ \t")
1535 (point))) method))
1536 groups))
1537 (forward-line))
1538 (while (not (eobp))
1539 (ignore-errors
1540 (push (mm-string-as-unibyte
1541 (if (eq (char-after) ?\")
1542 (gnus-group-full-name (read cur) method)
1543 (let ((p (point)) (name ""))
1544 (skip-chars-forward "^ \t\\\\")
1545 (setq name (buffer-substring p (point)))
1546 (while (eq (char-after) ?\\)
1547 (setq p (1+ (point)))
1548 (forward-char 2)
1549 (skip-chars-forward "^ \t\\\\")
1550 (setq name (concat name (buffer-substring
1551 p (point)))))
1552 (gnus-group-full-name name method))))
1553 groups))
1554 (forward-line)))))
1507 groups)) 1555 groups))
1508 1556
1557(defun nnir-registry-action (action data-header from &optional to method)
1558 "Call `gnus-registry-action' with the original article group."
1559 (gnus-registry-action
1560 action
1561 data-header
1562 (nnir-article-group (mail-header-number data-header))
1563 to
1564 method))
1565
1566(defun nnir-mode ()
1567 (when (eq (car (gnus-find-method-for-group gnus-newsgroup-name)) 'nnir)
1568 (setq gnus-summary-line-format
1569 (or nnir-summary-line-format gnus-summary-line-format))
1570 (remove-hook 'gnus-summary-article-delete-hook 'gnus-registry-action t)
1571 (remove-hook 'gnus-summary-article-move-hook 'gnus-registry-action t)
1572 (add-hook 'gnus-summary-article-delete-hook 'nnir-registry-action t t)
1573 (add-hook 'gnus-summary-article-move-hook 'nnir-registry-action t t)))
1574
1575
1576
1509;; The end. 1577;; The end.
1510(provide 'nnir) 1578(provide 'nnir)
1511 1579
diff --git a/lisp/gnus/nnmaildir.el b/lisp/gnus/nnmaildir.el
index 65f33411297..8e2cd4bdde3 100644
--- a/lisp/gnus/nnmaildir.el
+++ b/lisp/gnus/nnmaildir.el
@@ -1559,7 +1559,7 @@ by nnmaildir-request-article.")
1559 (t (signal (car err) (cdr err)))))) 1559 (t (signal (car err) (cdr err))))))
1560 todo-marks)) 1560 todo-marks))
1561 set-action (lambda (article) 1561 set-action (lambda (article)
1562 (funcall add-action) 1562 (funcall add-action article)
1563 (mapcar (lambda (mark) 1563 (mapcar (lambda (mark)
1564 (unless (memq mark todo-marks) 1564 (unless (memq mark todo-marks)
1565 (funcall del-mark mark))) 1565 (funcall del-mark mark)))
diff --git a/lisp/gnus/nntp.el b/lisp/gnus/nntp.el
index f37a1c8c48f..6504f05c9d2 100644
--- a/lisp/gnus/nntp.el
+++ b/lisp/gnus/nntp.el
@@ -34,6 +34,7 @@
34(require 'nnoo) 34(require 'nnoo)
35(require 'gnus-util) 35(require 'gnus-util)
36(require 'gnus) 36(require 'gnus)
37(require 'proto-stream)
37(require 'gnus-group) ;; gnus-group-name-charset 38(require 'gnus-group) ;; gnus-group-name-charset
38 39
39(nnoo-declare nntp) 40(nnoo-declare nntp)
@@ -305,13 +306,6 @@ update their active files often, this can help.")
305(defvar nntp-async-timer nil) 306(defvar nntp-async-timer nil)
306(defvar nntp-async-process-list nil) 307(defvar nntp-async-process-list nil)
307 308
308(defvar nntp-ssl-program
309 "openssl s_client -quiet -ssl3 -connect %s:%p"
310"A string containing commands for SSL connections.
311Within a string, %s is replaced with the server address and %p with
312port number on server. The program should accept IMAP commands on
313stdin and return responses to stdout.")
314
315(defvar nntp-authinfo-rejected nil 309(defvar nntp-authinfo-rejected nil
316"A custom error condition used to report 'Authentication Rejected' errors. 310"A custom error condition used to report 'Authentication Rejected' errors.
317Condition handlers that match just this condition ensure that the nntp 311Condition handlers that match just this condition ensure that the nntp
@@ -1268,11 +1262,28 @@ password contained in '~/.nntp-authinfo'."
1268 `(lambda () 1262 `(lambda ()
1269 (nntp-kill-buffer ,pbuffer))))) 1263 (nntp-kill-buffer ,pbuffer)))))
1270 (process 1264 (process
1271 (condition-case () 1265 (condition-case err
1272 (let ((coding-system-for-read nntp-coding-system-for-read) 1266 (let ((coding-system-for-read nntp-coding-system-for-read)
1273 (coding-system-for-write nntp-coding-system-for-write)) 1267 (coding-system-for-write nntp-coding-system-for-write)
1274 (funcall nntp-open-connection-function pbuffer)) 1268 (map '((nntp-open-network-stream network)
1275 (error nil) 1269 (nntp-open-ssl-stream tls)
1270 (nntp-open-tls-stream tls))))
1271 (if (assoc nntp-open-connection-function map)
1272 (car (open-protocol-stream
1273 "nntpd" pbuffer nntp-address nntp-port-number
1274 :type (cadr
1275 (assoc nntp-open-connection-function map))
1276 :end-of-command "^\\([2345]\\|[.]\\).*\n"
1277 :capability-command "CAPABILITIES\r\n"
1278 :success "^3"
1279 :starttls-function
1280 (lambda (capabilities)
1281 (if (not (string-match "STARTTLS" capabilities))
1282 nil
1283 "STARTTLS\r\n"))))
1284 (funcall nntp-open-connection-function pbuffer)))
1285 (error
1286 (nnheader-report 'nntp "%s" err))
1276 (quit 1287 (quit
1277 (message "Quit opening connection to %s" nntp-address) 1288 (message "Quit opening connection to %s" nntp-address)
1278 (nntp-kill-buffer pbuffer) 1289 (nntp-kill-buffer pbuffer)
@@ -1300,40 +1311,6 @@ password contained in '~/.nntp-authinfo'."
1300 (nntp-kill-buffer (process-buffer process)) 1311 (nntp-kill-buffer (process-buffer process))
1301 nil)))) 1312 nil))))
1302 1313
1303(defun nntp-open-network-stream (buffer)
1304 (open-network-stream "nntpd" buffer nntp-address nntp-port-number))
1305
1306(autoload 'format-spec "format-spec")
1307(autoload 'format-spec-make "format-spec")
1308(autoload 'open-tls-stream "tls")
1309
1310(defun nntp-open-ssl-stream (buffer)
1311 (let* ((process-connection-type nil)
1312 (proc (start-process "nntpd" buffer
1313 shell-file-name
1314 shell-command-switch
1315 (format-spec nntp-ssl-program
1316 (format-spec-make
1317 ?s nntp-address
1318 ?p nntp-port-number)))))
1319 (gnus-set-process-query-on-exit-flag proc nil)
1320 (with-current-buffer buffer
1321 (let ((nntp-connection-alist (list proc buffer nil)))
1322 (nntp-wait-for-string "^\r*20[01]"))
1323 (beginning-of-line)
1324 (delete-region (point-min) (point))
1325 proc)))
1326
1327(defun nntp-open-tls-stream (buffer)
1328 (let ((proc (open-tls-stream "nntpd" buffer nntp-address nntp-port-number)))
1329 (gnus-set-process-query-on-exit-flag proc nil)
1330 (with-current-buffer buffer
1331 (let ((nntp-connection-alist (list proc buffer nil)))
1332 (nntp-wait-for-string "^\r*20[01]"))
1333 (beginning-of-line)
1334 (delete-region (point-min) (point))
1335 proc)))
1336
1337(defun nntp-read-server-type () 1314(defun nntp-read-server-type ()
1338 "Find out what the name of the server we have connected to is." 1315 "Find out what the name of the server we have connected to is."
1339 ;; Wait for the status string to arrive. 1316 ;; Wait for the status string to arrive.
diff --git a/lisp/gnus/proto-stream.el b/lisp/gnus/proto-stream.el
new file mode 100644
index 00000000000..d402a876456
--- /dev/null
+++ b/lisp/gnus/proto-stream.el
@@ -0,0 +1,262 @@
1;;; proto-stream.el --- negotiating TLS, STARTTLS and other connections
2;; Copyright (C) 2010 Free Software Foundation, Inc.
3
4;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
5;; Keywords: network
6
7;; This file is part of GNU Emacs.
8
9;; GNU Emacs is free software; you can redistribute it and/or modify
10;; it under the terms of the GNU General Public License as published by
11;; the Free Software Foundation; either version 3, or (at your option)
12;; any later version.
13
14;; GNU Emacs is distributed in the hope that it will be useful,
15;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17;; GNU General Public License for more details.
18
19;; You should have received a copy of the GNU General Public License
20;; along with GNU Emacs; see the file COPYING. If not, write to the
21;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22;; Boston, MA 02110-1301, USA.
23
24;;; Commentary:
25
26;; This library is meant to provide the glue between modules that want
27;; to establish a network connection to a server for protocols such as
28;; IMAP, NNTP, SMTP and POP3.
29
30;; The main problem is that there's more than a couple of interfaces
31;; towards doing this. You have normal, plain connections, which are
32;; no trouble at all, but you also have TLS/SSL connections, and you
33;; have STARTTLS. Negotiating this for each protocol can be rather
34;; tedious, so this library provides a single entry point, and hides
35;; much of the ugliness.
36
37;; Usage example:
38
39;; (open-protocol-stream
40;; "*nnimap*" buffer address port
41;; :type 'network
42;; :capability-command "1 CAPABILITY\r\n"
43;; :success " OK "
44;; :starttls-function
45;; (lambda (capabilities)
46;; (if (not (string-match "STARTTLS" capabilities))
47;; nil
48;; "1 STARTTLS\r\n")))
49
50;;; Code:
51
52(eval-when-compile
53 (require 'cl))
54(require 'tls)
55(require 'starttls)
56(require 'format-spec)
57
58(defcustom proto-stream-always-use-starttls (fboundp 'open-gnutls-stream)
59 "If non-nil, always try to upgrade network connections with STARTTLS."
60 :version "24.1"
61 :type 'boolean
62 :group 'comm)
63
64(declare-function gnutls-negotiate "gnutls"
65 (proc type &optional priority-string trustfiles keyfiles))
66
67;;;###autoload
68(defun open-protocol-stream (name buffer host service &rest parameters)
69 "Open a network stream to HOST, upgrading to STARTTLS if possible.
70The first four parameters have the same meaning as in
71`open-network-stream'. The function returns a list where the
72first element is the stream, the second element is the greeting
73the server replied with after connecting, and the third element
74is a string representing the capabilities of the server (if any).
75
76The PARAMETERS is a keyword list that can have the following
77values:
78
79:type -- either `network', `tls', `shell' or `starttls'. If
80omitted, the default is `network'. `network' will be
81opportunistically upgraded to STARTTLS if both the server and
82Emacs supports it.
83
84:end-of-command -- a regexp saying what the end of a command is.
85This defaults to \"\\n\".
86
87:success -- a regexp saying whether the STARTTLS command was
88successful or not. For instance, for NNTP this is \"^3\".
89
90:capability-command -- a string representing the command used to
91query server for capabilities. For instance, for IMAP this is
92\"1 CAPABILITY\\r\\n\".
93
94:starttls-function -- a function that takes one parameter, which
95is the response to the capaibility command. It should return nil
96if it turns out that the server doesn't support STARTTLS, or the
97command to switch on STARTTLS otherwise."
98 (let ((type (or (cadr (memq :type parameters)) 'network)))
99 (cond
100 ((eq type 'starttls)
101 (setq type 'network))
102 ((eq type 'ssl)
103 (setq type 'tls)))
104 (destructuring-bind (stream greeting capabilities)
105 (funcall (intern (format "proto-stream-open-%s" type) obarray)
106 name buffer host service parameters)
107 (list (and stream
108 (memq (process-status stream)
109 '(open run))
110 stream)
111 greeting capabilities))))
112
113(defun proto-stream-open-network (name buffer host service parameters)
114 (let* ((start (with-current-buffer buffer (point)))
115 (stream (open-network-stream name buffer host service))
116 (capability-command (cadr (memq :capability-command parameters)))
117 (eoc (proto-stream-eoc parameters))
118 (type (cadr (memq :type parameters)))
119 (greeting (proto-stream-get-response stream start eoc))
120 success)
121 (if (not capability-command)
122 (list stream greeting nil)
123 (let* ((capabilities
124 (proto-stream-command stream capability-command eoc))
125 (starttls-command
126 (funcall (cadr (memq :starttls-function parameters))
127 capabilities)))
128 (cond
129 ;; If this server doesn't support STARTTLS, but we have
130 ;; requested it explicitly, then close the connection and
131 ;; return nil.
132 ((or (not starttls-command)
133 (and (not (eq type 'starttls))
134 (not proto-stream-always-use-starttls)))
135 (if (eq type 'starttls)
136 (progn
137 (delete-process stream)
138 nil)
139 ;; Otherwise, just return this plain network connection.
140 (list stream greeting capabilities)))
141 ;; We have some kind of STARTTLS support, so we try to
142 ;; upgrade the connection opportunistically.
143 ((or (fboundp 'open-gnutls-stream)
144 (executable-find "gnutls-cli"))
145 (unless (fboundp 'open-gnutls-stream)
146 (delete-process stream)
147 (setq start (with-current-buffer buffer (point-max)))
148 (let* ((starttls-use-gnutls t)
149 (starttls-extra-arguments
150 (if (not (eq type 'starttls))
151 ;; When doing opportunistic TLS upgrades we
152 ;; don't really care about the identity of the
153 ;; peer.
154 (cons "--insecure" starttls-extra-arguments)
155 starttls-extra-arguments)))
156 (setq stream (starttls-open-stream name buffer host service)))
157 (proto-stream-get-response stream start eoc))
158 (if (not
159 (string-match
160 (cadr (memq :success parameters))
161 (proto-stream-command stream starttls-command eoc)))
162 ;; We got an error back from the STARTTLS command.
163 (progn
164 (if (eq type 'starttls)
165 (progn
166 (delete-process stream)
167 nil)
168 (list stream greeting capabilities)))
169 ;; The server said it was OK to start doing STARTTLS negotiations.
170 (if (fboundp 'open-gnutls-stream)
171 (gnutls-negotiate stream nil)
172 (unless (starttls-negotiate stream)
173 (delete-process stream)
174 (setq stream nil)))
175 (when (or (null stream)
176 (not (memq (process-status stream)
177 '(open run))))
178 ;; It didn't successfully negotiate STARTTLS, so we reopen
179 ;; the connection.
180 (setq stream (open-network-stream name buffer host service))
181 (proto-stream-get-response stream start eoc))
182 ;; Re-get the capabilities, since they may have changed
183 ;; after switching to TLS.
184 (list stream greeting
185 (proto-stream-command stream capability-command eoc))))
186 ;; We don't have STARTTLS support available, but the caller
187 ;; requested a STARTTLS connection, so we give up.
188 ((eq (cadr (memq :type parameters)) 'starttls)
189 (delete-process stream)
190 nil)
191 ;; Fall back on using a plain network stream.
192 (t
193 (list stream greeting capabilities)))))))
194
195(defun proto-stream-command (stream command eoc)
196 (let ((start (with-current-buffer (process-buffer stream) (point-max))))
197 (process-send-string stream command)
198 (proto-stream-get-response stream start eoc)))
199
200(defun proto-stream-get-response (stream start end-of-command)
201 (with-current-buffer (process-buffer stream)
202 (save-excursion
203 (goto-char start)
204 (while (and (memq (process-status stream)
205 '(open run))
206 (not (re-search-forward end-of-command nil t)))
207 (accept-process-output stream 0 50)
208 (goto-char start))
209 (if (= start (point))
210 ;; The process died; return nil.
211 nil
212 ;; Return the data we got back.
213 (buffer-substring start (point))))))
214
215(defun proto-stream-open-tls (name buffer host service parameters)
216 (with-current-buffer buffer
217 (let ((start (point-max))
218 (stream
219 (funcall (if (fboundp 'open-gnutls-stream)
220 'open-gnutls-stream
221 'open-tls-stream)
222 name buffer host service)))
223 ;; If we're using tls.el, we have to delete the output from
224 ;; openssl/gnutls-cli.
225 (unless (fboundp 'open-gnutls-stream)
226 (proto-stream-get-response
227 stream start (proto-stream-eoc parameters))
228 (goto-char (point-min))
229 (when (re-search-forward (proto-stream-eoc parameters) nil t)
230 (goto-char (match-beginning 0))
231 (delete-region (point-min) (line-beginning-position))))
232 (proto-stream-capability-open start stream parameters))))
233
234(defun proto-stream-open-shell (name buffer host service parameters)
235 (proto-stream-capability-open
236 (with-current-buffer buffer (point))
237 (let ((process-connection-type nil))
238 (start-process name buffer shell-file-name
239 shell-command-switch
240 (format-spec
241 (cadr (memq :shell-command parameters))
242 (format-spec-make
243 ?s host
244 ?p service))))
245 parameters))
246
247(defun proto-stream-capability-open (start stream parameters)
248 (let ((capability-command (cadr (memq :capability-command parameters)))
249 (greeting (proto-stream-get-response
250 stream start (proto-stream-eoc parameters))))
251 (list stream greeting
252 (and capability-command
253 (proto-stream-command
254 stream capability-command (proto-stream-eoc parameters))))))
255
256(defun proto-stream-eoc (parameters)
257 (or (cadr (memq :end-of-command parameters))
258 "\r\n"))
259
260(provide 'proto-stream)
261
262;;; proto-stream.el ends here
diff --git a/lisp/gnus/rtree.el b/lisp/gnus/rtree.el
new file mode 100644
index 00000000000..d2aa91848e8
--- /dev/null
+++ b/lisp/gnus/rtree.el
@@ -0,0 +1,279 @@
1;;; rtree.el --- functions for manipulating range trees
2;; Copyright (C) 2010 Free Software Foundation, Inc.
3
4;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
5
6;; This file is part of GNU Emacs.
7
8;; GNU Emacs is free software; you can redistribute it and/or modify
9;; it under the terms of the GNU General Public License as published by
10;; the Free Software Foundation; either version 3, or (at your option)
11;; any later version.
12
13;; GNU Emacs is distributed in the hope that it will be useful,
14;; but WITHOUT ANY WARRANTY; without even the implied warranty of
15;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16;; GNU General Public License for more details.
17
18;; You should have received a copy of the GNU General Public License
19;; along with GNU Emacs; see the file COPYING. If not, write to the
20;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21;; Boston, MA 02110-1301, USA.
22
23;;; Commentary:
24
25;; A "range tree" is a binary tree that stores ranges. They are
26;; similar to interval trees, but do not allow overlapping intervals.
27
28;; A range is an ordered list of number intervals, like this:
29
30;; ((10 . 25) 56 78 (98 . 201))
31
32;; Common operations, like lookup, deletion and insertion are O(n) in
33;; a range, but an rtree is O(log n) in all these operations.
34;; Transformation between a range and an rtree is O(n).
35
36;; The rtrees are quite simple. The structure of each node is
37
38;; (cons (cons low high) (cons left right))
39
40;; That is, they are three cons cells, where the car of the top cell
41;; is the actual range, and the cdr has the left and right child. The
42;; rtrees aren't automatically balanced, but are balanced when
43;; created, and can be rebalanced when deemed necessary.
44
45;;; Code:
46
47(eval-when-compile
48 (require 'cl))
49
50(defmacro rtree-make-node ()
51 `(list (list nil) nil))
52
53(defmacro rtree-set-left (node left)
54 `(setcar (cdr ,node) ,left))
55
56(defmacro rtree-set-right (node right)
57 `(setcdr (cdr ,node) ,right))
58
59(defmacro rtree-set-range (node range)
60 `(setcar ,node ,range))
61
62(defmacro rtree-low (node)
63 `(caar ,node))
64
65(defmacro rtree-high (node)
66 `(cdar ,node))
67
68(defmacro rtree-set-low (node number)
69 `(setcar (car ,node) ,number))
70
71(defmacro rtree-set-high (node number)
72 `(setcdr (car ,node) ,number))
73
74(defmacro rtree-left (node)
75 `(cadr ,node))
76
77(defmacro rtree-right (node)
78 `(cddr ,node))
79
80(defmacro rtree-range (node)
81 `(car ,node))
82
83(defsubst rtree-normalise-range (range)
84 (when (numberp range)
85 (setq range (cons range range)))
86 range)
87
88(defun rtree-make (range)
89 "Make an rtree from RANGE."
90 ;; Normalize the range.
91 (unless (listp (cdr-safe range))
92 (setq range (list range)))
93 (rtree-make-1 (cons nil range) (length range)))
94
95(defun rtree-make-1 (range length)
96 (let ((mid (/ length 2))
97 (node (rtree-make-node)))
98 (when (> mid 0)
99 (rtree-set-left node (rtree-make-1 range mid)))
100 (rtree-set-range node (rtree-normalise-range (cadr range)))
101 (setcdr range (cddr range))
102 (when (> (- length mid 1) 0)
103 (rtree-set-right node (rtree-make-1 range (- length mid 1))))
104 node))
105
106(defun rtree-memq (tree number)
107 "Return non-nil if NUMBER is present in TREE."
108 (while (and tree
109 (not (and (>= number (rtree-low tree))
110 (<= number (rtree-high tree)))))
111 (setq tree
112 (if (< number (rtree-low tree))
113 (rtree-left tree)
114 (rtree-right tree))))
115 tree)
116
117(defun rtree-add (tree number)
118 "Add NUMBER to TREE."
119 (while tree
120 (cond
121 ;; It's already present, so we don't have to do anything.
122 ((and (>= number (rtree-low tree))
123 (<= number (rtree-high tree)))
124 (setq tree nil))
125 ((< number (rtree-low tree))
126 (cond
127 ;; Extend the low range.
128 ((= number (1- (rtree-low tree)))
129 (rtree-set-low tree number)
130 ;; Check whether we need to merge this node with the child.
131 (when (and (rtree-left tree)
132 (= (rtree-high (rtree-left tree)) (1- number)))
133 ;; Extend the range to the low from the child.
134 (rtree-set-low tree (rtree-low (rtree-left tree)))
135 ;; The child can't have a right child, so just transplant the
136 ;; child's left tree to our left tree.
137 (rtree-set-left tree (rtree-left (rtree-left tree))))
138 (setq tree nil))
139 ;; Descend further to the left.
140 ((rtree-left tree)
141 (setq tree (rtree-left tree)))
142 ;; Add a new node.
143 (t
144 (let ((new-node (rtree-make-node)))
145 (rtree-set-low new-node number)
146 (rtree-set-high new-node number)
147 (rtree-set-left tree new-node)
148 (setq tree nil)))))
149 (t
150 (cond
151 ;; Extend the high range.
152 ((= number (1+ (rtree-high tree)))
153 (rtree-set-high tree number)
154 ;; Check whether we need to merge this node with the child.
155 (when (and (rtree-right tree)
156 (= (rtree-low (rtree-right tree)) (1+ number)))
157 ;; Extend the range to the high from the child.
158 (rtree-set-high tree (rtree-high (rtree-right tree)))
159 ;; The child can't have a left child, so just transplant the
160 ;; child's left right to our right tree.
161 (rtree-set-right tree (rtree-right (rtree-right tree))))
162 (setq tree nil))
163 ;; Descend further to the right.
164 ((rtree-right tree)
165 (setq tree (rtree-right tree)))
166 ;; Add a new node.
167 (t
168 (let ((new-node (rtree-make-node)))
169 (rtree-set-low new-node number)
170 (rtree-set-high new-node number)
171 (rtree-set-right tree new-node)
172 (setq tree nil))))))))
173
174(defun rtree-delq (tree number)
175 "Remove NUMBER from TREE destructively. Returns the new tree."
176 (let ((result tree)
177 prev)
178 (while tree
179 (cond
180 ((< number (rtree-low tree))
181 (setq prev tree
182 tree (rtree-left tree)))
183 ((> number (rtree-high tree))
184 (setq prev tree
185 tree (rtree-right tree)))
186 ;; The number is in this node.
187 (t
188 (cond
189 ;; The only entry; delete the node.
190 ((= (rtree-low tree) (rtree-high tree))
191 (cond
192 ;; Two children. Replace with successor value.
193 ((and (rtree-left tree) (rtree-right tree))
194 (let ((parent tree)
195 (successor (rtree-right tree)))
196 (while (rtree-left successor)
197 (setq parent successor
198 successor (rtree-left successor)))
199 ;; We now have the leftmost child of our right child.
200 (rtree-set-range tree (rtree-range successor))
201 ;; Transplant the child (if any) to the parent.
202 (rtree-set-left parent (rtree-right successor))))
203 (t
204 (let ((rest (or (rtree-left tree)
205 (rtree-right tree))))
206 ;; One or zero children. Remove the node.
207 (cond
208 ((null prev)
209 (setq result rest))
210 ((eq (rtree-left prev) tree)
211 (rtree-set-left prev rest))
212 (t
213 (rtree-set-right prev rest)))))))
214 ;; The lowest in the range; just adjust.
215 ((= number (rtree-low tree))
216 (rtree-set-low tree (1+ number)))
217 ;; The highest in the range; just adjust.
218 ((= number (rtree-high tree))
219 (rtree-set-high tree (1- number)))
220 ;; We have to split this range.
221 (t
222 (let ((new-node (rtree-make-node)))
223 (rtree-set-low new-node (rtree-low tree))
224 (rtree-set-high new-node (1- number))
225 (rtree-set-low tree (1+ number))
226 (cond
227 ;; Two children; insert the new node as the predecessor
228 ;; node.
229 ((and (rtree-left tree) (rtree-right tree))
230 (let ((predecessor (rtree-left tree)))
231 (while (rtree-right predecessor)
232 (setq predecessor (rtree-right predecessor)))
233 (rtree-set-right predecessor new-node)))
234 ((rtree-left tree)
235 (rtree-set-right new-node tree)
236 (rtree-set-left new-node (rtree-left tree))
237 (rtree-set-left tree nil)
238 (cond
239 ((null prev)
240 (setq result new-node))
241 ((eq (rtree-left prev) tree)
242 (rtree-set-left prev new-node))
243 (t
244 (rtree-set-right prev new-node))))
245 (t
246 (rtree-set-left tree new-node))))))
247 (setq tree nil))))
248 result))
249
250(defun rtree-extract (tree)
251 "Convert TREE to range form."
252 (let (stack result)
253 (while (or stack
254 tree)
255 (if tree
256 (progn
257 (push tree stack)
258 (setq tree (rtree-right tree)))
259 (setq tree (pop stack))
260 (push (if (= (rtree-low tree)
261 (rtree-high tree))
262 (rtree-low tree)
263 (rtree-range tree))
264 result)
265 (setq tree (rtree-left tree))))
266 result))
267
268(defun rtree-length (tree)
269 "Return the number of numbers stored in TREE."
270 (if (null tree)
271 0
272 (+ (rtree-length (rtree-left tree))
273 (1+ (- (rtree-high tree)
274 (rtree-low tree)))
275 (rtree-length (rtree-right tree)))))
276
277(provide 'rtree)
278
279;;; rtree.el ends here
diff --git a/lisp/gnus/shr.el b/lisp/gnus/shr.el
index 69973fbfb50..c07bb34ef8d 100644
--- a/lisp/gnus/shr.el
+++ b/lisp/gnus/shr.el
@@ -32,8 +32,6 @@
32 32
33(eval-when-compile (require 'cl)) 33(eval-when-compile (require 'cl))
34(require 'browse-url) 34(require 'browse-url)
35(unless (aref (char-category-set (make-char 'japanese-jisx0208 33 35)) ?>)
36 (load "kinsoku" nil t))
37 35
38(defgroup shr nil 36(defgroup shr nil
39 "Simple HTML Renderer" 37 "Simple HTML Renderer"
@@ -214,6 +212,26 @@ redirects somewhere else."
214 ((listp (cdr sub)) 212 ((listp (cdr sub))
215 (shr-descend sub))))) 213 (shr-descend sub)))))
216 214
215(defmacro shr-char-breakable-p (char)
216 "Return non-nil if a line can be broken before and after CHAR."
217 `(aref fill-find-break-point-function-table ,char))
218(defmacro shr-char-nospace-p (char)
219 "Return non-nil if no space is required before and after CHAR."
220 `(aref fill-nospace-between-words-table ,char))
221
222;; KINSOKU is a Japanese word meaning a rule that should not be violated.
223;; In Emacs, it is a term used for characters, e.g. punctuation marks,
224;; parentheses, and so on, that should not be placed in the beginning
225;; of a line or the end of a line.
226(defmacro shr-char-kinsoku-bol-p (char)
227 "Return non-nil if a line ought not to begin with CHAR."
228 `(aref (char-category-set ,char) ?>))
229(defmacro shr-char-kinsoku-eol-p (char)
230 "Return non-nil if a line ought not to end with CHAR."
231 `(aref (char-category-set ,char) ?<))
232(unless (shr-char-kinsoku-bol-p (make-char 'japanese-jisx0208 33 35))
233 (load "kinsoku" nil t))
234
217(defun shr-insert (text) 235(defun shr-insert (text)
218 (when (and (eq shr-state 'image) 236 (when (and (eq shr-state 'image)
219 (not (string-match "\\`[ \t\n]+\\'" text))) 237 (not (string-match "\\`[ \t\n]+\\'" text)))
@@ -242,12 +260,11 @@ redirects somewhere else."
242 (let (prev) 260 (let (prev)
243 (when (and (eq (preceding-char) ? ) 261 (when (and (eq (preceding-char) ? )
244 (or (= (line-beginning-position) (1- (point))) 262 (or (= (line-beginning-position) (1- (point)))
245 (and (aref fill-find-break-point-function-table 263 (and (shr-char-breakable-p
246 (setq prev (char-after (- (point) 2)))) 264 (setq prev (char-after (- (point) 2))))
247 (aref (char-category-set prev) ?>)) 265 (shr-char-kinsoku-bol-p prev))
248 (and (aref fill-nospace-between-words-table prev) 266 (and (shr-char-nospace-p prev)
249 (aref fill-nospace-between-words-table 267 (shr-char-nospace-p (aref elem 0)))))
250 (aref elem 0)))))
251 (delete-char -1))) 268 (delete-char -1)))
252 (insert elem) 269 (insert elem)
253 (let (found) 270 (let (found)
@@ -273,67 +290,88 @@ redirects somewhere else."
273(defun shr-find-fill-point () 290(defun shr-find-fill-point ()
274 (when (> (move-to-column shr-width) shr-width) 291 (when (> (move-to-column shr-width) shr-width)
275 (backward-char 1)) 292 (backward-char 1))
276 (let (failed) 293 (let ((bp (point))
277 (while (not 294 failed)
278 (or (setq failed (= (current-column) shr-indentation)) 295 (while (not (or (setq failed (= (current-column) shr-indentation))
279 (eq (preceding-char) ? ) 296 (eq (preceding-char) ? )
280 (eq (following-char) ? ) 297 (eq (following-char) ? )
281 (aref fill-find-break-point-function-table (preceding-char)) 298 (shr-char-breakable-p (preceding-char))
282 (aref (char-category-set (preceding-char)) ?>))) 299 (shr-char-breakable-p (following-char))
300 (and (eq (preceding-char) ?')
301 (not (memq (char-after (- (point) 2))
302 (list nil ?\n ? ))))
303 ;; There're some kinsoku CJK chars that aren't breakable.
304 (and (shr-char-kinsoku-bol-p (preceding-char))
305 (not (shr-char-kinsoku-bol-p (following-char))))
306 (shr-char-kinsoku-eol-p (following-char))))
283 (backward-char 1)) 307 (backward-char 1))
308 (if (and (not (or failed (eolp)))
309 (eq (preceding-char) ?'))
310 (while (not (or (setq failed (eolp))
311 (eq (following-char) ? )
312 (shr-char-breakable-p (following-char))
313 (shr-char-kinsoku-eol-p (following-char))))
314 (forward-char 1)))
284 (if failed 315 (if failed
285 ;; There's no breakable point, so we give it up. 316 ;; There's no breakable point, so we give it up.
286 (progn 317 (let (found)
287 (end-of-line) 318 (goto-char bp)
288 (while (aref fill-find-break-point-function-table (preceding-char)) 319 (unless shr-kinsoku-shorten
289 (backward-char 1)) 320 (while (and (setq found (re-search-forward
290 nil) 321 "\\(\\c>\\)\\| \\|\\c<\\|\\c|"
322 (line-end-position) 'move))
323 (eq (preceding-char) ?')))
324 (if (and found (not (match-beginning 1)))
325 (goto-char (match-beginning 0)))))
291 (or 326 (or
292 (eolp) 327 (eolp)
293 (progn 328 ;; Don't put kinsoku-bol characters at the beginning of a line,
294 ;; Don't put kinsoku-bol characters at the beginning of a line, 329 ;; or kinsoku-eol characters at the end of a line.
295 ;; or kinsoku-eol characters at the end of a line. 330 (cond
296 (cond 331 (shr-kinsoku-shorten
297 (shr-kinsoku-shorten 332 (while (and (not (memq (preceding-char) (list ?\C-@ ?\n ? )))
298 (while (and 333 (shr-char-kinsoku-eol-p (preceding-char)))
299 (not (memq (preceding-char) (list ?\C-@ ?\n ? ))) 334 (backward-char 1))
300 (not (or (aref (char-category-set (preceding-char)) ?>) 335 (when (setq failed (= (current-column) shr-indentation))
301 (aref (char-category-set (following-char)) ?<))) 336 ;; There's no breakable point that doesn't violate kinsoku,
302 (or (aref (char-category-set (preceding-char)) ?<) 337 ;; so we look for the second best position.
303 (aref (char-category-set (following-char)) ?>))) 338 (while (and (progn
304 (backward-char 1))) 339 (forward-char 1)
305 ((aref (char-category-set (preceding-char)) ?<) 340 (<= (current-column) shr-width))
306 (let ((count 3)) 341 (progn
307 (while (progn 342 (setq bp (point))
308 (backward-char 1) 343 (shr-char-kinsoku-eol-p (following-char)))))
309 (and 344 (goto-char bp)))
310 (> (setq count (1- count)) 0) 345 ((shr-char-kinsoku-eol-p (preceding-char))
311 (not (memq (preceding-char) (list ?\C-@ ?\n ? ))) 346 (if (shr-char-kinsoku-eol-p (following-char))
312 (or (aref (char-category-set (preceding-char)) ?<) 347 ;; There are consecutive kinsoku-eol characters.
313 (aref (char-category-set (following-char)) ?>)))))) 348 (setq failed t)
314 (if (and (setq failed (= (current-column) shr-indentation)) 349 (let ((count 4))
315 (re-search-forward "\\c|" (line-end-position) 'move)) 350 (while
351 (progn
352 (backward-char 1)
353 (and (> (setq count (1- count)) 0)
354 (not (memq (preceding-char) (list ?\C-@ ?\n ? )))
355 (or (shr-char-kinsoku-eol-p (preceding-char))
356 (shr-char-kinsoku-bol-p (following-char)))))))
357 (if (setq failed (= (current-column) shr-indentation))
316 ;; There's no breakable point that doesn't violate kinsoku, 358 ;; There's no breakable point that doesn't violate kinsoku,
317 ;; so we look for the second best position. 359 ;; so we go to the second best position.
318 (let (bp) 360 (if (looking-at "\\(\\c<+\\)\\c<")
319 (while (and (<= (current-column) shr-width) 361 (goto-char (match-end 1))
320 (progn 362 (forward-char 1)))))
321 (setq bp (point)) 363 (t
322 (not (eolp))) 364 (if (shr-char-kinsoku-bol-p (preceding-char))
323 (aref fill-find-break-point-function-table 365 ;; There are consecutive kinsoku-bol characters.
324 (following-char))) 366 (setq failed t)
325 (forward-char 1))
326 (goto-char (or bp (line-end-position))))))
327 (t
328 (let ((count 4)) 367 (let ((count 4))
329 (while (and (>= (setq count (1- count)) 0) 368 (while (and (>= (setq count (1- count)) 0)
330 (aref (char-category-set (following-char)) ?>) 369 (shr-char-kinsoku-bol-p (following-char))
331 (aref fill-find-break-point-function-table 370 (shr-char-breakable-p (following-char)))
332 (following-char))) 371 (forward-char 1))))))
333 (forward-char 1))))) 372 (when (eq (following-char) ? )
334 (when (eq (following-char) ? ) 373 (forward-char 1))))
335 (forward-char 1)) 374 (not failed)))
336 (not failed))))))
337 375
338(defun shr-ensure-newline () 376(defun shr-ensure-newline ()
339 (unless (zerop (current-column)) 377 (unless (zerop (current-column))