Esempio n. 1
0
    def __init__(self, optnode):

        if optnode != None:

            nFilterType = xml2util.FindChildNode(optnode, "FilterType")
            if nFilterType == None:
                self.FilterType = 2
            else:
                self.FilterType = int(xml2util.GetNodeValue(nFilterType))

            nTruncation = xml2util.FindChildNode(optnode, "Truncation")
            if nTruncation == None:
                self.Truncation = 4
            else:
                self.Truncation = int(xml2util.GetNodeValue(nTruncation))

            nConflict = xml2util.FindChildNode(optnode, "Conflict")
            if nConflict == None:
                self.Conflict = 1
            else:
                self.Conflict = int(xml2util.GetNodeValue(nConflict))
        else:
            self.FilterType = 2
            self.Truncation = 4
            self.Conflict = 1
Esempio n. 2
0
    def _ProcessUpdateFolder(self):

        req_doc = self._ReadXMLRequest()

        self.server.logger.debug(
            "ProcessUpdateFolder: request document is \n%s",
            req_doc.serialize("utf-8", 1))

        root = req_doc.getRootElement()

        SyncKey = xml2util.GetNodeValue(xml2util.FindChildNode(
            root, "SyncKey"))
        ServerID = xml2util.GetNodeValue(
            xml2util.FindChildNode(root, "ServerId"))
        ParentID = xml2util.GetNodeValue(
            xml2util.FindChildNode(root, "ParentId"))
        DisplayName = xml2util.GetNodeValue(
            xml2util.FindChildNode(root, "DisplayName"))
        keyID, keyval = util.GetSyncKeyData(SyncKey)

        status = self.backend.DeleteFolder(ServerID)

        rsp_doc = self._CreateWBXMLDoc(
            "FolderUpdate",
            "http://synce.org/formats/airsync_wm5/folderhierarchy")
        node = rsp_doc.getRootElement()
        node.newChild(None, "Status", str(status))
        node.newChild(None, "SyncKey", keyID + (str(keyval + 1)))

        self.server.logger.debug("ProcessCreateFolder: reply document is \n%s",
                                 rsp_doc.serialize("utf-8", 1))
        self._SendWBXMLResponse(rsp_doc.serialize("utf-8", 0))
Esempio n. 3
0
    def _ProcessMoveItems(self):

        req_doc = self._ReadXMLRequest()
        self.server.logger.info("ProcessMoveItems: request is \n%s",
                                req_doc.serialize("utf-8", 1))

        rsp_doc = self._CreateWBXMLDoc(
            "Moves", "http://synce.org/formats/airsync_wm5/move")

        xp = req_doc.xpathNewContext()
        xp.xpathRegisterNs("m", "http://synce.org/formats/airsync_wm5/move")

        for n in xp.xpathEval("/m:Moves/m:Move"):

            respnode = rsp_doc.getRootElement().newChild(
                None, "Response", None)

            src_msgID = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "SrcMsgId"))
            src_fldID = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "SrcFldId"))
            dst_fldID = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "DstFldId"))

            src_msgfldr, src_msg = util.SplitCombinedID(src_msgID)

            self.server.logger.info("ProcessMoveItems: src_msgfldr is %s" %
                                    src_msgfldr)
            self.server.logger.info("ProcessMoveItems: src_fldID is %s" %
                                    src_fldID)

            respnode.newChild(None, "SrcMsgId", src_msgID)

            status = 0
            if src_msgfldr == src_fldID:
                rc = self.backend.MoveItem(src_fldID, dst_fldID, src_msg)
                if rc:
                    status = 3
                else:
                    status = 2
            else:
                status = 0

            respnode.newChild(None, "Status", str(status))
            respnode.newChild(None, "DstMsgId",
                              util.GenerateCombinedID(dst_fldID, src_msg))

        self.server.logger.debug(
            "_ProcessMoveItems: response document is \n%s",
            rsp_doc.serialize("utf-8", 1))
        self._SendWBXMLResponse(rsp_doc.serialize("utf-8", 0))
