[Erp5-report] r14280 - /erp5/trunk/products/ERP5SyncML/
nobody at svn.erp5.org
nobody at svn.erp5.org
Mon Apr 30 16:34:22 CEST 2007
Author: seb
Date: Mon Apr 30 16:34:22 2007
New Revision: 14280
URL: http://svn.erp5.org?rev=14280&view=rev
Log:
Commit the work of Fabien
- use list of string instead of adding string to strings
in order to improve performance
- use message id instead of session id. Increase message id
for each message
- start to implement authentication
Modified:
erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py
erp5/trunk/products/ERP5SyncML/Subscription.py
erp5/trunk/products/ERP5SyncML/SubscriptionSynchronization.py
erp5/trunk/products/ERP5SyncML/SyncCode.py
erp5/trunk/products/ERP5SyncML/SynchronizationTool.py
erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py
Modified: erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py?rev=14280&r1=14279&r2=14280&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py (original)
+++ erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py Mon Apr 30 16:34:22 2007
@@ -39,12 +39,21 @@
class PublicationSynchronization(XMLSyncUtils):
- def PubSyncInit(self, publication=None, xml_client=None, subscriber=None, sync_type=None):
+ def PubSyncInit(self, publication=None, xml_client=None, subscriber=None,
+ sync_type=None, auth_required=0):
"""
Read the client xml message
Send the first XML message from the server
"""
LOG('PubSyncInit',0,'Starting... publication: %s' % str(publication))
+
+ #the session id is set at the same value of those of the client
+ subscriber.setSessionId(self.getSessionId(xml_client))
+ # for a new session, the message Id must be reset
+ subscriber.resetMessageId()
+ #the last_message_id is 1 because the message that
+ #we are about to send is the message 1
+ subscriber.initLastMessageId(1)
alert = None
# Get informations from the body
@@ -53,55 +62,91 @@
next_anchor = self.getAlertNextAnchor(xml_client)
alert = self.checkAlert(xml_client)
alert_code = self.getAlertCode(xml_client)
-
- # If slow sync, then resend everything
- if alert_code == self.SLOW_SYNC:
- LOG('Warning !!!, reseting client synchronization for subscriber:',0,subscriber)
- subscriber.resetAllSignatures()
-
- # Check if the last time synchronization is the same as the client one
- if subscriber.getNextAnchor() != last_anchor:
- if last_anchor == None:
- LOG('PubSyncInit',0,'anchor null')
+ cred = self.checkCred(xml_client)
+ #XXX this is in developement, it's just for tests
+ if not cred and auth_required:
+ LOG('PubSyncInit',0,'authentication required')
+ # Prepare the xml message for the Sync initialization package
+ cmd_id = 1 # specifies a SyncML message-unique command identifier
+ xml_list = []
+ xml = xml_list.append
+ xml('<SyncML>\n')
+ # syncml header
+ xml(self.SyncMLHeader(subscriber.getSessionId(),
+ subscriber.incrementMessageId(), subscriber.getSubscriptionUrl(),
+ publication.getPublicationUrl()))
+ # syncml body
+ xml(' <SyncBody>\n')
+ # chal message
+ xml(self.SyncMLChal(cmd_id, "SyncHdr", publication.getPublicationUrl(),
+ subscriber.getSubscriptionUrl(), "b64", "syncml:auth-basic",
+ self.UNAUTHORIZED))
+ cmd_id += 1
+
+ xml(' </SyncBody>\n')
+
+ xml('</SyncML>\n')
+ xml_a = ''.join(xml_list)
+
+ self.sendResponse(from_url=publication.getPublicationUrl(),
+ to_url=subscriber.getSubscriptionUrl(),sync_id=publication.getTitle(),
+ xml=xml_a,domain=publication)
+ else :
+ # If slow sync, then resend everything
+ if alert_code == self.SLOW_SYNC:
+ LOG('Warning !!!, reseting client synchronization for subscriber:',0,
+ subscriber)
+ subscriber.resetAllSignatures()
+
+ # Check if the last time synchronization is the same as the client one
+ mess='\nsubscriber.getNextAnchor:\t%s\nsubscriber.getLastAnchor:\t%s\
+ \nlast_anchor:\t\t\t%s\nnext_anchor:\t\t\t%s' % (subscriber.getNextAnchor(),
+ subscriber.getLastAnchor(), last_anchor, next_anchor)
+ LOG('PubSyncInit',0,mess)
+
+ if subscriber.getNextAnchor() != last_anchor:
+ if last_anchor == None:
+ LOG('PubSyncInit',0,'anchor null')
+ raise ValueError, "Sorry, the anchor was null"
+ else:
+ message = "bad anchors in PubSyncInit! " + subscriber.getNextAnchor() + \
+ " and " + last_anchor
+ LOG('PubSyncInit',0,message)
else:
- message = "bad anchors in PubSyncInit! " + subscriber.getNextAnchor() + \
- " and " + last_anchor
- LOG('PubSyncInit',0,message)
- else:
- subscriber.setNextAnchor(next_anchor)
-
+ subscriber.setNextAnchor(next_anchor)
# We have to set every object as NOT_SYNCHRONIZED
subscriber.startSynchronization()
else:
# We have started the sync from the server (may be for a conflict resolution)
pass
- xml = ""
- #if alert is not None:
- if 1:
+ if alert is not None and auth_required==0:
+ #if 1:
# Prepare the xml message for the Sync initialization package
cmd_id = 1 # specifies a SyncML message-unique command identifier
- xml = ""
- xml += '<SyncML>\n'
-
+ xml_list = []
+ xml = xml_list.append
+
+ xml('<SyncML>\n')
# syncml header
- xml += self.SyncMLHeader(subscriber.getSessionId(), "1",
- subscriber.getSubscriptionUrl(), publication.getPublicationUrl())
-
+ xml(self.SyncMLHeader(subscriber.getSessionId(),
+ subscriber.incrementMessageId(), subscriber.getSubscriptionUrl(),
+ publication.getPublicationUrl()))
# syncml body
- xml += ' <SyncBody>\n'
+ xml(' <SyncBody>\n')
# alert message
- xml += self.SyncMLAlert(cmd_id, sync_type, subscriber.getSubscriptionUrl(),
- publication.getPublicationUrl(), subscriber.getLastAnchor(), subscriber.getNextAnchor())
+ xml(self.SyncMLAlert(cmd_id, sync_type, subscriber.getSubscriptionUrl(),
+ publication.getPublicationUrl(), subscriber.getLastAnchor(),
+ subscriber.getNextAnchor()))
cmd_id += 1
- xml += ' </SyncBody>\n'
-
- xml += '</SyncML>\n'
-
- self.sendResponse(from_url=publication.getPublicationUrl(),
- to_url=subscriber.getSubscriptionUrl(),sync_id=publication.getTitle(),xml=xml,
- domain=publication)
- return {'has_response':1,'xml':xml}
+ xml(' </SyncBody>\n')
+ xml('</SyncML>\n')
+ xml_a = ''.join(xml_list)
+
+ self.sendResponse(from_url=publication.getPublicationUrl(),
+ to_url=subscriber.getSubscriptionUrl(), sync_id=publication.getTitle(),
+ xml=xml_a, domain=publication)
+ return {'has_response':1,'xml':xml_a}
def PubSync(self, id, msg=None, RESPONSE=None, subscriber=None):
@@ -118,23 +163,27 @@
publication = self.getPublication(id)
if xml_client is not None:
- if type(xml_client) in (type('a'),type(u'a')):
+ if isinstance(xml_client, str) or isinstance(xml_client, unicode):
xml_client = parseString(xml_client)
first_node = xml_client.childNodes[0]
if first_node.nodeName != "SyncML":
LOG('PubSync',0,'This is not a SyncML Message')
- return
+ raise ValueError, "Sorry, This is not a SyncML Message"
alert_code = self.getAlertCode(xml_client)
# Get informations from the header
client_header = first_node.childNodes[1]
if client_header.nodeName != "SyncHdr":
LOG('PubSync',0,'This is not a SyncML Header')
- return
+ raise ValueError, "Sorry, This is not a SyncML Header"
for subnode in client_header.childNodes:
- if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Source":
- subscription_url = str(subnode.childNodes[0].data)
+ if subnode.nodeType == subnode.ELEMENT_NODE and \
+ subnode.nodeName == "Source":
+ for subnode2 in subnode.childNodes:
+ if subnode2.nodeType == subnode2.ELEMENT_NODE and \
+ subnode2.nodeName == "LocURI":
+ subscription_url = str(subnode2.childNodes[0].data)
# Get the subscriber or create it if not already in the list
subscriber = publication.getSubscriber(subscription_url)
if subscriber == None:
@@ -142,19 +191,21 @@
subscriber.setXMLMapping(publication.getXMLMapping())
publication.addSubscriber(subscriber)
# first synchronization
- result = self.PubSyncInit(publication,xml_client,subscriber=subscriber,sync_type=self.SLOW_SYNC)
-
-
- elif self.checkAlert(xml_client) and alert_code in (self.TWO_WAY,self.SLOW_SYNC):
- result = self.PubSyncInit(publication=publication,
- xml_client=xml_client, subscriber=subscriber,sync_type=alert_code)
+ result = self.PubSyncInit(publication,xml_client,subscriber=subscriber,
+ sync_type=self.SLOW_SYNC)
+
+
+ elif self.checkAlert(xml_client) and \
+ alert_code in (self.TWO_WAY,self.SLOW_SYNC):
+ result = self.PubSyncInit(publication=publication,
+ xml_client=xml_client, subscriber=subscriber, sync_type=alert_code)
else:
result = self.PubSyncModif(publication, xml_client)
elif subscriber is not None:
# This looks like we are starting a synchronization after
# a conflict resolution by the user
- result = self.PubSyncInit(publication=publication,
- xml_client=None, subscriber=subscriber,sync_type=self.TWO_WAY)
+ result = self.PubSyncInit(publication=publication, xml_client=None,
+ subscriber=subscriber,sync_type=self.TWO_WAY)
if RESPONSE is not None:
RESPONSE.redirect('managePublications')
Modified: erp5/trunk/products/ERP5SyncML/Subscription.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/Subscription.py?rev=14280&r1=14279&r2=14280&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/Subscription.py (original)
+++ erp5/trunk/products/ERP5SyncML/Subscription.py Mon Apr 30 16:34:22 2007
@@ -660,7 +660,7 @@
self.setConduit(conduit)
Folder.__init__(self, id)
self.title = title
-
+
#self.signatures = PersitentMapping()
def getTitle(self):
@@ -723,6 +723,26 @@
self.last_session_id = session_id
return 1
+ def checkCorrectRemoteMessageId(self, message_id):
+ """
+ We will see if the last message id was the same
+ wich means that the same message was sent again
+
+ return 1 if the message id was not seen, 0 if already seen
+ """
+ last_message_id = getattr(self,'last_message_id',None)
+ LOG('checkCorrectRemoteMessageId last_message_id =',0,last_message_id)
+ LOG('checkCorrectRemoteMessageId message_id =',0,message_id)
+ if last_message_id == message_id:
+ return 0
+ self.last_message_id = message_id
+ return 1
+
+ def initLastMessageId(self, last_message_id=None):
+ """
+ set the last message id to 0
+ """
+ self.last_message_id=last_message_id
def getLastSentMessage(self):
"""
@@ -926,7 +946,7 @@
query_list = []
if query is None:
return query_list
- if type(query) is type('a'):
+ if isinstance(query, str):
query_method = getattr(destination,query,None)
if query_method is not None:
query_list = query_method()
@@ -1009,13 +1029,50 @@
return the current subscription
"""
return self
+
+ def setSessionId(self, session_id):
+ """
+ set the session id
+ """
+ self.session_id = session_id
def getSessionId(self):
"""
return the session id
"""
+ #self.session_id += 1 #to be commented
+ return self.session_id
+
+ def incrementSessionId(self):
+ """
+ increment and return the session id
+ """
self.session_id += 1
+ self.resetMessageId() # for a new session, the message Id must be reset
return self.session_id
+
+ def incrementMessageId(self):
+ """
+ return the message id
+ """
+ #self.message_id += 1
+ #return self.message_id
+ #return 5
+ value = getattr(self, 'message_id', 0)
+ self.message_id = value +1
+ return self.message_id
+
+ def getMessageId(self):
+ """
+ increment and return the message id
+ """
+ return self.message_id
+
+ def resetMessageId(self):
+ """
+ set the message id to 0
+ """
+ self.message_id = 0
def getLastAnchor(self):
"""
Modified: erp5/trunk/products/ERP5SyncML/SubscriptionSynchronization.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/SubscriptionSynchronization.py?rev=14280&r1=14279&r2=14280&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/SubscriptionSynchronization.py (original)
+++ erp5/trunk/products/ERP5SyncML/SubscriptionSynchronization.py Mon Apr 30 16:34:22 2007
@@ -44,38 +44,43 @@
"""
LOG('SubSyncInit',0,'starting....')
cmd_id = 1 # specifies a SyncML message-unique command identifier
- xml = ""
- xml += '<SyncML>\n'
-
+ xml_list = []
+ xml = xml_list.append
+ xml('<SyncML>\n')
# syncml header
- xml += self.SyncMLHeader(subscription.getSessionId(), "1",
- subscription.getPublicationUrl(), subscription.getSubscriptionUrl())
+ xml(self.SyncMLHeader(subscription.incrementSessionId(),
+ subscription.incrementMessageId(), subscription.getPublicationUrl(),
+ subscription.getSubscriptionUrl()))
# syncml body
- xml += ' <SyncBody>\n'
+ xml(' <SyncBody>\n')
subscription.NewAnchor()
+ subscription.initLastMessageId()
# We have to set every object as NOT_SYNCHRONIZED
subscription.startSynchronization()
# alert message
- xml += self.SyncMLAlert(cmd_id, subscription.getSynchronizationType(),
+ xml(self.SyncMLAlert(cmd_id, subscription.getSynchronizationType(),
subscription.getPublicationUrl(),
subscription.getDestinationPath(),
- subscription.getLastAnchor(), subscription.getNextAnchor())
+ subscription.getLastAnchor(),
+ subscription.getNextAnchor()))
cmd_id += 1
- xml += ' <Put>\n'
- xml += ' <CmdID>%s</CmdID>\n' % cmd_id ; cmd_id += 1
- xml += ' </Put>\n'
- xml += ' </SyncBody>\n'
+ xml(' <Put>\n')
+ xml(' <CmdID>%s</CmdID>\n' % cmd_id)
+ cmd_id += 1
+ xml(' </Put>\n')
+ xml(' </SyncBody>\n')
+ xml('</SyncML>\n')
+ xml_a = ''.join(xml_list)
- xml += '</SyncML>\n'
+ self.sendResponse(from_url=subscription.subscription_url,
+ to_url=subscription.publication_url, sync_id=subscription.getTitle(),
+ xml=xml_a,domain=subscription)
- self.sendResponse(from_url=subscription.subscription_url, to_url=subscription.publication_url,
- sync_id=subscription.getTitle(), xml=xml,domain=subscription)
-
- return {'has_response':1,'xml':xml}
+ return {'has_response':1,'xml':xml_a}
def SubSync(self, id, msg=None, RESPONSE=None):
"""
@@ -83,17 +88,17 @@
"""
LOG('SubSync',0,'starting... id: %s' % str(id))
LOG('SubSync',0,'starting... msg: %s' % str(msg))
-
response = None #check if subsync replies to this messages
subscription = self.getSubscription(id)
if msg==None and (subscription.getSubscriptionUrl()).find('file')>=0:
- msg = self.readResponse(sync_id=id,from_url=subscription.getSubscriptionUrl())
+ msg = self.readResponse(sync_id=id,
+ from_url=subscription.getSubscriptionUrl())
if msg==None:
response = self.SubSyncInit(self.getSubscription(id))
else:
xml_client = msg
- if type(xml_client) in (type('a'),type(u'a')):
+ if isinstance(xml_client, str) or isinstance(xml_client, unicode):
xml_client = parseString(xml_client)
response = self.SubSyncModif(self.getSubscription(id),xml_client)
Modified: erp5/trunk/products/ERP5SyncML/SyncCode.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/SyncCode.py?rev=14280&r1=14279&r2=14280&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/SyncCode.py (original)
+++ erp5/trunk/products/ERP5SyncML/SyncCode.py Mon Apr 30 16:34:22 2007
@@ -47,6 +47,9 @@
# whatever is needed to change(replace)
CONFLICT_CLIENT_WIN = 208 # The client is the "winner", we keep
# the version of the client
+ UNAUTHORIZED = 401
+ AUTH_REQUIRED = 407
+ AUTH_ACCEPTED = 212
# Difference between publication and subscription
PUB = 1
Modified: erp5/trunk/products/ERP5SyncML/SynchronizationTool.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/SynchronizationTool.py?rev=14280&r1=14279&r2=14280&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/SynchronizationTool.py (original)
+++ erp5/trunk/products/ERP5SyncML/SynchronizationTool.py Mon Apr 30 16:34:22 2007
@@ -734,9 +734,9 @@
"""
if context is None:
return context
- elif type(context) is type(()):
+ elif isinstance(context, tuple):
return context
- elif type(context) is type('a'):
+ elif isinstance(context, tuple):
return tuple(context.split('/'))
else:
return context.getPhysicalPath()
@@ -751,7 +751,7 @@
LOG('sendResponse, to_url: ',0,to_url)
LOG('sendResponse, from_url: ',0,from_url)
LOG('sendResponse, sync_id: ',0,sync_id)
- LOG('sendResponse, xml: ',0,xml)
+ LOG('sendResponse, xml: \n',0,xml)
if domain is not None:
gpg_key = domain.getGPGKey()
if gpg_key not in ('',None):
@@ -768,14 +768,14 @@
commands.getstatusoutput('rm -f /tmp/%s.gz' % filename)
commands.getstatusoutput('rm -f /tmp/%s.gz.gpg' % filename)
if send:
- if type(to_url) is type('a'):
+ if isinstance(to_url, str):
if to_url.find('http://')==0:
# XXX Make sure this is not a problem
if domain.domain_type == self.PUB:
return None
# we will send an http response
domain = aq_base(domain)
- LOG('sendResponse, will start sendHttpResponse, xml',0,xml)
+ LOG('sendResponse, will start sendHttpResponse, xml\n',0,xml)
self.activate(activity='RAMQueue').sendHttpResponse(sync_id=sync_id,
to_url=to_url,
xml=xml, domain=domain)
@@ -907,30 +907,38 @@
commands.getstatusoutput('rm -f /tmp/%s.gz.gpg' % filename)
# Get the target and then find the corresponding publication or
# Subscription
- LOG('readResponse, xml before parseSTring',0,text)
+ LOG('readResponse, xml before parseSTring\n',0,text)
xml = parseString(text)
- url = ''
- for subnode in self.getElementNodeList(xml):
- if subnode.nodeName == 'SyncML':
- for subnode1 in self.getElementNodeList(subnode):
- if subnode1.nodeName == 'SyncHdr':
- for subnode2 in self.getElementNodeList(subnode1):
- if subnode2.nodeName == 'Target':
- url = subnode2.childNodes[0].data
+
+ #XXX this function is not very optimized and should be improved
+ url = self.getTarget(xml)
+
for publication in self.getPublicationList():
if publication.getPublicationUrl()==url and publication.getTitle()==sync_id:
result = self.PubSync(sync_id,xml)
# Then encrypt the message
xml = result['xml']
- xml = self.sendResponse(xml=xml,domain=publication,send=0)
+
+ #must be commented because this method is alredy called
+ #xml = self.sendResponse(xml=xml,domain=publication,send=0)
return xml
for subscription in self.getSubscriptionList():
- if subscription.getSubscriptionUrl()==url and subscription.getTitle()==sync_id:
- result = self.activate(activity='RAMQueue').SubSync(sync_id,xml)
+ if subscription.getSubscriptionUrl()==url and \
+ subscription.getTitle()==sync_id:
+ next_status = self.getNextSyncBodyStatus(xml, None)
+ if next_status is not None:
+ status_code = self.getStatusCode(next_status)
+ LOG('readResponse status code :',0,status_code)
+ if status_code == self.UNAUTHORIZED or \
+ status_code == self.AUTH_REQUIRED:
+ LOG('readResponse', 0, 'Authentication required')
+ raise ValueError, "Authentication required"
+ else:
+ result = self.activate(activity='RAMQueue').SubSync(sync_id,xml)
#result = self.SubSync(sync_id,xml)
# we use from only if we have a file
- elif type(from_url) is type('a'):
+ elif isinstance(from_url, str):
if from_url.find('file://')==0:
try:
filename = from_url[len('file:/'):]
Modified: erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py?rev=14280&r1=14279&r2=14280&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py (original)
+++ erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py Mon Apr 30 16:34:22 2007
@@ -46,78 +46,124 @@
class XMLSyncUtilsMixin(SyncCode):
- def SyncMLHeader(self, session_id, msg_id, target, source):
+ def SyncMLHeader(self, session_id, msg_id, target, source, target_name=None,
+ source_name=None):
"""
Since the Header is always almost the same, this is the
way to set one quickly.
"""
- xml = ""
- xml += ' <SyncHdr>\n'
- xml += ' <VerDTD>1.1</VerDTD>\n'
- xml += ' <VerProto>SyncML/1.1</VerProto>\n'
- xml += ' <SessionID>%s</SessionID>\n' % session_id
- xml += ' <MsgID>%s</MsgID>\n' % msg_id
- xml += ' <Target>%s</Target>\n' % target
- xml += ' <Source>%s</Source>\n' % source
- xml += ' </SyncHdr>\n'
- return xml
-
- def SyncMLAlert(self, cmd_id, sync_code, target, source, last_anchor, next_anchor):
+ xml_list = []
+ xml = xml_list.append
+ xml(' <SyncHdr>\n')
+ xml(' <VerDTD>1.1</VerDTD>\n')
+ xml(' <VerProto>SyncML/1.1</VerProto>\n')
+ xml(' <SessionID>%s</SessionID>\n' % session_id)
+ xml(' <MsgID>%s</MsgID>\n' % msg_id)
+ xml(' <Target>\n')
+ xml(' <LocURI>%s</LocURI>\n' % target)
+ if target_name is not None:
+ xml(' <LocName>%s</LocName>\n' %target_name)
+ xml(' </Target>\n')
+ xml(' <Source>\n')
+ xml(' <LocURI>%s</LocURI>\n' % source)
+ if source_name is not None:
+ xml(' <LocName>%s</LocName>\n' % source_name)
+ xml(' </Source>\n')
+ xml(' </SyncHdr>\n')
+ xml_a = ''.join(xml_list)
+ return xml_a
+
+ def SyncMLAlert(self, cmd_id, sync_code, target, source, last_anchor,
+ next_anchor):
"""
Since the Alert section is always almost the same, this is the
way to set one quickly.
"""
- xml = ""
- xml += ' <Alert>\n'
- xml += ' <CmdID>%s</CmdID>\n' % cmd_id
- xml += ' <Data>%s</Data>\n' % sync_code
- xml += ' <Item>\n'
- xml += ' <Target>%s</Target>\n' % target
- xml += ' <Source>%s</Source>\n' % source
- xml += ' <Meta>\n'
- xml += ' <Anchor xmlns=\'syncml:metinf\'>\n'
- xml += ' <Last>%s</Last>\n' % last_anchor
- xml += ' <Next>%s</Next>\n' % next_anchor
- xml += ' </Anchor>\n'
- xml += ' </Meta>\n'
- xml += ' </Item>\n'
- xml += ' </Alert>\n'
- return xml
-
- def SyncMLStatus(self, cmd_id, target_ref, source_ref, sync_code, next_anchor):
+ xml_list = []
+ xml = xml_list.append
+ xml(' <Alert>\n')
+ xml(' <CmdID>%s</CmdID>\n' % cmd_id)
+ xml(' <Data>%s</Data>\n' % sync_code)
+ xml(' <Item>\n')
+ xml(' <Target>\n')
+ xml(' <LocURI>%s</LocURI>\n' % target)
+ xml(' </Target>\n')
+ xml(' <Source>\n')
+ xml(' <LocURI>%s</LocURI>\n' % source)
+ xml(' </Source>\n')
+ xml(' <Meta>\n')
+ xml(' <Anchor xmlns=\'syncml:metinf\'>\n')
+ xml(' <Last>%s</Last>\n' % last_anchor)
+ xml(' <Next>%s</Next>\n' % next_anchor)
+ xml(' </Anchor>\n')
+ xml(' </Meta>\n')
+ xml(' </Item>\n')
+ xml(' </Alert>\n')
+ xml_a = ''.join(xml_list)
+ return xml_a
+
+ def SyncMLStatus(self, cmd_id, target_ref, source_ref, sync_code,
+ next_anchor):
"""
Since the Status section is always almost the same, this is the
way to set one quickly.
"""
- xml = ""
- xml += ' <Status>\n'
- xml += ' <CmdID>%s</CmdID>\n' % cmd_id
- xml += ' <TargetRef>%s</TargetRef>\n' % target_ref
- xml += ' <SourceRef>%s</SourceRef>\n' % source_ref
- xml += ' <Data>%s</Data>\n' % sync_code
- xml += ' <Item>\n'
- xml += ' <Data>\n'
- xml += ' <Anchor xmlns=\'syncml:metinf\'>\n'
- xml += ' <Next>%s</Next>\n' % next_anchor
- xml += ' </Anchor>\n'
- xml += ' </Data>\n'
- xml += ' </Item>\n'
- xml += ' </Status>\n'
- return xml
+ xml_list = []
+ xml = xml_list.append
+ xml(' <Status>\n')
+ xml(' <CmdID>%s</CmdID>\n' % cmd_id)
+ xml(' <TargetRef>%s</TargetRef>\n' % target_ref)
+ xml(' <SourceRef>%s</SourceRef>\n' % source_ref)
+ xml(' <Data>%s</Data>\n' % sync_code)
+ xml(' <Item>\n')
+ xml(' <Data>\n')
+ xml(' <Anchor xmlns=\'syncml:metinf\'>\n')
+ xml(' <Next>%s</Next>\n' % next_anchor)
+ xml(' </Anchor>\n')
+ xml(' </Data>\n')
+ xml(' </Item>\n')
+ xml(' </Status>\n')
+ xml_a = ''.join(xml_list)
+ return xml_a
def SyncMLConfirmation(self, cmd_id, target_ref, sync_code, cmd):
"""
- This is used in order ton confirm that an object was correctly
+ This is used in order to confirm that an object was correctly
synchronized
"""
- xml = ""
- xml += ' <Status>\n'
- xml += ' <CmdID>%s</CmdID>\n' % cmd_id
- xml += ' <TargetRef>%s</TargetRef>\n' % target_ref
- xml += ' <Cmd>%s</Cmd>' % cmd
- xml += ' <Data>%s</Data>\n' % sync_code
- xml += ' </Status>\n'
- return xml
+ xml_list = []
+ xml = xml_list.append
+ xml(' <Status>\n')
+ xml(' <CmdID>%s</CmdID>\n' % cmd_id)
+ xml(' <TargetRef>%s</TargetRef>\n' % target_ref)
+ xml(' <Cmd>%s</Cmd>\n' % cmd)
+ xml(' <Data>%s</Data>\n' % sync_code)
+ xml(' </Status>\n')
+ xml_a = ''.join(xml_list)
+ return xml_a
+
+ def SyncMLChal(self, cmd_id, cmd, target_ref, source_ref, auth_format,
+ auth_type, data_code):
+ """
+ This is used in order to ask crendentials
+ """
+ xml_list = []
+ xml = xml_list.append
+ xml(' <Status>\n')
+ xml(' <CmdID>%s</CmdID>\n' % cmd_id)
+ xml(' <Cmd>%s</Cmd>\n' % cmd)
+ xml(' <TargetRef>%s</TargetRef>\n' % target_ref)
+ xml(' <SourceRef>%s</SourceRef>\n' % source_ref)
+ xml(' <Chal>\n')
+ xml(' <Meta>\n')
+ xml(' <Format>%s</Format>\n' % auth_format)
+ xml(' <Type>%s</Type>\n' % auth_type)
+ xml(' </Meta>\n')
+ xml(' </Chal>\n')
+ xml(' <Data>%s</Data>\n' % str(data_code))
+ xml(' </Status>\n')
+ xml_a = ''.join(xml_list)
+ return xml_a
def sendMail(self, fromaddr, toaddr, id_sync, msg):
"""
@@ -140,55 +186,67 @@
"""
Add an object with the SyncML protocol
"""
- xml = ""
- xml += ' <Add>\n'
- xml += ' <CmdID>%s</CmdID>\n' % cmd_id
- xml += ' <Meta><Type>%s</Type></Meta>\n' % object.portal_type
- xml += ' <Item>\n'
- xml += ' <Source><LocURI>%s</LocURI></Source>\n' % gid
- xml += ' <Data>\n'
- xml += xml_string
- xml += ' </Data>\n'
+ xml_list = []
+ xml = xml_list.append
+ xml(' <Add>\n')
+ xml(' <CmdID>%s</CmdID>\n' % cmd_id)
+ xml(' <Meta><Type>%s</Type></Meta>\n' % object.portal_type)
+ xml(' <Item>\n')
+ xml(' <Source>\n')
+ xml(' <LocURI>%s</LocURI>\n' % gid)
+ xml(' </Source>\n')
+ xml(' <Data>\n')
+ xml(xml_string)
+ xml(' </Data>\n')
if more_data == 1:
- xml += ' <MoreData/>\n'
- xml += ' </Item>\n'
- xml += ' </Add>\n'
- return xml
+ xml(' <MoreData/>\n')
+ xml(' </Item>\n')
+ xml(' </Add>\n')
+ xml_a = ''.join(xml_list)
+ return xml_a
def deleteXMLObject(self, cmd_id=0, object_gid=None, xml_object=''):
"""
- Add an object with the SyncML protocol
- """
- xml = ""
- xml += ' <Delete>\n'
- xml += ' <CmdID>%s</CmdID>\n' % cmd_id
- xml += ' <Item>\n'
- xml += ' <Source><LocURI>%s</LocURI></Source>\n' % object_gid
- xml += ' <Data>\n'
- xml += ' </Data>\n'
- xml += ' </Item>\n'
- xml += ' </Delete>\n'
- return xml
+ Delete an object with the SyncML protocol
+ """
+ xml_list = []
+ xml = xml_list.append
+ xml(' <Delete>\n')
+ xml(' <CmdID>%s</CmdID>\n' % cmd_id)
+ xml(' <Item>\n')
+ xml(' <Source>\n')
+ xml(' <LocURI>%s</LocURI>\n' % object_gid)
+ xml(' </Source>\n')
+ xml(' <Data>\n')
+ xml(' </Data>\n')
+ xml(' </Item>\n')
+ xml(' </Delete>\n')
+ xml_a = ''.join(xml_list)
+ return xml_a
def replaceXMLObject(self, cmd_id=0, object=None, xml_string=None,
more_data=0,gid=None):
"""
- Add an object with the SyncML protocol
- """
- xml = ""
- xml += ' <Replace>\n'
- xml += ' <CmdID>%s</CmdID>\n' % cmd_id
- xml += ' <Meta><Type>%s</Type></Meta>\n' % object.portal_type
- xml += ' <Item>\n'
- xml += ' <Source><LocURI>%s</LocURI></Source>\n' % str(gid)
- xml += ' <Data>\n'
- xml += xml_string
- xml += ' </Data>\n'
+ Replace an object with the SyncML protocol
+ """
+ xml_list = []
+ xml = xml_list.append
+ xml(' <Replace>\n')
+ xml(' <CmdID>%s</CmdID>\n' % cmd_id)
+ xml(' <Meta><Type>%s</Type></Meta>\n' % object.portal_type)
+ xml(' <Item>\n')
+ xml(' <Source>\n')
+ xml(' <LocURI>%s</LocURI>\n' % str(gid))
+ xml(' </Source>\n')
+ xml(' <Data>\n')
+ xml(xml_string)
+ xml(' </Data>\n')
if more_data == 1:
- xml += ' <MoreData/>\n'
- xml += ' </Item>\n'
- xml += ' </Replace>\n'
- return xml
+ xml(' <MoreData/>\n')
+ xml(' </Item>\n')
+ xml(' </Replace>\n')
+ xml_a = ''.join(xml_list)
+ return xml_a
def getXupdateObject(self, object=None, xml_mapping=None, old_xml=None):
"""
@@ -206,7 +264,8 @@
file2 = open('/tmp/%s'% old_filename,'w')
file2.write(old_xml)
file2.close()
- xupdate = commands.getoutput('erp5diff /tmp/%s /tmp/%s' % (old_filename,new_filename))
+ xupdate = commands.getoutput('erp5diff /tmp/%s /tmp/%s' %
+ (old_filename,new_filename))
xupdate = xupdate[xupdate.find('<xupdate:modifications'):]
commands.getstatusoutput('rm -f /tmp/%s' % old_filename)
commands.getstatusoutput('rm -f /tmp/%s' % new_filename)
@@ -240,6 +299,38 @@
if subnode2.nodeName == 'SessionID':
session_id = int(subnode2.childNodes[0].data)
return session_id
+
+
+ def getMessageId(self, xml):
+ """
+ We will retrieve the message id of the message
+ """
+ message_id = 0
+ for subnode in self.getElementNodeList(xml):
+ if subnode.nodeName == 'SyncML':
+ for subnode1 in self.getElementNodeList(subnode):
+ if subnode1.nodeName == 'SyncHdr':
+ for subnode2 in self.getElementNodeList(subnode1):
+ if subnode2.nodeName == 'MsgID':
+ message_id = int(subnode2.childNodes[0].data)
+ return message_id
+
+ def getTarget(self, xml):
+ """
+ return the target in the SyncHdr section
+ """
+ url = ''
+ for subnode in self.getElementNodeList(xml):
+ if subnode.nodeName == 'SyncML':
+ for subnode1 in self.getElementNodeList(subnode):
+ if subnode1.nodeName == 'SyncHdr':
+ for subnode2 in self.getElementNodeList(subnode1):
+ if subnode2.nodeName == 'Target':
+ for subnode3 in self.getElementNodeList(subnode2):
+ if subnode3.nodeName == 'LocURI':
+ url = subnode3.childNodes[0].data
+ return url
+
def getAlertLastAnchor(self, xml_stream):
"""
@@ -251,18 +342,23 @@
# Get informations from the body
client_body = first_node.childNodes[3]
for subnode in client_body.childNodes:
- if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Alert":
+ if subnode.nodeType == subnode.ELEMENT_NODE and \
+ subnode.nodeName == "Alert":
for subnode2 in subnode.childNodes:
- if subnode2.nodeType == subnode2.ELEMENT_NODE and subnode2.nodeName == "Item":
+ if subnode2.nodeType == subnode2.ELEMENT_NODE and \
+ subnode2.nodeName == "Item":
for subnode3 in subnode2.childNodes:
- if subnode3.nodeType == subnode3.ELEMENT_NODE and subnode3.nodeName == "Meta":
- for subnode4 in subnode3.childNodes:
- if subnode4.nodeType == subnode4.ELEMENT_NODE and subnode4.nodeName == "Anchor":
+ if subnode3.nodeType == subnode3.ELEMENT_NODE and \
+ subnode3.nodeName == "Meta":
+ for subnode4 in subnode3.childNodes:
+ if subnode4.nodeType == subnode4.ELEMENT_NODE and \
+ subnode4.nodeName == "Anchor":
for subnode5 in subnode4.childNodes:
# Get the last time we had a synchronization
- if subnode5.nodeType == subnode5.ELEMENT_NODE and subnode5.nodeName == "Last":
+ if subnode5.nodeType == subnode5.ELEMENT_NODE and \
+ subnode5.nodeName == "Last":
last_anchor = subnode5.childNodes[0].data
- return last_anchor
+ return last_anchor
def getAlertNextAnchor(self, xml_stream):
"""
@@ -278,16 +374,21 @@
if client_body.nodeName != "SyncBody":
print "This is not a SyncML Body"
for subnode in client_body.childNodes:
- if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Alert":
+ if subnode.nodeType == subnode.ELEMENT_NODE and \
+ subnode.nodeName == "Alert":
for subnode2 in subnode.childNodes:
- if subnode2.nodeType == subnode2.ELEMENT_NODE and subnode2.nodeName == "Item":
+ if subnode2.nodeType == subnode2.ELEMENT_NODE and \
+ subnode2.nodeName == "Item":
for subnode3 in subnode2.childNodes:
- if subnode3.nodeType == subnode3.ELEMENT_NODE and subnode3.nodeName == "Meta":
+ if subnode3.nodeType == subnode3.ELEMENT_NODE and \
+ subnode3.nodeName == "Meta":
for subnode4 in subnode3.childNodes:
- if subnode4.nodeType == subnode4.ELEMENT_NODE and subnode4.nodeName == "Anchor":
+ if subnode4.nodeType == subnode4.ELEMENT_NODE and \
+ subnode4.nodeName == "Anchor":
for subnode5 in subnode4.childNodes:
# Get the last time we had a synchronization
- if subnode5.nodeType == subnode5.ELEMENT_NODE and subnode5.nodeName == "Next":
+ if subnode5.nodeType == subnode5.ELEMENT_NODE and \
+ subnode5.nodeName == "Next":
next_anchor = subnode5.childNodes[0].data
return next_anchor
@@ -298,7 +399,8 @@
# Get informations from the body
if xml.nodeName=='Status':
for subnode in xml.childNodes:
- if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'TargetRef':
+ if subnode.nodeType == subnode.ELEMENT_NODE and \
+ subnode.nodeName == 'TargetRef':
return subnode.childNodes[0].data
return None
@@ -309,9 +411,31 @@
# Get informations from the body
if xml.nodeName=='Status':
for subnode in xml.childNodes:
- if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'Data':
+ if subnode.nodeType == subnode.ELEMENT_NODE and \
+ subnode.nodeName == 'Data':
return int(subnode.childNodes[0].data)
return None
+
+
+ #def getStatusCode(self, xml):
+ # """
+ # Return the value of the alert code inside the xml_stream
+ # """
+ # # Get informations from the body
+ # first_node = xml.childNodes[0]
+ # if first_node.nodeName != "SyncML":
+ # print "This is not a SyncML message"
+ #
+ # client_body = first_node.childNodes[3]
+ # if client_body.nodeName != "SyncBody":
+ # print "This is not a SyncML Body"
+ #
+ # for subnode in client_body.childNodes:
+ # if subnode.nodeName=='Status':
+ # for subnode2 in subnode.childNodes:
+ # if subnode2.nodeType == subnode.ELEMENT_NODE and subnode2.nodeName == 'Data':
+ # return int(subnode2.childNodes[0].data)
+ # return None
def getStatusCommand(self, xml):
"""
@@ -333,6 +457,7 @@
client_body = first_node.childNodes[3]
if client_body.nodeName != "SyncBody":
LOG('XMLSyncUtils.getAlertCode',0,"This is not a SyncML Body")
+ raise ValueError, "Sorry, This is not a SyncML Body"
alert = 0
for subnode in client_body.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName=='Alert':
@@ -341,9 +466,25 @@
return int(subnode1.childNodes[0].data)
return None
+ def checkCred(self, xml_stream):
+ """
+ Check if there's a Cred section in the xml_stream
+ """
+ first_node = xml_stream.childNodes[0]
+ # Get informations from the header
+ xml_header = first_node.childNodes[1]
+ if xml_header.nodeName != "SyncHdr":
+ LOG('PubSyncModif',0,'This is not a SyncML Header')
+ raise ValueError, "Sorry, This is not a SyncML Header"
+ cred = 0
+ for subnode in xml_header.childNodes:
+ if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Cred":
+ cred=1
+ return cred
+
def checkAlert(self, xml_stream):
"""
- Check if there's an Alert section in the xml_xtream
+ Check if there's an Alert section in the xml_stream
"""
first_node = xml_stream.childNodes[0]
client_body = first_node.childNodes[3]
@@ -363,6 +504,7 @@
client_body = first_node.childNodes[3]
if client_body.nodeName != "SyncBody":
LOG('checkSync',0,"This is not a SyncML Body")
+ raise ValueError, "Sorry, This is not a SyncML Body"
for subnode in client_body.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Sync":
return 1
@@ -420,6 +562,7 @@
client_body = first_node.childNodes[3]
if client_body.nodeName != "SyncBody":
LOG('getNextSyncBodyStatus',0,"This is not a SyncML Body")
+ raise ValueError, "Sorry, This is not a SyncML Body"
next_status = None
found = None
for subnode in client_body.childNodes:
@@ -463,7 +606,7 @@
# data = subnode3.data
# data = data[data.find('<!--')+4:data.rfind('-->')]
xml = subnode3.data
- if type(xml) is type(u'a'):
+ if isinstance(xml, unicode):
xml = xml.encode('utf-8')
return xml
@@ -936,6 +1079,7 @@
xml_header = first_node.childNodes[1]
if xml_header.nodeName != "SyncHdr":
LOG('PubSyncModif',0,'This is not a SyncML Header')
+ raise ValueError, "Sorry, This is not a SyncML Header"
return
subscriber = domain # If we are the client, this is fine
@@ -944,14 +1088,17 @@
simulate = 1
for subnode in xml_header.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Source":
- subscription_url = str(subnode.childNodes[0].data)
+ for subnode2 in subnode.childNodes:
+ if subnode2.nodeType == subnode2.ELEMENT_NODE and subnode2.nodeName == 'LocURI':
+ subscription_url = str(subnode2.childNodes[0].data)
subscriber = domain.getSubscriber(subscription_url)
# We have to check if this message was not already, this can be dangerous
# to update two times the same object
- session_id = self.getSessionId(remote_xml)
- correct_session = subscriber.checkCorrectRemoteSessionId(session_id)
- if not correct_session: # We need to send again the message
+ message_id = self.getMessageId(remote_xml)
+ correct_message = subscriber.checkCorrectRemoteMessageId(message_id)
+ if not correct_message: # We need to send again the message
+ LOG('SyncModif, no correct message:',0,"sending again...")
last_xml = subscriber.getLastSentMessage()
if last_xml != '':
has_response = 1
@@ -974,7 +1121,7 @@
conduit_name = subscriber.getConduit()
conduit_module = __import__('.'.join([Conduit.__name__, conduit_name]), globals(), locals(), [''])
conduit = getattr(conduit_module, conduit_name)()
- LOG('SyncModif, subscriber: ',0,subscriber)
+ LOG('SyncModif, subscriber:',0,subscriber)
# Then apply the list of actions
(xml_confirmation,has_next_action,cmd_id) = self.applyActionList(cmd_id=cmd_id,
domain=domain,
@@ -984,16 +1131,17 @@
conduit=conduit, simulate=simulate)
LOG('SyncModif, has_next_action:',0,has_next_action)
- xml = ""
- xml += '<SyncML>\n'
-
+ xml_list = []
+ xml = xml_list.append
+ xml('<SyncML>\n')
+
# syncml header
if domain.domain_type == self.PUB:
- xml += self.SyncMLHeader(subscriber.getSessionId(), "1",
- subscriber.getSubscriptionUrl(), domain.getPublicationUrl())
+ xml(self.SyncMLHeader(subscriber.getSessionId(), subscriber.incrementMessageId(),
+ subscriber.getSubscriptionUrl(), domain.getPublicationUrl()))
elif domain.domain_type == self.SUB:
- xml += self.SyncMLHeader(domain.getSessionId(), "1",
- domain.getPublicationUrl(), domain.getSubscriptionUrl())
+ xml(self.SyncMLHeader(domain.getSessionId(), domain.incrementMessageId(),
+ domain.getPublicationUrl(), domain.getSubscriptionUrl()))
cmd_id += 1
@@ -1010,47 +1158,51 @@
conduit=conduit)
# syncml body
- xml += ' <SyncBody>\n'
+ xml(' <SyncBody>\n')
destination_url = ''
if domain.domain_type == self.PUB:
subscriber.NewAnchor()
destination_url = domain.getPublicationUrl()
- xml += self.SyncMLStatus(cmd_id, subscriber.getSubscriptionUrl(),
+ xml(self.SyncMLStatus(cmd_id, subscriber.getSubscriptionUrl(),
domain.getDestinationPath(),
subscriber.getSynchronizationType(),
- subscriber.getNextAnchor())
+ subscriber.getNextAnchor()))
elif domain.domain_type == self.SUB:
destination_url = domain.getPublicationUrl()
- xml += self.SyncMLStatus(cmd_id, domain.getPublicationUrl(),
+ xml(self.SyncMLStatus(cmd_id, domain.getPublicationUrl(),
subscriber.getDestinationPath(),
subscriber.getSynchronizationType(),
- subscriber.getNextAnchor())
+ subscriber.getNextAnchor()))
# alert message if we want more data
if destination_waiting_more_data == 1:
- xml += self.SyncMLAlert(cmd_id, self.WAITING_DATA,
+ xml(self.SyncMLAlert(cmd_id, self.WAITING_DATA,
destination_url,
domain.getDestinationPath(),
- subscriber.getLastAnchor(), subscriber.getNextAnchor())
+ subscriber.getLastAnchor(),
+ subscriber.getNextAnchor()))
# Now we should send confirmations
- xml += xml_confirmation
+ xml(xml_confirmation)
if syncml_data != '':
- xml += ' <Sync>\n'
- xml += syncml_data
- xml += ' </Sync>\n'
- xml += ' <Final/>\n'
- xml += ' </SyncBody>\n'
- xml += '</SyncML>\n'
+ xml(' <Sync>\n')
+ xml(syncml_data)
+ xml(' </Sync>\n')
+ xml(' <Final/>\n')
+ xml(' </SyncBody>\n')
+ xml('</SyncML>\n')
+ xml_a = ''.join(xml_list)
if domain.domain_type == self.PUB: # We always reply
- subscriber.setLastSentMessage(xml)
- self.sendResponse(from_url=domain.publication_url, to_url=subscriber.subscription_url,
- sync_id=domain.getTitle(), xml=xml,domain=domain)
+ subscriber.setLastSentMessage(xml_a)
+ self.sendResponse(from_url=domain.publication_url,
+ to_url=subscriber.subscription_url, sync_id=domain.getTitle(),
+ xml=xml_a,domain=domain)
has_response = 1
elif domain.domain_type == self.SUB:
if self.checkAlert(remote_xml) or \
(xml_confirmation,syncml_data)!=('','') or \
has_status_list:
- subscriber.setLastSentMessage(xml)
- self.sendResponse(from_url=domain.subscription_url, to_url=domain.publication_url,
- sync_id=domain.getTitle(), xml=xml,domain=domain)
+ subscriber.setLastSentMessage(xml_a)
+ self.sendResponse(from_url=domain.subscription_url,
+ to_url=domain.publication_url, sync_id=domain.getTitle(),
+ xml=xml_a,domain=domain)
has_response = 1
- return {'has_response':has_response,'xml':xml}
+ return {'has_response':has_response,'xml':xml_a}
More information about the Erp5-report
mailing list