aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/misc/ChangeLog49
-rw-r--r--doc/misc/gnus.texi289
-rw-r--r--doc/misc/message.texi34
-rw-r--r--etc/GNUS-NEWS262
-rw-r--r--lisp/gnus/ChangeLog394
-rw-r--r--lisp/gnus/gnus-agent.el19
-rw-r--r--lisp/gnus/gnus-art.el18
-rw-r--r--lisp/gnus/gnus-cite.el1
-rw-r--r--lisp/gnus/gnus-demon.el45
-rw-r--r--lisp/gnus/gnus-group.el38
-rw-r--r--lisp/gnus/gnus-int.el61
-rw-r--r--lisp/gnus/gnus-msg.el112
-rw-r--r--lisp/gnus/gnus-picon.el12
-rw-r--r--lisp/gnus/gnus-registry.el127
-rw-r--r--lisp/gnus/gnus-spec.el100
-rw-r--r--lisp/gnus/gnus-start.el15
-rw-r--r--lisp/gnus/gnus-sum.el77
-rw-r--r--lisp/gnus/gnus-sync.el826
-rw-r--r--lisp/gnus/gnus-util.el22
-rw-r--r--lisp/gnus/gnus.el5
-rw-r--r--lisp/gnus/message.el57
-rw-r--r--lisp/gnus/mm-decode.el171
-rw-r--r--lisp/gnus/mm-util.el2
-rw-r--r--lisp/gnus/mml.el11
-rw-r--r--lisp/gnus/nnfolder.el151
-rw-r--r--lisp/gnus/nnimap.el2
-rw-r--r--lisp/gnus/nnmail.el6
-rw-r--r--lisp/gnus/nnml.el137
-rw-r--r--lisp/gnus/nntp.el154
-rw-r--r--lisp/gnus/pop3.el14
-rw-r--r--lisp/gnus/registry.el112
-rw-r--r--lisp/gnus/shr.el138
-rw-r--r--lisp/gnus/spam.el27
33 files changed, 2019 insertions, 1469 deletions
diff --git a/doc/misc/ChangeLog b/doc/misc/ChangeLog
index 212343f4c67..42320b227f8 100644
--- a/doc/misc/ChangeLog
+++ b/doc/misc/ChangeLog
@@ -1,3 +1,52 @@
12012-06-26 Lars Magne Ingebrigtsen <larsi@gnus.org>
2
3 * gnus.texi (POP before SMTP): POP-before-SMTP works with all sending
4 methods, so don't mention smtpmail here.
5
62012-06-26 Wolfgang Jenkner <wjenkner@inode.at>
7
8 * gnus.texi (Picons): Document gnus-picon-properties.
9
102012-06-26 Lars Magne Ingebrigtsen <larsi@gnus.org>
11
12 * gnus.texi: Remove mention of compilation, as that's no longer
13 supported.
14
152012-06-26 Christopher Schmidt <christopher@ch.ristopher.com>
16
17 * gnus.texi (Archived Messages): Mention
18 gnus-gcc-pre-body-encode-hook and gnus-gcc-post-body-encode-hook.
19
202012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
21
22 * gnus.texi (Various Summary Stuff):
23 Remove mention of `gnus-propagate-marks'.
24
252012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
26
27 * gnus.texi: Remove mentions of nnml/nnfolder/nntp backend marks,
28 which no longer exist.
29
302012-06-26 Katsumi Yamaoka <yamaoka@jpl.org>
31
32 * gnus.texi (Archived Messages):
33 Document gnus-gcc-self-resent-messages.
34
352012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
36
37 * message.texi (Mail Variables):
38 Mention the optional user parameter for X-Message-SMTP-Method.
39
402012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
41
42 * gnus.texi (Posting Styles): Mention X-Message-SMTP-Method.
43
44 * message.texi (Mail Variables): Document X-Message-SMTP-Method.
45
462012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
47
48 * gnus.texi (Key Index): Change encoding to utf-8.
49
12012-06-21 Glenn Morris <rgm@gnu.org> 502012-06-21 Glenn Morris <rgm@gnu.org>
2 51
3 * Makefile.in: Rename infodir to buildinfodir throughout. (Bug#11737) 52 * Makefile.in: Rename infodir to buildinfodir throughout. (Bug#11737)
diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi
index 71a06d4461a..df4493789b6 100644
--- a/doc/misc/gnus.texi
+++ b/doc/misc/gnus.texi
@@ -8,7 +8,7 @@
8@syncodeindex vr cp 8@syncodeindex vr cp
9@syncodeindex pg cp 9@syncodeindex pg cp
10 10
11@documentencoding ISO-8859-1 11@documentencoding UTF-8
12 12
13@copying 13@copying
14Copyright @copyright{} 1995-2012 Free Software Foundation, Inc. 14Copyright @copyright{} 1995-2012 Free Software Foundation, Inc.
@@ -663,7 +663,6 @@ Getting News
663* Direct Functions:: Connecting directly to the server. 663* Direct Functions:: Connecting directly to the server.
664* Indirect Functions:: Connecting indirectly to the server. 664* Indirect Functions:: Connecting indirectly to the server.
665* Common Variables:: Understood by several connection functions. 665* Common Variables:: Understood by several connection functions.
666* NNTP marks:: Storing marks for @acronym{NNTP} servers.
667 666
668Getting Mail 667Getting Mail
669 668
@@ -816,7 +815,6 @@ Various
816* Formatting Variables:: You can specify what buffers should look like. 815* Formatting Variables:: You can specify what buffers should look like.
817* Window Layout:: Configuring the Gnus buffer windows. 816* Window Layout:: Configuring the Gnus buffer windows.
818* Faces and Fonts:: How to change how faces look. 817* Faces and Fonts:: How to change how faces look.
819* Compilation:: How to speed Gnus up.
820* Mode Lines:: Displaying information in the mode lines. 818* Mode Lines:: Displaying information in the mode lines.
821* Highlighting and Menus:: Making buffers look all nice and cozy. 819* Highlighting and Menus:: Making buffers look all nice and cozy.
822* Daemons:: Gnus can do things behind your back. 820* Daemons:: Gnus can do things behind your back.
@@ -907,7 +905,8 @@ New Features
907* Quassia Gnus:: Two times two is four, or Gnus 5.6/5.7. 905* Quassia Gnus:: Two times two is four, or Gnus 5.6/5.7.
908* Pterodactyl Gnus:: Pentad also starts with P, AKA Gnus 5.8/5.9. 906* Pterodactyl Gnus:: Pentad also starts with P, AKA Gnus 5.8/5.9.
909* Oort Gnus:: It's big. It's far out. Gnus 5.10/5.11. 907* Oort Gnus:: It's big. It's far out. Gnus 5.10/5.11.
910* No Gnus:: Very punny. 908* No Gnus:: Very punny. Gnus 5.12/5.13
909* Ma Gnus:: Celebrating 25 years of Gnus.
911 910
912Customization 911Customization
913 912
@@ -1066,10 +1065,6 @@ you would typically set this variable to
1066(setq gnus-secondary-select-methods '((nnmbox ""))) 1065(setq gnus-secondary-select-methods '((nnmbox "")))
1067@end lisp 1066@end lisp
1068 1067
1069Note: the @acronym{NNTP} back end stores marks in marks files
1070(@pxref{NNTP marks}). This feature makes it easy to share marks between
1071several Gnus installations, but may slow down things a bit when fetching
1072new articles. @xref{NNTP marks}, for more information.
1073 1068
1074 1069
1075@node The Server is Down 1070@node The Server is Down
@@ -2884,7 +2879,7 @@ composed messages will be @code{Gcc}'d to the current group. If
2884generated, if @code{(gcc-self . "string")} is present, this string will 2879generated, if @code{(gcc-self . "string")} is present, this string will
2885be inserted literally as a @code{gcc} header. This parameter takes 2880be inserted literally as a @code{gcc} header. This parameter takes
2886precedence over any default @code{Gcc} rules as described later 2881precedence over any default @code{Gcc} rules as described later
2887(@pxref{Archived Messages}). 2882(@pxref{Archived Messages}), with the exception for messages to resend.
2888 2883
2889@strong{Caveat}: Adding @code{(gcc-self . t)} to the parameter list of 2884@strong{Caveat}: Adding @code{(gcc-self . t)} to the parameter list of
2890@code{nntp} groups (or the like) isn't valid. An @code{nntp} server 2885@code{nntp} groups (or the like) isn't valid. An @code{nntp} server
@@ -3027,6 +3022,7 @@ like this in the group parameters:
3027@example 3022@example
3028(posting-style 3023(posting-style
3029 (name "Funky Name") 3024 (name "Funky Name")
3025 ("X-Message-SMTP-Method" "smtp smtp.example.org 587")
3030 ("X-My-Header" "Funky Value") 3026 ("X-My-Header" "Funky Value")
3031 (signature "Funky Signature")) 3027 (signature "Funky Signature"))
3032@end example 3028@end example
@@ -4293,12 +4289,11 @@ default is @code{nil} in Emacs, or is the aliasee of the coding system
4293named @code{file-name} (a certain coding system of which an alias is 4289named @code{file-name} (a certain coding system of which an alias is
4294@code{file-name}) in XEmacs. 4290@code{file-name}) in XEmacs.
4295 4291
4296The @code{nnml} back end, the @code{nnrss} back end, the @acronym{NNTP} 4292The @code{nnml} back end, the @code{nnrss} back end, the agent, and
4297marks feature (@pxref{NNTP marks}), the agent, and the cache use 4293the cache use non-@acronym{ASCII} group names in those files and
4298non-@acronym{ASCII} group names in those files and directories. This 4294directories. This variable overrides the value of
4299variable overrides the value of @code{file-name-coding-system} which 4295@code{file-name-coding-system} which specifies the coding system used
4300specifies the coding system used when encoding and decoding those file 4296when encoding and decoding those file names and directory names.
4301names and directory names.
4302 4297
4303In XEmacs (with the @code{mule} feature), @code{file-name-coding-system} 4298In XEmacs (with the @code{mule} feature), @code{file-name-coding-system}
4304is the only means to specify the coding system used to encode and decode 4299is the only means to specify the coding system used to encode and decode
@@ -8986,7 +8981,7 @@ Translate many non-@acronym{ASCII} characters into their
8986@acronym{ASCII} equivalents (@code{gnus-article-treat-non-ascii}). 8981@acronym{ASCII} equivalents (@code{gnus-article-treat-non-ascii}).
8987This is mostly useful if you're on a terminal that has a limited font 8982This is mostly useful if you're on a terminal that has a limited font
8988and doesn't show accented characters, ``advanced'' punctuation, and the 8983and doesn't show accented characters, ``advanced'' punctuation, and the
8989like. For instance, @samp{»} is translated into @samp{>>}, and so on. 8984like. For instance, @samp{»} is translated into @samp{>>}, and so on.
8990 8985
8991@item W Y f 8986@item W Y f
8992@kindex W Y f (Summary) 8987@kindex W Y f (Summary)
@@ -10819,12 +10814,6 @@ buffers. For example:
10819 10814
10820Also @pxref{Group Parameters}. 10815Also @pxref{Group Parameters}.
10821 10816
10822@vindex gnus-propagate-marks
10823@item gnus-propagate-marks
10824If non-@code{nil}, propagate marks to the backends for possible
10825storing. @xref{NNTP marks}, and friends, for a more fine-grained
10826sieve.
10827
10828@end table 10817@end table
10829 10818
10830 10819
@@ -12404,32 +12393,25 @@ value suitable for your system.
12404@xref{Mail Variables, ,Mail Variables,message,Message manual}, for more 12393@xref{Mail Variables, ,Mail Variables,message,Message manual}, for more
12405information. 12394information.
12406 12395
12396
12407@node POP before SMTP 12397@node POP before SMTP
12408@section POP before SMTP 12398@section POP before SMTP
12409@cindex pop before smtp 12399@cindex pop before smtp
12410@findex message-smtpmail-send-it
12411@findex mail-source-touch-pop 12400@findex mail-source-touch-pop
12412 12401
12413Does your @acronym{ISP} require the @acronym{POP}-before-@acronym{SMTP} 12402Does your @acronym{ISP} use @acronym{POP}-before-@acronym{SMTP}
12414authentication? It is whether you need to connect to the @acronym{POP} 12403authentication? This authentication method simply requires you to
12415mail server within a certain time before sending mails. If so, there is 12404contact the @acronym{POP} server before sending email. To do that,
12416a convenient way. To do that, put the following lines in your 12405put the following lines in your @file{~/.gnus.el} file:
12417@file{~/.gnus.el} file:
12418 12406
12419@lisp 12407@lisp
12420(setq message-send-mail-function 'message-smtpmail-send-it)
12421(add-hook 'message-send-mail-hook 'mail-source-touch-pop) 12408(add-hook 'message-send-mail-hook 'mail-source-touch-pop)
12422@end lisp 12409@end lisp
12423 12410
12424@noindent 12411@noindent
12425It means to let Gnus connect to the @acronym{POP} mail server in advance 12412The @code{mail-source-touch-pop} function does @acronym{POP}
12426whenever you send a mail. The @code{mail-source-touch-pop} function 12413authentication according to the value of @code{mail-sources} without
12427does only a @acronym{POP} authentication according to the value of 12414fetching mails, just before sending a mail. @xref{Mail Sources}.
12428@code{mail-sources} without fetching mails, just before sending a mail.
12429Note that you have to use @code{message-smtpmail-send-it} which runs
12430@code{message-send-mail-hook} rather than @code{smtpmail-send-it} and
12431set the value of @code{mail-sources} for a @acronym{POP} connection
12432correctly. @xref{Mail Sources}.
12433 12415
12434If you have two or more @acronym{POP} mail servers set in 12416If you have two or more @acronym{POP} mail servers set in
12435@code{mail-sources}, you may want to specify one of them to 12417@code{mail-sources}, you may want to specify one of them to
@@ -12457,6 +12439,7 @@ Otherwise, bind it dynamically only when performing the
12457 (mail-source-touch-pop)))) 12439 (mail-source-touch-pop))))
12458@end lisp 12440@end lisp
12459 12441
12442
12460@node Mail and Post 12443@node Mail and Post
12461@section Mail and Post 12444@section Mail and Post
12462 12445
@@ -12674,6 +12657,35 @@ and matches the Gcc group name, attach files as external parts; if it is
12674non-@code{nil}, the behavior is the same as @code{all}, but it may be 12657non-@code{nil}, the behavior is the same as @code{all}, but it may be
12675changed in the future. 12658changed in the future.
12676 12659
12660@item gnus-gcc-self-resent-messages
12661@vindex gnus-gcc-self-resent-messages
12662Like the @code{gcc-self} group parameter, applied only for unmodified
12663messages that @code{gnus-summary-resend-message} (@pxref{Summary Mail
12664Commands}) resends. Non-@code{nil} value of this variable takes
12665precedence over any existing @code{Gcc} header.
12666
12667If this is @code{none}, no @code{Gcc} copy will be made. If this is
12668@code{t}, messages resent will be @code{Gcc} copied to the current
12669group. If this is a string, it specifies a group to which resent
12670messages will be @code{Gcc} copied. If this is @code{nil}, @code{Gcc}
12671will be done according to existing @code{Gcc} header(s), if any. If
12672this is @code{no-gcc-self}, that is the default, resent messages will be
12673@code{Gcc} copied to groups that existing @code{Gcc} header specifies,
12674except for the current group.
12675
12676@item gnus-gcc-pre-body-encode-hook
12677@vindex gnus-gcc-pre-body-encode-hook
12678@itemx gnus-gcc-post-body-encode-hook
12679@vindex gnus-gcc-post-body-encode-hook
12680
12681These hooks are run before/after encoding the message body of the Gcc
12682copy of a sent message. The current buffer (when the hook is run)
12683contains the message including the message header. Changes made to
12684the message will only affect the Gcc copy, but not the original
12685message. You can use these hooks to edit the copy (and influence
12686subsequent transformations), e.g. remove MML secure tags
12687(@pxref{Signing and encrypting}).
12688
12677@end table 12689@end table
12678 12690
12679 12691
@@ -12805,6 +12817,7 @@ So here's a new example:
12805 (signature-file "~/.work-signature") 12817 (signature-file "~/.work-signature")
12806 (address "user@@bar.foo") 12818 (address "user@@bar.foo")
12807 (body "You are fired.\n\nSincerely, your boss.") 12819 (body "You are fired.\n\nSincerely, your boss.")
12820 ("X-Message-SMTP-Method" "smtp smtp.example.org 587")
12808 (organization "Important Work, Inc")) 12821 (organization "Important Work, Inc"))
12809 ("nnml:.*" 12822 ("nnml:.*"
12810 (From (with-current-buffer gnus-article-buffer 12823 (From (with-current-buffer gnus-article-buffer
@@ -12819,6 +12832,13 @@ if you fill many roles.
12819You may also use @code{message-alternative-emails} instead. 12832You may also use @code{message-alternative-emails} instead.
12820@xref{Message Headers, ,Message Headers, message, Message Manual}. 12833@xref{Message Headers, ,Message Headers, message, Message Manual}.
12821 12834
12835Of particular interest in the ``work-mail'' style is the
12836@samp{X-Message-SMTP-Method} header. It specifies how to send the
12837outgoing email. You may want to sent certain emails through certain
12838@acronym{SMTP} servers due to company policies, for instance.
12839@xref{Mail Variables, ,Message Variables, message, Message Manual}.
12840
12841
12822@node Drafts 12842@node Drafts
12823@section Drafts 12843@section Drafts
12824@cindex drafts 12844@cindex drafts
@@ -13744,7 +13764,6 @@ don't update their active files often, this can help.
13744* Direct Functions:: Connecting directly to the server. 13764* Direct Functions:: Connecting directly to the server.
13745* Indirect Functions:: Connecting indirectly to the server. 13765* Indirect Functions:: Connecting indirectly to the server.
13746* Common Variables:: Understood by several connection functions. 13766* Common Variables:: Understood by several connection functions.
13747* NNTP marks:: Storing marks for @acronym{NNTP} servers.
13748@end menu 13767@end menu
13749 13768
13750 13769
@@ -14015,53 +14034,6 @@ is @samp{()}.
14015 14034
14016@end table 14035@end table
14017 14036
14018@node NNTP marks
14019@subsubsection NNTP marks
14020@cindex storing NNTP marks
14021
14022Gnus stores marks (@pxref{Marking Articles}) for @acronym{NNTP}
14023servers in marks files. A marks file records what marks you have set
14024in a group and each file is specific to the corresponding server.
14025Marks files are stored in @file{~/News/marks}
14026(@code{nntp-marks-directory}) under a classic hierarchy resembling
14027that of a news server, for example marks for the group
14028@samp{gmane.discuss} on the news.gmane.org server will be stored in
14029the file @file{~/News/marks/news.gmane.org/gmane/discuss/.marks}.
14030
14031Marks files are useful because you can copy the @file{~/News/marks}
14032directory (using rsync, scp or whatever) to another Gnus installation,
14033and it will realize what articles you have read and marked. The data
14034in @file{~/News/marks} has priority over the same data in
14035@file{~/.newsrc.eld}.
14036
14037Note that marks files are very much server-specific: Gnus remembers
14038the article numbers so if you don't use the same servers on both
14039installations things are most likely to break (most @acronym{NNTP}
14040servers do not use the same article numbers as any other server).
14041However, if you use servers A, B, C on one installation and servers A,
14042D, E on the other, you can sync the marks files for A and then you'll
14043get synchronization for that server between the two installations.
14044
14045Using @acronym{NNTP} marks can possibly incur a performance penalty so
14046if Gnus feels sluggish, try setting the @code{nntp-marks-is-evil}
14047variable to @code{t}. Marks will then be stored in @file{~/.newsrc.eld}.
14048
14049Related variables:
14050
14051@table @code
14052
14053@item nntp-marks-is-evil
14054@vindex nntp-marks-is-evil
14055If non-@code{nil}, this back end will ignore any marks files. The
14056default is @code{nil}.
14057
14058@item nntp-marks-directory
14059@vindex nntp-marks-directory
14060The directory where marks for nntp groups will be stored.
14061
14062@end table
14063
14064
14065@node News Spool 14037@node News Spool
14066@subsection News Spool 14038@subsection News Spool
14067@cindex nnspool 14039@cindex nnspool
@@ -16152,22 +16124,6 @@ splitting. It has to create lots of files, and it also generates
16152@acronym{NOV} databases for the incoming mails. This makes it possibly the 16124@acronym{NOV} databases for the incoming mails. This makes it possibly the
16153fastest back end when it comes to reading mail. 16125fastest back end when it comes to reading mail.
16154 16126
16155@cindex self contained nnml servers
16156@cindex marks
16157When the marks file is used (which it is by default), @code{nnml}
16158servers have the property that you may backup them using @code{tar} or
16159similar, and later be able to restore them into Gnus (by adding the
16160proper @code{nnml} server) and have all your marks be preserved. Marks
16161for a group are usually stored in the @code{.marks} file (but see
16162@code{nnml-marks-file-name}) within each @code{nnml} group's directory.
16163Individual @code{nnml} groups are also possible to backup, use @kbd{G m}
16164to restore the group (after restoring the backup into the nnml
16165directory).
16166
16167If for some reason you believe your @file{.marks} files are screwed
16168up, you can just delete them all. Gnus will then correctly regenerate
16169them next time it starts.
16170
16171Virtual server settings: 16127Virtual server settings:
16172 16128
16173@table @code 16129@table @code
@@ -16205,15 +16161,6 @@ The name of the @acronym{NOV} files. The default is @file{.overview}.
16205@vindex nnml-prepare-save-mail-hook 16161@vindex nnml-prepare-save-mail-hook
16206Hook run narrowed to an article before saving. 16162Hook run narrowed to an article before saving.
16207 16163
16208@item nnml-marks-is-evil
16209@vindex nnml-marks-is-evil
16210If non-@code{nil}, this back end will ignore any @sc{marks} files. The
16211default is @code{nil}.
16212
16213@item nnml-marks-file-name
16214@vindex nnml-marks-file-name
16215The name of the @dfn{marks} files. The default is @file{.marks}.
16216
16217@item nnml-use-compressed-files 16164@item nnml-use-compressed-files
16218@vindex nnml-use-compressed-files 16165@vindex nnml-use-compressed-files
16219If non-@code{nil}, @code{nnml} will allow using compressed message 16166If non-@code{nil}, @code{nnml} will allow using compressed message
@@ -16554,19 +16501,6 @@ separate file. Each file is in the standard Un*x mbox format.
16554@code{nnfolder} will add extra headers to keep track of article 16501@code{nnfolder} will add extra headers to keep track of article
16555numbers and arrival dates. 16502numbers and arrival dates.
16556 16503
16557@cindex self contained nnfolder servers
16558@cindex marks
16559When the marks file is used (which it is by default), @code{nnfolder}
16560servers have the property that you may backup them using @code{tar} or
16561similar, and later be able to restore them into Gnus (by adding the
16562proper @code{nnfolder} server) and have all your marks be preserved.
16563Marks for a group are usually stored in a file named as the mbox file
16564with @code{.mrk} concatenated to it (but see
16565@code{nnfolder-marks-file-suffix}) within the @code{nnfolder}
16566directory. Individual @code{nnfolder} groups are also possible to
16567backup, use @kbd{G m} to restore the group (after restoring the backup
16568into the @code{nnfolder} directory).
16569
16570Virtual server settings: 16504Virtual server settings:
16571 16505
16572@table @code 16506@table @code
@@ -16625,20 +16559,6 @@ The extension for @acronym{NOV} files. The default is @file{.nov}.
16625The directory where the @acronym{NOV} files should be stored. If 16559The directory where the @acronym{NOV} files should be stored. If
16626@code{nil}, @code{nnfolder-directory} is used. 16560@code{nil}, @code{nnfolder-directory} is used.
16627 16561
16628@item nnfolder-marks-is-evil
16629@vindex nnfolder-marks-is-evil
16630If non-@code{nil}, this back end will ignore any @sc{marks} files. The
16631default is @code{nil}.
16632
16633@item nnfolder-marks-file-suffix
16634@vindex nnfolder-marks-file-suffix
16635The extension for @sc{marks} files. The default is @file{.mrk}.
16636
16637@item nnfolder-marks-directory
16638@vindex nnfolder-marks-directory
16639The directory where the @sc{marks} files should be stored. If
16640@code{nil}, @code{nnfolder-directory} is used.
16641
16642@end table 16562@end table
16643 16563
16644 16564
@@ -16799,9 +16719,7 @@ undergo treatment such as duplicate checking.
16799@code{nnmaildir} stores article marks for a given group in the 16719@code{nnmaildir} stores article marks for a given group in the
16800corresponding maildir, in a way designed so that it's easy to manipulate 16720corresponding maildir, in a way designed so that it's easy to manipulate
16801them from outside Gnus. You can tar up a maildir, unpack it somewhere 16721them from outside Gnus. You can tar up a maildir, unpack it somewhere
16802else, and still have your marks. @code{nnml} also stores marks, but 16722else, and still have your marks.
16803it's not as easy to work with them from outside Gnus as with
16804@code{nnmaildir}.
16805 16723
16806@code{nnmaildir} uses a significant amount of memory to speed things up. 16724@code{nnmaildir} uses a significant amount of memory to speed things up.
16807(It keeps in memory some of the things that @code{nnml} stores in files 16725(It keeps in memory some of the things that @code{nnml} stores in files
@@ -16893,16 +16811,6 @@ adding a server definition pointing to that directory in Gnus. The
16893might interfere with overwriting data, so you may want to shut down Gnus 16811might interfere with overwriting data, so you may want to shut down Gnus
16894before you restore the data. 16812before you restore the data.
16895 16813
16896It is also possible to archive individual @code{nnml},
16897@code{nnfolder}, or @code{nnmaildir} groups, while preserving marks.
16898For @code{nnml} or @code{nnmaildir}, you copy all files in the group's
16899directory. For @code{nnfolder} you need to copy both the base folder
16900file itself (@file{FOO}, say), and the marks file (@file{FOO.mrk} in
16901this example). Restoring the group is done with @kbd{G m} from the Group
16902buffer. The last step makes Gnus notice the new directory.
16903@code{nnmaildir} notices the new directory automatically, so @kbd{G m}
16904is unnecessary in that case.
16905
16906@node Web Searches 16814@node Web Searches
16907@subsection Web Searches 16815@subsection Web Searches
16908@cindex nnweb 16816@cindex nnweb
@@ -20875,7 +20783,7 @@ then this operator will return @code{false}.
20875 20783
20876@item ! 20784@item !
20877@itemx not 20785@itemx not
20878@itemx ¬ 20786@itemx ¬
20879This logical operator only takes a single argument. It returns the 20787This logical operator only takes a single argument. It returns the
20880logical negation of the value of its argument. 20788logical negation of the value of its argument.
20881 20789
@@ -22168,7 +22076,6 @@ to you, using @kbd{G b u} and updating the group will usually fix this.
22168* Formatting Variables:: You can specify what buffers should look like. 22076* Formatting Variables:: You can specify what buffers should look like.
22169* Window Layout:: Configuring the Gnus buffer windows. 22077* Window Layout:: Configuring the Gnus buffer windows.
22170* Faces and Fonts:: How to change how faces look. 22078* Faces and Fonts:: How to change how faces look.
22171* Compilation:: How to speed Gnus up.
22172* Mode Lines:: Displaying information in the mode lines. 22079* Mode Lines:: Displaying information in the mode lines.
22173* Highlighting and Menus:: Making buffers look all nice and cozy. 22080* Highlighting and Menus:: Making buffers look all nice and cozy.
22174* Daemons:: Gnus can do things behind your back. 22081* Daemons:: Gnus can do things behind your back.
@@ -22465,11 +22372,6 @@ than 6 characters to make it look nice in columns.)
22465Ignoring is done first; then cutting; then maxing; and then as the very 22372Ignoring is done first; then cutting; then maxing; and then as the very
22466last operation, padding. 22373last operation, padding.
22467 22374
22468If you use lots of these advanced thingies, you'll find that Gnus gets
22469quite slow. This can be helped enormously by running @kbd{M-x
22470gnus-compile} when you are satisfied with the look of your lines.
22471@xref{Compilation}.
22472
22473 22375
22474@node User-Defined Specs 22376@node User-Defined Specs
22475@subsection User-Defined Specs 22377@subsection User-Defined Specs
@@ -22515,7 +22417,7 @@ and so on. Create as many faces as you wish. The same goes for the
22515@samp{hello} mouse-highlighted with @code{gnus-mouse-face-3}. 22417@samp{hello} mouse-highlighted with @code{gnus-mouse-face-3}.
22516 22418
22517@cindex %<<, %>>, guillemets 22419@cindex %<<, %>>, guillemets
22518@c @cindex %<<, %>>, %«, %», guillemets 22420@c @cindex %<<, %>>, %«, %», guillemets
22519@vindex gnus-balloon-face-0 22421@vindex gnus-balloon-face-0
22520Text inside the @samp{%<<} and @samp{%>>} specifiers will get the 22422Text inside the @samp{%<<} and @samp{%>>} specifiers will get the
22521special @code{balloon-help} property set to 22423special @code{balloon-help} property set to
@@ -22978,30 +22880,6 @@ the face you want to alter, and alter it via the standard Customize
22978interface. 22880interface.
22979 22881
22980 22882
22981@node Compilation
22982@section Compilation
22983@cindex compilation
22984@cindex byte-compilation
22985
22986@findex gnus-compile
22987
22988Remember all those line format specification variables?
22989@code{gnus-summary-line-format}, @code{gnus-group-line-format}, and so
22990on. Now, Gnus will of course heed whatever these variables are, but,
22991unfortunately, changing them will mean a quite significant slow-down.
22992(The default values of these variables have byte-compiled functions
22993associated with them, while the user-generated versions do not, of
22994course.)
22995
22996To help with this, you can run @kbd{M-x gnus-compile} after you've
22997fiddled around with the variables and feel that you're (kind of)
22998satisfied. This will result in the new specs being byte-compiled, and
22999you'll get top speed again. Gnus will save these compiled specs in the
23000@file{.newsrc.eld} file. (User-defined functions aren't compiled by
23001this function, though---you should compile them yourself by sticking
23002them into the @file{~/.gnus.el} file and byte-compiling that file.)
23003
23004
23005@node Mode Lines 22883@node Mode Lines
23006@section Mode Lines 22884@section Mode Lines
23007@cindex mode lines 22885@cindex mode lines
@@ -23656,6 +23534,10 @@ The variable @code{gnus-picon-style} controls how picons are displayed.
23656If @code{inline}, the textual representation is replaced. If 23534If @code{inline}, the textual representation is replaced. If
23657@code{right}, picons are added right to the textual representation. 23535@code{right}, picons are added right to the textual representation.
23658 23536
23537@vindex gnus-picon-properties
23538The value of the variable @code{gnus-picon-properties} is a list of
23539properties applied to picons.
23540
23659The following variables offer control over where things are located. 23541The following variables offer control over where things are located.
23660 23542
23661@table @code 23543@table @code
@@ -26409,6 +26291,7 @@ renamed it back again to ``Gnus''. But in mixed case. ``Gnus'' vs.
26409@cindex Pterodactyl Gnus 26291@cindex Pterodactyl Gnus
26410@cindex Oort Gnus 26292@cindex Oort Gnus
26411@cindex No Gnus 26293@cindex No Gnus
26294@cindex Ma Gnus
26412@cindex Gnus versions 26295@cindex Gnus versions
26413 26296
26414The first ``proper'' release of Gnus 5 was done in November 1995 when it 26297The first ``proper'' release of Gnus 5 was done in November 1995 when it
@@ -26437,12 +26320,15 @@ On April 19, 2010 Gnus development was moved to Git. See
26437http://git.gnus.org for details (http://www.gnus.org will be updated 26320http://git.gnus.org for details (http://www.gnus.org will be updated
26438with the information when possible). 26321with the information when possible).
26439 26322
26323On the January 31th 2012, Ma Gnus was begun.
26324
26440If you happen upon a version of Gnus that has a prefixed name -- 26325If you happen upon a version of Gnus that has a prefixed name --
26441``(ding) Gnus'', ``September Gnus'', ``Red Gnus'', ``Quassia Gnus'', 26326``(ding) Gnus'', ``September Gnus'', ``Red Gnus'', ``Quassia Gnus'',
26442``Pterodactyl Gnus'', ``Oort Gnus'', ``No Gnus'' -- don't panic. 26327``Pterodactyl Gnus'', ``Oort Gnus'', ``No Gnus'', ``Ma Gnus'' -- don't
26443Don't let it know that you're frightened. Back away. Slowly. Whatever 26328panic. Don't let it know that you're frightened. Back away. Slowly.
26444you do, don't run. Walk away, calmly, until you're out of its reach. 26329Whatever you do, don't run. Walk away, calmly, until you're out of
26445Find a proper released version of Gnus and snuggle up to that instead. 26330its reach. Find a proper released version of Gnus and snuggle up to
26331that instead.
26446 26332
26447 26333
26448@node Why? 26334@node Why?
@@ -27045,7 +26931,8 @@ actually are people who are using Gnus. Who'd'a thunk it!
27045* Quassia Gnus:: Two times two is four, or Gnus 5.6/5.7. 26931* Quassia Gnus:: Two times two is four, or Gnus 5.6/5.7.
27046* Pterodactyl Gnus:: Pentad also starts with P, AKA Gnus 5.8/5.9. 26932* Pterodactyl Gnus:: Pentad also starts with P, AKA Gnus 5.8/5.9.
27047* Oort Gnus:: It's big. It's far out. Gnus 5.10/5.11. 26933* Oort Gnus:: It's big. It's far out. Gnus 5.10/5.11.
27048* No Gnus:: Very punny. 26934* No Gnus:: Very punny. Gnus 5.12/5.13.
26935* Ma Gnus:: Celebrating 25 years of Gnus.
27049@end menu 26936@end menu
27050 26937
27051These lists are, of course, just @emph{short} overviews of the 26938These lists are, of course, just @emph{short} overviews of the
@@ -28420,6 +28307,32 @@ New features in No Gnus:
28420 28307
28421@include gnus-news.texi 28308@include gnus-news.texi
28422 28309
28310@node Ma Gnus
28311@subsubsection Ma Gnus
28312@cindex Ma Gnus
28313
28314I'm sure there will be lots of text here. It's really spelled 真
28315Gnus.
28316
28317New features in Ma Gnus:
28318
28319@itemize @bullet
28320
28321@item Changes in Message mode and related Gnus features
28322@c ****************************************************
28323
28324@itemize @bullet
28325
28326@item
28327The new hooks @code{gnus-gcc-pre-body-encode-hook} and
28328@code{gnus-gcc-post-body-encode-hook} are run before/after encoding
28329the message body of the Gcc copy of a sent message. See
28330@xref{Archived Messages}.
28331
28332@end itemize
28333
28334@end itemize
28335
28423@iftex 28336@iftex
28424 28337
28425@page 28338@page
@@ -30642,5 +30555,5 @@ former). The manual is unambiguous, but it can be confusing.
30642 30555
30643@c Local Variables: 30556@c Local Variables:
30644@c mode: texinfo 30557@c mode: texinfo
30645@c coding: iso-8859-1 30558@c coding: utf-8
30646@c End: 30559@c End:
diff --git a/doc/misc/message.texi b/doc/misc/message.texi
index ac5811a0ce8..ef752a96fdc 100644
--- a/doc/misc/message.texi
+++ b/doc/misc/message.texi
@@ -1637,6 +1637,40 @@ To the thing similar to this, there is
1637requires the @acronym{POP}-before-@acronym{SMTP} authentication. 1637requires the @acronym{POP}-before-@acronym{SMTP} authentication.
1638@xref{POP before SMTP, , POP before SMTP, gnus, The Gnus Manual}. 1638@xref{POP before SMTP, , POP before SMTP, gnus, The Gnus Manual}.
1639 1639
1640@cindex X-Message-SMTP-Method
1641If you have a complex @acronym{SMTP} setup, and want some messages to
1642go via one mail server, and other messages to go through another, you
1643can use the @samp{X-Message-SMTP-Method} header. These are the
1644supported values:
1645
1646@table @samp
1647@item smtpmail
1648
1649@example
1650X-Message-SMTP-Method: smtp smtp.fsf.org 587
1651@end example
1652
1653This will send the message via @samp{smtp.fsf.org}, using port 587.
1654
1655@example
1656X-Message-SMTP-Method: smtp smtp.fsf.org 587 other-user
1657@end example
1658
1659This is the same as the above, but uses @samp{other-user} as the user
1660name when authenticating. This is handy if you have several
1661@acronym{SMTP} accounts on the same server.
1662
1663@item sendmail
1664
1665@example
1666X-Message-SMTP-Method: sendmail
1667@end example
1668
1669This will send the message via the locally installed sendmail/exim/etc
1670installation.
1671
1672@end table
1673
1640@item message-mh-deletable-headers 1674@item message-mh-deletable-headers
1641@vindex message-mh-deletable-headers 1675@vindex message-mh-deletable-headers
1642Most versions of MH doesn't like being fed messages that contain the 1676Most versions of MH doesn't like being fed messages that contain the
diff --git a/etc/GNUS-NEWS b/etc/GNUS-NEWS
index 086e44f2bba..c5fca9de929 100644
--- a/etc/GNUS-NEWS
+++ b/etc/GNUS-NEWS
@@ -7,257 +7,35 @@ Please send Gnus bug reports to bugs@gnus.org.
7For older news, see Gnus info node "New Features". 7For older news, see Gnus info node "New Features".
8 8
9 9
10* Installation changes 10* New features
11 11
12** Upgrading from previous (stable) version if you have used No Gnus. 12** If you have the "tnef" program installed, Gnus will display ms-tnef
13 files, aka "winmail.dat".
13 14
14If you have tried No Gnus (the unstable Gnus branch leading to this 15** Archives (like tar and zip files) will be automatically unpacked,
15release) but went back to a stable version, be careful when upgrading to 16 and the files inside the packages will be displayed as MIME parts.
16this version. In particular, you will probably want to remove the
17`~/News/marks' directory (perhaps selectively), so that flags are read
18from your `~/.newsrc.eld' instead of from the stale marks file, where
19this release will store flags for nntp. See a later entry for more
20information about nntp marks. Note that downgrading isn't safe in
21general.
22 17
23** Incompatibility when switching from Emacs 23 to Emacs 22 In Emacs 23, 18** shr has a new command `z' that cycles through image sizes.
24Gnus uses Emacs' new internal coding system `utf-8-emacs' for saving
25articles drafts and `~/.newsrc.eld'. These files may not be read
26correctly in Emacs 22 and below. If you want to use Gnus across
27different Emacs versions, you may set `mm-auto-save-coding-system' to
28`emacs-mule'.
29 19
30** Lisp files are now installed in `.../site-lisp/gnus/' by default. It 20** `backtab' in the summary buffer now selects the previous link in
31defaulted to `.../site-lisp/' formerly. In addition to this, the new 21 the article buffer.
32installer issues a warning if other Gnus installations which will shadow
33the latest one are detected. You can then remove those shadows manually
34or remove them using `make remove-installed-shadows'.
35 22
36** The installation directory name is allowed to have spaces and/or tabs. 23** Using the "X-Message-SMTP-Method" header in Message buffers now
24 allows specifying how messages are to be sent. For example:
37 25
38 26 X-Message-SMTP-Method: smtp smtp.fsf.org 587
39* New packages and libraries within Gnus
40
41** Gnus includes the Emacs Lisp SASL library.
42
43This provides a clean API to SASL mechanisms from within Emacs. The
44user visible aspects of this, compared to the earlier situation, include
45support for DIGEST-MD5 and NTLM. *Note Emacs SASL: (sasl)Top.
46
47** ManageSieve connections uses the SASL library by default.
48
49The primary change this brings is support for DIGEST-MD5 and NTLM, when
50the server supports it.
51
52** Gnus includes a password cache mechanism in password-cache.el.
53
54It is enabled by default (see `password-cache'), with a short timeout of
5516 seconds (see `password-cache-expiry'). If PGG is used as the PGP
56back end, the PGP passphrase is managed by this mechanism. Passwords
57for ManageSieve connections are managed by this mechanism, after
58querying the user about whether to do so.
59
60** Using EasyPG with Gnus When EasyPG, is available, Gnus will use it
61instead of PGG. EasyPG is an Emacs user interface to GNU Privacy Guard.
62 *Note EasyPG Assistant user's manual: (epa)Top. EasyPG is included in
63Emacs 23 and available separately as well.
64
65
66* Changes in group mode
67
68** Old intermediate incoming mail files (`Incoming*') are deleted after a
69couple of days, not immediately. *Note Mail Source Customization::.
70(New in Gnus 5.10.10 / Emacs 22.2)
71
72
73
74* Changes in summary and article mode
75
76** Gnus now supports sticky article buffers. Those are article buffers
77that are not reused when you select another article. *Note Sticky
78Articles::.
79
80** Gnus can selectively display `text/html' articles with a WWW browser
81with `K H'. *Note MIME Commands::.
82
83** International host names (IDNA) can now be decoded inside article bodies
84using `W i' (`gnus-summary-idna-message'). This requires that GNU Libidn
85(`http://www.gnu.org/software/libidn/') has been installed.
86
87** The non-ASCII group names handling has been much improved. The back
88ends that fully support non-ASCII group names are now `nntp', `nnml',
89and `nnrss'. Also the agent, the cache, and the marks features work
90with those back ends. *Note Non-ASCII Group Names::.
91 27
92** Gnus now displays DNS master files sent as text/dns using dns-mode. 28** Gnus keeps track of non-existent articles for nnimap groups, so
29 that sparse IMAP folders now list a correct number of messages in
30 them.
93 31
94** Gnus supports new limiting commands in the Summary buffer: `/ r' 32** Gnus will guess the real type of MIME parts of type
95(`gnus-summary-limit-to-replied') and `/ R' 33 application/octet-stream based on the file suffix. So an
96(`gnus-summary-limit-to-recipient'). *Note Limiting::. 34 application/octet-stream with a name of "rms.jpg" will be displayed
97 35 as an image/jpeg type by default, for instance.
98** You can now fetch all ticked articles from the server using `Y t'
99(`gnus-summary-insert-ticked-articles'). *Note Summary Generation
100Commands::.
101
102** Gnus supports a new sort command in the Summary buffer: `C-c C-s C-t'
103(`gnus-summary-sort-by-recipient'). *Note Summary Sorting::.
104
105** S/MIME now features LDAP user certificate searches. You need to
106configure the server in `smime-ldap-host-list'.
107
108** URLs inside OpenPGP headers are retrieved and imported to your PGP key
109ring when you click on them.
110
111** Picons can be displayed right from the textual address, see
112`gnus-picon-style'. *Note Picons::.
113
114** ANSI SGR control sequences can be transformed using `W A'.
115
116ANSI sequences are used in some Chinese hierarchies for highlighting
117articles (`gnus-article-treat-ansi-sequences').
118
119** Gnus now MIME decodes articles even when they lack "MIME-Version" header.
120This changes the default of `gnus-article-loose-mime'.
121
122** `gnus-decay-scores' can be a regexp matching score files. For example,
123set it to `\\.ADAPT\\'' and only adaptive score files will be decayed.
124 *Note Score Decays::.
125
126** Strings prefixing to the `To' and `Newsgroup' headers in summary lines
127when using `gnus-ignored-from-addresses' can be customized with
128`gnus-summary-to-prefix' and `gnus-summary-newsgroup-prefix'. *Note To
129From Newsgroups::.
130
131** You can replace MIME parts with external bodies. See
132`gnus-mime-replace-part' and `gnus-article-replace-part'. *Note MIME
133Commands::, *note Using MIME::.
134
135** The option `mm-fill-flowed' can be used to disable treatment of
136format=flowed messages. Also, flowed text is disabled when sending
137inline PGP signed messages. *Note Flowed text: (emacs-mime)Flowed text.
138(New in Gnus 5.10.7)
139
140** Now the new command `S W' (`gnus-article-wide-reply-with-original') for
141a wide reply in the article buffer yanks a text that is in the active
142region, if it is set, as well as the `R'
143(`gnus-article-reply-with-original') command. Note that the `R' command
144in the article buffer no longer accepts a prefix argument, which was
145used to make it do a wide reply. *Note Article Keymap::.
146
147** The new command `C-h b' (`gnus-article-describe-bindings') used in the
148article buffer now shows not only the article commands but also the real
149summary commands that are accessible from the article buffer.
150
151
152
153* Changes in Message mode
154 36
155** Gnus now supports the "hashcash" client puzzle anti-spam mechanism. Use 37** `nnimap-inbox' can now be a list of mail box names.
156`(setq message-generate-hashcash t)' to enable. *Note Hashcash::. 38
157
158** You can now drag and drop attachments to the Message buffer. See
159`mml-dnd-protocol-alist' and `mml-dnd-attach-options'. *Note MIME:
160(message)MIME.
161
162** The option `message-yank-empty-prefix' now controls how empty lines are
163prefixed in cited text. *Note Insertion Variables: (message)Insertion
164Variables.
165
166** Gnus uses narrowing to hide headers in Message buffers. The
167`References' header is hidden by default. To make all headers visible,
168use `(setq message-hidden-headers nil)'. *Note Message Headers:
169(message)Message Headers.
170
171** You can highlight different levels of citations like in the article
172buffer. See `gnus-message-highlight-citation'.
173
174** `auto-fill-mode' is enabled by default in Message mode. See
175`message-fill-column'. *Note Message Headers: (message)Various Message
176Variables.
177
178** You can now store signature files in a special directory named
179`message-signature-directory'.
180
181** The option `message-citation-line-format' controls the format of the
182"Whomever writes:" line. You need to set
183`message-citation-line-function' to
184`message-insert-formatted-citation-line' as well.
185
186
187* Changes in back ends
188
189** The nntp back end stores article marks in `~/News/marks'.
190
191The directory can be changed using the (customizable) variable
192`nntp-marks-directory', and marks can be disabled using the (back end)
193variable `nntp-marks-is-evil'. The advantage of this is that you can
194copy `~/News/marks' (using rsync, scp or whatever) to another Gnus
195installation, and it will realize what articles you have read and
196marked. The data in `~/News/marks' has priority over the same data in
197`~/.newsrc.eld'.
198
199** You can import and export your RSS subscriptions from OPML files. *Note
200RSS::.
201
202** IMAP identity (RFC 2971) is supported.
203
204By default, Gnus does not send any information about itself, but you can
205customize it using the variable `nnimap-id'.
206
207** The `nnrss' back end now supports multilingual text. Non-ASCII group
208names for the `nnrss' groups are also supported. *Note RSS::.
209
210** Retrieving mail with POP3 is supported over SSL/TLS and with StartTLS.
211
212** The nnml back end allows other compression programs beside `gzip' for
213compressed message files. *Note Mail Spool::.
214
215** The nnml back end supports group compaction.
216
217This feature, accessible via the functions `gnus-group-compact-group'
218(`G z' in the group buffer) and `gnus-server-compact-server' (`z' in the
219server buffer) renumbers all articles in a group, starting from 1 and
220removing gaps. As a consequence, you get a correct total article count
221(until messages are deleted again).
222
223
224
225* Appearance
226
227** The tool bar has been updated to use GNOME icons. You can also
228customize the tool bars: `M-x customize-apropos RET -tool-bar$' should
229get you started. (Only for Emacs, not in XEmacs.)
230
231** The tool bar icons are now (de)activated correctly in the group buffer,
232see the variable `gnus-group-update-tool-bar'. Its default value
233depends on your Emacs version.
234
235** You can change the location of XEmacs' toolbars in Gnus buffers. See
236`gnus-use-toolbar' and `message-use-toolbar'.
237
238
239
240* Miscellaneous changes
241
242** Having edited the select-method for the foreign server in the server
243buffer is immediately reflected to the subscription of the groups which
244use the server in question. For instance, if you change
245`nntp-via-address' into `bar.example.com' from `foo.example.com', Gnus
246will connect to the news host by way of the intermediate host
247`bar.example.com' from next time.
248
249** The `all.SCORE' file can be edited from the group buffer using `W e'.
250
251** You can set `gnus-mark-copied-or-moved-articles-as-expirable' to a
252non-`nil' value so that articles that have been read may be marked as
253expirable automatically when copying or moving them to a group that has
254auto-expire turned on. The default is `nil' and copying and moving of
255articles behave as before; i.e., the expirable marks will be unchanged
256except that the marks will be removed when copying or moving articles to
257a group that has not turned auto-expire on. *Note Expiring Mail::.
258
259
260
261* For older news, see Gnus info node "New Features". 39* For older news, see Gnus info node "New Features".
262 40
263---------------------------------------------------------------------- 41----------------------------------------------------------------------
diff --git a/lisp/gnus/ChangeLog b/lisp/gnus/ChangeLog
index 0923ed4db96..5472af42113 100644
--- a/lisp/gnus/ChangeLog
+++ b/lisp/gnus/ChangeLog
@@ -1,3 +1,397 @@
12012-06-26 Katsumi Yamaoka <yamaoka@jpl.org>
2
3 * mm-decode.el: Add coding cookie for a soft hyphen that mm-shr uses.
4
52012-06-26 Lars Magne Ingebrigtsen <larsi@gnus.org>
6
7 * gnus-art.el (gnus-article-read-summary-keys): Protect against the key
8 being bound to a lambda form.
9
102012-06-26 Wolfgang Jenkner <wjenkner@inode.at>
11
12 * gnus-picon.el (gnus-picon-properties): New defcustom.
13 (gnus-picon-create-glyph): Use it.
14
152012-06-26 Lars Magne Ingebrigtsen <larsi@gnus.org>
16
17 * shr.el: Add a iso-8859-1 cookie to make stuff work under other
18 locales.
19
20 * mm-decode.el (mm-display-part): Dissect archives when hitting `RET'
21 on a handle.
22
23 * gnus-sum.el (gnus-summary-limit-to-author): Use the current From
24 address as the default.
25
26 * nnfolder.el (nnfolder-save-buffer): Delete old versions silently.
27 It makes no sense to query the user about internal files.
28
29 * gnus-spec.el: Remove all the byte-compilation stuff, since
30 benchmarking shows that it doesn't help when entering large summary
31 buffers.
32
33 * gnus-util.el (gnus-byte-code): Remove.
34
35 * gnus-spec.el (gnus-update-format-specifications): Remove outdated
36 grouplens stuff.
37
382012-06-26 Lars Magne Ingebrigtsen <larsi@gnus.org>
39
40 * gnus-msg.el (gnus-msg-mail): Warn the user about Gnus not running
41 (bug#11514).
42
432012-06-26 Stephen Eglen <S.J.Eglen@damtp.cam.ac.uk>
44
45 * message.el (message-buffers): Return all buffers derived from Message
46 to make `gnus-dired-attach' work with mu4e.
47
482012-06-26 Daiki Ueno <ueno@unixuser.org>
49
50 * mm-decode.el (mm-inhibit-auto-detect-attachment): New variable.
51 (mm-dissect-singlepart): Don't guess the MIME type of
52 application/octet-stream parts if mm-inhibit-auto-detect-attachment is
53 set.
54 (mm-dissect-multipart): Bind mm-inhibit-auto-detect-attachment if the
55 toplevel MIME type is multipart/encrypted.
56
572012-06-26 Wolfgang Jenkner <wjenkner@inode.at>
58
59 * gnus-agent.el (gnus-agent-save-active): Deal with the "groups" format.
60 In particular, add an optional argument and a docstring.
61
62 * gnus-start.el (gnus-groups-to-gnus-format): Use it.
63
64 * nntp.el (nntp-finish-retrieve-group-infos): Make `nntp-server-buffer'
65 current before calling `gnus-groups-to-gnus-format'.
66 Note that this was already the case for `gnus-active-to-gnus-format'.
67
682012-06-26 Katsumi Yamaoka <yamaoka@jpl.org>
69
70 * pop3.el (pop3-wait-for-messages): Fix retrieved data size calculation.
71
722012-06-26 Lars Magne Ingebrigtsen <larsi@gnus.org>
73
74 * mm-decode.el (mm-dissect-buffer): Doc fix.
75
76 * gnus-sum.el (gnus-handle-ephemeral-exit):
77 Avoid creating the group buffer if it doesn't exist.
78
79 * gnus-group.el (gnus-group-read-ephemeral-group): If no quit-config
80 is given, mark the group as ephemeral with the current window conf.
81
82 * gnus-sum.el (gnus-set-global-variables): Don't assume that the group
83 buffer exists, which it doesn't if we haven't started Gnus.
84 (gnus-summary-exit): Allow quitting when we don't have a group buffer.
85
862012-06-26 Lars Magne Ingebrigtsen <larsi@gnus.org>
87
88 * mml.el (mml-generate-mime):
89 Allow specifying what the top-level part type is.
90
91 * gnus-sum.el (gnus-auto-center-summary):
92 `scroll-margin' isn't defined on XEmacs.
93
942012-06-26 Philipp Haselwarter <philipp.haselwarter@gmx.de> (tiny change)
95
96 * gnus-sum.el (gnus-auto-center-summary):
97 Set default to respect `scroll-margin'.
98
992012-06-26 Elias Oltmanns <eo@nebensachen.de> (tiny change)
100
101 * gnus-cite.el (gnus-dissect-cited-text): A single line without
102 citation prefix within a block of cited text should be considered
103 part of that block *only* if it is a blank line.
104
1052012-06-26 Katsumi Yamaoka <yamaoka@jpl.org>
106
107 * shr.el (shr-find-fill-point): Remove unused code; don't break a line
108 before kinsoku-bol characters nor within kinsoku-eol characters.
109
1102012-06-26 Katsumi Yamaoka <yamaoka@jpl.org>
111
112 * gnus-sync.el (gnus-topic-alist, gnus-group-topic)
113 (gnus-topic-create-topic, gnus-topic-enter-dribble):
114 Silence compiler.
115 (gnus-sync-read): Use mapc instead of mapcar.
116
117 * mm-archive.el: Require mm-decode for some macros.
118 (gnus-recursive-directory-files, mailcap-extension-to-mime):
119 Silence the byte compiler.
120 (mm-archive-decoders): New function that returns the value of
121 the mm-archive-decoders variable.
122
123 * mm-decode.el:
124 Don't require mm-archive; autoload mm-archive functions instead.
125 (mm-dissect-singlepart): Use the function mm-archive-decoders.
126
127 * nnmail.el (mail-send-and-exit): Silence the byte compiler.
128
1292012-06-26 Peter Munster <pmrb@free.fr>
130
131 * gnus-demon.el (gnus-demon-timers): Now a plist (function -> timer).
132 (gnus-demon-cancel): Ditto.
133 (gnus-demon-run-callback): When function cannot be called due to low
134 idleness, call it when idleness reaches the expected value, instead
135 of waiting another timer period.
136 (gnus-demon-init): Add `time' to arguments of call-back.
137
1382012-06-26 Lars Magne Ingebrigtsen <larsi@gnus.org>
139
140 * gnus.el: Register gnus-registry functions.
141
142 * gnus-registry.el (gnus-try-warping-via-registry):
143 Moved here and indent.
144
145 * gnus-int.el (gnus-warp-to-article):
146 Check whether the registry is enabled before warping.
147
1482012-06-26 Dave Abrahams <dave@boostpro.com>
149
150 * gnus-sum.el (gnus-summary-insert-subject): Record information
151 in the registry about each article retrieved.
152
153 * gnus-int.el (gnus-select-group-with-message-id): New function.
154 (gnus-try-warping-via-registry): Ditto.
155 (gnus-warp-to-article): Fall back on the registry.
156
1572012-06-26 Lars Magne Ingebrigtsen <larsi@gnus.org>
158
159 * nnimap.el (nnimap-fetch-partial-articles): Minor doc string fixup.
160
1612012-06-26 Katsumi Yamaoka <yamaoka@jpl.org>
162
163 * gnus-msg.el (gnus-summary-resend-message-insert-gcc): Assume that
164 gnus-gcc-self-resent-messages may be a group parameter.
165 (gnus-summary-resend-message):
166 Don't encode encoded words in header when Gcc'ing resent message.
167
1682012-06-26 Lars Magne Ingebrigtsen <larsi@gnus.org>
169
170 * shr.el (shr-insert): Treat non-breaking space just like normal
171 space. This seems to produce more pleasing results.
172 (shr-insert):
173 Only insert a blank line if we're starting from an image.
174 (shr-tag-br):
175 Allow <br> to end lines or to make a single blank line.
176 (shr-ensure-paragraph): Consider lines with white space to be blank.
177
1782012-06-26 Christopher Schmidt <christopher@ch.ristopher.com>
179
180 * gnus-msg.el (gnus-inews-do-gcc): Add gnus-gcc-pre-body-encode-hook
181 and gnus-gcc-post-body-encode-hook.
182
1832012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
184
185 * mm-decode.el (mm-dissect-singlepart):
186 Guess what the type of application/octet-stream parts really is.
187
188 * gnus-sum.el (gnus-propagate-marks): Remove.
189
1902012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
191
192 * nntp.el (nntp-coding-system-for-read): Remove.
193 (nntp-coding-system-for-write): Ditto.
194 (nntp-open-connection): Just use `binary' directly.
195
1962012-06-26 Teodor Zlatanov <tzz@lifelogs.com>
197
198 * registry.el (registry-usage-test, registry-persistence-test):
199 Move to tests/gnustest-registry.el.
200 (registry-make-testable-db, registry-match-test)
201 (registry-instantiation-test): Move to tests/gnustest-registry.el.
202
203 * gnus-registry.el (gnus-registry-misc-test)
204 (gnus-registry-usage-test): Move to tests/gnustest-registry.el.
205
206 * tests/gnustest-registry.el:
207 New file with the registry and gnus-registry ERT tests.
208
2092012-06-26 Katsumi Yamaoka <yamaoka@jpl.org>
210
211 * gnus-msg.el (gnus-summary-resend-message):
212 Make gnus-summary-resend-message-insert-gcc be last item in
213 message-header-setup-hook.
214
2152012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
216
217 * nnfolder.el (nnfolder-marks-directory, nnfolder-marks-is-evil)
218 (nnfolder-marks, nnfolder-marks-file-suffix)
219 (nnfolder-marks-modtime): Remove.
220 (nnfolder-open-server): Don't use marks.
221 (nnfolder-request-delete-group): Ditto.
222 (nnfolder-request-rename-group): Ditto.
223 (nnfolder-request-set-mark, nnfolder-request-marks)
224 (nnfolder-group-marks-pathname, nnfolder-marks-changed-p)
225 (nnfolder-save-marks, nnfolder-open-marks): Remove.
226
227 * nnml.el (nnml-marks-is-evil, nnml-marks-file-name, nnml-marks)
228 (nnml-marks-modtime): Remove.
229 (nnml-request-delete-group): Don't use marks.
230 (nnml-request-rename-group): Ditto.
231 (nnml-request-set-mark, nnml-request-marks, nnml-marks-changed-p)
232 (nnml-save-marks, nnml-open-marks): Remove.
233
234 * nntp.el (nntp-marks-is-evil, nntp-marks-file-name, nntp-marks)
235 (nntp-marks-modtime, nntp-marks-directory, nntp-request-set-mark)
236 (nntp-request-marks, nntp-marks-directory, nntp-marks-changed-p)
237 (nntp-save-marks, nntp-open-marks, nntp-possibly-create-directory)
238 (nntp-server-to-method-cache): Remove.
239
240 * shr.el (shr-rescale-image): Fix wrong merge.
241
2422012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
243
244 * shr.el (shr-remove-trailing-whitespace):
245 Really delete the padding on too-wide lines.
246
2472012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
248
249 * mm-archive.el (mm-archive-dissect-and-inline): New function.
250 (mm-archive-dissect-and-inline): Fix up the undisplayer.
251
252 * mm-decode.el (mm-display-external): Output the text from
253 the command in the buffer after the command finished.
254 This makes text-based commands behave better.
255
2562012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
257
258 * message.el (smtpmail-smtp-user): Silence compiler warning.
259
2602012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
261
262 * message.el (message-multi-smtp-send-mail): Also allow specifying
263 the SMTP user name.
264
2652012-06-26 Katsumi Yamaoka <yamaoka@jpl.org>
266
267 * gnus-sum.el (gnus-summary-article-map): Fix typo.
268
2692012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
270
271 * message.el (message-multi-smtp-send-mail): New function.
272 (message-multi-smtp-send-mail): Respect the X-Message-SMTP-Method
273 header to implement multi-SMTP functionality.
274
275 * gnus-agent.el (gnus-agent-send-mail-function): Removed.
276 (gnus-agentize): Don't set it.
277 (gnus-agent-send-mail): Don't use it.
278
279 * gnus-sum.el (gnus-summary-widget-backward):
280 New function and keystroke.
281
282 * shr.el (shr-put-image): Remove underlines from sliced images.
283 (shr-zoom-image): Compute the region to be replaced more correctly.
284
2852012-06-26 Katsumi Yamaoka <yamaoka@jpl.org>
286
287 * gnus-msg.el (gnus-gcc-self-resent-messages): New user option.
288 (gnus-summary-resend-message-insert-gcc): New function.
289 (gnus-summary-resend-message): Modify message-header-setup-hook and
290 message-sent-hook to make it work for Gcc.
291 (gnus-inews-do-gcc): Update the number of unread articles of groups
292 that messages are Gcc'd to.
293
294 * message.el (message-resend): Run message-sent-hook to do Gcc.
295
2962012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
297
298 * gnus-registry.el (gnus-registry-fixup-registry):
299 Move the message to a higher level to silence compilation.
300
301 * gnus-art.el (gnus-shr-put-image): Take and pass on a `flags'
302 parameter to allow controlling the scaling.
303
304 * shr.el (shr-zoom-image): New command and keystroke.
305 (shr-put-image): Take a `size' flag to say how to scale the image.
306
307 * mm-archive.el (mm-dissect-archive): Use it to get all file names.
308 Use recursive deletion.
309 (mm-dissect-archive): Add support for zip files.
310
311 * gnus-util.el (gnus-recursive-directory-files): New function.
312
313 * mm-archive.el (mm-archive-list-files): Inline text and image parts.
314 (mm-archive-decoders): Add tgz support.
315
316 * mm-decode.el (mm-shr): Make sure that the HTML ends with a newline.
317 Otherwise inserting text into the Gnus buffer can look odd.
318
319 * gnus-art.el (gnus-mime-inline-part): Slight clean-up.
320
321 * mm-archive.el (mm-archive-decoders): Add support for tar.
322
323 * gnus.el (gnus-logo-color-alist): Change the colours for Ma Gnus.
324
325 * nnmail.el (nnmail-extra-headers): Add Cc to the default.
326
3272012-06-26 Lars Ingebrigtsen <larsi@gnus.org>
328
329 * mm-decode.el (mm-dissect-singlepart): Check that the decoder exists.
330
331 * mm-archive.el: New file.
332
333 * mm-decode.el (mm-dissect-singlepart):
334 Use it to decode ms-tnef files.
335
336 * mm-util.el (mm-find-buffer-file-coding-system): Comment fix.
337
338 * message.el (message-goto-*): Make all the `message-goto-*' commands
339 push the mark before moving point. This makes it easier to go back
340 to where you came from after editing whatever you jumped to.
341
3422012-06-26 Teodor Zlatanov <tzz@lifelogs.com>
343
344 * gnus-sync.el (gnus-sync-newsrc-groups): Quote normally.
345 (gnus-sync-lesync-pre-save-group-entry): Remove invalid invlists.
346 (gnus-sync-lesync-normalize-group-entry): Ignore a few more keys.
347
3482012-06-26 Teodor Zlatanov <tzz@lifelogs.com>
349
350 * spam.el: Move BBDB autoloads.
351 (spam-exists-in-BBDB-p):
352 New function to do the BBDB search directly in BBDB 2 and 3.
353 (spam-check-BBDB): Use it.
354 (spam-enter-ham-BBDB): Use it.
355
3562012-06-26 Peter Munster <pmrb@free.fr> (tiny change)
357
358 * gnus-group.el (gnus-group-get-new-news):
359 New parameter `one-level' for scanning exactly one level.
360
361 * gnus-start.el (gnus-get-unread-articles): Ditto.
362
3632012-06-26 Teodor Zlatanov <tzz@lifelogs.com>
364
365 * gnus-sync.el: More commentary about setup.
366
3672012-06-26 Teodor Zlatanov <tzz@lifelogs.com>
368
369 * gnus-sync.el: More commentary about `gnus-sync-read' issues.
370
3712012-06-26 Teodor Zlatanov <tzz@lifelogs.com>
372
373 * gnus-sync.el: Improve docs about CouchDB admins.
374
3752012-06-26 Teodor Zlatanov <tzz@lifelogs.com>
376
377 * gnus-sync.el (gnus-sync-lesync-setup): Fix salt when user setup is
378 not needed. Provide xmlplistread list function to produce XML plist
379 output for non-Gnus LeSync clients.
380
3812012-06-26 Teodor Zlatanov <tzz@lifelogs.com>
382
383 * gnus-sync.el: Add LeSync synchronization backend and logic to read
384 and save against it. Group subscriptions, read marks, other marks,
385 subscription levels, topic names, and topic offsets (the group's
386 position within the topic) are saved. This is an experimental
387 backend and may change significantly. Load json.el from
388 the gnus-fallback-lib if it's not available otherwise.
389 (gnus-sync-save): Don't use `apply-partially' because of XEmacs.
390
3912012-06-26 David Engster <dengste@eml.cc>
392
393 * tests/gnustest-nntp.el: New file for simple NNTP testing.
394
12012-06-18 Nelson Ferreira <nelson.ferreira@ieee.org> (tiny change) 3952012-06-18 Nelson Ferreira <nelson.ferreira@ieee.org> (tiny change)
2 396
3 * gnus-win.el (gnus-configure-frame): Pass an arg to window-dedicated-p. 397 * gnus-win.el (gnus-configure-frame): Pass an arg to window-dedicated-p.
diff --git a/lisp/gnus/gnus-agent.el b/lisp/gnus/gnus-agent.el
index 0d469b174bf..525008c351f 100644
--- a/lisp/gnus/gnus-agent.el
+++ b/lisp/gnus/gnus-agent.el
@@ -242,7 +242,6 @@ NOTES:
242(defvar gnus-category-group-cache nil) 242(defvar gnus-category-group-cache nil)
243(defvar gnus-agent-spam-hashtb nil) 243(defvar gnus-agent-spam-hashtb nil)
244(defvar gnus-agent-file-name nil) 244(defvar gnus-agent-file-name nil)
245(defvar gnus-agent-send-mail-function nil)
246(defvar gnus-agent-file-coding-system 'raw-text) 245(defvar gnus-agent-file-coding-system 'raw-text)
247(defvar gnus-agent-file-loading-cache nil) 246(defvar gnus-agent-file-loading-cache nil)
248(defvar gnus-agent-total-fetched-hashtb nil) 247(defvar gnus-agent-total-fetched-hashtb nil)
@@ -683,11 +682,7 @@ This will modify the `gnus-setup-news-hook', and
683minor mode in all Gnus buffers." 682minor mode in all Gnus buffers."
684 (interactive) 683 (interactive)
685 (gnus-open-agent) 684 (gnus-open-agent)
686 (unless gnus-agent-send-mail-function 685 (setq message-send-mail-real-function 'gnus-agent-send-mail)
687 (setq gnus-agent-send-mail-function
688 (or message-send-mail-real-function
689 (function (lambda () (funcall message-send-mail-function))))
690 message-send-mail-real-function 'gnus-agent-send-mail))
691 686
692 ;; If the servers file doesn't exist, auto-agentize some servers and 687 ;; If the servers file doesn't exist, auto-agentize some servers and
693 ;; save the servers file so this auto-agentizing isn't invoked 688 ;; save the servers file so this auto-agentizing isn't invoked
@@ -723,7 +718,7 @@ Optional arg GROUP-NAME allows to specify another group."
723(defun gnus-agent-send-mail () 718(defun gnus-agent-send-mail ()
724 (if (or (not gnus-agent-queue-mail) 719 (if (or (not gnus-agent-queue-mail)
725 (and gnus-plugged (not (eq gnus-agent-queue-mail 'always)))) 720 (and gnus-plugged (not (eq gnus-agent-queue-mail 'always))))
726 (funcall gnus-agent-send-mail-function) 721 (message-multi-smtp-send-mail)
727 (goto-char (point-min)) 722 (goto-char (point-min))
728 (re-search-forward 723 (re-search-forward
729 (concat "^" (regexp-quote mail-header-separator) "\n")) 724 (concat "^" (regexp-quote mail-header-separator) "\n"))
@@ -1304,12 +1299,18 @@ This can be added to `gnus-select-article-hook' or
1304 (gnus-group-update-group group t))) 1299 (gnus-group-update-group group t)))
1305 nil)) 1300 nil))
1306 1301
1307(defun gnus-agent-save-active (method) 1302(defun gnus-agent-save-active (method &optional groups-p)
1303 "Sync the agent's active file with the current buffer.
1304Pass non-nil for GROUPS-P if the buffer starts out in groups format.
1305Regardless, both the file and the buffer end up in active format
1306if METHOD is agentized; otherwise the function is a no-op."
1308 (when (gnus-agent-method-p method) 1307 (when (gnus-agent-method-p method)
1309 (let* ((gnus-command-method method) 1308 (let* ((gnus-command-method method)
1310 (new (gnus-make-hashtable (count-lines (point-min) (point-max)))) 1309 (new (gnus-make-hashtable (count-lines (point-min) (point-max))))
1311 (file (gnus-agent-lib-file "active"))) 1310 (file (gnus-agent-lib-file "active")))
1312 (gnus-active-to-gnus-format nil new) 1311 (if groups-p
1312 (gnus-groups-to-gnus-format nil new)
1313 (gnus-active-to-gnus-format nil new))
1313 (gnus-agent-write-active file new) 1314 (gnus-agent-write-active file new)
1314 (erase-buffer) 1315 (erase-buffer)
1315 (let ((nnheader-file-coding-system gnus-agent-file-coding-system)) 1316 (let ((nnheader-file-coding-system gnus-agent-file-coding-system))
diff --git a/lisp/gnus/gnus-art.el b/lisp/gnus/gnus-art.el
index b04615dc5a9..b92c3b6435f 100644
--- a/lisp/gnus/gnus-art.el
+++ b/lisp/gnus/gnus-art.el
@@ -2231,7 +2231,8 @@ unfolded."
2231 (unfoldable 2231 (unfoldable
2232 (or (equal gnus-article-unfold-long-headers t) 2232 (or (equal gnus-article-unfold-long-headers t)
2233 (and (stringp gnus-article-unfold-long-headers) 2233 (and (stringp gnus-article-unfold-long-headers)
2234 (string-match gnus-article-unfold-long-headers header))))) 2234 (string-match gnus-article-unfold-long-headers
2235 header)))))
2235 (with-temp-buffer 2236 (with-temp-buffer
2236 (insert header) 2237 (insert header)
2237 (goto-char (point-min)) 2238 (goto-char (point-min))
@@ -5329,9 +5330,8 @@ Compressed files like .gz and .bz2 are decompressed."
5329 (or (cdr (assq arg 5330 (or (cdr (assq arg
5330 gnus-summary-show-article-charset-alist)) 5331 gnus-summary-show-article-charset-alist))
5331 (mm-read-coding-system "Charset: ")))) 5332 (mm-read-coding-system "Charset: "))))
5332 (t 5333 ((mm-handle-undisplayer handle)
5333 (if (mm-handle-undisplayer handle) 5334 (mm-remove-part handle)))
5334 (mm-remove-part handle))))
5335 (forward-line 2) 5335 (forward-line 2)
5336 (mm-display-inline handle) 5336 (mm-display-inline handle)
5337 (goto-char b))))) 5337 (goto-char b)))))
@@ -6200,12 +6200,13 @@ Provided for backwards compatibility."
6200 (not gnus-inhibit-hiding)) 6200 (not gnus-inhibit-hiding))
6201 (gnus-article-hide-headers))) 6201 (gnus-article-hide-headers)))
6202 6202
6203(declare-function shr-put-image "shr" (data alt)) 6203(declare-function shr-put-image "shr" (data alt &optional flags))
6204 6204
6205(defun gnus-shr-put-image (data alt) 6205(defun gnus-shr-put-image (data alt &optional flags)
6206 "Put image DATA with a string ALT. Enable image to be deleted." 6206 "Put image DATA with a string ALT. Enable image to be deleted."
6207 (let ((image (shr-put-image data (propertize (or alt "*") 6207 (let ((image (shr-put-image data (propertize (or alt "*")
6208 'gnus-image-category 'shr)))) 6208 'gnus-image-category 'shr)
6209 flags)))
6209 (when image 6210 (when image
6210 (gnus-add-image 'shr image)))) 6211 (gnus-add-image 'shr image))))
6211 6212
@@ -6524,7 +6525,8 @@ not have a face in `gnus-article-boring-faces'."
6524 (ding) 6525 (ding)
6525 (unless (member keys nosave-in-article) 6526 (unless (member keys nosave-in-article)
6526 (set-buffer gnus-article-current-summary)) 6527 (set-buffer gnus-article-current-summary))
6527 (when (get func 'disabled) 6528 (when (and (symbolp func)
6529 (get func 'disabled))
6528 (error "Function %s disabled" func)) 6530 (error "Function %s disabled" func))
6529 (call-interactively func) 6531 (call-interactively func)
6530 (setq new-sum-point (point))) 6532 (setq new-sum-point (point)))
diff --git a/lisp/gnus/gnus-cite.el b/lisp/gnus/gnus-cite.el
index c7443446ceb..6bcba714696 100644
--- a/lisp/gnus/gnus-cite.el
+++ b/lisp/gnus/gnus-cite.el
@@ -509,6 +509,7 @@ Lines matching `gnus-cite-attribution-suffix' and perhaps
509 (if (and (equal (cdadr m) "") 509 (if (and (equal (cdadr m) "")
510 (equal (cdar m) (cdaddr m)) 510 (equal (cdar m) (cdaddr m))
511 (goto-char (caadr m)) 511 (goto-char (caadr m))
512 (looking-at "[ \t]*$")
512 (forward-line 1) 513 (forward-line 1)
513 (= (point) (caaddr m))) 514 (= (point) (caaddr m)))
514 (setcdr m (cdddr m)) 515 (setcdr m (cdddr m))
diff --git a/lisp/gnus/gnus-demon.el b/lisp/gnus/gnus-demon.el
index 2a4fa6f483e..115c5777448 100644
--- a/lisp/gnus/gnus-demon.el
+++ b/lisp/gnus/gnus-demon.el
@@ -71,7 +71,7 @@ Emacs has been idle for IDLE `gnus-demon-timestep's."
71;;; Internal variables. 71;;; Internal variables.
72 72
73(defvar gnus-demon-timers nil 73(defvar gnus-demon-timers nil
74 "List of idle timers which are running.") 74 "Plist of idle timers which are running.")
75(defvar gnus-inhibit-demon nil 75(defvar gnus-inhibit-demon nil
76 "If non-nil, no daemonic function will be run.") 76 "If non-nil, no daemonic function will be run.")
77 77
@@ -98,15 +98,32 @@ Emacs has been idle for IDLE `gnus-demon-timestep's."
98 (float-time (or (current-idle-time) 98 (float-time (or (current-idle-time)
99 '(0 0 0))))) 99 '(0 0 0)))))
100 100
101(defun gnus-demon-run-callback (func &optional idle) 101(defun gnus-demon-run-callback (func &optional idle time special)
102 "Run FUNC if Emacs has been idle for longer than IDLE seconds." 102 "Run FUNC if Emacs has been idle for longer than IDLE seconds.
103If not, and a TIME is given, restart a new idle timer, so FUNC
104can be called at the next opportunity. Such a special idle run is
105marked with SPECIAL."
103 (unless gnus-inhibit-demon 106 (unless gnus-inhibit-demon
104 (when (or (not idle) 107 (block run-callback
105 (and (eq idle t) (> (gnus-demon-idle-since) 0)) 108 (when (eq idle t)
106 (<= idle (gnus-demon-idle-since))) 109 (setq idle 0.001))
110 (cond (special
111 (setq gnus-demon-timers
112 (plist-put gnus-demon-timers func
113 (run-with-timer time time 'gnus-demon-run-callback
114 func idle time))))
115 ((and idle (> idle (gnus-demon-idle-since)))
116 (when time
117 (nnheader-cancel-timer (plist-get gnus-demon-timers func))
118 (setq gnus-demon-timers
119 (plist-put gnus-demon-timers func
120 (run-with-idle-timer idle nil
121 'gnus-demon-run-callback
122 func idle time t))))
123 (return-from run-callback)))
107 (with-local-quit 124 (with-local-quit
108 (ignore-errors 125 (ignore-errors
109 (funcall func)))))) 126 (funcall func))))))
110 127
111(defun gnus-demon-init () 128(defun gnus-demon-init ()
112 "Initialize the Gnus daemon." 129 "Initialize the Gnus daemon."
@@ -140,12 +157,14 @@ Emacs has been idle for IDLE `gnus-demon-timestep's."
140 ;; (func number any) 157 ;; (func number any)
141 ;; Call every `time' 158 ;; Call every `time'
142 ((integerp time) 159 ((integerp time)
143 (run-with-timer time time 'gnus-demon-run-callback func idle)) 160 (run-with-timer time time 'gnus-demon-run-callback
161 func idle time))
144 ;; (func string any) 162 ;; (func string any)
145 ((stringp time) 163 ((stringp time)
146 (run-with-timer time (* 24 60 60) 'gnus-demon-run-callback func idle))))) 164 (run-with-timer time (* 24 60 60) 'gnus-demon-run-callback
165 func idle)))))
147 (when timer 166 (when timer
148 (add-to-list 'gnus-demon-timers timer))))) 167 (setq gnus-demon-timers (plist-put gnus-demon-timers func timer))))))
149 168
150(defun gnus-demon-time-to-step (time) 169(defun gnus-demon-time-to-step (time)
151 "Find out how many steps to TIME, which is on the form \"17:43\"." 170 "Find out how many steps to TIME, which is on the form \"17:43\"."
@@ -184,8 +203,8 @@ Emacs has been idle for IDLE `gnus-demon-timestep's."
184(defun gnus-demon-cancel () 203(defun gnus-demon-cancel ()
185 "Cancel any Gnus daemons." 204 "Cancel any Gnus daemons."
186 (interactive) 205 (interactive)
187 (dolist (timer gnus-demon-timers) 206 (dotimes (i (/ (length gnus-demon-timers) 2))
188 (nnheader-cancel-timer timer)) 207 (nnheader-cancel-timer (nth (1+ (* i 2)) gnus-demon-timers)))
189 (setq gnus-demon-timers nil)) 208 (setq gnus-demon-timers nil))
190 209
191(defun gnus-demon-add-disconnection () 210(defun gnus-demon-add-disconnection ()
diff --git a/lisp/gnus/gnus-group.el b/lisp/gnus/gnus-group.el
index ff41f13de30..8287a6bb86e 100644
--- a/lisp/gnus/gnus-group.el
+++ b/lisp/gnus/gnus-group.el
@@ -56,7 +56,7 @@
56 56
57(autoload 'gnus-group-make-nnir-group "nnir") 57(autoload 'gnus-group-make-nnir-group "nnir")
58 58
59(defcustom gnus-no-groups-message "No Gnus is good news" 59(defcustom gnus-no-groups-message "No news is good news"
60 "*Message displayed by Gnus when no groups are available." 60 "*Message displayed by Gnus when no groups are available."
61 :group 'gnus-start 61 :group 'gnus-start
62 :type 'string) 62 :type 'string)
@@ -2290,9 +2290,12 @@ Return the name of the group if selection was successful."
2290 ;; (gnus-read-group "Group name: ") 2290 ;; (gnus-read-group "Group name: ")
2291 (gnus-group-completing-read) 2291 (gnus-group-completing-read)
2292 (gnus-read-method "From method"))) 2292 (gnus-read-method "From method")))
2293 ;; Transform the select method into a unique server.
2294 (unless (gnus-alive-p) 2293 (unless (gnus-alive-p)
2295 (gnus-no-server)) 2294 (nnheader-init-server-buffer)
2295 ;; Necessary because of funky inlining.
2296 (require 'gnus-cache)
2297 (setq gnus-newsrc-hashtb (gnus-make-hashtable)))
2298 ;; Transform the select method into a unique server.
2296 (when (stringp method) 2299 (when (stringp method)
2297 (setq method (gnus-server-to-method method))) 2300 (setq method (gnus-server-to-method method)))
2298 (let ((address-slot 2301 (let ((address-slot
@@ -2312,18 +2315,22 @@ Return the name of the group if selection was successful."
2312 `(-1 nil (,group 2315 `(-1 nil (,group
2313 ,gnus-level-default-subscribed nil nil ,method 2316 ,gnus-level-default-subscribed nil nil ,method
2314 ,(cons 2317 ,(cons
2315 (cond 2318 (cons 'quit-config
2316 (quit-config 2319 (cond
2317 (cons 'quit-config quit-config)) 2320 (quit-config
2318 ((assq gnus-current-window-configuration 2321 quit-config)
2319 gnus-buffer-configuration) 2322 ((assq gnus-current-window-configuration
2320 (cons 'quit-config 2323 gnus-buffer-configuration)
2321 (cons gnus-summary-buffer 2324 (cons gnus-summary-buffer
2322 gnus-current-window-configuration)))) 2325 gnus-current-window-configuration))
2326 (t
2327 (cons (current-buffer)
2328 (current-window-configuration)))))
2323 parameters))) 2329 parameters)))
2324 gnus-newsrc-hashtb) 2330 gnus-newsrc-hashtb)
2325 (push method gnus-ephemeral-servers) 2331 (push method gnus-ephemeral-servers)
2326 (set-buffer gnus-group-buffer) 2332 (when (gnus-buffer-live-p gnus-group-buffer)
2333 (set-buffer gnus-group-buffer))
2327 (unless (gnus-check-server method) 2334 (unless (gnus-check-server method)
2328 (error "Unable to contact server: %s" (gnus-status-message method))) 2335 (error "Unable to contact server: %s" (gnus-status-message method)))
2329 (when activate 2336 (when activate
@@ -4014,11 +4021,13 @@ entail asking the server for the groups."
4014 (gnus-activate-foreign-newsgroups level)) 4021 (gnus-activate-foreign-newsgroups level))
4015 (gnus-group-get-new-news))) 4022 (gnus-group-get-new-news)))
4016 4023
4017(defun gnus-group-get-new-news (&optional arg) 4024(defun gnus-group-get-new-news (&optional arg one-level)
4018 "Get newly arrived articles. 4025 "Get newly arrived articles.
4019If ARG is a number, it specifies which levels you are interested in 4026If ARG is a number, it specifies which levels you are interested in
4020re-scanning. If ARG is non-nil and not a number, this will force 4027re-scanning. If ARG is non-nil and not a number, this will force
4021\"hard\" re-reading of the active files from all servers." 4028\"hard\" re-reading of the active files from all servers.
4029If ONE-LEVEL is not nil, then re-scan only the specified level,
4030otherwise all levels below ARG will be scanned too."
4022 (interactive "P") 4031 (interactive "P")
4023 (require 'nnmail) 4032 (require 'nnmail)
4024 (let ((gnus-inhibit-demon t) 4033 (let ((gnus-inhibit-demon t)
@@ -4032,7 +4041,8 @@ re-scanning. If ARG is non-nil and not a number, this will force
4032 (unless gnus-slave 4041 (unless gnus-slave
4033 (gnus-master-read-slave-newsrc)) 4042 (gnus-master-read-slave-newsrc))
4034 4043
4035 (gnus-get-unread-articles (gnus-group-default-level arg t)) 4044 (gnus-get-unread-articles (gnus-group-default-level arg t)
4045 nil one-level)
4036 4046
4037 ;; If the user wants it, we scan for new groups. 4047 ;; If the user wants it, we scan for new groups.
4038 (when (eq gnus-check-new-newsgroups 'always) 4048 (when (eq gnus-check-new-newsgroups 'always)
diff --git a/lisp/gnus/gnus-int.el b/lisp/gnus/gnus-int.el
index 52a8520a252..18e56ed9b3a 100644
--- a/lisp/gnus/gnus-int.el
+++ b/lisp/gnus/gnus-int.el
@@ -533,16 +533,69 @@ If BUFFER, insert the article in that group."
533 header 533 header
534 (gnus-group-real-name group)))) 534 (gnus-group-real-name group))))
535 535
536(defun gnus-select-group-with-message-id (group message-id)
537 "Activate and select GROUP with the given MESSAGE-ID selected.
538Returns the article number of the message.
539
540If GROUP is not already selected, the message will be the only one in
541the group's summary.
542"
543 ;; TODO: is there a way to know at this point whether the group will
544 ;; be newly-selected? If so we could clean up the logic at the end
545 ;;
546 ;; save the new group's display parameter, if any, so we
547 ;; can replace it temporarily with zero.
548 (let ((saved-display
549 (gnus-group-get-parameter group 'display :allow-list)))
550
551 ;; Tell gnus we really don't want any articles
552 (gnus-group-set-parameter group 'display 0)
553
554 (unwind-protect
555 (gnus-summary-read-group-1
556 group (not :show-all) :no-article (not :kill-buffer)
557 ;; The combination of no-display and this dummy list of
558 ;; articles to select somehow makes it possible to open a
559 ;; group with no articles in it. Black magic.
560 :no-display '(-1); select-articles
561 )
562 ;; Restore the new group's display parameter
563 (gnus-group-set-parameter group 'display saved-display)))
564
565 ;; The summary buffer was suppressed by :no-display above.
566 ;; Create it now and insert the message
567 (let ((group-is-new (gnus-summary-setup-buffer group)))
568 (condition-case err
569 (let ((article-number
570 (gnus-summary-insert-subject message-id)))
571 (unless article-number
572 (signal 'error "message-id not in group"))
573 (gnus-summary-select-article nil nil nil article-number)
574 article-number)
575 ;; Clean up the new summary and propagate the error
576 (error (when group-is-new (gnus-summary-exit))
577 (apply 'signal err)))))
578
579(defun gnus-simplify-group-name (group)
580 "Return the simplest representation of the name of GROUP.
581This is the string that Gnus uses to identify the group."
582 (gnus-group-prefixed-name
583 (gnus-group-real-name group)
584 (gnus-group-method group)))
585
536(defun gnus-warp-to-article () 586(defun gnus-warp-to-article ()
537 "Warps from an article in a virtual group to the article in its 587 "Warps from an article in a virtual group to the article in its
538real group. Does nothing on a real group." 588real group. Does nothing on a real group."
539 (interactive) 589 (interactive)
540 (when (gnus-virtual-group-p gnus-newsgroup-name) 590 (when (gnus-virtual-group-p gnus-newsgroup-name)
541 (let ((gnus-command-method 591 (let ((gnus-command-method
542 (gnus-find-method-for-group gnus-newsgroup-name))) 592 (gnus-find-method-for-group gnus-newsgroup-name)))
543 (when (gnus-check-backend-function 593 (or
544 'warp-to-article (car gnus-command-method)) 594 (when (gnus-check-backend-function
545 (funcall (gnus-get-function gnus-command-method 'warp-to-article)))))) 595 'warp-to-article (car gnus-command-method))
596 (funcall (gnus-get-function gnus-command-method 'warp-to-article)))
597 (and (bound-and-true-p gnus-registry-enabled)
598 (gnus-try-warping-via-registry))))))
546 599
547(defun gnus-request-head (article group) 600(defun gnus-request-head (article group)
548 "Request the head of ARTICLE in GROUP." 601 "Request the head of ARTICLE in GROUP."
diff --git a/lisp/gnus/gnus-msg.el b/lisp/gnus/gnus-msg.el
index a041a85d444..d38f36a0c77 100644
--- a/lisp/gnus/gnus-msg.el
+++ b/lisp/gnus/gnus-msg.el
@@ -163,6 +163,22 @@ if nil, attach files as normal parts."
163 (const all :tag "Any") 163 (const all :tag "Any")
164 (string :tag "Regexp"))) 164 (string :tag "Regexp")))
165 165
166(defcustom gnus-gcc-self-resent-messages 'no-gcc-self
167 "Like `gcc-self' group parameter, only for unmodified resent messages.
168Applied to messages sent by `gnus-summary-resend-message'. Non-nil
169value of this variable takes precedence over any existing Gcc header.
170
171If this is `none', no Gcc copy will be made. If this is t, messages
172resent will be Gcc'd to the current group. If this is a string, it
173specifies a group to which resent messages will be Gcc'd. If this is
174nil, Gcc will be done according to existing Gcc header(s), if any.
175If this is `no-gcc-self', resent messages will be Gcc'd to groups that
176existing Gcc header specifies, except for the current group."
177 :version "24.2"
178 :group 'gnus-message
179 :type '(choice (const none) (const t) string (const nil)
180 (const no-gcc-self)))
181
166(gnus-define-group-parameter 182(gnus-define-group-parameter
167 posting-charset-alist 183 posting-charset-alist
168 :type list 184 :type list
@@ -297,6 +313,22 @@ If nil, the address field will always be empty after invoking
297 :group 'gnus-message 313 :group 'gnus-message
298 :type 'boolean) 314 :type 'boolean)
299 315
316(defcustom gnus-gcc-pre-body-encode-hook nil
317 "A hook called before encoding the body of the Gcc copy of a message.
318The current buffer (when the hook is run) contains the message
319including the message header. Changes made to the message will
320only affect the Gcc copy, but not the original message."
321 :group 'gnus-message
322 :type 'hook)
323
324(defcustom gnus-gcc-post-body-encode-hook nil
325 "A hook called after encoding the body of the Gcc copy of a message.
326The current buffer (when the hook is run) contains the message
327including the message header. Changes made to the message will
328only affect the Gcc copy, but not the original message."
329 :group 'gnus-message
330 :type 'hook)
331
300(autoload 'gnus-message-citation-mode "gnus-cite" nil t) 332(autoload 'gnus-message-citation-mode "gnus-cite" nil t)
301 333
302;;; Internal variables. 334;;; Internal variables.
@@ -1285,6 +1317,44 @@ For the \"inline\" alternatives, also see the variable
1285 (set-buffer gnus-original-article-buffer) 1317 (set-buffer gnus-original-article-buffer)
1286 (message-forward post))))))) 1318 (message-forward post)))))))
1287 1319
1320(defun gnus-summary-resend-message-insert-gcc ()
1321 "Insert Gcc header according to `gnus-gcc-self-resent-messages'."
1322 (gnus-inews-insert-gcc)
1323 (let ((gcc (mapcar
1324 (lambda (group)
1325 (mm-encode-coding-string
1326 group
1327 (gnus-group-name-charset (gnus-inews-group-method group)
1328 group)))
1329 (message-unquote-tokens
1330 (message-tokenize-header (mail-fetch-field "gcc" nil t)
1331 " ,"))))
1332 (self (with-current-buffer gnus-summary-buffer
1333 gnus-gcc-self-resent-messages)))
1334 (message-remove-header "gcc")
1335 (when gcc
1336 (goto-char (point-max))
1337 (cond ((eq self 'none))
1338 ((eq self t)
1339 (insert "Gcc: \"" gnus-newsgroup-name "\"\n"))
1340 ((stringp self)
1341 (insert "Gcc: "
1342 (mm-encode-coding-string
1343 (if (string-match " " self)
1344 (concat "\"" self "\"")
1345 self)
1346 (gnus-group-name-charset (gnus-inews-group-method self)
1347 self))
1348 "\n"))
1349 ((null self)
1350 (insert "Gcc: " (mapconcat 'identity gcc ", ") "\n"))
1351 ((eq self 'no-gcc-self)
1352 (when (setq gcc (delete
1353 gnus-newsgroup-name
1354 (delete (concat "\"" gnus-newsgroup-name "\"")
1355 gcc)))
1356 (insert "Gcc: " (mapconcat 'identity gcc ", ") "\n")))))))
1357
1288(defun gnus-summary-resend-message (address n) 1358(defun gnus-summary-resend-message (address n)
1289 "Resend the current article to ADDRESS." 1359 "Resend the current article to ADDRESS."
1290 (interactive 1360 (interactive
@@ -1298,12 +1368,24 @@ For the \"inline\" alternatives, also see the variable
1298 (with-current-buffer gnus-original-article-buffer 1368 (with-current-buffer gnus-original-article-buffer
1299 (nnmail-fetch-field "to")))) 1369 (nnmail-fetch-field "to"))))
1300 current-prefix-arg)) 1370 current-prefix-arg))
1301 (dolist (article (gnus-summary-work-articles n)) 1371 (let ((message-header-setup-hook (copy-sequence message-header-setup-hook))
1302 (gnus-summary-select-article nil nil nil article) 1372 (message-sent-hook (copy-sequence message-sent-hook)))
1303 (with-current-buffer gnus-original-article-buffer 1373 ;; `gnus-summary-resend-message-insert-gcc' must run last.
1304 (let ((gnus-gcc-externalize-attachments nil)) 1374 (add-hook 'message-header-setup-hook
1305 (message-resend address))) 1375 'gnus-summary-resend-message-insert-gcc t)
1306 (gnus-summary-mark-article-as-forwarded article))) 1376 (add-hook 'message-sent-hook
1377 `(lambda ()
1378 (let ((rfc2047-encode-encoded-words nil))
1379 ,(if gnus-agent
1380 '(gnus-agent-possibly-do-gcc)
1381 '(gnus-inews-do-gcc)))))
1382 (dolist (article (gnus-summary-work-articles n))
1383 (gnus-summary-select-article nil nil nil article)
1384 (with-current-buffer gnus-original-article-buffer
1385 (let ((gnus-gcc-externalize-attachments nil)
1386 (message-inhibit-body-encoding t))
1387 (message-resend address)))
1388 (gnus-summary-mark-article-as-forwarded article))))
1307 1389
1308;; From: Matthieu Moy <Matthieu.Moy@imag.fr> 1390;; From: Matthieu Moy <Matthieu.Moy@imag.fr>
1309(defun gnus-summary-resend-message-edit () 1391(defun gnus-summary-resend-message-edit ()
@@ -1595,7 +1677,9 @@ this is a reply."
1595 (nnheader-set-temp-buffer " *acc*") 1677 (nnheader-set-temp-buffer " *acc*")
1596 (setq message-options (with-current-buffer cur message-options)) 1678 (setq message-options (with-current-buffer cur message-options))
1597 (insert-buffer-substring cur) 1679 (insert-buffer-substring cur)
1680 (run-hooks 'gnus-gcc-pre-body-encode-hook)
1598 (message-encode-message-body) 1681 (message-encode-message-body)
1682 (run-hooks 'gnus-gcc-post-body-encode-hook)
1599 (save-restriction 1683 (save-restriction
1600 (message-narrow-to-headers) 1684 (message-narrow-to-headers)
1601 (let* ((mail-parse-charset message-default-charset) 1685 (let* ((mail-parse-charset message-default-charset)
@@ -1644,12 +1728,16 @@ this is a reply."
1644 (when (and group-art 1728 (when (and group-art
1645 ;; FIXME: Should gcc-mark-as-read work when 1729 ;; FIXME: Should gcc-mark-as-read work when
1646 ;; Gnus is not running? 1730 ;; Gnus is not running?
1647 (gnus-alive-p) 1731 (gnus-alive-p))
1648 (or gnus-gcc-mark-as-read 1732 (if (or gnus-gcc-mark-as-read
1649 (and 1733 (and (boundp 'gnus-inews-mark-gcc-as-read)
1650 (boundp 'gnus-inews-mark-gcc-as-read) 1734 (symbol-value 'gnus-inews-mark-gcc-as-read)))
1651 (symbol-value 'gnus-inews-mark-gcc-as-read)))) 1735 (gnus-group-mark-article-read group (cdr group-art))
1652 (gnus-group-mark-article-read group (cdr group-art))) 1736 (with-current-buffer gnus-group-buffer
1737 (let ((gnus-group-marked (list group))
1738 (gnus-get-new-news-hook nil)
1739 (inhibit-read-only t))
1740 (gnus-group-get-new-news-this-group nil t)))))
1653 (setq options message-options) 1741 (setq options message-options)
1654 (with-current-buffer cur (setq message-options options)) 1742 (with-current-buffer cur (setq message-options options))
1655 (kill-buffer (current-buffer))))))))) 1743 (kill-buffer (current-buffer)))))))))
diff --git a/lisp/gnus/gnus-picon.el b/lisp/gnus/gnus-picon.el
index 2f347efe579..3b335b335dd 100644
--- a/lisp/gnus/gnus-picon.el
+++ b/lisp/gnus/gnus-picon.el
@@ -75,6 +75,12 @@ Some people may want to add \"unknown\" to this list."
75 :type '(repeat string) 75 :type '(repeat string)
76 :group 'gnus-picon) 76 :group 'gnus-picon)
77 77
78(defcustom gnus-picon-properties '(:color-symbols (("None" . "white")))
79 "List of image properties applied to picons."
80 :type 'list
81 :version "24.2"
82 :group 'gnus-picon)
83
78(defcustom gnus-picon-style 'inline 84(defcustom gnus-picon-style 'inline
79 "How should picons be displayed. 85 "How should picons be displayed.
80If `inline', the textual representation is replaced. If `right', picons are 86If `inline', the textual representation is replaced. If `right', picons are
@@ -157,9 +163,9 @@ replacement is added."
157 163
158(defun gnus-picon-create-glyph (file) 164(defun gnus-picon-create-glyph (file)
159 (or (cdr (assoc file gnus-picon-glyph-alist)) 165 (or (cdr (assoc file gnus-picon-glyph-alist))
160 (cdar (push (cons file (gnus-create-image 166 (cdar (push (cons file (apply 'gnus-create-image
161 file nil nil 167 file nil nil
162 :color-symbols '(("None" . "white")))) 168 gnus-picon-properties))
163 gnus-picon-glyph-alist)))) 169 gnus-picon-glyph-alist))))
164 170
165;;; Functions that does picon transformations: 171;;; Functions that does picon transformations:
diff --git a/lisp/gnus/gnus-registry.el b/lisp/gnus/gnus-registry.el
index 53690f04169..8aecc98ee86 100644
--- a/lisp/gnus/gnus-registry.el
+++ b/lisp/gnus/gnus-registry.el
@@ -78,12 +78,6 @@
78 78
79(eval-when-compile (require 'cl)) 79(eval-when-compile (require 'cl))
80 80
81(eval-when-compile
82 (when (null (ignore-errors (require 'ert)))
83 (defmacro* ert-deftest (name () &body docstring-keys-and-body))))
84
85(ignore-errors
86 (require 'ert))
87(require 'gnus) 81(require 'gnus)
88(require 'gnus-int) 82(require 'gnus-int)
89(require 'gnus-sum) 83(require 'gnus-sum)
@@ -267,7 +261,7 @@ the Bit Bucket."
267 (append gnus-registry-track-extra 261 (append gnus-registry-track-extra
268 '(mark group keyword))) 262 '(mark group keyword)))
269 (when (not (equal old (oref db :tracked))) 263 (when (not (equal old (oref db :tracked)))
270 (gnus-message 4 "Reindexing the Gnus registry (tracked change)") 264 (gnus-message 9 "Reindexing the Gnus registry (tracked change)")
271 (registry-reindex db)))) 265 (registry-reindex db))))
272 db) 266 db)
273 267
@@ -1077,79 +1071,6 @@ only the last one's marks are returned."
1077 (gnus-registry-set-id-key id key val)))) 1071 (gnus-registry-set-id-key id key val))))
1078 (message "Import done, collected %d entries" count)))) 1072 (message "Import done, collected %d entries" count))))
1079 1073
1080(ert-deftest gnus-registry-misc-test ()
1081 (should-error (gnus-registry-extract-addresses '("" "")))
1082
1083 (should (equal '("Ted Zlatanov <tzz@lifelogs.com>"
1084 "noname <ed@you.me>"
1085 "noname <cyd@stupidchicken.com>"
1086 "noname <tzz@lifelogs.com>")
1087 (gnus-registry-extract-addresses
1088 (concat "Ted Zlatanov <tzz@lifelogs.com>, "
1089 "ed <ed@you.me>, " ; "ed" is not a valid name here
1090 "cyd@stupidchicken.com, "
1091 "tzz@lifelogs.com")))))
1092
1093(ert-deftest gnus-registry-usage-test ()
1094 (let* ((n 100)
1095 (tempfile (make-temp-file "gnus-registry-persist"))
1096 (db (gnus-registry-make-db tempfile))
1097 (gnus-registry-db db)
1098 back size)
1099 (message "Adding %d keys to the test Gnus registry" n)
1100 (dotimes (i n)
1101 (let ((id (number-to-string i)))
1102 (gnus-registry-handle-action id
1103 (if (>= 50 i) "fromgroup" nil)
1104 "togroup"
1105 (when (>= 70 i)
1106 (format "subject %d" (mod i 10)))
1107 (when (>= 80 i)
1108 (format "sender %d" (mod i 10))))))
1109 (message "Testing Gnus registry size is %d" n)
1110 (should (= n (registry-size db)))
1111 (message "Looking up individual keys (registry-lookup)")
1112 (should (equal (loop for e
1113 in (mapcar 'cadr
1114 (registry-lookup db '("20" "83" "72")))
1115 collect (assq 'subject e)
1116 collect (assq 'sender e)
1117 collect (assq 'group e))
1118 '((subject "subject 0") (sender "sender 0") (group "togroup")
1119 (subject) (sender) (group "togroup")
1120 (subject) (sender "sender 2") (group "togroup"))))
1121
1122 (message "Looking up individual keys (gnus-registry-id-key)")
1123 (should (equal (gnus-registry-get-id-key "34" 'group) '("togroup")))
1124 (should (equal (gnus-registry-get-id-key "34" 'subject) '("subject 4")))
1125 (message "Trying to insert a duplicate key")
1126 (should-error (gnus-registry-insert db "55" '()))
1127 (message "Looking up individual keys (gnus-registry-get-or-make-entry)")
1128 (should (gnus-registry-get-or-make-entry "22"))
1129 (message "Saving the Gnus registry to %s" tempfile)
1130 (should (gnus-registry-save tempfile db))
1131 (setq size (nth 7 (file-attributes tempfile)))
1132 (message "Saving the Gnus registry to %s: size %d" tempfile size)
1133 (should (< 0 size))
1134 (with-temp-buffer
1135 (insert-file-contents-literally tempfile)
1136 (should (looking-at (concat ";; Object "
1137 "Gnus Registry"
1138 "\n;; EIEIO PERSISTENT OBJECT"))))
1139 (message "Reading Gnus registry back")
1140 (setq back (eieio-persistent-read tempfile))
1141 (should back)
1142 (message "Read Gnus registry back: %d keys, expected %d==%d"
1143 (registry-size back) n (registry-size db))
1144 (should (= (registry-size back) n))
1145 (should (= (registry-size back) (registry-size db)))
1146 (delete-file tempfile)
1147 (message "Pruning Gnus registry to 0 by setting :max-soft")
1148 (oset db :max-soft 0)
1149 (registry-prune db)
1150 (should (= (registry-size db) 0)))
1151 (message "Done with Gnus registry usage testing."))
1152
1153;;;###autoload 1074;;;###autoload
1154(defun gnus-registry-initialize () 1075(defun gnus-registry-initialize ()
1155 "Initialize the Gnus registry." 1076 "Initialize the Gnus registry."
@@ -1206,6 +1127,52 @@ the user is asked first. Returns non-nil iff the registry is enabled."
1206 (gnus-registry-initialize))) 1127 (gnus-registry-initialize)))
1207 gnus-registry-enabled) 1128 gnus-registry-enabled)
1208 1129
1130;; largely based on nnir-warp-to-article
1131(defun gnus-try-warping-via-registry ()
1132 "Try to warp via the registry.
1133This will be done via the current article's source group based on
1134data stored in the registry."
1135 (interactive)
1136 (when (gnus-summary-article-header)
1137 (let* ((message-id (mail-header-id (gnus-summary-article-header)))
1138 ;; Retrieve the message's group(s) from the registry
1139 (groups (gnus-registry-get-id-key message-id 'group))
1140 ;; If starting from an ephemeral group, this describes
1141 ;; how to restore the window configuration
1142 (quit-config
1143 (gnus-ephemeral-group-p gnus-newsgroup-name))
1144 (seen-groups (list (gnus-group-group-name))))
1145
1146 (catch 'found
1147 (dolist (group (mapcar 'gnus-simplify-group-name groups))
1148
1149 ;; skip over any groups we really don't want to warp to.
1150 (unless (or (member group seen-groups)
1151 (gnus-ephemeral-group-p group) ;; any ephemeral group
1152 (memq (car (gnus-find-method-for-group group))
1153 ;; Specific methods; this list may need to expand.
1154 '(nnir)))
1155
1156 ;; remember that we've seen this group already
1157 (push group seen-groups)
1158
1159 ;; first exit from any ephemeral summary buffer.
1160 (when quit-config
1161 (gnus-summary-exit)
1162 ;; and if the ephemeral summary buffer in turn came from
1163 ;; another summary buffer we have to clean that summary
1164 ;; up too.
1165 (when (eq (cdr quit-config) 'summary)
1166 (gnus-summary-exit))
1167 ;; remember that we've already done this part
1168 (setq quit-config nil))
1169
1170 ;; Try to activate the group. If that fails, just move
1171 ;; along. We may have more groups to work with
1172 (ignore-errors
1173 (gnus-select-group-with-message-id group message-id))
1174 (throw 'found t)))))))
1175
1209;; TODO: a few things 1176;; TODO: a few things
1210 1177
1211(provide 'gnus-registry) 1178(provide 'gnus-registry)
diff --git a/lisp/gnus/gnus-spec.el b/lisp/gnus/gnus-spec.el
index e1879202ef3..f40177d5c60 100644
--- a/lisp/gnus/gnus-spec.el
+++ b/lisp/gnus/gnus-spec.el
@@ -101,66 +101,13 @@ text properties. This is only needed on XEmacs, as Emacs does this anyway."
101 (propertize (string 8206) 'invisible t) 101 (propertize (string 8206) 'invisible t)
102 "")) 102 ""))
103 103
104(defun gnus-summary-line-format-spec () 104(defvar gnus-summary-line-format-spec nil)
105 (insert gnus-tmp-unread gnus-tmp-replied 105(defvar gnus-summary-dummy-line-format-spec nil)
106 gnus-tmp-score-char gnus-tmp-indentation) 106(defvar gnus-group-line-format-spec nil)
107 (gnus-put-text-property
108 (point)
109 (progn
110 (insert
111 (format "%c%4s: %-23s%c" gnus-tmp-opening-bracket gnus-tmp-lines
112 (let ((val
113 (inline
114 (gnus-summary-from-or-to-or-newsgroups
115 gnus-tmp-header gnus-tmp-from))))
116 (if (> (length val) 23)
117 (if (gnus-lrm-string-p val)
118 (concat (substring val 0 23) gnus-lrm-string)
119 (substring val 0 23))
120 val))
121 gnus-tmp-closing-bracket))
122 (point))
123 gnus-mouse-face-prop gnus-mouse-face)
124 (insert " " gnus-tmp-subject-or-nil "\n"))
125
126(defvar gnus-summary-line-format-spec
127 (gnus-byte-code 'gnus-summary-line-format-spec))
128
129(defun gnus-summary-dummy-line-format-spec ()
130 (insert "* ")
131 (gnus-put-text-property
132 (point)
133 (progn
134 (insert ": :")
135 (point))
136 gnus-mouse-face-prop gnus-mouse-face)
137 (insert " " gnus-tmp-subject "\n"))
138
139(defvar gnus-summary-dummy-line-format-spec
140 (gnus-byte-code 'gnus-summary-dummy-line-format-spec))
141
142(defun gnus-group-line-format-spec ()
143 (insert gnus-tmp-marked-mark gnus-tmp-subscribed
144 gnus-tmp-process-marked
145 gnus-group-indentation
146 (format "%5s: " gnus-tmp-number-of-unread))
147 (gnus-put-text-property
148 (point)
149 (progn
150 (insert gnus-tmp-group "\n")
151 (1- (point)))
152 gnus-mouse-face-prop gnus-mouse-face))
153(defvar gnus-group-line-format-spec
154 (gnus-byte-code 'gnus-group-line-format-spec))
155 107
156(defvar gnus-format-specs 108(defvar gnus-format-specs
157 `((version . ,emacs-version) 109 `((version . ,emacs-version)
158 (gnus-version . ,(gnus-continuum-version)) 110 (gnus-version . ,(gnus-continuum-version)))
159 (group "%M\%S\%p\%P\%5y: %(%g%)\n" ,gnus-group-line-format-spec)
160 (summary-dummy "* %(: :%) %S\n"
161 ,gnus-summary-dummy-line-format-spec)
162 (summary "%U%R%z%I%(%[%4L: %-23,23f%]%) %s\n"
163 ,gnus-summary-line-format-spec))
164 "Alist of format specs.") 111 "Alist of format specs.")
165 112
166(defvar gnus-default-format-specs gnus-format-specs) 113(defvar gnus-default-format-specs gnus-format-specs)
@@ -214,15 +161,6 @@ Return a list of updated types."
214 (not (equal emacs-version 161 (not (equal emacs-version
215 (cdr (assq 'version gnus-format-specs))))) 162 (cdr (assq 'version gnus-format-specs)))))
216 (setq gnus-format-specs nil)) 163 (setq gnus-format-specs nil))
217 ;; Flush the group format spec cache if there's the grouplens stuff
218 ;; or it doesn't support decoded group names.
219 (when (memq 'group types)
220 (let* ((spec (assq 'group gnus-format-specs))
221 (sspec (gnus-prin1-to-string (nth 2 spec))))
222 (when (or (string-match " gnus-tmp-grouplens[ )]" sspec)
223 (not (string-match " gnus-tmp-decoded-group[ )]" sspec)))
224 (setq gnus-format-specs (delq spec gnus-format-specs)))))
225
226 ;; Go through all the formats and see whether they need updating. 164 ;; Go through all the formats and see whether they need updating.
227 (let (new-format entry type val updated) 165 (let (new-format entry type val updated)
228 (while (setq type (pop types)) 166 (while (setq type (pop types))
@@ -778,36 +716,6 @@ If PROPS, insert the result."
778 (gnus-add-text-properties (point) (progn (eval form) (point)) props) 716 (gnus-add-text-properties (point) (progn (eval form) (point)) props)
779 (eval form)))) 717 (eval form))))
780 718
781(defun gnus-compile ()
782 "Byte-compile the user-defined format specs."
783 (interactive)
784 (require 'bytecomp)
785 (let ((entries gnus-format-specs)
786 (byte-compile-warnings '(unresolved callargs redefine))
787 entry gnus-tmp-func)
788 (save-excursion
789 (gnus-message 7 "Compiling format specs...")
790
791 (while entries
792 (setq entry (pop entries))
793 (if (memq (car entry) '(gnus-version version))
794 (setq gnus-format-specs (delq entry gnus-format-specs))
795 (let ((form (caddr entry)))
796 (when (and (listp form)
797 ;; Under GNU Emacs, it's (byte-code ...)
798 (not (eq 'byte-code (car form)))
799 ;; Under XEmacs, it's (funcall #<compiled-function ...>)
800 (not (and (eq 'funcall (car form))
801 (byte-code-function-p (cadr form)))))
802 (defalias 'gnus-tmp-func `(lambda () ,form))
803 (byte-compile 'gnus-tmp-func)
804 (setcar (cddr entry) (gnus-byte-code 'gnus-tmp-func))))))
805
806 (push (cons 'version emacs-version) gnus-format-specs)
807 ;; Mark the .newsrc.eld file as "dirty".
808 (gnus-dribble-touch)
809 (gnus-message 7 "Compiling user specs...done"))))
810
811(defun gnus-set-format (type &optional insertable) 719(defun gnus-set-format (type &optional insertable)
812 (set (intern (format "gnus-%s-line-format-spec" type)) 720 (set (intern (format "gnus-%s-line-format-spec" type))
813 (gnus-parse-format 721 (gnus-parse-format
diff --git a/lisp/gnus/gnus-start.el b/lisp/gnus/gnus-start.el
index f025960c348..15bbf01c469 100644
--- a/lisp/gnus/gnus-start.el
+++ b/lisp/gnus/gnus-start.el
@@ -1504,8 +1504,6 @@ backend check whether the group actually exists."
1504 ;; Return the new active info. 1504 ;; Return the new active info.
1505 active))))) 1505 active)))))
1506 1506
1507(defvar gnus-propagate-marks) ; gnus-sum
1508
1509(defun gnus-get-unread-articles-in-group (info active &optional update) 1507(defun gnus-get-unread-articles-in-group (info active &optional update)
1510 (when (and info active) 1508 (when (and info active)
1511 ;; Allow the backend to update the info in the group. 1509 ;; Allow the backend to update the info in the group.
@@ -1515,13 +1513,6 @@ backend check whether the group actually exists."
1515 (gnus-info-group info))))) 1513 (gnus-info-group info)))))
1516 (gnus-activate-group (gnus-info-group info) nil t)) 1514 (gnus-activate-group (gnus-info-group info) nil t))
1517 1515
1518 ;; Allow backends to update marks,
1519 (when gnus-propagate-marks
1520 (let ((method (inline (gnus-find-method-for-group
1521 (gnus-info-group info)))))
1522 (when (gnus-check-backend-function 'request-marks (car method))
1523 (gnus-request-marks info method))))
1524
1525 (let* ((range (gnus-info-read info)) 1516 (let* ((range (gnus-info-read info))
1526 (num 0)) 1517 (num 0))
1527 1518
@@ -1610,7 +1601,7 @@ backend check whether the group actually exists."
1610 1601
1611;; Go though `gnus-newsrc-alist' and compare with `gnus-active-hashtb' 1602;; Go though `gnus-newsrc-alist' and compare with `gnus-active-hashtb'
1612;; and compute how many unread articles there are in each group. 1603;; and compute how many unread articles there are in each group.
1613(defun gnus-get-unread-articles (&optional level dont-connect) 1604(defun gnus-get-unread-articles (&optional level dont-connect one-level)
1614 (setq gnus-server-method-cache nil) 1605 (setq gnus-server-method-cache nil)
1615 (require 'gnus-agent) 1606 (require 'gnus-agent)
1616 (let* ((newsrc (cdr gnus-newsrc-alist)) 1607 (let* ((newsrc (cdr gnus-newsrc-alist))
@@ -1667,7 +1658,7 @@ backend check whether the group actually exists."
1667 (push (setq method-group-list (list method method-type nil nil)) 1658 (push (setq method-group-list (list method method-type nil nil))
1668 type-cache)) 1659 type-cache))
1669 ;; Only add groups that need updating. 1660 ;; Only add groups that need updating.
1670 (if (<= (gnus-info-level info) 1661 (if (funcall (if one-level #'= #'<=) (gnus-info-level info)
1671 (if (eq (cadr method-group-list) 'foreign) 1662 (if (eq (cadr method-group-list) 'foreign)
1672 foreign-level 1663 foreign-level
1673 alevel)) 1664 alevel))
@@ -2230,7 +2221,7 @@ backend check whether the group actually exists."
2230 (gnus-online method) 2221 (gnus-online method)
2231 (gnus-agent-method-p method)) 2222 (gnus-agent-method-p method))
2232 (progn 2223 (progn
2233 (gnus-agent-save-active method) 2224 (gnus-agent-save-active method t)
2234 (gnus-active-to-gnus-format method hashtb nil real-active)) 2225 (gnus-active-to-gnus-format method hashtb nil real-active))
2235 2226
2236 (goto-char (point-min)) 2227 (goto-char (point-min))
diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el
index 7f095e15496..10b314a1435 100644
--- a/lisp/gnus/gnus-sum.el
+++ b/lisp/gnus/gnus-sum.el
@@ -451,7 +451,8 @@ current article is unread."
451 :group 'gnus-summary-maneuvering 451 :group 'gnus-summary-maneuvering
452 :type 'boolean) 452 :type 'boolean)
453 453
454(defcustom gnus-auto-center-summary 2 454(defcustom gnus-auto-center-summary
455 (max (or (bound-and-true-p scroll-margin) 0) 2)
455 "*If non-nil, always center the current summary buffer. 456 "*If non-nil, always center the current summary buffer.
456In particular, if `vertical' do only vertical recentering. If non-nil 457In particular, if `vertical' do only vertical recentering. If non-nil
457and non-`vertical', do both horizontal and vertical recentering." 458and non-`vertical', do both horizontal and vertical recentering."
@@ -1243,13 +1244,6 @@ For example: ((1 . cn-gb-2312) (2 . big5))."
1243 :type 'boolean 1244 :type 'boolean
1244 :group 'gnus-summary-marks) 1245 :group 'gnus-summary-marks)
1245 1246
1246(defcustom gnus-propagate-marks nil
1247 "If non-nil, Gnus will store and retrieve marks from the backends.
1248This means that marks will be stored both in .newsrc.eld and in
1249the backend, and will slow operation down somewhat."
1250 :type 'boolean
1251 :group 'gnus-summary-marks)
1252
1253(defcustom gnus-alter-articles-to-read-function nil 1247(defcustom gnus-alter-articles-to-read-function nil
1254 "Function to be called to alter the list of articles to be selected." 1248 "Function to be called to alter the list of articles to be selected."
1255 :type '(choice (const nil) function) 1249 :type '(choice (const nil) function)
@@ -1918,6 +1912,7 @@ increase the score of each group you read."
1918 "x" gnus-summary-limit-to-unread 1912 "x" gnus-summary-limit-to-unread
1919 "s" gnus-summary-isearch-article 1913 "s" gnus-summary-isearch-article
1920 [tab] gnus-summary-widget-forward 1914 [tab] gnus-summary-widget-forward
1915 [backtab] gnus-summary-widget-backward
1921 "t" gnus-summary-toggle-header 1916 "t" gnus-summary-toggle-header
1922 "g" gnus-summary-show-article 1917 "g" gnus-summary-show-article
1923 "l" gnus-summary-goto-last-article 1918 "l" gnus-summary-goto-last-article
@@ -2082,6 +2077,7 @@ increase the score of each group you read."
2082 "g" gnus-summary-show-article 2077 "g" gnus-summary-show-article
2083 "s" gnus-summary-isearch-article 2078 "s" gnus-summary-isearch-article
2084 [tab] gnus-summary-widget-forward 2079 [tab] gnus-summary-widget-forward
2080 [backtab] gnus-summary-widget-backward
2085 "P" gnus-summary-print-article 2081 "P" gnus-summary-print-article
2086 "S" gnus-sticky-article 2082 "S" gnus-sticky-article
2087 "M" gnus-mailing-list-insinuate 2083 "M" gnus-mailing-list-insinuate
@@ -3558,7 +3554,7 @@ buffer that was in action when the last article was fetched."
3558 (push (eval (car locals)) vlist)) 3554 (push (eval (car locals)) vlist))
3559 (setq locals (cdr locals))) 3555 (setq locals (cdr locals)))
3560 (setq vlist (nreverse vlist))) 3556 (setq vlist (nreverse vlist)))
3561 (with-current-buffer gnus-group-buffer 3557 (with-temp-buffer
3562 (setq gnus-newsgroup-name name 3558 (setq gnus-newsgroup-name name
3563 gnus-newsgroup-marked marked 3559 gnus-newsgroup-marked marked
3564 gnus-newsgroup-spam-marked spam 3560 gnus-newsgroup-spam-marked spam
@@ -6074,10 +6070,6 @@ If SELECT-ARTICLES, only select those articles from GROUP."
6074 6070
6075 (when (and (gnus-check-backend-function 6071 (when (and (gnus-check-backend-function
6076 'request-set-mark gnus-newsgroup-name) 6072 'request-set-mark gnus-newsgroup-name)
6077 (or gnus-propagate-marks
6078 (gnus-method-option-p
6079 (gnus-find-method-for-group gnus-newsgroup-name)
6080 'server-marks))
6081 (not (gnus-article-unpropagatable-p (cdr type)))) 6073 (not (gnus-article-unpropagatable-p (cdr type))))
6082 (let* ((old (cdr (assq (cdr type) (gnus-info-marks info)))) 6074 (let* ((old (cdr (assq (cdr type) (gnus-info-marks info))))
6083 ;; Don't do anything about marks for articles we 6075 ;; Don't do anything about marks for articles we
@@ -6289,10 +6281,9 @@ The resulting hash table is returned, or nil if no Xrefs were found."
6289 (info (nth 2 entry)) 6281 (info (nth 2 entry))
6290 (active (gnus-active group)) 6282 (active (gnus-active group))
6291 (set-marks 6283 (set-marks
6292 (or gnus-propagate-marks 6284 (gnus-method-option-p
6293 (gnus-method-option-p 6285 (gnus-find-method-for-group group)
6294 (gnus-find-method-for-group group) 6286 'server-marks))
6295 'server-marks)))
6296 range) 6287 range)
6297 (if (not entry) 6288 (if (not entry)
6298 ;; Group that Gnus doesn't know exists, but still allow the 6289 ;; Group that Gnus doesn't know exists, but still allow the
@@ -6629,9 +6620,9 @@ too, instead of trying to fetch new headers."
6629 ;; article if ID is a number -- so that the next `P' or `N' 6620 ;; article if ID is a number -- so that the next `P' or `N'
6630 ;; command will fetch the previous (or next) article even 6621 ;; command will fetch the previous (or next) article even
6631 ;; if the one we tried to fetch this time has been canceled. 6622 ;; if the one we tried to fetch this time has been canceled.
6632 (when (> number gnus-newsgroup-end) 6623 (unless (and gnus-newsgroup-end (< number gnus-newsgroup-end))
6633 (setq gnus-newsgroup-end number)) 6624 (setq gnus-newsgroup-end number))
6634 (when (< number gnus-newsgroup-begin) 6625 (unless (and gnus-newsgroup-begin (> number gnus-newsgroup-begin))
6635 (setq gnus-newsgroup-begin number)) 6626 (setq gnus-newsgroup-begin number))
6636 (setq gnus-newsgroup-unselected 6627 (setq gnus-newsgroup-unselected
6637 (delq number gnus-newsgroup-unselected))) 6628 (delq number gnus-newsgroup-unselected)))
@@ -7257,7 +7248,8 @@ If FORCE (the prefix), also save the .newsrc file(s)."
7257 (gnus-summary-update-info)) 7248 (gnus-summary-update-info))
7258 (gnus-close-group group) 7249 (gnus-close-group group)
7259 ;; Make sure where we were, and go to next newsgroup. 7250 ;; Make sure where we were, and go to next newsgroup.
7260 (set-buffer gnus-group-buffer) 7251 (when (buffer-live-p (get-buffer gnus-group-buffer))
7252 (set-buffer gnus-group-buffer))
7261 (unless quit-config 7253 (unless quit-config
7262 (gnus-group-jump-to-group group)) 7254 (gnus-group-jump-to-group group))
7263 (gnus-run-hooks 'gnus-summary-exit-hook) 7255 (gnus-run-hooks 'gnus-summary-exit-hook)
@@ -7282,7 +7274,8 @@ If FORCE (the prefix), also save the .newsrc file(s)."
7282 (gnus-kill-buffer buf))) 7274 (gnus-kill-buffer buf)))
7283 7275
7284 (setq gnus-current-select-method gnus-select-method) 7276 (setq gnus-current-select-method gnus-select-method)
7285 (set-buffer gnus-group-buffer) 7277 (when (gnus-buffer-live-p gnus-group-buffer)
7278 (set-buffer gnus-group-buffer))
7286 (if quit-config 7279 (if quit-config
7287 (gnus-handle-ephemeral-exit quit-config) 7280 (gnus-handle-ephemeral-exit quit-config)
7288 (goto-char group-point) 7281 (goto-char group-point)
@@ -7361,7 +7354,8 @@ If FORCE (the prefix), also save the .newsrc file(s)."
7361 "Handle movement when leaving an ephemeral group. 7354 "Handle movement when leaving an ephemeral group.
7362The state which existed when entering the ephemeral is reset." 7355The state which existed when entering the ephemeral is reset."
7363 (if (not (buffer-live-p (car quit-config))) 7356 (if (not (buffer-live-p (car quit-config)))
7364 (gnus-configure-windows 'group 'force) 7357 (when (gnus-buffer-live-p gnus-group-buffer)
7358 (gnus-configure-windows 'group 'force))
7365 (set-buffer (car quit-config)) 7359 (set-buffer (car quit-config))
7366 (unless (eq (cdr quit-config) 'group) 7360 (unless (eq (cdr quit-config) 'group)
7367 (setq gnus-current-select-method 7361 (setq gnus-current-select-method
@@ -8238,7 +8232,12 @@ If NOT-MATCHING, excluding articles that have authors that match a regexp."
8238 (interactive 8232 (interactive
8239 (list (read-string (if current-prefix-arg 8233 (list (read-string (if current-prefix-arg
8240 "Exclude author (regexp): " 8234 "Exclude author (regexp): "
8241 "Limit to author (regexp): ")) 8235 "Limit to author (regexp): ")
8236 (let ((header (gnus-summary-article-header)))
8237 (if (not header)
8238 ""
8239 (car (mail-header-parse-address
8240 (mail-header-from header))))))
8242 current-prefix-arg)) 8241 current-prefix-arg))
8243 (gnus-summary-limit-to-subject from "from" not-matching)) 8242 (gnus-summary-limit-to-subject from "from" not-matching))
8244 8243
@@ -9270,6 +9269,17 @@ With optional ARG, move across that many fields."
9270 (select-window (gnus-get-buffer-window gnus-article-buffer)) 9269 (select-window (gnus-get-buffer-window gnus-article-buffer))
9271 (widget-forward arg)) 9270 (widget-forward arg))
9272 9271
9272(defun gnus-summary-widget-backward (arg)
9273 "Move point to the previous field or button in the article.
9274With optional ARG, move across that many fields."
9275 (interactive "p")
9276 (gnus-summary-select-article)
9277 (gnus-configure-windows 'article)
9278 (select-window (gnus-get-buffer-window gnus-article-buffer))
9279 (unless (widget-at (point))
9280 (goto-char (point-max)))
9281 (widget-backward arg))
9282
9273(defun gnus-summary-isearch-article (&optional regexp-p) 9283(defun gnus-summary-isearch-article (&optional regexp-p)
9274 "Do incremental search forward on the current article. 9284 "Do incremental search forward on the current article.
9275If REGEXP-P (the prefix) is non-nil, do regexp isearch." 9285If REGEXP-P (the prefix) is non-nil, do regexp isearch."
@@ -10080,10 +10090,9 @@ ACTION can be either `move' (the default), `crosspost' or `copy'."
10080 to-group 'expire (list to-article) info)) 10090 to-group 'expire (list to-article) info))
10081 10091
10082 (when (and to-marks 10092 (when (and to-marks
10083 (or gnus-propagate-marks 10093 (gnus-method-option-p
10084 (gnus-method-option-p 10094 (gnus-find-method-for-group to-group)
10085 (gnus-find-method-for-group to-group) 10095 'server-marks))
10086 'server-marks)))
10087 (gnus-request-set-mark 10096 (gnus-request-set-mark
10088 to-group (list (list (list to-article) 'add to-marks))))) 10097 to-group (list (list (list to-article) 'add to-marks)))))
10089 10098
@@ -12418,6 +12427,13 @@ If REVERSE, save parts that do not match TYPE."
12418 (not (setq header (car (gnus-get-newsgroup-headers nil t))))) 12427 (not (setq header (car (gnus-get-newsgroup-headers nil t)))))
12419 () ; Malformed head. 12428 () ; Malformed head.
12420 (unless (gnus-summary-article-sparse-p (mail-header-number header)) 12429 (unless (gnus-summary-article-sparse-p (mail-header-number header))
12430 (when (and (bound-and-true-p gnus-registry-enabled)
12431 (not (gnus-ephemeral-group-p (car where))))
12432 (gnus-registry-handle-action
12433 (mail-header-id header) nil
12434 (gnus-group-prefixed-name (car where) gnus-override-method)
12435 (mail-header-subject header)
12436 (mail-header-from header)))
12421 (when (and (stringp id) 12437 (when (and (stringp id)
12422 (or 12438 (or
12423 (not (string= (gnus-group-real-name group) 12439 (not (string= (gnus-group-real-name group)
@@ -12565,10 +12581,9 @@ UNREAD is a sorted list."
12565 (save-excursion 12581 (save-excursion
12566 (let (setmarkundo) 12582 (let (setmarkundo)
12567 ;; Propagate the read marks to the backend. 12583 ;; Propagate the read marks to the backend.
12568 (when (and (or gnus-propagate-marks 12584 (when (and (gnus-method-option-p
12569 (gnus-method-option-p 12585 (gnus-find-method-for-group group)
12570 (gnus-find-method-for-group group) 12586 'server-marks)
12571 'server-marks))
12572 (gnus-check-backend-function 'request-set-mark group)) 12587 (gnus-check-backend-function 'request-set-mark group))
12573 (let ((del (gnus-remove-from-range (gnus-info-read info) read)) 12588 (let ((del (gnus-remove-from-range (gnus-info-read info) read))
12574 (add (gnus-remove-from-range read (gnus-info-read info)))) 12589 (add (gnus-remove-from-range read (gnus-info-read info))))
diff --git a/lisp/gnus/gnus-sync.el b/lisp/gnus/gnus-sync.el
index 6efd34e1596..7e13b885edf 100644
--- a/lisp/gnus/gnus-sync.el
+++ b/lisp/gnus/gnus-sync.el
@@ -24,44 +24,94 @@
24 24
25;; This is the gnus-sync.el package. 25;; This is the gnus-sync.el package.
26 26
27;; It's due for a rewrite using gnus-after-set-mark-hook and
28;; gnus-before-update-mark-hook, and my plan is to do this once No
29;; Gnus development is done. Until then please consider it
30;; experimental.
31
32;; Put this in your startup file (~/.gnus.el for instance) 27;; Put this in your startup file (~/.gnus.el for instance)
33 28
34;; possibilities for gnus-sync-backend: 29;; possibilities for gnus-sync-backend:
35;; Tramp over SSH: /ssh:user@host:/path/to/filename 30;; Tramp over SSH: /ssh:user@host:/path/to/filename
36;; Tramp over IMAP: /imaps:user@yourhosthere.com:/INBOX.test/filename
37;; ...or any other file Tramp and Emacs can handle... 31;; ...or any other file Tramp and Emacs can handle...
38 32
39;; (setq gnus-sync-backend "/remote:/path.gpg" ; will use Tramp+EPA if loaded 33;; (setq gnus-sync-backend "/remote:/path.gpg" ; will use Tramp+EPA if loaded
40;; gnus-sync-global-vars `(gnus-newsrc-last-checked-date) 34;; gnus-sync-global-vars '(gnus-newsrc-last-checked-date)
41;; gnus-sync-newsrc-groups `("nntp" "nnrss") 35;; gnus-sync-newsrc-groups '("nntp" "nnrss"))
42;; gnus-sync-newsrc-offsets `(2 3)) 36;; gnus-sync-newsrc-offsets '(2 3))
37;; against a LeSync server (beware the vampire LeSync, who knows your newsrc)
38
39;; (setq gnus-sync-backend '(lesync "http://lesync.info:5984/tzz")
40;; gnus-sync-newsrc-groups '("nntp" "nnrss"))
41
42;; What's a LeSync server?
43
44;; 1. install CouchDB, set up a real server admin user, and create a
45;; database, e.g. "tzz" and save the URL,
46;; e.g. http://lesync.info:5984/tzz
47
48;; 2. run `M-: (gnus-sync-lesync-setup "http://lesync.info:5984/tzz" "tzzadmin" "mypassword" "mysalt" t t)'
49
50;; (If you run it more than once, you have to remove the entry from
51;; _users yourself. This is intentional. This sets up a database
52;; admin for the "tzz" database, distinct from the server admin
53;; user in (1) above.)
54
55;; That's it, you can start using http://lesync.info:5984/tzz in your
56;; gnus-sync-backend as a LeSync backend. Fan fiction about the
57;; vampire LeSync is welcome.
58
59;; You may not want to expose a CouchDB install to the Big Bad
60;; Internet, especially if your love of all things furry would be thus
61;; revealed. Make sure it's not accessible by unauthorized users and
62;; guests, at least.
63
64;; If you want to try it out, I will create a test DB for you under
65;; http://lesync.info:5984/yourfavoritedbname
43 66
44;; TODO: 67;; TODO:
45 68
46;; - after gnus-sync-read, the message counts are wrong. So it's not 69;; - after gnus-sync-read, the message counts look wrong until you do
47;; run automatically, you have to call it with M-x gnus-sync-read 70;; `g'. So it's not run automatically, you have to call it with M-x
71;; gnus-sync-read
48 72
49;; - use gnus-after-set-mark-hook and gnus-before-update-mark-hook to 73;; - use gnus-after-set-mark-hook and gnus-before-update-mark-hook to
50;; catch the mark updates 74;; catch the mark updates
51 75
76;; - repositioning of groups within topic after a LeSync sync is a
77;; weird sort of bubble sort ("buttle" sort: the old entry ends up
78;; at the rear of the list); you will eventually end up with the
79;; right order after calling `gnus-sync-read' a bunch of times.
80
81;; - installing topics and groups is inefficient and annoying, lots of
82;; prompts could be avoided
83
52;;; Code: 84;;; Code:
53 85
54(eval-when-compile (require 'cl)) 86(eval-when-compile (require 'cl))
87(eval-and-compile
88 (or (ignore-errors (progn
89 (require 'json)))
90 ;; gnus-fallback-lib/ from gnus/lisp/gnus-fallback-lib
91 (ignore-errors
92 (let ((load-path (cons (expand-file-name
93 "gnus-fallback-lib"
94 (file-name-directory (locate-library "gnus")))
95 load-path)))
96 (require 'json)))
97 (error
98 "json not found in `load-path' or gnus-fallback-lib/ directory.")))
55(require 'gnus) 99(require 'gnus)
56(require 'gnus-start) 100(require 'gnus-start)
57(require 'gnus-util) 101(require 'gnus-util)
58 102
103(defvar gnus-topic-alist) ;; gnus-group.el
104(eval-when-compile
105 (autoload 'gnus-group-topic "gnus-topic")
106 (autoload 'gnus-topic-create-topic "gnus-topic" nil t)
107 (autoload 'gnus-topic-enter-dribble "gnus-topic"))
108
59(defgroup gnus-sync nil 109(defgroup gnus-sync nil
60 "The Gnus synchronization facility." 110 "The Gnus synchronization facility."
61 :version "24.1" 111 :version "24.1"
62 :group 'gnus) 112 :group 'gnus)
63 113
64(defcustom gnus-sync-newsrc-groups `("nntp" "nnrss") 114(defcustom gnus-sync-newsrc-groups '("nntp" "nnrss")
65 "List of groups to be synchronized in the gnus-newsrc-alist. 115 "List of groups to be synchronized in the gnus-newsrc-alist.
66The group names are matched, they don't have to be fully 116The group names are matched, they don't have to be fully
67qualified. Typically you would choose all of these. That's the 117qualified. Typically you would choose all of these. That's the
@@ -70,20 +120,12 @@ this setting is harmless until the user chooses a sync backend."
70 :group 'gnus-sync 120 :group 'gnus-sync
71 :type '(repeat regexp)) 121 :type '(repeat regexp))
72 122
73(defcustom gnus-sync-newsrc-offsets '(2 3)
74 "List of per-group data to be synchronized."
75 :group 'gnus-sync
76 :type '(set (const :tag "Read ranges" 2)
77 (const :tag "Marks" 3)))
78
79(defcustom gnus-sync-global-vars nil 123(defcustom gnus-sync-global-vars nil
80 "List of global variables to be synchronized. 124 "List of global variables to be synchronized.
81You may want to sync `gnus-newsrc-last-checked-date' but pretty 125You may want to sync `gnus-newsrc-last-checked-date' but pretty
82much any symbol is fair game. You could additionally sync 126much any symbol is fair game. You could additionally sync
83`gnus-newsrc-alist', `gnus-server-alist', `gnus-topic-topology', 127`gnus-newsrc-alist', `gnus-server-alist', `gnus-topic-topology',
84and `gnus-topic-alist' to cover all the variables in 128and `gnus-topic-alist'. Also see `gnus-variable-list'."
85newsrc.eld (except for `gnus-format-specs' which should not be
86synchronized, I believe). Also see `gnus-variable-list'."
87 :group 'gnus-sync 129 :group 'gnus-sync
88 :type '(repeat (choice (variable :tag "A known variable") 130 :type '(repeat (choice (variable :tag "A known variable")
89 (symbol :tag "Any symbol")))) 131 (symbol :tag "Any symbol"))))
@@ -92,30 +134,625 @@ synchronized, I believe). Also see `gnus-variable-list'."
92 "The synchronization backend." 134 "The synchronization backend."
93 :group 'gnus-sync 135 :group 'gnus-sync
94 :type '(radio (const :format "None" nil) 136 :type '(radio (const :format "None" nil)
137 (list :tag "Sync server"
138 (const :format "LeSync Server API" lesync)
139 (string :tag "URL of a CouchDB database for API access"))
95 (string :tag "Sync to a file"))) 140 (string :tag "Sync to a file")))
96 141
97(defvar gnus-sync-newsrc-loader nil 142(defvar gnus-sync-newsrc-loader nil
98 "Carrier for newsrc data") 143 "Carrier for newsrc data")
99 144
100(defun gnus-sync-save () 145(defcustom gnus-sync-lesync-name (system-name)
101"Save the Gnus sync data to the backend." 146 "The LeSync name for this machine."
102 (interactive) 147 :group 'gnus-sync
148 :type 'string)
149
150(defcustom gnus-sync-lesync-install-topics 'ask
151 "Should LeSync install the recorded topics?"
152 :group 'gnus-sync
153 :type '(choice (const :tag "Never Install" nil)
154 (const :tag "Always Install" t)
155 (const :tag "Ask Me Once" ask)))
156
157(defvar gnus-sync-lesync-props-hash (make-hash-table :test 'equal)
158 "LeSync props, keyed by group name")
159
160(defvar gnus-sync-lesync-design-prefix "/_design/lesync"
161 "The LeSync design prefix for CouchDB")
162
163(defvar gnus-sync-lesync-security-object "/_security"
164 "The LeSync security object for CouchDB")
165
166(defun gnus-sync-lesync-parse ()
167 "Parse the result of a LeSync request."
168 (goto-char (point-min))
169 (condition-case nil
170 (when (search-forward-regexp "^$" nil t)
171 (json-read))
172 (error
173 (gnus-message
174 1
175 "gnus-sync-lesync-parse: Could not read the LeSync response!")
176 nil)))
177
178(defun gnus-sync-lesync-call (url method headers &optional kvdata)
179 "Make an access request to URL using KVDATA and METHOD.
180KVDATA must be an alist."
181 (flet ((json-alist-p (list) (gnus-sync-json-alist-p list))) ; temp patch
182 (let ((url-request-method method)
183 (url-request-extra-headers headers)
184 (url-request-data (if kvdata (json-encode kvdata) nil)))
185 (with-current-buffer (url-retrieve-synchronously url)
186 (let ((data (gnus-sync-lesync-parse)))
187 (gnus-message 12 "gnus-sync-lesync-call: %s URL %s sent %S got %S"
188 method url `((headers . ,headers) (data ,kvdata)) data)
189 (kill-buffer (current-buffer))
190 data)))))
191
192(defun gnus-sync-lesync-PUT (url headers &optional data)
193 (gnus-sync-lesync-call url "PUT" headers data))
194
195(defun gnus-sync-lesync-POST (url headers &optional data)
196 (gnus-sync-lesync-call url "POST" headers data))
197
198(defun gnus-sync-lesync-GET (url headers &optional data)
199 (gnus-sync-lesync-call url "GET" headers data))
200
201(defun gnus-sync-lesync-DELETE (url headers &optional data)
202 (gnus-sync-lesync-call url "DELETE" headers data))
203
204;; this is not necessary with newer versions of json.el but 1.2 or older
205;; (which are in Emacs 24.1 and earlier) need it
206(defun gnus-sync-json-alist-p (list)
207 "Non-null if and only if LIST is an alist."
208 (while (consp list)
209 (setq list (if (consp (car list))
210 (cdr list)
211 'not-alist)))
212 (null list))
213
214;; this is not necessary with newer versions of json.el but 1.2 or older
215;; (which are in Emacs 24.1 and earlier) need it
216(defun gnus-sync-json-plist-p (list)
217 "Non-null if and only if LIST is a plist."
218 (while (consp list)
219 (setq list (if (and (keywordp (car list))
220 (consp (cdr list)))
221 (cddr list)
222 'not-plist)))
223 (null list))
224
225; (gnus-sync-lesync-setup "http://lesync.info:5984/tzz" "tzzadmin" "mypassword" "mysalt" t t)
226; (gnus-sync-lesync-setup "http://lesync.info:5984/tzz")
227
228(defun gnus-sync-lesync-setup (url &optional user password salt reader admin)
229 (interactive "sEnter URL to set up: ")
230 "Set up the LeSync database at URL.
231Install USER as a READER and/or an ADMIN in the security object
232under \"_security\", and in the CouchDB \"_users\" table using
233PASSWORD and SALT. Only one USER is thus supported for now.
234When SALT is nil, a random one will be generated using `random'."
235 (let* ((design-url (concat url gnus-sync-lesync-design-prefix))
236 (security-object (concat url "/_security"))
237 (user-record `((names . [,user]) (roles . [])))
238 (couch-user-name (format "org.couchdb.user:%s" user))
239 (salt (or salt (sha1 (format "%s" (random t)))))
240 (couch-user-record
241 `((_id . ,couch-user-name)
242 (type . user)
243 (name . ,(format "%s" user))
244 (roles . [])
245 (salt . ,salt)
246 (password_sha . ,(when password
247 (sha1
248 (format "%s%s" password salt))))))
249 (rev (progn
250 (gnus-sync-lesync-find-prop 'rev design-url design-url)
251 (gnus-sync-lesync-get-prop 'rev design-url)))
252 (latest-func "function(head,req)
253{
254 var tosend = [];
255 var row;
256 var ftime = (req.query['ftime'] || 0);
257 while (row = getRow())
258 {
259 if (row.value['float-time'] > ftime)
260 {
261 var s = row.value['_id'];
262 if (s) tosend.push('\"'+s.replace('\"', '\\\"')+'\"');
263 }
264 }
265 send('['+tosend.join(',') + ']');
266}")
267;; <key>read</key>
268;; <dict>
269;; <key>de.alt.fan.ipod</key>
270;; <array>
271;; <integer>1</integer>
272;; <integer>2</integer>
273;; <dict>
274;; <key>start</key>
275;; <integer>100</integer>
276;; <key>length</key>
277;; <integer>100</integer>
278;; </dict>
279;; </array>
280;; </dict>
281 (xmlplistread-func "function(head, req) {
282 var row;
283 start({ 'headers': { 'Content-Type': 'text/xml' } });
284
285 send('<dict>');
286 send('<key>read</key>');
287 send('<dict>');
288 while(row = getRow())
289 {
290 var read = row.value.read;
291 if (read && read[0] && read[0] == 'invlist')
292 {
293 send('<key>'+row.key+'</key>');
294 //send('<invlist>'+read+'</invlist>');
295 send('<array>');
296
297 var from = 0;
298 var flip = false;
299
300 for (var i = 1; i < read.length && read[i]; i++)
301 {
302 var cur = read[i];
303 if (flip)
304 {
305 if (from == cur-1)
306 {
307 send('<integer>'+read[i]+'</integer>');
308 }
309 else
310 {
311 send('<dict>');
312 send('<key>start</key>');
313 send('<integer>'+from+'</integer>');
314 send('<key>end</key>');
315 send('<integer>'+(cur-1)+'</integer>');
316 send('</dict>');
317 }
318
319 }
320 flip = ! flip;
321 from = cur;
322 }
323 send('</array>');
324 }
325 }
326
327 send('</dict>');
328 send('</dict>');
329}
330")
331 (subs-func "function(doc){emit([doc._id, doc.source], doc._rev);}")
332 (revs-func "function(doc){emit(doc._id, doc._rev);}")
333 (bytimesubs-func "function(doc)
334{emit([(doc['float-time']||0), doc._id], doc._rev);}")
335 (bytime-func "function(doc)
336{emit([(doc['float-time']||0), doc._id], doc);}")
337 (groups-func "function(doc){emit(doc._id, doc);}"))
338 (and (if user
339 (and (assq 'ok (gnus-sync-lesync-PUT
340 security-object
341 nil
342 (append (and reader
343 (list `(readers . ,user-record)))
344 (and admin
345 (list `(admins . ,user-record))))))
346 (assq 'ok (gnus-sync-lesync-PUT
347 (concat (file-name-directory url)
348 "_users/"
349 couch-user-name)
350 nil
351 couch-user-record)))
352 t)
353 (assq 'ok (gnus-sync-lesync-PUT
354 design-url
355 nil
356 `(,@(when rev (list (cons '_rev rev)))
357 (lists . ((latest . ,latest-func)
358 (xmlplistread . ,xmlplistread-func)))
359 (views . ((subs . ((map . ,subs-func)))
360 (revs . ((map . ,revs-func)))
361 (bytimesubs . ((map . ,bytimesubs-func)))
362 (bytime . ((map . ,bytime-func)))
363 (groups . ((map . ,groups-func)))))))))))
364
365(defun gnus-sync-lesync-find-prop (prop url key)
366 "Retrieve a PROPerty of a document KEY at URL.
367Calls `gnus-sync-lesync-set-prop'.
368For the 'rev PROP, uses '_rev against the document."
369 (gnus-sync-lesync-set-prop
370 prop key (cdr (assq (if (eq prop 'rev) '_rev prop)
371 (gnus-sync-lesync-GET url nil)))))
372
373(defun gnus-sync-lesync-set-prop (prop key val)
374 "Update the PROPerty of document KEY at URL to VAL.
375Updates `gnus-sync-lesync-props-hash'."
376 (puthash (format "%s.%s" key prop) val gnus-sync-lesync-props-hash))
377
378(defun gnus-sync-lesync-get-prop (prop key)
379 "Get the PROPerty of KEY from `gnus-sync-lesync-props-hash'."
380 (gethash (format "%s.%s" key prop) gnus-sync-lesync-props-hash))
381
382(defun gnus-sync-deep-print (data)
383 (let* ((print-quoted t)
384 (print-readably t)
385 (print-escape-multibyte nil)
386 (print-escape-nonascii t)
387 (print-length nil)
388 (print-level nil)
389 (print-circle nil)
390 (print-escape-newlines t))
391 (format "%S" data)))
392
393(defun gnus-sync-newsrc-loader-builder (&optional only-modified)
394 (let* ((entries (cdr gnus-newsrc-alist))
395 entry name ret)
396 (while entries
397 (setq entry (pop entries)
398 name (car entry))
399 (when (gnus-grep-in-list name gnus-sync-newsrc-groups)
400 (if only-modified
401 (when (not (equal (gnus-sync-deep-print entry)
402 (gnus-sync-lesync-get-prop 'checksum name)))
403 (gnus-message 9 "%s: add %s, it's modified"
404 "gnus-sync-newsrc-loader-builder" name)
405 (push entry ret))
406 (push entry ret))))
407 ret))
408
409; (json-encode (gnus-sync-range2invlist '((1 . 47137) (47139 . 47714) 48129 48211 49231 49281 49342 49473 49475 49502)))
410(defun gnus-sync-range2invlist (ranges)
411 (append '(invlist)
412 (let ((ranges (delq nil ranges))
413 ret range from to)
414 (while ranges
415 (setq range (pop ranges))
416 (if (atom range)
417 (setq from range
418 to range)
419 (setq from (car range)
420 to (cdr range)))
421 (push from ret)
422 (push (1+ to) ret))
423 (reverse ret))))
424
425; (let* ((d '((1 . 47137) (47139 . 47714) 48129 48211 49231 49281 49342 49473 49475 49502)) (j (format "%S" (gnus-sync-invlist2range (gnus-sync-range2invlist d))))) (or (equal (format "%S" d) j) j))
426(defun gnus-sync-invlist2range (inv)
427 (setq inv (append inv nil))
428 (if (equal (format "%s" (car inv)) "invlist")
429 (let ((i (cdr inv))
430 (start 0)
431 ret cur top flip)
432 (while i
433 (setq cur (pop i))
434 (when flip
435 (setq top (1- cur))
436 (if (= start top)
437 (push start ret)
438 (push (cons start top) ret)))
439 (setq flip (not flip))
440 (setq start cur))
441 (reverse ret))
442 inv))
443
444(defun gnus-sync-position (search list &optional test)
445 "Find the position of SEARCH in LIST using TEST, defaulting to `eq'."
446 (let ((pos 0)
447 (test (or test 'eq)))
448 (while (and list (not (funcall test (car list) search)))
449 (pop list)
450 (incf pos))
451 (if (funcall test (car list) search) pos nil)))
452
453(defun gnus-sync-topic-group-position (group topic-name)
454 (gnus-sync-position
455 group (cdr (assoc topic-name gnus-topic-alist)) 'equal))
456
457(defun gnus-sync-fix-topic-group-position (group topic-name position)
458 (unless (equal position (gnus-sync-topic-group-position group topic-name))
459 (let* ((loc "gnus-sync-fix-topic-group-position")
460 (groups (delete group (cdr (assoc topic-name gnus-topic-alist))))
461 (position (min position (1- (length groups))))
462 (old (nth position groups)))
463 (when (and old (not (equal old group)))
464 (setf (nth position groups) group)
465 (setcdr (assoc topic-name gnus-topic-alist)
466 (append groups (list old)))
467 (gnus-message 9 "%s: %s moved to %d, swap with %s"
468 loc group position old)))))
469
470(defun gnus-sync-lesync-pre-save-group-entry (url nentry &rest passed-props)
471 (let* ((loc "gnus-sync-lesync-save-group-entry")
472 (k (car nentry))
473 (revision (gnus-sync-lesync-get-prop 'rev k))
474 (sname gnus-sync-lesync-name)
475 (topic (gnus-group-topic k))
476 (topic-offset (gnus-sync-topic-group-position k topic))
477 (sources (gnus-sync-lesync-get-prop 'source k)))
478 ;; set the revision so we don't have a conflict
479 `(,@(when revision
480 (list (cons '_rev revision)))
481 (_id . ,k)
482 ;; the time we saved
483 ,@passed-props
484 ;; add our name to the sources list for this key
485 (source ,@(if (member gnus-sync-lesync-name sources)
486 sources
487 (cons gnus-sync-lesync-name sources)))
488 ,(cons 'level (nth 1 nentry))
489 ,@(if topic (list (cons 'topic topic)) nil)
490 ,@(if topic-offset (list (cons 'topic-offset topic-offset)) nil)
491 ;; the read marks
492 ,(cons 'read (gnus-sync-range2invlist (nth 2 nentry)))
493 ;; the other marks
494 ,@(delq nil (mapcar (lambda (mark-entry)
495 (gnus-message 12 "%s: prep param %s in %s"
496 loc
497 (car mark-entry)
498 (nth 3 nentry))
499 (if (listp (cdr mark-entry))
500 (cons (car mark-entry)
501 (gnus-sync-range2invlist
502 (cdr mark-entry)))
503 (progn ; else this is not a list
504 (gnus-message 9 "%s: non-list param %s in %s"
505 loc
506 (car mark-entry)
507 (nth 3 nentry))
508 nil)))
509 (nth 3 nentry))))))
510
511(defun gnus-sync-lesync-post-save-group-entry (url entry)
512 (let* ((loc "gnus-sync-lesync-post-save-group-entry")
513 (k (cdr (assq 'id entry))))
514 (cond
515 ;; success!
516 ((and (assq 'rev entry) (assq 'id entry))
517 (progn
518 (gnus-sync-lesync-set-prop 'rev k (cdr (assq 'rev entry)))
519 (gnus-sync-lesync-set-prop 'checksum
520 k
521 (gnus-sync-deep-print
522 (assoc k gnus-newsrc-alist)))
523 (gnus-message 9 "%s: successfully synced %s to %s"
524 loc k url)))
525 ;; specifically check for document conflicts
526 ((equal "conflict" (format "%s" (cdr-safe (assq 'error entry))))
527 (gnus-error
528 1
529 "%s: use `%s' to resolve the conflict synchronizing %s to %s: %s"
530 loc "gnus-sync-read" k url (cdr (assq 'reason entry))))
531 ;; generic errors
532 ((assq 'error entry)
533 (gnus-error 1 "%s: got error while synchronizing %s to %s: %s"
534 loc k url (cdr (assq 'reason entry))))
535
536 (t
537 (gnus-message 2 "%s: unknown sync status after %s to %s: %S"
538 loc k url entry)))
539 (assoc 'error entry)))
540
541(defun gnus-sync-lesync-groups-builder (url)
542 (let ((u (concat url gnus-sync-lesync-design-prefix "/_view/groups")))
543 (cdr (assq 'rows (gnus-sync-lesync-GET u nil)))))
544
545(defun gnus-sync-subscribe-group (name)
546 "Subscribe to group NAME. Returns NAME on success, nil otherwise."
547 (gnus-subscribe-newsgroup name))
548
549(defun gnus-sync-lesync-read-group-entry (url name entry &rest passed-props)
550 "Read ENTRY information for NAME. Returns NAME if successful.
551Skips entries whose sources don't contain
552`gnus-sync-lesync-name'. When the alist PASSED-PROPS has a
553`subscribe-all' element that evaluates to true, we attempt to
554subscribe to unknown groups. The user is also allowed to delete
555unwanted groups via the LeSync URL."
556 (let* ((loc "gnus-sync-lesync-read-group-entry")
557 (entry (gnus-sync-lesync-normalize-group-entry entry passed-props))
558 (subscribe-all (cdr (assq 'subscribe-all passed-props)))
559 (sources (cdr (assq 'source entry)))
560 (rev (cdr (assq 'rev entry)))
561 (in-sources (member gnus-sync-lesync-name sources))
562 (known (assoc name gnus-newsrc-alist))
563 cell)
564 (unless known
565 (if (and subscribe-all
566 (y-or-n-p (format "Subscribe to group %s?" name)))
567 (setq known (gnus-sync-subscribe-group name)
568 in-sources t)
569 ;; else...
570 (when (y-or-n-p (format "Delete group %s from server?" name))
571 (if (equal name (gnus-sync-lesync-delete-group url name))
572 (gnus-message 1 "%s: removed group %s from server %s"
573 loc name url)
574 (gnus-error 1 "%s: could not remove group %s from server %s"
575 loc name url)))))
576 (when known
577 (unless in-sources
578 (setq in-sources
579 (y-or-n-p
580 (format "Read group %s even though %s is not in sources %S?"
581 name gnus-sync-lesync-name (or sources ""))))))
582 (when rev
583 (gnus-sync-lesync-set-prop 'rev name rev))
584
585 ;; if the source matches AND we have this group
586 (if (and known in-sources)
587 (progn
588 (gnus-message 10 "%s: reading LeSync entry %s, sources %S"
589 loc name sources)
590 (while entry
591 (setq cell (pop entry))
592 (let ((k (car cell))
593 (val (cdr cell)))
594 (gnus-sync-lesync-set-prop k name val)))
595 name)
596 ;; else...
597 (unless known
598 (gnus-message 5 "%s: ignoring entry %s, it wasn't subscribed. %s"
599 loc name "Call `gnus-sync-read' with C-u to force it."))
600 (unless in-sources
601 (gnus-message 5 "%s: ignoring entry %s, %s not in sources %S"
602 loc name gnus-sync-lesync-name (or sources "")))
603 nil)))
604
605(defun gnus-sync-lesync-install-group-entry (name)
606 (let* ((master (assoc name gnus-newsrc-alist))
607 (old-topic-name (gnus-group-topic name))
608 (old-topic (assoc old-topic-name gnus-topic-alist))
609 (target-topic-name (gnus-sync-lesync-get-prop 'topic name))
610 (target-topic-offset (gnus-sync-lesync-get-prop 'topic-offset name))
611 (target-topic (assoc target-topic-name gnus-topic-alist))
612 (loc "gnus-sync-lesync-install-group-entry"))
613 (if master
614 (progn
615 (when (eq 'ask gnus-sync-lesync-install-topics)
616 (setq gnus-sync-lesync-install-topics
617 (y-or-n-p "Install topics from LeSync?")))
618 (when (and (eq t gnus-sync-lesync-install-topics)
619 target-topic-name)
620 (if (equal old-topic-name target-topic-name)
621 (gnus-message 12 "%s: %s is already in topic %s"
622 loc name target-topic-name)
623 ;; see `gnus-topic-move-group'
624 (when (and old-topic target-topic)
625 (setcdr old-topic (gnus-delete-first name (cdr old-topic)))
626 (gnus-message 5 "%s: removing %s from topic %s"
627 loc name old-topic-name))
628 (unless target-topic
629 (when (y-or-n-p (format "Create missing topic %s?"
630 target-topic-name))
631 (gnus-topic-create-topic target-topic-name nil)
632 (setq target-topic (assoc target-topic-name
633 gnus-topic-alist))))
634 (if target-topic
635 (prog1
636 (nconc target-topic (list name))
637 (gnus-message 5 "%s: adding %s to topic %s"
638 loc name (car target-topic))
639 (gnus-topic-enter-dribble))
640 (gnus-error 2 "%s: LeSync group %s can't go in missing topic %s"
641 loc name target-topic-name)))
642 (when (and target-topic-offset target-topic)
643 (gnus-sync-fix-topic-group-position
644 name target-topic-name target-topic-offset)))
645 ;; install the subscription level
646 (when (gnus-sync-lesync-get-prop 'level name)
647 (setf (nth 1 master) (gnus-sync-lesync-get-prop 'level name)))
648 ;; install the read and other marks
649 (setf (nth 2 master) (gnus-sync-lesync-get-prop 'read name))
650 (setf (nth 3 master) (gnus-sync-lesync-get-prop 'marks name))
651 (gnus-sync-lesync-set-prop 'checksum
652 name
653 (gnus-sync-deep-print master))
654 nil)
655 (gnus-error 1 "%s: invalid LeSync group %s" loc name)
656 'invalid-name)))
657
658; (gnus-sync-lesync-delete-group (cdr gnus-sync-backend) "nntp+Gmane:gwene.org.slashdot")
659
660(defun gnus-sync-lesync-delete-group (url name)
661 "Returns NAME if successful deleting it from URL, an error otherwise."
662 (interactive "sEnter URL to set up: \rsEnter group name: ")
663 (let* ((u (concat (cadr gnus-sync-backend) "/" (url-hexify-string name)))
664 (del (gnus-sync-lesync-DELETE
665 u
666 `(,@(when (gnus-sync-lesync-get-prop 'rev name)
667 (list (cons "If-Match"
668 (gnus-sync-lesync-get-prop 'rev name))))))))
669 (or (cdr (assq 'id del)) del)))
670
671;;; (gnus-sync-lesync-normalize-group-entry '((subscribe . ["invlist"]) (read . ["invlist"]) (topic-offset . 20) (topic . "news") (level . 6) (source . ["a" "b"]) (float-time . 1319671237.099285) (_rev . "10-edf5107f41e5e6f7f6629d1c0ee172f7") (_id . "nntp+news.net:alt.movies")) '((read-time 1319672156.486414) (subscribe-all nil)))
672
673(defun gnus-sync-lesync-normalize-group-entry (entry &optional passed-props)
674 (let (ret
675 marks
676 cell)
677 (setq entry (append passed-props entry))
678 (while (setq cell (pop entry))
679 (let ((k (car cell))
680 (val (cdr cell)))
681 (cond
682 ((eq k 'read)
683 (push (cons k (gnus-sync-invlist2range val)) ret))
684 ;; we ignore these parameters
685 ((member k '(_id subscribe-all _deleted_conflicts))
686 nil)
687 ((eq k '_rev)
688 (push (cons 'rev val) ret))
689 ((eq k 'source)
690 (push (cons 'source (append val nil)) ret))
691 ((or (eq k 'float-time)
692 (eq k 'level)
693 (eq k 'topic)
694 (eq k 'topic-offset)
695 (eq k 'read-time))
696 (push (cons k val) ret))
697;;; "How often have I said to you that when you have eliminated the
698;;; impossible, whatever remains, however improbable, must be the
699;;; truth?" --Sherlock Holmes
700 ;; everything remaining must be a mark
701 (t (push (cons k (gnus-sync-invlist2range val)) marks)))))
702 (cons (cons 'marks marks) ret)))
703
704(defun gnus-sync-save (&optional force)
705"Save the Gnus sync data to the backend.
706With a prefix, FORCE is set and all groups will be saved."
707 (interactive "P")
103 (cond 708 (cond
709 ((and (listp gnus-sync-backend)
710 (eq (nth 0 gnus-sync-backend) 'lesync)
711 (stringp (nth 1 gnus-sync-backend)))
712
713 ;; refresh the revisions if we're forcing the save
714 (when force
715 (mapc (lambda (entry)
716 (when (and (assq 'key entry)
717 (assq 'value entry))
718 (gnus-sync-lesync-set-prop
719 'rev
720 (cdr (assq 'key entry))
721 (cdr (assq 'value entry)))))
722 ;; the revs view is key = name, value = rev
723 (cdr (assq 'rows (gnus-sync-lesync-GET
724 (concat (nth 1 gnus-sync-backend)
725 gnus-sync-lesync-design-prefix
726 "/_view/revs")
727 nil)))))
728
729 (let* ((ftime (float-time))
730 (url (nth 1 gnus-sync-backend))
731 (entries
732 (mapcar (lambda (entry)
733 (gnus-sync-lesync-pre-save-group-entry
734 (cadr gnus-sync-backend)
735 entry
736 (cons 'float-time ftime)))
737 (gnus-sync-newsrc-loader-builder (not force))))
738 ;; when there are no entries, there's nothing to save
739 (sync (if entries
740 (gnus-sync-lesync-POST
741 (concat url "/_bulk_docs")
742 '(("Content-Type" . "application/json"))
743 `((docs . ,(vconcat entries nil))))
744 (gnus-message
745 2 "gnus-sync-save: nothing to save to the LeSync backend")
746 nil)))
747 (mapcar (lambda (e) (gnus-sync-lesync-post-save-group-entry url e))
748 sync)))
104 ((stringp gnus-sync-backend) 749 ((stringp gnus-sync-backend)
105 (gnus-message 7 "gnus-sync: saving to backend %s" gnus-sync-backend) 750 (gnus-message 7 "gnus-sync-save: saving to backend %s" gnus-sync-backend)
106 ;; populate gnus-sync-newsrc-loader from all but the first dummy 751 ;; populate gnus-sync-newsrc-loader from all but the first dummy
107 ;; entry in gnus-newsrc-alist whose group matches any of the 752 ;; entry in gnus-newsrc-alist whose group matches any of the
108 ;; gnus-sync-newsrc-groups 753 ;; gnus-sync-newsrc-groups
109 ;; TODO: keep the old contents for groups we don't have! 754 ;; TODO: keep the old contents for groups we don't have!
110 (let ((gnus-sync-newsrc-loader 755 (let ((gnus-sync-newsrc-loader (gnus-sync-newsrc-loader-builder)))
111 (loop for entry in (cdr gnus-newsrc-alist)
112 when (gnus-grep-in-list
113 (car entry) ;the group name
114 gnus-sync-newsrc-groups)
115 collect (cons (car entry)
116 (mapcar (lambda (offset)
117 (cons offset (nth offset entry)))
118 gnus-sync-newsrc-offsets)))))
119 (with-temp-file gnus-sync-backend 756 (with-temp-file gnus-sync-backend
120 (progn 757 (progn
121 (let ((coding-system-for-write gnus-ding-file-coding-system) 758 (let ((coding-system-for-write gnus-ding-file-coding-system)
@@ -123,6 +760,7 @@ synchronized, I believe). Also see `gnus-variable-list'."
123 (princ (format ";; -*- mode:emacs-lisp; coding: %s; -*-\n" 760 (princ (format ";; -*- mode:emacs-lisp; coding: %s; -*-\n"
124 gnus-ding-file-coding-system)) 761 gnus-ding-file-coding-system))
125 (princ ";; Gnus sync data v. 0.0.1\n") 762 (princ ";; Gnus sync data v. 0.0.1\n")
763 ;; TODO: replace with `gnus-sync-deep-print'
126 (let* ((print-quoted t) 764 (let* ((print-quoted t)
127 (print-readably t) 765 (print-readably t)
128 (print-escape-multibyte nil) 766 (print-escape-multibyte nil)
@@ -147,14 +785,14 @@ synchronized, I believe). Also see `gnus-variable-list'."
147 (princ (symbol-name variable))))) 785 (princ (symbol-name variable)))))
148 (gnus-message 786 (gnus-message
149 7 787 7
150 "gnus-sync: stored variables %s and %d groups in %s" 788 "gnus-sync-save: stored variables %s and %d groups in %s"
151 gnus-sync-global-vars 789 gnus-sync-global-vars
152 (length gnus-sync-newsrc-loader) 790 (length gnus-sync-newsrc-loader)
153 gnus-sync-backend) 791 gnus-sync-backend)
154 792
155 ;; Idea from Dan Christensen <jdc@chow.mat.jhu.edu> 793 ;; Idea from Dan Christensen <jdc@chow.mat.jhu.edu>
156 ;; Save the .eld file with extra line breaks. 794 ;; Save the .eld file with extra line breaks.
157 (gnus-message 8 "gnus-sync: adding whitespace to %s" 795 (gnus-message 8 "gnus-sync-save: adding whitespace to %s"
158 gnus-sync-backend) 796 gnus-sync-backend)
159 (save-excursion 797 (save-excursion
160 (goto-char (point-min)) 798 (goto-char (point-min))
@@ -166,49 +804,74 @@ synchronized, I believe). Also see `gnus-variable-list'."
166 ;; the pass-through case: gnus-sync-backend is not a known choice 804 ;; the pass-through case: gnus-sync-backend is not a known choice
167 (nil))) 805 (nil)))
168 806
169(defun gnus-sync-read () 807(defun gnus-sync-read (&optional subscribe-all)
170"Load the Gnus sync data from the backend." 808 "Load the Gnus sync data from the backend.
171 (interactive) 809With a prefix, SUBSCRIBE-ALL is set and unknown groups will be subscribed."
810 (interactive "P")
172 (when gnus-sync-backend 811 (when gnus-sync-backend
173 (gnus-message 7 "gnus-sync: loading from backend %s" gnus-sync-backend) 812 (gnus-message 7 "gnus-sync-read: loading from backend %s" gnus-sync-backend)
174 (cond ((stringp gnus-sync-backend) 813 (cond
175 ;; read data here... 814 ((and (listp gnus-sync-backend)
176 (if (or debug-on-error debug-on-quit) 815 (eq (nth 0 gnus-sync-backend) 'lesync)
177 (load gnus-sync-backend nil t) 816 (stringp (nth 1 gnus-sync-backend)))
178 (condition-case var 817 (let ((errored nil)
179 (load gnus-sync-backend nil t) 818 name ftime)
180 (error 819 (mapc (lambda (entry)
181 (error "Error in %s: %s" gnus-sync-backend (cadr var))))) 820 (setq name (cdr (assq 'id entry)))
182 (let ((valid-count 0) 821 ;; set ftime the FIRST time through this loop, that
183 invalid-groups) 822 ;; way it reflects the time we FINISHED reading
184 (dolist (node gnus-sync-newsrc-loader) 823 (unless ftime (setq ftime (float-time)))
185 (if (gnus-gethash (car node) gnus-newsrc-hashtb) 824
186 (progn 825 (unless errored
187 (incf valid-count) 826 (setq errored
188 (loop for store in (cdr node) 827 (when (equal name
189 do (setf (nth (car store) 828 (gnus-sync-lesync-read-group-entry
190 (assoc (car node) gnus-newsrc-alist)) 829 (nth 1 gnus-sync-backend)
191 (cdr store)))) 830 name
192 (push (car node) invalid-groups))) 831 (cdr (assq 'value entry))
193 (gnus-message 832 `(read-time ,ftime)
194 7 833 `(subscribe-all ,subscribe-all)))
195 "gnus-sync: loaded %d groups (out of %d) from %s" 834 (gnus-sync-lesync-install-group-entry
196 valid-count (length gnus-sync-newsrc-loader) 835 (cdr (assq 'id entry)))))))
197 gnus-sync-backend) 836 (gnus-sync-lesync-groups-builder (nth 1 gnus-sync-backend)))))
198 (when invalid-groups 837
199 (gnus-message 838 ((stringp gnus-sync-backend)
200 7 839 ;; read data here...
201 "gnus-sync: skipped %d groups (out of %d) from %s" 840 (if (or debug-on-error debug-on-quit)
202 (length invalid-groups) 841 (load gnus-sync-backend nil t)
203 (length gnus-sync-newsrc-loader) 842 (condition-case var
204 gnus-sync-backend) 843 (load gnus-sync-backend nil t)
205 (gnus-message 9 "gnus-sync: skipped groups: %s" 844 (error
206 (mapconcat 'identity invalid-groups ", "))))) 845 (error "Error in %s: %s" gnus-sync-backend (cadr var)))))
207 (nil)) 846 (let ((valid-count 0)
208 ;; make the hashtable again because the newsrc-alist may have been modified 847 invalid-groups)
209 (when gnus-sync-newsrc-offsets 848 (dolist (node gnus-sync-newsrc-loader)
210 (gnus-message 9 "gnus-sync: remaking the newsrc hashtable") 849 (if (gnus-gethash (car node) gnus-newsrc-hashtb)
211 (gnus-make-hashtable-from-newsrc-alist)))) 850 (progn
851 (incf valid-count)
852 (loop for store in (cdr node)
853 do (setf (nth (car store)
854 (assoc (car node) gnus-newsrc-alist))
855 (cdr store))))
856 (push (car node) invalid-groups)))
857 (gnus-message
858 7
859 "gnus-sync-read: loaded %d groups (out of %d) from %s"
860 valid-count (length gnus-sync-newsrc-loader)
861 gnus-sync-backend)
862 (when invalid-groups
863 (gnus-message
864 7
865 "gnus-sync-read: skipped %d groups (out of %d) from %s"
866 (length invalid-groups)
867 (length gnus-sync-newsrc-loader)
868 gnus-sync-backend)
869 (gnus-message 9 "gnus-sync-read: skipped groups: %s"
870 (mapconcat 'identity invalid-groups ", ")))))
871 (nil))
872
873 (gnus-message 9 "gnus-sync-read: remaking the newsrc hashtable")
874 (gnus-make-hashtable-from-newsrc-alist)))
212 875
213;;;###autoload 876;;;###autoload
214(defun gnus-sync-initialize () 877(defun gnus-sync-initialize ()
@@ -228,14 +891,11 @@ synchronized, I believe). Also see `gnus-variable-list'."
228(defun gnus-sync-unload-hook () 891(defun gnus-sync-unload-hook ()
229 "Uninstall the sync hooks." 892 "Uninstall the sync hooks."
230 (interactive) 893 (interactive)
231 (remove-hook 'gnus-get-new-news-hook 'gnus-sync-read) 894 (remove-hook 'gnus-save-newsrc-hook 'gnus-sync-save))
232 (remove-hook 'gnus-save-newsrc-hook 'gnus-sync-save)
233 (remove-hook 'gnus-read-newsrc-el-hook 'gnus-sync-read))
234 895
235(add-hook 'gnus-sync-unload-hook 'gnus-sync-unload-hook) 896(add-hook 'gnus-sync-unload-hook 'gnus-sync-unload-hook)
236 897
237;; this is harmless by default, until the gnus-sync-backend is set 898(when gnus-sync-backend (gnus-sync-initialize))
238(gnus-sync-initialize)
239 899
240(provide 'gnus-sync) 900(provide 'gnus-sync)
241 901
diff --git a/lisp/gnus/gnus-util.el b/lisp/gnus/gnus-util.el
index da899f4bf10..072e7b5822a 100644
--- a/lisp/gnus/gnus-util.el
+++ b/lisp/gnus/gnus-util.el
@@ -169,15 +169,6 @@ This is a compatibility function for different Emacsen."
169 `(delete-region (point-at-bol) 169 `(delete-region (point-at-bol)
170 (progn (forward-line ,(or n 1)) (point)))) 170 (progn (forward-line ,(or n 1)) (point))))
171 171
172(defun gnus-byte-code (func)
173 "Return a form that can be `eval'ed based on FUNC."
174 (let ((fval (indirect-function func)))
175 (if (byte-code-function-p fval)
176 (let ((flist (append fval nil)))
177 (setcar flist 'byte-code)
178 flist)
179 (cons 'progn (cddr fval)))))
180
181(defun gnus-extract-address-components (from) 172(defun gnus-extract-address-components (from)
182 "Extract address components from a From header. 173 "Extract address components from a From header.
183Given an RFC-822 address FROM, extract full name and canonical address. 174Given an RFC-822 address FROM, extract full name and canonical address.
@@ -1927,6 +1918,19 @@ Sizes are in pixels."
1927 image))) 1918 image)))
1928 image))) 1919 image)))
1929 1920
1921(defun gnus-recursive-directory-files (dir)
1922 "Return all regular files below DIR."
1923 (let (files)
1924 (dolist (file (directory-files dir t))
1925 (when (and (not (member (file-name-nondirectory file) '("." "..")))
1926 (file-readable-p file))
1927 (cond
1928 ((file-regular-p file)
1929 (push file files))
1930 ((file-directory-p file)
1931 (setq files (append (gnus-recursive-directory-files file) files))))))
1932 files))
1933
1930(defun gnus-list-memq-of-list (elements list) 1934(defun gnus-list-memq-of-list (elements list)
1931 "Return non-nil if any of the members of ELEMENTS are in LIST." 1935 "Return non-nil if any of the members of ELEMENTS are in LIST."
1932 (let ((found nil)) 1936 (let ((found nil))
diff --git a/lisp/gnus/gnus.el b/lisp/gnus/gnus.el
index bba56e31d9b..a605f483ea4 100644
--- a/lisp/gnus/gnus.el
+++ b/lisp/gnus/gnus.el
@@ -1009,10 +1009,11 @@ be set in `.emacs' instead."
1009 (purp "#9999cc" "#666699") 1009 (purp "#9999cc" "#666699")
1010 (no "#ff0000" "#ffff00") 1010 (no "#ff0000" "#ffff00")
1011 (neutral "#b4b4b4" "#878787") 1011 (neutral "#b4b4b4" "#878787")
1012 (ma "#2020e0" "#8080ff")
1012 (september "#bf9900" "#ffcc00")) 1013 (september "#bf9900" "#ffcc00"))
1013 "Color alist used for the Gnus logo.") 1014 "Color alist used for the Gnus logo.")
1014 1015
1015(defcustom gnus-logo-color-style 'no 1016(defcustom gnus-logo-color-style 'ma
1016 "*Color styles used for the Gnus logo." 1017 "*Color styles used for the Gnus logo."
1017 :type `(choice ,@(mapcar (lambda (elem) (list 'const (car elem))) 1018 :type `(choice ,@(mapcar (lambda (elem) (list 'const (car elem)))
1018 gnus-logo-color-alist)) 1019 gnus-logo-color-alist))
@@ -2803,6 +2804,8 @@ gnus-registry.el will populate this if it's loaded.")
2803 ("gnus-kill" gnus-kill gnus-apply-kill-file-internal 2804 ("gnus-kill" gnus-kill gnus-apply-kill-file-internal
2804 gnus-kill-file-edit-file gnus-kill-file-raise-followups-to-author 2805 gnus-kill-file-edit-file gnus-kill-file-raise-followups-to-author
2805 gnus-execute gnus-expunge gnus-batch-kill gnus-batch-score) 2806 gnus-execute gnus-expunge gnus-batch-kill gnus-batch-score)
2807 ("gnus-registry" gnus-try-warping-via-registry
2808 gnus-registry-handle-action)
2806 ("gnus-cache" gnus-cache-possibly-enter-article gnus-cache-save-buffers 2809 ("gnus-cache" gnus-cache-possibly-enter-article gnus-cache-save-buffers
2807 gnus-cache-possibly-remove-articles gnus-cache-request-article 2810 gnus-cache-possibly-remove-articles gnus-cache-request-article
2808 gnus-cache-retrieve-headers gnus-cache-possibly-alter-active 2811 gnus-cache-retrieve-headers gnus-cache-possibly-alter-active
diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el
index 4ce9279114b..21ce9e4a873 100644
--- a/lisp/gnus/message.el
+++ b/lisp/gnus/message.el
@@ -3057,66 +3057,79 @@ M-RET `message-newline-and-reformat' (break the line and reformat)."
3057(defun message-goto-to () 3057(defun message-goto-to ()
3058 "Move point to the To header." 3058 "Move point to the To header."
3059 (interactive) 3059 (interactive)
3060 (push-mark)
3060 (message-position-on-field "To")) 3061 (message-position-on-field "To"))
3061 3062
3062(defun message-goto-from () 3063(defun message-goto-from ()
3063 "Move point to the From header." 3064 "Move point to the From header."
3064 (interactive) 3065 (interactive)
3066 (push-mark)
3065 (message-position-on-field "From")) 3067 (message-position-on-field "From"))
3066 3068
3067(defun message-goto-subject () 3069(defun message-goto-subject ()
3068 "Move point to the Subject header." 3070 "Move point to the Subject header."
3069 (interactive) 3071 (interactive)
3072 (push-mark)
3070 (message-position-on-field "Subject")) 3073 (message-position-on-field "Subject"))
3071 3074
3072(defun message-goto-cc () 3075(defun message-goto-cc ()
3073 "Move point to the Cc header." 3076 "Move point to the Cc header."
3074 (interactive) 3077 (interactive)
3078 (push-mark)
3075 (message-position-on-field "Cc" "To")) 3079 (message-position-on-field "Cc" "To"))
3076 3080
3077(defun message-goto-bcc () 3081(defun message-goto-bcc ()
3078 "Move point to the Bcc header." 3082 "Move point to the Bcc header."
3079 (interactive) 3083 (interactive)
3084 (push-mark)
3080 (message-position-on-field "Bcc" "Cc" "To")) 3085 (message-position-on-field "Bcc" "Cc" "To"))
3081 3086
3082(defun message-goto-fcc () 3087(defun message-goto-fcc ()
3083 "Move point to the Fcc header." 3088 "Move point to the Fcc header."
3084 (interactive) 3089 (interactive)
3090 (push-mark)
3085 (message-position-on-field "Fcc" "To" "Newsgroups")) 3091 (message-position-on-field "Fcc" "To" "Newsgroups"))
3086 3092
3087(defun message-goto-reply-to () 3093(defun message-goto-reply-to ()
3088 "Move point to the Reply-To header." 3094 "Move point to the Reply-To header."
3089 (interactive) 3095 (interactive)
3096 (push-mark)
3090 (message-position-on-field "Reply-To" "Subject")) 3097 (message-position-on-field "Reply-To" "Subject"))
3091 3098
3092(defun message-goto-newsgroups () 3099(defun message-goto-newsgroups ()
3093 "Move point to the Newsgroups header." 3100 "Move point to the Newsgroups header."
3094 (interactive) 3101 (interactive)
3102 (push-mark)
3095 (message-position-on-field "Newsgroups")) 3103 (message-position-on-field "Newsgroups"))
3096 3104
3097(defun message-goto-distribution () 3105(defun message-goto-distribution ()
3098 "Move point to the Distribution header." 3106 "Move point to the Distribution header."
3099 (interactive) 3107 (interactive)
3108 (push-mark)
3100 (message-position-on-field "Distribution")) 3109 (message-position-on-field "Distribution"))
3101 3110
3102(defun message-goto-followup-to () 3111(defun message-goto-followup-to ()
3103 "Move point to the Followup-To header." 3112 "Move point to the Followup-To header."
3104 (interactive) 3113 (interactive)
3114 (push-mark)
3105 (message-position-on-field "Followup-To" "Newsgroups")) 3115 (message-position-on-field "Followup-To" "Newsgroups"))
3106 3116
3107(defun message-goto-mail-followup-to () 3117(defun message-goto-mail-followup-to ()
3108 "Move point to the Mail-Followup-To header." 3118 "Move point to the Mail-Followup-To header."
3109 (interactive) 3119 (interactive)
3120 (push-mark)
3110 (message-position-on-field "Mail-Followup-To" "To")) 3121 (message-position-on-field "Mail-Followup-To" "To"))
3111 3122
3112(defun message-goto-keywords () 3123(defun message-goto-keywords ()
3113 "Move point to the Keywords header." 3124 "Move point to the Keywords header."
3114 (interactive) 3125 (interactive)
3126 (push-mark)
3115 (message-position-on-field "Keywords" "Subject")) 3127 (message-position-on-field "Keywords" "Subject"))
3116 3128
3117(defun message-goto-summary () 3129(defun message-goto-summary ()
3118 "Move point to the Summary header." 3130 "Move point to the Summary header."
3119 (interactive) 3131 (interactive)
3132 (push-mark)
3120 (message-position-on-field "Summary" "Subject")) 3133 (message-position-on-field "Summary" "Subject"))
3121 3134
3122(eval-when-compile 3135(eval-when-compile
@@ -3137,6 +3150,7 @@ M-RET `message-newline-and-reformat' (break the line and reformat)."
3137 (when (and (message-called-interactively-p 'any) 3150 (when (and (message-called-interactively-p 'any)
3138 (looking-at "[ \t]*\n")) 3151 (looking-at "[ \t]*\n"))
3139 (expand-abbrev)) 3152 (expand-abbrev))
3153 (push-mark)
3140 (goto-char (point-min)) 3154 (goto-char (point-min))
3141 (or (search-forward (concat "\n" mail-header-separator "\n") nil t) 3155 (or (search-forward (concat "\n" mail-header-separator "\n") nil t)
3142 (search-forward-regexp "[^:]+:\\([^\n]\\|\n[ \t]\\)+\n\n" nil t))) 3156 (search-forward-regexp "[^:]+:\\([^\n]\\|\n[ \t]\\)+\n\n" nil t)))
@@ -3157,6 +3171,7 @@ M-RET `message-newline-and-reformat' (break the line and reformat)."
3157If there is no signature in the article, go to the end and 3171If there is no signature in the article, go to the end and
3158return nil." 3172return nil."
3159 (interactive) 3173 (interactive)
3174 (push-mark)
3160 (goto-char (point-min)) 3175 (goto-char (point-min))
3161 (if (re-search-forward message-signature-separator nil t) 3176 (if (re-search-forward message-signature-separator nil t)
3162 (forward-line 1) 3177 (forward-line 1)
@@ -3796,7 +3811,7 @@ prefix, and don't delete any headers."
3796 (save-current-buffer 3811 (save-current-buffer
3797 (dolist (buffer (buffer-list t)) 3812 (dolist (buffer (buffer-list t))
3798 (set-buffer buffer) 3813 (set-buffer buffer)
3799 (when (and (eq major-mode 'message-mode) 3814 (when (and (derived-mode-p 'message-mode)
3800 (null message-sent-message-via)) 3815 (null message-sent-message-via))
3801 (push (buffer-name buffer) buffers)))) 3816 (push (buffer-name buffer) buffers))))
3802 (nreverse buffers))) 3817 (nreverse buffers)))
@@ -4479,8 +4494,9 @@ This function could be useful in `message-setup-hook'."
4479 (end-of-line) 4494 (end-of-line)
4480 (insert (format " (%d/%d)" n total)) 4495 (insert (format " (%d/%d)" n total))
4481 (widen) 4496 (widen)
4482 (funcall (or message-send-mail-real-function 4497 (if message-send-mail-real-function
4483 message-send-mail-function))) 4498 (funcall message-send-mail-real-function)
4499 (message-multi-smtp-send-mail)))
4484 (setq n (+ n 1)) 4500 (setq n (+ n 1))
4485 (setq p (pop plist)) 4501 (setq p (pop plist))
4486 (erase-buffer))) 4502 (erase-buffer)))
@@ -4634,8 +4650,9 @@ If you always want Gnus to send messages in one piece, set
4634"))) 4650")))
4635 (progn 4651 (progn
4636 (message "Sending via mail...") 4652 (message "Sending via mail...")
4637 (funcall (or message-send-mail-real-function 4653 (if message-send-mail-real-function
4638 message-send-mail-function))) 4654 (funcall message-send-mail-real-function)
4655 (message-multi-smtp-send-mail)))
4639 (message-send-mail-partially)) 4656 (message-send-mail-partially))
4640 (setq options message-options)) 4657 (setq options message-options))
4641 (kill-buffer tembuf)) 4658 (kill-buffer tembuf))
@@ -4644,6 +4661,28 @@ If you always want Gnus to send messages in one piece, set
4644 (push 'mail message-sent-message-via))) 4661 (push 'mail message-sent-message-via)))
4645 4662
4646(defvar sendmail-program) 4663(defvar sendmail-program)
4664(defvar smtpmail-smtp-user)
4665
4666(defun message-multi-smtp-send-mail ()
4667 "Send the current buffer to `message-send-mail-function'.
4668Or, if there's a header that specifies a different method, use
4669that instead."
4670 (let ((method (message-field-value "X-Message-SMTP-Method")))
4671 (if (not method)
4672 (funcall message-send-mail-function)
4673 (message-remove-header "X-Message-SMTP-Method")
4674 (setq method (split-string method))
4675 (cond
4676 ((equal (car method) "sendmail")
4677 (message-send-mail-with-sendmail))
4678 ((equal (car method) "smtp")
4679 (require 'smtpmail)
4680 (let ((smtpmail-smtp-server (nth 1 method))
4681 (smtpmail-smtp-service (nth 2 method))
4682 (smtpmail-smtp-user (or (nth 3 method) smtpmail-smtp-user)))
4683 (message-smtpmail-send-it)))
4684 (t
4685 (error "Unknown method %s" method))))))
4647 4686
4648(defun message-send-mail-with-sendmail () 4687(defun message-send-mail-with-sendmail ()
4649 "Send off the prepared buffer with sendmail." 4688 "Send off the prepared buffer with sendmail."
@@ -7530,7 +7569,7 @@ is for the internal use."
7530 (message "Resending message to %s..." address) 7569 (message "Resending message to %s..." address)
7531 (save-excursion 7570 (save-excursion
7532 (let ((cur (current-buffer)) 7571 (let ((cur (current-buffer))
7533 beg) 7572 gcc beg)
7534 ;; We first set up a normal mail buffer. 7573 ;; We first set up a normal mail buffer.
7535 (unless (message-mail-user-agent) 7574 (unless (message-mail-user-agent)
7536 (set-buffer (get-buffer-create " *message resend*")) 7575 (set-buffer (get-buffer-create " *message resend*"))
@@ -7543,6 +7582,8 @@ is for the internal use."
7543 ;; Insert our usual headers. 7582 ;; Insert our usual headers.
7544 (message-generate-headers '(From Date To Message-ID)) 7583 (message-generate-headers '(From Date To Message-ID))
7545 (message-narrow-to-headers) 7584 (message-narrow-to-headers)
7585 (when (setq gcc (mail-fetch-field "gcc" nil t))
7586 (message-remove-header "gcc"))
7546 ;; Remove X-Draft-From header etc. 7587 ;; Remove X-Draft-From header etc.
7547 (message-remove-header message-ignored-mail-headers t) 7588 (message-remove-header message-ignored-mail-headers t)
7548 ;; Rename them all to "Resent-*". 7589 ;; Rename them all to "Resent-*".
@@ -7584,6 +7625,10 @@ is for the internal use."
7584 message-generate-hashcash 7625 message-generate-hashcash
7585 rfc2047-encode-encoded-words) 7626 rfc2047-encode-encoded-words)
7586 (message-send-mail)) 7627 (message-send-mail))
7628 (when gcc
7629 (message-goto-eoh)
7630 (insert "Gcc: " gcc "\n"))
7631 (run-hooks 'message-sent-hook)
7587 (kill-buffer (current-buffer))) 7632 (kill-buffer (current-buffer)))
7588 (message "Resending message to %s...done" address))) 7633 (message "Resending message to %s...done" address)))
7589 7634
diff --git a/lisp/gnus/mm-decode.el b/lisp/gnus/mm-decode.el
index 4a6da2d437c..d0401bc9de3 100644
--- a/lisp/gnus/mm-decode.el
+++ b/lisp/gnus/mm-decode.el
@@ -41,6 +41,10 @@
41(autoload 'mm-extern-cache-contents "mm-extern") 41(autoload 'mm-extern-cache-contents "mm-extern")
42(autoload 'mm-insert-inline "mm-view") 42(autoload 'mm-insert-inline "mm-view")
43 43
44(autoload 'mm-archive-decoders "mm-archive")
45(autoload 'mm-archive-dissect-and-inline "mm-archive")
46(autoload 'mm-dissect-archive "mm-archive")
47
44(defvar gnus-current-window-configuration) 48(defvar gnus-current-window-configuration)
45 49
46(add-hook 'gnus-exit-gnus-hook 'mm-destroy-postponed-undisplay-list) 50(add-hook 'gnus-exit-gnus-hook 'mm-destroy-postponed-undisplay-list)
@@ -248,6 +252,8 @@ before the external MIME handler is invoked."
248 ("message/partial" mm-inline-partial identity) 252 ("message/partial" mm-inline-partial identity)
249 ("message/external-body" mm-inline-external-body identity) 253 ("message/external-body" mm-inline-external-body identity)
250 ("text/.*" mm-inline-text identity) 254 ("text/.*" mm-inline-text identity)
255 ("application/x-.?tar\\(-.*\\)?" mm-archive-dissect-and-inline identity)
256 ("application/zip" mm-archive-dissect-and-inline identity)
251 ("audio/wav" mm-inline-audio 257 ("audio/wav" mm-inline-audio
252 (lambda (handle) 258 (lambda (handle)
253 (and (or (featurep 'nas-sound) (featurep 'native-sound)) 259 (and (or (featurep 'nas-sound) (featurep 'native-sound))
@@ -275,7 +281,8 @@ before the external MIME handler is invoked."
275 (ignore-errors 281 (ignore-errors
276 (if (fboundp 'create-image) 282 (if (fboundp 'create-image)
277 (create-image (buffer-string) 'imagemagick 'data-p) 283 (create-image (buffer-string) 'imagemagick 'data-p)
278 (mm-create-image-xemacs (mm-handle-media-subtype handle)))))) 284 (mm-create-image-xemacs
285 (mm-handle-media-subtype handle))))))
279 (when image 286 (when image
280 (setcar (cdr handle) (list "image/imagemagick")) 287 (setcar (cdr handle) (list "image/imagemagick"))
281 (mm-image-fit-p handle))))))) 288 (mm-image-fit-p handle)))))))
@@ -297,6 +304,9 @@ before the external MIME handler is invoked."
297 "application/pgp-signature" "application/x-pkcs7-signature" 304 "application/pgp-signature" "application/x-pkcs7-signature"
298 "application/pkcs7-signature" "application/x-pkcs7-mime" 305 "application/pkcs7-signature" "application/x-pkcs7-mime"
299 "application/pkcs7-mime" 306 "application/pkcs7-mime"
307 "application/x-gtar-compressed"
308 "application/x-tar"
309 "application/zip"
300 ;; Mutt still uses this even though it has already been withdrawn. 310 ;; Mutt still uses this even though it has already been withdrawn.
301 "application/pgp") 311 "application/pgp")
302 "List of media types that are to be displayed inline. 312 "List of media types that are to be displayed inline.
@@ -448,6 +458,7 @@ If not set, `default-directory' will be used."
448(defvar mm-last-shell-command "") 458(defvar mm-last-shell-command "")
449(defvar mm-content-id-alist nil) 459(defvar mm-content-id-alist nil)
450(defvar mm-postponed-undisplay-list nil) 460(defvar mm-postponed-undisplay-list nil)
461(defvar mm-inhibit-auto-detect-attachment nil)
451 462
452;; According to RFC2046, in particular, in a digest, the default 463;; According to RFC2046, in particular, in a digest, the default
453;; Content-Type value for a body part is changed from "text/plain" to 464;; Content-Type value for a body part is changed from "text/plain" to
@@ -567,7 +578,9 @@ Postpone undisplaying of viewers for types in
567(autoload 'message-fetch-field "message") 578(autoload 'message-fetch-field "message")
568 579
569(defun mm-dissect-buffer (&optional no-strict-mime loose-mime from) 580(defun mm-dissect-buffer (&optional no-strict-mime loose-mime from)
570 "Dissect the current buffer and return a list of MIME handles." 581 "Dissect the current buffer and return a list of MIME handles.
582If NO-STRICT-MIME, don't require the message to have a
583MIME-Version header before proceeding."
571 (save-excursion 584 (save-excursion
572 (let (ct ctl type subtype cte cd description id result) 585 (let (ct ctl type subtype cte cd description id result)
573 (save-restriction 586 (save-restriction
@@ -653,8 +666,26 @@ Postpone undisplaying of viewers for types in
653 (if (equal "text/plain" (car ctl)) 666 (if (equal "text/plain" (car ctl))
654 (assoc 'format ctl) 667 (assoc 'format ctl)
655 t)) 668 t))
656 (mm-make-handle 669 ;; Guess what the type of application/octet-stream parts should
657 (mm-copy-to-buffer) ctl cte nil cdl description nil id))) 670 ;; really be.
671 (let ((filename (cdr (assq 'filename (cdr cdl)))))
672 (when (and (not mm-inhibit-auto-detect-attachment)
673 (equal (car ctl) "application/octet-stream")
674 filename
675 (string-match "\\.\\([^.]+\\)$" filename))
676 (let ((new-type (mailcap-extension-to-mime (match-string 1 filename))))
677 (when new-type
678 (setcar ctl new-type)))))
679 (let ((handle
680 (mm-make-handle
681 (mm-copy-to-buffer) ctl cte nil cdl description nil id))
682 (decoder (assoc (car ctl) (mm-archive-decoders))))
683 (if (and decoder
684 ;; Do automatic decoding
685 (cadr decoder)
686 (executable-find (caddr decoder)))
687 (mm-dissect-archive handle)
688 handle))))
658 689
659(defun mm-dissect-multipart (ctl from) 690(defun mm-dissect-multipart (ctl from)
660 (goto-char (point-min)) 691 (goto-char (point-min))
@@ -665,7 +696,9 @@ Postpone undisplaying of viewers for types in
665 (goto-char (point-max)) 696 (goto-char (point-max))
666 (if (re-search-backward close-delimiter nil t) 697 (if (re-search-backward close-delimiter nil t)
667 (match-beginning 0) 698 (match-beginning 0)
668 (point-max))))) 699 (point-max))))
700 (mm-inhibit-auto-detect-attachment
701 (equal (car ctl) "multipart/encrypted")))
669 (setq boundary (concat (regexp-quote boundary) "[ \t]*$")) 702 (setq boundary (concat (regexp-quote boundary) "[ \t]*$"))
670 (while (and (< (point) end) (re-search-forward boundary end t)) 703 (while (and (< (point) end) (re-search-forward boundary end t))
671 (goto-char (match-beginning 0)) 704 (goto-char (match-beginning 0))
@@ -736,23 +769,29 @@ external if displayed external."
736 (mail-content-type-get 769 (mail-content-type-get
737 (mm-handle-type handle) 'name) 770 (mm-handle-type handle) 'name)
738 "<file>")) 771 "<file>"))
739 (external mm-enable-external)) 772 (external mm-enable-external)
740 (if (and (mm-inlinable-p ehandle) 773 (decoder (assoc (car (mm-handle-type handle))
741 (mm-inlined-p ehandle)) 774 (mm-archive-decoders))))
742 (progn 775 (cond
743 (forward-line 1) 776 ((and decoder
744 (mm-display-inline handle) 777 (executable-find (caddr decoder)))
745 'inline) 778 (mm-archive-dissect-and-inline handle)
746 (when (or method 779 'inline)
747 (not no-default)) 780 ((and (mm-inlinable-p ehandle)
748 (if (and (not method) 781 (mm-inlined-p ehandle))
749 (equal "text" (car (split-string type "/")))) 782 (forward-line 1)
750 (progn 783 (mm-display-inline handle)
751 (forward-line 1) 784 'inline)
752 (mm-insert-inline handle (mm-get-part handle)) 785 ((or method
753 'inline) 786 (not no-default))
754 (setq external 787 (if (and (not method)
755 (and method ;; If nil, we always use "save". 788 (equal "text" (car (split-string type "/"))))
789 (progn
790 (forward-line 1)
791 (mm-insert-inline handle (mm-get-part handle))
792 'inline)
793 (setq external
794 (and method ;; If nil, we always use "save".
756 (stringp method) ;; 'mailcap-save-binary-file 795 (stringp method) ;; 'mailcap-save-binary-file
757 (or (eq mm-enable-external t) 796 (or (eq mm-enable-external t)
758 (and (eq mm-enable-external 'ask) 797 (and (eq mm-enable-external 'ask)
@@ -765,12 +804,12 @@ external if displayed external."
765 (concat 804 (concat
766 " \"" (format method filename) "\"") 805 " \"" (format method filename) "\"")
767 "") 806 "")
768 "? ")))))) 807 "? "))))))
769 (if external 808 (if external
770 (mm-display-external
771 handle (or method 'mailcap-save-binary-file))
772 (mm-display-external 809 (mm-display-external
773 handle 'mailcap-save-binary-file))))))))) 810 handle (or method 'mailcap-save-binary-file))
811 (mm-display-external
812 handle 'mailcap-save-binary-file)))))))))
774 813
775(declare-function gnus-configure-windows "gnus-win" (setting &optional force)) 814(declare-function gnus-configure-windows "gnus-win" (setting &optional force))
776(defvar mailcap-mime-extensions) ; mailcap-mime-info autoloads 815(defvar mailcap-mime-extensions) ; mailcap-mime-info autoloads
@@ -918,46 +957,38 @@ external if displayed external."
918 shell-command-switch command) 957 shell-command-switch command)
919 (set-process-sentinel 958 (set-process-sentinel
920 (get-buffer-process buffer) 959 (get-buffer-process buffer)
921 (lexical-let ;; Don't use `let'. 960 (lexical-let ((outbuf outbuf)
922 ;; Function used to remove temp file and directory. 961 (file file)
923 ((fn `(lambda nil 962 (buffer buffer)
924 ;; Don't use `ignore-errors'. 963 (command command)
925 (condition-case nil 964 (handle handle))
926 (delete-file ,file) 965 (run-at-time
927 (error)) 966 30.0 nil
928 (condition-case nil 967 (lambda ()
929 (delete-directory 968 (ignore-errors
930 ,(file-name-directory file)) 969 (delete-file file))
931 (error)))) 970 (ignore-errors
932 ;; Form uses to kill the process buffer and 971 (delete-directory (file-name-directory file)))))
933 ;; remove the undisplayer. 972 (lambda (process state)
934 (fm `(progn 973 (when (eq (process-status process) 'exit)
935 (kill-buffer ,buffer) 974 (condition-case nil
936 ,(macroexpand 975 (delete-file file)
937 (list 'mm-handle-set-undisplayer 976 (error))
938 (list 'quote handle) 977 (condition-case nil
939 nil)))) 978 (delete-directory (file-name-directory file))
940 ;; Message to be issued when the process exits. 979 (error))
941 (done (format "Displaying %s...done" command)) 980 (when (buffer-live-p outbuf)
942 ;; In particular, the timer object (which is 981 (with-current-buffer outbuf
943 ;; a vector in Emacs but is a list in XEmacs) 982 (let ((buffer-read-only nil)
944 ;; requires that it is lexically scoped. 983 (point (point)))
945 (timer (run-at-time 30.0 nil 'ignore))) 984 (forward-line 2)
946 (if (featurep 'xemacs) 985 (mm-insert-inline
947 (lambda (process state) 986 handle (with-current-buffer buffer
948 (when (eq 'exit (process-status process)) 987 (buffer-string)))
949 (if (memq timer itimer-list) 988 (goto-char point))))
950 (set-itimer-function timer fn) 989 (when (buffer-live-p buffer)
951 (funcall fn)) 990 (kill-buffer buffer)))
952 (ignore-errors (eval fm)) 991 (message "Displaying %s...done" command)))))
953 (message "%s" done)))
954 (lambda (process state)
955 (when (eq 'exit (process-status process))
956 (if (memq timer timer-list)
957 (timer-set-function timer fn)
958 (funcall fn))
959 (ignore-errors (eval fm))
960 (message "%s" done)))))))
961 (mm-handle-set-external-undisplayer 992 (mm-handle-set-external-undisplayer
962 handle (cons file buffer))) 993 handle (cons file buffer)))
963 (message "Displaying %s..." command)) 994 (message "Displaying %s..." command))
@@ -1762,6 +1793,8 @@ If RECURSIVE, search recursively."
1762 (while (search-forward "­" nil t) 1793 (while (search-forward "­" nil t)
1763 (replace-match "" t t)) 1794 (replace-match "" t t))
1764 (libxml-parse-html-region (point-min) (point-max)))) 1795 (libxml-parse-html-region (point-min) (point-max))))
1796 (unless (bobp)
1797 (insert "\n"))
1765 (mm-handle-set-undisplayer 1798 (mm-handle-set-undisplayer
1766 handle 1799 handle
1767 `(lambda () 1800 `(lambda ()
@@ -1778,4 +1811,8 @@ If RECURSIVE, search recursively."
1778 1811
1779(provide 'mm-decode) 1812(provide 'mm-decode)
1780 1813
1814;; Local Variables:
1815;; coding: iso-8859-1
1816;; End:
1817
1781;;; mm-decode.el ends here 1818;;; mm-decode.el ends here
diff --git a/lisp/gnus/mm-util.el b/lisp/gnus/mm-util.el
index e9119284a04..4fb5ea704bd 100644
--- a/lisp/gnus/mm-util.el
+++ b/lisp/gnus/mm-util.el
@@ -1592,7 +1592,7 @@ gzip, bzip2, etc. are allowed."
1592 (unless filename 1592 (unless filename
1593 (setq filename buffer-file-name)) 1593 (setq filename buffer-file-name))
1594 (save-excursion 1594 (save-excursion
1595 (let ((decomp (unless ;; No worth to examine charset of tar files. 1595 (let ((decomp (unless ;; Not worth it to examine charset of tar files.
1596 (and filename 1596 (and filename
1597 (string-match 1597 (string-match
1598 "\\.\\(?:tar\\.[^.]+\\|tbz\\|tgz\\)\\'" 1598 "\\.\\(?:tar\\.[^.]+\\|tbz\\|tgz\\)\\'"
diff --git a/lisp/gnus/mml.el b/lisp/gnus/mml.el
index a9901d7163e..cc1aedf1b97 100644
--- a/lisp/gnus/mml.el
+++ b/lisp/gnus/mml.el
@@ -463,8 +463,10 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
463(defvar mml-multipart-number 0) 463(defvar mml-multipart-number 0)
464(defvar mml-inhibit-compute-boundary nil) 464(defvar mml-inhibit-compute-boundary nil)
465 465
466(defun mml-generate-mime () 466(defun mml-generate-mime (&optional multipart-type)
467 "Generate a MIME message based on the current MML document." 467 "Generate a MIME message based on the current MML document.
468MULTIPART-TYPE defaults to \"mixed\", but can also
469be \"related\" or \"alternate\"."
468 (let ((cont (mml-parse)) 470 (let ((cont (mml-parse))
469 (mml-multipart-number mml-multipart-number) 471 (mml-multipart-number mml-multipart-number)
470 (options message-options)) 472 (options message-options))
@@ -476,8 +478,9 @@ If MML is non-nil, return the buffer up till the correspondent mml tag."
476 (if (and (consp (car cont)) 478 (if (and (consp (car cont))
477 (= (length cont) 1)) 479 (= (length cont) 1))
478 (mml-generate-mime-1 (car cont)) 480 (mml-generate-mime-1 (car cont))
479 (mml-generate-mime-1 (nconc (list 'multipart '(type . "mixed")) 481 (mml-generate-mime-1
480 cont))) 482 (nconc (list 'multipart (cons 'type (or multipart-type "mixed")))
483 cont)))
481 (setq options message-options) 484 (setq options message-options)
482 (buffer-string)) 485 (buffer-string))
483 (setq message-options options))))) 486 (setq message-options options)))))
diff --git a/lisp/gnus/nnfolder.el b/lisp/gnus/nnfolder.el
index 89961dc7dad..e93bd7f43e0 100644
--- a/lisp/gnus/nnfolder.el
+++ b/lisp/gnus/nnfolder.el
@@ -2,7 +2,7 @@
2 2
3;; Copyright (C) 1995-2012 Free Software Foundation, Inc. 3;; Copyright (C) 1995-2012 Free Software Foundation, Inc.
4 4
5;; Author: Simon Josefsson <simon@josefsson.org> (adding MARKS) 5;; Author: Simon Josefsson <simon@josefsson.org>
6;; ShengHuo Zhu <zsh@cs.rochester.edu> (adding NOV) 6;; ShengHuo Zhu <zsh@cs.rochester.edu> (adding NOV)
7;; Scott Byer <byer@mv.us.adobe.com> 7;; Scott Byer <byer@mv.us.adobe.com>
8;; Lars Magne Ingebrigtsen <larsi@gnus.org> 8;; Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -53,10 +53,6 @@
53 "The name of the nnfolder NOV directory. 53 "The name of the nnfolder NOV directory.
54If nil, `nnfolder-directory' is used.") 54If nil, `nnfolder-directory' is used.")
55 55
56(defvoo nnfolder-marks-directory nil
57 "The name of the nnfolder MARKS directory.
58If nil, `nnfolder-directory' is used.")
59
60(defvoo nnfolder-active-file 56(defvoo nnfolder-active-file
61 (nnheader-concat nnfolder-directory "active") 57 (nnheader-concat nnfolder-directory "active")
62 "The name of the active file.") 58 "The name of the active file.")
@@ -134,21 +130,6 @@ all. This may very well take some time.")
134 130
135(defvar nnfolder-nov-buffer-file-name nil) 131(defvar nnfolder-nov-buffer-file-name nil)
136 132
137(defvoo nnfolder-marks-is-evil nil
138 "If non-nil, Gnus will never generate and use marks file for mail groups.
139Using marks files makes it possible to backup and restore mail groups
140separately from `.newsrc.eld'. If you have, for some reason, set
141this to t, and want to set it to nil again, you should always remove
142the corresponding marks file (usually base nnfolder file name
143concatenated with `.mrk', but see `nnfolder-marks-file-suffix') for
144the group. Then the marks file will be regenerated properly by Gnus.")
145
146(defvoo nnfolder-marks nil)
147
148(defvoo nnfolder-marks-file-suffix ".mrk")
149
150(defvar nnfolder-marks-modtime (gnus-make-hashtable))
151
152 133
153 134
154;;; Interface functions 135;;; Interface functions
@@ -231,9 +212,6 @@ the group. Then the marks file will be regenerated properly by Gnus.")
231 (unless (or gnus-nov-is-evil nnfolder-nov-is-evil) 212 (unless (or gnus-nov-is-evil nnfolder-nov-is-evil)
232 (and nnfolder-nov-directory 213 (and nnfolder-nov-directory
233 (gnus-make-directory nnfolder-nov-directory))) 214 (gnus-make-directory nnfolder-nov-directory)))
234 (unless nnfolder-marks-is-evil
235 (and nnfolder-marks-directory
236 (gnus-make-directory nnfolder-marks-directory)))
237 (cond 215 (cond
238 ((not (file-exists-p nnfolder-directory)) 216 ((not (file-exists-p nnfolder-directory))
239 (nnfolder-close-server) 217 (nnfolder-close-server)
@@ -607,11 +585,9 @@ the group. Then the marks file will be regenerated properly by Gnus.")
607 () ; Don't delete the articles. 585 () ; Don't delete the articles.
608 ;; Delete the file that holds the group. 586 ;; Delete the file that holds the group.
609 (let ((data (nnfolder-group-pathname group)) 587 (let ((data (nnfolder-group-pathname group))
610 (nov (nnfolder-group-nov-pathname group)) 588 (nov (nnfolder-group-nov-pathname group)))
611 (mrk (nnfolder-group-marks-pathname group)))
612 (ignore-errors (delete-file data)) 589 (ignore-errors (delete-file data))
613 (ignore-errors (delete-file nov)) 590 (ignore-errors (delete-file nov))))
614 (ignore-errors (delete-file mrk))))
615 ;; Remove the group from all structures. 591 ;; Remove the group from all structures.
616 (setq nnfolder-group-alist 592 (setq nnfolder-group-alist
617 (delq (assoc group nnfolder-group-alist) nnfolder-group-alist) 593 (delq (assoc group nnfolder-group-alist) nnfolder-group-alist)
@@ -632,11 +608,7 @@ the group. Then the marks file will be regenerated properly by Gnus.")
632 (when (file-exists-p (nnfolder-group-nov-pathname group)) 608 (when (file-exists-p (nnfolder-group-nov-pathname group))
633 (setq new-file (nnfolder-group-nov-pathname new-name)) 609 (setq new-file (nnfolder-group-nov-pathname new-name))
634 (gnus-make-directory (file-name-directory new-file)) 610 (gnus-make-directory (file-name-directory new-file))
635 (rename-file (nnfolder-group-nov-pathname group) new-file)) 611 (rename-file (nnfolder-group-nov-pathname group) new-file)))
636 (when (file-exists-p (nnfolder-group-marks-pathname group))
637 (setq new-file (nnfolder-group-marks-pathname new-name))
638 (gnus-make-directory (file-name-directory new-file))
639 (rename-file (nnfolder-group-marks-pathname group) new-file)))
640 t) 612 t)
641 ;; That went ok, so we change the internal structures. 613 ;; That went ok, so we change the internal structures.
642 (let ((entry (assoc group nnfolder-group-alist))) 614 (let ((entry (assoc group nnfolder-group-alist)))
@@ -1087,16 +1059,17 @@ This command does not work if you use short group names."
1087 1059
1088(defun nnfolder-save-buffer () 1060(defun nnfolder-save-buffer ()
1089 "Save the buffer." 1061 "Save the buffer."
1090 (when (buffer-modified-p) 1062 (let ((delete-old-versions t))
1091 (run-hooks 'nnfolder-save-buffer-hook) 1063 (when (buffer-modified-p)
1092 (gnus-make-directory (file-name-directory (buffer-file-name))) 1064 (run-hooks 'nnfolder-save-buffer-hook)
1093 (let ((coding-system-for-write 1065 (gnus-make-directory (file-name-directory (buffer-file-name)))
1094 (or nnfolder-file-coding-system-for-write 1066 (let ((coding-system-for-write
1095 nnfolder-file-coding-system))) 1067 (or nnfolder-file-coding-system-for-write
1096 (set (make-local-variable 'copyright-update) nil) 1068 nnfolder-file-coding-system)))
1097 (save-buffer))) 1069 (set (make-local-variable 'copyright-update) nil)
1098 (unless (or gnus-nov-is-evil nnfolder-nov-is-evil) 1070 (save-buffer)))
1099 (nnfolder-save-nov))) 1071 (unless (or gnus-nov-is-evil nnfolder-nov-is-evil)
1072 (nnfolder-save-nov))))
1100 1073
1101(defun nnfolder-save-active (group-alist active-file) 1074(defun nnfolder-save-active (group-alist active-file)
1102 (let ((nnmail-active-file-coding-system 1075 (let ((nnmail-active-file-coding-system
@@ -1182,100 +1155,6 @@ This command does not work if you use short group names."
1182 (mail-header-set-number headers article) 1155 (mail-header-set-number headers article)
1183 (nnheader-insert-nov headers))) 1156 (nnheader-insert-nov headers)))
1184 1157
1185(deffoo nnfolder-request-set-mark (group actions &optional server)
1186 (when (and server
1187 (not (nnfolder-server-opened server)))
1188 (nnfolder-open-server server))
1189 (unless nnfolder-marks-is-evil
1190 (nnfolder-open-marks group server)
1191 (setq nnfolder-marks (nnheader-update-marks-actions nnfolder-marks actions))
1192 (nnfolder-save-marks group server))
1193 nil)
1194
1195(deffoo nnfolder-request-marks (group info &optional server)
1196 ;; Change servers.
1197 (when (and server
1198 (not (nnfolder-server-opened server)))
1199 (nnfolder-open-server server))
1200 (when (and (not nnfolder-marks-is-evil) (nnfolder-marks-changed-p group))
1201 (nnheader-message 8 "Updating marks for %s..." group)
1202 (nnfolder-open-marks group server)
1203 ;; Update info using `nnfolder-marks'.
1204 (mapc (lambda (pred)
1205 (unless (memq (cdr pred) gnus-article-unpropagated-mark-lists)
1206 (gnus-info-set-marks
1207 info
1208 (gnus-update-alist-soft
1209 (cdr pred)
1210 (cdr (assq (cdr pred) nnfolder-marks))
1211 (gnus-info-marks info))
1212 t)))
1213 gnus-article-mark-lists)
1214 (let ((seen (cdr (assq 'read nnfolder-marks))))
1215 (gnus-info-set-read info
1216 (if (and (integerp (car seen))
1217 (null (cdr seen)))
1218 (list (cons (car seen) (car seen)))
1219 seen)))
1220 (nnheader-message 8 "Updating marks for %s...done" group))
1221 info)
1222
1223(defun nnfolder-group-marks-pathname (group)
1224 "Make pathname for GROUP NOV."
1225 (let ((nnfolder-directory (or nnfolder-marks-directory nnfolder-directory)))
1226 (concat (nnfolder-group-pathname group) nnfolder-marks-file-suffix)))
1227
1228(defun nnfolder-marks-changed-p (group)
1229 (let ((file (nnfolder-group-marks-pathname group)))
1230 (if (null (gnus-gethash file nnfolder-marks-modtime))
1231 t ;; never looked at marks file, assume it has changed
1232 (not (equal (gnus-gethash file nnfolder-marks-modtime)
1233 (nth 5 (file-attributes file)))))))
1234
1235(defun nnfolder-save-marks (group server)
1236 (let ((file-name-coding-system nnmail-pathname-coding-system)
1237 (file (nnfolder-group-marks-pathname group)))
1238 (condition-case err
1239 (progn
1240 (with-temp-file file
1241 (erase-buffer)
1242 (gnus-prin1 nnfolder-marks)
1243 (insert "\n"))
1244 (gnus-sethash file
1245 (nth 5 (file-attributes file))
1246 nnfolder-marks-modtime))
1247 (error (or (gnus-yes-or-no-p
1248 (format "Could not write to %s (%s). Continue? " file err))
1249 (error "Cannot write to %s (%s)" file err))))))
1250
1251(defun nnfolder-open-marks (group server)
1252 (let ((file (nnfolder-group-marks-pathname group)))
1253 (if (file-exists-p file)
1254 (condition-case err
1255 (with-temp-buffer
1256 (gnus-sethash file (nth 5 (file-attributes file))
1257 nnfolder-marks-modtime)
1258 (nnheader-insert-file-contents file)
1259 (setq nnfolder-marks (read (current-buffer)))
1260 (dolist (el gnus-article-unpropagated-mark-lists)
1261 (setq nnfolder-marks (gnus-remassoc el nnfolder-marks))))
1262 (error (or (gnus-yes-or-no-p
1263 (format "Error reading nnfolder marks file %s (%s). Continuing will use marks from .newsrc.eld. Continue? " file err))
1264 (error "Cannot read nnfolder marks file %s (%s)" file err))))
1265 ;; User didn't have a .marks file. Probably first time
1266 ;; user of the .marks stuff. Bootstrap it from .newsrc.eld.
1267 (let ((info (gnus-get-info
1268 (gnus-group-prefixed-name
1269 group
1270 (gnus-server-to-method (format "nnfolder:%s" server))))))
1271 (nnheader-message 7 "Bootstrapping marks for %s..." group)
1272 (setq nnfolder-marks (gnus-info-marks info))
1273 (push (cons 'read (gnus-info-read info)) nnfolder-marks)
1274 (dolist (el gnus-article-unpropagated-mark-lists)
1275 (setq nnfolder-marks (gnus-remassoc el nnfolder-marks)))
1276 (nnfolder-save-marks group server)
1277 (nnheader-message 7 "Bootstrapping marks for %s...done" group)))))
1278
1279(provide 'nnfolder) 1158(provide 'nnfolder)
1280 1159
1281;;; nnfolder.el ends here 1160;;; nnfolder.el ends here
diff --git a/lisp/gnus/nnimap.el b/lisp/gnus/nnimap.el
index 114d83b7286..5126c25f66b 100644
--- a/lisp/gnus/nnimap.el
+++ b/lisp/gnus/nnimap.el
@@ -117,7 +117,7 @@ some servers.")
117 117
118(defvoo nnimap-fetch-partial-articles nil 118(defvoo nnimap-fetch-partial-articles nil
119 "If non-nil, Gnus will fetch partial articles. 119 "If non-nil, Gnus will fetch partial articles.
120If t, nnimap will fetch only the first part. If a string, it 120If t, Gnus will fetch only the first part. If a string, it
121will fetch all parts that have types that match that string. A 121will fetch all parts that have types that match that string. A
122likely value would be \"text/\" to automatically fetch all 122likely value would be \"text/\" to automatically fetch all
123textual parts.") 123textual parts.")
diff --git a/lisp/gnus/nnmail.el b/lisp/gnus/nnmail.el
index 9c3a814d3ea..1645f49091f 100644
--- a/lisp/gnus/nnmail.el
+++ b/lisp/gnus/nnmail.el
@@ -40,6 +40,8 @@
40 40
41(autoload 'gnus-add-buffer "gnus") 41(autoload 'gnus-add-buffer "gnus")
42(autoload 'gnus-kill-buffer "gnus") 42(autoload 'gnus-kill-buffer "gnus")
43(eval-when-compile
44 (autoload 'mail-send-and-exit "sendmail" nil t))
43 45
44(defgroup nnmail nil 46(defgroup nnmail nil
45 "Reading mail with Gnus." 47 "Reading mail with Gnus."
@@ -553,11 +555,11 @@ parameter. It should return nil, `warn' or `delete'."
553 (const warn) 555 (const warn)
554 (const delete))) 556 (const delete)))
555 557
556(defcustom nnmail-extra-headers '(To Newsgroups) 558(defcustom nnmail-extra-headers '(To Newsgroups Cc)
557 "Extra headers to parse. 559 "Extra headers to parse.
558In addition to the standard headers, these extra headers will be 560In addition to the standard headers, these extra headers will be
559included in NOV headers (and the like) when backends parse headers." 561included in NOV headers (and the like) when backends parse headers."
560 :version "21.1" 562 :version "24.2"
561 :group 'nnmail 563 :group 'nnmail
562 :type '(repeat symbol)) 564 :type '(repeat symbol))
563 565
diff --git a/lisp/gnus/nnml.el b/lisp/gnus/nnml.el
index b8652600ae7..600a0d21e3c 100644
--- a/lisp/gnus/nnml.el
+++ b/lisp/gnus/nnml.el
@@ -4,7 +4,7 @@
4;; Foundation, Inc. 4;; Foundation, Inc.
5 5
6;; Authors: Didier Verna <didier@xemacs.org> (adding compaction) 6;; Authors: Didier Verna <didier@xemacs.org> (adding compaction)
7;; Simon Josefsson <simon@josefsson.org> (adding MARKS) 7;; Simon Josefsson <simon@josefsson.org>
8;; Lars Magne Ingebrigtsen <larsi@gnus.org> 8;; Lars Magne Ingebrigtsen <larsi@gnus.org>
9;; Masanobu UMEDA <umerin@flab.flab.fujitsu.junet> 9;; Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
10;; Keywords: news, mail 10;; Keywords: news, mail
@@ -67,15 +67,6 @@ the `nnml-generate-nov-databases' command. The function will go
67through all nnml directories and generate nov databases for them 67through all nnml directories and generate nov databases for them
68all. This may very well take some time.") 68all. This may very well take some time.")
69 69
70(defvoo nnml-marks-is-evil nil
71 "If non-nil, Gnus will never generate and use marks file for mail spools.
72Using marks files makes it possible to backup and restore mail groups
73separately from `.newsrc.eld'. If you have, for some reason, set this
74to t, and want to set it to nil again, you should always remove the
75corresponding marks file (usually named `.marks' in the nnml group
76directory, but see `nnml-marks-file-name') for the group. Then the
77marks file will be regenerated properly by Gnus.")
78
79(defvoo nnml-prepare-save-mail-hook nil 70(defvoo nnml-prepare-save-mail-hook nil
80 "Hook run narrowed to an article before saving.") 71 "Hook run narrowed to an article before saving.")
81 72
@@ -102,7 +93,6 @@ non-nil.")
102 "nnml version.") 93 "nnml version.")
103 94
104(defvoo nnml-nov-file-name ".overview") 95(defvoo nnml-nov-file-name ".overview")
105(defvoo nnml-marks-file-name ".marks")
106 96
107(defvoo nnml-current-directory nil) 97(defvoo nnml-current-directory nil)
108(defvoo nnml-current-group nil) 98(defvoo nnml-current-group nil)
@@ -118,10 +108,6 @@ non-nil.")
118 108
119(defvoo nnml-file-coding-system nnmail-file-coding-system) 109(defvoo nnml-file-coding-system nnmail-file-coding-system)
120 110
121(defvoo nnml-marks nil)
122
123(defvar nnml-marks-modtime (gnus-make-hashtable))
124
125 111
126;;; Interface functions. 112;;; Interface functions.
127 113
@@ -513,8 +499,7 @@ non-nil.")
513 nnml-current-directory t 499 nnml-current-directory t
514 (concat 500 (concat
515 nnheader-numerical-short-files 501 nnheader-numerical-short-files
516 "\\|" (regexp-quote nnml-nov-file-name) "$" 502 "\\|" (regexp-quote nnml-nov-file-name) "$")))
517 "\\|" (regexp-quote nnml-marks-file-name) "$")))
518 (decoded (nnml-decoded-group-name group server))) 503 (decoded (nnml-decoded-group-name group server)))
519 (dolist (article articles) 504 (dolist (article articles)
520 (when (file-writable-p article) 505 (when (file-writable-p article)
@@ -554,10 +539,6 @@ non-nil.")
554 (let ((overview (concat old-dir nnml-nov-file-name))) 539 (let ((overview (concat old-dir nnml-nov-file-name)))
555 (when (file-exists-p overview) 540 (when (file-exists-p overview)
556 (rename-file overview (concat new-dir nnml-nov-file-name)))) 541 (rename-file overview (concat new-dir nnml-nov-file-name))))
557 ;; Move .marks file.
558 (let ((marks (concat old-dir nnml-marks-file-name)))
559 (when (file-exists-p marks)
560 (rename-file marks (concat new-dir nnml-marks-file-name))))
561 (when (<= (length (directory-files old-dir)) 2) 542 (when (<= (length (directory-files old-dir)) 2)
562 (ignore-errors (delete-directory old-dir))) 543 (ignore-errors (delete-directory old-dir)))
563 ;; That went ok, so we change the internal structures. 544 ;; That went ok, so we change the internal structures.
@@ -1033,99 +1014,6 @@ Use the nov database for the current group if available."
1033 (forward-line 1)) 1014 (forward-line 1))
1034 alist)))) 1015 alist))))
1035 1016
1036(deffoo nnml-request-set-mark (group actions &optional server)
1037 (nnml-possibly-change-directory group server)
1038 (unless nnml-marks-is-evil
1039 (nnml-open-marks group server)
1040 (setq nnml-marks (nnheader-update-marks-actions nnml-marks actions))
1041 (nnml-save-marks group server))
1042 nil)
1043
1044(deffoo nnml-request-marks (group info &optional server)
1045 (nnml-possibly-change-directory group server)
1046 (when (and (not nnml-marks-is-evil) (nnml-marks-changed-p group server))
1047 (nnheader-message 8 "Updating marks for %s..." group)
1048 (nnml-open-marks group server)
1049 ;; Update info using `nnml-marks'.
1050 (mapc (lambda (pred)
1051 (unless (memq (cdr pred) gnus-article-unpropagated-mark-lists)
1052 (gnus-info-set-marks
1053 info
1054 (gnus-update-alist-soft
1055 (cdr pred)
1056 (cdr (assq (cdr pred) nnml-marks))
1057 (gnus-info-marks info))
1058 t)))
1059 gnus-article-mark-lists)
1060 (let ((seen (cdr (assq 'read nnml-marks))))
1061 (gnus-info-set-read info
1062 (if (and (integerp (car seen))
1063 (null (cdr seen)))
1064 (list (cons (car seen) (car seen)))
1065 seen)))
1066 (nnheader-message 8 "Updating marks for %s...done" group))
1067 info)
1068
1069(defun nnml-marks-changed-p (group server)
1070 (let ((file (nnml-group-pathname group nnml-marks-file-name server)))
1071 (if (null (gnus-gethash file nnml-marks-modtime))
1072 t ;; never looked at marks file, assume it has changed
1073 (not (equal (gnus-gethash file nnml-marks-modtime)
1074 (nth 5 (file-attributes file)))))))
1075
1076(defun nnml-save-marks (group server)
1077 (let ((file-name-coding-system nnmail-pathname-coding-system)
1078 (file (nnml-group-pathname group nnml-marks-file-name server)))
1079 (condition-case err
1080 (progn
1081 (nnml-possibly-create-directory group server)
1082 (with-temp-file file
1083 (erase-buffer)
1084 (gnus-prin1 nnml-marks)
1085 (insert "\n"))
1086 (gnus-sethash file
1087 (nth 5 (file-attributes file))
1088 nnml-marks-modtime))
1089 (error (or (gnus-yes-or-no-p
1090 (format "Could not write to %s (%s). Continue? " file err))
1091 (error "Cannot write to %s (%s)" file err))))))
1092
1093(defun nnml-open-marks (group server)
1094 (let* ((decoded (nnml-decoded-group-name group server))
1095 (file (nnmail-group-pathname decoded nnml-directory
1096 nnml-marks-file-name))
1097 (file-name-coding-system nnmail-pathname-coding-system))
1098 (if (file-exists-p file)
1099 (condition-case err
1100 (with-temp-buffer
1101 (gnus-sethash file (nth 5 (file-attributes file))
1102 nnml-marks-modtime)
1103 (nnheader-insert-file-contents file)
1104 (setq nnml-marks (read (current-buffer)))
1105 (dolist (el gnus-article-unpropagated-mark-lists)
1106 (setq nnml-marks (gnus-remassoc el nnml-marks))))
1107 (error (or (gnus-yes-or-no-p
1108 (format "Error reading nnml marks file %s (%s). Continuing will use marks from .newsrc.eld. Continue? " file err))
1109 (error "Cannot read nnml marks file %s (%s)" file err))))
1110 ;; User didn't have a .marks file. Probably first time
1111 ;; user of the .marks stuff. Bootstrap it from .newsrc.eld.
1112 (let ((info (gnus-get-info
1113 (gnus-group-prefixed-name
1114 group
1115 (gnus-server-to-method
1116 (format "nnml:%s" (or server "")))))))
1117 (setq decoded (if (member server '(nil ""))
1118 (concat "nnml:" decoded)
1119 (format "nnml+%s:%s" server decoded)))
1120 (nnheader-message 7 "Bootstrapping marks for %s..." decoded)
1121 (setq nnml-marks (gnus-info-marks info))
1122 (push (cons 'read (gnus-info-read info)) nnml-marks)
1123 (dolist (el gnus-article-unpropagated-mark-lists)
1124 (setq nnml-marks (gnus-remassoc el nnml-marks)))
1125 (nnml-save-marks group server)
1126 (nnheader-message 7 "Bootstrapping marks for %s...done" decoded)))))
1127
1128
1129;;; 1017;;;
1130;;; Group and server compaction. -- dvl 1018;;; Group and server compaction. -- dvl
1131;;; 1019;;;
@@ -1275,19 +1163,11 @@ Use the nov database for the current group if available."
1275 (gnus-set-active group-full-name active)) 1163 (gnus-set-active group-full-name active))
1276 ;; 1 bis/ 1164 ;; 1 bis/
1277 ;; #### NOTE: normally, we should save the overview (NOV) file 1165 ;; #### NOTE: normally, we should save the overview (NOV) file
1278 ;; #### here, just like we save the marks file. However, there is no 1166 ;; #### here. However, there is no such function as
1279 ;; #### such function as nnml-save-nov for a single group. Only for 1167 ;; #### nnml-save-nov for a single group. Only for all
1280 ;; #### all groups. Gnus inconsistency is getting worse every day... 1168 ;; #### groups. Gnus inconsistency is getting worse every
1281 ;; 2/ Rebuild marks file: 1169 ;; #### day... ;; 3/ Save everything if this was not part of
1282 (unless nnml-marks-is-evil 1170 ;; #### a bigger operation:
1283 ;; #### NOTE: this constant use of global variables everywhere is
1284 ;; #### truly disgusting. Gnus really needs a *major* cleanup.
1285 (setq nnml-marks (gnus-info-marks info))
1286 (push (cons 'read (gnus-info-read info)) nnml-marks)
1287 (dolist (el gnus-article-unpropagated-mark-lists)
1288 (setq nnml-marks (gnus-remassoc el nnml-marks)))
1289 (nnml-save-marks group server))
1290 ;; 3/ Save everything if this was not part of a bigger operation:
1291 (if (not save) 1171 (if (not save)
1292 ;; Nothing to save (yet): 1172 ;; Nothing to save (yet):
1293 t 1173 t
@@ -1298,9 +1178,6 @@ Use the nov database for the current group if available."
1298 (nnml-save-nov) 1178 (nnml-save-nov)
1299 ;; b/ Save the active file: 1179 ;; b/ Save the active file:
1300 (nnmail-save-active nnml-group-alist nnml-active-file) 1180 (nnmail-save-active nnml-group-alist nnml-active-file)
1301 (let ((marks (nnml-group-pathname group nnml-marks-file-name server)))
1302 (when (file-exists-p marks)
1303 (delete-file marks)))
1304 t))))) 1181 t)))))
1305 1182
1306(defun nnml-request-compact (&optional server) 1183(defun nnml-request-compact (&optional server)
diff --git a/lisp/gnus/nntp.el b/lisp/gnus/nntp.el
index e237227f78a..c538d740209 100644
--- a/lisp/gnus/nntp.el
+++ b/lisp/gnus/nntp.el
@@ -222,27 +222,6 @@ then use this hook to rsh to the remote machine and start a proxy NNTP
222server there that you can connect to. See also 222server there that you can connect to. See also
223`nntp-open-connection-function'") 223`nntp-open-connection-function'")
224 224
225(defvoo nntp-coding-system-for-read 'binary
226 "*Coding system to read from NNTP.")
227
228(defvoo nntp-coding-system-for-write 'binary
229 "*Coding system to write to NNTP.")
230
231;; Marks
232(defvoo nntp-marks-is-evil nil
233 "*If non-nil, Gnus will never generate and use marks file for nntp groups.
234See `nnml-marks-is-evil' for more information.")
235
236(defvoo nntp-marks-file-name ".marks")
237(defvoo nntp-marks nil)
238(defvar nntp-marks-modtime (gnus-make-hashtable))
239
240(defcustom nntp-marks-directory
241 (nnheader-concat gnus-directory "marks/")
242 "*The directory where marks for nntp groups will be stored."
243 :group 'nntp
244 :type 'directory)
245
246(defcustom nntp-authinfo-file "~/.authinfo" 225(defcustom nntp-authinfo-file "~/.authinfo"
247 ".netrc-like file that holds nntp authinfo passwords." 226 ".netrc-like file that holds nntp authinfo passwords."
248 :group 'nntp 227 :group 'nntp
@@ -826,7 +805,8 @@ command whose response triggered the error."
826 (progn 805 (progn
827 (nntp-copy-to-buffer nntp-server-buffer 806 (nntp-copy-to-buffer nntp-server-buffer
828 (point-min) (point-max)) 807 (point-min) (point-max))
829 (gnus-groups-to-gnus-format method gnus-active-hashtb t)) 808 (with-current-buffer nntp-server-buffer
809 (gnus-groups-to-gnus-format method gnus-active-hashtb t)))
830 ;; We have read active entries, so we just delete the 810 ;; We have read active entries, so we just delete the
831 ;; superfluous gunk. 811 ;; superfluous gunk.
832 (goto-char (point-min)) 812 (goto-char (point-min))
@@ -1184,43 +1164,6 @@ command whose response triggered the error."
1184(deffoo nntp-asynchronous-p () 1164(deffoo nntp-asynchronous-p ()
1185 t) 1165 t)
1186 1166
1187(deffoo nntp-request-set-mark (group actions &optional server)
1188 (when (and (not nntp-marks-is-evil)
1189 nntp-marks-file-name)
1190 (nntp-possibly-create-directory group server)
1191 (nntp-open-marks group server)
1192 (setq nntp-marks (nnheader-update-marks-actions nntp-marks actions))
1193 (nntp-save-marks group server))
1194 nil)
1195
1196(deffoo nntp-request-marks (group info &optional server)
1197 (when (and (not nntp-marks-is-evil)
1198 nntp-marks-file-name)
1199 (nntp-possibly-create-directory group server)
1200 (when (nntp-marks-changed-p group server)
1201 (nnheader-message 8 "Updating marks for %s..." group)
1202 (nntp-open-marks group server)
1203 ;; Update info using `nntp-marks'.
1204 (mapc (lambda (pred)
1205 (unless (memq (cdr pred) gnus-article-unpropagated-mark-lists)
1206 (gnus-info-set-marks
1207 info
1208 (gnus-update-alist-soft
1209 (cdr pred)
1210 (cdr (assq (cdr pred) nntp-marks))
1211 (gnus-info-marks info))
1212 t)))
1213 gnus-article-mark-lists)
1214 (let ((seen (cdr (assq 'read nntp-marks))))
1215 (gnus-info-set-read info
1216 (if (and (integerp (car seen))
1217 (null (cdr seen)))
1218 (list (cons (car seen) (car seen)))
1219 seen)))
1220 (nnheader-message 8 "Updating marks for %s...done" group)))
1221 nil)
1222
1223
1224 1167
1225;;; Hooky functions. 1168;;; Hooky functions.
1226 1169
@@ -1351,8 +1294,8 @@ password contained in '~/.nntp-authinfo'."
1351 (nntp-kill-buffer ,pbuffer))))) 1294 (nntp-kill-buffer ,pbuffer)))))
1352 (process 1295 (process
1353 (condition-case err 1296 (condition-case err
1354 (let ((coding-system-for-read nntp-coding-system-for-read) 1297 (let ((coding-system-for-read 'binary)
1355 (coding-system-for-write nntp-coding-system-for-write) 1298 (coding-system-for-write 'binary)
1356 (map '((nntp-open-network-stream network) 1299 (map '((nntp-open-network-stream network)
1357 (network-only plain) ; compat 1300 (network-only plain) ; compat
1358 (nntp-open-plain-stream plain) 1301 (nntp-open-plain-stream plain)
@@ -2161,95 +2104,6 @@ Please refer to the following variables to customize the connection:
2161 (delete-region (point) (point-max))) 2104 (delete-region (point) (point-max)))
2162 proc))) 2105 proc)))
2163 2106
2164;; Marks handling
2165
2166(defun nntp-marks-directory (server)
2167 (expand-file-name server nntp-marks-directory))
2168
2169(defvar nntp-server-to-method-cache nil
2170 "Alist of servers and select methods.")
2171
2172(defun nntp-group-pathname (server group &optional file)
2173 "Return an absolute file name of FILE for GROUP on SERVER."
2174 (let ((method (cdr (assoc server nntp-server-to-method-cache))))
2175 (unless method
2176 (push (cons server (setq method (or (gnus-server-to-method server)
2177 (gnus-find-method-for-group group))))
2178 nntp-server-to-method-cache))
2179 (nnmail-group-pathname
2180 (mm-decode-coding-string group
2181 (inline (gnus-group-name-charset method group)))
2182 (nntp-marks-directory server)
2183 file)))
2184
2185(defun nntp-possibly-create-directory (group server)
2186 (let ((dir (nntp-group-pathname server group))
2187 (file-name-coding-system nnmail-pathname-coding-system))
2188 (unless (file-exists-p dir)
2189 (make-directory (directory-file-name dir) t)
2190 (nnheader-message 5 "Creating nntp marks directory %s" dir))))
2191
2192(autoload 'time-less-p "time-date")
2193
2194(defun nntp-marks-changed-p (group server)
2195 (let ((file (nntp-group-pathname server group nntp-marks-file-name))
2196 (file-name-coding-system nnmail-pathname-coding-system))
2197 (if (null (gnus-gethash file nntp-marks-modtime))
2198 t ;; never looked at marks file, assume it has changed
2199 (time-less-p (gnus-gethash file nntp-marks-modtime)
2200 (nth 5 (file-attributes file))))))
2201
2202(defun nntp-save-marks (group server)
2203 (let ((file-name-coding-system nnmail-pathname-coding-system)
2204 (file (nntp-group-pathname server group nntp-marks-file-name)))
2205 (condition-case err
2206 (progn
2207 (nntp-possibly-create-directory group server)
2208 (with-temp-file file
2209 (erase-buffer)
2210 (gnus-prin1 nntp-marks)
2211 (insert "\n"))
2212 (gnus-sethash file
2213 (nth 5 (file-attributes file))
2214 nntp-marks-modtime))
2215 (error (or (gnus-yes-or-no-p
2216 (format "Could not write to %s (%s). Continue? " file err))
2217 (error "Cannot write to %s (%s)" file err))))))
2218
2219(defun nntp-open-marks (group server)
2220 (let ((file (nntp-group-pathname server group nntp-marks-file-name))
2221 (file-name-coding-system nnmail-pathname-coding-system))
2222 (if (file-exists-p file)
2223 (condition-case err
2224 (with-temp-buffer
2225 (gnus-sethash file (nth 5 (file-attributes file))
2226 nntp-marks-modtime)
2227 (nnheader-insert-file-contents file)
2228 (setq nntp-marks (read (current-buffer)))
2229 (dolist (el gnus-article-unpropagated-mark-lists)
2230 (setq nntp-marks (gnus-remassoc el nntp-marks))))
2231 (error (or (gnus-yes-or-no-p
2232 (format "Error reading nntp marks file %s (%s). Continuing will use marks from .newsrc.eld. Continue? " file err))
2233 (error "Cannot read nntp marks file %s (%s)" file err))))
2234 ;; User didn't have a .marks file. Probably first time
2235 ;; user of the .marks stuff. Bootstrap it from .newsrc.eld.
2236 (let ((info (gnus-get-info
2237 (gnus-group-prefixed-name
2238 group
2239 (gnus-server-to-method (format "nntp:%s" server)))))
2240 (decoded-name (mm-decode-coding-string
2241 group
2242 (gnus-group-name-charset
2243 (gnus-server-to-method server) group))))
2244 (nnheader-message 7 "Bootstrapping marks for %s..." decoded-name)
2245 (setq nntp-marks (gnus-info-marks info))
2246 (push (cons 'read (gnus-info-read info)) nntp-marks)
2247 (dolist (el gnus-article-unpropagated-mark-lists)
2248 (setq nntp-marks (gnus-remassoc el nntp-marks)))
2249 (nntp-save-marks group server)
2250 (nnheader-message 7 "Bootstrapping marks for %s...done"
2251 decoded-name)))))
2252
2253(provide 'nntp) 2107(provide 'nntp)
2254 2108
2255;;; nntp.el ends here 2109;;; nntp.el ends here
diff --git a/lisp/gnus/pop3.el b/lisp/gnus/pop3.el
index ee4345c2f4f..25330989e00 100644
--- a/lisp/gnus/pop3.el
+++ b/lisp/gnus/pop3.el
@@ -194,10 +194,16 @@ Use streaming commands."
194 (unless (memq (process-status process) '(open run)) 194 (unless (memq (process-status process) '(open run))
195 (error "pop3 process died")) 195 (error "pop3 process died"))
196 (when total-size 196 (when total-size
197 (message "pop3 retrieved %dKB (%d%%)" 197 (let ((size 0))
198 (truncate (/ (buffer-size) 1000)) 198 (goto-char (point-min))
199 (truncate (* (/ (* (buffer-size) 1.0) 199 (while (re-search-forward "^\\+OK.*\n" nil t)
200 total-size) 100)))) 200 (setq size (+ size (- (point))
201 (if (re-search-forward "^\\.\r?\n" nil 'move)
202 (match-beginning 0)
203 (point)))))
204 (message "pop3 retrieved %dKB (%d%%)"
205 (truncate (/ size 1000))
206 (truncate (* (/ (* size 1.0) total-size) 100)))))
201 (pop3-accept-process-output process)) 207 (pop3-accept-process-output process))
202 start-point) 208 start-point)
203 209
diff --git a/lisp/gnus/registry.el b/lisp/gnus/registry.el
index c54fe3e3d71..b2130d56eb6 100644
--- a/lisp/gnus/registry.el
+++ b/lisp/gnus/registry.el
@@ -79,12 +79,6 @@
79 79
80(eval-when-compile (require 'cl)) 80(eval-when-compile (require 'cl))
81 81
82(eval-when-compile
83 (when (null (ignore-errors (require 'ert)))
84 (defmacro* ert-deftest (name () &body docstring-keys-and-body))))
85
86(ignore-errors
87 (require 'ert))
88(eval-and-compile 82(eval-and-compile
89 (or (ignore-errors (progn 83 (or (ignore-errors (progn
90 (require 'eieio) 84 (require 'eieio)
@@ -373,111 +367,5 @@ Proposes any entries over the max-hard limit minus size * prune-factor."
373 collect k))) 367 collect k)))
374 (list limit candidates)))) 368 (list limit candidates))))
375 369
376(ert-deftest registry-instantiation-test ()
377 (should (registry-db "Testing")))
378
379(ert-deftest registry-match-test ()
380 (let ((entry '((hello "goodbye" "bye") (blank))))
381
382 (message "Testing :regex matching")
383 (should (registry--match :regex entry '((hello "nye" "bye"))))
384 (should (registry--match :regex entry '((hello "good"))))
385 (should-not (registry--match :regex entry '((hello "nye"))))
386 (should-not (registry--match :regex entry '((hello))))
387
388 (message "Testing :member matching")
389 (should (registry--match :member entry '((hello "bye"))))
390 (should (registry--match :member entry '((hello "goodbye"))))
391 (should-not (registry--match :member entry '((hello "good"))))
392 (should-not (registry--match :member entry '((hello "nye"))))
393 (should-not (registry--match :member entry '((hello)))))
394 (message "Done with matching testing."))
395
396(defun registry-make-testable-db (n &optional name file)
397 (let* ((db (registry-db
398 (or name "Testing")
399 :file (or file "unused")
400 :max-hard n
401 :max-soft 0 ; keep nothing not precious
402 :precious '(extra more-extra)
403 :tracked '(sender subject groups))))
404 (dotimes (i n)
405 (registry-insert db i `((sender "me")
406 (subject "about you")
407 (more-extra) ; empty data key should be pruned
408 ;; first 5 entries will NOT have this extra data
409 ,@(when (< 5 i) (list (list 'extra "more data")))
410 (groups ,(number-to-string i)))))
411 db))
412
413(ert-deftest registry-usage-test ()
414 (let* ((n 100)
415 (db (registry-make-testable-db n)))
416 (message "size %d" n)
417 (should (= n (registry-size db)))
418 (message "max-hard test")
419 (should-error (registry-insert db "new" '()))
420 (message "Individual lookup")
421 (should (= 58 (caadr (registry-lookup db '(1 58 99)))))
422 (message "Grouped individual lookup")
423 (should (= 3 (length (registry-lookup db '(1 58 99)))))
424 (when (boundp 'lexical-binding)
425 (message "Individual lookup (breaks before lexbind)")
426 (should (= 58
427 (caadr (registry-lookup-breaks-before-lexbind db '(1 58 99)))))
428 (message "Grouped individual lookup (breaks before lexbind)")
429 (should (= 3
430 (length (registry-lookup-breaks-before-lexbind db
431 '(1 58 99))))))
432 (message "Search")
433 (should (= n (length (registry-search db :all t))))
434 (should (= n (length (registry-search db :member '((sender "me"))))))
435 (message "Secondary index search")
436 (should (= n (length (registry-lookup-secondary-value db 'sender "me"))))
437 (should (equal '(74) (registry-lookup-secondary-value db 'groups "74")))
438 (message "Delete")
439 (should (registry-delete db '(1) t))
440 (decf n)
441 (message "Search after delete")
442 (should (= n (length (registry-search db :all t))))
443 (message "Secondary search after delete")
444 (should (= n (length (registry-lookup-secondary-value db 'sender "me"))))
445 ;; (message "Pruning")
446 ;; (let* ((tokeep (registry-search db :member '((extra "more data"))))
447 ;; (count (- n (length tokeep)))
448 ;; (pruned (registry-prune db))
449 ;; (prune-count (length pruned)))
450 ;; (message "Expecting to prune %d entries and pruned %d"
451 ;; count prune-count)
452 ;; (should (and (= count 5)
453 ;; (= count prune-count))))
454 (message "Done with usage testing.")))
455
456(ert-deftest registry-persistence-test ()
457 (let* ((n 100)
458 (tempfile (make-temp-file "registry-persistence-"))
459 (name "persistence tester")
460 (db (registry-make-testable-db n name tempfile))
461 size back)
462 (message "Saving to %s" tempfile)
463 (eieio-persistent-save db)
464 (setq size (nth 7 (file-attributes tempfile)))
465 (message "Saved to %s: size %d" tempfile size)
466 (should (< 0 size))
467 (with-temp-buffer
468 (insert-file-contents-literally tempfile)
469 (should (looking-at (concat ";; Object "
470 name
471 "\n;; EIEIO PERSISTENT OBJECT"))))
472 (message "Reading object back")
473 (setq back (eieio-persistent-read tempfile))
474 (should back)
475 (message "Read object back: %d keys, expected %d==%d"
476 (registry-size back) n (registry-size db))
477 (should (= (registry-size back) n))
478 (should (= (registry-size back) (registry-size db)))
479 (delete-file tempfile))
480 (message "Done with persistence testing."))
481
482(provide 'registry) 370(provide 'registry)
483;;; registry.el ends here 371;;; registry.el ends here
diff --git a/lisp/gnus/shr.el b/lisp/gnus/shr.el
index 42118298734..a0cf10daaaf 100644
--- a/lisp/gnus/shr.el
+++ b/lisp/gnus/shr.el
@@ -119,6 +119,7 @@ cid: URL as the argument.")
119 (let ((map (make-sparse-keymap))) 119 (let ((map (make-sparse-keymap)))
120 (define-key map "a" 'shr-show-alt-text) 120 (define-key map "a" 'shr-show-alt-text)
121 (define-key map "i" 'shr-browse-image) 121 (define-key map "i" 'shr-browse-image)
122 (define-key map "z" 'shr-zoom-image)
122 (define-key map "I" 'shr-insert-image) 123 (define-key map "I" 'shr-insert-image)
123 (define-key map "u" 'shr-copy-url) 124 (define-key map "u" 'shr-copy-url)
124 (define-key map "v" 'shr-browse-url) 125 (define-key map "v" 'shr-browse-url)
@@ -235,6 +236,40 @@ the URL of the image to the kill buffer instead."
235 (list (current-buffer) (1- (point)) (point-marker)) 236 (list (current-buffer) (1- (point)) (point-marker))
236 t t)))) 237 t t))))
237 238
239(defun shr-zoom-image ()
240 "Toggle the image size.
241The size will be rotated between the default size, the original
242size, and full-buffer size."
243 (interactive)
244 (let ((url (get-text-property (point) 'image-url))
245 (size (get-text-property (point) 'image-size))
246 (buffer-read-only nil))
247 (if (not url)
248 (message "No image under point")
249 ;; Delete the old picture.
250 (while (get-text-property (point) 'image-url)
251 (forward-char -1))
252 (forward-char 1)
253 (let ((start (point)))
254 (while (get-text-property (point) 'image-url)
255 (forward-char 1))
256 (forward-char -1)
257 (put-text-property start (point) 'display nil)
258 (when (> (- (point) start) 2)
259 (delete-region start (1- (point)))))
260 (message "Inserting %s..." url)
261 (url-retrieve url 'shr-image-fetched
262 (list (current-buffer) (1- (point)) (point-marker)
263 (list (cons 'size
264 (cond ((or (eq size 'default)
265 (null size))
266 'original)
267 ((eq size 'original)
268 'full)
269 ((eq size 'full)
270 'default)))))
271 t))))
272
238;;; Utility functions. 273;;; Utility functions.
239 274
240(defun shr-transform-dom (dom) 275(defun shr-transform-dom (dom)
@@ -298,6 +333,7 @@ the URL of the image to the kill buffer instead."
298 333
299(defun shr-insert (text) 334(defun shr-insert (text)
300 (when (and (eq shr-state 'image) 335 (when (and (eq shr-state 'image)
336 (not (bolp))
301 (not (string-match "\\`[ \t\n]+\\'" text))) 337 (not (string-match "\\`[ \t\n]+\\'" text)))
302 (insert "\n") 338 (insert "\n")
303 (setq shr-state nil)) 339 (setq shr-state nil))
@@ -305,11 +341,11 @@ the URL of the image to the kill buffer instead."
305 ((eq shr-folding-mode 'none) 341 ((eq shr-folding-mode 'none)
306 (insert text)) 342 (insert text))
307 (t 343 (t
308 (when (and (string-match "\\`[ \t\n]" text) 344 (when (and (string-match "\\`[ \t\n ]" text)
309 (not (bolp)) 345 (not (bolp))
310 (not (eq (char-after (1- (point))) ? ))) 346 (not (eq (char-after (1- (point))) ? )))
311 (insert " ")) 347 (insert " "))
312 (dolist (elem (split-string text)) 348 (dolist (elem (split-string text "[ \f\t\n\r\v ]+" t))
313 (when (and (bolp) 349 (when (and (bolp)
314 (> shr-indentation 0)) 350 (> shr-indentation 0))
315 (shr-indent)) 351 (shr-indent))
@@ -349,7 +385,7 @@ the URL of the image to the kill buffer instead."
349 (shr-indent)) 385 (shr-indent))
350 (end-of-line)) 386 (end-of-line))
351 (insert " "))) 387 (insert " ")))
352 (unless (string-match "[ \t\n]\\'" text) 388 (unless (string-match "[ \t\n ]\\'" text)
353 (delete-char -1))))) 389 (delete-char -1)))))
354 390
355(defun shr-find-fill-point () 391(defun shr-find-fill-point ()
@@ -408,32 +444,29 @@ the URL of the image to the kill buffer instead."
408 (shr-char-kinsoku-eol-p (following-char))))) 444 (shr-char-kinsoku-eol-p (following-char)))))
409 (goto-char bp))) 445 (goto-char bp)))
410 ((shr-char-kinsoku-eol-p (preceding-char)) 446 ((shr-char-kinsoku-eol-p (preceding-char))
411 (if (shr-char-kinsoku-eol-p (following-char)) 447 ;; Find backward the point where kinsoku-eol characters begin.
412 ;; There are consecutive kinsoku-eol characters. 448 (let ((count 4))
413 (setq failed t) 449 (while
414 (let ((count 4)) 450 (progn
415 (while 451 (backward-char 1)
416 (progn 452 (and (> (setq count (1- count)) 0)
417 (backward-char 1) 453 (not (memq (preceding-char) (list ?\C-@ ?\n ? )))
418 (and (> (setq count (1- count)) 0) 454 (or (shr-char-kinsoku-eol-p (preceding-char))
419 (not (memq (preceding-char) (list ?\C-@ ?\n ? ))) 455 (shr-char-kinsoku-bol-p (following-char)))))))
420 (or (shr-char-kinsoku-eol-p (preceding-char)) 456 (if (setq failed (= (current-column) shr-indentation))
421 (shr-char-kinsoku-bol-p (following-char))))))) 457 ;; There's no breakable point that doesn't violate kinsoku,
422 (if (setq failed (= (current-column) shr-indentation)) 458 ;; so we go to the second best position.
423 ;; There's no breakable point that doesn't violate kinsoku, 459 (if (looking-at "\\(\\c<+\\)\\c<")
424 ;; so we go to the second best position. 460 (goto-char (match-end 1))
425 (if (looking-at "\\(\\c<+\\)\\c<") 461 (forward-char 1))))
426 (goto-char (match-end 1)) 462 ((shr-char-kinsoku-bol-p (following-char))
427 (forward-char 1))))) 463 ;; Find forward the point where kinsoku-bol characters end.
428 (t 464 (let ((count 4))
429 (if (shr-char-kinsoku-bol-p (preceding-char)) 465 (while (progn
430 ;; There are consecutive kinsoku-bol characters. 466 (forward-char 1)
431 (setq failed t) 467 (and (>= (setq count (1- count)) 0)
432 (let ((count 4))
433 (while (and (>= (setq count (1- count)) 0)
434 (shr-char-kinsoku-bol-p (following-char)) 468 (shr-char-kinsoku-bol-p (following-char))
435 (shr-char-breakable-p (following-char))) 469 (shr-char-breakable-p (following-char))))))))
436 (forward-char 1))))))
437 (when (eq (following-char) ? ) 470 (when (eq (following-char) ? )
438 (forward-char 1)))) 471 (forward-char 1))))
439 (not failed))) 472 (not failed)))
@@ -465,7 +498,7 @@ the URL of the image to the kill buffer instead."
465 (if (save-excursion 498 (if (save-excursion
466 (beginning-of-line) 499 (beginning-of-line)
467 (looking-at " *$")) 500 (looking-at " *$"))
468 (insert "\n") 501 (delete-region (match-beginning 0) (match-end 0))
469 (insert "\n\n"))))) 502 (insert "\n\n")))))
470 503
471(defun shr-indent () 504(defun shr-indent ()
@@ -523,7 +556,7 @@ the URL of the image to the kill buffer instead."
523 (expand-file-name (file-name-nondirectory url) 556 (expand-file-name (file-name-nondirectory url)
524 directory))))) 557 directory)))))
525 558
526(defun shr-image-fetched (status buffer start end) 559(defun shr-image-fetched (status buffer start end &optional flags)
527 (let ((image-buffer (current-buffer))) 560 (let ((image-buffer (current-buffer)))
528 (when (and (buffer-name buffer) 561 (when (and (buffer-name buffer)
529 (not (plist-get status :error))) 562 (not (plist-get status :error)))
@@ -534,30 +567,53 @@ the URL of the image to the kill buffer instead."
534 (with-current-buffer buffer 567 (with-current-buffer buffer
535 (save-excursion 568 (save-excursion
536 (let ((alt (buffer-substring start end)) 569 (let ((alt (buffer-substring start end))
570 (properties (text-properties-at start))
537 (inhibit-read-only t)) 571 (inhibit-read-only t))
538 (delete-region start end) 572 (delete-region start end)
539 (goto-char start) 573 (goto-char start)
540 (funcall shr-put-image-function data alt))))))) 574 (funcall shr-put-image-function data alt flags)
575 (while properties
576 (let ((type (pop properties))
577 (value (pop properties)))
578 (unless (memq type '(display image-size))
579 (put-text-property start (point) type value))))))))))
541 (kill-buffer image-buffer))) 580 (kill-buffer image-buffer)))
542 581
543(defun shr-put-image (data alt) 582(defun shr-put-image (data alt &optional flags)
544 "Put image DATA with a string ALT. Return image." 583 "Put image DATA with a string ALT. Return image."
545 (if (display-graphic-p) 584 (if (display-graphic-p)
546 (let ((image (ignore-errors 585 (let* ((size (cdr (assq 'size flags)))
547 (shr-rescale-image data)))) 586 (start (point))
587 (image (cond
588 ((eq size 'original)
589 (create-image data nil t :ascent 100))
590 ((eq size 'full)
591 (ignore-errors
592 (shr-rescale-image data t)))
593 (t
594 (ignore-errors
595 (shr-rescale-image data))))))
548 (when image 596 (when image
549 ;; When inserting big-ish pictures, put them at the 597 ;; When inserting big-ish pictures, put them at the
550 ;; beginning of the line. 598 ;; beginning of the line.
551 (when (and (> (current-column) 0) 599 (when (and (> (current-column) 0)
552 (> (car (image-size image t)) 400)) 600 (> (car (image-size image t)) 400))
553 (insert "\n")) 601 (insert "\n"))
554 (insert-image image (or alt "*")) 602 (if (eq size 'original)
603 (let ((overlays (overlays-at (point))))
604 (insert-sliced-image image (or alt "*") nil 20 1)
605 (dolist (overlay overlays)
606 (overlay-put overlay 'face 'default)))
607 (insert-image image (or alt "*")))
608 (put-text-property start (point) 'image-size size)
555 (when (image-animated-p image) 609 (when (image-animated-p image)
556 (image-animate image nil 60))) 610 (image-animate image nil 60)))
557 image) 611 image)
558 (insert alt))) 612 (insert alt)))
559 613
560(defun shr-rescale-image (data) 614(defun shr-rescale-image (data &optional force)
615 "Rescale DATA, if too big, to fit the current buffer.
616If FORCE, rescale the image anyway."
561 (let ((image (create-image data nil t :ascent 100))) 617 (let ((image (create-image data nil t :ascent 100)))
562 (if (or (not (fboundp 'imagemagick-types)) 618 (if (or (not (fboundp 'imagemagick-types))
563 (not (get-buffer-window (current-buffer)))) 619 (not (get-buffer-window (current-buffer))))
@@ -572,7 +628,8 @@ the URL of the image to the kill buffer instead."
572 (window-height (truncate (* shr-max-image-proportion 628 (window-height (truncate (* shr-max-image-proportion
573 (- (nth 3 edges) (nth 1 edges))))) 629 (- (nth 3 edges) (nth 1 edges)))))
574 scaled-image) 630 scaled-image)
575 (when (> height window-height) 631 (when (or force
632 (> height window-height))
576 (setq image (or (create-image data 'imagemagick t 633 (setq image (or (create-image data 'imagemagick t
577 :height window-height 634 :height window-height
578 :ascent 100) 635 :ascent 100)
@@ -984,7 +1041,12 @@ ones, in case fg and bg are nil."
984 (shr-generic cont))) 1041 (shr-generic cont)))
985 1042
986(defun shr-tag-br (cont) 1043(defun shr-tag-br (cont)
987 (unless (bobp) 1044 (when (and (not (bobp))
1045 ;; Only add a newline if we break the current line, or
1046 ;; the previous line isn't a blank line.
1047 (or (not (bolp))
1048 (and (> (- (point) 2) (point-min))
1049 (not (= (char-after (- (point) 2)) ?\n)))))
988 (insert "\n") 1050 (insert "\n")
989 (shr-indent)) 1051 (shr-indent))
990 (shr-generic cont)) 1052 (shr-generic cont))
diff --git a/lisp/gnus/spam.el b/lisp/gnus/spam.el
index 3cfbd7dba35..c3be15adc1a 100644
--- a/lisp/gnus/spam.el
+++ b/lisp/gnus/spam.el
@@ -2088,11 +2088,6 @@ See the Info node `(gnus)Fancy Mail Splitting' for more details."
2088 2088
2089;; all this is done inside a condition-case to trap errors 2089;; all this is done inside a condition-case to trap errors
2090 2090
2091(eval-when-compile
2092 (autoload 'bbdb-buffer "bbdb")
2093 (autoload 'bbdb-create-internal "bbdb")
2094 (autoload 'bbdb-search-simple "bbdb"))
2095
2096;; Autoloaded in message, which we require. 2091;; Autoloaded in message, which we require.
2097(declare-function gnus-extract-address-components "gnus-util" (from)) 2092(declare-function gnus-extract-address-components "gnus-util" (from))
2098 2093
@@ -2104,9 +2099,13 @@ See the Info node `(gnus)Fancy Mail Splitting' for more details."
2104 (file-error 2099 (file-error
2105 ;; `bbdb-records' should not be bound as an autoload function 2100 ;; `bbdb-records' should not be bound as an autoload function
2106 ;; before loading bbdb because of `bbdb-hashtable-size'. 2101 ;; before loading bbdb because of `bbdb-hashtable-size'.
2102 (defalias 'bbdb-buffer 'ignore)
2103 (defalias 'bbdb-create-internal 'ignore)
2107 (defalias 'bbdb-records 'ignore) 2104 (defalias 'bbdb-records 'ignore)
2108 (defalias 'spam-BBDB-register-routine 'ignore) 2105 (defalias 'spam-BBDB-register-routine 'ignore)
2109 (defalias 'spam-enter-ham-BBDB 'ignore) 2106 (defalias 'spam-enter-ham-BBDB 'ignore)
2107 (defalias 'spam-exists-in-BBDB-p 'ignore)
2108 (defalias 'bbdb-gethash 'ignore)
2110 nil)) 2109 nil))
2111 2110
2112 ;; when the BBDB changes, we want to clear out our cache 2111 ;; when the BBDB changes, we want to clear out our cache
@@ -2126,7 +2125,7 @@ See the Info node `(gnus)Fancy Mail Splitting' for more details."
2126 'ignore)) 2125 'ignore))
2127 (net-address (nth 1 parsed-address)) 2126 (net-address (nth 1 parsed-address))
2128 (record (and net-address 2127 (record (and net-address
2129 (bbdb-search-simple nil net-address)))) 2128 (spam-exists-in-BBDB-p net-address))))
2130 (when net-address 2129 (when net-address
2131 (gnus-message 6 "%s address %s %s BBDB" 2130 (gnus-message 6 "%s address %s %s BBDB"
2132 (if remove "Deleting" "Adding") 2131 (if remove "Deleting" "Adding")
@@ -2148,15 +2147,17 @@ See the Info node `(gnus)Fancy Mail Splitting' for more details."
2148 (defun spam-BBDB-unregister-routine (articles) 2147 (defun spam-BBDB-unregister-routine (articles)
2149 (spam-BBDB-register-routine articles t)) 2148 (spam-BBDB-register-routine articles t))
2150 2149
2150 (defsubst spam-exists-in-BBDB-p (net)
2151 (when (and (stringp net) (not (zerop (length net))))
2152 (bbdb-records)
2153 (bbdb-gethash (downcase net))))
2154
2151 (defun spam-check-BBDB () 2155 (defun spam-check-BBDB ()
2152 "Mail from people in the BBDB is classified as ham or non-spam" 2156 "Mail from people in the BBDB is classified as ham or non-spam"
2153 (let ((who (message-fetch-field "from"))) 2157 (let ((net (message-fetch-field "from")))
2154 (when who 2158 (when net
2155 (setq who (nth 1 (gnus-extract-address-components who))) 2159 (setq net (nth 1 (gnus-extract-address-components net)))
2156 (if 2160 (if (spam-exists-in-BBDB-p net)
2157 (if (fboundp 'bbdb-search)
2158 (bbdb-search (bbdb-records) who) ;; v3
2159 (bbdb-search-simple nil who)) ;; v2
2160 t 2161 t
2161 (if spam-use-BBDB-exclusive 2162 (if spam-use-BBDB-exclusive
2162 spam-split-group 2163 spam-split-group