Commit ee110eaa authored by Sebastien Robin's avatar Sebastien Robin

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


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@14280 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent b3833444
......@@ -39,13 +39,22 @@ from zLOG import LOG
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
if xml_client is not None: # We have received a message
......@@ -53,55 +62,91 @@ class PublicationSynchronization(XMLSyncUtils):
next_anchor = self.getAlertNextAnchor(xml_client)
alert = self.checkAlert(xml_client)
alert_code = self.getAlertCode(xml_client)
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)
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:
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'
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,
domain=publication)
return {'has_response':1,'xml':xml}
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 @@ class PublicationSynchronization(XMLSyncUtils):
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 @@ class PublicationSynchronization(XMLSyncUtils):
subscriber.setXMLMapping(publication.getXMLMapping())
publication.addSubscriber(subscriber)
# first synchronization
result = self.PubSyncInit(publication,xml_client,subscriber=subscriber,sync_type=self.SLOW_SYNC)
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):
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)
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')
......
......@@ -723,6 +723,26 @@ class Subscription(Folder, SyncCode):
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 @@ class Subscription(Folder, SyncCode):
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()
......@@ -1010,13 +1030,50 @@ class Subscription(Folder, SyncCode):
"""
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):
"""
return the id of the last synchronisation
......
......@@ -44,38 +44,43 @@ class SubscriptionSynchronization(XMLSyncUtils):
"""
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 += '</SyncML>\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)
self.sendResponse(from_url=subscription.subscription_url, to_url=subscription.publication_url,
sync_id=subscription.getTitle(), xml=xml,domain=subscription)
self.sendResponse(from_url=subscription.subscription_url,
to_url=subscription.publication_url, sync_id=subscription.getTitle(),
xml=xml_a,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 @@ class SubscriptionSynchronization(XMLSyncUtils):
"""
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)
......
......@@ -47,6 +47,9 @@ class SyncCode(Persistent):
# 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
......
......@@ -734,9 +734,9 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
"""
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 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
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 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
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 @@ class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronizati
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:
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:/'):]
......
......@@ -46,78 +46,124 @@ from zLOG import LOG
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
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):
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
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):
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 @@ class XMLSyncUtilsMixin(SyncCode):
"""
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 @@ class XMLSyncUtilsMixin(SyncCode):
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)
......@@ -241,6 +300,38 @@ class XMLSyncUtilsMixin(SyncCode):
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):
"""
Return the value of the last anchor, in the
......@@ -251,16 +342,21 @@ class XMLSyncUtilsMixin(SyncCode):
# 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":
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 == "Last":
if subnode5.nodeType == subnode5.ELEMENT_NODE and \
subnode5.nodeName == "Last":
last_anchor = subnode5.childNodes[0].data
return last_anchor
......@@ -278,16 +374,21 @@ class XMLSyncUtilsMixin(SyncCode):
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 @@ class XMLSyncUtilsMixin(SyncCode):
# 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,10 +411,32 @@ class XMLSyncUtilsMixin(SyncCode):
# 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):
"""
Return the value of the command inside the xml_stream
......@@ -333,6 +457,7 @@ class XMLSyncUtilsMixin(SyncCode):
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 @@ class XMLSyncUtilsMixin(SyncCode):
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 @@ class XMLSyncUtilsMixin(SyncCode):
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 @@ class XMLSyncUtilsMixin(SyncCode):
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 @@ class XMLSyncUtilsMixin(SyncCode):
# 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 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
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 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
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 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
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 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
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 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
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}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment