Example #1
0
    def __init__(self,
                 server,
                 port=None,
                 ssl=False,
                 afunix=None,
                 user="",
                 pswd="",
                 principal=None,
                 root=None,
                 logging=False,
                 noHostRedirect=False):
        super(CalDAVSession, self).__init__(server,
                                            port,
                                            ssl,
                                            afunix,
                                            log=CalDAVSession.logger())

        self.loghttp = logging

        self.user = user
        self.pswd = pswd

        self.noHostRedirect = noHostRedirect

        # Initialize state
        self.connect = None

        # Paths
        self.rootPath = URL(url=root)
        self.principalPath = URL(url=principal) if principal else None

        self._initCalDAVState()
Example #2
0
    def _discoverPrincipal(self):

        current = self.getCurrentPrincipalResource(self.rootPath)
        if current:
            self.principalPath = current
            return
        current = self.getCurrentPrincipalResource(
            URL(url="/.well-known/caldav"))
        if current:
            self.principalPath = current
            return

        hrefs = self.getHrefListProperty(self.rootPath,
                                         davxml.principal_collection_set)
        if not hrefs:
            return
        hrefs = self.getHrefListProperty(URL(url="/.well-known/caldav"),
                                         davxml.principal_collection_set)
        if not hrefs:
            return

        # For each principal collection find current principal
        for href in hrefs:
            current = self.getCurrentPrincipalResource(href)
            if current:
                self.principalPath = current
                return
    def runSession(self, request):

        ctr = 5
        while ctr:
            ctr -= 1

            self.doSession(request)

            if request and request.isRedirect():
                location = request.getResponseHeader(headers.Location)
                if location:
                    u = URL(location)
                    if not u.scheme or u.scheme in ("http", "https",):
                        # Get new server and base RURL
                        different_server = (self.server != u.server) if u.server else False

                        # Use new host in this session
                        if different_server:
                            self.setServer(u.server)

                        # Reset the request with new info
                        request.setURL(u.relativeURL())
                        request.clearResponse()

                        # Write to log file
                        if self.loghttp and self.log:
                            self.log.write("\n        <-------- HTTP REDIRECT -------->\n")
                            self.log.write("Location: %s\n" % (location,))

                        # Recyle through loop
                        continue

            # Exit when redirect does not occur
            break
    def getPropertyNames(self, rurl):

        assert(isinstance(rurl, URL))

        results = ()

        # Create WebDAV propfind
        request = PropNames(self, rurl.relativeURL(), headers.Depth0)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):

                    results = tuple([name for name in item.getNodeProperties().iterkeys()])

        else:
            self.handleHTTPError(request)

        return results
Example #5
0
    def ensureSharees(self, session, calendarhref, n):
        """
        Make sure the required number of sharees are present in the calendar.

        @param n: number of sharees
        @type n: C{int}
        """

        users = []
        uids = []
        for i in range(n - self.currentCount):
            index = self.currentCount + i + 2
            users.append("user%02d" % (index, ))
            uids.append("urn:x-uid:10000000-0000-0000-0000-000000000%03d" %
                        (index, ))
        session.addInvitees(URL(path=calendarhref), uids, True)

        # Now accept each one
        for user in users:
            acceptor = SQLUsageSession(self.server,
                                       self.port,
                                       user=user,
                                       pswd=user,
                                       root="/",
                                       calendar="shared")
            notifications = acceptor.getNotifications(
                URL(path=acceptor.notificationHref))
            principal = principalCache.getPrincipal(acceptor,
                                                    acceptor.principalPath)
            acceptor.processNotification(principal, notifications[0], True)

        self.currentCount = n
Example #6
0
 def _warmUp():
     # Warm-up server by doing calendar home and child collection propfinds.
     # Do this twice because the very first time might provision DB objects and
     # blow any DB cache - the second time will warm the DB cache.
     props = (davxml.resourcetype,)
     for _ignore in range(2):
         for session in sessions:
             session.getPropertiesOnHierarchy(URL(path=session.homeHref), props)
             session.getPropertiesOnHierarchy(URL(path=session.calendarHref), props)
             session.getPropertiesOnHierarchy(URL(path=session.inboxHref), props)
             session.getPropertiesOnHierarchy(URL(path=session.notificationHref), props)
Example #7
0
    def runLoop(self, sharee_counts):

        # Make the sessions
        sessions = [
            SQLUsageSession(self.server,
                            self.port,
                            user=user,
                            pswd=pswd,
                            root="/",
                            calendar="shared")
            for user, pswd in itertools.izip(self.users, self.pswds)
        ]
        sessions = sessions[0:1]

        # Create the calendar first
        sessions[0].makeCalendar(URL(path=sessions[0].calendarHref))

        # Set of requests to execute
        requests = [
            MultigetTest("mget-1" if self.compact else "multiget-1", sessions,
                         self.logFilePath, "share", 1),
            MultigetTest("mget-50" if self.compact else "multiget-50",
                         sessions, self.logFilePath, "share", 50),
            PropfindInviteTest("propfind", sessions, self.logFilePath, "share",
                               1),
            SyncTest("s-full" if self.compact else "sync-full", sessions,
                     self.logFilePath, "share", True, 0),
            SyncTest("s-1" if self.compact else "sync-1", sessions,
                     self.logFilePath, "share", False, 1),
            QueryTest("q-1" if self.compact else "query-1", sessions,
                      self.logFilePath, "share", 1),
            QueryTest("q-10" if self.compact else "query-10", sessions,
                      self.logFilePath, "share", 10),
            PutTest("put", sessions, self.logFilePath, "share"),
        ]
        self.requestLabels = [request.label for request in requests]

        # Warm-up server by doing shared calendar propfinds
        props = (davxml.resourcetype, )
        for session in sessions:
            session.getPropertiesOnHierarchy(URL(path=session.calendarHref),
                                             props)

        # Now loop over sets of events
        for count in sharee_counts:
            print("Testing count = %d" % (count, ))
            self.ensureSharees(sessions[0], sessions[0].calendarHref, count)
            result = {}
            for request in requests:
                print("  Test = %s" % (request.label, ))
                result[request.label] = request.execute(count)
            self.results[count] = result
Example #8
0
    def del_folder (self, itemid, store=None):
        """Get rid of the specified folder."""

        sess = self.session()
        path = URL(url=itemid)

        logging.info('Deleting all the contained items. Will not remove folder')

        items = sess.getPropertiesOnHierarchy(path, (davxml.getetag,))
        hrefs = [x for x in items.keys() if x != path.toString().strip()]

        for href in hrefs:
            sess.deleteResource(URL(url=href))
            logging.info('Deleted file %s...', href)
Example #9
0
    def del_folder(self, itemid, store=None):
        """Get rid of the specified folder."""

        sess = self.session()
        path = URL(url=itemid)

        logging.info("Deleting all the contained items. Will not remove folder")

        items = sess.getPropertiesOnHierarchy(path, (davxml.getetag,))
        hrefs = [x for x in items.keys() if x != path.toString().strip()]

        for href in hrefs:
            sess.deleteResource(URL(url=href))
            logging.info("Deleted file %s...", href)
Example #10
0
    def prepare(self):
        """
        Do some setup prior to the real request.
        """
        if not self.full:
            # Get current sync token
            results, _ignore_bad = self.sessions[0].getProperties(URL(path=self.sessions[0].calendarHref), (davxml.sync_token,))
            self.synctoken = results[davxml.sync_token]

            # Add resources to create required number of changes
            now = DateTime.getNowUTC()
            for i in range(self.count):
                href = joinURL(self.sessions[0].calendarHref, "sync-collection-%d.ics" % (i + 1,))
                self.sessions[0].writeData(URL(path=href), ICAL % (now.getYear() + 1, i + 1,), "text/calendar")
Example #11
0
    def fetch_folders (self):
        """Fetch and return the list of addressbooks from the server."""
        
        logging.debug('CDPIMDB.set_folders(): Begin')

        sess  = self.session()
        roots = self.get_contacts_folders_roots()
        props = (davxml.resourcetype, davxml.getlastmodified,)

        ret   = []
        for root in roots:
            path = root.path
            logging.debug('Processing Root path %s in Root.', path)
            results = sess.getPropertiesOnHierarchy(URL(url=path), props)
            items = results.keys()
            items.sort()
            for rurl in items:
                rurl = urllib.unquote(rurl)
                if rurl == path:
                    continue

                props = results[rurl]
                rtype = props.get(davxml.resourcetype)
                if not isinstance(rtype, str):
                    for child in rtype.getchildren():
                        if child.tag == carddavxml.addressbook:
                            name = rurl[len(path):-1]
                            logging.debug('Found Folder %-15s in URI "%s"',
                                          name, rurl)
                            ret.append((rurl.strip(), path, name))

        logging.debug('CDPIMDB.set_folders(): Done.')

        return ret
Example #12
0
    def execute(self, cmdname, options):

        opts, args = getopt.getopt(shlex.split(options), '')

        data = None
        content_type = None
        path = None

        for name, _ignore_value in opts:

            print "Unknown option: %s" % (name, )
            print self.usage(cmdname)
            raise WrongOptions

        if len(args) > 1:
            print "Wrong number of arguments: %d" % (len(args), )
            print self.usage(cmdname)
            raise WrongOptions
        elif args:
            path = args[0]
            if not path.startswith("/"):
                path = os.path.join(self.shell.wd, path)
        else:
            path = self.shell.wd

        resource = URL(url=path)
        self.shell.account.session.writeData(resource,
                                             data,
                                             content_type,
                                             method="OPTIONS")

        return True
Example #13
0
    def execute(self, cmdname, options):
        opts, args = getopt.getopt(shlex.split(options), '')
        if len(opts) != 0:
            print self.usage(cmdname)
            raise WrongOptions

        if len(args) > 1:
            print "Wrong number of arguments: %d" % (len(args), )
            print self.usage(cmdname)
            raise WrongOptions
        pid = args[0] if args else None
        if pid and pid.find("/") == -1:
            pid = "/principals/__uids__/%s/" % pid
        ppath = URL(url=pid) if pid else None
        principal = self.shell.account.getPrincipal(ppath)
        if principal is None:
            print "No principal found for %s" % (ppath if ppath else
                                                 "current principal")
            raise CommandError

        homeset = principal.adbkhomeset
        if not homeset:
            print "No address book home set found for %s" % (
                principal.principalPath, )
            raise CommandError

        newpath = homeset[0].path
        result = self.shell.setWD(newpath)

        if not result:
            print "%s: No such directory" % (newpath, )

        return result
    def __init__(self, server, port=None, ssl=False, user="", pswd="", principal=None, root=None, logging=False):
        super(CalDAVSession, self).__init__(server, port, ssl, log=CalDAVSession.logger())

        self.loghttp = logging

        self.user = user
        self.pswd = pswd

        # Initialize state
        self.connect = None

        # Paths
        self.rootPath = URL(url=root)
        self.principalPath = URL(url=principal) if principal else None

        self._initCalDAVState()
Example #15
0
 def cleanup(self):
     """
     Do some cleanup after the real request.
     """
     # Remove created resources
     href = joinURL(self.sessions[0].calendarHref, "put.ics")
     self.sessions[0].deleteResource(URL(path=href))
Example #16
0
    def set_def_folders(self):
        """See the documentation in class PIMDB"""

        root = self.get_def_root_folder_path()
        props = (carddavxml.default_addressbook_url, )

        res, bad = self.session().getProperties(URL(url=root), props)
        uris = res.values()
        if len(uris) > 0:
            def_uri = uris[0].toString().strip()
            logging.debug('Looking for default folder: "%s"', def_uri)
            def_f, t = self.find_folder(def_uri)
        else:
            ## In some instances the server does not respond properly to the
            ## def_adbk_url property request. In this case we will just pick
            ## the first folder. One hopes every addressbook server will have
            ## at least one server
            logging.debug('Coud not find default adbk Property.')
            fs = self.get_contacts_folders()
            assert (len(fs) > 0)
            def_f = fs[0]
            logging.debug('Setting first available folder as default: %s',
                          def_f.get_name())

        self.set_def_folder(Folder.CONTACT_t, def_f)
Example #17
0
    def getSelfHrefs(self, rurl):

        assert (isinstance(rurl, URL))

        results = ()

        # Create WebDAV principal-match
        request = PrincipalMatch(self, rurl.relativeURL(),
                                 (davxml.principal_URL, ))
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result and extract any Hrefs
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)
                results += (name, )

        else:
            self.handleHTTPError(request)
            return None

        return results
Example #18
0
def printACE(ace, account):

    principalText = ace.principal
    if principalText == str(davxml.href):
        principal = account.getPrincipal(URL(url=ace.data))
        principalText = "%s (%s)" % (principal.getSmartDisplayName(),
                                     principal.principalURL)
    elif principalText == str(davxml.all):
        principalText = "ALL"
    elif principalText == str(davxml.authenticated):
        principalText = "AUTHENTICATED"
    elif principalText == str(davxml.unauthenticated):
        principalText = "UNAUTHENTICATED"
    elif principalText == str(davxml.property):
        principalText = "PROPERTY: %s" % (ace.data, )
    result = "Principal: %s\n" % (principalText, )
    if ace.invert or ace.protected or ace.inherited:
        result += "    Status:"
        if ace.invert:
            result += " INVERTED"
        if ace.protected:
            result += " PROTECTED"
        if ace.inherited:
            result += " INHERITED"
        result += "\n"
    result += "    Grant: " if ace.grant else "    Deny: "
    result += ", ".join(ace.privs)
    result += "\n"
    return result
Example #19
0
    def execute(self, cmdname, options):

        opts, args = getopt.getopt(shlex.split(options), 'n')

        doURLDecode = False
        for name, _ignore_value in opts:

            if name == "-n":
                doURLDecode = True
            else:
                print "Unknown option: %s" % (name, )
                print self.usage(cmdname)
                raise WrongOptions

        if len(args) != 2:
            print "Wrong number of arguments: %d" % (len(args), )
            print self.usage(cmdname)
            raise WrongOptions

        while True:
            result = raw_input("Really move resource '%s' to '%s' [y/n]: " % (
                args[0],
                args[1],
            ))
            if readline.get_current_history_length():
                readline.remove_history_item(
                    readline.get_current_history_length() - 1)
            if not result:
                continue
            if result[0] == "n":
                return True
            elif result[0] == "y":
                break

        fromResource = args[0]
        if not fromResource.startswith("/"):
            fromResource = os.path.join(self.shell.wd, fromResource)
        toResource = args[1]
        if not toResource.startswith("/"):
            toResource = os.path.join(self.shell.wd, toResource)

        resourceFrom = URL(url=fromResource, decode=doURLDecode)
        resourceTo = URL(url=self.shell.server + toResource,
                         decode=doURLDecode)
        self.shell.account.session.moveResource(resourceFrom, resourceTo)

        return True
Example #20
0
    def execute(self, cmdname, options):

        fname = None
        content_type = None
        path = None

        opts, args = getopt.getopt(shlex.split(options), 'acf:')

        for name, value in opts:

            if name == "-f":
                fname = value
            elif name == "-a":
                if content_type:
                    raise WrongOptions
                content_type = "text/vcard"
            elif name == "-c":
                content_type = "text/calendar"
                if content_type:
                    raise WrongOptions
            else:
                print "Unknown option: %s" % (name, )
                print self.usage(cmdname)
                raise WrongOptions

        if not fname:
            print "File name must be provided"
            print self.usage(cmdname)
            raise WrongOptions

        elif len(args) > 1:
            print "Wrong number of arguments: %d" % (len(args), )
            print self.usage(cmdname)
            raise WrongOptions
        elif args:
            path = args[0]
            if not path.startswith("/"):
                path = os.path.join(self.shell.wd, path)
            if not path.endswith("/"):
                print "Can only POST to a directory: %s" % (path, )
                print self.usage(cmdname)
                raise WrongOptions
        else:
            print "Path to POST to must be provided"
            print self.usage(cmdname)
            raise WrongOptions

        # Read in data
        try:
            data = open(os.path.expanduser(fname), "r").read()
        except IOError:
            print "Unable to read data from file: %s" % (fname, )
            print self.usage(cmdname)
            raise WrongOptions

        resource = URL(url=path)
        self.shell.account.session.importData(resource, data, content_type)

        return True
Example #21
0
    def doRequest(self):
        """
        Execute the actual HTTP request.
        """

        now = DateTime.getNowUTC()
        href = joinURL(self.sessions[0].calendarHref, "put.ics")
        self.sessions[0].writeData(URL(path=href), ICAL % (now.getYear() + 1,), "text/calendar")
    def setWD(self, newwd):

        # Check that the new one exists
        resource = (newwd if newwd.endswith("/") else newwd + "/")
        if not self.account.session.testResource(URL(url=resource)):
            return False
        self.prefix = self.wd = newwd
        return True
Example #23
0
    def put_item(self, name, data, content_type, etag=None):
        path = URL(url=name)
        res = self.get_db().session().writeData(path,
                                                data,
                                                content_type,
                                                etag=etag)

        return name
Example #24
0
    def getProperties(self, rurl, props, xmldata=False):

        assert (isinstance(rurl, URL))

        results = {}
        bad = None

        # Create WebDAV propfind
        if props:
            request = PropFind(self, rurl.relativeURL(), headers.Depth0, props)
        else:
            request = PropAll(self, rurl.relativeURL(), headers.Depth0)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):
                    for name, value in item.getTextProperties().iteritems():
                        results[name] = value
                    for name, value in item.getHrefProperties().iteritems():
                        if name not in results:
                            results[name] = value
                    for name, value in item.getNodeProperties().iteritems():
                        if name not in results:
                            results[name] = tostring(
                                value) if xmldata else value
                    bad = item.getBadProperties()
        else:
            self.handleHTTPError(request)

        return results, bad
Example #25
0
 def cleanup(self):
     """
     Do some cleanup after the real request.
     """
     # Remove created resources
     for i in range(self.count):
         href = joinURL(self.sessions[0].calendarHref, "tr-query-%d.ics" % (i + 1,))
         self.sessions[0].deleteResource(URL(path=href))
    def execute(self, cmdname, options):

        names = False
        all_props = False
        xmllist = False
        prop = None
        path = None

        opts, args = getopt.getopt(shlex.split(options), 'alnp:')

        for name, value in opts:

            if name == "-a":
                all_props = True
            elif name == "-l":
                xmllist = True
            elif name == "-n":
                names = True
            elif name == "-p":
                prop = value
            else:
                print "Unknown option: %s" % (name, )
                print self.usage(cmdname)
                raise WrongOptions

        if len(args) > 1:
            print "Wrong number of arguments: %d" % (len(args), )
            print self.usage(cmdname)
            raise WrongOptions
        elif args:
            path = args[0]
            if not path.startswith("/"):
                path = os.path.join(self.shell.wd, path)
        else:
            path = self.shell.wd
        if not path.endswith("/"):
            path += "/"
        resource = URL(url=path)

        if names:
            results = self.shell.account.session.getPropertyNames(resource)
            print "    Properties: %s" % (utils.printList(results), )
        else:
            if all_props:
                props = None
            elif prop:
                props = (prop, )
            else:
                props = self.shell.account.session.getPropertyNames(resource)
            results, bad = self.shell.account.session.getProperties(
                resource, props, xmllist)
            print "OK Properties:"
            utils.printProperties(results)
            if bad:
                print "Failed Properties:"
                utils.printProperties(bad)

        return True
    def getProperties(self, rurl, props, xmldata=False):

        assert(isinstance(rurl, URL))

        results = {}
        bad = None

        # Create WebDAV propfind
        if props:
            request = PropFind(self, rurl.relativeURL(), headers.Depth0, props)
        else:
            request = PropAll(self, rurl.relativeURL(), headers.Depth0)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):
                    for name, value in item.getTextProperties().iteritems():
                        results[name] = value
                    for name, value in item.getHrefProperties().iteritems():
                        if name not in results:
                            results[name] = value
                    for name, value in item.getNodeProperties().iteritems():
                        if name not in results:
                            results[name] = tostring(value) if xmldata else value
                    bad = item.getBadProperties()
        else:
            self.handleHTTPError(request)

        return results, bad
Example #28
0
 def getAllDetails(self):
     if self.details is None:
         resource = URL(url=self.path + "/")
         props = self.session.account.session.getPropertyNames(resource)
         results, _ignore_bad = self.session.account.session.getProperties(resource, props)
         sorted = results.keys()
         sorted.sort()
         self.details = [(key, results[key],) for key in sorted]
     return self.details
Example #29
0
 def del_itemids(self, itemids):
     sess = self.get_db().session()
     for itemid in itemids:
         try:
             sess.deleteResource(URL(url=self.item_path(itemid)))
             self.del_contact(itemid)
             logging.info('Deleted CardDAV server contact %s...', itemid)
         except HTTPError, e:
             logging.error('Could not delete itemid: %s (%s)', itemid, e)
Example #30
0
    def cleanup(self):
        """
        Do some cleanup after the real request.
        """
        # Remove created resources
        href = joinURL(self.sessions[1].calendarHref, "organizer.ics")
        self.sessions[1].deleteResource(URL(path=href))

        # Remove the attendee event and inbox items
        props = (davxml.resourcetype,)
        results = self.sessions[0].getPropertiesOnHierarchy(URL(path=self.sessions[0].calendarHref), props)
        for href in results.keys():
            if len(href.split("/")[-1]) > 10:
                self.sessions[0].deleteResource(URL(path=href))
        results = self.sessions[0].getPropertiesOnHierarchy(URL(path=self.sessions[0].inboxHref), props)
        for href in results.keys():
            if href != self.sessions[0].inboxHref:
                self.sessions[0].deleteResource(URL(path=href))
Example #31
0
 def getDetails(self):
     resource = URL(url=self.path + "/")
     props = (davxml.resourcetype,)
     props += (davxml.getcontentlength, davxml.getlastmodified,)
     props, _ignore_bad = self.session.account.session.getProperties(resource, props)
     size = props.get(davxml.getcontentlength, "-")
     if not size:
         size = "0"
     modtime = props.get(davxml.getlastmodified, "-")
     return ["Size: %s" % (size,), "Modtime: %s" % (modtime,)]
Example #32
0
 def parsePropElementHref(self, prop, result, is_list):
     # Grab the element data
     hrefs = tuple([URL(url=href.text, decode=True) for href in prop.findall(str(davxml.href))])
     if not is_list:
         if len(hrefs) == 1:
             hrefs = hrefs[0]
         else:
             hrefs = ""
     result.addHrefProperty(QName(prop.tag), hrefs)
     result.addNodeProperty(QName(prop.tag), prop)
    def _getProperties(self):
        assert (self.session is not None)

        results, _ignore_bad = self.session.getProperties(
            URL(url=self.path), (
                davxml.displayname,
                carddavxml.addressbook_description,
            ))
        self.displayname = results.get(davxml.displayname, "")
        self.description = results.get(carddavxml.addressbook_description, "")
Example #34
0
    def execute(self, cmdname, options):

        fname = None
        content_type = "text/plain"
        path = None

        opts, args = getopt.getopt(shlex.split(options), 'f:t:')

        for name, value in opts:

            if name == "-f":
                fname = value
            elif name == "-t":
                content_type = value
            else:
                print "Unknown option: %s" % (name, )
                print self.usage(cmdname)
                raise WrongOptions

        if not fname:
            print "File name must be provided"
            print self.usage(cmdname)
            raise WrongOptions

        elif len(args) > 1:
            print "Wrong number of arguments: %d" % (len(args), )
            print self.usage(cmdname)
            raise WrongOptions
        elif args:
            path = args[0]
            if not path.startswith("/"):
                path = os.path.join(self.shell.wd, path)
            if path.endswith("/"):
                print "Cannot PUT to a directory: %s" % (path, )
                print self.usage(cmdname)
                raise WrongOptions
        else:
            print "Path to PUT to must be provided"
            print self.usage(cmdname)
            raise WrongOptions

        # Read in data
        fname = os.path.expanduser(fname)
        try:
            with open(fname, "r") as f:
                data = f.read()
        except IOError:
            print "Unable to read data from file: %s" % (fname, )
            print self.usage(cmdname)
            raise WrongOptions

        resource = URL(url=path)
        self.shell.account.session.writeData(resource, data, content_type)

        return True
Example #35
0
    def getHrefListProperty(self, rurl, propname):

        assert (isinstance(rurl, URL))

        results = ()

        # Create WebDAV propfind
        request = PropFind(self, rurl.relativeURL(), headers.Depth0,
                           (propname, ))
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result and extract any Hrefs
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match the URL the request was actually targeted at
                if name.equalRelative(URL(url=request.url)):

                    if str(propname) in item.getNodeProperties():

                        propnode = item.getNodeProperties()[str(propname)]
                        results += tuple([
                            URL(url=href.text, decode=True)
                            for href in propnode.findall(str(davxml.href))
                            if href.text
                        ])
        else:
            self.handleHTTPError(request)

        return results
    def getPropertiesOnHierarchy(self, rurl, props):

        assert(isinstance(rurl, URL))

        results = {}

        # Create WebDAV propfind
        request = PropFind(self, rurl.relativeURL(), headers.Depth1, props)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)
                propresults = {}
                results[name.relativeURL()] = propresults

                for prop in props:

                    if str(prop) in item.getTextProperties():
                        propresults[prop] = item.getTextProperties().get(str(prop))

                    elif str(prop) in item.getNodeProperties():
                        propresults[prop] = item.getNodeProperties()[str(prop)]
        else:
            self.handleHTTPError(request)

        return results
Example #37
0
    def _refresh_contacts (self):
        logging.debug('Refreshing Contacts for folder %s...',
                      self.get_name())
        self.reset_contacts()
        ## Now fetch from server

        sess  = self.get_db().session()
        path  = URL(url=self.get_itemid())
        props = (davxml.getetag,)
        items = sess.getPropertiesOnHierarchy(path, props)

        hrefs = [x for x in items.keys() if x != path.toString().strip()]
        etags = [items[x].get(davxml.getetag, "-") for x in items.keys()]

        cons  = self.find_items(hrefs)

        for con in cons:
            self.add_contact(con)
            logging.debug('Successfully fetched and added contact: %s',
                          con.get_disp_name())

        logging.debug('Refreshing Contacts for folder %s..done.',
                      self.get_name())
    def getHrefListProperty(self, rurl, propname):

        assert(isinstance(rurl, URL))

        results = ()

        # Create WebDAV propfind
        request = PropFind(self, rurl.relativeURL(), headers.Depth0, (propname,))
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result and extract any Hrefs
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):

                    if str(propname) in item.getNodeProperties():

                        propnode = item.getNodeProperties()[str(propname)]
                        results += tuple([URL(url=href.text, decode=True) for href in propnode.findall(str(davxml.href)) if href.text])
        else:
            self.handleHTTPError(request)

        return results
class CalDAVSession(Session):

    class logger(object):

        def write(self, data):
            print data.replace("\r\n", "\n"),


    def __init__(self, server, port=None, ssl=False, user="", pswd="", principal=None, root=None, logging=False):
        super(CalDAVSession, self).__init__(server, port, ssl, log=CalDAVSession.logger())

        self.loghttp = logging

        self.user = user
        self.pswd = pswd

        # Initialize state
        self.connect = None

        # Paths
        self.rootPath = URL(url=root)
        self.principalPath = URL(url=principal) if principal else None

        self._initCalDAVState()


    def _initCalDAVState(self):

        # We need to cache the server capabilities and properties
        if not self.principalPath:
            self._discoverPrincipal()


    def _discoverPrincipal(self):

        current = self.getCurrentPrincipalResource(self.rootPath)
        if current:
            self.principalPath = current
            if self.log:
                self.log.write("Found current principal path: %s\n" % (self.principalPath.absoluteURL(),))
            return

        hrefs = self.getHrefListProperty(self.rootPath, davxml.principal_collection_set)
        if not hrefs:
            return

        # For each principal collection find current principal
        for href in hrefs:
            current = self.getCurrentPrincipalResource(href)
            if current:
                self.principalPath = current
                if self.log:
                    self.log.write("Found current principal path: %s\n" % (self.principalPath.absoluteURL(),))
                return


    def setUserPswd(self, user, pswd):

        self.user = user
        self.pswd = pswd
        self.authorization = None
        self._discoverPrincipal()


    def testResource(self, rurl):

        assert(isinstance(rurl, URL))

        request = PropFind(self, rurl.relativeURL(), headers.Depth0, (davxml.resourcetype,))

        # Process it
        self.runSession(request)

        return request.getStatusCode() == statuscodes.MultiStatus


    def getPropertyNames(self, rurl):

        assert(isinstance(rurl, URL))

        results = ()

        # Create WebDAV propfind
        request = PropNames(self, rurl.relativeURL(), headers.Depth0)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):

                    results = tuple([name for name in item.getNodeProperties().iterkeys()])

        else:
            self.handleHTTPError(request)

        return results


    def getProperties(self, rurl, props, xmldata=False):

        assert(isinstance(rurl, URL))

        results = {}
        bad = None

        # Create WebDAV propfind
        if props:
            request = PropFind(self, rurl.relativeURL(), headers.Depth0, props)
        else:
            request = PropAll(self, rurl.relativeURL(), headers.Depth0)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):
                    for name, value in item.getTextProperties().iteritems():
                        results[name] = value
                    for name, value in item.getHrefProperties().iteritems():
                        if name not in results:
                            results[name] = value
                    for name, value in item.getNodeProperties().iteritems():
                        if name not in results:
                            results[name] = tostring(value) if xmldata else value
                    bad = item.getBadProperties()
        else:
            self.handleHTTPError(request)

        return results, bad


    def getPropertiesOnHierarchy(self, rurl, props):

        assert(isinstance(rurl, URL))

        results = {}

        # Create WebDAV propfind
        request = PropFind(self, rurl.relativeURL(), headers.Depth1, props)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)
                propresults = {}
                results[name.relativeURL()] = propresults

                for prop in props:

                    if str(prop) in item.getTextProperties():
                        propresults[prop] = item.getTextProperties().get(str(prop))

                    elif str(prop) in item.getNodeProperties():
                        propresults[prop] = item.getNodeProperties()[str(prop)]
        else:
            self.handleHTTPError(request)

        return results


    def getHrefListProperty(self, rurl, propname):

        assert(isinstance(rurl, URL))

        results = ()

        # Create WebDAV propfind
        request = PropFind(self, rurl.relativeURL(), headers.Depth0, (propname,))
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result and extract any Hrefs
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):

                    if str(propname) in item.getNodeProperties():

                        propnode = item.getNodeProperties()[str(propname)]
                        results += tuple([URL(url=href.text, decode=True) for href in propnode.findall(str(davxml.href)) if href.text])
        else:
            self.handleHTTPError(request)

        return results


    # Do principal-match report with self on the passed in url
    def getSelfProperties(self, rurl, props):

        assert(isinstance(rurl, URL))

        results = {}

        # Create WebDAV principal-match
        request = PrincipalMatch(self, rurl.relativeURL(), props)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each principal-match result and return first one that is appropriate
            for item in parser.getResults().itervalues():

                for prop in props:

                    if str(prop) in item.getNodeProperties():

                        href = item.getNodeProperties()[str(prop)].find(str(davxml.href))

                        if href is not None:
                            results[prop] = URL(url=href.text, decode=True)

                # We'll take the first one, whatever that is
                break

        else:
            self.handleHTTPError(request)
            return None

        return results


    # Do principal-match report with self on the passed in url
    def getSelfHrefs(self, rurl):

        assert(isinstance(rurl, URL))

        results = ()

        # Create WebDAV principal-match
        request = PrincipalMatch(self, rurl.relativeURL(), (davxml.principal_URL,))
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result and extract any Hrefs
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)
                results += (name,)

        else:
            self.handleHTTPError(request)
            return None

        return results


    # Do principal-match report with self on the passed in url
    def getSelfPrincipalResource(self, rurl):

        assert(isinstance(rurl, URL))

        hrefs = self.getHrefListProperty(rurl, davxml.principal_collection_set)
        if not hrefs:
            return None

        # For each principal collection find one that matches self
        for href in hrefs:

            results = self.getSelfHrefs(href)
            if results:
                return results[0]

        return None


    # Do current-user-principal property on the passed in url
    def getCurrentPrincipalResource(self, rurl):

        assert(isinstance(rurl, URL))

        hrefs = self.getHrefListProperty(rurl, davxml.current_user_principal)
        return hrefs[0] if hrefs else None


    def setProperties(self, rurl, props):

        assert(isinstance(rurl, URL))

        results = ()

        # Convert property data into something sensible
        converted = []
        for name, value in props:
            node = None
            if isinstance(value, types.StringType):
                node = Element(name)
                node.text = value
            elif isinstance(value, URL):
                node = Element(davxml.href)
                node.text = value.absoluteURL()
            elif isinstance(value, types.ListType) or isinstance(value, types.TupleType):
                hrefs = []
                for item in value:
                    if isinstance(item, URL):
                        href = Element(davxml.href)
                        href.text = item.relativeURL()
                        hrefs.append(href)
                    else:
                        break
                else:
                    node = Element(name)
                    map(node.append, hrefs)

            if node is not None:
                converted.append(node)

        # Create WebDAV propfind
        request = PropPatch(self, rurl.relativeURL(), converted)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):

                    for prop in item.getNodeProperties():
                        results += (prop,)

        else:
            self.handleHTTPError(request)

        return results


    def setACL(self, rurl, aces):

        assert(isinstance(rurl, URL))

        # Create WebDAV ACL
        request = ACL(self, rurl.relativeURL(), aces)

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent):
            self.handleHTTPError(request)


    def makeCollection(self, rurl):

        assert(isinstance(rurl, URL))

        # Create WebDAV MKCOL
        request = MakeCollection(self, rurl.relativeURL())

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent):
            self.handleHTTPError(request)


    def makeCalendar(self, rurl, displayname=None, description=None):

        assert(isinstance(rurl, URL))

        # Create WebDAV MKCALENDAR
        request = MakeCalendar(self, rurl.relativeURL(), displayname, description)

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent):
            self.handleHTTPError(request)


    def makeAddressBook(self, rurl, displayname=None, description=None):

        assert(isinstance(rurl, URL))

        # Create WebDAV extended MKCOL
        request = MakeAddressBook(self, rurl.relativeURL(), displayname, description)

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent):
            self.handleHTTPError(request)


    def syncCollection(self, rurl, synctoken, props=()):

        assert(isinstance(rurl, URL))

        newsynctoken = ""
        changed = set()
        removed = set()
        other = set()

        # Create WebDAV sync REPORT
        request = SyncCollection(self, rurl.relativeURL(), davxml.sync_level_1, synctoken, props)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)
                if item.status == 404:
                    removed.add(name)
                elif item.status / 100 != 2:
                    other.add(name)
                else:
                    changed.add(name)

            # Get the new token
            for node in parser.getOthers():
                if node.tag == davxml.sync_token:
                    newsynctoken = node.text
                    break

        else:
            self.handleHTTPError(request)

        return (newsynctoken, changed, removed, other,)


    def queryCollection(self, rurl, timerange, start, end, expand, props=()):

        assert(isinstance(rurl, URL))

        hrefs = set()

        # Create CalDAV query REPORT
        if timerange:
            request = QueryVEVENTTimeRange(self, rurl.relativeURL(), start, end, expand, props=props)
        else:
            raise NotImplementedError
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)
                hrefs.add(name)

        else:
            self.handleHTTPError(request)

        return hrefs


    def deleteResource(self, rurl):

        assert(isinstance(rurl, URL))

        # Create WebDAV DELETE
        request = Delete(self, rurl.relativeURL())

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.NoContent):
            self.handleHTTPError(request)


    def moveResource(self, rurlFrom, rurlTo):

        assert(isinstance(rurlFrom, URL))
        assert(isinstance(rurlTo, URL))

        # Create WebDAV MOVE
        request = Move(self, rurlFrom.relativeURL(), rurlTo.absoluteURL())

        # Process it
        self.runSession(request)

        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent):
            self.handleHTTPError(request)


    def readData(self, rurl):

        assert(isinstance(rurl, URL))

        # Create WebDAV GET
        request = Get(self, rurl.relativeURL())
        dout = ResponseDataString()
        request.setData(dout)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() != statuscodes.OK:
            self.handleHTTPError(request)
            return None

        # Look for ETag
        if request.getNewETag() is not None:

            etag = request.getNewETag()

            # Handle server bug: ETag value MUST be quoted per HTTP/1.1 S3.11
            if not etag.startswith('"'):
                etag = "\"%s\"" % (etag,)
        else:
            etag = None

        # Return data as a string and etag
        return dout.getData(), etag


    def writeData(self, rurl, data, contentType):

        assert(isinstance(rurl, URL))

        # Create WebDAV PUT
        request = Put(self, rurl.relativeURL())
        dout = RequestDataString(data, contentType)
        request.setData(dout, None)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent,):
            self.handleHTTPError(request)


    def importData(self, rurl, data, contentType):

        assert(isinstance(rurl, URL))

        # Create WebDAV POST
        request = Post(self, rurl.relativeURL())
        dout = RequestDataString(data, contentType)
        request.setData(dout, None)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (statuscodes.OK, statuscodes.MultiStatus, statuscodes.NoContent,):
            self.handleHTTPError(request)


    def addAttachment(self, rurl, filename, data, contentType, return_representation):

        assert(isinstance(rurl, URL))

        # Create WebDAV POST
        rurl.extended = "?action=attachment-add"
        request = Post(self, rurl.relativeURL())
        dout = RequestDataString(data, contentType)
        request.setRequestHeader("Content-Disposition", "attachment;filename=%s" % (filename,))
        if return_representation:
            request.setRequestHeader("Prefer", "return-representation")
        request.setData(dout, None)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent,):
            self.handleHTTPError(request)


    def updateAttachment(self, rurl, managed_id, filename, data, contentType, return_representation):

        assert(isinstance(rurl, URL))

        # Create WebDAV POST
        rurl.extended = "?action=attachment-update&managed-id=%s" % (managed_id,)
        request = Post(self, rurl.relativeURL())
        request.setRequestHeader("Content-Disposition", "attachment;filename=%s" % (filename,))
        if return_representation:
            request.setRequestHeader("Prefer", "return-representation")
        dout = RequestDataString(data, contentType)
        request.setData(dout, None)

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (statuscodes.OK, statuscodes.Created, statuscodes.NoContent,):
            self.handleHTTPError(request)


    def removeAttachment(self, rurl, managed_id):

        assert(isinstance(rurl, URL))

        # Create WebDAV POST
        rurl.extended = "?action=attachment-remove&managed-id=%s" % (managed_id,)
        request = Post(self, rurl.relativeURL())

        # Process it
        self.runSession(request)

        # Check response status
        if request.getStatusCode() not in (statuscodes.OK, statuscodes.NoContent,):
            self.handleHTTPError(request)


    def displayHTTPError(self, request):
        print request.status_code


    def openSession(self):
        # Create connection
        self.connect = SmartHTTPConnection(self.server, self.port, self.ssl)

        # Write to log file
        if self.loghttp and self.log:
            self.log.write("\n        <-------- BEGIN HTTP CONNECTION -------->\n")
            self.log.write("Server: %s\n" % (self.server,))


    def closeSession(self):
        if self.connect:
            self.connect.close()
            self.connect = None

            # Write to log file
            if self.loghttp and self.log:
                self.log.write("\n        <-------- END HTTP CONNECTION -------->\n")


    def runSession(self, request):

        ctr = 5
        while ctr:
            ctr -= 1

            self.doSession(request)

            if request and request.isRedirect():
                location = request.getResponseHeader(headers.Location)
                if location:
                    u = URL(location)
                    if not u.scheme or u.scheme in ("http", "https",):
                        # Get new server and base RURL
                        different_server = (self.server != u.server) if u.server else False

                        # Use new host in this session
                        if different_server:
                            self.setServer(u.server)

                        # Reset the request with new info
                        request.setURL(u.relativeURL())
                        request.clearResponse()

                        # Write to log file
                        if self.loghttp and self.log:
                            self.log.write("\n        <-------- HTTP REDIRECT -------->\n")
                            self.log.write("Location: %s\n" % (location,))

                        # Recyle through loop
                        continue

            # Exit when redirect does not occur
            break


    def doSession(self, request):
        # Do initialisation if not already done
        if not self.initialised:

            if not self.initialise(self.server, self.rootPath.relativeURL()):

                # Break connection with server
                self.closeConnection()
                return

        # Do the request if present
        if request:

            # Handle delayed authorization
            first_time = True
            while True:

                # Run the request actions - this will make any connection that is needed
                self.sendRequest(request)

                # Check for auth failure if none before
                if request.getStatusCode() == statuscodes.Unauthorized:

                    # If we had authorization before, then chances are auth details are wrong - so delete and try again with new auth
                    if self.hasAuthorization():

                        self.authorization = None

                        # Display error so user knows why the prompt occurs again - but not the first time
                        # as we might have a digest re-auth.
                        if not first_time:
                            self.displayHTTPError(request)

                    # Get authorization object (prompt the user) and redo the request
                    self.authorization, cancelled = self.getAuthorizor(first_time, request.getResponseHeaders(headers.WWWAuthenticate))

                    # Check for auth cancellation
                    if cancelled:
                        self.authorization = None

                    else:
                        first_time = False

                        request.clearResponse()

                        # Repeat the request loop with new authorization
                        continue

                # If we get here we are complete with auth loop
                break

        # Now close it - eventually we will do keep-alive support

        # Break connection with server
        self.closeConnection()


    def doRequest(self, request):

        # Write request headers
        self.connect.putrequest(request.method, request.url, skip_host=True, skip_accept_encoding=True)
        hdrs = request.getRequestHeaders()
        for header, value in hdrs:
            self.connect.putheader(header, value)
        self.connect.endheaders()

        # Write to log file
        if self.loghttp and self.log:
            self.log.write("\n        <-------- BEGIN HTTP REQUEST -------->\n")
            self.log.write("%s\n" % (request.getRequestStartLine(),))
            for header, value in hdrs:
                self.log.write("%s: %s\n" % (header, value))
            self.log.write("\n")

        # Write the data
        self.writeRequestData(request)

        # Blank line in log between
        if self.loghttp and self.log:
            self.log.write("\n        <-------- BEGIN HTTP RESPONSE -------->\n")

        # Get response
        response = self.connect.getresponse()

        # Get response headers
        request.setResponseStatus(response.version, response.status, response.reason)
        request.setResponseHeaders(response.msg.headers)
        if self.loghttp and self.log:
            self.log.write("HTTP/%s %s %s\r\n" % (
                {11: "1.1", 10: "1.0", 9: "0.9"}.get(response.version, "?"),
                response.status,
                response.reason
            ))
            for hdr in response.msg.headers:
                self.log.write(hdr)
            self.log.write("\n")

        # Now get the data
        self.readResponseData(request, response)

        # Trailer in log
        if self.loghttp and self.log:
            self.log.write("\n        <-------- END HTTP RESPONSE -------->\n")


    def handleHTTPError(self, request):
        print "Ignoring error: %d" % (request.getStatusCode(),)


    def getAuthorizor(self, first_time, wwwhdrs):

        for witem in wwwhdrs:
            for item in witem.split(","):
                item = item.strip()
                if item.lower().startswith("basic"):
                    return Basic(self.user, self.pswd), False
                elif item.lower().startswith("digest"):
                    return Digest(self.user, self.pswd, wwwhdrs), False
                elif item.lower().startswith("negotiate") and Kerberos is not None:
                    return Kerberos(self.user), False
        else:
            return None, True


    def writeRequestData(self, request):

        # Write the data if any present
        if request.hasRequestData():

            stream = request.getRequestData()
            if stream:
                # Tell data we are using it
                stream.start()

                # Buffered write from stream
                more = True
                while more:
                    data, more = stream.read()
                    if data:
                        self.connect.send(data)

                        if self.loghttp and self.log:
                            self.log.write(data)

                # Tell data we are done using it
                stream.stop()


    def readResponseData(self, request, response):

        # Check for data and write it
        data = response.read()

        if request.hasResponseData():
            stream = request.getResponseData()
            stream.start()
            stream.write(data)
            stream.stop()
        else:
            response.read()

        if self.loghttp and self.log:
            self.log.write(data)


    def setServerType(self, type):
        self.type = type


    def setServerDescriptor(self, txt):
        self.descriptor = txt


    def setServerCapability(self, txt):
        self.capability = txt
    def setProperties(self, rurl, props):

        assert(isinstance(rurl, URL))

        results = ()

        # Convert property data into something sensible
        converted = []
        for name, value in props:
            node = None
            if isinstance(value, types.StringType):
                node = Element(name)
                node.text = value
            elif isinstance(value, URL):
                node = Element(davxml.href)
                node.text = value.absoluteURL()
            elif isinstance(value, types.ListType) or isinstance(value, types.TupleType):
                hrefs = []
                for item in value:
                    if isinstance(item, URL):
                        href = Element(davxml.href)
                        href.text = item.relativeURL()
                        hrefs.append(href)
                    else:
                        break
                else:
                    node = Element(name)
                    map(node.append, hrefs)

            if node is not None:
                converted.append(node)

        # Create WebDAV propfind
        request = PropPatch(self, rurl.relativeURL(), converted)
        result = ResponseDataString()
        request.setOutput(result)

        # Process it
        self.runSession(request)

        # If its a 207 we want to parse the XML
        if request.getStatusCode() == statuscodes.MultiStatus:

            parser = PropFindParser()
            parser.parseData(result.getData())

            # Look at each propfind result
            for item in parser.getResults().itervalues():

                # Get child element name (decode URL)
                name = URL(url=item.getResource(), decode=True)

                # Must match rurl
                if name.equalRelative(rurl):

                    for prop in item.getNodeProperties():
                        results += (prop,)

        else:
            self.handleHTTPError(request)

        return results