SubscriptionSynchronization.py 7.54 KB
Newer Older
Jean-Paul Smets's avatar
Jean-Paul Smets committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
##############################################################################
#
# Copyright (c) 2003 Nexedi SARL and Contributors. All Rights Reserved.
#          Sebastien Robin <seb@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################

import smtplib # to send emails
from Subscription import Subscription,Signature
31
from XMLSyncUtils import XMLSyncUtils, Parse
Jean-Paul Smets's avatar
Jean-Paul Smets committed
32 33
import commands
from Conduit.ERP5Conduit import ERP5Conduit
34
from DateTime import DateTime
35
from zLOG import LOG, DEBUG, INFO
Jean-Paul Smets's avatar
Jean-Paul Smets committed
36 37 38 39 40 41 42

class SubscriptionSynchronization(XMLSyncUtils):

  def SubSyncInit(self, subscription):
    """
      Send the first XML message from the client
    """
Nicolas Delaby's avatar
Nicolas Delaby committed
43
    #LOG('SubSyncInit',0,'starting....')
Jean-Paul Smets's avatar
Jean-Paul Smets committed
44
    cmd_id = 1 # specifies a SyncML message-unique command identifier
45 46
    subscription.NewAnchor()
    subscription.initLastMessageId()
Fabien Morin's avatar
Fabien Morin committed
47 48 49 50 51 52 53

    #save the actual user to use it in all the session:
    user = self.portal_membership.getAuthenticatedMember().getUserName()
    LOG('SubSyncInit, user saved :',DEBUG, user)
    subscription.setZopeUser(user)
    subscription.setAuthenticated(True)

Sebastien Robin's avatar
Sebastien Robin committed
54 55 56
    xml_list = []
    xml = xml_list.append
    xml('<SyncML>\n')
Jean-Paul Smets's avatar
Jean-Paul Smets committed
57
    # syncml header
58 59
    xml(self.SyncMLHeader(subscription.incrementSessionId(),
      subscription.incrementMessageId(), subscription.getPublicationUrl(),
60
      subscription.getSubscriptionUrl(), source_name=subscription.getLogin()))
Jean-Paul Smets's avatar
Jean-Paul Smets committed
61 62

    # syncml body
Sebastien Robin's avatar
Sebastien Robin committed
63
    xml(' <SyncBody>\n')
Jean-Paul Smets's avatar
Jean-Paul Smets committed
64 65 66 67 68

    # We have to set every object as NOT_SYNCHRONIZED
    subscription.startSynchronization()

    # alert message
Sebastien Robin's avatar
Sebastien Robin committed
69
    xml(self.SyncMLAlert(cmd_id, subscription.getSynchronizationType(),
70 71
                            subscription.getTargetURI(),
                            subscription.getSourceURI(),
72
                            subscription.getLastAnchor(),
Sebastien Robin's avatar
Sebastien Robin committed
73
                            subscription.getNextAnchor()))
Jean-Paul Smets's avatar
Jean-Paul Smets committed
74
    cmd_id += 1
75 76 77 78
    syncml_put = self.SyncMLPut(cmd_id, subscription)
    if syncml_put not in ('', None):
      xml(syncml_put)
      cmd_id += 1
Sebastien Robin's avatar
Sebastien Robin committed
79 80 81
    xml(' </SyncBody>\n')
    xml('</SyncML>\n')
    xml_a = ''.join(xml_list)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
82

Sebastien Robin's avatar
Sebastien Robin committed
83
    self.sendResponse(from_url=subscription.subscription_url,
84 85 86
        to_url=subscription.publication_url, sync_id=subscription.getTitle(),
        xml=xml_a,domain=subscription,
        content_type=subscription.getSyncContentType())
87

Sebastien Robin's avatar
Sebastien Robin committed
88
    return {'has_response':1,'xml':xml_a}
Jean-Paul Smets's avatar
Jean-Paul Smets committed
89

90
  def SubSync(self, subscription_path, msg=None, RESPONSE=None):
Jean-Paul Smets's avatar
Jean-Paul Smets committed
91 92 93
    """
      This is the synchronization method for the client
    """
94
    response = None #check if subsync replies to this messages
95
    subscription = self.unrestrictedTraverse(subscription_path)
Sebastien Robin's avatar
Sebastien Robin committed
96
    if msg==None and (subscription.getSubscriptionUrl()).find('file')>=0:
