Files
harbour-quill/qml/components/DavClient.qml
T

146 lines
4.4 KiB
QML

import QtQuick 2.2
import "PropfindParser.js" as Prop
// Minimal WebDAV client over XMLHttpRequest. One request at a time
// (busy flag); 30 s watchdog turns hangs into a failed() signal.
Item {
id: dav
property bool busy: false
signal listReady(var entries)
signal fileReady(string content)
signal writeDone()
signal deleteDone()
signal connOk()
signal failed(string message)
property var currentXhr: null
Timer {
id: watchdog
interval: 30000
repeat: false
onTriggered: {
if (dav.currentXhr) {
dav.currentXhr.abort()
dav.currentXhr = null
}
dav.busy = false
dav.failed(qsTr("Network timeout"))
}
}
function authHeader() {
var user = appSettings.username
if (!user) return ""
return "Basic " + Qt.btoa(user + ":" + appSettings.password)
}
function encodeRel(rel) {
if (!rel) return rel
var parts = rel.split("/")
var out = []
for (var i = 0; i < parts.length; i++) out.push(encodeURIComponent(parts[i]))
return out.join("/")
}
function fullUrl(rel) {
var base = String(appSettings.serverUrl).replace(/\s+$/, "")
if (!base) return ""
if (rel && rel !== "") {
if (base.charAt(base.length - 1) !== "/") base += "/"
base += encodeRel(rel)
}
return base
}
function request(method, url, body, onDone) {
if (busy) {
failed(qsTr("Request already in progress"))
return
}
busy = true
var xhr = new XMLHttpRequest()
currentXhr = xhr
xhr.open(method, url, true)
var auth = authHeader()
if (auth) xhr.setRequestHeader("Authorization", auth)
if (method === "PROPFIND") xhr.setRequestHeader("Depth", "1")
if (method === "PUT") xhr.setRequestHeader("Content-Type", "text/markdown; charset=utf-8")
xhr.onreadystatechange = function () {
if (xhr.readyState !== 4) return
watchdog.stop()
if (currentXhr === xhr) {
currentXhr = null
busy = false
onDone(xhr)
}
// else: aborted by the watchdog — already signalled
}
xhr.send(body || "")
watchdog.restart()
}
function listDir(relPath) {
request("PROPFIND", fullUrl(relPath || ""), "", function (xhr) {
if (xhr.status >= 200 && xhr.status < 300) {
var entries = Prop.parse(xhr.responseText, appSettings.serverUrl)
listReady(entries)
} else {
failed(statusMessage(xhr.status))
}
})
}
function readFile(relPath) {
request("GET", fullUrl(relPath), "", function (xhr) {
if (xhr.status >= 200 && xhr.status < 300) {
fileReady(xhr.responseText)
} else {
failed(statusMessage(xhr.status))
}
})
}
function writeFile(relPath, content) {
request("PUT", fullUrl(relPath), content, function (xhr) {
if (xhr.status >= 200 && xhr.status < 300) {
writeDone()
} else {
failed(statusMessage(xhr.status))
}
})
}
function deleteFile(relPath) {
request("DELETE", fullUrl(relPath), "", function (xhr) {
if (xhr.status >= 200 && xhr.status < 300) {
deleteDone()
} else {
failed(statusMessage(xhr.status))
}
})
}
function testConnection() {
request("PROPFIND", fullUrl(""), "", function (xhr) {
if (xhr.status >= 200 && xhr.status < 300) {
connOk()
} else {
failed(statusMessage(xhr.status))
}
})
}
function statusMessage(status) {
if (status === 401) return qsTr("Invalid credentials (401)")
if (status === 403) return qsTr("Access denied (403)")
if (status === 404) return qsTr("Folder not found (404) — check the URL")
if (status === 405) return qsTr("WebDAV not available (405) — the URL must point to a DAV folder")
if (status === 0) return qsTr("Server unreachable")
if (status >= 500) return qsTr("Server error (%1)").arg(status)
return qsTr("HTTP error %1").arg(status)
}
}