(eval '(run-hooks 'gnus-load-hook))
-(require 'mail-utils)
-(require 'timezone)
-(require 'nnheader)
-(require 'message)
-
-(eval-when-compile (require 'cl))
-
-(defvar gnus-directory (or (getenv "SAVEDIR") "~/News/")
- "*Directory variable from which all other Gnus file variables are derived.")
-
-;; Site dependent variables. These variables should be defined in
-;; paths.el.
-
-(defvar gnus-default-nntp-server nil
- "Specify a default NNTP server.
-This variable should be defined in paths.el, and should never be set
-by the user.
-If you want to change servers, you should use `gnus-select-method'.
-See the documentation to that variable.")
-
-(defvar gnus-backup-default-subscribed-newsgroups
- '("news.announce.newusers" "news.groups.questions" "gnu.emacs.gnus")
- "Default default new newsgroups the first time Gnus is run.
-Should be set in paths.el, and shouldn't be touched by the user.")
+(defconst gnus-version-number "0.15"
+ "Version number for this version of Gnus.")
-(defvar gnus-local-domain nil
- "Local domain name without a host name.
-The DOMAINNAME environment variable is used instead if it is defined.
-If the `system-name' function returns the full Internet name, there is
-no need to set this variable.")
+(defconst gnus-version (format "Red Gnus v%s" gnus-version-number)
+ "Version string for this version of Gnus.")
-(defvar gnus-local-organization nil
- "String with a description of what organization (if any) the user belongs to.
-The ORGANIZATION environment variable is used instead if it is defined.
-If this variable contains a function, this function will be called
-with the current newsgroup name as the argument. The function should
-return a string.
+(defvar gnus-inhibit-startup-message nil
+ "*If non-nil, the startup message will not be displayed.")
-In any case, if the string (either in the variable, in the environment
-variable, or returned by the function) is a file name, the contents of
-this file will be used as the organization.")
+;;; Internal variables
-;; Customization variables
+(defvar gnus-group-buffer "*Group*")
-;; Don't touch this variable.
-(defvar gnus-nntp-service "nntp"
- "*NNTP service name (\"nntp\" or 119).
-This is an obsolete variable, which is scarcely used. If you use an
-nntp server for your newsgroup and want to change the port number
-used to 899, you would say something along these lines:
+;;; Splash screen.
- (setq gnus-select-method '(nntp \"my.nntp.server\" (nntp-port-number 899)))")
+(defun gnus-splash ()
+ (save-excursion
+ (switch-to-buffer gnus-group-buffer)
+ (let ((buffer-read-only nil))
+ (erase-buffer)
+ (unless gnus-inhibit-startup-message
+ (gnus-group-startup-message)
+ (sit-for 0)))))
-(defvar gnus-nntpserver-file "/etc/nntpserver"
- "*A file with only the name of the nntp server in it.")
+(defun gnus-indent-rigidly (start end arg)
+ "Indent rigidly using only spaces and no tabs."
+ (save-excursion
+ (save-restriction
+ (narrow-to-region start end)
+ (indent-rigidly start end arg)
+ ;; We translate tabs into spaces -- not everybody uses
+ ;; an 8-character tab.
+ (goto-char (point-min))
+ (while (search-forward "\t" nil t)
+ (replace-match " " t t)))))
-;; This function is used to check both the environment variable
-;; NNTPSERVER and the /etc/nntpserver file to see whether one can find
-;; an nntp server name default.
-(defun gnus-getenv-nntpserver ()
- (or (getenv "NNTPSERVER")
- (and (file-readable-p gnus-nntpserver-file)
- (save-excursion
- (set-buffer (get-buffer-create " *gnus nntp*"))
- (buffer-disable-undo (current-buffer))
- (insert-file-contents gnus-nntpserver-file)
- (let ((name (buffer-string)))
- (prog1
- (if (string-match "^[ \t\n]*$" name)
- nil
- name)
- (kill-buffer (current-buffer))))))))
+(defun gnus-group-startup-message (&optional x y)
+ "Insert startup message in current buffer."
+ ;; Insert the message.
+ (erase-buffer)
+ (insert
+ (format " %s
+ _ ___ _ _
+ _ ___ __ ___ __ _ ___
+ __ _ ___ __ ___
+ _ ___ _
+ _ _ __ _
+ ___ __ _
+ __ _
+ _ _ _
+ _ _ _
+ _ _ _
+ __ ___
+ _ _ _ _
+ _ _
+ _ _
+ _ _
+ _
+ __
-(defvar gnus-select-method
- (nconc
- (list 'nntp (or (condition-case ()
- (gnus-getenv-nntpserver)
- (error nil))
- (if (and gnus-default-nntp-server
- (not (string= gnus-default-nntp-server "")))
- gnus-default-nntp-server)
- (system-name)))
- (if (or (null gnus-nntp-service)
- (equal gnus-nntp-service "nntp"))
- nil
- (list gnus-nntp-service)))
- "*Default method for selecting a newsgroup.
-This variable should be a list, where the first element is how the
-news is to be fetched, the second is the address.
+"
+ ""))
+ ;; And then hack it.
+ (gnus-indent-rigidly (point-min) (point-max)
+ (/ (max (- (window-width) (or x 46)) 0) 2))
+ (goto-char (point-min))
+ (forward-line 1)
+ (let* ((pheight (count-lines (point-min) (point-max)))
+ (wheight (window-height))
+ (rest (- wheight pheight)))
+ (insert (make-string (max 0 (* 2 (/ rest 3))) ?\n)))
+ ;; Fontify some.
+ (goto-char (point-min))
+ (and (search-forward "Praxis" nil t)
+ (put-text-property (match-beginning 0) (match-end 0) 'face 'bold))
+ (goto-char (point-min))
+ (setq mode-line-buffer-identification gnus-version)
+ (set-buffer-modified-p t))
-For instance, if you want to get your news via NNTP from
-\"flab.flab.edu\", you could say:
+(eval-when (load)
+ (gnus-splash))
-(setq gnus-select-method '(nntp \"flab.flab.edu\"))
+;;; Do the rest.
-If you want to use your local spool, say:
+(require 'gnus-load)
-(setq gnus-select-method (list 'nnspool (system-name)))
+\f
-If you use this variable, you must set `gnus-nntp-server' to nil.
+;; Fix by Hallvard B Furuseth <h.b.furuseth@usit.uio.no>.
+;; If you want the cursor to go somewhere else, set these two
+;; functions in some startup hook to whatever you want.
+(defalias 'gnus-summary-position-point 'gnus-goto-colon)
+(defalias 'gnus-group-position-point 'gnus-goto-colon)
-There is a lot more to know about select methods and virtual servers -
-see the manual for details.")
+;;; Various macros and substs.
-(defvar gnus-message-archive-method
- `(nnfolder
- "archive"
- (nnfolder-directory ,(nnheader-concat message-directory "archive"))
- (nnfolder-active-file
- ,(nnheader-concat message-directory "archive/active"))
- (nnfolder-get-new-mail nil)
- (nnfolder-inhibit-expiry t))
- "*Method used for archiving messages you've sent.
-This should be a mail method.")
+(defun gnus-header-from (header)
+ (mail-header-from header))
-(defvar gnus-refer-article-method nil
- "*Preferred method for fetching an article by Message-ID.
-If you are reading news from the local spool (with nnspool), fetching
-articles by Message-ID is painfully slow. By setting this method to an
-nntp method, you might get acceptable results.
+(defmacro gnus-gethash (string hashtable)
+ "Get hash value of STRING in HASHTABLE."
+ `(symbol-value (intern-soft ,string ,hashtable)))
-The value of this variable must be a valid select method as discussed
-in the documentation of `gnus-select-method'.")
+(defmacro gnus-sethash (string value hashtable)
+ "Set hash value. Arguments are STRING, VALUE, and HASHTABLE."
+ `(set (intern ,string ,hashtable) ,value))
+(put 'nnheader-temp-write 'edebug-form-spec '(form form form))
-(defvar gnus-secondary-select-methods nil
- "*A list of secondary methods that will be used for reading news.
-This is a list where each element is a complete select method (see
-`gnus-select-method').
+(defmacro gnus-group-unread (group)
+ "Get the currently computed number of unread articles in GROUP."
+ `(car (gnus-gethash ,group gnus-newsrc-hashtb)))
-If, for instance, you want to read your mail with the nnml backend,
-you could set this variable:
+(defmacro gnus-group-entry (group)
+ "Get the newsrc entry for GROUP."
+ `(gnus-gethash ,group gnus-newsrc-hashtb))
-(setq gnus-secondary-select-methods '((nnml \"\")))")
+(defmacro gnus-active (group)
+ "Get active info on GROUP."
+ `(gnus-gethash ,group gnus-active-hashtb))
-(defvar gnus-secondary-servers nil
- "*List of NNTP servers that the user can choose between interactively.
-To make Gnus query you for a server, you have to give `gnus' a
-non-numeric prefix - `C-u M-x gnus', in short.")
+(defmacro gnus-set-active (group active)
+ "Set GROUP's active info."
+ `(gnus-sethash ,group ,active gnus-active-hashtb))
-(defvar gnus-nntp-server nil
- "*The name of the host running the NNTP server.
-This variable is semi-obsolete. Use the `gnus-select-method'
-variable instead.")
+(defun gnus-alive-p ()
+ "Say whether Gnus is running or not."
+ (and gnus-group-buffer
+ (get-buffer gnus-group-buffer)
+ (save-excursion
+ (set-buffer gnus-group-buffer)
+ (eq major-mode 'gnus-group-mode))))
-(defvar gnus-startup-file "~/.newsrc"
- "*Your `.newsrc' file.
-`.newsrc-SERVER' will be used instead if that exists.")
+;; Info access macros.
-(defvar gnus-init-file "~/.gnus"
- "*Your Gnus elisp startup file.
-If a file with the .el or .elc suffixes exist, it will be read
-instead.")
+(defmacro gnus-info-group (info)
+ `(nth 0 ,info))
+(defmacro gnus-info-rank (info)
+ `(nth 1 ,info))
+(defmacro gnus-info-read (info)
+ `(nth 2 ,info))
+(defmacro gnus-info-marks (info)
+ `(nth 3 ,info))
+(defmacro gnus-info-method (info)
+ `(nth 4 ,info))
+(defmacro gnus-info-params (info)
+ `(nth 5 ,info))
-(defvar gnus-group-faq-directory
- '("/ftp@mirrors.aol.com:/pub/rtfm/usenet/"
- "/ftp@sunsite.auc.dk:/pub/usenet/"
- "/ftp@src.doc.ic.ac.uk:/usenet/news-FAQS/"
- "/ftp@ftp.seas.gwu.edu:/pub/rtfm/"
- "/ftp@rtfm.mit.edu:/pub/usenet/"
- "/ftp@ftp.uni-paderborn.de:/pub/FAQ/"
- "/ftp@ftp.sunet.se:/pub/usenet/"
- "/ftp@nctuccca.edu.tw:/USENET/FAQ/"
- "/ftp@hwarang.postech.ac.kr:/pub/usenet/"
- "/ftp@ftp.hk.super.net:/mirror/faqs/")
- "*Directory where the group FAQs are stored.
-This will most commonly be on a remote machine, and the file will be
-fetched by ange-ftp.
+(defmacro gnus-info-level (info)
+ `(let ((rank (gnus-info-rank ,info)))
+ (if (consp rank)
+ (car rank)
+ rank)))
+(defmacro gnus-info-score (info)
+ `(let ((rank (gnus-info-rank ,info)))
+ (or (and (consp rank) (cdr rank)) 0)))
-This variable can also be a list of directories. In that case, the
-first element in the list will be used by default, and the others will
-be used as backup sites.
+(defmacro gnus-info-set-group (info group)
+ `(setcar ,info ,group))
+(defmacro gnus-info-set-rank (info rank)
+ `(setcar (nthcdr 1 ,info) ,rank))
+(defmacro gnus-info-set-read (info read)
+ `(setcar (nthcdr 2 ,info) ,read))
+(defmacro gnus-info-set-marks (info marks &optional extend)
+ (if extend
+ `(gnus-info-set-entry ,info ,marks 3)
+ `(setcar (nthcdr 3 ,info) ,marks)))
+(defmacro gnus-info-set-method (info method &optional extend)
+ (if extend
+ `(gnus-info-set-entry ,info ,method 4)
+ `(setcar (nthcdr 4 ,info) ,method)))
+(defmacro gnus-info-set-params (info params &optional extend)
+ (if extend
+ `(gnus-info-set-entry ,info ,params 5)
+ `(setcar (nthcdr 5 ,info) ,params)))
+
+(defun gnus-info-set-entry (info entry number)
+ ;; Extend the info until we have enough elements.
+ (while (< (length info) number)
+ (nconc info (list nil)))
+ ;; Set the entry.
+ (setcar (nthcdr number info) entry))
-Note that Gnus uses an aol machine as the default directory. If this
-feels fundamentally unclean, just think of it as a way to finally get
-something of value back from them.
+(defmacro gnus-info-set-level (info level)
+ `(let ((rank (cdr ,info)))
+ (if (consp (car rank))
+ (setcar (car rank) ,level)
+ (setcar rank ,level))))
+(defmacro gnus-info-set-score (info score)
+ `(let ((rank (cdr ,info)))
+ (if (consp (car rank))
+ (setcdr (car rank) ,score)
+ (setcar rank (cons (car rank) ,score)))))
-If the default site is too slow, try one of these:
+(defmacro gnus-get-info (group)
+ `(nth 2 (gnus-gethash ,group gnus-newsrc-hashtb)))
- North America: mirrors.aol.com /pub/rtfm/usenet
- ftp.seas.gwu.edu /pub/rtfm
- rtfm.mit.edu /pub/usenet
- Europe: ftp.uni-paderborn.de /pub/FAQ
- src.doc.ic.ac.uk /usenet/news-FAQS
- ftp.sunet.se /pub/usenet
- sunsite.auc.dk /pub/usenet
- Asia: nctuccca.edu.tw /USENET/FAQ
- hwarang.postech.ac.kr /pub/usenet
- ftp.hk.super.net /mirror/faqs")
+;; Byte-compiler warning.
+(defvar gnus-visual)
+;; Find out whether the gnus-visual TYPE is wanted.
+(defun gnus-visual-p (&optional type class)
+ (and gnus-visual ; Has to be non-nil, at least.
+ (if (not type) ; We don't care about type.
+ gnus-visual
+ (if (listp gnus-visual) ; It's a list, so we check it.
+ (or (memq type gnus-visual)
+ (memq class gnus-visual))
+ t))))
-(defvar gnus-group-archive-directory
- "/ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list/"
- "*The address of the (ding) archives.")
+;;; Load the compatability functions.
-(defvar gnus-group-recent-archive-directory
- "/ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list-recent/"
- "*The address of the most recent (ding) articles.")
+(require 'gnus-cus)
+(require 'gnus-ems)
-(defvar 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
-started; it'll just use the normal newsgroups subscription methods.")
+\f
+;;;
+;;; Shutdown
+;;;
-(defvar gnus-use-cross-reference t
- "*Non-nil means that cross referenced articles will be marked as read.
-If nil, ignore cross references. If t, mark articles as read in
-subscribed newsgroups. If neither t nor nil, mark as read in all
-newsgroups.")
+(defvar gnus-shutdown-alist nil)
-(defvar gnus-single-article-buffer t
- "*If non-nil, display all articles in the same buffer.
-If nil, each group will get its own article buffer.")
+(defun gnus-add-shutdown (function &rest symbols)
+ "Run FUNCTION whenever one of SYMBOLS is shut down."
+ (push (cons function symbols) gnus-shutdown-alist))
-(defvar gnus-use-dribble-file t
- "*Non-nil means that Gnus will use a dribble file to store user updates.
-If Emacs should crash without saving the .newsrc files, complete
-information can be restored from the dribble file.")
+(defun gnus-shutdown (symbol)
+ "Shut down everything that waits for SYMBOL."
+ (let ((alist gnus-shutdown-alist)
+ entry)
+ (while (setq entry (pop alist))
+ (when (memq symbol (cdr entry))
+ (funcall (car entry))))))
-(defvar gnus-dribble-directory nil
- "*The directory where dribble files will be saved.
-If this variable is nil, the directory where the .newsrc files are
-saved will be used.")
+\f
+;;;
+;;; Gnus Utility Functions
+;;;
-(defvar gnus-asynchronous nil
- "*If non-nil, Gnus will supply backends with data needed for async article fetching.")
+;; Add the current buffer to the list of buffers to be killed on exit.
+(defun gnus-add-current-to-buffer-list ()
+ (or (memq (current-buffer) gnus-buffer-list)
+ (setq gnus-buffer-list (cons (current-buffer) gnus-buffer-list))))
-(defvar gnus-kill-summary-on-exit t
- "*If non-nil, kill the summary buffer when you exit from it.
-If nil, the summary will become a \"*Dead Summary*\" buffer, and
-it will be killed sometime later.")
+(defun gnus-version (&optional arg)
+ "Version number of this version of Gnus.
+If ARG, insert string at point."
+ (interactive "P")
+ (let ((methods gnus-valid-select-methods)
+ (mess gnus-version)
+ meth)
+ ;; Go through all the legal select methods and add their version
+ ;; numbers to the total version string. Only the backends that are
+ ;; currently in use will have their message numbers taken into
+ ;; consideration.
+ (while methods
+ (setq meth (intern (concat (caar methods) "-version")))
+ (and (boundp meth)
+ (stringp (symbol-value meth))
+ (setq mess (concat mess "; " (symbol-value meth))))
+ (setq methods (cdr methods)))
+ (if arg
+ (insert (message mess))
+ (message mess))))
-(defvar gnus-large-newsgroup 200
- "*The number of articles which indicates a large newsgroup.
-If the number of articles in a newsgroup is greater than this value,
-confirmation is required for selecting the newsgroup.")
+(defun gnus-continuum-version (version)
+ "Return VERSION as a floating point number."
+ (when (or (string-match "^\\([^ ]+\\)? ?Gnus v?\\([0-9.]+\\)$" version)
+ (string-match "^\\(.?\\)gnus-\\([0-9.]+\\)$" version))
+ (let* ((alpha (and (match-beginning 1) (match-string 1 version)))
+ (number (match-string 2 version))
+ major minor least)
+ (string-match "\\([0-9]\\)\\.\\([0-9]+\\)\\.?\\([0-9]+\\)?" number)
+ (setq major (string-to-number (match-string 1 number)))
+ (setq minor (string-to-number (match-string 2 number)))
+ (setq least (if (match-beginning 3)
+ (string-to-number (match-string 3 number))
+ 0))
+ (string-to-number
+ (if (zerop major)
+ (format "%s00%02d%02d"
+ (cond
+ ((member alpha '("(ding)" "d")) "4.99")
+ ((member alpha '("September" "s")) "5.01")
+ ((member alpha '("Red" "r")) "5.03"))
+ minor least)
+ (format "%d.%02d%02d" major minor least))))))
-;; Suggested by Andrew Eskilsson <pi92ae@lelle.pt.hk-r.se>.
-(defvar gnus-no-groups-message "No news is horrible news"
- "*Message displayed by Gnus when no groups are available.")
+(defun gnus-info-find-node ()
+ "Find Info documentation of Gnus."
+ (interactive)
+ ;; Enlarge info window if needed.
+ (let (gnus-info-buffer)
+ (Info-goto-node (cadr (assq major-mode gnus-info-nodes)))
+ (setq gnus-info-buffer (current-buffer))
+ (gnus-configure-windows 'info)))
-(defvar gnus-use-long-file-name (not (memq system-type '(usg-unix-v xenix)))
- "*Non-nil means that the default name of a file to save articles in is the group name.
-If it's nil, the directory form of the group name is used instead.
+;;; More various functions.
-If this variable is a list, and the list contains the element
-`not-score', long file names will not be used for score files; if it
-contains the element `not-save', long file names will not be used for
-saving; and if it contains the element `not-kill', long file names
-will not be used for kill files.")
+(defun gnus-group-read-only-p (&optional group)
+ "Check whether GROUP supports editing or not.
+If GROUP is nil, `gnus-newsgroup-name' will be checked instead. Note
+that that variable is buffer-local to the summary buffers."
+ (let ((group (or group gnus-newsgroup-name)))
+ (not (gnus-check-backend-function 'request-replace-article group))))
-(defvar gnus-article-save-directory gnus-directory
- "*Name of the directory articles will be saved in (default \"~/News\").")
+(defun gnus-group-total-expirable-p (group)
+ "Check whether GROUP is total-expirable or not."
+ (let ((params (gnus-group-find-parameter group)))
+ (or (memq 'total-expire params)
+ (cdr (assq 'total-expire params)) ; (total-expire . t)
+ (and gnus-total-expirable-newsgroups ; Check var.
+ (string-match gnus-total-expirable-newsgroups group)))))
-(defvar gnus-kill-files-directory gnus-directory
- "*Name of the directory where kill files will be stored (default \"~/News\").")
+(defun gnus-group-auto-expirable-p (group)
+ "Check whether GROUP is total-expirable or not."
+ (let ((params (gnus-group-find-parameter group)))
+ (or (memq 'auto-expire params)
+ (cdr (assq 'auto-expire params)) ; (auto-expire . t)
+ (and gnus-auto-expirable-newsgroups ; Check var.
+ (string-match gnus-auto-expirable-newsgroups group)))))
-(defvar gnus-default-article-saver 'gnus-summary-save-in-rmail
- "*A function to save articles in your favorite format.
-The function must be interactively callable (in other words, it must
-be an Emacs command).
+(defun gnus-virtual-group-p (group)
+ "Say whether GROUP is virtual or not."
+ (memq 'virtual (assoc (symbol-name (car (gnus-find-method-for-group group)))
+ gnus-valid-select-methods)))
-Gnus provides the following functions:
+(defun gnus-news-group-p (group &optional article)
+ "Return non-nil if GROUP (and ARTICLE) come from a news server."
+ (or (gnus-member-of-valid 'post group) ; Ordinary news group.
+ (and (gnus-member-of-valid 'post-mail group) ; Combined group.
+ (eq (gnus-request-type group article) 'news))))
-* gnus-summary-save-in-rmail (Rmail format)
-* gnus-summary-save-in-mail (Unix mail format)
-* gnus-summary-save-in-folder (MH folder)
-* gnus-summary-save-in-file (article format).
-* gnus-summary-save-in-vm (use VM's folder format).")
+;; Returns a list of writable groups.
+(defun gnus-writable-groups ()
+ (let ((alist gnus-newsrc-alist)
+ groups group)
+ (while (setq group (car (pop alist)))
+ (unless (gnus-group-read-only-p group)
+ (push group groups)))
+ (nreverse groups)))
-(defvar gnus-prompt-before-saving 'always
- "*This variable says how much prompting is to be done when saving articles.
-If it is nil, no prompting will be done, and the articles will be
-saved to the default files. If this variable is `always', each and
-every article that is saved will be preceded by a prompt, even when
-saving large batches of articles. If this variable is neither nil not
-`always', there the user will be prompted once for a file name for
-each invocation of the saving commands.")
+;; Check&nb