| 83 | | """A simple XML DOM like class""" |
| 84 | | def __init__(self, tag=None, parent=None, attrs={}, payload=[], node=None): |
| 85 | | if node: |
| 86 | | if type(node)<>type(self): node=NodeBuilder(node).getDom() |
| 87 | | self.name,self.namespace,self.attrs,self.data,self.kids,self.parent = \ |
| 88 | | node.name,node.namespace,node.attrs,node.data,node.kids,node.parent |
| 89 | | else: |
| 90 | | self.name,self.namespace,self.attrs,self.data,self.kids,self.parent = 'tag','',{},[],[],None |
| 91 | | |
| 92 | | if tag: self.namespace, self.name = (['']+tag.split())[-2:] |
| 93 | | |
| 94 | | if parent: self.parent = parent |
| 95 | | |
| 96 | | # if self.parent and not self.namespace: self.namespace=self.parent.namespace # Doesn't checked if this neccessary |
| 97 | | |
| 98 | | for attr in attrs.keys(): |
| 99 | | self.attrs[attr]=attrs[attr] |
| 100 | | |
| 101 | | for i in payload: |
| 102 | | if type(i)==type(self): self.insertNode(i) |
| 103 | | else: self.insertXML(i) |
| 104 | | # self.insertNode(Node(node=i)) # Alternative way. Needs perfomance testing. |
| 105 | | |
| 106 | | def setParent(self, node): |
| 107 | | "Set the nodes parent node." |
| 108 | | self.parent = node |
| 109 | | |
| 110 | | def getParent(self): |
| 111 | | "return the nodes parent node." |
| 112 | | return self.parent |
| 113 | | |
| 114 | | def getName(self): |
| 115 | | "Set the nodes tag name." |
| 116 | | return self.name |
| 117 | | |
| 118 | | def setName(self,val): |
| 119 | | "Set the nodes tag name." |
| 120 | | self.name = val |
| 121 | | |
| 122 | | def putAttr(self, key, val): |
| 123 | | "Add a name/value attribute to the node." |
| 124 | | self.attrs[key] = val |
| 125 | | |
| 126 | | def getAttr(self, key): |
| 127 | | "Get a value for the nodes named attribute." |
| 128 | | try: return self.attrs[key] |
| 129 | | except: return None |
| 130 | | |
| 131 | | def putData(self, data): |
| 132 | | "Set the nodes textual data" |
| 133 | | self.data.append(data) |
| 134 | | |
| 135 | | def insertData(self, data): |
| 136 | | "Set the nodes textual data" |
| 137 | | self.data.append(data) |
| 138 | | |
| 139 | | def getData(self): |
| 140 | | "Return the nodes textual data" |
| 141 | | return ''.join(self.data) |
| 142 | | |
| 143 | | def getDataAsParts(self): |
| 144 | | "Return the node data as an array" |
| 145 | | return self.data |
| 146 | | |
| 147 | | def getNamespace(self): |
| 148 | | "Returns the nodes namespace." |
| 149 | | return self.namespace |
| 150 | | |
| 151 | | def setNamespace(self, namespace): |
| 152 | | "Set the nodes namespace." |
| 153 | | self.namespace = namespace |
| 154 | | |
| 155 | | def insertTag(self, name=None, attrs={}, payload=[], node=None): |
| 156 | | """ Add a child tag of name 'name' to the node. |
| 157 | | |
| 158 | | Returns the newly created node. |
| 159 | | """ |
| 160 | | newnode = Node(tag=name, parent=self, attrs=attrs, payload=payload, node=node) |
| 161 | | self.kids.append(newnode) |
| 162 | | return newnode |
| 163 | | |
| 164 | | def insertNode(self, node): |
| 165 | | "Add a child node to the node" |
| 166 | | self.kids.append(node) |
| 167 | | return node |
| 168 | | |
| 169 | | def insertXML(self, xml_str): |
| 170 | | "Add raw xml as a child of the node" |
| 171 | | newnode = NodeBuilder(xml_str).getDom() |
| 172 | | self.kids.append(newnode) |
| 173 | | return newnode |
| 174 | | |
| 175 | | def __str__(self): |
| 176 | | return self._xmlnode2str() |
| 177 | | |
| 178 | | def _xmlnode2str(self, parent=None): |
| 179 | | """Returns an xml ( string ) representation of the node |
| 180 | | and it children""" |
| 181 | | s = "<" + self.name |
| 182 | | if self.namespace: |
| 183 | | if parent and parent.namespace != self.namespace: |
| 184 | | s = s + " xmlns = '%s' " % self.namespace |
| 185 | | for key in self.attrs.keys(): |
| 186 | | val = ustr(self.attrs[key]) |
| 187 | | s = s + " %s='%s'" % ( key, XMLescape(val) ) |
| 188 | | s = s + ">" |
| 189 | | cnt = 0 |
| 190 | | if self.kids != None: |
| 191 | | for a in self.kids: |
| 192 | | if (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt]) |
| 193 | | s = s + a._xmlnode2str(parent=self) |
| 194 | | cnt=cnt+1 |
| 195 | | if (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt]) |
| 196 | | if not self.kids and s[-1:]=='>': |
| 197 | | s=s[:-1]+' />' |
| 198 | | else: |
| 199 | | s = s + "</" + self.name + ">" |
| 200 | | return s |
| 201 | | |
| 202 | | def getTag(self, name, index=None): |
| 203 | | """Returns a child node with tag name. Returns None |
| 204 | | if not found.""" |
| 205 | | for node in self.kids: |
| 206 | | if node.getName() == name: |
| 207 | | if not index: return node |
| 208 | | if index is not None: index-=1 |
| 209 | | return None |
| 210 | | |
| 211 | | def getTags(self, name): |
| 212 | | """Like getTag but returns a list with matching child nodes""" |
| 213 | | nodes=[] |
| 214 | | for node in self.kids: |
| 215 | | if node.getName() == name: |
| 216 | | nodes.append(node) |
| 217 | | return nodes |
| 218 | | |
| 219 | | def getChildren(self): |
| 220 | | """Returns a nodes children""" |
| 221 | | return self.kids |
| 222 | | |
| 223 | | def removeTag(self,tag): |
| 224 | | """Pops out specified child and returns it.""" |
| 225 | | if type(tag)==type(self): |
| 226 | | try: |
| 227 | | self.kids.remove(tag) |
| 228 | | return tag |
| 229 | | except: return None |
| 230 | | for node in self.kids: |
| 231 | | if node.getName()==tag: |
| 232 | | self.kids.remove(node) |
| 233 | | return node |
| | 83 | """A simple XML DOM like class""" |
| | 84 | def __init__(self, tag=None, parent=None, attrs={}, payload=[], node=None): |
| | 85 | if node: |
| | 86 | if type(node)<>type(self): node=NodeBuilder(node).getDom() |
| | 87 | self.name,self.namespace,self.attrs,self.data,self.kids,self.parent = \ |
| | 88 | node.name,node.namespace,node.attrs,node.data,node.kids,node.parent |
| | 89 | else: |
| | 90 | self.name,self.namespace,self.attrs,self.data,self.kids,self.parent = 'tag','',{},[],[],None |
| | 91 | |
| | 92 | if tag: self.namespace, self.name = (['']+tag.split())[-2:] |
| | 93 | |
| | 94 | if parent: self.parent = parent |
| | 95 | |
| | 96 | # if self.parent and not self.namespace: self.namespace=self.parent.namespace # Doesn't checked if this neccessary |
| | 97 | |
| | 98 | for attr in attrs.keys(): |
| | 99 | self.attrs[attr]=attrs[attr] |
| | 100 | |
| | 101 | for i in payload: |
| | 102 | if type(i)==type(self): self.insertNode(i) |
| | 103 | else: self.insertXML(i) |
| | 104 | # self.insertNode(Node(node=i)) # Alternative way. Needs perfomance testing. |
| | 105 | |
| | 106 | def setParent(self, node): |
| | 107 | "Set the nodes parent node." |
| | 108 | self.parent = node |
| | 109 | |
| | 110 | def getParent(self): |
| | 111 | "return the nodes parent node." |
| | 112 | return self.parent |
| | 113 | |
| | 114 | def getName(self): |
| | 115 | "Set the nodes tag name." |
| | 116 | return self.name |
| | 117 | |
| | 118 | def setName(self,val): |
| | 119 | "Set the nodes tag name." |
| | 120 | self.name = val |
| | 121 | |
| | 122 | def putAttr(self, key, val): |
| | 123 | "Add a name/value attribute to the node." |
| | 124 | self.attrs[key] = val |
| | 125 | |
| | 126 | def getAttr(self, key): |
| | 127 | "Get a value for the nodes named attribute." |
| | 128 | try: return self.attrs[key] |
| | 129 | except: return None |
| | 130 | |
| | 131 | def putData(self, data): |
| | 132 | "Set the nodes textual data" |
| | 133 | self.data.append(data) |
| | 134 | |
| | 135 | def insertData(self, data): |
| | 136 | "Set the nodes textual data" |
| | 137 | self.data.append(data) |
| | 138 | |
| | 139 | def getData(self): |
| | 140 | "Return the nodes textual data" |
| | 141 | return ''.join(self.data) |
| | 142 | |
| | 143 | def getDataAsParts(self): |
| | 144 | "Return the node data as an array" |
| | 145 | return self.data |
| | 146 | |
| | 147 | def getNamespace(self): |
| | 148 | "Returns the nodes namespace." |
| | 149 | return self.namespace |
| | 150 | |
| | 151 | def setNamespace(self, namespace): |
| | 152 | "Set the nodes namespace." |
| | 153 | self.namespace = namespace |
| | 154 | |
| | 155 | def insertTag(self, name=None, attrs={}, payload=[], node=None): |
| | 156 | """ Add a child tag of name 'name' to the node. |
| | 157 | |
| | 158 | Returns the newly created node. |
| | 159 | """ |
| | 160 | newnode = Node(tag=name, parent=self, attrs=attrs, payload=payload, node=node) |
| | 161 | self.kids.append(newnode) |
| | 162 | return newnode |
| | 163 | |
| | 164 | def insertNode(self, node): |
| | 165 | "Add a child node to the node" |
| | 166 | self.kids.append(node) |
| | 167 | return node |
| | 168 | |
| | 169 | def insertXML(self, xml_str): |
| | 170 | "Add raw xml as a child of the node" |
| | 171 | newnode = NodeBuilder(xml_str).getDom() |
| | 172 | self.kids.append(newnode) |
| | 173 | return newnode |
| | 174 | |
| | 175 | def __str__(self): |
| | 176 | return self._xmlnode2str() |
| | 177 | |
| | 178 | def _xmlnode2str(self, parent=None): |
| | 179 | """Returns an xml ( string ) representation of the node |
| | 180 | and it children""" |
| | 181 | s = "<" + self.name |
| | 182 | if self.namespace: |
| | 183 | if parent and parent.namespace != self.namespace: |
| | 184 | s = s + " xmlns = '%s' " % self.namespace |
| | 185 | for key in self.attrs.keys(): |
| | 186 | val = ustr(self.attrs[key]) |
| | 187 | s = s + " %s='%s'" % ( key, XMLescape(val) ) |
| | 188 | s = s + ">" |
| | 189 | cnt = 0 |
| | 190 | if self.kids != None: |
| | 191 | for a in self.kids: |
| | 192 | if (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt]) |
| | 193 | s = s + a._xmlnode2str(parent=self) |
| | 194 | cnt=cnt+1 |
| | 195 | if (len(self.data)-1) >= cnt: s = s + XMLescape(self.data[cnt]) |
| | 196 | if not self.kids and s[-1:]=='>': |
| | 197 | s=s[:-1]+' />' |
| | 198 | else: |
| | 199 | s = s + "</" + self.name + ">" |
| | 200 | return s |
| | 201 | |
| | 202 | def getTag(self, name, index=None): |
| | 203 | """Returns a child node with tag name. Returns None |
| | 204 | if not found.""" |
| | 205 | for node in self.kids: |
| | 206 | if node.getName() == name: |
| | 207 | if not index: return node |
| | 208 | if index is not None: index-=1 |
| | 209 | return None |
| | 210 | |
| | 211 | def getTags(self, name): |
| | 212 | """Like getTag but returns a list with matching child nodes""" |
| | 213 | nodes=[] |
| | 214 | for node in self.kids: |
| | 215 | if node.getName() == name: |
| | 216 | nodes.append(node) |
| | 217 | return nodes |
| | 218 | |
| | 219 | def getChildren(self): |
| | 220 | """Returns a nodes children""" |
| | 221 | return self.kids |
| | 222 | |
| | 223 | def removeTag(self,tag): |
| | 224 | """Pops out specified child and returns it.""" |
| | 225 | if type(tag)==type(self): |
| | 226 | try: |
| | 227 | self.kids.remove(tag) |
| | 228 | return tag |
| | 229 | except: return None |
| | 230 | for node in self.kids: |
| | 231 | if node.getName()==tag: |
| | 232 | self.kids.remove(node) |
| | 233 | return node |
| 236 | | """builds a 'minidom' from data parsed to it. Primarily for insertXML |
| 237 | | method of Node""" |
| 238 | | def __init__(self,data=None): |
| 239 | | self._parser = xml.parsers.expat.ParserCreate(namespace_separator=' ') |
| 240 | | self._parser.StartElementHandler = self.unknown_starttag |
| 241 | | self._parser.EndElementHandler = self.unknown_endtag |
| 242 | | self._parser.CharacterDataHandler = self.handle_data |
| 243 | | |
| 244 | | self.__depth = 0 |
| 245 | | self._dispatch_depth = 1 |
| 246 | | |
| 247 | | if data: self._parser.Parse(data,1) |
| 248 | | |
| 249 | | def unknown_starttag(self, tag, attrs): |
| 250 | | """XML Parser callback""" |
| 251 | | self.__depth = self.__depth + 1 |
| 252 | | self.DEBUG("DEPTH -> %i , tag -> %s, attrs -> %s" % \ |
| 253 | | (self.__depth, tag, str(attrs)),DBG_XML_PARSE ) |
| 254 | | if self.__depth == self._dispatch_depth: |
| 255 | | self._mini_dom = Node(tag=tag, attrs=attrs) |
| 256 | | self._ptr = self._mini_dom |
| 257 | | elif self.__depth > self._dispatch_depth: |
| 258 | | self._ptr.kids.append(Node(tag=tag,parent=self._ptr,attrs=attrs)) |
| 259 | | self._ptr = self._ptr.kids[-1] |
| 260 | | else: ## it the stream tag: |
| 261 | | if attrs.has_key('id'): |
| 262 | | self._incomingID = attrs['id'] |
| 263 | | self.last_is_data = False |
| 264 | | |
| 265 | | def unknown_endtag(self, tag ): |
| 266 | | """XML Parser callback""" |
| 267 | | self.DEBUG("DEPTH -> %i" % self.__depth,DBG_XML_PARSE) |
| 268 | | if self.__depth == self._dispatch_depth: |
| 269 | | self.dispatch(self._mini_dom) |
| 270 | | elif self.__depth > self._dispatch_depth: |
| 271 | | self._ptr = self._ptr.parent |
| 272 | | else: |
| 273 | | self.DEBUG("*** Stream terminated ? ****",DBG_CONN_ERROR) |
| 274 | | self.__depth = self.__depth - 1 |
| 275 | | self.last_is_data = False |
| 276 | | |
| 277 | | def handle_data(self, data): |
| 278 | | """XML Parser callback""" |
| 279 | | self.DEBUG("data-> " + data,DBG_XML_PARSE) |
| 280 | | if self.last_is_data: |
| 281 | | self._ptr.data[-1] += data |
| 282 | | else: |
| 283 | | self._ptr.data.append(data) |
| 284 | | self.last_is_data = True |
| 285 | | |
| 286 | | def dispatch(self,dom): |
| 287 | | pass |
| 288 | | |
| 289 | | def DEBUG(self,dup1,dup2=None): |
| 290 | | pass |
| 291 | | |
| 292 | | def getDom(self): |
| 293 | | return self._mini_dom |
| | 236 | """builds a 'minidom' from data parsed to it. Primarily for insertXML |
| | 237 | method of Node""" |
| | 238 | def __init__(self,data=None): |
| | 239 | self._parser = xml.parsers.expat.ParserCreate(namespace_separator=' ') |
| | 240 | self._parser.StartElementHandler = self.unknown_starttag |
| | 241 | self._parser.EndElementHandler = self.unknown_endtag |
| | 242 | self._parser.CharacterDataHandler = self.handle_data |
| | 243 | |
| | 244 | self.__depth = 0 |
| | 245 | self._dispatch_depth = 1 |
| | 246 | |
| | 247 | if data: self._parser.Parse(data,1) |
| | 248 | |
| | 249 | def unknown_starttag(self, tag, attrs): |
| | 250 | """XML Parser callback""" |
| | 251 | self.__depth = self.__depth + 1 |
| | 252 | self.DEBUG("DEPTH -> %i , tag -> %s, attrs -> %s" % \ |
| | 253 | (self.__depth, tag, str(attrs)),DBG_XML_PARSE ) |
| | 254 | if self.__depth == self._dispatch_depth: |
| | 255 | self._mini_dom = Node(tag=tag, attrs=attrs) |
| | 256 | self._ptr = self._mini_dom |
| | 257 | elif self.__depth > self._dispatch_depth: |
| | 258 | self._ptr.kids.append(Node(tag=tag,parent=self._ptr,attrs=attrs)) |
| | 259 | self._ptr = self._ptr.kids[-1] |
| | 260 | else: ## it the stream tag: |
| | 261 | if attrs.has_key('id'): |
| | 262 | self._incomingID = attrs['id'] |
| | 263 | self.last_is_data = False |
| | 264 | |
| | 265 | def unknown_endtag(self, tag ): |
| | 266 | """XML Parser callback""" |
| | 267 | self.DEBUG("DEPTH -> %i" % self.__depth,DBG_XML_PARSE) |
| | 268 | if self.__depth == self._dispatch_depth: |
| | 269 | self.dispatch(self._mini_dom) |
| | 270 | elif self.__depth > self._dispatch_depth: |
| | 271 | self._ptr = self._ptr.parent |
| | 272 | else: |
| | 273 | self.DEBUG("*** Stream terminated ? ****",DBG_CONN_ERROR) |
| | 274 | self.__depth = self.__depth - 1 |
| | 275 | self.last_is_data = False |
| | 276 | |
| | 277 | def handle_data(self, data): |
| | 278 | """XML Parser callback""" |
| | 279 | self.DEBUG("data-> " + data,DBG_XML_PARSE) |
| | 280 | if self.last_is_data: |
| | 281 | self._ptr.data[-1] += data |
| | 282 | else: |
| | 283 | self._ptr.data.append(data) |
| | 284 | self.last_is_data = True |
| | 285 | |
| | 286 | def dispatch(self,dom): |
| | 287 | pass |
| | 288 | |
| | 289 | def DEBUG(self,dup1,dup2=None): |
| | 290 | pass |
| | 291 | |
| | 292 | def getDom(self): |
| | 293 | return self._mini_dom |
| 297 | | """Extention of NodeBuilder class. Handles stream of XML stanzas. |
| 298 | | Calls dispatch method for every child of root node |
| 299 | | (stream:stream for jabber stream). |
| 300 | | attributes _read, _write and _reader must be set by external entity |
| 301 | | """ |
| 302 | | def __init__(self, namespace, |
| 303 | | debug=[DBG_ALWAYS], |
| 304 | | log=None, |
| 305 | | id=None, |
| 306 | | timestampLog=True): |
| 307 | | |
| 308 | | self._namespace = namespace |
| 309 | | |
| 310 | | self._read , self._reader , self._write = None , None , None |
| 311 | | |
| 312 | | self._incomingID = None |
| 313 | | self._outgoingID = id |
| 314 | | |
| 315 | | self._debug = _debug.Debug(debug,encoding=ENCODING) |
| 316 | | self.DEBUG = self._debug.show # makes it backwards compatible with v0.4 code |
| 317 | | |
| 318 | | self.DEBUG("stream init called",DBG_INIT) |
| 319 | | |
| 320 | | if log: |
| 321 | | if type(log) is type(""): |
| 322 | | try: |
| 323 | | self._logFH = open(log,'w') |
| 324 | | except: |
| 325 | | print "ERROR: can open %s for writing" % log |
| 326 | | sys.exit(0) |
| 327 | | else: ## assume its a stream type object |
| 328 | | self._logFH = log |
| 329 | | else: |
| 330 | | self._logFH = None |
| 331 | | self._timestampLog = timestampLog |
| 332 | | |
| 333 | | def connect(self): |
| 334 | | NodeBuilder.__init__(self) |
| 335 | | self._dispatch_depth = 2 |
| 336 | | |
| 337 | | def timestampLog(self,timestamp): |
| 338 | | """ Enable or disable the showing of a timestamp in the log. |
| 339 | | By default, timestamping is enabled. |
| 340 | | """ |
| 341 | | self._timestampLog = timestamp |
| 342 | | |
| 343 | | def read(self): |
| 344 | | """Reads incoming data. Blocks until done. Calls self.disconnected(self) if appropriate.""" |
| 345 | | try: received = self._read(BLOCK_SIZE) |
| 346 | | except: received = '' |
| 347 | | |
| 348 | | while select([self._reader],[],[],0)[0]: |
| 349 | | add = self._read(BLOCK_SIZE) |
| 350 | | received +=add |
| 351 | | if not add: break |
| 352 | | |
| 353 | | if len(received): # length of 0 means disconnect |
| 354 | | self.DEBUG("got data " + received , DBG_XML_RAW ) |
| 355 | | self.log(received, 'RECV:') |
| 356 | | else: self.disconnected(self) |
| 357 | | return received |
| 358 | | |
| 359 | | def write(self,raw_data): |
| 360 | | """Writes raw outgoing data. Blocks until done. |
| 361 | | If supplied data is not unicode string, ENCODING |
| 362 | | is used for convertion. Avoid this! |
| 363 | | Always send your data as a unicode string.""" |
| 364 | | if type(raw_data) == type(''): |
| 365 | | self.DEBUG('Non-utf-8 string "%s" passed to Stream.write! Treating it as %s encoded.'%(raw_data,ENCODING)) |
| 366 | | raw_data = unicode(raw_data,ENCODING) |
| 367 | | data_out = raw_data.encode('utf-8') |
| 368 | | try: |
| 369 | | self._write(data_out) |
| 370 | | self.log(data_out, 'SENT:') |
| 371 | | self.DEBUG("sent %s" % data_out,DBG_XML_RAW) |
| 372 | | except: |
| 373 | | self.DEBUG("xmlstream write threw error",DBG_CONN_ERROR) |
| 374 | | self.disconnected(self) |
| 375 | | |
| 376 | | def process(self, timeout=0): |
| 377 | | """Receives incoming data (if any) and processes it. |
| 378 | | Waits for data no more than timeout seconds.""" |
| 379 | | if select([self._reader],[],[],timeout)[0]: |
| 380 | | data = self.read() |
| 381 | | self._parser.Parse(data) |
| 382 | | return len(data) |
| 383 | | return '0' # Zero means that nothing received but link is alive. |
| 384 | | |
| 385 | | def disconnect(self): |
| 386 | | """Close the stream and socket""" |
| 387 | | self.write ( u"</stream:stream>" ) |
| 388 | | while self.process(): pass |
| 389 | | self._sock.close() |
| 390 | | self._sock = None |
| 391 | | |
| 392 | | def disconnected(self,conn): |
| 393 | | """Called when a Network Error or disconnection occurs.""" |
| 394 | | try: self.disconnectHandler(conn) |
| 395 | | except TypeError: self.disconnectHandler() |
| 396 | | |
| 397 | | def disconnectHandler(self,conn): ## To be overidden ## |
| 398 | | """Called when a Network Error or disconnection occurs. |
| 399 | | Designed to be overidden""" |
| 400 | | raise error("Standart disconnectionHandler called. Replace it with appropriate for your client.") |
| 401 | | |
| 402 | | def log(self, data, inout=''): |
| 403 | | """Logs data to the specified filehandle. Data is time stamped |
| 404 | | and prefixed with inout""" |
| 405 | | if self._logFH is not None: |
| 406 | | if self._timestampLog: |
| 407 | | self._logFH.write("%s - %s - %s\n" % (time.asctime(), inout, data)) |
| 408 | | else: |
| 409 | | self._logFH.write("%s - %s\n" % (inout, data ) ) |
| 410 | | self._logFH.flush() |
| 411 | | |
| 412 | | def getIncomingID(self): |
| 413 | | """Returns the streams ID""" |
| 414 | | return self._incomingID |
| 415 | | |
| 416 | | def getOutgoingID(self): |
| 417 | | """Returns the streams ID""" |
| 418 | | return self._incomingID |
| | 297 | """Extention of NodeBuilder class. Handles stream of XML stanzas. |
| | 298 | Calls dispatch method for every child of root node |
| | 299 | (stream:stream for jabber stream). |
| | 300 | attributes _read, _write and _reader must be set by external entity |
| | 301 | """ |
| | 302 | def __init__(self, namespace, |
| | 303 | debug=[DBG_ALWAYS], |
| | 304 | log=None, |
| | 305 | id=None, |
| | 306 | timestampLog=True): |
| | 307 | |
| | 308 | self._namespace = namespace |
| | 309 | |
| | 310 | self._read , self._reader , self._write = None , None , None |
| | 311 | |
| | 312 | self._incomingID = None |
| | 313 | self._outgoingID = id |
| | 314 | |
| | 315 | self._debug = _debug.Debug(debug,encoding=ENCODING) |
| | 316 | self.DEBUG = self._debug.show # makes it backwards compatible with v0.4 code |
| | 317 | |
| | 318 | self.DEBUG("stream init called",DBG_INIT) |
| | 319 | |
| | 320 | if log: |
| | 321 | if type(log) is type(""): |
| | 322 | try: |
| | 323 | self._logFH = open(log,'w') |
| | 324 | except: |
| | 325 | print "ERROR: can open %s for writing" % log |
| | 326 | sys.exit(0) |
| | 327 | else: ## assume its a stream type object |
| | 328 | self._logFH = log |
| | 329 | else: |
| | 330 | self._logFH = None |
| | 331 | self._timestampLog = timestampLog |
| | 332 | |
| | 333 | def connect(self): |
| | 334 | NodeBuilder.__init__(self) |
| | 335 | self._dispatch_depth = 2 |
| | 336 | |
| | 337 | def timestampLog(self,timestamp): |
| | 338 | """ Enable or disable the showing of a timestamp in the log. |