Esempio n. 4
0
    def _ProcessGetItemEstimate(self):

        req_doc = self._ReadXMLRequest()

        self.server.logger.debug(
            "_handle_get_item_estimate: request document is \n%s",
            req_doc.serialize("utf-8", 1))

        rsp_doc = self._CreateWBXMLDoc(
            "GetItemEstimate",
            "http://synce.org/formats/airsync_wm5/getitemestimate")

        xp = req_doc.xpathNewContext()
        xp.xpathRegisterNs(
            "e", "http://synce.org/formats/airsync_wm5/getitemestimate")

        for n in xp.xpathEval("/e:GetItemEstimate/e:Collections/e:Collection"):

            rsp_node = rsp_doc.getRootElement().newChild(
                None, "Response", None)

            rsp_node.newChild(None, "Status", "1")

            collclass = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "Class"))
            folderID = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "CollectionId"))
            filter = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "FilterType"))
            keystr = xml2util.GetNodeValue(xml2util.FindChildNode(
                n, "SyncKey"))

            keyID, synckey = util.GetSyncKeyData(keystr)

            firstrequest = (synckey == 0)

            coll_node = rsp_node.newChild(None, "Collection", None)
            coll_node.newChild(None, "Class", collclass)
            coll_node.newChild(None, "CollectionId", folderID)

            # get change count here. TODO: Support filter-type and sync-key

            chcount = self.backend.QueryChangeCount(folderID, firstrequest)

            coll_node.newChild(None, "Estimate", str(chcount))

        self.server.logger.debug(
            "_handle_get_item_estimate: response document is \n%s",
            rsp_doc.serialize("utf-8", 1))
        self._SendWBXMLResponse(rsp_doc.serialize("utf-8", 0))
Esempio n. 5
0
    def _ProcessKeepalive(self):

        req_doc = self._ReadXMLRequest()
        self.server.logger.info("ProcessKeepAlive: request is \n%s",
                                req_doc.serialize("utf-8", 1))

        req_node = req_doc.getRootElement()

        interval = xml2util.GetNodeValue(
            xml2util.FindChildNode(req_node, "HeartbeatInterval"))

        self.server.logger.info("ProcessKeepAlive: requested interval -%s-" %
                                interval)

        # we now know how long we have!

        if interval != "":
            ivalue = int(interval)
        else:
            ivalue = 60  # get this from config later?

        self.server.logger.info("ProcessKeepAlive: actual interval -%d-" %
                                ivalue)

        gobject.timeout_add(1000 * ivalue, self._ProcessEndKeepalive)

        return
Esempio n. 6
0
    def _ProcessGetItemEstimate(self):

        req_doc = self._ReadXMLRequest()

        self.server.logger.debug(
            "_ProcessGetItemEstimate: request document is \n%s",
            req_doc.serialize("utf-8", 1))

        rsp_doc = self._CreateWBXMLDoc(
            "GetItemEstimate",
            "http://synce.org/formats/airsync_wm5/getitemestimate")

        AvailableItemDBs = self.server.device.PshipManager.GetCurrentPartnership(
        ).deviceitemdbs

        xp = req_doc.xpathNewContext()
        xp.xpathRegisterNs(
            "e", "http://synce.org/formats/airsync_wm5/getitemestimate")

        for n in xp.xpathEval("/e:GetItemEstimate/e:Collections/e:Collection"):

            rsp_node = rsp_doc.getRootElement().newChild(
                None, "Response", None)

            rsp_node.newChild(None, "Status", "1")

            coll_cls = xml2util.GetNodeValue(xml2util.FindChildNode(
                n, "Class"))
            coll_id = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "CollectionId"))
            coll_filter = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "FilterType"))
            coll_key = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "SyncKey"))

            coll_node = rsp_node.newChild(None, "Collection", None)
            coll_node.newChild(None, "Class", coll_cls)
            coll_node.newChild(None, "CollectionId", coll_id)

            itemDB = AvailableItemDBs[SYNC_ITEM_CLASS_TO_ID[coll_cls]]
            coll_node.newChild(None, "Estimate",
                               str(itemDB.GetLocalChangeCount()))

        self.server.logger.debug(
            "_ProcessGetItemEstimate: response document is \n%s",
            rsp_doc.serialize("utf-8", 1))
        self._SendWBXMLResponse(rsp_doc)
