Synch to No Gnus 200504221124.
[elisp/gnus.git-] / lisp / gnus-msg.el
index 6d2e1b0..88069e1 100644 (file)
@@ -1,6 +1,6 @@
 ;;; gnus-msg.el --- mail and post interface for Semi-gnus
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
-;;        Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+;;        2005 Free Software Foundation, Inc.
 
 ;; Author: Masanobu UMEDA <umerin@flab.flab.fujitsu.junet>
 ;;     Lars Magne Ingebrigtsen <larsi@gnus.org>
@@ -168,7 +168,7 @@ See Info node `(gnus)Posting Styles'."
 
 (defcustom gnus-gcc-mark-as-read nil
   "If non-nil, automatically mark Gcc articles as read."
-  :version "21.1"
+  :version "22.1"
   :group 'gnus-message
   :type 'boolean)
 
@@ -180,7 +180,7 @@ See Info node `(gnus)Posting Styles'."
 If it is `all', attach files as external parts;
 if a regexp and matches the Gcc group name, attach files as external parts;
 if nil, attach files as normal parts."
-  :version "21.1"
+  :version "22.1"
   :group 'gnus-message
   :type '(choice (const nil :tag "None")
                 (const all :tag "Any")
@@ -238,7 +238,7 @@ List of charsets that are permitted to be unencoded.")
     "gnus-agent.el" "gnus-cache.el" "gnus-srvr.el"
     "mm-util.el" "mm-decode.el" "nnmail.el" "nntp.el" "message.el")
   "Files whose variables will be reported in `gnus-bug'."
-  :version "21.1"
+  :version "22.1"
   :group 'gnus-message
   :type '(repeat (string :tag "File")))
 
@@ -246,7 +246,7 @@ List of charsets that are permitted to be unencoded.")
   '(mm-mime-mule-charset-alist
     nnmail-split-fancy message-minibuffer-local-map)
   "Variables that should not be reported in `gnus-bug'."
-  :version "21.1"
+  :version "22.1"
   :group 'gnus-message
   :type '(repeat (symbol :tag "Variable")))
 
@@ -254,7 +254,7 @@ List of charsets that are permitted to be unencoded.")
   '(nndraft nnml nnimap nnmaildir nnmh nnfolder nndir)
   "A list of back ends that are not used in \"real\" newsgroups.
 This variable is used only when `gnus-post-method' is `current'."
-  :version "21.3"
+  :version "22.1"
   :group 'gnus-group-foreign
   :type '(repeat (symbol :tag "Back end")))
 
@@ -274,11 +274,12 @@ See also the `mml-default-encrypt-method' variable."
 
 (defcustom gnus-message-replysignencrypted
   t
-  "Setting this causes automatically encryped messages to also be signed."
+  "Setting this causes automatically encrypted messages to also be signed."
   :group 'gnus-message
   :type 'boolean)
 
-(defcustom gnus-confirm-mail-reply-to-news nil
+(defcustom gnus-confirm-mail-reply-to-news (and gnus-novice-user
+                                               (not gnus-expert-user))
   "If non-nil, Gnus requests confirmation when replying to news.
 This is done because new users often reply by mistake when reading
 news.
@@ -286,6 +287,7 @@ This can also be a function receiving the group name as the only
 parameter which should return non-nil iff a confirmation is needed, or
 a regexp, in which case a confirmation is asked for iff the group name
 matches the regexp."
+  :version "22.1"
   :group 'gnus-message
   :type '(choice (const :tag "No" nil)
                 (const :tag "Yes" t)
@@ -298,6 +300,7 @@ matches the regexp."
 when replying by mail.  See the `gnus-confirm-mail-reply-to-news' variable
 for fine-tuning this.
 If nil, Gnus will never ask for confirmation if replying to mail."
+  :version "22.1"
   :group 'gnus-message
   :type 'boolean)
 
