*** empty log message ***
[gnus] / lisp / gnus-start.el
index a846c84..3b5ffd0 100644 (file)
@@ -32,6 +32,7 @@
 (require 'gnus-range)
 (require 'gnus-util)
 (require 'message)
+(eval-when-compile (require 'cl))
 
 (defcustom gnus-startup-file (nnheader-concat gnus-home-directory ".newsrc")
   "Your `.newsrc' file.
   :type 'file)
 
 (defcustom gnus-init-file (nnheader-concat gnus-home-directory ".gnus")
-  "Your Gnus elisp startup file.
-If a file with the .el or .elc suffixes exist, it will be read
-instead."
+  "Your Gnus Emacs-Lisp startup file name.
+If a file with the `.el' or `.elc' suffixes exists, it will be read instead."
   :group 'gnus-start
   :type 'file)
 
 (defcustom gnus-site-init-file
-  (ignore-errors
-    (concat (file-name-directory
-            (directory-file-name installation-directory))
-           "site-lisp/gnus-init"))
-  "The site-wide Gnus elisp startup file.
-If a file with the .el or .elc suffixes exist, it will be read
-instead."
+  (condition-case nil
+      (concat (file-name-directory
+              (directory-file-name installation-directory))
+             "site-lisp/gnus-init")
+    (error nil))
+  "The site-wide Gnus Emacs-Lisp startup file name, or nil if none.
+If a file with the `.el' or `.elc' suffixes exists, it will be read instead."
   :group 'gnus-start
-  :type 'file)
+  :type '(choice file (const nil)))
 
 (defcustom gnus-default-subscribed-newsgroups nil
-  "This variable lists what newsgroups should be subscribed the first time Gnus is used.
-It should be a list of strings.
-If it is `t', Gnus will not do anything special the first time it is
+  "List of newsgroups to subscribe, when a user runs Gnus the first time.
+The value should be a list of strings.
+If it is t, Gnus will not do anything special the first time it is
 started; it'll just use the normal newsgroups subscription methods."
   :group 'gnus-start
-  :type '(repeat string))
+  :type '(choice (repeat string) (const :tag "Nothing special" t)))
 
 (defcustom gnus-use-dribble-file t
   "*Non-nil means that Gnus will use a dribble file to store user updates.
@@ -79,7 +79,7 @@ saved will be used."
   :group 'gnus-dribble-file
   :type '(choice directory (const nil)))
 
-(defcustom gnus-check-new-newsgroups t
+(defcustom gnus-check-new-newsgroups 'ask-server
   "*Non-nil means that Gnus will run gnus-find-new-newsgroups at startup.
 This normally finds new newsgroups by comparing the active groups the
 servers have already reported with those Gnus already knows, either alive
@@ -123,7 +123,7 @@ check for bogus newsgroups with \\<gnus-group-mode-map>\\[gnus-group-check-bogus
   :group 'gnus-start-server
   :type 'boolean)
 
-(defcustom gnus-read-active-file t
+(defcustom gnus-read-active-file 'some
   "*Non-nil means that Gnus will read the entire active file at startup.
 If this variable is nil, Gnus will only know about the groups in your
 `.newsrc' file.
@@ -337,11 +337,22 @@ This hook is called after Gnus is connected to the NNTP server."
   :group 'gnus-start
   :type 'hook)
 
+(defcustom gnus-before-startup-hook nil
+  "A hook called at before startup.
+This hook is called as the first thing when Gnus is started."
+  :group 'gnus-start
+  :type 'hook)
+
 (defcustom gnus-started-hook nil
   "A hook called as the last thing after startup."
   :group 'gnus-start
   :type 'hook)
 
+(defcustom gnus-setup-news-hook nil
+  "A hook after reading the .newsrc file, but before generating the buffer."
+  :group 'gnus-start
+  :type 'hook)
+
 (defcustom gnus-get-new-news-hook nil
   "A hook run just before Gnus checks for new news."
   :group 'gnus-group-new
@@ -434,7 +445,8 @@ Can be used to turn version control on or off."
              (push prefix prefixes)
              (message "Descend hierarchy %s? ([y]nsq): "
                       (substring prefix 1 (1- (length prefix))))
-             (while (not (memq (setq ans (read-char)) '(?y ?\n ?\r ?n ?s ?q)))
+             (while (not (memq (setq ans (read-char-exclusive))
+                               '(?y ?\n ?\r ?n ?s ?q)))
                (ding)
                (message "Descend hierarchy %s? ([y]nsq): "
                         (substring prefix 1 (1- (length prefix)))))
@@ -462,7 +474,8 @@ Can be used to turn version control on or off."
                       (setq groups (cdr groups))))
                    (t nil)))
          (message "Subscribe %s? ([n]yq)" (car groups))
-         (while (not (memq (setq ans (read-char)) '(?y ?\n ?\r ?q ?n)))
+         (while (not (memq (setq ans (read-char-exclusive))
+                           '(?y ?\n ?\r ?q ?n)))
            (ding)
            (message "Subscribe %s? ([n]yq)" (car groups)))
          (setq group (car groups))
@@ -642,14 +655,19 @@ prompt the user for the name of an NNTP server to use."
 
     (gnus-splash)
     (gnus-clear-system)
+    (run-hooks 'gnus-before-startup-hook)
     (nnheader-init-server-buffer)
-    (gnus-read-init-file)
     (setq gnus-slave slave)
+    (gnus-read-init-file)
 
-    (when (and (string-match "XEmacs" (emacs-version))
-              gnus-simple-splash)
+    (when gnus-simple-splash
       (setq gnus-simple-splash nil)
-      (gnus-xmas-splash))
+      (cond
+       (gnus-xemacs
+       (gnus-xmas-splash))
+       ((and (eq window-system 'x)
+            (= (frame-height) (1+ (window-height))))
+       (gnus-x-splash))))
 
     (let ((level (and (numberp arg) (> arg 0) arg))
          did-connect)
@@ -679,6 +697,8 @@ prompt the user for the name of an NNTP server to use."
 
          ;; Do the actual startup.
          (gnus-setup-news nil level dont-connect)
+         (run-hooks 'gnus-setup-news-hook)
+         (gnus-start-draft-setup)
          ;; Generate the group buffer.
          (gnus-group-list-groups level)
          (gnus-group-first-unread-group)
@@ -686,12 +706,21 @@ prompt the user for the name of an NNTP server to use."
          (gnus-group-set-mode-line)
          (run-hooks 'gnus-started-hook))))))
 
+(defun gnus-start-draft-setup ()
+  "Make sure the draft group exists."
+  (gnus-request-create-group "drafts" '(nndraft ""))
+  (unless (gnus-gethash "nndraft:drafts" gnus-newsrc-hashtb)
+    (let ((gnus-level-default-subscribed 1))
+      (gnus-subscribe-group "nndraft:drafts" nil '(nndraft "")))
+    (gnus-group-set-parameter
+     "nndraft:drafts" 'gnus-dummy '((gnus-draft-mode)))))
+
 ;;;###autoload
 (defun gnus-unload ()
   "Unload all Gnus features."
   (interactive)
   (unless (boundp 'load-history)
-    (error "Sorry, `gnus-unload' is not implemented in this Emacs version."))
+    (error "Sorry, `gnus-unload' is not implemented in this Emacs version"))
   (let ((history load-history)
        feature)
     (while history
@@ -823,8 +852,10 @@ If LEVEL is non-nil, the news will be set up at level LEVEL."
       ;; Read the newsrc file and create `gnus-newsrc-hashtb'.
       (gnus-read-newsrc-file rawfile))
 
-    (when (and (not (assoc "archive" gnus-server-alist))
-              (gnus-archive-server-wanted-p))
+    ;; Make sure the archive server is available to all and sundry.
+    (when gnus-message-archive-method
+      (setq gnus-server-alist (delq (assoc "archive" gnus-server-alist)
+                                   gnus-server-alist))
       (push (cons "archive" gnus-message-archive-method)
            gnus-server-alist))
 
@@ -840,7 +871,7 @@ If LEVEL is non-nil, the news will be set up at level LEVEL."
     ;; done in `gnus-get-unread-articles'.
     (and gnus-read-active-file
         (not level)
-        (gnus-read-active-file))
+        (gnus-read-active-file nil dont-connect))
 
     (unless gnus-active-hashtb
       (setq gnus-active-hashtb (gnus-make-hashtable 4096)))
@@ -897,8 +928,8 @@ If LEVEL is non-nil, the news will be set up at level LEVEL."
   "Search for new newsgroups and add them.
 Each new newsgroup will be treated with `gnus-subscribe-newsgroup-method.'
 The `-n' option line from .newsrc is respected.
-If ARG (the prefix), use the `ask-server' method to query
-the server for new groups."
+If ARG (the prefix), use the `ask-server' method to query the server
+for new groups."
   (interactive "P")
   (let ((check (if (or (and arg (not (listp gnus-check-new-newsgroups)))
                       (null gnus-read-active-file)
@@ -1036,7 +1067,6 @@ the server for new groups."
         hashtb))
       (when new-newsgroups
        (gnus-subscribe-hierarchical-interactive new-newsgroups)))
-    ;; Suggested by Per Abrahamsen <amanda@iesd.auc.dk>.
     (when (> groups 0)
       (gnus-message 6 "%d new newsgroup%s arrived."
                    groups (if (> groups 1) "s have" " has")))
@@ -1052,7 +1082,8 @@ the server for new groups."
       nil
     (gnus-message 6 "First time user; subscribing you to default groups")
     (unless (gnus-read-active-file-p)
-      (gnus-read-active-file))
+      (let ((gnus-read-active-file t))
+       (gnus-read-active-file)))
     (setq gnus-newsrc-last-checked-date (current-time-string))
     (let ((groups gnus-default-subscribed-newsgroups)
          group)
@@ -1211,7 +1242,8 @@ the server for new groups."
           (format
            "(gnus-group-set-info '%S)" info)))))
       (when gnus-group-change-level-function
-       (funcall gnus-group-change-level-function group level oldlevel)))))
+       (funcall gnus-group-change-level-function
+                group level oldlevel previous)))))
 
 (defun gnus-kill-newsgroup (newsgroup)
   "Obsolete function.  Kills a newsgroup."
@@ -1284,12 +1316,11 @@ newsgroup."
     "Alter the ACTIVE info for GROUP to reflect the articles in the cache."
     (when gnus-cache-active-hashtb
       (let ((cache-active (gnus-gethash group gnus-cache-active-hashtb)))
-       (and cache-active
-            (< (car cache-active) (car active))
-            (setcar active (car cache-active)))
-       (and cache-active
-            (> (cdr cache-active) (cdr active))
-            (setcdr active (cdr cache-active)))))))
+       (when cache-active
+         (when (< (car cache-active) (car active))
+           (setcar active (car cache-active)))
+         (when (> (cdr cache-active) (cdr active))
+           (setcdr active (cdr cache-active))))))))
 
 (defun gnus-activate-group (group &optional scan dont-check method)
   ;; Check whether a group has been activated or not.
@@ -1309,9 +1340,18 @@ newsgroup."
             (inline (gnus-request-group group dont-check method))
           (error nil)
           (quit nil))
-        (gnus-set-active group (setq active (gnus-parse-active)))
-        ;; Return the new active info.
-        active)))
+        (setq active (gnus-parse-active))
+        ;; If there are no articles in the group, the GROUP
+        ;; command may have responded with the `(0 . 0)'.  We
+        ;; ignore this if we already have an active entry
+        ;; for the group.
+        (if (and (zerop (car active))
+                 (zerop (cdr active))
+                 (gnus-active group))
+            (gnus-active group)
+          (gnus-set-active group active)
+          ;; Return the new active info.
+          active))))
 
 (defun gnus-get-unread-articles-in-group (info active &optional update)
   (when active
@@ -1554,11 +1594,12 @@ newsgroup."
   (gnus-dribble-touch))
 
 ;; Get the active file(s) from the backend(s).
-(defun gnus-read-active-file (&optional force)
+(defun gnus-read-active-file (&optional force not-native)
   (gnus-group-set-mode-line)
   (let ((methods
         (append
-         (if (gnus-check-server gnus-select-method)
+         (if (and (not not-native)
+                  (gnus-check-server gnus-select-method))
              ;; The native server is available.
              (cons gnus-select-method gnus-secondary-select-methods)
            ;; The native server is down, so we just do the
@@ -1610,18 +1651,20 @@ newsgroup."
                     1.2 "Cannot read partial active file from %s server."
                     (car method)))
                   ((eq list-type 'active)
-                   (gnus-active-to-gnus-format method gnus-active-hashtb))
+                   (gnus-active-to-gnus-format
+                    method gnus-active-hashtb nil t))
                   (t
-                   (gnus-groups-to-gnus-format method gnus-active-hashtb))))))
+                   (gnus-groups-to-gnus-format
+                    method gnus-active-hashtb t))))))
             ((null method)
              t)
             (t
              (if (not (gnus-request-list method))
                  (unless (equal method gnus-message-archive-method)
-                   (gnus-error 1 "Cannot read active file from %s server."
+                   (gnus-error 1 "Cannot read active file from %s server"
                                (car method)))
                (gnus-message 5 mesg)
-               (gnus-active-to-gnus-format method gnus-active-hashtb)
+               (gnus-active-to-gnus-format method gnus-active-hashtb nil t)
                ;; We mark this active file as read.
                (push method gnus-have-read-active-file)
                (gnus-message 5 "%sdone" mesg))))))
@@ -1636,7 +1679,8 @@ newsgroup."
                gnus-ignored-newsgroups))
 
 ;; Read an active file and place the results in `gnus-active-hashtb'.
-(defun gnus-active-to-gnus-format (&optional method hashtb ignore-errors)
+(defun gnus-active-to-gnus-format (&optional method hashtb ignore-errors
+                                            real-active)
   (unless method
     (setq method gnus-select-method))
   (let ((cur (current-buffer))
@@ -1665,6 +1709,10 @@ newsgroup."
     (while (re-search-backward "[][';?()#]" nil t)
       (insert ?\\))
 
+    ;; Let the Gnus agent save the active file.
+    (when (and gnus-agent real-active)
+      (gnus-agent-save-active method))
+
     ;; If these are groups from a foreign select method, we insert the
     ;; group prefix in front of the group names.
     (when (not (gnus-server-equal
@@ -1690,13 +1738,13 @@ newsgroup."
                       (progn
                         (skip-chars-forward " \t")
                         (not
-                         (or (= (char-after (point)) ?=)
-                             (= (char-after (point)) ?x)
-                             (= (char-after (point)) ?j)))))
+                         (or (= (following-char) ?=)
+                             (= (following-char) ?x)
+                             (= (following-char) ?j)))))
                  (progn
                    (set group (cons min max))
                    ;; if group is moderated, stick in moderation table
-                   (when (= (char-after (point)) ?m)
+                   (when (= (following-char) ?m)
                      (unless gnus-moderated-hashtb
                        (setq gnus-moderated-hashtb (gnus-make-hashtable)))
                      (gnus-sethash (symbol-name group) t
@@ -1713,7 +1761,7 @@ newsgroup."
        (widen)
        (forward-line 1)))))
 
-(defun gnus-groups-to-gnus-format (method &optional hashtb)
+(defun gnus-groups-to-gnus-format (method &optional hashtb real-active)
   ;; Parse a "groups" active file.
   (let ((cur (current-buffer))
        (hashtb (or hashtb
@@ -1728,6 +1776,10 @@ newsgroup."
                           (gnus-server-get-method nil gnus-select-method)))
                     (gnus-group-prefixed-name "" method))))
 
+    ;; Let the Gnus agent save the active file.
+    (when (and gnus-agent real-active)
+      (gnus-agent-save-groups method))
+    
     (goto-char (point-min))
     ;; We split this into to separate loops, one with the prefix
     ;; and one without to speed the reading up somewhat.
@@ -1750,7 +1802,7 @@ newsgroup."
       (let (min max group)
        (while (not (eobp))
          (condition-case ()
-             (when (= (char-after (point)) ?2)
+             (when (= (following-char) ?2)
                (read cur) (read cur)
                (setq min (read cur)
                      max (read cur))
@@ -1965,7 +2017,7 @@ If FORCE is non-nil, the .newsrc file is read."
        (unless (boundp symbol)
          (set symbol nil))
        ;; It was a group name.
-       (setq subscribed (= (char-after (point)) ?:)
+       (setq subscribed (= (following-char) ?:)
              group (symbol-name symbol)
              reads nil)
        (if (eolp)
@@ -1989,7 +2041,7 @@ If FORCE is non-nil, the .newsrc file is read."
                           (read buf)))
              (widen)
              ;; If the next character is a dash, then this is a range.
-             (if (= (char-after (point)) ?-)
+             (if (= (following-char) ?-)
                  (progn
                    ;; We read the upper bound of the range.
                    (forward-char 1)
@@ -2011,8 +2063,8 @@ If FORCE is non-nil, the .newsrc file is read."
                (push num1 reads))
              ;; If the next char in ?\n, then we have reached the end
              ;; of the line and return nil.
-             (/= (char-after (point)) ?\n))
-            ((= (char-after (point)) ?\n)
+             (/= (following-char) ?\n))
+            ((= (following-char) ?\n)
              ;; End of line, so we end.
              nil)
             (t
@@ -2145,11 +2197,12 @@ If FORCE is non-nil, the .newsrc file is read."
              (push (cons (concat
                           "^" (buffer-substring
                                (1+ (match-beginning 0))
-                               (match-end 0)))
+                               (match-end 0))
+                          "\\($\\|\\.\\)")
                          'ignore)
                    out)
            ;; There was no bang, so this is a "yes" spec.
-           (push (cons (concat "^" (match-string 0))
+           (push (cons (concat "^" (match-string 0) "\\($\\|\\.\\)")
                        'subscribe)
                  out))))
 
@@ -2200,12 +2253,13 @@ If FORCE is non-nil, the .newsrc file is read."
 
 (defun gnus-gnus-to-quick-newsrc-format ()
   "Insert Gnus variables such as gnus-newsrc-alist in lisp format."
-  (let ((print-quoted t))
+  (let ((print-quoted t)
+       (print-escape-newlines t))
     (insert ";; -*- emacs-lisp -*-\n")
     (insert ";; Gnus startup file.\n")
-    (insert
-     ";; Never delete this file - touch .newsrc instead to force Gnus\n")
-    (insert ";; to read .newsrc.\n")
+    (insert "\
+;; Never delete this file -- if you want to force Gnus to read the
+;; .newsrc file (if you have one), touch .newsrc instead.\n")
     (insert "(setq gnus-newsrc-file-version "
            (prin1-to-string gnus-version) ")\n")
     (let* ((gnus-killed-list
@@ -2426,8 +2480,15 @@ If FORCE is non-nil, the .newsrc file is read."
            (skip-chars-forward " \t")
            ;; ...  which leads to this line being effectively ignored.
            (when (symbolp group)
-             (set group (buffer-substring
-                         (point) (progn (end-of-line) (point)))))
+             (let ((str (buffer-substring
+                         (point) (progn (end-of-line) (point))))
+                   (coding
+                    (and (boundp 'enable-multibyte-characters)
+                         enable-multibyte-characters
+                         (gnus-mule-get-coding-system (symbol-name group)))))
+               (if coding
+                   (setq str (decode-coding-string str (car coding))))
+               (set group str)))
            (forward-line 1))))
       (gnus-message 5 "Reading descriptions file...done")
       t))))