diff options
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 @@ | |||
| 1 | 2012-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 | |||
| 6 | 2012-06-26 Wolfgang Jenkner <wjenkner@inode.at> | ||
| 7 | |||
| 8 | * gnus.texi (Picons): Document gnus-picon-properties. | ||
| 9 | |||
| 10 | 2012-06-26 Lars Magne Ingebrigtsen <larsi@gnus.org> | ||
| 11 | |||
| 12 | * gnus.texi: Remove mention of compilation, as that's no longer | ||
| 13 | supported. | ||
| 14 | |||
| 15 | 2012-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 | |||
| 20 | 2012-06-26 Lars Ingebrigtsen <larsi@gnus.org> | ||
| 21 | |||
| 22 | * gnus.texi (Various Summary Stuff): | ||
| 23 | Remove mention of `gnus-propagate-marks'. | ||
| 24 | |||
| 25 | 2012-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 | |||
| 30 | 2012-06-26 Katsumi Yamaoka <yamaoka@jpl.org> | ||
| 31 | |||
| 32 | * gnus.texi (Archived Messages): | ||
| 33 | Document gnus-gcc-self-resent-messages. | ||
| 34 | |||
| 35 | 2012-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 | |||
| 40 | 2012-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 | |||
| 46 | 2012-06-26 Lars Ingebrigtsen <larsi@gnus.org> | ||
| 47 | |||
| 48 | * gnus.texi (Key Index): Change encoding to utf-8. | ||
| 49 | |||
| 1 | 2012-06-21 Glenn Morris <rgm@gnu.org> | 50 | 2012-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 |
| 14 | Copyright @copyright{} 1995-2012 Free Software Foundation, Inc. | 14 | Copyright @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 | ||
| 668 | Getting Mail | 667 | Getting 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 | ||
| 912 | Customization | 911 | Customization |
| 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 | ||
| 1069 | Note: the @acronym{NNTP} back end stores marks in marks files | ||
| 1070 | (@pxref{NNTP marks}). This feature makes it easy to share marks between | ||
| 1071 | several Gnus installations, but may slow down things a bit when fetching | ||
| 1072 | new 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 | |||
| 2884 | generated, if @code{(gcc-self . "string")} is present, this string will | 2879 | generated, if @code{(gcc-self . "string")} is present, this string will |
| 2885 | be inserted literally as a @code{gcc} header. This parameter takes | 2880 | be inserted literally as a @code{gcc} header. This parameter takes |
| 2886 | precedence over any default @code{Gcc} rules as described later | 2881 | precedence 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 | |||
| 4293 | named @code{file-name} (a certain coding system of which an alias is | 4289 | named @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 | ||
| 4296 | The @code{nnml} back end, the @code{nnrss} back end, the @acronym{NNTP} | 4292 | The @code{nnml} back end, the @code{nnrss} back end, the agent, and |
| 4297 | marks feature (@pxref{NNTP marks}), the agent, and the cache use | 4293 | the cache use non-@acronym{ASCII} group names in those files and |
| 4298 | non-@acronym{ASCII} group names in those files and directories. This | 4294 | directories. This variable overrides the value of |
| 4299 | variable overrides the value of @code{file-name-coding-system} which | 4295 | @code{file-name-coding-system} which specifies the coding system used |
| 4300 | specifies the coding system used when encoding and decoding those file | 4296 | when encoding and decoding those file names and directory names. |
| 4301 | names and directory names. | ||
| 4302 | 4297 | ||
| 4303 | In XEmacs (with the @code{mule} feature), @code{file-name-coding-system} | 4298 | In XEmacs (with the @code{mule} feature), @code{file-name-coding-system} |
| 4304 | is the only means to specify the coding system used to encode and decode | 4299 | is 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}). |
| 8987 | This is mostly useful if you're on a terminal that has a limited font | 8982 | This is mostly useful if you're on a terminal that has a limited font |
| 8988 | and doesn't show accented characters, ``advanced'' punctuation, and the | 8983 | and doesn't show accented characters, ``advanced'' punctuation, and the |
| 8989 | like. For instance, @samp{»} is translated into @samp{>>}, and so on. | 8984 | like. 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 | ||
| 10820 | Also @pxref{Group Parameters}. | 10815 | Also @pxref{Group Parameters}. |
| 10821 | 10816 | ||
| 10822 | @vindex gnus-propagate-marks | ||
| 10823 | @item gnus-propagate-marks | ||
| 10824 | If non-@code{nil}, propagate marks to the backends for possible | ||
| 10825 | storing. @xref{NNTP marks}, and friends, for a more fine-grained | ||
| 10826 | sieve. | ||
| 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 |
| 12405 | information. | 12394 | information. |
| 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 | ||
| 12413 | Does your @acronym{ISP} require the @acronym{POP}-before-@acronym{SMTP} | 12402 | Does your @acronym{ISP} use @acronym{POP}-before-@acronym{SMTP} |
| 12414 | authentication? It is whether you need to connect to the @acronym{POP} | 12403 | authentication? This authentication method simply requires you to |
| 12415 | mail server within a certain time before sending mails. If so, there is | 12404 | contact the @acronym{POP} server before sending email. To do that, |
| 12416 | a convenient way. To do that, put the following lines in your | 12405 | put 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 |
| 12425 | It means to let Gnus connect to the @acronym{POP} mail server in advance | 12412 | The @code{mail-source-touch-pop} function does @acronym{POP} |
| 12426 | whenever you send a mail. The @code{mail-source-touch-pop} function | 12413 | authentication according to the value of @code{mail-sources} without |
| 12427 | does only a @acronym{POP} authentication according to the value of | 12414 | fetching mails, just before sending a mail. @xref{Mail Sources}. |
| 12428 | @code{mail-sources} without fetching mails, just before sending a mail. | ||
| 12429 | Note 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 | ||
| 12431 | set the value of @code{mail-sources} for a @acronym{POP} connection | ||
| 12432 | correctly. @xref{Mail Sources}. | ||
| 12433 | 12415 | ||
| 12434 | If you have two or more @acronym{POP} mail servers set in | 12416 | If 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 | |||
| 12674 | non-@code{nil}, the behavior is the same as @code{all}, but it may be | 12657 | non-@code{nil}, the behavior is the same as @code{all}, but it may be |
| 12675 | changed in the future. | 12658 | changed in the future. |
| 12676 | 12659 | ||
| 12660 | @item gnus-gcc-self-resent-messages | ||
| 12661 | @vindex gnus-gcc-self-resent-messages | ||
| 12662 | Like the @code{gcc-self} group parameter, applied only for unmodified | ||
| 12663 | messages that @code{gnus-summary-resend-message} (@pxref{Summary Mail | ||
| 12664 | Commands}) resends. Non-@code{nil} value of this variable takes | ||
| 12665 | precedence over any existing @code{Gcc} header. | ||
| 12666 | |||
| 12667 | If 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 | ||
| 12669 | group. If this is a string, it specifies a group to which resent | ||
| 12670 | messages will be @code{Gcc} copied. If this is @code{nil}, @code{Gcc} | ||
| 12671 | will be done according to existing @code{Gcc} header(s), if any. If | ||
| 12672 | this 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, | ||
| 12674 | except 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 | |||
| 12681 | These hooks are run before/after encoding the message body of the Gcc | ||
| 12682 | copy of a sent message. The current buffer (when the hook is run) | ||
| 12683 | contains the message including the message header. Changes made to | ||
| 12684 | the message will only affect the Gcc copy, but not the original | ||
| 12685 | message. You can use these hooks to edit the copy (and influence | ||
| 12686 | subsequent 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. | |||
| 12819 | You may also use @code{message-alternative-emails} instead. | 12832 | You 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 | ||
| 12835 | Of particular interest in the ``work-mail'' style is the | ||
| 12836 | @samp{X-Message-SMTP-Method} header. It specifies how to send the | ||
| 12837 | outgoing 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 | |||
| 14022 | Gnus stores marks (@pxref{Marking Articles}) for @acronym{NNTP} | ||
| 14023 | servers in marks files. A marks file records what marks you have set | ||
| 14024 | in a group and each file is specific to the corresponding server. | ||
| 14025 | Marks files are stored in @file{~/News/marks} | ||
| 14026 | (@code{nntp-marks-directory}) under a classic hierarchy resembling | ||
| 14027 | that of a news server, for example marks for the group | ||
| 14028 | @samp{gmane.discuss} on the news.gmane.org server will be stored in | ||
| 14029 | the file @file{~/News/marks/news.gmane.org/gmane/discuss/.marks}. | ||
| 14030 | |||
| 14031 | Marks files are useful because you can copy the @file{~/News/marks} | ||
| 14032 | directory (using rsync, scp or whatever) to another Gnus installation, | ||
| 14033 | and it will realize what articles you have read and marked. The data | ||
| 14034 | in @file{~/News/marks} has priority over the same data in | ||
| 14035 | @file{~/.newsrc.eld}. | ||
| 14036 | |||
| 14037 | Note that marks files are very much server-specific: Gnus remembers | ||
| 14038 | the article numbers so if you don't use the same servers on both | ||
| 14039 | installations things are most likely to break (most @acronym{NNTP} | ||
| 14040 | servers do not use the same article numbers as any other server). | ||
| 14041 | However, if you use servers A, B, C on one installation and servers A, | ||
| 14042 | D, E on the other, you can sync the marks files for A and then you'll | ||
| 14043 | get synchronization for that server between the two installations. | ||
| 14044 | |||
| 14045 | Using @acronym{NNTP} marks can possibly incur a performance penalty so | ||
| 14046 | if Gnus feels sluggish, try setting the @code{nntp-marks-is-evil} | ||
| 14047 | variable to @code{t}. Marks will then be stored in @file{~/.newsrc.eld}. | ||
| 14048 | |||
| 14049 | Related variables: | ||
| 14050 | |||
| 14051 | @table @code | ||
| 14052 | |||
| 14053 | @item nntp-marks-is-evil | ||
| 14054 | @vindex nntp-marks-is-evil | ||
| 14055 | If non-@code{nil}, this back end will ignore any marks files. The | ||
| 14056 | default is @code{nil}. | ||
| 14057 | |||
| 14058 | @item nntp-marks-directory | ||
| 14059 | @vindex nntp-marks-directory | ||
| 14060 | The 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 |
| 16153 | fastest back end when it comes to reading mail. | 16125 | fastest back end when it comes to reading mail. |
| 16154 | 16126 | ||
| 16155 | @cindex self contained nnml servers | ||
| 16156 | @cindex marks | ||
| 16157 | When the marks file is used (which it is by default), @code{nnml} | ||
| 16158 | servers have the property that you may backup them using @code{tar} or | ||
| 16159 | similar, and later be able to restore them into Gnus (by adding the | ||
| 16160 | proper @code{nnml} server) and have all your marks be preserved. Marks | ||
| 16161 | for 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. | ||
| 16163 | Individual @code{nnml} groups are also possible to backup, use @kbd{G m} | ||
| 16164 | to restore the group (after restoring the backup into the nnml | ||
| 16165 | directory). | ||
| 16166 | |||
| 16167 | If for some reason you believe your @file{.marks} files are screwed | ||
| 16168 | up, you can just delete them all. Gnus will then correctly regenerate | ||
| 16169 | them next time it starts. | ||
| 16170 | |||
| 16171 | Virtual server settings: | 16127 | Virtual 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 |
| 16206 | Hook run narrowed to an article before saving. | 16162 | Hook run narrowed to an article before saving. |
| 16207 | 16163 | ||
| 16208 | @item nnml-marks-is-evil | ||
| 16209 | @vindex nnml-marks-is-evil | ||
| 16210 | If non-@code{nil}, this back end will ignore any @sc{marks} files. The | ||
| 16211 | default is @code{nil}. | ||
| 16212 | |||
| 16213 | @item nnml-marks-file-name | ||
| 16214 | @vindex nnml-marks-file-name | ||
| 16215 | The 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 |
| 16219 | If non-@code{nil}, @code{nnml} will allow using compressed message | 16166 | If 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 |
| 16555 | numbers and arrival dates. | 16502 | numbers and arrival dates. |
| 16556 | 16503 | ||
| 16557 | @cindex self contained nnfolder servers | ||
| 16558 | @cindex marks | ||
| 16559 | When the marks file is used (which it is by default), @code{nnfolder} | ||
| 16560 | servers have the property that you may backup them using @code{tar} or | ||
| 16561 | similar, and later be able to restore them into Gnus (by adding the | ||
| 16562 | proper @code{nnfolder} server) and have all your marks be preserved. | ||
| 16563 | Marks for a group are usually stored in a file named as the mbox file | ||
| 16564 | with @code{.mrk} concatenated to it (but see | ||
| 16565 | @code{nnfolder-marks-file-suffix}) within the @code{nnfolder} | ||
| 16566 | directory. Individual @code{nnfolder} groups are also possible to | ||
| 16567 | backup, use @kbd{G m} to restore the group (after restoring the backup | ||
| 16568 | into the @code{nnfolder} directory). | ||
| 16569 | |||
| 16570 | Virtual server settings: | 16504 | Virtual 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}. | |||
| 16625 | The directory where the @acronym{NOV} files should be stored. If | 16559 | The 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 | ||
| 16630 | If non-@code{nil}, this back end will ignore any @sc{marks} files. The | ||
| 16631 | default is @code{nil}. | ||
| 16632 | |||
| 16633 | @item nnfolder-marks-file-suffix | ||
| 16634 | @vindex nnfolder-marks-file-suffix | ||
| 16635 | The extension for @sc{marks} files. The default is @file{.mrk}. | ||
| 16636 | |||
| 16637 | @item nnfolder-marks-directory | ||
| 16638 | @vindex nnfolder-marks-directory | ||
| 16639 | The 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 |
| 16800 | corresponding maildir, in a way designed so that it's easy to manipulate | 16720 | corresponding maildir, in a way designed so that it's easy to manipulate |
| 16801 | them from outside Gnus. You can tar up a maildir, unpack it somewhere | 16721 | them from outside Gnus. You can tar up a maildir, unpack it somewhere |
| 16802 | else, and still have your marks. @code{nnml} also stores marks, but | 16722 | else, and still have your marks. |
| 16803 | it'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 | |||
| 16893 | might interfere with overwriting data, so you may want to shut down Gnus | 16811 | might interfere with overwriting data, so you may want to shut down Gnus |
| 16894 | before you restore the data. | 16812 | before you restore the data. |
| 16895 | 16813 | ||
| 16896 | It is also possible to archive individual @code{nnml}, | ||
| 16897 | @code{nnfolder}, or @code{nnmaildir} groups, while preserving marks. | ||
| 16898 | For @code{nnml} or @code{nnmaildir}, you copy all files in the group's | ||
| 16899 | directory. For @code{nnfolder} you need to copy both the base folder | ||
| 16900 | file itself (@file{FOO}, say), and the marks file (@file{FOO.mrk} in | ||
| 16901 | this example). Restoring the group is done with @kbd{G m} from the Group | ||
| 16902 | buffer. The last step makes Gnus notice the new directory. | ||
| 16903 | @code{nnmaildir} notices the new directory automatically, so @kbd{G m} | ||
| 16904 | is 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 ¬ |
| 20879 | This logical operator only takes a single argument. It returns the | 20787 | This logical operator only takes a single argument. It returns the |
| 20880 | logical negation of the value of its argument. | 20788 | logical 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.) | |||
| 22465 | Ignoring is done first; then cutting; then maxing; and then as the very | 22372 | Ignoring is done first; then cutting; then maxing; and then as the very |
| 22466 | last operation, padding. | 22373 | last operation, padding. |
| 22467 | 22374 | ||
| 22468 | If you use lots of these advanced thingies, you'll find that Gnus gets | ||
| 22469 | quite slow. This can be helped enormously by running @kbd{M-x | ||
| 22470 | gnus-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 |
| 22520 | Text inside the @samp{%<<} and @samp{%>>} specifiers will get the | 22422 | Text inside the @samp{%<<} and @samp{%>>} specifiers will get the |
| 22521 | special @code{balloon-help} property set to | 22423 | special @code{balloon-help} property set to |
| @@ -22978,30 +22880,6 @@ the face you want to alter, and alter it via the standard Customize | |||
| 22978 | interface. | 22880 | interface. |
| 22979 | 22881 | ||
| 22980 | 22882 | ||
| 22981 | @node Compilation | ||
| 22982 | @section Compilation | ||
| 22983 | @cindex compilation | ||
| 22984 | @cindex byte-compilation | ||
| 22985 | |||
| 22986 | @findex gnus-compile | ||
| 22987 | |||
| 22988 | Remember all those line format specification variables? | ||
| 22989 | @code{gnus-summary-line-format}, @code{gnus-group-line-format}, and so | ||
| 22990 | on. Now, Gnus will of course heed whatever these variables are, but, | ||
| 22991 | unfortunately, changing them will mean a quite significant slow-down. | ||
| 22992 | (The default values of these variables have byte-compiled functions | ||
| 22993 | associated with them, while the user-generated versions do not, of | ||
| 22994 | course.) | ||
| 22995 | |||
| 22996 | To help with this, you can run @kbd{M-x gnus-compile} after you've | ||
| 22997 | fiddled around with the variables and feel that you're (kind of) | ||
| 22998 | satisfied. This will result in the new specs being byte-compiled, and | ||
| 22999 | you'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 | ||
| 23001 | this function, though---you should compile them yourself by sticking | ||
| 23002 | them 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. | |||
| 23656 | If @code{inline}, the textual representation is replaced. If | 23534 | If @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 | ||
| 23538 | The value of the variable @code{gnus-picon-properties} is a list of | ||
| 23539 | properties applied to picons. | ||
| 23540 | |||
| 23659 | The following variables offer control over where things are located. | 23541 | The 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 | ||
| 26414 | The first ``proper'' release of Gnus 5 was done in November 1995 when it | 26297 | The 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 | |||
| 26437 | http://git.gnus.org for details (http://www.gnus.org will be updated | 26320 | http://git.gnus.org for details (http://www.gnus.org will be updated |
| 26438 | with the information when possible). | 26321 | with the information when possible). |
| 26439 | 26322 | ||
| 26323 | On the January 31th 2012, Ma Gnus was begun. | ||
| 26324 | |||
| 26440 | If you happen upon a version of Gnus that has a prefixed name -- | 26325 | If 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 |
| 26443 | Don't let it know that you're frightened. Back away. Slowly. Whatever | 26328 | panic. Don't let it know that you're frightened. Back away. Slowly. |
| 26444 | you do, don't run. Walk away, calmly, until you're out of its reach. | 26329 | Whatever you do, don't run. Walk away, calmly, until you're out of |
| 26445 | Find a proper released version of Gnus and snuggle up to that instead. | 26330 | its reach. Find a proper released version of Gnus and snuggle up to |
| 26331 | that 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 | ||
| 27051 | These lists are, of course, just @emph{short} overviews of the | 26938 | These 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 | |||
| 28314 | I'm sure there will be lots of text here. It's really spelled 真 | ||
| 28315 | Gnus. | ||
| 28316 | |||
| 28317 | New 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 | ||
| 28327 | The new hooks @code{gnus-gcc-pre-body-encode-hook} and | ||
| 28328 | @code{gnus-gcc-post-body-encode-hook} are run before/after encoding | ||
| 28329 | the 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 | |||
| 1637 | requires the @acronym{POP}-before-@acronym{SMTP} authentication. | 1637 | requires 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 | ||
| 1641 | If you have a complex @acronym{SMTP} setup, and want some messages to | ||
| 1642 | go via one mail server, and other messages to go through another, you | ||
| 1643 | can use the @samp{X-Message-SMTP-Method} header. These are the | ||
| 1644 | supported values: | ||
| 1645 | |||
| 1646 | @table @samp | ||
| 1647 | @item smtpmail | ||
| 1648 | |||
| 1649 | @example | ||
| 1650 | X-Message-SMTP-Method: smtp smtp.fsf.org 587 | ||
| 1651 | @end example | ||
| 1652 | |||
| 1653 | This will send the message via @samp{smtp.fsf.org}, using port 587. | ||
| 1654 | |||
| 1655 | @example | ||
| 1656 | X-Message-SMTP-Method: smtp smtp.fsf.org 587 other-user | ||
| 1657 | @end example | ||
| 1658 | |||
| 1659 | This is the same as the above, but uses @samp{other-user} as the user | ||
| 1660 | name when authenticating. This is handy if you have several | ||
| 1661 | @acronym{SMTP} accounts on the same server. | ||
| 1662 | |||
| 1663 | @item sendmail | ||
| 1664 | |||
| 1665 | @example | ||
| 1666 | X-Message-SMTP-Method: sendmail | ||
| 1667 | @end example | ||
| 1668 | |||
| 1669 | This will send the message via the locally installed sendmail/exim/etc | ||
| 1670 | installation. | ||
| 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 |
| 1642 | Most versions of MH doesn't like being fed messages that contain the | 1676 | Most 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. | |||
| 7 | For older news, see Gnus info node "New Features". | 7 | For 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 | ||
| 14 | If you have tried No Gnus (the unstable Gnus branch leading to this | 15 | ** Archives (like tar and zip files) will be automatically unpacked, |
| 15 | release) 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. |
| 16 | this version. In particular, you will probably want to remove the | ||
| 17 | `~/News/marks' directory (perhaps selectively), so that flags are read | ||
| 18 | from your `~/.newsrc.eld' instead of from the stale marks file, where | ||
| 19 | this release will store flags for nntp. See a later entry for more | ||
| 20 | information about nntp marks. Note that downgrading isn't safe in | ||
| 21 | general. | ||
| 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. |
| 24 | Gnus uses Emacs' new internal coding system `utf-8-emacs' for saving | ||
| 25 | articles drafts and `~/.newsrc.eld'. These files may not be read | ||
| 26 | correctly in Emacs 22 and below. If you want to use Gnus across | ||
| 27 | different 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 |
| 31 | defaulted to `.../site-lisp/' formerly. In addition to this, the new | 21 | the article buffer. |
| 32 | installer issues a warning if other Gnus installations which will shadow | ||
| 33 | the latest one are detected. You can then remove those shadows manually | ||
| 34 | or 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 | |||
| 43 | This provides a clean API to SASL mechanisms from within Emacs. The | ||
| 44 | user visible aspects of this, compared to the earlier situation, include | ||
| 45 | support for DIGEST-MD5 and NTLM. *Note Emacs SASL: (sasl)Top. | ||
| 46 | |||
| 47 | ** ManageSieve connections uses the SASL library by default. | ||
| 48 | |||
| 49 | The primary change this brings is support for DIGEST-MD5 and NTLM, when | ||
| 50 | the server supports it. | ||
| 51 | |||
| 52 | ** Gnus includes a password cache mechanism in password-cache.el. | ||
| 53 | |||
| 54 | It is enabled by default (see `password-cache'), with a short timeout of | ||
| 55 | 16 seconds (see `password-cache-expiry'). If PGG is used as the PGP | ||
| 56 | back end, the PGP passphrase is managed by this mechanism. Passwords | ||
| 57 | for ManageSieve connections are managed by this mechanism, after | ||
| 58 | querying the user about whether to do so. | ||
| 59 | |||
| 60 | ** Using EasyPG with Gnus When EasyPG, is available, Gnus will use it | ||
| 61 | instead 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 | ||
| 63 | Emacs 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 | ||
| 69 | couple 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 | ||
| 77 | that are not reused when you select another article. *Note Sticky | ||
| 78 | Articles::. | ||
| 79 | |||
| 80 | ** Gnus can selectively display `text/html' articles with a WWW browser | ||
| 81 | with `K H'. *Note MIME Commands::. | ||
| 82 | |||
| 83 | ** International host names (IDNA) can now be decoded inside article bodies | ||
| 84 | using `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 | ||
| 88 | ends that fully support non-ASCII group names are now `nntp', `nnml', | ||
| 89 | and `nnrss'. Also the agent, the cache, and the marks features work | ||
| 90 | with 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 | ||
| 100 | Commands::. | ||
| 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 | ||
| 106 | configure the server in `smime-ldap-host-list'. | ||
| 107 | |||
| 108 | ** URLs inside OpenPGP headers are retrieved and imported to your PGP key | ||
| 109 | ring 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 | |||
| 116 | ANSI sequences are used in some Chinese hierarchies for highlighting | ||
| 117 | articles (`gnus-article-treat-ansi-sequences'). | ||
| 118 | |||
| 119 | ** Gnus now MIME decodes articles even when they lack "MIME-Version" header. | ||
| 120 | This changes the default of `gnus-article-loose-mime'. | ||
| 121 | |||
| 122 | ** `gnus-decay-scores' can be a regexp matching score files. For example, | ||
| 123 | set 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 | ||
| 127 | when using `gnus-ignored-from-addresses' can be customized with | ||
| 128 | `gnus-summary-to-prefix' and `gnus-summary-newsgroup-prefix'. *Note To | ||
| 129 | From Newsgroups::. | ||
| 130 | |||
| 131 | ** You can replace MIME parts with external bodies. See | ||
| 132 | `gnus-mime-replace-part' and `gnus-article-replace-part'. *Note MIME | ||
| 133 | Commands::, *note Using MIME::. | ||
| 134 | |||
| 135 | ** The option `mm-fill-flowed' can be used to disable treatment of | ||
| 136 | format=flowed messages. Also, flowed text is disabled when sending | ||
| 137 | inline 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 | ||
| 141 | a wide reply in the article buffer yanks a text that is in the active | ||
| 142 | region, if it is set, as well as the `R' | ||
| 143 | (`gnus-article-reply-with-original') command. Note that the `R' command | ||
| 144 | in the article buffer no longer accepts a prefix argument, which was | ||
| 145 | used 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 | ||
| 148 | article buffer now shows not only the article commands but also the real | ||
| 149 | summary 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 | ||
| 163 | prefixed in cited text. *Note Insertion Variables: (message)Insertion | ||
| 164 | Variables. | ||
| 165 | |||
| 166 | ** Gnus uses narrowing to hide headers in Message buffers. The | ||
| 167 | `References' header is hidden by default. To make all headers visible, | ||
| 168 | use `(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 | ||
| 172 | buffer. 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 | ||
| 176 | Variables. | ||
| 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 | |||
| 191 | The directory can be changed using the (customizable) variable | ||
| 192 | `nntp-marks-directory', and marks can be disabled using the (back end) | ||
| 193 | variable `nntp-marks-is-evil'. The advantage of this is that you can | ||
| 194 | copy `~/News/marks' (using rsync, scp or whatever) to another Gnus | ||
| 195 | installation, and it will realize what articles you have read and | ||
| 196 | marked. 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 | ||
| 200 | RSS::. | ||
| 201 | |||
| 202 | ** IMAP identity (RFC 2971) is supported. | ||
| 203 | |||
| 204 | By default, Gnus does not send any information about itself, but you can | ||
| 205 | customize it using the variable `nnimap-id'. | ||
| 206 | |||
| 207 | ** The `nnrss' back end now supports multilingual text. Non-ASCII group | ||
| 208 | names 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 | ||
| 213 | compressed message files. *Note Mail Spool::. | ||
| 214 | |||
| 215 | ** The nnml back end supports group compaction. | ||
| 216 | |||
| 217 | This feature, accessible via the functions `gnus-group-compact-group' | ||
| 218 | (`G z' in the group buffer) and `gnus-server-compact-server' (`z' in the | ||
| 219 | server buffer) renumbers all articles in a group, starting from 1 and | ||
| 220 | removing 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 | ||
| 228 | customize the tool bars: `M-x customize-apropos RET -tool-bar$' should | ||
| 229 | get you started. (Only for Emacs, not in XEmacs.) | ||
| 230 | |||
| 231 | ** The tool bar icons are now (de)activated correctly in the group buffer, | ||
| 232 | see the variable `gnus-group-update-tool-bar'. Its default value | ||
| 233 | depends 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 | ||
| 243 | buffer is immediately reflected to the subscription of the groups which | ||
| 244 | use the server in question. For instance, if you change | ||
| 245 | `nntp-via-address' into `bar.example.com' from `foo.example.com', Gnus | ||
| 246 | will 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 | ||
| 252 | non-`nil' value so that articles that have been read may be marked as | ||
| 253 | expirable automatically when copying or moving them to a group that has | ||
| 254 | auto-expire turned on. The default is `nil' and copying and moving of | ||
| 255 | articles behave as before; i.e., the expirable marks will be unchanged | ||
| 256 | except that the marks will be removed when copying or moving articles to | ||
| 257 | a 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 @@ | |||
| 1 | 2012-06-26 Katsumi Yamaoka <yamaoka@jpl.org> | ||
| 2 | |||
| 3 | * mm-decode.el: Add coding cookie for a soft hyphen that mm-shr uses. | ||
| 4 | |||
| 5 | 2012-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 | |||
| 10 | 2012-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 | |||
| 15 | 2012-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 | |||
| 38 | 2012-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 | |||
| 43 | 2012-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 | |||
| 48 | 2012-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 | |||
| 57 | 2012-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 | |||
| 68 | 2012-06-26 Katsumi Yamaoka <yamaoka@jpl.org> | ||
| 69 | |||
| 70 | * pop3.el (pop3-wait-for-messages): Fix retrieved data size calculation. | ||
| 71 | |||
| 72 | 2012-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 | |||
| 86 | 2012-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 | |||
| 94 | 2012-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 | |||
| 99 | 2012-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 | |||
| 105 | 2012-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 | |||
| 110 | 2012-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 | |||
| 129 | 2012-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 | |||
| 138 | 2012-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 | |||
| 148 | 2012-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 | |||
| 157 | 2012-06-26 Lars Magne Ingebrigtsen <larsi@gnus.org> | ||
| 158 | |||
| 159 | * nnimap.el (nnimap-fetch-partial-articles): Minor doc string fixup. | ||
| 160 | |||
| 161 | 2012-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 | |||
| 168 | 2012-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 | |||
| 178 | 2012-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 | |||
| 183 | 2012-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 | |||
| 190 | 2012-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 | |||
| 196 | 2012-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 | |||
| 209 | 2012-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 | |||
| 215 | 2012-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 | |||
| 242 | 2012-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 | |||
| 247 | 2012-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 | |||
| 256 | 2012-06-26 Lars Ingebrigtsen <larsi@gnus.org> | ||
| 257 | |||
| 258 | * message.el (smtpmail-smtp-user): Silence compiler warning. | ||
| 259 | |||
| 260 | 2012-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 | |||
| 265 | 2012-06-26 Katsumi Yamaoka <yamaoka@jpl.org> | ||
| 266 | |||
| 267 | * gnus-sum.el (gnus-summary-article-map): Fix typo. | ||
| 268 | |||
| 269 | 2012-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 | |||
| 285 | 2012-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 | |||
| 296 | 2012-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 | |||
| 327 | 2012-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 | |||
| 342 | 2012-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 | |||
| 348 | 2012-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 | |||
| 356 | 2012-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 | |||
| 363 | 2012-06-26 Teodor Zlatanov <tzz@lifelogs.com> | ||
| 364 | |||
| 365 | * gnus-sync.el: More commentary about setup. | ||
| 366 | |||
| 367 | 2012-06-26 Teodor Zlatanov <tzz@lifelogs.com> | ||
| 368 | |||
| 369 | * gnus-sync.el: More commentary about `gnus-sync-read' issues. | ||
| 370 | |||
| 371 | 2012-06-26 Teodor Zlatanov <tzz@lifelogs.com> | ||
| 372 | |||
| 373 | * gnus-sync.el: Improve docs about CouchDB admins. | ||
| 374 | |||
| 375 | 2012-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 | |||
| 381 | 2012-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 | |||
| 391 | 2012-06-26 David Engster <dengste@eml.cc> | ||
| 392 | |||
| 393 | * tests/gnustest-nntp.el: New file for simple NNTP testing. | ||
| 394 | |||
| 1 | 2012-06-18 Nelson Ferreira <nelson.ferreira@ieee.org> (tiny change) | 395 | 2012-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 | |||
| 683 | minor mode in all Gnus buffers." | 682 | minor 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. | ||
| 1304 | Pass non-nil for GROUPS-P if the buffer starts out in groups format. | ||
| 1305 | Regardless, both the file and the buffer end up in active format | ||
| 1306 | if 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. |
| 103 | If not, and a TIME is given, restart a new idle timer, so FUNC | ||
| 104 | can be called at the next opportunity. Such a special idle run is | ||
| 105 | marked 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. |
| 4019 | If ARG is a number, it specifies which levels you are interested in | 4026 | If ARG is a number, it specifies which levels you are interested in |
| 4020 | re-scanning. If ARG is non-nil and not a number, this will force | 4027 | re-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. |
| 4029 | If ONE-LEVEL is not nil, then re-scan only the specified level, | ||
| 4030 | otherwise 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. | ||
| 538 | Returns the article number of the message. | ||
| 539 | |||
| 540 | If GROUP is not already selected, the message will be the only one in | ||
| 541 | the 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. | ||
| 581 | This 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 |
| 538 | real group. Does nothing on a real group." | 588 | real 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. | ||
| 168 | Applied to messages sent by `gnus-summary-resend-message'. Non-nil | ||
| 169 | value of this variable takes precedence over any existing Gcc header. | ||
| 170 | |||
| 171 | If this is `none', no Gcc copy will be made. If this is t, messages | ||
| 172 | resent will be Gcc'd to the current group. If this is a string, it | ||
| 173 | specifies a group to which resent messages will be Gcc'd. If this is | ||
| 174 | nil, Gcc will be done according to existing Gcc header(s), if any. | ||
| 175 | If this is `no-gcc-self', resent messages will be Gcc'd to groups that | ||
| 176 | existing 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. | ||
| 318 | The current buffer (when the hook is run) contains the message | ||
| 319 | including the message header. Changes made to the message will | ||
| 320 | only 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. | ||
| 326 | The current buffer (when the hook is run) contains the message | ||
| 327 | including the message header. Changes made to the message will | ||
| 328 | only 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. |
| 80 | If `inline', the textual representation is replaced. If `right', picons are | 86 | If `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. | ||
| 1133 | This will be done via the current article's source group based on | ||
| 1134 | data 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. |
| 456 | In particular, if `vertical' do only vertical recentering. If non-nil | 457 | In particular, if `vertical' do only vertical recentering. If non-nil |
| 457 | and non-`vertical', do both horizontal and vertical recentering." | 458 | and 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. | ||
| 1248 | This means that marks will be stored both in .newsrc.eld and in | ||
| 1249 | the 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. |
| 7362 | The state which existed when entering the ephemeral is reset." | 7355 | The 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. | ||
| 9274 | With 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. |
| 9275 | If REGEXP-P (the prefix) is non-nil, do regexp isearch." | 9285 | If 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. |
| 66 | The group names are matched, they don't have to be fully | 116 | The group names are matched, they don't have to be fully |
| 67 | qualified. Typically you would choose all of these. That's the | 117 | qualified. 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. |
| 81 | You may want to sync `gnus-newsrc-last-checked-date' but pretty | 125 | You may want to sync `gnus-newsrc-last-checked-date' but pretty |
| 82 | much any symbol is fair game. You could additionally sync | 126 | much 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', |
| 84 | and `gnus-topic-alist' to cover all the variables in | 128 | and `gnus-topic-alist'. Also see `gnus-variable-list'." |
| 85 | newsrc.eld (except for `gnus-format-specs' which should not be | ||
| 86 | synchronized, 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. | ||
| 180 | KVDATA 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. | ||
| 231 | Install USER as a READER and/or an ADMIN in the security object | ||
| 232 | under \"_security\", and in the CouchDB \"_users\" table using | ||
| 233 | PASSWORD and SALT. Only one USER is thus supported for now. | ||
| 234 | When 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. | ||
| 367 | Calls `gnus-sync-lesync-set-prop'. | ||
| 368 | For 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. | ||
| 375 | Updates `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. | ||
| 551 | Skips 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 | ||
| 554 | subscribe to unknown groups. The user is also allowed to delete | ||
| 555 | unwanted 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. | ||
| 706 | With 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) | 809 | With 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. |
| 183 | Given an RFC-822 address FROM, extract full name and canonical address. | 174 | Given 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)." | |||
| 3157 | If there is no signature in the article, go to the end and | 3171 | If there is no signature in the article, go to the end and |
| 3158 | return nil." | 3172 | return 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'. | ||
| 4668 | Or, if there's a header that specifies a different method, use | ||
| 4669 | that 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. |
| 582 | If NO-STRICT-MIME, don't require the message to have a | ||
| 583 | MIME-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. |
| 468 | MULTIPART-TYPE defaults to \"mixed\", but can also | ||
| 469 | be \"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. |
| 54 | If nil, `nnfolder-directory' is used.") | 54 | If nil, `nnfolder-directory' is used.") |
| 55 | 55 | ||
| 56 | (defvoo nnfolder-marks-directory nil | ||
| 57 | "The name of the nnfolder MARKS directory. | ||
| 58 | If 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. | ||
| 139 | Using marks files makes it possible to backup and restore mail groups | ||
| 140 | separately from `.newsrc.eld'. If you have, for some reason, set | ||
| 141 | this to t, and want to set it to nil again, you should always remove | ||
| 142 | the corresponding marks file (usually base nnfolder file name | ||
| 143 | concatenated with `.mrk', but see `nnfolder-marks-file-suffix') for | ||
| 144 | the 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. |
| 120 | If t, nnimap will fetch only the first part. If a string, it | 120 | If t, Gnus will fetch only the first part. If a string, it |
| 121 | will fetch all parts that have types that match that string. A | 121 | will fetch all parts that have types that match that string. A |
| 122 | likely value would be \"text/\" to automatically fetch all | 122 | likely value would be \"text/\" to automatically fetch all |
| 123 | textual parts.") | 123 | textual 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. |
| 558 | In addition to the standard headers, these extra headers will be | 560 | In addition to the standard headers, these extra headers will be |
| 559 | included in NOV headers (and the like) when backends parse headers." | 561 | included 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 | |||
| 67 | through all nnml directories and generate nov databases for them | 67 | through all nnml directories and generate nov databases for them |
| 68 | all. This may very well take some time.") | 68 | all. 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. | ||
| 72 | Using marks files makes it possible to backup and restore mail groups | ||
| 73 | separately from `.newsrc.eld'. If you have, for some reason, set this | ||
| 74 | to t, and want to set it to nil again, you should always remove the | ||
| 75 | corresponding marks file (usually named `.marks' in the nnml group | ||
| 76 | directory, but see `nnml-marks-file-name') for the group. Then the | ||
| 77 | marks 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 | |||
| 222 | server there that you can connect to. See also | 222 | server 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. | ||
| 234 | See `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. | ||
| 241 | The size will be rotated between the default size, the original | ||
| 242 | size, 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. | ||
| 616 | If 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 |