@@ -305,27 +308,10 @@ If nil, Gnus will never ask for confirmation if replying to mail."
   "If non-nil, Gnus tries to suggest a default address to resend to.
 If nil, the address field will always be empty after invoking
 `gnus-summary-resend-message'."
+  :version "22.1"
   :group 'gnus-message
   :type 'boolean)
 
-(defcustom gnus-user-agent 'emacs-gnus-type
-  "Which information should be exposed in the User-Agent header.
-
-It can be one of the symbols `gnus' \(show only Gnus version\), `emacs-gnus'
-\(show only Emacs and Gnus versions\), `emacs-gnus-config' \(same as
-`emacs-gnus' plus system configuration\), `emacs-gnus-type' \(same as
-`emacs-gnus' plus system type\) or a custom string.  If you set it to a
-string, be sure to use a valid format, see RFC 2616."
-  :group 'gnus-message
-  :type '(choice
-         (item :tag "Show Gnus and Emacs versions and system type"
-               emacs-gnus-type)
-         (item :tag "Show Gnus and Emacs versions and system configuration"
-               emacs-gnus-config)
-         (item :tag "Show Gnus and Emacs versions" emacs-gnus)
-         (item :tag "Show only Gnus version" gnus)
-         (string :tag "Other")))
-
 ;;; Internal variables.
 
 (defvar gnus-inhibit-posting-styles nil
@@ -372,11 +358,7 @@ Thank you for your help in stamping out bugs.
            ", a modified version of Semi-gnus")))
 
 (eval-and-compile
-  (autoload 'gnus-uu-post-news "gnus-uu" nil t)
-  (autoload 'news-setup "rnewspost")
-  (autoload 'news-reply-mode "rnewspost")
-  (autoload 'rmail-dont-reply-to "mail-utils")
-  (autoload 'rmail-output "rmailout"))
+  (autoload 'gnus-uu-post-news "gnus-uu" nil t))
 
 \f
 ;;;
@@ -418,10 +400,10 @@ Thank you for your help in stamping out bugs.
 
 ;;; Internal functions.
 
-(defun gnus-inews-make-draft ()
+(defun gnus-inews-make-draft (articles)
   `(lambda ()
      (gnus-inews-make-draft-meta-information
-      ,gnus-newsgroup-name ',gnus-article-reply)))
+      ,gnus-newsgroup-name ',articles)))
 
 (defvar gnus-article-reply nil)
 (defmacro gnus-setup-message (config &rest forms)
@@ -452,15 +434,20 @@ Thank you for your help in stamping out bugs.
        ;; added an optional argument to `gnus-configure-posting-styles' to
        ;; make sure that the correct value for the group name is used. -- drv
        (add-hook 'message-mode-hook
-                (lambda ()
-                  (gnus-configure-posting-styles ,group)))
+                (if (memq ,config '(reply-yank reply))
+                    (lambda ()
+                      (gnus-configure-posting-styles ,group))
+                  (lambda ()
+                    ;; There may be an old " *gnus article copy*" buffer.
+                    (let (gnus-article-copy)
+                      (gnus-configure-posting-styles ,group)))))
        (gnus-pull ',(intern gnus-draft-meta-information-header)
                  message-required-headers)
        (when (and ,group
                  (not (string= ,group "")))
         (push (cons
                (intern gnus-draft-meta-information-header)
-               (gnus-inews-make-draft))
+               (gnus-inews-make-draft (or ,yanked ,article)))
               message-required-headers))
        (unwind-protect
           (progn
@@ -479,12 +466,20 @@ Thank you for your help in stamping out bugs.
        (run-hooks 'post-command-hook)
        (set-buffer-modified-p nil))))
 
-(defun gnus-inews-make-draft-meta-information (group article)
-  (concat "(\"" group "\" "
-         (if article (number-to-string
-                      (if (listp article)
-                          (car article)
-                        article)) "\"\"")
+(defun gnus-inews-make-draft-meta-information (group articles)
+  (when (numberp articles)
+    (setq articles (list articles)))
+  (concat "(\"" group "\""
+         (if articles
+             (concat " "
+                     (mapconcat
+                      (lambda (elem)
+                        (number-to-string
+                         (if (consp elem)
+                             (car elem)
+                           elem)))
+                      articles " "))
+           "")
          ")"))
 
 ;;;###autoload
@@ -559,14 +554,16 @@ Gcc: header for archiving purposes."
   (setq message-post-method
        `(lambda (arg)
           (gnus-post-method arg ,gnus-newsgroup-name)))
-  (setq message-user-agent (gnus-extended-version))
+  (setq message-user-agent (gnus-message-make-user-agent))
   (unless message-use-multi-frames
     (message-add-action
      `(if (gnus-buffer-exists-p ,buffer)
          (set-window-configuration ,winconf))
      'exit 'postpone 'kill))
   (let ((to-be-marked (cond
-                      (yanked yanked)
+                      (yanked
+                       (mapcar
+                        (lambda (x) (if (listp x) (car x) x)) yanked))
                       (article (if (listp article) article (list article)))
                       (t nil))))
     (message-add-action
@@ -618,7 +615,7 @@ If ARG is 1, prompt for group name to post to.
 
 This function prepares a news even when using mail groups.  This is useful
 for posting messages to mail groups without actually sending them over the
-network.  The corresponding backend must have a 'request-post method."
+network.  The corresponding back end must have a 'request-post method."
   (interactive "P")
   ;; We can't `let' gnus-newsgroup-name here, since that leads
   ;; to local variables leaking.
@@ -697,7 +694,7 @@ If ARG, don't do that.  If ARG is 1, prompt for group name to post to.
 
 This function prepares a news even when using mail groups.  This is useful
 for posting messages to mail groups without actually sending them over the
-network.  The corresponding backend must have a 'request-post method."
+network.  The corresponding back end must have a 'request-post method."
   (interactive "P")
   ;; We can't `let' gnus-newsgroup-name here, since that leads
   ;; to local variables leaking.
@@ -720,9 +717,9 @@ network.  The corresponding backend must have a 'request-post method."
            (progn
              (message-news (gnus-group-real-name gnus-newsgroup-name))
              (set (make-local-variable 'gnus-discouraged-post-methods)
-                  (delq
+                  (remove
                    (car (gnus-find-method-for-group gnus-newsgroup-name))
-                   (copy-sequence gnus-discouraged-post-methods))))))
+                   gnus-discouraged-post-methods)))))
       (save-excursion
        (set-buffer buffer)
        (setq gnus-newsgroup-name group)))))
