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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2002 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
import os
from base64 import b64encode, b64decode
from lxml import etree
from lxml.builder import ElementMaker
from zLOG import LOG, INFO
from ERP5Diff import ERP5Diff
from DateTime import DateTime
from SyncMLConstant import SYNCML_NAMESPACE, NSMAP, MAX_LEN
from Products.ERP5.ERP5Site import getSite
E = ElementMaker(namespace=SYNCML_NAMESPACE, nsmap=NSMAP)
parser = etree.XMLParser(remove_blank_text=True)
def buildAnchorFromDate(date):
if isinstance(date, DateTime):
date = date.HTML4()
date = date.replace("-", "")
date = date.replace(":", "")
return date
def encode(format, string_to_encode):
"""
return the string_to_encode encoded with format format
"""
if not format:
return string_to_encode
if format == 'b64':
return b64encode(string_to_encode)
#elif format is .... put here the other formats
else:#if there is no format corresponding with format, raise an error
LOG('encode : unknown or not implemented format : ', INFO, format)
raise ValueError, "Sorry, the server ask for the format %s but \
it's unknow or not implemented" % format
def decode(format, string_to_decode):
"""
return the string_to_decode decoded with format format
"""
string_to_decode = string_to_decode.encode('utf-8')
if not format:
return string_to_decode
if format == 'b64':
return b64decode(string_to_decode)
#elif format is .... put here the other formats
else:#if there is no format corresponding with format, raise an error
LOG('decode : unknown or not implemented format :', INFO, format)
raise ValueError, "Sorry, the format %s is unknow or \
not implemented" % format
def isDecodeEncodeTheSame(string_encoded, string_decoded, format):
"""
return True if the string_encoded is equal to string_decoded encoded
in format
"""
return encode(format, string_decoded) == string_encoded
def xml2wbxml(xml):
"""
convert xml string to wbxml using a temporary file
"""
#LOG('xml2wbxml starting ...', DEBUG, '')
f = open('/tmp/xml2wbxml', 'w')
f.write(xml)
f.close()
os.system('/usr/bin/xml2wbxml -o /tmp/xml2wbxml /tmp/xml2wbxml')
f = open('/tmp/xml2wbxml', 'r')
wbxml = f.read()
f.close()
return wbxml
def wbxml2xml(wbxml):
"""
convert wbxml string to xml using a temporary file
"""
#LOG('wbxml2xml starting ...', DEBUG, '')
f = open('/tmp/wbxml2xml', 'w')
f.write(wbxml)
f.close()
os.system('/usr/bin/wbxml2xml -o /tmp/wbxml2xml /tmp/wbxml2xml')
f = open('/tmp/wbxml2xml', 'r')
xml = f.read()
f.close()
return xml
def getConduitByName(conduit_name):
"""
Get Conduit Object by given name.
The Conduit can be located in Any Products according to naming Convention
Products.<Product Name>.Conduit.<Conduit Module> ,if conduit_name equal module's name.
By default Conduit must be defined in Products.ERP5SyncML.Conduit.<Conduit Module>
Conduit can also be defined as Extension to have it editable through the web, in this
case its definition must be Extensions.<Conduit Module>
"""
if conduit_name.startswith('Products'):
path = conduit_name
conduit_name = conduit_name.split('.')[-1]
conduit_module = __import__(path, globals(), locals(), [''])
elif conduit_name.startswith('Extensions'):
conduit_module = __import__(conduit_name, globals(), locals(), [''])
conduit_name = conduit_name.split('.')[-1]
elif conduit_name.startswith('extension.'):
conduit_module = __import__("erp5.component."+conduit_name, globals(), locals(), [''])
conduit_name = conduit_name.split('.')[-1]
else:
from Products.ERP5SyncML import Conduit
conduit_module = __import__('.'.join([Conduit.__name__, conduit_name]),
globals(), locals(), [''])
conduit_instance = getattr(conduit_module, conduit_name)()
return conduit_instance
def resolveSyncmlStatusCode(category_id):
"""Return reference of syncml_status_code category
"""
try:
return str(int(category_id))
except ValueError:
return getSite().portal_categories.getCategoryValue(
category_id,
base_category='syncml_status_code').getReference()
def resolveSyncmlAlertCode(category_id):
"""Return reference of syncml_alert_code category
"""
try:
return str(int(category_id))
except ValueError:
return getSite().portal_categories.getCategoryValue(
category_id,
base_category='syncml_alert_code').getReference()
# def setRidWithMap(xml, subscriber):
# """
# get all the local objects of the given target id and set them the rid with
# the given source id (in the Map section)
# """
# item_list = xml.xpath('/syncml:SyncML/syncml:SyncBody/syncml:Map/syncml:MapItem',
# namespaces=xml.nsmap)
# for map_item in item_list:
# gid = '%s' % map_item.xpath('string(.//syncml:Target/syncml:LocURI)', namespaces=xml.nsmap)
# signature = subscriber.getSignatureFromGid(gid)
# rid = '%s' % map_item.xpath('string(.//syncml:Source/syncml:LocURI)', namespaces=xml.nsmap)
# signature.setRid(rid)
def getXupdateObject(object_xml=None, old_xml=None):
"""
Generate the xupdate with the new object and the old xml
"""
erp5diff = ERP5Diff()
erp5diff.compare(old_xml, object_xml)
#Upper version of ERP5Diff produce valid XML.
if erp5diff._getResultRoot():
xupdate = erp5diff.outputString()
#omit xml declaration
xupdate = xupdate[xupdate.find('<xupdate:modifications'):]
return xupdate
def cutXML(xml_string, length=None):
"""
Sliced a xml tree a return two fragment
"""
if length is None:
length = MAX_LEN
short_string = xml_string[:length]
rest_string = xml_string[length:]
xml_string = etree.CDATA(short_string.decode('utf-8'))
return xml_string, rest_string
class XMLSyncUtilsMixin(object):
def sendMail(self, fromaddr, toaddr, id_sync, msg):
"""
Send a message via email
- sync_object : this is a publication or a subscription
- message : what we want to send
"""
header = "Subject: %s\n" % id_sync
header += "To: %s\n\n" % toaddr
msg = header + msg
#LOG('SubSendMail', DEBUG,'from: %s, to: %s' % (fromaddr,toaddr))
server = smtplib.SMTP('localhost')
server.sendmail(fromaddr, toaddr, msg)
# if we want to send the email to someone else (debugging)
#server.sendmail(fromaddr, "seb@localhost", msg)
server.quit()