]> git.eshelyaron.com Git - emacs.git/commitdiff
Add new Tramp connection method "owncloud"
authorMichael Albinus <michael.albinus@gmx.de>
Fri, 5 Jan 2018 20:04:39 +0000 (21:04 +0100)
committerMichael Albinus <michael.albinus@gmx.de>
Fri, 5 Jan 2018 20:04:39 +0000 (21:04 +0100)
* doc/misc/tramp.texi (all): Use @acronym{GNOME} thoroughly.
(Using GNOME Online Accounts based methods): Rename from
"Using Google Drive".  Add `owncloud'.
(GVFS based methods): Add `owncloud'.

* etc/NEWS: Add Tramp connection method "owncloud".

* lisp/net/tramp-gvfs.el (tramp-gvfs-methods): Add "owncloud".
Remove goa methods if not supported.
(tramp-goa-methods, tramp-goa-service, tramp-goa-path)
(tramp-goa-path-accounts, tramp-goa-interface-documents)
(tramp-goa-interface-printers, tramp-goa-interface-files)
(tramp-goa-interface-contacts, tramp-goa-interface-calendar)
(tramp-goa-interface-oauth2based)
(tramp-goa-interface-account, tramp-goa-identity-regexp)
(tramp-goa-interface-mail, tramp-goa-interface-chat)
(tramp-goa-interface-photos, tramp-goa-path-manager)
(tramp-goa-interface-documents)
(tramp-gvfs-owncloud-default-prefix)
(tramp-gvfs-owncloud-default-prefix-regexp): New defconst.
(tramp-goa-name): New defstruct.
(tramp-gvfs-stringify-dbus-message): Handle all consp messages.
(tramp-dbus-function, tramp-gvfs-get-remote-prefix)
(tramp-get-goa-accounts): New defun.
(with-tramp-dbus-call-method): Use it.
(with-tramp-dbus-get-all-properties): New defmacro.
(tramp-gvfs-url-file-name)
(tramp-gvfs-handler-mounted-unmounted)
(tramp-gvfs-connection-mounted-p, tramp-gvfs-mount-spec):
Map between "owncloud" and "davs".
(tramp-gvfs-maybe-open-connection): Set "vector" connection property.

* test/lisp/net/tramp-tests.el (tramp-gvfs-handler-askquestion):
Suppress run in tests.
(tramp--test-owncloud-p): New defun.
(tramp-test11-copy-file, tramp-test12-rename-file): Use it.

doc/misc/tramp.texi
etc/NEWS
lisp/net/tramp-cache.el
lisp/net/tramp-gvfs.el
test/lisp/net/tramp-tests.el

index 4bfebc00af403b232d266c2a3f7e1613abbba77d..deaafb3d2571a33d6018e727ca397dc9a834a55e 100644 (file)
@@ -531,24 +531,33 @@ of the local file name is the share exported by the remote host,
 @cindex dav method
 @cindex davs method
 
-On systems, which have installed the virtual file system for the Gnome
-Desktop (GVFS), its offered methods could be used by @value{tramp}.
-Examples are @file{@trampfn{sftp,user@@host,/path/to/file}},
+On systems, which have installed the virtual file system for the
+@acronym{GNOME} Desktop (GVFS), its offered methods could be used by
+@value{tramp}.  Examples are
+@file{@trampfn{sftp,user@@host,/path/to/file}},
 @file{@trampfn{afp,user@@host,/path/to/file}} (accessing Apple's AFP
 file system), @file{@trampfn{dav,user@@host,/path/to/file}} and
 @file{@trampfn{davs,user@@host,/path/to/file}} (for WebDAV shares).
 
 
-@anchor{Quick Start Guide: Google Drive}
-@section Using Google Drive
+@anchor{Quick Start Guide: GNOME Online Accounts based methods}
+@section Using @acronym{GNOME} Online Accounts based methods
+@cindex @acronym{GNOME} Online Accounts
 @cindex method gdrive
 @cindex gdrive method
 @cindex google drive
+@cindex method owncloud
+@cindex owncloud method
+@cindex nextcloud
 