Esempio n. 7
0
    def _ProcessCreateFolder(self):

        req_doc = self._ReadXMLRequest()

        self.server.logger.debug(
            "ProcessSyncCommand: request document is \n%s",
            req_doc.serialize("utf-8", 1))

        root = req_doc.getRootElement()
        SyncKey = xml2util.GetNodeValue(xml2util.FindChildNode(
            root, "SyncKey"))
        ParentID = xml2util.GetNodeValue(
            xml2util.FindChildNode(root, "ParentId"))
        DisplayName = xml2util.GetNodeValue(
            xml2util.FindChildNode(root, "DisplayName"))
        Type = xml2util.GetNodeValue(xml2util.FindChildNode(root, "Type"))

        self.server.logger.debug("New folder %s" % DisplayName)
        self.server.logger.debug("ParentId   %s" % ParentID)

        newID = self.backend.AddFolder(DisplayName, ParentID)

        if newID == "":
            status = 0
            newID = None
        else:
            status = 1

        rsp_doc = self._CreateWBXMLDoc(
            "FolderCreate",
            "http://synce.org/formats/airsync_wm5/folderhierarchy")
        node = rsp_doc.getRootElement()
        node.newChild(None, "Status", str(status))
        node.newChild(None, "SyncKey", self.backend.sync_key + "1")
        node.newChild(None, "ServerId", newID)

        self.server.logger.debug("ProcessCreateFolder: reply document is \n%s",
                                 rsp_doc.serialize("utf-8", 1))
        self._SendWBXMLResponse(rsp_doc.serialize("utf-8", 0))
Esempio n. 8
0
    def _ProcessFolderSync(self):

        req_doc = self._ReadXMLRequest()

        self.server.logger.debug(
            "_ProcessFolderSync: request document is\n %s",
            req_doc.serialize("utf-8", 1))

        req_folder_node = xml2util.FindChildNode(req_doc, "FolderSync")

        req_key = xml2util.GetNodeValue(
            xml2util.FindChildNode(req_folder_node, "SyncKey"))

        if req_key != "0":
            raise ValueError("SyncKey in FolderSync request is not 0")

        rsp_doc = self._CreateWBXMLDoc(
            "FolderSync",
            "http://synce.org/formats/airsync_wm5/folderhierarchy")

        rsp_folder_node = rsp_doc.getRootElement()

        rsp_folder_node.newChild(None, "Status", "1")
        rsp_folder_node.newChild(None, "SyncKey",
                                 "{00000000-0000-0000-0000-000000000000}1")

        rsp_changes_node = rsp_folder_node.newChild(None, "Changes", None)

        cpship = self.server.device.PshipManager.GetCurrentPartnership()

        rsp_changes_node.newChild(None, "Count", str(len(cpship.info.folders)))

        for server_id, data in cpship.info.folders.items():

            parent_id, display_name, type = data

            add_node = rsp_changes_node.newChild(None, "Add", None)

            add_node.newChild(None, "ServerId", server_id)
            add_node.newChild(None, "ParentId", str(parent_id))
            add_node.newChild(None, "DisplayName", display_name)
            add_node.newChild(None, "Type", str(type))

        self.server.logger.debug(
            "_ProcessFolderSync: response document is \n%s",
            rsp_doc.serialize("utf-8", 1))
        self._SendWBXMLResponse(rsp_doc)
