Fix doc.
[gnus] / lisp / message.el
index f35b9a3..3c465b1 100644 (file)
@@ -1,27 +1,25 @@
 ;;; message.el --- composing mail and news messages
 
 ;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-;;   2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+;;   2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
 
 ;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
 ;; Keywords: mail, news
 
 ;; This file is part of GNU Emacs.
 
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.         See the
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 ;; GNU General Public License for more details.
 
 ;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-;; Boston, MA 02110-1301, USA.
+;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -443,6 +441,14 @@ nil means let mailer mail back a message to report errors."
   :link '(custom-manual "(message)Sending Variables")
   :type 'boolean)
 
+(defcustom message-confirm-send nil
+  "When non-nil, ask for confirmation when sending a message."
+  :group 'message-sending
+  :group 'message-mail
+  :version "23.1" ;; No Gnus
+  :link '(custom-manual "(message)Sending Variables")
+  :type 'boolean)
+
 (defcustom message-generate-new-buffers 'unique
   "*Say whether to create a new message buffer to compose a message.
 Valid values include:
@@ -1018,7 +1024,6 @@ Used by `message-yank-original' via `message-yank-cite'."
   :link '(custom-manual "(message)Insertion Variables")
   :type 'integer)
 
-;;;###autoload
 (defcustom message-cite-function 'message-cite-original-without-signature
   "*Function for citing an original message.
 Predefined functions include `message-cite-original' and
@@ -1312,6 +1317,7 @@ starting with `not' and followed by regexps."
   :group 'message-faces)
 ;; backward-compatibility alias
 (put 'message-header-to-face 'face-alias 'message-header-to)
+(put 'message-header-to-face 'obsolete-face "22.1")
 
 (defface message-header-cc
   '((((class color)
@@ -1326,6 +1332,7 @@ starting with `not' and followed by regexps."
   :group 'message-faces)
 ;; backward-compatibility alias
 (put 'message-header-cc-face 'face-alias 'message-header-cc)
+(put 'message-header-cc-face 'obsolete-face "22.1")
 
 (defface message-header-subject
   '((((class color)
@@ -1340,6 +1347,7 @@ starting with `not' and followed by regexps."
   :group 'message-faces)
 ;; backward-compatibility alias
 (put 'message-header-subject-face 'face-alias 'message-header-subject)
+(put 'message-header-subject-face 'obsolete-face "22.1")
 
 (defface message-header-newsgroups
   '((((class color)
@@ -1354,6 +1362,7 @@ starting with `not' and followed by regexps."
   :group 'message-faces)
 ;; backward-compatibility alias
 (put 'message-header-newsgroups-face 'face-alias 'message-header-newsgroups)
+(put 'message-header-newsgroups-face 'obsolete-face "22.1")
 
 (defface message-header-other
   '((((class color)
@@ -1368,6 +1377,7 @@ starting with `not' and followed by regexps."
   :group 'message-faces)
 ;; backward-compatibility alias
 (put 'message-header-other-face 'face-alias 'message-header-other)
+(put 'message-header-other-face 'obsolete-face "22.1")
 
 (defface message-header-name
   '((((class color)
@@ -1382,6 +1392,7 @@ starting with `not' and followed by regexps."
   :group 'message-faces)
 ;; backward-compatibility alias
 (put 'message-header-name-face 'face-alias 'message-header-name)
+(put 'message-header-name-face 'obsolete-face "22.1")
 
 (defface message-header-xheader
   '((((class color)
@@ -1396,6 +1407,7 @@ starting with `not' and followed by regexps."
   :group 'message-faces)
 ;; backward-compatibility alias
 (put 'message-header-xheader-face 'face-alias 'message-header-xheader)
+(put 'message-header-xheader-face 'obsolete-face "22.1")
 
 (defface message-separator
   '((((class color)
@@ -1410,6 +1422,7 @@ starting with `not' and followed by regexps."
   :group 'message-faces)
 ;; backward-compatibility alias
 (put 'message-separator-face 'face-alias 'message-separator)
+(put 'message-separator-face 'obsolete-face "22.1")
 
 (defface message-cited-text
   '((((class color)
@@ -1424,6 +1437,7 @@ starting with `not' and followed by regexps."
   :group 'message-faces)
 ;; backward-compatibility alias
 (put 'message-cited-text-face 'face-alias 'message-cited-text)
+(put 'message-cited-text-face 'obsolete-face "22.1")
 
 (defface message-mml
   '((((class color)
@@ -1438,6 +1452,7 @@ starting with `not' and followed by regexps."
   :group 'message-faces)
 ;; backward-compatibility alias
 (put 'message-mml-face 'face-alias 'message-mml)
+(put 'message-mml-face 'obsolete-face "22.1")
 
 (defun message-font-lock-make-header-matcher (regexp)
   (let ((form
@@ -1795,33 +1810,31 @@ You must have the \"hashcash\" binary installed, see `hashcash-path'."
   :group 'message-headers
   :type 'regexp)
 
-(eval-and-compile
-  (autoload 'gnus-alive-p "gnus-util")
-  (autoload 'gnus-delay-article "gnus-delay")
-  (autoload 'gnus-extract-address-components "gnus-util")
-  (autoload 'gnus-find-method-for-group "gnus")
-  (autoload 'gnus-group-decoded-name "gnus-group")
-  (autoload 'gnus-group-name-charset "gnus-group")
-  (autoload 'gnus-group-name-decode "gnus-group")
-  (autoload 'gnus-groups-from-server "gnus")
-  (autoload 'gnus-make-local-hook "gnus-util")
-  (autoload 'gnus-open-server "gnus-int")
-  (autoload 'gnus-output-to-mail "gnus-util")
-  (autoload 'gnus-output-to-rmail "gnus-util")
-  (autoload 'gnus-request-post "gnus-int")
-  (autoload 'gnus-select-frame-set-input-focus "gnus-util")
-  (autoload 'gnus-server-string "gnus")
-  (autoload 'idna-to-ascii "idna")
-  (autoload 'message-setup-toolbar "messagexmas")
-  (autoload 'mh-new-draft-name "mh-comp")
-  (autoload 'mh-send-letter "mh-comp")
-  (autoload 'nndraft-request-associate-buffer "nndraft")
-  (autoload 'nndraft-request-expire-articles "nndraft")
-  (autoload 'nnvirtual-find-group-art "nnvirtual")
-  (autoload 'rmail-dont-reply-to "mail-utils")
-  (autoload 'rmail-msg-is-pruned "rmail")
-  (autoload 'rmail-msg-restore-non-pruned-header "rmail")
-  (autoload 'rmail-output "rmailout"))
+(autoload 'gnus-alive-p "gnus-util")
+(autoload 'gnus-delay-article "gnus-delay")
+(autoload 'gnus-extract-address-components "gnus-util")
+(autoload 'gnus-find-method-for-group "gnus")
+(autoload 'gnus-group-decoded-name "gnus-group")
+(autoload 'gnus-group-name-charset "gnus-group")
+(autoload 'gnus-group-name-decode "gnus-group")
+(autoload 'gnus-groups-from-server "gnus")
+(autoload 'gnus-make-local-hook "gnus-util")
+(autoload 'gnus-open-server "gnus-int")
+(autoload 'gnus-output-to-mail "gnus-util")
+(autoload 'gnus-output-to-rmail "gnus-util")
+(autoload 'gnus-request-post "gnus-int")
+(autoload 'gnus-select-frame-set-input-focus "gnus-util")
+(autoload 'gnus-server-string "gnus")
+(autoload 'idna-to-ascii "idna")
+(autoload 'message-setup-toolbar "messagexmas")
+(autoload 'mh-new-draft-name "mh-comp")
+(autoload 'mh-send-letter "mh-comp")
+(autoload 'nndraft-request-associate-buffer "nndraft")
+(autoload 'nndraft-request-expire-articles "nndraft")
+(autoload 'nnvirtual-find-group-art "nnvirtual")
+(autoload 'rmail-dont-reply-to "mail-utils")
+(autoload 'rmail-msg-is-pruned "rmail")
+(autoload 'rmail-output "rmailout")
 
 \f
 
@@ -2391,6 +2404,8 @@ Return the number of headers removed."
      (point-max)))
   (goto-char (point-min)))
 
+;; FIXME: clarify diffference: message-narrow-to-head,
+;; message-narrow-to-headers-or-head, message-narrow-to-headers
 (defun message-narrow-to-head ()
   "Narrow the buffer to the head of the message.
 Point is left at the beginning of the narrowed-to region."
@@ -3966,6 +3981,9 @@ It should typically alter the sending method in some way or other."
     (put-text-property (point-min) (point-max) 'read-only nil))
   (message-fix-before-sending)
   (run-hooks 'message-send-hook)
+  (when message-confirm-send
+    (or (y-or-n-p "Send message? ")
+       (keyboard-quit)))
   (message message-sending-message)
   (let ((alist message-send-method-alist)
        (success t)
@@ -4063,11 +4081,32 @@ not have PROP."
        (setq start next)))
     (nreverse regions)))
 
-(defcustom message-bogus-address-regexp nil ;; "noreply\\|nospam\\|invalid"
-  "Regexp of potentially bogus mail addresses."
+(defcustom message-bogus-addresses
+  ;; '("noreply" "nospam" "invalid")
+  '("noreply" "nospam" "invalid" "@@" "[^[:ascii:]].*@" "[ \t]")
+  "List of regexps of potentially bogus mail addresses.
+See `message-check-recipients' how to setup checking.
+
+This list should make it possible to catch typos or warn about
+spam-trap addresses.  It doesn't aim to verify strict RFC
+conformance."
   :version "23.1" ;; No Gnus
   :group 'message-headers
-  :type 'regexp)
+  :type '(choice
+         (const :tag "None" nil)
+         (list
+          (set :inline t
+               (const "noreply")
+               (const "nospam")
+               (const "invalid")
+               (const :tag "duplicate @" "@@")
+               (const :tag "non-ascii local part" "[^[:ascii:]].*@")
+               ;; Already caught by `message-valid-fqdn-regexp'
+               ;; (const :tag "`_' in domain part" "@.*_")
+               (const :tag "whitespace" "[ \t]"))
+          (repeat :inline t
+                  :tag "Other"
+                  (regexp)))))
 
 (defun message-fix-before-sending ()
   "Do various things to make the message nice before sending it."
@@ -4112,6 +4151,8 @@ not have PROP."
                  (and (mm-multibyte-p)
                       (memq (char-charset char)
                             '(eight-bit-control eight-bit-graphic
+                                                ;; Emacs 23, Bug#1770:
+                                                eight-bit
                                                 control-1))
                       (not (get-text-property
                             (point) 'untranslated-utf-8))))
@@ -4138,10 +4179,13 @@ not have PROP."
                  (or (< (mm-char-int char) 128)
                      (and (mm-multibyte-p)
                           ;; FIXME: Wrong for Emacs 23 (unicode) and for
-                          ;; things like undecable utf-8.  Should at least
-                          ;; use find-coding-systems-region.
+                          ;; things like undecodable utf-8 (in Emacs 21?).
+                          ;; Should at least use find-coding-systems-region.
+                          ;; -- fx
                           (memq (char-charset char)
                                 '(eight-bit-control eight-bit-graphic
+                                                    ;; Emacs 23, Bug#1770:
+                                                    eight-bit
                                                     control-1))
                           (not (get-text-property
                                 (point) 'untranslated-utf-8)))))
@@ -4153,7 +4197,7 @@ not have PROP."
          (forward-char)
          (skip-chars-forward mm-7bit-chars)))))
   (message-check 'bogus-recipient
-    ;; Warn before composing or sending a mail to an invalid address.
+    ;; Warn before sending a mail to an invalid address.
     (message-check-recipients)))
 
 (defun message-bogus-recipient-p (recipients)
@@ -4162,9 +4206,9 @@ not have PROP."
 RECIPIENTS is a mail header.  Return a list of potentially bogus
 addresses.  If none is found, return nil.
 
-An addresses might be bogus if the domain part is not fully
-qualified, see `message-valid-fqdn-regexp', or if it matches
-`message-bogus-address-regexp'."
+An address might be bogus if the domain part is not fully
+qualified, see `message-valid-fqdn-regexp', or if there's a
+matching entry in `message-bogus-addresses'."
   ;; FIXME: How about "foo@subdomain", when the MTA adds ".domain.tld"?
   (let (found)
     (mapc (lambda (address)
@@ -4176,9 +4220,15 @@ qualified, see `message-valid-fqdn-regexp', or if it matches
                      (string-match
                       (concat ".@.*\\("
                               message-valid-fqdn-regexp "\\)\\'") address)))
-                   (and (stringp message-bogus-address-regexp)
-                        (string-match message-bogus-address-regexp address)))
-             (push address found)))
+                   (and message-bogus-addresses
+                        (let ((re
+                               (if (listp message-bogus-addresses)
+                                   (mapconcat 'identity
+                                              message-bogus-addresses
+                                              "\\|")
+                                 message-bogus-addresses)))
+                          (string-match re address))))
+                        (push address found)))
          ;;
          (mail-extract-address-components recipients t))
     found))
@@ -4200,6 +4250,8 @@ This function could be useful in `message-setup-hook'."
                        "Address `%s' might be bogus.  Continue? " bog)))
                 (error "Bogus address."))))))))
 
+(custom-add-option 'message-setup-hook 'message-check-recipients)
+
 (defun message-add-action (action &rest types)
   "Add ACTION to be performed when doing an exit of type TYPES."
   (while types
@@ -4289,9 +4341,8 @@ This function could be useful in `message-setup-hook'."
              (end-of-line)
              (insert (format " (%d/%d)" n total))
              (widen)
-             (mm-with-unibyte-current-buffer
-               (funcall (or message-send-mail-real-function
-                            message-send-mail-function))))
+              (funcall (or message-send-mail-real-function
+                           message-send-mail-function)))
            (setq n (+ n 1))
            (setq p (pop plist))
            (erase-buffer)))
@@ -4393,6 +4444,11 @@ This function could be useful in `message-setup-hook'."
                                  (message-fetch-field
                                   "content-transfer-encoding")))))))
            (message-insert-courtesy-copy))
+          ;; Let's make sure we encoded all the body.
+          (assert (save-excursion
+                    (goto-char (point-min))
+                    (not (re-search-forward "[^\000-\377]" nil t))))
+          (mm-disable-multibyte)
          (if (or (not message-send-mail-partially-limit)
                  (< (buffer-size) message-send-mail-partially-limit)
                  (not (message-y-or-n-p
@@ -4417,7 +4473,7 @@ The size limit is controlled by `message-send-mail-partially-limit'.
 If you always want Gnus to send messages in one piece, set
 `message-send-mail-partially-limit' to nil.
 ")))
-             (mm-with-unibyte-current-buffer
+             (progn
                (message "Sending via mail...")
                (funcall (or message-send-mail-real-function
                             message-send-mail-function)))
@@ -4490,6 +4546,7 @@ If you always want Gnus to send messages in one piece, set
                            (list resend-to-addresses)
                          '("-t"))))))
            (unless (or (null cpr) (and (numberp cpr) (zerop cpr)))
+              (if errbuf (pop-to-buffer errbuf))
              (error "Sending...failed with exit value %d" cpr)))
          (when message-interactive
            (with-current-buffer errbuf
@@ -4518,7 +4575,7 @@ to find out how to use this."
        (apply
         'call-process-region (point-min) (point-max)
         message-qmail-inject-program nil nil nil
-        ;; qmail-inject's default behaviour is to look for addresses on the
+        ;; qmail-inject's default behavior is to look for addresses on the
         ;; command line; if there're none, it scans the headers.
         ;; yes, it does The Right Thing w.r.t. Resent-To and it's kin.
         ;;
@@ -5078,17 +5135,24 @@ Otherwise, generate and save a value for `canlock-password' first."
        nil)))
    ;; Check the length of the signature.
    (message-check 'signature
-     (goto-char (point-max))
-     (if (not (re-search-backward message-signature-separator nil t))
-        t
-       (if (>= (count-lines (1+ (point-at-eol)) (point-max)) 5)
-          (if (message-gnksa-enable-p 'signature)
-              (y-or-n-p
-               (format "Signature is excessively long (%d lines).  Really post? "
-                       (count-lines (1+ (point-at-eol)) (point-max))))
-            (message "Denied posting -- Excessive signature.")
-            nil)
-        t)))
+     (let (sig-start sig-end)
+       (goto-char (point-max))
+       (if (not (re-search-backward message-signature-separator nil t))
+          t
+        (setq sig-start (1+ (point-at-eol)))
+        (setq sig-end
+              (if (re-search-forward
+                   "<#/?\\(multipart\\|part\\|external\\|mml\\)" nil t)
+                  (- (point-at-bol) 1)
+                (point-max)))
+        (if (>= (count-lines sig-start sig-end) 5)
+            (if (message-gnksa-enable-p 'signature)
+                (y-or-n-p
+                 (format "Signature is excessively long (%d lines).  Really post? "
+                         (count-lines sig-start sig-end)))
+              (message "Denied posting -- Excessive signature.")
+              nil)
+          t))))
    ;; Ensure that text follows last quoted portion.
    (message-check 'quoting-style
      (goto-char (point-max))
@@ -5167,6 +5231,13 @@ Otherwise, generate and save a value for `canlock-password' first."
            (if (and message-fcc-handler-function
                     (not (eq message-fcc-handler-function 'rmail-output)))
                (funcall message-fcc-handler-function file)
+             ;; FIXME this option, rmail-output (also used if
+             ;; message-fcc-handler-function is nil) is not
+             ;; documented anywhere AFAICS.  It should work in Emacs
+             ;; 23; I suspect it does not work in Emacs 22.
+             ;; FIXME I don't see the need for the two different cases here.
+             ;; mail-use-rfc822 makes no difference (in Emacs 23),and
+             ;; the third argument just controls \"Wrote file\" message.
              (if (and (file-readable-p file) (mail-file-babyl-p file))
                  (rmail-output file 1 nil t)
                (let ((mail-use-rfc822 t))
@@ -5270,7 +5341,7 @@ In posting styles use `(\"Expires\" (make-expires-date 30))'."
           (* 25 25)))
   (let ((tm (current-time)))
     (concat
-     (if (or (memq system-type '(ms-dos emx vax-vms))
+     (if (or (memq system-type '(ms-dos emx))
             ;; message-number-base36 doesn't handle bigints.
             (floatp (user-uid)))
         (let ((user (downcase (user-login-name))))
@@ -5596,8 +5667,11 @@ subscribed address (and not the additional To and Cc header contents)."
                (mapcar (lambda (rhs) (or (cadr (split-string rhs "@")) ""))
                        (mapcar 'downcase
                                (mapcar
-                                'car (mail-header-parse-addresses field))))))
-       (setq ace (if (string-match "\\`[[:ascii:]]+\\'" rhs)
+                                'cadr
+                                (mail-extract-address-components field t))))))
+       ;; Note that `rhs' will be "" if the address does not have
+       ;; the domain part, i.e., if it is a local user's address.
+       (setq ace (if (string-match "\\`[[:ascii:]]*\\'" rhs)
                      rhs
                    (downcase (idna-to-ascii rhs))))
        (when (and (not (equal rhs ace))
@@ -5619,7 +5693,13 @@ See `message-idna-encode'."
   (when message-use-idna
     (save-excursion
       (save-restriction
-       (message-narrow-to-head)
+       ;; `message-narrow-to-head' that recognizes only the first empty
+       ;; line as the message header separator used to be used here.
+       ;; However, since there is the "--text follows this line--" line
+       ;; normally, it failed in narrowing to the headers and potentially
+       ;; caused the IDNA encoding on lines that look like headers in
+       ;; the message body.
+       (message-narrow-to-headers-or-head)
        (message-idna-to-ascii-rhs-1 "From")
        (message-idna-to-ascii-rhs-1 "To")
        (message-idna-to-ascii-rhs-1 "Reply-To")
@@ -6260,13 +6340,22 @@ are not included."
     (if (gnus-alive-p)
        (setq message-draft-article
              (nndraft-request-associate-buffer "drafts"))
+
+      ;; If Gnus were alive, draft messages would be saved in the drafts folder.
+      ;; But Gnus is not alive, so arrange to save the draft message in a
+      ;; regular file in message-auto-save-directory.  Append a unique
+      ;; time-based suffix to the filename to allow multiple drafts to be saved
+      ;; simultaneously without overwriting each other (which mimics the
+      ;; functionality of the Gnus drafts folder).
       (setq buffer-file-name (expand-file-name
+                             (concat
                              (if (memq system-type
                                        '(ms-dos ms-windows windows-nt
                                                 cygwin cygwin32 win32 w32
                                                 mswindows))
                                  "message"
                                "*message*")
+                              (format-time-string "-%Y%m%d-%H%M%S"))
                              message-auto-save-directory))
       (setq buffer-auto-save-file-name (make-auto-save-file-name)))
     (clear-visited-file-modtime)
@@ -6276,7 +6365,7 @@ are not included."
   "Disassociate the message buffer from the drafts directory."
   (when message-draft-article
     (nndraft-request-expire-articles
-     (list message-draft-article) "nndraft:drafts" nil t)))
+     (list message-draft-article) "drafts" nil t)))
 
 (defun message-insert-headers ()
   "Generate the headers for the article."
@@ -6832,14 +6921,13 @@ header line with the old Message-ID."
   (interactive)
   (let ((file-name (make-auto-save-file-name)))
     (cond ((save-window-excursion
-            (if (not (eq system-type 'vax-vms))
-                (with-output-to-temp-buffer "*Directory*"
-                  (with-current-buffer standard-output
-                    (fundamental-mode)) ; for Emacs 20.4+
-                  (buffer-disable-undo standard-output)
-                  (let ((default-directory "/"))
-                    (call-process
-                     "ls" nil standard-output nil "-l" file-name))))
+            (with-output-to-temp-buffer "*Directory*"
+              (with-current-buffer standard-output
+                (fundamental-mode))    ; for Emacs 20.4+
+              (buffer-disable-undo standard-output)
+              (let ((default-directory "/"))
+                (call-process
+                 "ls" nil standard-output nil "-l" file-name)))
             (yes-or-no-p (format "Recover auto save file %s? " file-name)))
           (let ((buffer-read-only nil))
             (erase-buffer)
@@ -7081,9 +7169,8 @@ Optional DIGEST will use digest to forward."
       (message-forward-make-body-digest-mime forward-buffer)
     (message-forward-make-body-digest-plain forward-buffer)))
 
-(eval-and-compile
-  (autoload 'mm-uu-dissect-text-parts "mm-uu")
-  (autoload 'mm-uu-dissect "mm-uu"))
+(autoload 'mm-uu-dissect-text-parts "mm-uu")
+(autoload 'mm-uu-dissect "mm-uu")
 
 (defun message-signed-or-encrypted-p (&optional dont-emulate-mime handles)
   "Say whether the current buffer contains signed or encrypted message.
@@ -7161,12 +7248,16 @@ is for the internal use."
       (message-forward-make-body-plain forward-buffer)))
   (message-position-point))
 
+(declare-function rmail-toggle-header "rmail" (&optional arg))
+
 ;;;###autoload
 (defun message-forward-rmail-make-body (forward-buffer)
   (save-window-excursion
     (set-buffer forward-buffer)
     (if (rmail-msg-is-pruned)
-       (rmail-msg-restore-non-pruned-header)))
+       (if (fboundp 'rmail-msg-restore-non-pruned-header)
+           (rmail-msg-restore-non-pruned-header) ; Emacs 22
+         (rmail-toggle-header 0))))              ; Emacs 23
   (message-forward-make-body forward-buffer))
 
 ;; Fixme: Should have defcustom.