-Another GVFS-based method allows to access a Google Drive file system.
-The file name syntax is here always
-@file{@trampfn{gdrive,john.doe@@gmail.com,/path/to/file}}.
-@samp{john.doe@@gmail.com} stands here for your Google Drive account.
+GVFS-based methods include also @acronym{GNOME} Online Accounts, which
+support the @option{Files} service.  These are the Google Drive file
+system, and the OwnCloud/NextCloud file system.  The file name syntax
+is here always
+@file{@trampfn{gdrive,john.doe@@gmail.com,/path/to/file}}
+(@samp{john.doe@@gmail.com} stands here for your Google Drive
+account), or @file{@trampfn{owncloud,user@@host#8081,/path/to/file}}
+(@samp{8081} stands for the port number) for OwnCloud/NextCloud files.
 
 
 @anchor{Quick Start Guide: Android}
@@ -1061,7 +1070,7 @@ numbers are not applicable to Android devices connected through USB@.
 @cindex gvfs based methods
 @cindex dbus
 
-GVFS is the virtual file system for the Gnome Desktop,
+GVFS is the virtual file system for the @acronym{GNOME} Desktop,
 @uref{https://en.wikipedia.org/wiki/GVFS}.  Remote files on GVFS are
 mounted locally through FUSE and @value{tramp} uses this locally
 mounted directory internally.
@@ -1114,6 +1123,18 @@ directory have the same @code{display-name}, such a situation must be avoided.
 OBEX is an FTP-like access protocol for cell phones and similar simple
 devices.  @value{tramp} supports OBEX over Bluetooth.
 
+@item @option{owncloud}
+@cindex @acronym{GNOME} Online Accounts
+@cindex method owncloud
+@cindex owncloud method
+@cindex nextcloud
+
+As the name indicates, the method @option{owncloud} allows you to
+access OwnCloud or NextCloud hosted files and directories.  Like the
+@option{gdrive} method, your credentials must be populated in your
+@command{Online Accounts} application outside Emacs. The method
+supports port numbers.
+
 @item @option{sftp}
 @cindex method sftp
 @cindex sftp method
@@ -1135,11 +1156,11 @@ requires the SYNCE-GVFS plugin.
 @defopt tramp-gvfs-methods
 This user option is a list of external methods for GVFS@.  By default,
 this list includes @option{afp}, @option{dav}, @option{davs},
-@option{gdrive}, @option{obex}, @option{sftp} and @option{synce}.
-Other methods to include are @option{ftp}, @option{http},
-@option{https} and @option{smb}.  These methods are not intended to be
-used directly as GVFS based method.  Instead, they are added here for
-the benefit of @ref{Archive file names}.
+@option{gdrive}, @option{obex}, @option{owncloud}, @option{sftp} and
+@option{synce}.  Other methods to include are @option{ftp},
+@option{http}, @option{https} and @option{smb}.  These methods are not
+intended to be used directly as GVFS based method.  Instead, they are
+added here for the benefit of @ref{Archive file names}.
 @end defopt
 
 
@@ -2928,8 +2949,8 @@ that remote connection.
 
 @value{tramp} offers also transparent access to files inside file
 archives.  This is possible only on machines which have installed the
-virtual file system for the Gnome Desktop (GVFS), @ref{GVFS based
-methods}.  Internally, file archives are mounted via the GVFS
+virtual file system for the @acronym{GNOME} Desktop (GVFS), @ref{GVFS
+based methods}.  Internally, file archives are mounted via the GVFS
 @option{archive} method.
 
 A file archive is a regular file of kind @file{/path/to/dir/file.EXT}.
index 3ba95c1ff6120d61a219aafd0b7178ef4238bca9..c5a4bc3344b532ac2cbb22be32797872fdba564b 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -159,6 +159,12 @@ To restore the old behavior, use
     (add-hook 'eshell-expand-input-functions
               #'eshell-expand-history-references)
 
+** Tramp
+
++++
+*** New connection method "owncloud", which allows to access OwnCloud
+or NextCloud hosted files and directories.
+
 \f
 * New Modes and Packages in Emacs 27.1
 
index 844813936fb697866b7ead5a7b9a6cb11c51ac65..97c687598f2288b1dc704f1e1693a11d2169923c 100644 (file)
@@ -114,8 +114,7 @@ Returns DEFAULT if not set."
        (tramp-file-name-hop key) nil)
   (let* ((hash (tramp-get-hash-table key))
         (value (when (hash-table-p hash) (gethash property hash))))
-    (if
-       ;; We take the value only if there is any, and
+    (if ;; We take the value only if there is any, and
        ;; `remote-file-name-inhibit-cache' indicates that it is still
        ;; valid.  Otherwise, DEFAULT is set.
        (and (consp value)
index ef354b689503848bf4b4c74843ee5e921eef6888..7d63118268dc310a3bfeb3b44e4426bb9833ae90 100644 (file)
 
 ;; The custom option `tramp-gvfs-methods' contains the list of
 ;; supported connection methods.  Per default, these are "afp", "dav",
-;; "davs", "gdrive", "obex", "sftp" and "synce".  Note that with
-;; "obex" it might be necessary to pair with the other bluetooth
-;; device, if it hasn't been done already.  There might be also some
-;; few seconds delay in discovering available bluetooth devices.
+;; "davs", "gdrive", "obex", "owncloud", "sftp" and "synce".  Note
+;; that with "obex" it might be necessary to pair with the other
+;; bluetooth device, if it hasn't been done already.  There might be
+;; also some few seconds delay in discovering available bluetooth
+;; devices.
+
+;; "gdrive" and "owncloud" connection methods require a respective
+;; account in GNOME Online Accounts, with enabled "Files" service.
 
 ;; Other possible connection methods are "ftp", "http", "https" and
 ;; "smb".  When one of these methods is added to the list, the remote
 
 ;;;###tramp-autoload
 (defcustom tramp-gvfs-methods
-  '("afp" "dav" "davs" "gdrive" "obex" "sftp" "synce")
+  '("afp" "dav" "davs" "gdrive" "obex" "owncloud" "sftp" "synce")
   "List of methods for remote files, accessed with GVFS."
   :group 'tramp
   :version "26.1"
                         (const "http")
                         (const "https")
                         (const "obex")
+                        (const "owncloud")
                         (const "sftp")
                         (const "smb")
                         (const "synce")))
   :require 'tramp)
 
+(defconst tramp-goa-methods '("gdrive" "owncloud")
+  "List of methods which require registration at GNOME Online Accounts.")
+
+;; Remove GNOME Online Accounts if not supported.
+(unless (member tramp-goa-service (dbus-list-known-names :session))
+  (dolist (method tramp-goa-methods)
+    (setq tramp-gvfs-methods (delete method tramp-gvfs-methods))))
+
 ;; Add defaults for `tramp-default-user-alist' and `tramp-default-host-alist'.
 ;;;###tramp-autoload
 (when (string-match "\\(.+\\)@\\(\\(?:gmail\\|googlemail\\)\\.com\\)"
@@ -293,6 +306,162 @@ It has been changed in GVFS 1.14.")
 (defconst tramp-gvfs-password-anonymous-supported 16
   "Operation supports anonymous users.")
 
+;; For the time being, we just need org.goa.Account and org.goa.Files
+;; interfaces.  We document the other ones, just in case.
+
+;;;###tramp-autoload
+(defconst tramp-goa-service "org.gnome.OnlineAccounts"
+  "The well known name of the GNOME Online Accounts service.")
+
+(defconst tramp-goa-path "/org/gnome/OnlineAccounts"
+  "The object path of the GNOME Online Accounts.")
+
+(defconst tramp-goa-path-accounts (concat tramp-goa-path "/Accounts")
+  "The object path of the GNOME Online Accounts accounts.")
+
+(defconst tramp-goa-interface-documents "org.gnome.OnlineAccounts.Documents"
+  "The documents interface of the GNOME Online Accounts.")
+
+;; <interface name='org.gnome.OnlineAccounts.Documents'>
+;; </interface>
+
+(defconst tramp-goa-interface-printers "org.gnome.OnlineAccounts.Printers"
+  "The printers interface of the GNOME Online Accounts.")
+
+;; <interface name='org.gnome.OnlineAccounts.Printers'>
+;; </interface>
+
+(defconst tramp-goa-interface-files "org.gnome.OnlineAccounts.Files"
+  "The files interface of the GNOME Online Accounts.")
+
+;; <interface name='org.gnome.OnlineAccounts.Files'>
+;;   <property type='b' name='AcceptSslErrors' access='read'/>
+;;   <property type='s' name='Uri' access='read'/>
+;; </interface>
+
+(defconst tramp-goa-interface-contacts "org.gnome.OnlineAccounts.Contacts"
+  "The contacts interface of the GNOME Online Accounts.")
+
+;; <interface name='org.gnome.OnlineAccounts.Contacts'>
+;;   <property type='b' name='AcceptSslErrors' access='read'/>
+;;   <property type='s' name='Uri' access='read'/>
+;; </interface>
+
+(defconst tramp-goa-interface-calendar "org.gnome.OnlineAccounts.Calendar"
+  "The calendar interface of the GNOME Online Accounts.")
+
+;; <interface name='org.gnome.OnlineAccounts.Calendar'>
+;;   <property type='b' name='AcceptSslErrors' access='read'/>
+;;   <property type='s' name='Uri' access='read'/>
+;; </interface>
+
+(defconst tramp-goa-interface-oauth2based "org.gnome.OnlineAccounts.OAuth2Based"
+  "The oauth2based interface of the GNOME Online Accounts.")
+
+;; <interface name='org.gnome.OnlineAccounts.OAuth2Based'>
+;;   <method name='GetAccessToken'>
+;;     <arg type='s' name='access_token' direction='out'/>
+;;     <arg type='i' name='expires_in' direction='out'/>
+;;   </method>
+;;   <property type='s' name='ClientId' access='read'/>
+;;   <property type='s' name='ClientSecret' access='read'/>
+;; </interface>
+
+(defconst tramp-goa-interface-account "org.gnome.OnlineAccounts.Account"
+  "The account interface of the GNOME Online Accounts.")
+
+;; <interface name='org.gnome.OnlineAccounts.Account'>
+;;   <method name='Remove'/>
+;;   <method name='EnsureCredentials'>
+;;     <arg type='i' name='expires_in' direction='out'/>
+;;   </method>
+;;   <property type='s' name='ProviderType' access='read'/>
+;;   <property type='s' name='ProviderName' access='read'/>
+;;   <property type='s' name='ProviderIcon' access='read'/>
+;;   <property type='s' name='Id' access='read'/>
+;;   <property type='b' name='IsLocked' access='read'/>
+;;   <property type='b' name='IsTemporary' access='readwrite'/>
+;;   <property type='b' name='AttentionNeeded' access='read'/>
+;;   <property type='s' name='Identity' access='read'/>
+;;   <property type='s' name='PresentationIdentity' access='read'/>
+;;   <property type='b' name='MailDisabled' access='readwrite'/>
+;;   <property type='b' name='CalendarDisabled' access='readwrite'/>
+;;   <property type='b' name='ContactsDisabled' access='readwrite'/>
+;;   <property type='b' name='ChatDisabled' access='readwrite'/>
+;;   <property type='b' name='DocumentsDisabled' access='readwrite'/>
+;;   <property type='b' name='MapsDisabled' access='readwrite'/>
+;;   <property type='b' name='MusicDisabled' access='readwrite'/>
+;;   <property type='b' name='PrintersDisabled' access='readwrite'/>
+;;   <property type='b' name='PhotosDisabled' access='readwrite'/>
+;;   <property type='b' name='FilesDisabled' access='readwrite'/>
+;;   <property type='b' name='TicketingDisabled' access='readwrite'/>
+;;   <property type='b' name='TodoDisabled' access='readwrite'/>
+;;   <property type='b' name='ReadLaterDisabled' access='readwrite'/>
+;; </interface>
+
+(defconst tramp-goa-identity-regexp
+  (concat "^" "\\(" tramp-user-regexp "\\)?"
+         "@" "\\(" tramp-host-regexp "\\)?"
+         "\\(?:" ":""\\(" tramp-port-regexp "\\)" "\\)?")
+  "Regexp matching GNOME Online Accounts \"PresentationIdentity\" property.")
+
+(defconst tramp-goa-interface-mail "org.gnome.OnlineAccounts.Mail"
+  "The mail interface of the GNOME Online Accounts.")
+
+;; <interface name='org.gnome.OnlineAccounts.Mail'>
+;;   <property type='s' name='EmailAddress' access='read'/>
+;;   <property type='s' name='Name' access='read'/>
+;;   <property type='b' name='ImapSupported' access='read'/>
+;;   <property type='b' name='ImapAcceptSslErrors' access='read'/>
+;;   <property type='s' name='ImapHost' access='read'/>
+;;   <property type='b' name='ImapUseSsl' access='read'/>
+;;   <property type='b' name='ImapUseTls' access='read'/>
+;;   <property type='s' name='ImapUserName' access='read'/>
+;;   <property type='b' name='SmtpSupported' access='read'/>
+;;   <property type='b' name='SmtpAcceptSslErrors' access='read'/>
+;;   <property type='s' name='SmtpHost' access='read'/>
+;;   <property type='b' name='SmtpUseAuth' access='read'/>
+;;   <property type='b' name='SmtpAuthLogin' access='read'/>
+;;   <property type='b' name='SmtpAuthPlain' access='read'/>
+;;   <property type='b' name='SmtpAuthXoauth2' access='read'/>
+;;   <property type='b' name='SmtpUseSsl' access='read'/>
+;;   <property type='b' name='SmtpUseTls' access='read'/>
+;;   <property type='s' name='SmtpUserName' access='read'/>
+;; </interface>
+
+(defconst tramp-goa-interface-chat "org.gnome.OnlineAccounts.Chat"
+  "The chat interface of the GNOME Online Accounts.")
+
+;; <interface name='org.gnome.OnlineAccounts.Chat'>
+;; </interface>
+
+(defconst tramp-goa-interface-photos "org.gnome.OnlineAccounts.Photos"
+  "The photos interface of the GNOME Online Accounts.")
+
+;; <interface name='org.gnome.OnlineAccounts.Photos'>
+;; </interface>
+
+(defconst tramp-goa-path-manager (concat tramp-goa-path "/Manager")
+  "The object path of the GNOME Online Accounts manager.")
+
+(defconst tramp-goa-interface-documents "org.gnome.OnlineAccounts.Manager"
+  "The manager interface of the GNOME Online Accounts.")
+
+;; <interface name='org.gnome.OnlineAccounts.Manager'>
+;;   <method name='AddAccount'>
+;;     <arg type='s' name='provider' direction='in'/>
+;;     <arg type='s' name='identity' direction='in'/>
+;;     <arg type='s' name='presentation_identity' direction='in'/>
+;;     <arg type='a{sv}' name='credentials' direction='in'/>
+;;     <arg type='a{ss}' name='details' direction='in'/>
+;;     <arg type='o' name='account_object_path' direction='out'/>
+;;   </method>
+;; </interface>
+
+;; The basic structure for GNOME Online Accounts.  We use a list :type,
+;; in order to be compatible with Emacs 24 and 25.
+(cl-defstruct (tramp-goa-name (:type list) :named) method user host port)
+
 (defconst tramp-bluez-service "org.bluez"
   "The well known name of the BLUEZ service.")
 
@@ -479,6 +648,13 @@ Every entry is a list (NAME ADDRESS).")
          ":[[:blank:]]+\\(.*\\)$")
   "Regexp to parse GVFS file system attributes with `gvfs-info'.")
 
+(defconst tramp-gvfs-owncloud-default-prefix "/remote.php/webdav"
+  "Default prefix for owncloud / nextcloud methods.")
+
+(defconst tramp-gvfs-owncloud-default-prefix-regexp
+  (concat (regexp-quote tramp-gvfs-owncloud-default-prefix) "$")
+  "Regexp of default prefix for owncloud / nextcloud methods.")
+
 \f
 ;; New handlers should be added here.
 ;;;###tramp-autoload
@@ -610,12 +786,24 @@ Return nil for null BYTE-ARRAY."
   (cond
    ((and (consp message) (characterp (car message)))
     (format "%S" (tramp-gvfs-dbus-byte-array-to-string message)))
+   ((and (consp message) (not (consp (cdr message))))
+    (cons (tramp-gvfs-stringify-dbus-message (car message))
+         (tramp-gvfs-stringify-dbus-message (cdr message))))
    ((consp message)
     (mapcar 'tramp-gvfs-stringify-dbus-message message))
    ((stringp message)
     (format "%S" message))
    (t message)))
 
+(defun tramp-dbus-function (vec func args)
+  "Apply a D-Bus function FUNC from dbus.el.
+The call will be traced by Tramp with trace level 6."
+  (let (result)
+    (tramp-message vec 6 "%s" (cons func args))
+    (setq result (apply func args))
+    (tramp-message vec 6 "%s" result(tramp-gvfs-stringify-dbus-message result))
+    result))
+
 (defmacro with-tramp-dbus-call-method
   (vec synchronous bus service path interface method &rest args)
   "Apply a D-Bus call on bus BUS.
@@ -624,22 +812,34 @@ If SYNCHRONOUS is non-nil, the call is synchronously.  Otherwise,
 it is an asynchronous call, with `ignore' as callback function.
 
 The other arguments have the same meaning as with `dbus-call-method'
-or `dbus-call-method-asynchronously'.  Additionally, the call
-will be traced by Tramp with trace level 6."
+or `dbus-call-method-asynchronously'."
   `(let ((func (if ,synchronous
                   'dbus-call-method 'dbus-call-method-asynchronously))
         (args (append (list ,bus ,service ,path ,interface ,method)
-                      (if ,synchronous (list ,@args) (list 'ignore ,@args))))
-        result)
-     (tramp-message ,vec 6 "%s %s" func args)
-     (setq result (apply func args))
-     (tramp-message ,vec 6 "%s" (tramp-gvfs-stringify-dbus-message result))
-     result))
+                      (if ,synchronous (list ,@args) (list 'ignore ,@args)))))
+     (tramp-dbus-function ,vec func args)))
 
 (put 'with-tramp-dbus-call-method 'lisp-indent-function 2)
 (put 'with-tramp-dbus-call-method 'edebug-form-spec '(form symbolp body))
 (font-lock-add-keywords 'emacs-lisp-mode '("\\<with-tramp-dbus-call-method\\>"))
 
+(defmacro with-tramp-dbus-get-all-properties
+  (vec bus service path interface)
+  "Return all properties of INTERFACE.
+The call will be traced by Tramp with trace level 6."
+     ;; Check, that interface exists at object path.  Retrieve properties.
+  `(when (member
+         ,interface
+         (tramp-dbus-function
+          ,vec 'dbus-introspect-get-interface-names
+          (list ,bus ,service ,path)))
+     (tramp-dbus-function
+      ,vec 'dbus-get-all-properties (list ,bus ,service ,path ,interface))))
+
+(put 'with-tramp-dbus-get-all-properties 'lisp-indent-function 1)
+(put 'with-tramp-dbus-get-all-properties 'edebug-form-spec '(form symbolp body))
+(font-lock-add-keywords 'emacs-lisp-mode '("\\<with-tramp-dbus-get-all-properties\\>"))
+
 (defvar tramp-gvfs-dbus-event-vector nil
   "Current Tramp file name to be used, as vector.
 It is needed when D-Bus signals or errors arrive, because there
@@ -1293,6 +1493,10 @@ file-notify events."
          (with-parsed-tramp-file-name filename nil
            (when (string-equal "gdrive" method)
              (setq method "google-drive"))
+           (when (string-equal "owncloud" method)
+             (setq method "davs"
+                   localname
+                   (concat (tramp-gvfs-get-remote-prefix v) localname)))
            (when (and user domain)
              (setq user (concat domain ";" user)))
            (url-parse-make-urlobj
@@ -1317,24 +1521,6 @@ file-notify events."
   (dbus-unescape-from-identifier
    (replace-regexp-in-string "^.*/\\([^/]+\\)$" "\\1" object-path)))
 
-(defun tramp-bluez-address (device)
-  "Return bluetooth device address from a given bluetooth DEVICE name."
-  (when (stringp device)
-    (if (string-match tramp-ipv6-regexp device)
-       (match-string 0 device)
-      (cadr (assoc device (tramp-bluez-list-devices))))))
-
-(defun tramp-bluez-device (address)
-  "Return bluetooth device name from a given bluetooth device ADDRESS.
-ADDRESS can have the form \"xx:xx:xx:xx:xx:xx\" or \"[xx:xx:xx:xx:xx:xx]\"."
-  (when (stringp address)
-    (while (string-match "[][]" address)
-      (setq address (replace-match "" t t address)))
-    (let (result)
-      (dolist (item (tramp-bluez-list-devices) result)
-       (when (string-match address (cadr item))
-         (setq result (car item)))))))
-
 \f
 ;; D-Bus GVFS functions.
 
@@ -1405,7 +1591,7 @@ ADDRESS can have the form \"xx:xx:xx:xx:xx:xx\" or \"[xx:xx:xx:xx:xx:xx]\"."
                       (tramp-get-connection-process v) message
                     ;; In theory, there can be several choices.
                     ;; Until now, there is only the question whether
-                    ;; to accept an unknown host signature.
+                    ;; to accept an unknown host signature or certificate.
                     (with-temp-buffer
                       ;; Preserve message for `progress-reporter'.
                       (with-temp-message ""
@@ -1446,6 +1632,7 @@ ADDRESS can have the form \"xx:xx:xx:xx:xx:xx\" or \"[xx:xx:xx:xx:xx:xx]\"."
       (while (stringp (car elt)) (setq elt (cdr elt)))
       (let* ((fuse-mountpoint (tramp-gvfs-dbus-byte-array-to-string (cadr elt)))
             (mount-spec (cl-caddr elt))
+            (prefix (tramp-gvfs-dbus-byte-array-to-string (car mount-spec)))
             (default-location (tramp-gvfs-dbus-byte-array-to-string
                                (cl-cadddr elt)))
             (method (tramp-gvfs-dbus-byte-array-to-string
@@ -1462,19 +1649,17 @@ ADDRESS can have the form \"xx:xx:xx:xx:xx:xx\" or \"[xx:xx:xx:xx:xx:xx]\"."
             (ssl (tramp-gvfs-dbus-byte-array-to-string
                   (cadr (assoc "ssl" (cadr mount-spec)))))
             (uri (tramp-gvfs-dbus-byte-array-to-string
-                  (cadr (assoc "uri" (cadr mount-spec)))))
-            (prefix (concat
-                     (tramp-gvfs-dbus-byte-array-to-string
-                      (car mount-spec))
-                     (tramp-gvfs-dbus-byte-array-to-string
-                      (or (cadr (assoc "share" (cadr mount-spec)))
-                          (cadr (assoc "volume" (cadr mount-spec))))))))
+                  (cadr (assoc "uri" (cadr mount-spec))))))
        (when (string-match "^\\(afp\\|smb\\)" method)
          (setq method (match-string 1 method)))
        (when (string-equal "obex" method)
          (setq host (tramp-bluez-device host)))
        (when (and (string-equal "dav" method) (string-equal "true" ssl))
          (setq method "davs"))
+       (when (and (string-equal "davs" method)
+                  (string-match
+                   tramp-gvfs-owncloud-default-prefix-regexp prefix))
+         (setq method "owncloud"))
        (when (string-equal "google-drive" method)
          (setq method "gdrive"))
        (when (and (string-equal "http" method) (stringp uri))
@@ -1491,9 +1676,7 @@ ADDRESS can have the form \"xx:xx:xx:xx:xx:xx\" or \"[xx:xx:xx:xx:xx:xx]\"."
          (tramp-flush-file-property v "/" "list-mounts")
          (if (string-equal (downcase signal-name) "unmounted")
              (tramp-flush-file-properties v "/")
-           ;; Set prefix, mountpoint and location.
-           (unless (string-equal prefix "/")
-             (tramp-set-file-property v "/" "prefix" prefix))
+           ;; Set mountpoint and location.
            (tramp-set-file-property v "/" "fuse-mountpoint" fuse-mountpoint)
            (tramp-set-connection-property
             v "default-location" default-location)))))))
@@ -1536,6 +1719,7 @@ ADDRESS can have the form \"xx:xx:xx:xx:xx:xx\" or \"[xx:xx:xx:xx:xx:xx]\"."
        (let* ((fuse-mountpoint (tramp-gvfs-dbus-byte-array-to-string
                                (cadr elt)))
              (mount-spec (cl-caddr elt))
+             (prefix (tramp-gvfs-dbus-byte-array-to-string (car mount-spec)))
              (default-location (tramp-gvfs-dbus-byte-array-to-string
                                 (cl-cadddr elt)))
              (method (tramp-gvfs-dbus-byte-array-to-string
@@ -1553,19 +1737,20 @@ ADDRESS can have the form \"xx:xx:xx:xx:xx:xx\" or \"[xx:xx:xx:xx:xx:xx]\"."
                    (cadr (assoc "ssl" (cadr mount-spec)))))
              (uri (tramp-gvfs-dbus-byte-array-to-string
                    (cadr (assoc "uri" (cadr mount-spec)))))
-             (prefix (concat
-                      (tramp-gvfs-dbus-byte-array-to-string
-                       (car mount-spec))
-                      (tramp-gvfs-dbus-byte-array-to-string
-                       (or
-                        (cadr (assoc "share" (cadr mount-spec)))
-                        (cadr (assoc "volume" (cadr mount-spec))))))))
+             (share (tramp-gvfs-dbus-byte-array-to-string
+                     (or
+                      (cadr (assoc "share" (cadr mount-spec)))
+                      (cadr (assoc "volume" (cadr mount-spec)))))))
         (when (string-match "^\\(afp\\|smb\\)" method)
           (setq method (match-string 1 method)))
         (when (string-equal "obex" method)
           (setq host (tramp-bluez-device host)))
         (when (and (string-equal "dav" method) (string-equal "true" ssl))
           (setq method "davs"))
+        (when (and (string-equal "davs" method)
+                   (string-match
+                    tramp-gvfs-owncloud-default-prefix-regexp prefix))
+          (setq method "owncloud"))
         (when (string-equal "google-drive" method)
           (setq method "gdrive"))
         (when (and (string-equal "synce" method) (zerop (length user)))
@@ -1582,11 +1767,9 @@ ADDRESS can have the form \"xx:xx:xx:xx:xx:xx\" or \"[xx:xx:xx:xx:xx:xx]\"."
                (string-equal domain (tramp-file-name-domain vec))
                (string-equal host (tramp-file-name-host vec))
                (string-equal port (tramp-file-name-port vec))
-               (string-match (concat "^" (regexp-quote prefix))
+               (string-match (concat "^/" (regexp-quote (or share "")))
                              (tramp-file-name-unquote-localname vec)))
-          ;; Set prefix, mountpoint and location.
-          (unless (string-equal prefix "/")
-            (tramp-set-file-property vec "/" "prefix" prefix))
+          ;; Set mountpoint and location.
           (tramp-set-file-property vec "/" "fuse-mountpoint" fuse-mountpoint)
           (tramp-set-connection-property
            vec "default-location" default-location)
@@ -1620,7 +1803,7 @@ It was \"a(say)\", but has changed to \"a{sv})\"."
         (localname (tramp-file-name-unquote-localname vec))
         (share (when (string-match "^/?\\([^/]+\\)" localname)
                  (match-string 1 localname)))
-        (ssl (if (string-match "^davs" method) "true" "false"))
+        (ssl (if (string-match "^davs\\|^owncloud" method) "true" "false"))
         (mount-spec
           `(:array
             ,@(cond
@@ -1632,7 +1815,7 @@ It was \"a(say)\", but has changed to \"a{sv})\"."
                 (list (tramp-gvfs-mount-spec-entry "type" method)
                       (tramp-gvfs-mount-spec-entry
                        "host" (concat "[" (tramp-bluez-address host) "]"))))
-               ((string-match "\\`dav" method)
+               ((string-match "^dav\\|^owncloud" method)
                 (list (tramp-gvfs-mount-spec-entry "type" "dav")
                       (tramp-gvfs-mount-spec-entry "host" host)
                       (tramp-gvfs-mount-spec-entry "ssl" ssl)))
@@ -1643,7 +1826,7 @@ It was \"a(say)\", but has changed to \"a{sv})\"."
                ((string-equal "gdrive" method)
                 (list (tramp-gvfs-mount-spec-entry "type" "google-drive")
                       (tramp-gvfs-mount-spec-entry "host" host)))
-               ((string-match "\\`http" method)
+               ((string-match "^http" method)
                 (list (tramp-gvfs-mount-spec-entry "type" "http")
                       (tramp-gvfs-mount-spec-entry
                       "uri"
@@ -1660,10 +1843,10 @@ It was \"a(say)\", but has changed to \"a{sv})\"."
             ,@(when port
                 (list (tramp-gvfs-mount-spec-entry "port" port)))))
         (mount-pref
-          (if (and (string-match "\\`dav" method)
+          (if (and (string-match "^dav" method)
                    (string-match "^/?[^/]+" localname))
               (match-string 0 localname)
-            "/")))
+           (tramp-gvfs-get-remote-prefix vec))))
 
     ;; Return.
     `(:struct ,(tramp-gvfs-dbus-string-to-byte-array mount-pref) ,mount-spec)))
@@ -1715,6 +1898,21 @@ ID-FORMAT valid values are `string' and `integer'."
 (defvar tramp-gvfs-get-remote-uid-gid-in-progress nil
   "Indication, that remote uid and gid determination is in progress.")
 
+(defun tramp-gvfs-get-remote-prefix (vec)
+  "The prefix of the remote connection VEC.
+This is relevant for GNOME Online Accounts."
+  (with-tramp-connection-property vec "prefix"
+    ;; Ensure that GNOME Online Accounts are cached.
+    (when (member (tramp-file-name-method vec) tramp-goa-methods)
+      (tramp-get-goa-accounts vec))
+    (tramp-get-connection-property
+     (make-tramp-goa-name
+      :method (tramp-file-name-method vec)
+      :user (tramp-file-name-user vec)
+      :host (tramp-file-name-host vec)
+      :port (tramp-file-name-port vec))
+     "prefix" "/")))
+
 (defun tramp-gvfs-maybe-open-connection (vec)
   "Maybe open a connection VEC.
 Does not do anything if a connection is already open, but re-opens the
@@ -1731,6 +1929,7 @@ connection if a previous connection has died for some reason."
              :name (tramp-buffer-name vec)
              :buffer (tramp-get-connection-buffer vec)
              :server t :host 'local :service t :noquery t)))
+      (tramp-set-connection-property p "vector" vec)
       (set-process-query-on-exit-flag p nil)))
 
   (unless (tramp-gvfs-connection-mounted-p vec)
@@ -1868,9 +2067,82 @@ is applied, and it returns t if the return code is zero."
          ;; Remove information about mounted connection.
          (and (tramp-flush-file-properties vec "/") nil)))))
 
+\f
+;; D-Bus GNOME Online Accounts functions.
+
+(defun tramp-get-goa-accounts (vec)
+  "Retrieve GNOME Online Accounts, and cache them.
+The hash key is a `tramp-goa-name' structure.  The value is an
+alist of the properties of `tramp-goa-interface-account' and
+`tramp-goa-interface-files' of the corresponding GNOME online
+account.  Additionally, a property \"prefix\" is added.
+VEC is used only for traces."
+  (dolist
+      (object-path
+       (mapcar
+       'car
+       (tramp-dbus-function
+        vec 'dbus-get-all-managed-objects
+        `(:session ,tramp-goa-service ,tramp-goa-path))))
+    (let* ((account-properties
+           (with-tramp-dbus-get-all-properties vec
+             :session tramp-goa-service object-path
+             tramp-goa-interface-account))
+          (files-properties
+           (with-tramp-dbus-get-all-properties vec
+             :session tramp-goa-service object-path
+             tramp-goa-interface-files))
+          (identity
+           (or (cdr (assoc "PresentationIdentity" account-properties)) ""))
+          key)
+      ;; Only accounts which matter.
+      (when (and
+            (not (cdr (assoc "FilesDisabled" account-properties)))
+            (member
+             (cdr (assoc "ProviderType" account-properties))
+             '("google" "owncloud"))
+            (string-match tramp-goa-identity-regexp identity))
+       (setq key (make-tramp-goa-name
+                  :method (cdr (assoc "ProviderType" account-properties))
+                  :user (match-string 1 identity)
+                  :host (match-string 2 identity)
+                  :port (match-string 3 identity)))
+       (when (string-equal (tramp-goa-name-method key) "google")
+         (setf (tramp-goa-name-method key) "gdrive"))
+       ;; Cache all properties.
+       (dolist (prop (nconc account-properties files-properties))
+         (tramp-set-connection-property key (car prop) (cdr prop)))
+       ;; Cache "prefix".
+       (tramp-message
+        vec 10 "%s prefix %s" key
+        (tramp-set-connection-property
+         key "prefix"
+         (directory-file-name
+          (url-filename
+           (url-generic-parse-url
+            (tramp-get-connection-property key "Uri" "file:///"))))))))))
+
 \f
 ;; D-Bus BLUEZ functions.
 
+(defun tramp-bluez-address (device)
+  "Return bluetooth device address from a given bluetooth DEVICE name."
+  (when (stringp device)
+    (if (string-match tramp-ipv6-regexp device)
+       (match-string 0 device)
+      (cadr (assoc device (tramp-bluez-list-devices))))))
+
+(defun tramp-bluez-device (address)
+  "Return bluetooth device name from a given bluetooth device ADDRESS.
+ADDRESS can have the form \"xx:xx:xx:xx:xx:xx\" or \"[xx:xx:xx:xx:xx:xx]\"."
+  (when (stringp address)
+    (while (string-match "[][]" address)
+      (setq address (replace-match "" t t address)))
+    (let (result)
+      (dolist (item (tramp-bluez-list-devices) result)
+       (when (string-match address (cadr item))
+         (setq result (car item)))))))
+
 (defun tramp-bluez-list-devices ()
   "Return all discovered bluetooth devices as list.
 Every entry is a list (NAME ADDRESS).
index 1688a166ca6031177ac6fdeccd7bac314a3b7ca2..ec7e25247c71a280e3cd1d82496ce24a35aec376 100644 (file)
 (defvar tramp-copy-size-limit)
 (defvar tramp-persistency-file-name)
 (defvar tramp-remote-process-environment)
-;; Suppress nasty messages.
-(fset 'shell-command-sentinel 'ignore)
+
+;; Beautify batch mode.
+(when noninteractive
+  ;; Suppress nasty messages.
+  (fset 'shell-command-sentinel 'ignore)
+  ;; We do not want to be interrupted.
+  (eval-after-load 'tramp-gvfs
+    '(fset 'tramp-gvfs-handler-askquestion
+          (lambda (_message _choices) '(t nil 0)))))
 
 ;; There is no default value on w32 systems, which could work out of the box.
 (defconst tramp-test-temporary-file-directory
@@ -1941,7 +1948,9 @@ This checks also `file-name-as-directory', `file-name-directory',
 
          ;; Copy file to directory.
          (unwind-protect
-             (progn
+             ;; FIXME: This fails on my QNAP server, see
+             ;; /share/Web/owncloud/data/owncloud.log
+             (unless (tramp--test-owncloud-p)
                (write-region "foo" nil source)
                (should (file-exists-p source))
                (make-directory target)
@@ -1962,7 +1971,11 @@ This checks also `file-name-as-directory', `file-name-directory',
 
          ;; Copy directory to existing directory.
          (unwind-protect
-             (progn
+             ;; FIXME: This fails on my QNAP server, see
+             ;; /share/Web/owncloud/data/owncloud.log
+             (unless (and (tramp--test-owncloud-p)
+                          (or (not (file-remote-p source))
+                              (not (file-remote-p target))))
                (make-directory source)
                (should (file-directory-p source))
                (write-region "foo" nil (expand-file-name "foo" source))
@@ -1983,7 +1996,10 @@ This checks also `file-name-as-directory', `file-name-directory',
 
          ;; Copy directory/file to non-existing directory.
          (unwind-protect
-             (progn
+             ;; FIXME: This fails on my QNAP server, see
+             ;; /share/Web/owncloud/data/owncloud.log
+             (unless
+                 (and (tramp--test-owncloud-p) (not (file-remote-p source)))
                (make-directory source)
                (should (file-directory-p source))
                (write-region "foo" nil (expand-file-name "foo" source))
@@ -2069,7 +2085,9 @@ This checks also `file-name-as-directory', `file-name-directory',
 
          ;; Rename directory to existing directory.
          (unwind-protect
-             (progn
+             ;; FIXME: This fails on my QNAP server, see
+             ;; /share/Web/owncloud/data/owncloud.log
+             (unless (tramp--test-owncloud-p)
                (make-directory source)
                (should (file-directory-p source))
                (write-region "foo" nil (expand-file-name "foo" source))
@@ -2091,7 +2109,9 @@ This checks also `file-name-as-directory', `file-name-directory',
 
          ;; Rename directory/file to non-existing directory.
          (unwind-protect
-             (progn
+             ;; FIXME: This fails on my QNAP server, see
+             ;; /share/Web/owncloud/data/owncloud.log
+             (unless (tramp--test-owncloud-p)
                (make-directory source)
                (should (file-directory-p source))
                (write-region "foo" nil (expand-file-name "foo" source))
@@ -4079,6 +4099,11 @@ This does not support external Emacs calls."
   (string-equal
    "mock" (file-remote-p tramp-test-temporary-file-directory 'method)))
 
+(defun tramp--test-owncloud-p ()
+  "Check, whether the owncloud method is used."
+  (string-equal
+   "owncloud" (file-remote-p tramp-test-temporary-file-directory 'method)))
+
 (defun tramp--test-rsync-p ()
   "Check, whether the rsync method is used.
 This does not support special file names."
@@ -4830,6 +4855,8 @@ Since it unloads Tramp, it shall be the last test to run."
 ;; * Work on skipped tests.  Make a comment, when it is impossible.
 ;; * Fix `tramp-test05-expand-file-name-relative' in `expand-file-name'.
 ;; * Fix `tramp-test06-directory-file-name' for `ftp'.
+;; * Investigate, why `tramp-test11-copy-file' and `tramp-test12-rename-file'
+;;   do not work properly for `owncloud'.
 ;; * Fix `tramp-test29-start-file-process' on MS Windows (`process-send-eof'?).
 ;; * Fix `tramp-test30-interrupt-process', timeout doesn't work reliably.
 ;; * Fix Bug#16928 in `tramp-test41-asynchronous-requests'.