Esempio n. 9
0
    def _ProcessSync(self):

        req_doc = self._ReadXMLRequest()
        self.server.logger.debug("_ProcessSync: request document is \n%s",
                                 req_doc.serialize("utf-8", 1))

        rsp_doc = self._CreateWBXMLDoc(
            "Sync", "http://synce.org/formats/airsync_wm5/airsync")

        rsp_colls_node = rsp_doc.getRootElement().newChild(
            None, "Collections", None)

        AvailableItemDBs = self.server.device.PshipManager.GetCurrentPartnership(
        ).deviceitemdbs

        xp = req_doc.xpathNewContext()
        xp.xpathRegisterNs("s", "http://synce.org/formats/airsync_wm5/airsync")

        for n in xp.xpathEval("/s:Sync/s:Collections/s:Collection"):

            coll_cls = xml2util.GetNodeValue(xml2util.FindChildNode(
                n, "Class"))
            coll_key = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "SyncKey"))
            coll_id = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "CollectionId"))

            first_request = (coll_key == "0")

            coll_key = "%s%d" % (coll_id, int(coll_key.split("}")[-1]) + 1)

            rsp_coll_node = rsp_colls_node.newChild(None, "Collection", None)
            rsp_coll_node.newChild(None, "Class", coll_cls)
            rsp_coll_node.newChild(None, "SyncKey", coll_key)
            rsp_coll_node.newChild(None, "CollectionId", coll_id)
            rsp_coll_node.newChild(None, "Status", "1")

            itemDB = AvailableItemDBs[SYNC_ITEM_CLASS_TO_ID[coll_cls]]

            if not first_request and itemDB.GetLocalChangeCount() > 0:

                window_size = int(
                    xml2util.GetNodeValue(
                        xml2util.FindChildNode(n, "WindowSize")))

                changes = itemDB.QueryLocalChanges(window_size)

                if itemDB.GetLocalChangeCount() > 0:
                    rsp_coll_node.newChild(None, "MoreAvailable", None)

                rsp_cmd_node = rsp_coll_node.newChild(None, "Commands", None)

                for itemID, change in changes:

                    remID, change_type, data = change

                    if change_type == CHANGE_ADDED:
                        if remID == None:
                            remID = util.generate_guid()

                    rsp_change_node = rsp_cmd_node.newChild(
                        None, CHANGE_TYPE_TO_NODE_NAME[change_type], None)
                    rsp_change_node.newChild(None, "ServerId", remID)

                    if change_type != CHANGE_DELETED:

                        os_doc = libxml2.parseDoc(data)

                        self.server.logger.debug(
                            "_ProcessSync: converting item to airsync, source is \n%s",
                            os_doc.serialize("utf-8", 1))

                        as_doc = formatapi.ConvertFormat(
                            DIR_TO_AIRSYNC, itemDB.type, os_doc,
                            self.server.device.config.config_Global.
                            cfg["OpensyncXMLFormat"])

                        self.server.logger.debug(
                            "_ProcessSync: converting item to airsync, result is \n%s",
                            as_doc.serialize("utf-8", 1))

                        rsp_change_node.addChild(as_doc.getRootElement())

                    itemDB.AcknowledgeLocalChanges([(itemID, remID)])

            rsp_responses_node = rsp_doc.getRootElement().newChild(
                None, "Responses", None)

            cmd_count = 0

            xp.setContextNode(n)
            for req_cmd_node in xp.xpathEval("s:Commands/*"):

                cmd_name = req_cmd_node.name
                chg_type = CHANGE_TYPE_FROM_NODE_NAME[cmd_name]

                if chg_type == CHANGE_ADDED:

                    rsp_response_node = rsp_responses_node.newChild(
                        None, cmd_name, None)

                    cid = xml2util.GetNodeValue(
                        xml2util.FindChildNode(req_cmd_node, "ClientId"))
                    rsp_response_node.newChild(None, "ClientId", cid)

                    remID = util.generate_guid()

                    rsp_response_node.newChild(None, "ServerId", remID)
                    rsp_response_node.newChild(None, "Status", "1")

                else:

                    remID = xml2util.GetNodeValue(
                        xml2util.FindChildNode(req_cmd_node, "ServerId"))

                xml = u""
                if chg_type in (CHANGE_ADDED, CHANGE_MODIFIED):

                    app_node = xml2util.FindChildNode(req_cmd_node,
                                                      "ApplicationData")

                    self.server.logger.debug(
                        "_ProcessSync: converting item from airsync, source is \n%s",
                        app_node.serialize("utf-8", 1))

                    os_doc = formatapi.ConvertFormat(
                        DIR_FROM_AIRSYNC, itemDB.type, app_node, self.server.
                        device.config.config_Global.cfg["OpensyncXMLFormat"])

                    self.server.logger.debug(
                        "_ProcessSync: converting item from airsync, result is \n%s",
                        os_doc.serialize("utf-8", 1))

                    xml = os_doc.serialize("utf-8", 0)

                itemDB.AddRemoteChanges([(remID, chg_type, xml)])
                cmd_count += 1

            if rsp_responses_node.children:
                rsp_coll_node.addChild(rsp_responses_node)

        self.server.logger.debug("_ProcessSync: response document is \n%s",
                                 rsp_doc.serialize("utf-8", 1))
        self._SendWBXMLResponse(rsp_doc)
