SubscriptionSynchronization.py 6.89 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 34 35 36 37 38 39 40 41
import commands
from Conduit.ERP5Conduit import ERP5Conduit
from zLOG import LOG

class SubscriptionSynchronization(XMLSyncUtils):

  def SubSyncInit(self, subscription):
    """
      Send the first XML message from the client
    """
Nicolas Delaby's avatar
Nicolas Delaby committed
42
    #LOG('SubSyncInit',0,'starting....')
Jean-Paul Smets's avatar
Jean-Paul Smets committed
43
    cmd_id = 1 # specifies a SyncML message-unique command identifier
44 45
    subscription.NewAnchor()
    subscription.initLastMessageId()
Sebastien Robin's avatar
Sebastien Robin committed
46 47 48
    xml_list = []
    xml = xml_list.append
    xml('<SyncML>\n')
Jean-Paul Smets's avatar
Jean-Paul Smets committed
49
    # syncml header
Sebastien Robin's avatar
Sebastien Robin committed
50 51 52
    xml(self.SyncMLHeader(subscription.incrementSessionId(), 
      subscription.incrementMessageId(), subscription.getPublicationUrl(), 
      subscription.getSubscriptionUrl()))
Jean-Paul Smets's avatar
Jean-Paul Smets committed
53 54

    # syncml body
Sebastien Robin's avatar
Sebastien Robin committed
55
    xml(' <SyncBody>\n')
Jean-Paul Smets's avatar
Jean-Paul Smets committed
56 57 58 59 60

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

    # alert message
Sebastien Robin's avatar
Sebastien Robin committed
61
    xml(self.SyncMLAlert(cmd_id, subscription.getSynchronizationType(),
Jean-Paul Smets's avatar
Jean-Paul Smets committed
62 63
                            subscription.getPublicationUrl(),
                            subscription.getDestinationPath(),
Sebastien Robin's avatar
Sebastien Robin committed
64 65
                            subscription.getLastAnchor(), 
                            subscription.getNextAnchor()))
Jean-Paul Smets's avatar
Jean-Paul Smets committed
66 67
    cmd_id += 1

Sebastien Robin's avatar
Sebastien Robin committed
68 69 70 71 72 73 74
    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)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
75

Sebastien Robin's avatar
Sebastien Robin committed
76 77 78
    self.sendResponse(from_url=subscription.subscription_url,
        to_url=subscription.publication_url, sync_id=subscription.getTitle(), 
        xml=xml_a,domain=subscription)
79

Sebastien Robin's avatar
Sebastien Robin committed
80
    return {'has_response':1,'xml':xml_a}
Jean-Paul Smets's avatar
Jean-Paul Smets committed
81 82 83 84 85

  def SubSync(self, id, msg=None, RESPONSE=None):
    """
      This is the synchronization method for the client
    """
Nicolas Delaby's avatar
Nicolas Delaby committed
86 87
    #LOG('SubSync',0,'starting... id: %s' % str(id))
    #LOG('SubSync',0,'starting... msg: %s' % str(msg))
88
    response = None #check if subsync replies to this messages
89
    subscription = self.getSubscription(id)
90

Sebastien Robin's avatar
Sebastien Robin committed
91
    if msg==None and (subscription.getSubscriptionUrl()).find('file')>=0:
Sebastien Robin's avatar
Sebastien Robin committed
92 93
      msg = self.readResponse(sync_id=id, 
          from_url=subscription.getSubscriptionUrl())
94
    if msg==None:
95
      response = self.SubSyncInit(self.getSubscription(id))
Jean-Paul Smets's avatar
Jean-Paul Smets committed
96
    else:
97
      xml_client = msg
Sebastien Robin's avatar
Sebastien Robin committed
98
      if isinstance(xml_client, str) or isinstance(xml_client, unicode):
99
        xml_client = Parse(xml_client)
100 101 102 103 104 105
        next_status = self.getNextSyncBodyStatus(xml_client, None)
        #LOG('readResponse, next status :',0,next_status)
        if next_status is not None:
          status_code = self.getStatusCode(next_status)
          #LOG('readResponse status code :',0,status_code)
          if status_code == self.AUTH_REQUIRED:
106 107 108 109 110 111 112 113
            if self.checkChal(xml_client):
              authentication_format, authentication_type = self.getChal(xml_client)
              subscription.setAuthenticationFormat(authentication_format)
              subscription.setAuthenticationType(authentication_type)
            else:
              raise ValueError, "Sorry, the server chalenge for an \
                  authentication, but the authentication format is not find"

114 115 116 117 118 119 120 121 122
            #LOG('readResponse', 0, 'Authentication required')
            response = self.SubSyncCred(id, xml_client)
          elif status_code == self.UNAUTHORIZED:
            #LOG('readResponse', 0, 'Bad authentication')
            return {'has_response':0,'xml':xml_client}
          else:
            response = self.SubSyncModif(self.getSubscription(id), xml_client)
        else: 
            response = self.SubSyncModif(self.getSubscription(id), xml_client)
123

Jean-Paul Smets's avatar
Jean-Paul Smets committed
124 125 126

    if RESPONSE is not None:
      RESPONSE.redirect('manageSubscriptions')
127
    else:
128
      return response
Jean-Paul Smets's avatar
Jean-Paul Smets committed
129

130 131 132 133 134
  def SubSyncCred (self, id, msg=None, RESPONSE=None):
    """
      This method send crendentials
    """
    
Nicolas Delaby's avatar
Nicolas Delaby committed
135 136
    #LOG('SubSyncCred',0,'starting... id: %s' % str(id))
    #LOG('SubSyncCred',0,'starting... msg: %s' % str(msg))
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
    
    cmd_id = 1 # specifies a SyncML message-unique command identifier
    subscription = self.getSubscription(id)
    xml_list = []
    xml = xml_list.append
    xml('<SyncML>\n')
    # syncml header
    data = "%s:%s" % (subscription.getLogin(), subscription.getPassword())
    data=subscription.encode(subscription.getAuthenticationFormat(), data)
    xml(self.SyncMLHeader(subscription.getSessionId(),
      subscription.incrementMessageId(), subscription.getPublicationUrl(),
      subscription.getSubscriptionUrl(), dataCred=data, 
      authentication_format=subscription.getAuthenticationFormat(), 
      authentication_type=subscription.getAuthenticationType()))

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

    # alert message
    xml(self.SyncMLAlert(cmd_id, subscription.getSynchronizationType(),
                            subscription.getPublicationUrl(),
                            subscription.getDestinationPath(),
                            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_a = ''.join(xml_list)

    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_a}

Jean-Paul Smets's avatar
Jean-Paul Smets committed
177 178 179 180 181
  def SubSyncModif(self, subscription, xml_client):
    """
      Send the client modification, this happens after the Synchronization
      initialization
    """
182
    return self.SyncModif(subscription, xml_client)
Jean-Paul Smets's avatar
Jean-Paul Smets committed
183 184 185