*** empty log message ***
[gnus] / lisp / gnus-group.el
index badef71..375865f 100644 (file)
@@ -1,7 +1,7 @@
 ;;; gnus-group.el --- group mode commands for Gnus
-;; Copyright (C) 1996,97 Free Software Foundation, Inc.
+;; Copyright (C) 1996,97,98 Free Software Foundation, Inc.
 
-;; Author: Lars Magne Ingebrigtsen <larsi@ifi.uio.no>
+;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: news
 
 ;; This file is part of GNU Emacs.
 (require 'gnus-undo)
 
 (defcustom gnus-group-archive-directory
-  "/ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list/"
+  "*ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list/"
   "*The address of the (ding) archives."
   :group 'gnus-group-foreign
   :type 'directory)
 
 (defcustom gnus-group-recent-archive-directory
-  "/ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list-recent/"
+  "*ftp@ftp.hpc.uh.edu:/pub/emacs/ding-list-recent/"
   "*The address of the most recent (ding) articles."
   :group 'gnus-group-foreign
   :type 'directory)
@@ -261,10 +261,13 @@ variable."
   :type 'hook)
 
 (defcustom gnus-useful-groups
-  `(("(ding) mailing list mirrored at sunsite.auc.dk"
+  '(("(ding) mailing list mirrored at sunsite.auc.dk"
      "emacs.ding"
      (nntp "sunsite.auc.dk"
-                       (nntp-address "sunsite.auc.dk")))
+          (nntp-address "sunsite.auc.dk")))
+    ("gnus-bug archive"
+     "gnus-bug"
+     (nndir "/ftp@ftp.ifi.uio.no:/pub/emacs/gnus/gnus-bug/"))
     ("Gnus help group"
      "gnus-help"
      (nndoc "gnus-help"
@@ -275,7 +278,7 @@ variable."
                       (unless file
                         (error "Couldn't find doc group"))
                       file))))))
-  "Alist of useful group-server pairs."
+  "*Alist of useful group-server pairs."
   :group 'gnus-group-listing
   :type '(repeat (list (string :tag "Description")
                       (string :tag "Name")
@@ -316,7 +319,7 @@ variable."
      gnus-group-mail-low-empty-face)
     (t .
      gnus-group-mail-low-face))
-  "Controls the highlighting of group buffer lines.
+  "*Controls the highlighting of group buffer lines.
 
 Below is a list of `Form'/`Face' pairs.  When deciding how a a
 particular group line should be displayed, each form is
@@ -708,7 +711,7 @@ ticked: The number of ticked articles."
         (fboundp 'gnus-soup-pack-packet)]
        ["Pack packet" gnus-soup-pack-packet (fboundp 'gnus-soup-pack-packet)]
        ["Save areas" gnus-soup-save-areas (fboundp 'gnus-soup-pack-packet)]
-       ["Brew SOUP" gnus-soup-brew-soup (fboundp 'gnus-soup-pack-packet)])
+       ["Brew SOUP" gnus-group-brew-soup (fboundp 'gnus-soup-pack-packet)])
        ["Send a bug report" gnus-bug t]
        ["Send a mail" gnus-group-mail t]
        ["Post an article..." gnus-group-post-news t]
@@ -727,10 +730,11 @@ ticked: The number of ticked articles."
        ["Read manual" gnus-info-find-node t]
        ["Flush score cache" gnus-score-flush-cache t]
        ["Toggle topics" gnus-topic-mode t]
+       ["Send a bug report" gnus-bug t]
        ["Exit from Gnus" gnus-group-exit t]
        ["Exit without saving" gnus-group-quit t]))
 
-    (run-hooks 'gnus-group-menu-hook)))
+    (gnus-run-hooks 'gnus-group-menu-hook)))
 
 (defun gnus-group-mode ()
   "Major mode for reading news.
@@ -769,11 +773,13 @@ The following commands are available:
   (add-hook 'post-command-hook 'gnus-clear-inboxes-moved nil t)
   (when gnus-use-undo
     (gnus-undo-mode 1))
-  (run-hooks 'gnus-group-mode-hook))
+  (when gnus-slave
+    (gnus-slave-mode))
+  (gnus-run-hooks 'gnus-group-mode-hook))
 
 (defun gnus-update-group-mark-positions ()
   (save-excursion
-    (let ((gnus-process-mark 128)
+    (let ((gnus-process-mark ?\200)
          (gnus-group-marked '("dummy.group"))
          (gnus-active-hashtb (make-vector 10 0))
          (topic ""))
@@ -812,9 +818,8 @@ The following commands are available:
     (or level gnus-group-default-list-level gnus-level-subscribed))))
 
 (defun gnus-group-setup-buffer ()
-  (set-buffer (get-buffer-create gnus-group-buffer))
+  (set-buffer (gnus-get-buffer-create gnus-group-buffer))
   (unless (eq major-mode 'gnus-group-mode)
-    (gnus-add-current-to-buffer-list)
     (gnus-group-mode)
     (when gnus-carpal
       (gnus-carpal-setup-buffer 'group))))
@@ -948,7 +953,7 @@ If REGEXP, only list groups matching REGEXP."
 
     (gnus-group-set-mode-line)
     (setq gnus-group-list-mode (cons level all))
-    (run-hooks 'gnus-group-prepare-hook)
+    (gnus-run-hooks 'gnus-group-prepare-hook)
     t))
 
 (defun gnus-group-prepare-flat-list-dead (groups level mark regexp)
@@ -1090,7 +1095,7 @@ If REGEXP, only list groups matching REGEXP."
                  gnus-level ,gnus-tmp-level))
     (when (inline (gnus-visual-p 'group-highlight 'highlight))
       (forward-line -1)
-      (run-hooks 'gnus-group-update-hook)
+      (gnus-run-hooks 'gnus-group-update-hook)
       (forward-line))
     ;; Allow XEmacs to remove front-sticky text properties.
     (gnus-group-remove-excess-properties)))
@@ -1124,7 +1129,7 @@ If REGEXP, only list groups matching REGEXP."
       (setq list (cdr list)))
     (let ((face (cdar list)))
       (unless (eq face (get-text-property beg 'face))
-       (gnus-put-text-property
+       (gnus-put-text-property-excluding-characters-with-faces
         beg end 'face
         (setq face (if (boundp face) (symbol-value face) face)))
        (gnus-extent-start-open beg)))
@@ -1147,7 +1152,8 @@ already."
            found buffer-read-only)
        ;; Enter the current status into the dribble buffer.
        (let ((entry (gnus-gethash group gnus-newsrc-hashtb)))
-         (when (and entry (not (gnus-ephemeral-group-p group)))
+         (when (and entry
+                    (not (gnus-ephemeral-group-p group)))
            (gnus-dribble-enter
             (concat "(gnus-group-set-info '"
                     (gnus-prin1-to-string (nth 2 entry))
@@ -1163,7 +1169,7 @@ already."
            (gnus-group-insert-group-line-info group)
            (save-excursion
              (forward-line -1)
-             (run-hooks 'gnus-group-update-group-hook)))
+             (gnus-run-hooks 'gnus-group-update-group-hook)))
          (setq loc (1+ loc)))
        (unless (or found visible-only)
          ;; No such line in the buffer, find out where it's supposed to
@@ -1185,7 +1191,7 @@ already."
            (gnus-group-insert-group-line-info group)
            (save-excursion
              (forward-line -1)
-             (run-hooks 'gnus-group-update-group-hook))))
+             (gnus-run-hooks 'gnus-group-update-group-hook))))
        (when gnus-group-update-group-function
          (funcall gnus-group-update-group-function group))
        (gnus-group-set-mode-line)))
@@ -1231,7 +1237,8 @@ already."
 (defun gnus-group-group-name ()
   "Get the name of the newsgroup on the current line."
   (let ((group (get-text-property (gnus-point-at-bol) 'gnus-group)))
-    (and group (symbol-name group))))
+    (when group
+      (symbol-name group))))
 
 (defun gnus-group-group-level ()
   "Get the level of the newsgroup on the current line."
@@ -1446,6 +1453,8 @@ Take into consideration N (the prefix) and the list of marked groups."
     (let ((group (gnus-group-group-name)))
       (and group (list group))))))
 
+;;; !!!Surely gnus-group-iterate should be a macro instead?  I can't
+;;; imagine why I went through these contortions...
 (eval-and-compile
   (let ((function (make-symbol "gnus-group-iterate-function"))
        (window (make-symbol "gnus-group-iterate-window"))
@@ -1465,12 +1474,12 @@ and with point over the group in question."
            (save-selected-window
              (save-excursion
                (funcall ,function ,group)))))))))
-  
+
 (put 'gnus-group-iterate 'lisp-indent-function 1)
 
 ;; Selecting groups.
 
-(defun gnus-group-read-group (&optional all no-article group)
+(defun gnus-group-read-group (&optional all no-article group select-articles)
   "Read news in this newsgroup.
 If the prefix argument ALL is non-nil, already read articles become
 readable.  IF ALL is a number, fetch this number of articles.  If the
@@ -1501,7 +1510,7 @@ group."
                                          (cdr (assq 'tick marked)))
                                  (gnus-range-length
                                   (cdr (assq 'dormant marked)))))))
-     no-article nil no-display)))
+     no-article nil no-display nil select-articles)))
 
 (defun gnus-group-select-group (&optional all)
   "Select this newsgroup.
@@ -1547,10 +1556,6 @@ be permanent."
         gnus-summary-mode-hook gnus-select-group-hook
         (group (gnus-group-group-name))
         (method (gnus-find-method-for-group group)))
-    (setq method
-         `(,(car method) ,(concat (cadr method) "-ephemeral")
-           (,(intern (format "%s-address" (car method))) ,(cadr method))
-           ,@(cddr method)))
     (gnus-group-read-ephemeral-group
      (gnus-group-prefixed-name group method) method)))
 
@@ -1563,30 +1568,41 @@ Returns whether the fetching was successful or not."
     (gnus-no-server))
   (gnus-group-read-group nil nil group))
 
+;;;###autoload
+(defun gnus-fetch-group-other-frame (group)
+  "Pop up a frame and enter GROUP."
+  (interactive "P")
+  (let ((window (get-buffer-window gnus-group-buffer)))
+    (cond (window
+          (select-frame (window-frame window)))
+         ((= (length (frame-list)) 1)
+          (select-frame (make-frame)))
+         (t
+          (other-frame 1))))
+  (gnus-fetch-group group))
+
 (defvar gnus-ephemeral-group-server 0)
 
 ;; Enter a group that is not in the group buffer.  Non-nil is returned
 ;; if selection was successful.
 (defun gnus-group-read-ephemeral-group (group method &optional activate
-                                             quit-config request-only)
+                                             quit-config request-only
+                                             select-articles)
   "Read GROUP from METHOD as an ephemeral group.
 If ACTIVATE, request the group first.
 If QUIT-CONFIG, use that window configuration when exiting from the
 ephemeral group.
 If REQUEST-ONLY, don't actually read the group; just request it.
+If SELECT-ARTICLES, only select those articles.
 
 Return the name of the group is selection was successful."
   ;; Transform the select method into a unique server.
   (when (stringp method)
     (setq method (gnus-server-to-method method)))
-  (let ((saddr (intern (format "%s-address" (car method)))))
-    (setq method (gnus-copy-sequence method))
-    (require (car method))
-    (when (boundp saddr)
-      (unless (assq saddr method)
-       (nconc method `((,saddr ,(cadr method))))
-       (setf (cadr method) (format "%s-%d" (cadr method)
-                                   (incf gnus-ephemeral-group-server))))))
+  (setq method
+       `(,(car method) ,(concat (cadr method) "-ephemeral")
+         (,(intern (format "%s-address" (car method))) ,(cadr method))
+         ,@(cddr method)))
   (let ((group (if (gnus-group-foreign-p group) group
                 (gnus-group-prefixed-name group method))))
     (gnus-sethash
@@ -1598,6 +1614,7 @@ Return the name of the group is selection was successful."
                                (cons gnus-summary-buffer
                                      gnus-current-window-configuration))))))
      gnus-newsrc-hashtb)
+    (push method gnus-ephemeral-servers)
     (set-buffer gnus-group-buffer)
     (unless (gnus-check-server method)
       (error "Unable to contact server: %s" (gnus-status-message method)))
@@ -1609,7 +1626,7 @@ Return the name of the group is selection was successful."
     (if request-only
        group
       (condition-case ()
-         (when (gnus-group-read-group t t group)
+         (when (gnus-group-read-group t t group select-articles)
            group)
        ;;(error nil)
        (quit nil)))))
@@ -1784,6 +1801,8 @@ ADDRESS."
     (gnus-read-group "Group name: ")
     (gnus-read-method "From method: ")))
 
+  (when (stringp method)
+    (setq method (gnus-server-to-method method)))
   (let* ((meth (when (and method
                          (not (gnus-server-equal method gnus-select-method)))
                 (if address (list (intern method) address)
@@ -1896,6 +1915,9 @@ and NEW-NAME will be prompted for."
        (gnus-set-active new-name (gnus-active group))
        (gnus-message 6 "Renaming group %s to %s...done" group new-name)
        new-name)
+    (setq gnus-killed-list (delete group gnus-killed-list))
+    (gnus-set-active group nil)
+    (gnus-dribble-touch)
     (gnus-group-position-point)))
 
 (defun gnus-group-edit-group (group &optional part)
@@ -1974,6 +1996,7 @@ and NEW-NAME will be prompted for."
     (gnus-group-position-point)))
 
 (defun gnus-group-make-useful-group (group method)
+  "Create one of the groups described in `gnus-useful-groups'."
   (interactive
    (let ((entry (assoc (completing-read "Create group: " gnus-useful-groups
                                        nil t)
@@ -1989,8 +2012,7 @@ and NEW-NAME will be prompted for."
   "Create the Gnus documentation group."
   (interactive)
   (let ((name (gnus-group-prefixed-name "gnus-help" '(nndoc "gnus-help")))
-       (file (nnheader-find-etc-directory "gnus-tut.txt" t))
-       dir)
+       (file (nnheader-find-etc-directory "gnus-tut.txt" t)))
     (when (gnus-gethash name gnus-newsrc-hashtb)
       (error "Documentation group already exists"))
     (if (not file)
@@ -2133,7 +2155,7 @@ score file entries for articles to include in the group."
        (push (cons header regexps) scores))
       scores)))
   (gnus-group-make-group group "nnkiboze" address)
-  (nnheader-temp-write (gnus-score-file-name (concat "nnkiboze:" group))
+  (with-temp-file (gnus-score-file-name (concat "nnkiboze:" group))
     (let (emacs-lisp-mode-hook)
       (pp scores (current-buffer)))))
 
@@ -2383,7 +2405,7 @@ If REVERSE, sort in reverse order."
        (when (gnus-group-native-p (gnus-info-group info))
          (gnus-info-clear-data info)))
       (gnus-get-unread-articles)
-      (gnus-dribble-enter "")
+      (gnus-dribble-touch)
       (when (gnus-y-or-n-p
             "Move the cache away to avoid problems in the future? ")
        (call-interactively 'gnus-cache-move-cache)))))
@@ -2477,7 +2499,7 @@ or nil if no action could be taken."
          (gnus-add-marked-articles group 'tick nil nil 'force)
          (gnus-add-marked-articles group 'dormant nil nil 'force))
        (let ((gnus-newsgroup-name group))
-         (run-hooks 'gnus-group-catchup-group-hook))
+         (gnus-run-hooks 'gnus-group-catchup-group-hook))
        num))))
 
 (defun gnus-group-expire-articles (&optional n)
@@ -2710,7 +2732,8 @@ of groups killed."
                (delq (assoc group gnus-newsrc-alist)
                      gnus-newsrc-alist))
          (when gnus-group-change-level-function
-           (funcall gnus-group-change-level-function group gnus-level-killed 3))
+           (funcall gnus-group-change-level-function
+                    group gnus-level-killed 3))
          (cond
           ((setq entry (gnus-gethash group gnus-newsrc-hashtb))
            (push (cons (car entry) (nth 2 entry))
@@ -2727,11 +2750,10 @@ of groups killed."
     (if (< (length out) 2) (car out) (nreverse out))))
 
 (defun gnus-group-yank-group (&optional arg)
-  "Yank the last newsgroups killed with \\[gnus-group-kill-group],
-inserting it before the current newsgroup.  The numeric ARG specifies
-how many newsgroups are to be yanked.  The name of the newsgroup yanked
-is returned, or (if several groups are yanked) a list of yanked groups
-is returned."
+  "Yank the last newsgroups killed with \\[gnus-group-kill-group], inserting it before the current newsgroup.
+The numeric ARG specifies how many newsgroups are to be yanked.  The
+name of the newsgroup yanked is returned, or (if several groups are
+yanked) a list of yanked groups is returned."
   (interactive "p")
   (setq arg (or arg 1))
   (let (info group prev out)
@@ -2867,7 +2889,7 @@ re-scanning.  If ARG is non-nil and not a number, this will force
 \"hard\" re-reading of the active files from all servers."
   (interactive "P")
   (let ((gnus-inhibit-demon t))
-    (run-hooks 'gnus-get-new-news-hook)
+    (gnus-run-hooks 'gnus-get-new-news-hook)
 
     ;; Read any slave files.
     (unless gnus-slave
@@ -2894,7 +2916,7 @@ re-scanning.  If ARG is non-nil and not a number, this will force
          (gnus-get-unread-articles arg))
       (let ((gnus-read-active-file (if arg nil gnus-read-active-file)))
        (gnus-get-unread-articles arg)))
-    (run-hooks 'gnus-after-getting-new-news-hook)
+    (gnus-run-hooks 'gnus-after-getting-new-news-hook)
     (gnus-group-list-groups (and (numberp arg)
                                 (max (car gnus-group-list-mode) arg)))))
 
@@ -2907,17 +2929,19 @@ If N is negative, this group and the N-1 previous groups will be checked."
         (ret (if (numberp n) (- n (length groups)) 0))
         (beg (unless n
                (point)))
-        group)
+        group method)
     (while (setq group (pop groups))
       (gnus-group-remove-mark group)
       ;; Bypass any previous denials from the server.
-      (gnus-remove-denial (gnus-find-method-for-group group))
+      (gnus-remove-denial (setq method (gnus-find-method-for-group group)))
       (if (gnus-activate-group group (if dont-scan nil 'scan))
          (progn
            (gnus-get-unread-articles-in-group
             (gnus-get-info group) (gnus-active group) t)
            (unless (gnus-virtual-group-p group)
              (gnus-close-group group))
+           (gnus-agent-save-group-info
+            method (gnus-group-real-name group) (gnus-active group))
            (gnus-group-update-group group))
        (if (eq (gnus-server-status (gnus-find-method-for-group group))
                'denied)
@@ -2951,8 +2975,6 @@ to use."
     (while (and (not found)
                (setq dir (pop dirs)))
       (let ((name (gnus-group-real-name group)))
-       (while (string-match "\\." name)
-         (setq name (replace-match "/" t t name)))
        (setq file (concat (file-name-as-directory dir) name)))
       (if (not (file-exists-p file))
          (gnus-message 1 "No such file: %s" file)
@@ -3018,6 +3040,7 @@ to use."
      (lambda (group)
        (and (symbol-name group)
            (string-match regexp (symbol-name group))
+           (symbol-value group)
            (push (symbol-name group) groups)))
      gnus-active-hashtb)
     ;; Also go through all descriptions that are known to Gnus.
@@ -3118,12 +3141,14 @@ group."
 (defun gnus-group-find-new-groups (&optional arg)
   "Search for new groups and add them.
 Each new group will be treated with `gnus-subscribe-newsgroup-method.'
-If ARG (the prefix), use the `ask-server' method to query
-the server for new groups."
-  (interactive "P")
-  (gnus-find-new-newsgroups arg)
+With 1 C-u, use the `ask-server' method to query the server for new
+groups.
+With 2 C-u's, use most complete method possible to query the server
+for new groups, and subscribe the new groups as zombies."
+  (interactive "p")
+  (gnus-find-new-newsgroups (or arg 1))
   (gnus-group-list-groups))
-  
+
 (defun gnus-group-edit-global-kill (&optional article group)
   "Edit the global kill file.
 If GROUP, edit that local kill file instead."
@@ -3151,18 +3176,15 @@ If GROUP, edit that local kill file instead."
 In fact, cleanup buffers except for group mode buffer.
 The hook gnus-suspend-gnus-hook is called before actually suspending."
   (interactive)
-  (run-hooks 'gnus-suspend-gnus-hook)
+  (gnus-run-hooks 'gnus-suspend-gnus-hook)
   ;; Kill Gnus buffers except for group mode buffer.
-  (let* ((group-buf (get-buffer gnus-group-buffer))
-        ;; Do this on a separate list in case the user does a ^G before we finish
-        (gnus-buffer-list
-         (delete group-buf (delete gnus-dribble-buffer
-                                   (append gnus-buffer-list nil)))))
-    (while gnus-buffer-list
-      (gnus-kill-buffer (pop gnus-buffer-list)))
+  (let ((group-buf (get-buffer gnus-group-buffer)))
+    (mapcar (lambda (buf)
+             (unless (member buf (list group-buf gnus-dribble-buffer))
+               (kill-buffer buf)))
+           (gnus-buffers))
     (gnus-kill-gnus-frames)
     (when group-buf
-      (setq gnus-buffer-list (list group-buf))
       (bury-buffer group-buf)
       (delete-windows-on group-buf t))))
 
@@ -3181,7 +3203,7 @@ The hook `gnus-exit-gnus-hook' is called before actually exiting."
          (not gnus-interactive-exit)   ;Without confirmation
          gnus-expert-user
          (gnus-y-or-n-p "Are you sure you want to quit reading news? "))
-    (run-hooks 'gnus-exit-gnus-hook)
+    (gnus-run-hooks 'gnus-exit-gnus-hook)
     ;; Offer to save data from non-quitted summary buffers.
     (gnus-offer-save-summaries)
     ;; Save the newsrc file(s).
@@ -3191,7 +3213,7 @@ The hook `gnus-exit-gnus-hook' is called before actually exiting."
     ;; Reset everything.
     (gnus-clear-system)
     ;; Allow the user to do things after cleaning up.
-    (run-hooks 'gnus-after-exiting-gnus-hook)))
+    (gnus-run-hooks 'gnus-after-exiting-gnus-hook)))
 
 (defun gnus-group-quit ()
   "Quit reading news without updating .newsrc.eld or .newsrc.
@@ -3205,14 +3227,14 @@ The hook `gnus-exit-gnus-hook' is called before actually exiting."
            (gnus-yes-or-no-p
             (format "Quit reading news without saving %s? "
                     (file-name-nondirectory gnus-current-startup-file))))
-    (run-hooks 'gnus-exit-gnus-hook)
+    (gnus-run-hooks 'gnus-exit-gnus-hook)
     (gnus-configure-windows 'group t)
     (gnus-dribble-save)
     (gnus-close-backends)
     (gnus-clear-system)
     (gnus-kill-buffer gnus-group-buffer)
     ;; Allow the user to do things after cleaning up.
-    (run-hooks 'gnus-after-exiting-gnus-hook)))
+    (gnus-run-hooks 'gnus-after-exiting-gnus-hook)))
 
 (defun gnus-group-describe-briefly ()
   "Give a one line description of the group mode commands."
@@ -3309,7 +3331,6 @@ and the second element is the address."
   ;; If INFO is non-nil, use that info.         If FORCE is non-nil, don't
   ;; add, but replace marked articles of TYPE with ARTICLES.
   (let ((info (or info (gnus-get-info group)))
-       (uncompressed '(score bookmark killed))
        marked m)
     (or (not info)
        (and (not (setq marked (nthcdr 3 info)))
@@ -3325,7 +3346,7 @@ and the second element is the address."
        (if force
            (if (null articles)
                (setcar (nthcdr 3 info)
-                       (delq (assq type (car marked)) (car marked)))
+                       (gnus-delete-alist type (car marked)))
              (setcdr m (gnus-compress-sequence articles t)))
          (setcdr m (gnus-compress-sequence
                     (sort (nconc (gnus-uncompress-range (cdr m))
@@ -3346,13 +3367,13 @@ or `gnus-group-catchup-group-hook'."
 
 (defsubst gnus-group-timestamp (group)
   "Return the timestamp for GROUP."
-  (gnus-group-get-parameter group 'timestamp))
+  (gnus-group-get-parameter group 'timestamp t))
 
 (defun gnus-group-timestamp-delta (group)
   "Return the offset in seconds from the timestamp for GROUP to the current time, as a floating point number."
   (let* ((time (or (gnus-group-timestamp group)
                  (list 0 0)))
-         (delta (gnus-time-minus (current-time) time)))
+         (delta (subtract-time (current-time) time)))
     (+ (* (nth 0 delta) 65536.0)
        (nth 1 delta))))