Esempio n. 10
0
    def _ProcessFolderSync(self):

        req_doc = self._ReadXMLRequest()

        self.server.logger.debug(
            "_handle_foldersync: request document is\n %s",
            req_doc.serialize("utf-8", 1))

        req_folder_node = xml2util.FindChildNode(req_doc, "FolderSync")

        keydata = xml2util.GetNodeValue(
            xml2util.FindChildNode(req_folder_node, "SyncKey"))
        keyID, keyval = util.GetSyncKeyData(keydata)

        initialsync = (keyval == 0)

        if keyval == 0:
            self.server.logger.info("_ProcessFolderSync :  initial sync.")

        if keyID == "":
            keyID = self.backend.sync_key

        newKey = keyID + str(keyval + 1)

        changes = self.backend.QueryFolderChanges(initialsync)

        rsp_doc = self._CreateWBXMLDoc(
            "FolderSync",
            "http://synce.org/formats/airsync_wm5/folderhierarchy")

        rsp_folder_node = rsp_doc.getRootElement()

        rsp_folder_node.newChild(None, "Status", "1")
        rsp_folder_node.newChild(None, "SyncKey", newKey)

        rsp_changes_node = rsp_folder_node.newChild(None, "Changes", None)

        rsp_changes_node.newChild(None, "Count", str(len(changes)))

        for chg in changes:

            folderID, parentID, change, displayname, foldertype = chg

            if change == OBJECT_NEW:

                add_node = rsp_changes_node.newChild(None, "Add", None)

                add_node.newChild(None, "ServerId", folderID)
                add_node.newChild(None, "ParentId", parentID)
                add_node.newChild(None, "DisplayName", displayname)
                add_node.newChild(None, "Type", str(foldertype))

            elif change == OBJECT_TODEL:

                add_node = rsp_changes_node.newChild(None, "Delete", None)
                add_node.newChild(None, "ServerId", folderID)

            elif change == OBJECT_CHANGED:

                add_node = rsp_changes_node.newChild(None, "Update", None)

                add_node.newChild(None, "ServerId", folderID)
                add_node.newChild(None, "ParentId", parentID)
                add_node.newChild(None, "DisplayName", displayname)
                add_node.newChild(None, "Type", str(foldertype))
            else:
                self.server.logger.debug(
                    "ProcessFolderSync: unsupported change type %s" %
                    str(change))

        self.backend.AcknowledgeFolderChanges(changes)

        self.server.logger.debug(
            "handle_foldersync: response document is \n%s",
            rsp_doc.serialize("utf-8", 1))

        self._SendWBXMLResponse(rsp_doc.serialize("utf-8", 0))