97
      msg = self.readResponse(sync_id=subscription.getSubscriptionUrl(),
Sebastien Robin's avatar
Sebastien Robin committed
98
          from_url=subscription.getSubscriptionUrl())
99
    if msg==None:
100
      response = self.SubSyncInit(subscription)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
101
    else:
102
      xml_client = msg
Sebastien Robin's avatar
Sebastien Robin committed
103
      if isinstance(xml_client, str) or isinstance(xml_client, unicode):
104
        xml_client = Parse(xml_client)
105 106 107 108 109
        status_list = self.getSyncBodyStatusList(xml_client)
        if status_list not in (None, []):
          status_code_syncHdr = status_list[0]['code']
          if status_code_syncHdr.isdigit():
            status_code_syncHdr = int(status_code_syncHdr)
110
          LOG('SubSync status code : ', DEBUG, status_code_syncHdr)
111
          if status_code_syncHdr == self.AUTH_REQUIRED:
112 113
            if self.checkChal(xml_client):
              authentication_format, authentication_type = self.getChal(xml_client)
114
              LOG('SubSync auth_required :', DEBUG, 'format:%s, type:%s' % (authentication_format, authentication_type))
115 116 117 118
              if authentication_format is not None and \
                  authentication_type is not None:
                subscription.setAuthenticationFormat(authentication_format)
                subscription.setAuthenticationType(authentication_type)
119 120 121 122
            else:
              raise ValueError, "Sorry, the server chalenge for an \
                  authentication, but the authentication format is not find"

123
            LOG('SubSync', INFO, 'Authentication required')
124
            response = self.SubSyncCred(subscription, xml_client)
125
          elif status_code_syncHdr == self.UNAUTHORIZED:
126 127
            LOG('SubSync', INFO, 'Bad authentication')
            return {'has_response':0, 'xml':xml_client}
128
          else:
129
            response = self.SubSyncModif(subscription, xml_client)
130
        else:
131
            response = self.SubSyncModif(subscription, xml_client)
132

Jean-Paul Smets's avatar
Jean-Paul Smets committed
133 134
    if RESPONSE is not None:
      RESPONSE.redirect('manageSubscriptions')
135
    else:
136
      return response
Jean-Paul Smets's avatar
Jean-Paul Smets committed
137

138
  def SubSyncCred (self, subscription, msg=None, RESPONSE=None):
139 140 141 142 143 144 145 146 147 148
    """
      This method send crendentials
    """
    cmd_id = 1 # specifies a SyncML message-unique command identifier
    xml_list = []
    xml = xml_list.append
    xml('<SyncML>\n')
    # syncml header
    data = "%s:%s" % (subscription.getLogin(), subscription.getPassword())
    data=subscription.encode(subscription.getAuthenticationFormat(), data)
149 150
    xml(self.SyncMLHeader(
      subscription.incrementSessionId(),
151
      subscription.incrementMessageId(),
152
      subscription.getPublicationUrl(),
153 154
      subscription.getSubscriptionUrl(),
      source_name=subscription.getLogin(),
155
      dataCred=data, 
156
      authentication_format=subscription.getAuthenticationFormat(),
157 158 159 160 161
      authentication_type=subscription.getAuthenticationType()))

    # syncml body
    xml(' <SyncBody>\n')

162 163 164
    # We have to set every object as NOT_SYNCHRONIZED
    subscription.startSynchronization()

165 166
    # alert message
    xml(self.SyncMLAlert(cmd_id, subscription.getSynchronizationType(),
167 168
                            subscription.getTargetURI(),
                            subscription.getSourceURI(),
169 170 171
                            subscription.getLastAnchor(),
                            subscription.getNextAnchor()))
    cmd_id += 1
172
    xml(self.SyncMLPut(cmd_id, subscription))
173
    cmd_id += 1
174
    xml('  <Final/>\n')
175 176 177 178 179 180
    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(),
181 182
        xml=xml_a,domain=subscription,
        content_type=subscription.getSyncContentType())
183

184
    return {'has_response':1, 'xml':xml_a}
185

Jean-Paul Smets's avatar
Jean-Paul Smets committed
186 187 188 189 190
  def SubSyncModif(self, subscription, xml_client):
    """
      Send the client modification, this happens after the Synchronization
      initialization
    """
191
    return self.SyncModif(subscription, xml_client)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
192 193 194