specify filename for downloaded address books and calendars
This commit is contained in:
parent
5f8b9e5672
commit
f2389a1e53
@ -38,7 +38,7 @@ import threading
|
|||||||
import time
|
import time
|
||||||
import zlib
|
import zlib
|
||||||
from http import client
|
from http import client
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse, quote
|
||||||
from xml.etree import ElementTree as ET
|
from xml.etree import ElementTree as ET
|
||||||
|
|
||||||
import vobject
|
import vobject
|
||||||
@ -424,6 +424,35 @@ class Application:
|
|||||||
xmlutils.webdav_error(namespace, name))
|
xmlutils.webdav_error(namespace, name))
|
||||||
return status, headers, content
|
return status, headers, content
|
||||||
|
|
||||||
|
def _propose_filename(self, collection):
|
||||||
|
"""Propose a filename for a collection."""
|
||||||
|
tag = collection.get_meta("tag")
|
||||||
|
if tag == "VADDRESSBOOK":
|
||||||
|
fallback_title = "Address book"
|
||||||
|
suffix = ".vcf"
|
||||||
|
elif tag == "VCALENDAR":
|
||||||
|
fallback_title = "Calendar"
|
||||||
|
suffix = ".ics"
|
||||||
|
else:
|
||||||
|
fallback_title = posixpath.basename(collection.path)
|
||||||
|
suffix = ""
|
||||||
|
title = collection.get_meta("D:displayname") or fallback_title
|
||||||
|
if title and not title.lower().endswith(suffix.lower()):
|
||||||
|
title += suffix
|
||||||
|
return title
|
||||||
|
|
||||||
|
def _content_disposition_attachement(self, filename):
|
||||||
|
value = "attachement"
|
||||||
|
try:
|
||||||
|
encoded_filename = quote(filename, encoding=self.encoding)
|
||||||
|
except UnicodeEncodeError as e:
|
||||||
|
logger.warning("Failed to encode filename: %r", filename,
|
||||||
|
exc_info=True)
|
||||||
|
encoded_filename = ""
|
||||||
|
if encoded_filename:
|
||||||
|
value += "; filename*=%s''%s" % (self.encoding, encoded_filename)
|
||||||
|
return value
|
||||||
|
|
||||||
def do_DELETE(self, environ, base_prefix, path, user):
|
def do_DELETE(self, environ, base_prefix, path, user):
|
||||||
"""Manage DELETE request."""
|
"""Manage DELETE request."""
|
||||||
if not self._access(user, path, "w"):
|
if not self._access(user, path, "w"):
|
||||||
@ -473,12 +502,17 @@ class Application:
|
|||||||
if not tag:
|
if not tag:
|
||||||
return DIRECTORY_LISTING
|
return DIRECTORY_LISTING
|
||||||
content_type = xmlutils.MIMETYPES[tag]
|
content_type = xmlutils.MIMETYPES[tag]
|
||||||
|
content_disposition = self._content_disposition_attachement(
|
||||||
|
self._propose_filename(item))
|
||||||
else:
|
else:
|
||||||
content_type = xmlutils.OBJECT_MIMETYPES[item.name]
|
content_type = xmlutils.OBJECT_MIMETYPES[item.name]
|
||||||
|
content_disposition = ""
|
||||||
headers = {
|
headers = {
|
||||||
"Content-Type": content_type,
|
"Content-Type": content_type,
|
||||||
"Last-Modified": item.last_modified,
|
"Last-Modified": item.last_modified,
|
||||||
"ETag": item.etag}
|
"ETag": item.etag}
|
||||||
|
if content_disposition:
|
||||||
|
headers["Content-Disposition"] = content_disposition
|
||||||
answer = item.serialize()
|
answer = item.serialize()
|
||||||
return client.OK, headers, answer
|
return client.OK, headers, answer
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user