Esempio n. 11
0
    def _ProcessSyncCommand(self):

        req_doc = self._ReadXMLRequest()

        self.server.logger.debug(
            "ProcessSyncCommand: request document is \n%s",
            req_doc.serialize("utf-8", 1))

        rsp_doc = self._CreateWBXMLDoc(
            "Sync", "http://synce.org/formats/airsync_wm5/airsync")

        rsp_colls_node = rsp_doc.getRootElement().newChild(
            None, "Collections", None)

        xp = req_doc.xpathNewContext()
        xp.xpathRegisterNs("s", "http://synce.org/formats/airsync_wm5/airsync")

        for n in xp.xpathEval("/s:Sync/s:Collections/s:Collection"):

            collclass = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "Class"))
            keystr = xml2util.GetNodeValue(xml2util.FindChildNode(
                n, "SyncKey"))
            folderID = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "CollectionId"))
            delasmove = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "DeletesAsMoves"))
            getchanges = xml2util.GetNodeValue(
                xml2util.FindChildNode(n, "GetChanges"))

            # get the sync key ID and value from the sync key node

            keyID, synckey = util.GetSyncKeyData(keystr)

            newKey = util.GetIncrementedSyncKey(folderID, keystr)

            # capture the options for later.

            opt_node = xml2util.FindChildNode(n, "Options")
            options = mailconv.Options(opt_node)

            # On the very first sync, the SyncKey is "0". On subsequent collections, it
            # needs to be updated from the folder ID. Basically, if we are in a first
            # request, it means 'send everything down the wire'. This is handled
            # slightly differently in an OpenSync/sync-engine situation.

            first_request = (synckey == 0)

            # build the response block to _our_ changes

            rsp_coll_node = rsp_colls_node.newChild(None, "Collection", None)

            rsp_coll_node.newChild(None, "Class", collclass)
            rsp_coll_node.newChild(None, "SyncKey", newKey)
            rsp_coll_node.newChild(None, "CollectionId", folderID)
            rsp_coll_node.newChild(None, "Status", "1")

            wsnode = xml2util.FindChildNode(n, "WindowSize")
            if wsnode != None:
                window_size = int(
                    xml2util.GetNodeValue(
                        xml2util.FindChildNode(n, "WindowSize")))
            else:
                window_size = 1000

            changes = self.backend.QueryChanges(folderID, window_size)
            changecount = len(changes)

            converter = mailconv.MailConvert(folderID)

            if changecount > 0:

                if changecount == window_size:
                    rsp_coll_node.newChild(None, "MoreAvailable", None)

                rsp_cmd_node = rsp_coll_node.newChild(None, "Commands", None)

                for itemID, change, message in changes:

                    rsp_change_node = rsp_cmd_node.newChild(
                        None, CHANGE_TYPE_TO_NODE_NAME[change], None)
                    combinedID = util.GenerateCombinedID(folderID, itemID)
                    rsp_change_node.newChild(None, "ServerId", combinedID)

                    if change != OBJECT_TODEL:

                        xmlmail = converter.MailToApplicationNode(
                            itemID, message)

                        self.server.logger.debug("document data is \n%s",
                                                 xmlmail.serialize("utf-8", 1))

                        rsp_change_node.addChild(xmlmail)

                self.backend.AcknowledgeChanges(folderID, changes)

            rsp_responses_node = rsp_doc.getRootElement().newChild(
                None, "Responses", None)
            cmd_count = 0
            xp.setContextNode(n)

            for req_cmd_node in xp.xpathEval("s:Commands/*"):

                cmd_name = req_cmd_node.name
                objtype = CHANGE_TYPE_FROM_NODE_NAME[cmd_name]

                if cmd_name == "Add":

                    # Do we need to support this for mail? We do for other class types

                    rsp_response_node = rsp_responses_node.newChild(
                        None, "Add", None)

                    cid = xml2util.GetNodeValue(
                        xml2util.FindChildNode(req_cmd_node, "ClientId"))
                    rsp_response_node.newChild(None, "ClientId", cid)
                    remID = util.generate_guid()

                    rsp_response_node.newChild(None, "ServerId", remID)
                    rsp_response_node.newChild(None, "Status", "1")

                elif cmd_name == "Fetch":

                    # we need to fetch an item

                    rsp_response_node = rsp_responses_node.newChild(
                        None, "Fetch", None)

                    remID = xml2util.GetNodeValue(
                        xml2util.FindChildNode(req_cmd_node, "ServerId"))

                    status = 0
                    item = self.backend.FetchItem(
                        util.MessageIDFromCombinedID(remID))
                    if item:
                        itemID, change, message = item
                        status = 1

                        xmlmail = converter.MailToApplicationNode(message)

                        self.server.logger.debug(
                            "Fetch: document data is \n%s",
                            xmlmail.serialize("utf-8", 1))

                        rsp_response_node.newChild(None, "Status", "1")
                        rsp_response_node.addChild(xmlmail)

                elif cmd_name == "Delete":

                    remID = xml2util.GetNodeValue(
                        xml2util.FindChildNode(req_cmd_node, "ServerId"))

                    if self.backend.DeleteItem(
                            folderID,
                            util.MessageIDFromCombinedID(remID)) == False:
                        self.server.logger.debug(
                            "Delete: deleting non-existent message ID %s" %
                            remID)
                    else:
                        self.server.logger.info(
                            "Delete: deleted message ID %s" % remID)

                else:
                    # TODO - We need to support 'Change' as this sets the 'Read' flag
                    self.server.logger.info("Unsupported command %s" %
                                            cmd_name)

                cmd_count += 1

            if rsp_responses_node.children:
                rsp_coll_node.addChild(rsp_responses_node)

        self.server.logger.debug("_handle_sync: response document is \n%s",
                                 rsp_doc.serialize("utf-8", 1))
        self._SendWBXMLResponse(rsp_doc.serialize("utf-8", 0))