@@ -751,8 +748,7 @@ a news."
 If prefix argument YANK is non-nil, the original article is yanked
 automatically.
 YANK is a list of elements, where the car of each element is the
-article number, and the two following numbers is the region to be
-yanked."
+article number, and the cdr is the string to be yanked."
   (interactive
    (list (and current-prefix-arg
              (gnus-summary-work-articles 1))))
@@ -772,7 +768,9 @@ yanked."
     (gnus-summary-handle-replysign)))
 
 (defun gnus-summary-followup-with-original (n &optional force-news)
-  "Compose a followup to an article and include the original article."
+  "Compose a followup to an article and include the original article.
+The text in the region will be yanked.  If the region isn't
+active, the entire article will be yanked."
   (interactive "P")
   (gnus-summary-followup (gnus-summary-work-articles n) force-news))
 
@@ -840,8 +838,7 @@ yanked."
         (list (or (assq 'References message-header-format-alist)
                   '(References . message-shorten-references)))
         (list (cons 'References
-                    (mapconcat 'identity (nreverse refs) " "))))
-       (backward-delete-char 1))
+                    (mapconcat 'identity (nreverse refs) " ")))))
       (setq beg (mark t))
       (pop-mark))
 
@@ -853,12 +850,10 @@ Uses the process-prefix convention.  If given the symbolic
 prefix `a', cancel using the standard posting method; if not
 post using the current select method."
   (interactive (gnus-interactive "P\ny"))
-  (let ((articles (gnus-summary-work-articles n))
-       (message-post-method
+  (let ((message-post-method
         `(lambda (arg)
-           (gnus-post-method (eq ',symp 'a) ,gnus-newsgroup-name)))
-       article)
-    (while (setq article (pop articles))
+           (gnus-post-method (eq ',symp 'a) ,gnus-newsgroup-name))))
+    (dolist (article (gnus-summary-work-articles n))
       (when (gnus-summary-select-article t nil nil article)
        (when (gnus-eval-in-buffer-window gnus-article-buffer
                (save-excursion
@@ -1008,7 +1003,9 @@ header line with the old Message-ID."
                     (not to-address)))
            ;; This is news.
            (if post
-               (message-news (or to-group group))
+               (message-news
+                (or to-group
+                    (and (not (gnus-virtual-group-p pgroup)) group)))
              (set-buffer gnus-article-copy)
              (gnus-msg-treat-broken-reply-to)
              (message-followup (if (or newsgroup-p force-news)
@@ -1122,35 +1119,14 @@ If SILENT, don't prompt the user."
      (t gnus-select-method))))
 
 \f
-(defun gnus-message-make-user-agent (&optional include-mime-info max-column
-                                                newline-product)
-  "Return a user-agent info.  If INCLUDE-MIME-INFO is non-nil and the
-variable `mime-edit-user-agent-value' is bound, the value will be
-included in the return value.  If MAX-COLUMN is specified, the return
+(defun gnus-message-make-user-agent (&optional dummy max-column
+                                              newline-product)
+  "Return a user-agent info.  If MAX-COLUMN is specified, the return
 value will be folded up as it were filled.  NEWLINE-PRODUCT specifies
-whether a newline should be inserted in front of each product-token.
-If the value is t or `hard', it works strictly.  Otherwise, if it is
-non-nil (e.g. `soft'), it works semi-strictly.
-
-Here is an example of how to use this function:
-
-\(add-hook 'gnus-message-setup-hook
-         (lambda nil
-           (setq message-user-agent nil)
-           (save-excursion
-             (save-restriction
-               (message-narrow-to-headers)
-               (goto-char (point-max))
-               (insert \"User-Agent: \"
-                       (gnus-message-make-user-agent t 76 'soft)
-                       \"\\n\")))))
-"
-  (let ((user-agent (if (and include-mime-info
-                            (boundp 'mime-edit-user-agent-value))
-                       (concat (gnus-extended-version)
-                               " "
-                               mime-edit-user-agent-value)
-                     (gnus-extended-version))))
+whether a newline should be inserted in front of each product-token;
+if the value is t or `hard', it works strictly.  Otherwise, if it is
+non-nil (e.g. `soft'), it works semi-strictly."
+  (let ((user-agent (gnus-extended-version)))
     (when max-column
       (unless (natnump max-column)
        (setq max-column 76))
@@ -1226,7 +1202,7 @@ If VERY-WIDE, make a very wide reply."
              (gnus-summary-work-articles 1))))
   ;; Allow user to require confirmation before replying by mail to the
   ;; author of a news article (or mail message).
-  (when (or 
+  (when (or
            (not (or (gnus-news-group-p gnus-newsgroup-name)
                     gnus-confirm-treat-mail-like-news))
            (not (cond ((stringp gnus-confirm-mail-reply-to-news)
@@ -1439,14 +1415,12 @@ forward those articles instead."
            (with-current-buffer gnus-original-article-buffer
              (nnmail-fetch-field "to"))))
         current-prefix-arg))
-  (let ((articles (gnus-summary-work-articles n))
-       article)
-    (while (setq article (pop articles))
-      (gnus-summary-select-article nil nil nil article)
-      (save-excursion
-       (set-buffer gnus-original-article-buffer)
-       (message-resend address))
-      (gnus-summary-mark-article-as-forwarded article))))
+  (dolist (article (gnus-summary-work-articles n))
+    (gnus-summary-select-article nil nil nil article)
+    (save-excursion
+      (set-buffer gnus-original-article-buffer)
+      (message-resend address))
+    (gnus-summary-mark-article-as-forwarded article)))
 
 ;; From: Matthieu Moy <Matthieu.Moy@imag.fr>
 (defun gnus-summary-resend-message-edit ()
@@ -1494,8 +1468,8 @@ composing a new message."
        (goto-char (point-max))
        (insert mail-header-separator)
        (goto-char (point-min))
-       (re-search-forward "^To:\\|^Newsgroups:" nil 'move)
-       (forward-char 1)
+       (when (re-search-forward "^To:\\|^Newsgroups:" nil 'move)
+         (forward-char 1))
        (widen)))))
 
 (defun gnus-summary-post-forward (&optional full-headers)
@@ -1525,37 +1499,35 @@ The current group name will be inserted at \"%s\".")
 (defun gnus-summary-mail-crosspost-complaint (n)
   "Send a complaint about crossposting to the current article(s)."
   (interactive "P")
-  (let ((articles (gnus-summary-work-articles n))
-       article)
-    (while (setq article (pop articles))
-      (set-buffer gnus-summary-buffer)
-      (gnus-summary-goto-subject article)
-      (let ((group (gnus-group-real-name gnus-newsgroup-name))
-           newsgroups followup-to)
-       (gnus-summary-select-article)
-       (set-buffer gnus-original-article-buffer)
-       (if (and (<= (length (message-tokenize-header
-                             (setq newsgroups
-                                   (mail-fetch-field "newsgroups"))
-                             ", "))
-                    1)
-                (or (not (setq followup-to (mail-fetch-field "followup-to")))
-                    (not (member group (message-tokenize-header
-                                        followup-to ", ")))))
-           (if followup-to
-               (gnus-message 1 "Followup-to restricted")
-             (gnus-message 1 "Not a crossposted article"))
-         (set-buffer gnus-summary-buffer)
-         (gnus-summary-reply-with-original 1)
-         (set-buffer gnus-message-buffer)
-         (message-goto-body)
-         (insert (format gnus-crosspost-complaint newsgroups group))
-         (message-goto-subject)
-         (re-search-forward " *$")
-         (replace-match " (crosspost notification)" t t)
-         (gnus-deactivate-mark)
-         (when (gnus-y-or-n-p "Send this complaint? ")
-           (message-send-and-exit)))))))
+  (dolist (article (gnus-summary-work-articles n))
+    (set-buffer gnus-summary-buffer)
+    (gnus-summary-goto-subject article)
+    (let ((group (gnus-group-real-name gnus-newsgroup-name))
+         newsgroups followup-to)
+      (gnus-summary-select-article)
+      (set-buffer gnus-original-article-buffer)
+      (if (and (<= (length (message-tokenize-header
+                           (setq newsgroups
+                                 (mail-fetch-field "newsgroups"))
+                           ", "))
+                  1)
+              (or (not (setq followup-to (mail-fetch-field "followup-to")))
+                  (not (member group (message-tokenize-header
+                                      followup-to ", ")))))
+         (if followup-to
+             (gnus-message 1 "Followup-to restricted")
+           (gnus-message 1 "Not a crossposted article"))
+       (set-buffer gnus-summary-buffer)
+       (gnus-summary-reply-with-original 1)
+       (set-buffer gnus-message-buffer)
+       (message-goto-body)
+       (insert (format gnus-crosspost-complaint newsgroups group))
+       (message-goto-subject)
+       (re-search-forward " *$")
+       (replace-match " (crosspost notification)" t t)
+       (gnus-deactivate-mark)
+       (when (gnus-y-or-n-p "Send this complaint? ")
+         (message-send-and-exit))))))
 
 (defun gnus-mail-parse-comma-list ()
   (let (accumulated
@@ -1591,7 +1563,7 @@ The current group name will be inserted at \"%s\".")
       ;; This mail group doesn't have a `to-list', so we add one
       ;; here.  Magic!
       (when (gnus-y-or-n-p
-            (format "Do you want to add this as `to-list': %s " to-address))
+            (format "Do you want to add this as `to-list': %s? " to-address))
        (gnus-group-add-parameter group (cons 'to-list to-address))))))
 
 (defun gnus-put-message ()
@@ -1604,7 +1576,7 @@ The current group name will be inserted at \"%s\".")
                 (not (gnus-group-read-only-p group)))
       (setq group (read-string "Put in group: " nil (gnus-writable-groups))))
 
-    (when (gnus-gethash group gnus-newsrc-hashtb)
+    (when (gnus-group-entry group)
       (error "No such group: %s" group))
     (save-excursion
       (save-restriction
@@ -1762,20 +1734,21 @@ The source file has to be in the Emacs load path."
     (while olist
       (if (boundp (car olist))
          (ignore-errors
-           (pp `(setq ,(car olist)
-                      ,(if (or (consp (setq sym (symbol-value (car olist))))
-                               (and (symbolp sym)
-                                    (not (or (eq sym nil)
-                                             (eq sym t)))))
-                           (list 'quote (symbol-value (car olist)))
-                         (symbol-value (car olist))))
-               (current-buffer)))
+          (gnus-pp
+           `(setq ,(car olist)
+                  ,(if (or (consp (setq sym (symbol-value (car olist))))
+                           (and (symbolp sym)
+                                (not (or (eq sym nil)
+                                         (eq sym t)))))
+                       (list 'quote (symbol-value (car olist)))
+                     (symbol-value (car olist))))))
        (insert ";; (makeunbound '" (symbol-name (car olist)) ")\n"))
       (setq olist (cdr olist)))
     ;; Remove any control chars - they seem to cause trouble for some
     ;; mailers.  (Byte-compiled output from the stuff above.)
     (goto-char point)
-    (while (re-search-forward "[\000-\010\013-\037\200-\237]" nil t)
+    (while (re-search-forward (string-as-multibyte
+                              "[\000-\010\013-\037\200-\237]") nil t)
       (replace-match (format "\\%03o" (string-to-char (match-string 0)))
                     t t))
     ;; Break MIME tags purposely.
@@ -1789,7 +1762,7 @@ The source file has to be in the Emacs load path."
 
 (defun gnus-summary-resend-bounced-mail (&optional fetch)
   "Re-mail the current message.
-This only makes sense if the current message is a bounce message than
+This only makes sense if the current message is a bounce message that
 contains some mail you have written which has been bounced back to
 you.
 If FETCH, try to fetch the article that this is a reply to, if indeed
@@ -1830,7 +1803,6 @@ this is a reply."
       (message-narrow-to-headers)
       (let ((gcc (or gcc (mail-fetch-field "gcc" nil t)))
            (coding-system-for-write 'raw-text)
-           (output-coding-system 'raw-text)
            groups group method group-art
            mml-externalize-attachments)
        (when gcc
@@ -1859,11 +1831,13 @@ this is a reply."
                     (concat "^" (regexp-quote mail-header-separator) "$")
                     nil t)
                (replace-match "" t t ))
-             (unless (setq group-art
-                           (gnus-request-accept-article group method t t))
+             (when (or (not (gnus-check-backend-function
+                             'request-accept-article group))
+                       (not (setq group-art
+                                  (gnus-request-accept-article
+                                   group method t t))))
                (gnus-message 1 "Couldn't store article in group %s: %s"
-                             group (gnus-status-message method))
-               (sit-for 2))
+                             group (gnus-status-message method)))
              (when (and group-art
                         ;; FIXME: Should gcc-mark-as-read work when
                         ;; Gnus is not running?
@@ -1960,9 +1934,14 @@ this is a reply."
                     (if (string-match " " gcc-self-val)
                         (concat "\"" gcc-self-val "\"")
                       gcc-self-val)
-                  (if (string-match " " group)
-                      (concat "\"" group "\"")
-                    group)))
+                  ;; In nndoc groups, we use the parent group name
+                  ;; instead of the current group.
+                  (let ((group (or (gnus-group-find-parameter
+                                    gnus-newsgroup-name 'parent-group)
+                                   group)))
+                    (if (string-match " " group)
+                        (concat "\"" group "\"")
+                      group))))
                (if (not (eq gcc-self-val 'none))
                    (insert "\n")
                  (gnus-delete-line)))
@@ -2017,9 +1996,11 @@ this is a reply."
                ;; Obsolete format of header match.
                (and (gnus-buffer-live-p gnus-article-copy)
                     (with-current-buffer gnus-article-copy
-                      (let ((header (message-fetch-field (pop style))))
-                        (and header
-                             (string-match (pop style) header))))))
+                      (save-restriction
+                        (nnheader-narrow-to-headers)
+                        (let ((header (message-fetch-field (pop style))))
+                          (and header
+                               (string-match (pop style) header)))))))
               ((or (symbolp match)
                    (functionp match))
                (cond
@@ -2035,9 +2016,11 @@ this is a reply."
                  ;; New format of header match.
                  (and (gnus-buffer-live-p gnus-article-copy)
                       (with-current-buffer gnus-article-copy
-                        (let ((header (message-fetch-field (nth 1 match))))
-                          (and header
-                               (string-match (nth 2 match) header))))))
+                        (save-restriction
+                          (nnheader-narrow-to-headers)
+                          (let ((header (message-fetch-field (nth 1 match))))
+                            (and header
+                                 (string-match (nth 2 match) header)))))))
                 (t
                  ;; This is a form to be evaled.
                  (eval match)))))
@@ -2144,10 +2127,12 @@ this is a reply."
       (when (and filep v)
        (setq v (with-temp-buffer
                  (insert-file-contents v)
-                 (goto-char (point-max))
-                 (while (bolp)
-                   (delete-char -1))
-                 (buffer-string))))
+                 (buffer-substring (point-min)
+                                   (progn
+                                     (goto-char (point-max))
+                                     (if (zerop (skip-chars-backward "\n"))
+                                         (point)
+                                       (1+ (point))))))))
       (if (eq element 'import)
          (progn
            (if (member v stack)