X-Git-Url: https://cgit.sxemacs.org/?a=blobdiff_plain;f=lisp%2Fgnus-start.el;h=52a53a7be35638550a4579a8d52aa9a10bf99bd6;hb=HEAD;hp=b8a6be8702e92d7972dc3056db7375b40499cd0e;hpb=26be1f2820f24c95bc97369e86c6f0bd9b389cea;p=gnus diff --git a/lisp/gnus-start.el b/lisp/gnus-start.el index b8a6be870..52a53a7be 100644 --- a/lisp/gnus-start.el +++ b/lisp/gnus-start.el @@ -1,6 +1,6 @@ ;;; gnus-start.el --- startup functions for Gnus -;; Copyright (C) 1996-2011 Free Software Foundation, Inc. +;; Copyright (C) 1996-2016 Free Software Foundation, Inc. ;; Author: Lars Magne Ingebrigtsen ;; Keywords: news @@ -30,6 +30,7 @@ (require 'gnus-spec) (require 'gnus-range) (require 'gnus-util) +(ignore-errors (require 'gnus-cloud)) (autoload 'message-make-date "message") (autoload 'gnus-agent-read-servers-validate "gnus-agent") (autoload 'gnus-agent-save-local "gnus-agent") @@ -110,7 +111,7 @@ ask the servers (primary, secondary, and archive servers) to list new groups since the last time it checked: 1. This variable is `ask-server'. 2. This variable is a list of select methods (see below). - 3. `gnus-read-active-file' is nil or `some'. + 3. Option `gnus-read-active-file' is nil or `some'. 4. A prefix argument is given to `gnus-find-new-newsgroups' interactively. Thus, if this variable is `ask-server' or a list of select methods or @@ -121,9 +122,9 @@ This variable can be a list of select methods which Gnus will query with the `ask-server' method in addition to the primary, secondary, and archive servers. -Eg. +E.g.: (setq gnus-check-new-newsgroups - '((nntp \"some.server\") (nntp \"other.server\"))) + \\='((nntp \"some.server\") (nntp \"other.server\"))) If this variable is nil, then you have to tell Gnus explicitly to check for new newsgroups with \\\\[gnus-find-new-newsgroups]." @@ -291,7 +292,9 @@ claim them." function (repeat function))) -(defcustom gnus-subscribe-newsgroup-hooks nil +(define-obsolete-variable-alias 'gnus-subscribe-newsgroup-hooks + 'gnus-subscribe-newsgroup-functions "24.3") +(defcustom gnus-subscribe-newsgroup-functions nil "*Hooks run after you subscribe to a new group. The hooks will be called with new group's name as argument." :version "22.1" @@ -380,13 +383,6 @@ disc." :group 'gnus-newsrc :type 'boolean) -(defcustom gnus-use-backend-marks nil - "If non-nil, Gnus will store and retrieve marks from the backends. -This means that marks will be stored both in .newsrc.eld and in -the backend, and will slow operation down somewhat." - :group 'gnus-newsrc - :type 'boolean) - (defcustom gnus-check-bogus-groups-hook nil "A hook run after removing bogus groups." :group 'gnus-start-server @@ -400,7 +396,16 @@ This hook is called after Gnus is connected to the NNTP server." (defcustom gnus-before-startup-hook nil "A hook called before startup. -This hook is called as the first thing when Gnus is started." +This hook is called as the first thing when Gnus is started. +See also `gnus-before-resume-hook'." + :group 'gnus-start + :type 'hook) + +(defcustom gnus-before-resume-hook nil + "A hook called before resuming Gnus after suspend. +This hook is called as the first thing when Gnus is resumed after a suspend. +See also `gnus-before-startup-hook'." + :version "24.4" :group 'gnus-start :type 'hook) @@ -646,7 +651,7 @@ the first newsgroup." gnus-level-killed (gnus-group-entry (or next "dummy.group"))) (gnus-request-update-group-status newsgroup 'subscribe) (gnus-message 5 "Subscribe newsgroup: %s" newsgroup) - (run-hook-with-args 'gnus-subscribe-newsgroup-hooks newsgroup) + (run-hook-with-args 'gnus-subscribe-newsgroup-functions newsgroup) t)) (defun gnus-read-active-file-p () @@ -754,6 +759,7 @@ prompt the user for the name of an NNTP server to use." (if (gnus-alive-p) (progn + (gnus-run-hooks 'gnus-before-resume-hook) (switch-to-buffer gnus-group-buffer) (gnus-group-get-new-news (and (numberp arg) @@ -770,8 +776,8 @@ prompt the user for the name of an NNTP server to use." ;; Add "native" to gnus-predefined-server-alist just to have a ;; name for the native select method. (when gnus-select-method - (push (cons "native" gnus-select-method) - gnus-predefined-server-alist)) + (add-to-list 'gnus-predefined-server-alist + (cons "native" gnus-select-method))) (if gnus-agent (gnus-agentize)) @@ -839,13 +845,22 @@ prompt the user for the name of an NNTP server to use." gnus-current-startup-file) "-dribble")) -(defun gnus-dribble-enter (string) - "Enter STRING into the dribble buffer." +(defun gnus-dribble-enter (string &optional regexp) + "Enter STRING into the dribble buffer. +If REGEXP is given, lines that match it will be deleted." (when (and (not gnus-dribble-ignore) gnus-dribble-buffer (buffer-name gnus-dribble-buffer)) (let ((obuf (current-buffer))) (set-buffer gnus-dribble-buffer) + (when regexp + (goto-char (point-min)) + (let (end) + (while (re-search-forward regexp nil t) + (unless (bolp) (forward-line 1)) + (setq end (point)) + (goto-char (match-beginning 0)) + (delete-region (point-at-bol) end)))) (goto-char (point-max)) (insert string "\n") ;; This has been commented by Josh Huber @@ -871,8 +886,14 @@ prompt the user for the name of an NNTP server to use." (gnus-get-buffer-create (file-name-nondirectory dribble-file))) (set (make-local-variable 'file-precious-flag) t) + (setq buffer-save-without-query t) (erase-buffer) (setq buffer-file-name dribble-file) + ;; The buffer may be shrunk a lot when deleting old entries. + ;; It caused the auto-saving to stop. + (if (featurep 'emacs) + (set (make-local-variable 'auto-save-include-big-deletions) t) + (set (make-local-variable 'disable-auto-save-when-buffer-shrinks) nil)) (auto-save-mode t) (buffer-disable-undo) (bury-buffer (current-buffer)) @@ -929,7 +950,8 @@ prompt the user for the name of an NNTP server to use." (when (and gnus-dribble-buffer (buffer-name gnus-dribble-buffer)) (with-current-buffer gnus-dribble-buffer - (save-buffer)))) + (when (> (buffer-size) 0) + (save-buffer))))) (defun gnus-dribble-clear () (when (gnus-buffer-exists-p gnus-dribble-buffer) @@ -1040,7 +1062,7 @@ If LEVEL is non-nil, the news will be set up at level LEVEL." ;; Find the number of unread articles in each non-dead group. (let ((gnus-read-active-file (and (not level) gnus-read-active-file))) - (gnus-get-unread-articles level)))) + (gnus-get-unread-articles level dont-connect)))) (defun gnus-call-subscribe-functions (method group) "Call METHOD to subscribe GROUP. @@ -1312,16 +1334,13 @@ for new groups, and subscribe the new groups as zombies." ((>= level gnus-level-zombie) ;; Remove from the hash table. (gnus-sethash group nil gnus-newsrc-hashtb) - ;; We do not enter foreign groups into the list of dead - ;; groups. - (unless (gnus-group-foreign-p group) - (if (= level gnus-level-zombie) - (push group gnus-zombie-list) - (if (= oldlevel gnus-level-killed) - ;; Remove from active hashtb. - (unintern group gnus-active-hashtb) - ;; Don't add it into killed-list if it was killed. - (push group gnus-killed-list))))) + (if (= level gnus-level-zombie) + (push group gnus-zombie-list) + (if (= oldlevel gnus-level-killed) + ;; Remove from active hashtb. + (unintern group gnus-active-hashtb) + ;; Don't add it into killed-list if it was killed. + (push group gnus-killed-list)))) (t ;; If the list is to be entered into the newsrc assoc, and ;; it was killed, we have to create an entry in the newsrc @@ -1363,17 +1382,12 @@ for new groups, and subscribe the new groups as zombies." (when (cdr entry) (setcdr (gnus-group-entry (caadr entry)) entry)) (gnus-dribble-enter - (format - "(gnus-group-set-info '%S)" info))))) + (format "(gnus-group-set-info '%S)" info) + (concat "^(gnus-group-set-info '(\"" (regexp-quote group) "\""))))) (when gnus-group-change-level-function (funcall gnus-group-change-level-function group level oldlevel previous))))) -(defun gnus-kill-newsgroup (newsgroup) - "Obsolete function. Kills a newsgroup." - (gnus-group-change-level - (gnus-group-entry newsgroup) gnus-level-killed)) - (defun gnus-check-bogus-newsgroups (&optional confirm) "Remove bogus newsgroups. If CONFIRM is non-nil, the user has to confirm the deletion of every @@ -1451,7 +1465,11 @@ newsgroup." (defun gnus-activate-group (group &optional scan dont-check method dont-sub-check) "Check whether a group has been activated or not. -If SCAN, request a scan of that group as well." +If SCAN, request a scan of that group as well. If METHOD, use +that select method instead of determining the method based on the +group name. If DONT-CHECK, don't check whether the group +actually exists. If DONT-SUB-CHECK or DONT-CHECK, don't let the +backend check whether the group actually exists." (let ((method (or method (inline (gnus-find-method-for-group group)))) active) (and (inline (gnus-check-server method)) @@ -1471,9 +1489,10 @@ If SCAN, request a scan of that group as well." (inline (gnus-request-group group (or dont-sub-check dont-check) method (gnus-get-info group))) - ;;(error nil) (quit - (message "Quit activating %s" group) + (if debug-on-quit + (debug "Quit") + (message "Quit activating %s" group)) nil))) (unless dont-check (setq active (gnus-parse-active)) @@ -1508,18 +1527,11 @@ If SCAN, request a scan of that group as well." (gnus-info-group info))))) (gnus-activate-group (gnus-info-group info) nil t)) - ;; Allow backends to update marks, - (when gnus-use-backend-marks - (let ((method (inline (gnus-find-method-for-group - (gnus-info-group info))))) - (when (gnus-check-backend-function 'request-marks (car method)) - (gnus-request-marks info method)))) - (let* ((range (gnus-info-read info)) (num 0)) ;; These checks are present in gnus-activate-group but skipped - ;; due to setting dont-check in the preceeding call. + ;; due to setting dont-check in the preceding call. ;; If a cache is present, we may have to alter the active info. (when (and gnus-use-cache info) @@ -1603,7 +1615,7 @@ If SCAN, request a scan of that group as well." ;; Go though `gnus-newsrc-alist' and compare with `gnus-active-hashtb' ;; and compute how many unread articles there are in each group. -(defun gnus-get-unread-articles (&optional level) +(defun gnus-get-unread-articles (&optional level dont-connect one-level) (setq gnus-server-method-cache nil) (require 'gnus-agent) (let* ((newsrc (cdr gnus-newsrc-alist)) @@ -1660,7 +1672,7 @@ If SCAN, request a scan of that group as well." (push (setq method-group-list (list method method-type nil nil)) type-cache)) ;; Only add groups that need updating. - (if (<= (gnus-info-level info) + (if (funcall (if one-level #'= #'<=) (gnus-info-level info) (if (eq (cadr method-group-list) 'foreign) foreign-level alevel)) @@ -1675,49 +1687,91 @@ If SCAN, request a scan of that group as well." ;; Sort the methods based so that the primary and secondary ;; methods come first. This is done for legacy reasons to try to - ;; ensure that side-effect behaviour doesn't change from previous + ;; ensure that side-effect behavior doesn't change from previous ;; Gnus versions. (setq type-cache (sort (nreverse type-cache) (lambda (c1 c2) (< (gnus-method-rank (cadr c1) (car c1)) (gnus-method-rank (cadr c2) (car c2)))))) + ;; Go through the list of servers and possibly extend methods that + ;; aren't equal (and that need extension; i.e., they are async). + (let ((methods nil)) + (dolist (elem type-cache) + (destructuring-bind (method method-type infos dummy) elem + (let ((gnus-opened-servers methods)) + (when (and (gnus-similar-server-opened method) + (gnus-check-backend-function + 'retrieve-group-data-early (car method))) + (setq method (gnus-server-extend-method + (gnus-info-group (car infos)) + method)) + (setcar elem method)) + (push (list method 'ok) methods))))) - ;; Start early async retrieval of data. + ;; If we have primary/secondary select methods, but no groups from + ;; them, we still want to issue a retrieval request from them. + (unless dont-connect + (dolist (method (cons gnus-select-method + gnus-secondary-select-methods)) + (when (and (not (assoc method type-cache)) + (gnus-check-backend-function 'request-list (car method))) + (with-current-buffer nntp-server-buffer + (gnus-read-active-file-1 method nil))))) + + ;; Clear out all the early methods. (dolist (elem type-cache) (destructuring-bind (method method-type infos dummy) elem - (when (and method infos + (when (and method + infos + (gnus-check-backend-function + 'retrieve-group-data-early (car method)) (not (gnus-method-denied-p method))) - ;; If the open-server method doesn't exist, then the method - ;; itself doesn't exist, so we ignore it. - (if (not (ignore-errors (gnus-get-function method 'open-server))) - (setq type-cache (delq elem type-cache)) + (when (ignore-errors (gnus-get-function method 'open-server)) (unless (gnus-server-opened method) (gnus-open-server method)) - (when (and - (gnus-server-opened method) - (gnus-check-backend-function - 'retrieve-group-data-early (car method))) - (when (gnus-check-backend-function 'request-scan (car method)) - (gnus-request-scan nil method)) - ;; Store the token we get back from -early so that we - ;; can pass it to -finish later. - (setcar (nthcdr 3 elem) - (gnus-retrieve-group-data-early method infos))))))) + (when (gnus-server-opened method) + ;; Just mark this server as "cleared". + (gnus-retrieve-group-data-early method nil)))))) - ;; If we have primary/secondary select methods, but no groups from - ;; them, we still want to issue a retrieval request from them. - (dolist (method (cons gnus-select-method - gnus-secondary-select-methods)) - (when (and (not (assoc method type-cache)) - (gnus-check-backend-function 'request-list (car method))) - (with-current-buffer nntp-server-buffer - (gnus-read-active-file-1 method nil)))) + ;; Start early async retrieval of data. + (let ((done-methods nil) + sanity-spec) + (dolist (elem type-cache) + (destructuring-bind (method method-type infos dummy) elem + (setq sanity-spec (list (car method) (cadr method))) + (when (and method infos + (not (gnus-method-denied-p method))) + ;; If the open-server method doesn't exist, then the method + ;; itself doesn't exist, so we ignore it. + (if (not (ignore-errors (gnus-get-function method 'open-server))) + (setq type-cache (delq elem type-cache)) + (unless (gnus-server-opened method) + (gnus-open-server method)) + (when (and + ;; This is a sanity check, so that we never + ;; attempt to start two async requests to the + ;; same server, because that will fail. This + ;; should never happen, since the methods should + ;; be unique at this point, but apparently it + ;; does happen in the wild with some setups. + (not (member sanity-spec done-methods)) + (gnus-server-opened method) + (gnus-check-backend-function + 'retrieve-group-data-early (car method))) + (push sanity-spec done-methods) + (when (gnus-check-backend-function 'request-scan (car method)) + (gnus-request-scan nil method)) + ;; Store the token we get back from -early so that we + ;; can pass it to -finish later. + (setcar (nthcdr 3 elem) + (gnus-retrieve-group-data-early method infos)))))))) ;; Do the rest of the retrieval. (dolist (elem type-cache) (destructuring-bind (method method-type infos early-data) elem - (when (and method infos) + (when (and method infos + (not (gnus-method-denied-p method))) (let ((updatep (gnus-check-backend-function 'request-update-info (car method)))) ;; See if any of the groups from this method require updating. @@ -1755,10 +1809,14 @@ If SCAN, request a scan of that group as well." ;; Finish up getting the data from the methods that have -early ;; methods. ((and + early-data (gnus-check-backend-function 'finish-retrieve-group-infos (car method)) (or (not (gnus-agent-method-p method)) (gnus-online method))) (gnus-finish-retrieve-group-infos method infos early-data) + ;; We may have altered the data now, so mark the dribble buffer + ;; as dirty so that it gets saved. + (gnus-dribble-touch) (gnus-agent-save-active method)) ;; Most backends have -retrieve-groups. ((gnus-check-backend-function 'retrieve-groups (car method)) @@ -1879,7 +1937,7 @@ If SCAN, request a scan of that group as well." ;; OK - I'm done (setq articles nil)) ((< range article) - ;; this range preceeds the article. Leave the range unmodified. + ;; this range precedes the article. Leave the range unmodified. (pop ranges) ranges) ((= range article) @@ -1902,11 +1960,11 @@ If SCAN, request a scan of that group as well." (setcar ranges min) ranges) ((< max article) - ;; this range preceeds the article. Leave the range unmodified. + ;; this range precedes the article. Leave the range unmodified. (pop ranges) ranges) ((< article min) - ;; this article preceeds the range. Return null to move to the + ;; this article precedes the range. Return null to move to the ;; next article nil) (t @@ -1999,7 +2057,9 @@ If SCAN, request a scan of that group as well." ;; We catch C-g so that we can continue past servers ;; that do not respond. (quit - (message "Quit reading the active file") + (if debug-on-quit + (debug "Quit") + (message "Quit reading the active file")) nil)))))))) (defun gnus-read-active-file-1 (method force) @@ -2178,7 +2238,7 @@ If SCAN, request a scan of that group as well." (gnus-online method) (gnus-agent-method-p method)) (progn - (gnus-agent-save-active method) + (gnus-agent-save-active method t) (gnus-active-to-gnus-format method hashtb nil real-active)) (goto-char (point-min)) @@ -2251,7 +2311,12 @@ If FORCE is non-nil, the .newsrc file is read." (gnus-message 5 "Reading %s...done" newsrc-file))) ;; Convert old to new. - (gnus-convert-old-newsrc)))) + (gnus-convert-old-newsrc) + (gnus-clean-old-newsrc)))) + +(defun gnus-clean-old-newsrc (&optional force) + ;; Currently no cleanups. + ) (defun gnus-convert-old-newsrc () "Convert old newsrc formats into the current format, if needed." @@ -2304,7 +2369,7 @@ If FORCE is non-nil, the .newsrc file is read." (while (let (c (cursor-in-echo-area t) (echo-keystrokes 0)) - (message "Convert gnus from version '%s' to '%s'? (n/y/?)" + (message "Convert gnus from version `%s' to `%s'? (n/y/?)" gnus-newsrc-file-version gnus-version) (setq c (read-char-exclusive)) @@ -2325,8 +2390,8 @@ If FORCE is non-nil, the .newsrc file is read." (funcall func convert-to))) (gnus-dribble-enter - (format ";Converted gnus from version '%s' to '%s'." - gnus-newsrc-file-version gnus-version))))))) + (gnus-format-message ";Converted gnus from version `%s' to `%s'." + gnus-newsrc-file-version gnus-version))))))) (defun gnus-convert-mark-converter-prompt (converter no-prompt) "Indicate whether CONVERTER requires gnus-convert-old-newsrc to @@ -2390,7 +2455,9 @@ If FORCE is non-nil, the .newsrc file is read." (when gnus-newsrc-assoc (setq gnus-newsrc-alist gnus-newsrc-assoc)))) (dolist (elem gnus-newsrc-alist) - (setcar elem (mm-string-as-unibyte (car elem)))) + ;; Protect against broken .newsrc.el files. + (when (car elem) + (setcar elem (mm-string-as-unibyte (car elem))))) (gnus-make-hashtable-from-newsrc-alist) (when (file-newer-than-file-p file ding-file) ;; Old format quick file @@ -2500,7 +2567,7 @@ If FORCE is non-nil, the .newsrc file is read." ((or (eq symbol options-symbol) (eq symbol Options-symbol)) (setq gnus-newsrc-options - ;; This concating is quite inefficient, but since our + ;; This concatting is quite inefficient, but since our ;; thorough studies show that approx 99.37% of all ;; .newsrc files only contain a single options line, we ;; don't give a damn, frankly, my dear. @@ -2716,6 +2783,7 @@ If FORCE is non-nil, the .newsrc file is read." 'msdos-long-file-names (lambda () t)))) +(defvar gnus-save-newsrc-file-last-timestamp nil) (defun gnus-save-newsrc-file (&optional force) "Save .newsrc file." ;; Note: We cannot save .newsrc file if all newsgroups are removed @@ -2754,12 +2822,29 @@ If FORCE is non-nil, the .newsrc file is read." (erase-buffer) (gnus-message 5 "Saving %s.eld..." gnus-current-startup-file) + ;; check timestamp of `gnus-current-startup-file'.eld against + ;; `gnus-save-newsrc-file-last-timestamp' + (let* ((checkfile (concat gnus-current-startup-file ".eld")) + (mtime (nth 5 (file-attributes checkfile)))) + (when (and gnus-save-newsrc-file-last-timestamp + (time-less-p gnus-save-newsrc-file-last-timestamp + mtime)) + (unless (y-or-n-p + (format "%s was updated externally after %s, save?" + checkfile + (format-time-string + "%c" + gnus-save-newsrc-file-last-timestamp))) + (error "Couldn't save %s: updated externally" checkfile)))) + (if gnus-save-startup-file-via-temp-buffer (let ((coding-system-for-write gnus-ding-file-coding-system) (standard-output (current-buffer))) (gnus-gnus-to-quick-newsrc-format) (gnus-run-hooks 'gnus-save-quick-newsrc-hook) - (save-buffer)) + (save-buffer) + (setq gnus-save-newsrc-file-last-timestamp + (nth 5 (file-attributes buffer-file-name)))) (let ((coding-system-for-write gnus-ding-file-coding-system) (version-control gnus-backup-startup-file) (startup-file (concat gnus-current-startup-file ".eld")) @@ -2794,7 +2879,9 @@ If FORCE is non-nil, the .newsrc file is read." ;; Replace the existing startup file with the temp file. (rename-file working-file startup-file t) - (gnus-set-file-modes startup-file setmodes))) + (gnus-set-file-modes startup-file setmodes) + (setq gnus-save-newsrc-file-last-timestamp + (nth 5 (file-attributes startup-file))))) (condition-case nil (delete-file working-file) (file-error nil))))) @@ -2863,7 +2950,8 @@ If FORCE is non-nil, the .newsrc file is read." (pop list)) (nreverse olist))) -(defun gnus-gnus-to-newsrc-format () +(defun gnus-gnus-to-newsrc-format (&optional foreign-ok) + (interactive (list (gnus-y-or-n-p "write foreign groups too? "))) ;; Generate and save the .newsrc file. (with-current-buffer (create-file-buffer gnus-current-startup-file) (let ((newsrc (cdr gnus-newsrc-alist)) @@ -2885,7 +2973,8 @@ If FORCE is non-nil, the .newsrc file is read." ;; Don't write foreign groups to .newsrc. (when (or (null (setq method (gnus-info-method info))) (equal method "native") - (inline (gnus-server-equal method gnus-select-method))) + (inline (gnus-server-equal method gnus-select-method)) + foreign-ok) (insert (gnus-info-group info) (if (> (gnus-info-level info) gnus-level-subscribed) "!" ":"))