Package pyxmpp :: Package jabber :: Module vcard
[hide private]

Source Code for Module pyxmpp.jabber.vcard

   1  # 
   2  # (C) Copyright 2003-2006 Jacek Konieczny <jajcus@jajcus.net> 
   3  # 
   4  # This program is free software; you can redistribute it and/or modify 
   5  # it under the terms of the GNU Lesser General Public License Version 
   6  # 2.1 as published by the Free Software Foundation. 
   7  # 
   8  # This program is distributed in the hope that it will be useful, 
   9  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
  10  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  11  # GNU Lesser General Public License for more details. 
  12  # 
  13  # You should have received a copy of the GNU Lesser General Public 
  14  # License along with this program; if not, write to the Free Software 
  15  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
  16  # 
  17  # pylint: disable-msg=W0302 
  18  """Jabber vCard and MIME (RFC 2426) vCard implementation. 
  19   
  20  Normative reference: 
  21    - `JEP 54 <http://www.jabber.org/jeps/jep-0054.html>`__ 
  22    - `RFC 2425 <http://www.ietf.org/rfc/rfc2425.txt>`__ 
  23    - `RFC 2426 <http://www.ietf.org/rfc/rfc2426.txt>`__ 
  24  """ 
  25   
  26   
  27  __revision__="$Id: vcard.py 675 2007-06-28 08:36:17Z jajcus $" 
  28  __docformat__="restructuredtext en" 
  29   
  30  import base64 
  31  import binascii 
  32  import libxml2 
  33  import re 
  34   
  35  import pyxmpp.jid 
  36  from pyxmpp.utils import to_utf8,from_utf8 
  37  from pyxmpp.xmlextra import get_node_ns 
  38  from pyxmpp.objects import StanzaPayloadObject 
  39  from pyxmpp.exceptions import BadRequestProtocolError, JIDMalformedProtocolError, JIDError 
  40   
  41  VCARD_NS="vcard-temp" 
  42   
43 -class Empty(Exception):
44 """Exception raised when parsing empty vcard element. Such element will 45 be ignored.""" 46 pass
47 48 valid_string_re=re.compile(r"^[\w\d \t]*$") 49
50 -def rfc2425encode(name,value,parameters=None,charset="utf-8"):
51 """Encodes a vCard field into an RFC2425 line. 52 53 :Parameters: 54 - `name`: field type name 55 - `value`: field value 56 - `parameters`: optional parameters 57 - `charset`: encoding of the output and of the `value` (if not 58 `unicode`) 59 :Types: 60 - `name`: `str` 61 - `value`: `unicode` or `str` 62 - `parameters`: `dict` of `str` -> `str` 63 - `charset`: `str` 64 65 :return: the encoded RFC2425 line (possibly folded) 66 :returntype: `str`""" 67 if not parameters: 68 parameters={} 69 if type(value) is unicode: 70 value=value.replace(u"\r\n",u"\\n") 71 value=value.replace(u"\n",u"\\n") 72 value=value.replace(u"\r",u"\\n") 73 value=value.encode(charset,"replace") 74 elif type(value) is not str: 75 raise TypeError,"Bad type for rfc2425 value" 76 elif not valid_string_re.match(value): 77 parameters["encoding"]="b" 78 value=binascii.b2a_base64(value) 79 80 ret=str(name).lower() 81 for k,v in parameters.items(): 82 ret+=";%s=%s" % (str(k),str(v)) 83 ret+=":" 84 while(len(value)>70): 85 ret+=value[:70]+"\r\n " 86 value=value[70:] 87 ret+=value+"\r\n" 88 return ret
89
90 -class VCardField:
91 """Base class for vCard fields. 92 93 :Ivariables: 94 - `name`: name of the field. 95 """
96 - def __init__(self,name):
97 """Initialize a `VCardField` object. 98 99 Set its name. 100 101 :Parameters: 102 - `name`: field name 103 :Types: 104 - `name`: `str`""" 105 self.name=name
106 - def __repr__(self):
107 return "<%s %r>" % (self.__class__,self.rfc2426())
108 - def rfc2426(self):
109 """RFC2426-encode the field content. 110 111 :return: the field in the RFC 2426 format. 112 :returntype: `str`""" 113 return ""
114
115 -class VCardString(VCardField):
116 """Generic class for all standard text fields in the vCard. 117 118 :Ivariables: 119 - `value`: field value. 120 :Types: 121 - `value`: `unicode`"""
122 - def __init__(self,name, value, rfc2425parameters = None, empty_ok = False):
123 """Initialize a `VCardString` object. 124 125 :Parameters: 126 - `name`: field name 127 - `value`: field value as string or an XML node 128 - `rfc2425parameters`: optional RFC 2425 parameters 129 :Types: 130 - `name`: `str` 131 - `value`: `str` or `libxml2.xmlNode` 132 - `rfc2425parameters`: `dict`""" 133 _unused = rfc2425parameters 134 VCardField.__init__(self,name) 135 if isinstance(value,libxml2.xmlNode): 136 value=value.getContent() 137 if value: 138 self.value=unicode(value,"utf-8","replace").strip() 139 else: 140 self.value=u"" 141 else: 142 self.value=value 143 if not self.value and not empty_ok: 144 raise Empty,"Empty string value"
145 - def rfc2426(self):
146 """RFC2426-encode the field content. 147 148 :return: the field in the RFC 2426 format. 149 :returntype: `str`""" 150 return rfc2425encode(self.name,self.value)
151 - def as_xml(self,parent):
152 """Create vcard-tmp XML representation of the field. 153 154 :Parameters: 155 - `parent`: parent node for the element 156 :Types: 157 - `parent`: `libxml2.xmlNode` 158 159 :return: xml node with the field data. 160 :returntype: `libxml2.xmlNode`""" 161 return parent.newTextChild(None, to_utf8(self.name.upper()), to_utf8(self.value))
162 - def __unicode__(self):
163 return self.value
164 - def __str__(self):
165 return self.value.encode("utf-8")
166
167 -class VCardXString(VCardString):
168 """Generic class for all text vCard fields not defined in RFC 2426. 169 170 In the RFC 2425 representation field name will be prefixed with 'x-'. 171 172 :Ivariables: 173 - `value`: field value. 174 :Types: 175 - `value`: `unicode`"""
176 - def rfc2426(self):
177 """RFC2426-encode the field content. 178 179 :return: the field in the RFC 2426 format. 180 :returntype: `str`""" 181 return rfc2425encode("x-"+self.name,self.value)
182
183 -class VCardJID(VCardField):
184 """JID vCard field. 185 186 This field is not defined in RFC 2426, so it will be named 'x-jabberid' 187 in RFC 2425 output. 188 189 :Ivariables: 190 - `value`: field value. 191 :Types: 192 - `value`: `JID`"""
193 - def __init__(self,name,value,rfc2425parameters=None):
194 """Initialize a `VCardJID` object. 195 196 :Parameters: 197 - `name`: field name 198 - `value`: field value as string or an XML node 199 - `rfc2425parameters`: optional RFC 2425 parameters 200 :Types: 201 - `name`: `str` 202 - `value`: `str` or `libxml2.xmlNode` 203 - `rfc2425parameters`: `dict`""" 204 _unused = rfc2425parameters 205 VCardField.__init__(self,name) 206 if isinstance(value,libxml2.xmlNode): 207 try: 208 self.value=pyxmpp.jid.JID(value.getContent()) 209 except JIDError: 210 raise JIDMalformedProtocolError, "JID malformed" 211 else: 212 self.value=pyxmpp.jid.JID(value) 213 if not self.value: 214 raise Empty,"Empty JID value"
215 - def rfc2426(self):
216 """RFC2426-encode the field content. 217 218 :return: the field in the RFC 2426 format. 219 :returntype: `str`""" 220 return rfc2425encode("x-jabberid",self.value.as_unicode())
221 - def as_xml(self,parent):
222 """Create vcard-tmp XML representation of the field. 223 224 :Parameters: 225 - `parent`: parent node for the element 226 :Types: 227 - `parent`: `libxml2.xmlNode` 228 229 :return: xml node with the field data. 230 :returntype: `libxml2.xmlNode`""" 231 name=to_utf8(self.name.upper()) 232 content=self.value.as_utf8() 233 return parent.newTextChild(None, name, content)
234 - def __unicode__(self):
235 return self.value.as_unicode()
236 - def __str__(self):
237 return self.value.as_string()
238
239 -class VCardName(VCardField):
240 """Name vCard field. 241 242 :Ivariables: 243 - `family`: family name. 244 - `given`: given name. 245 - `middle`: middle name. 246 - `prefix`: name prefix. 247 - `suffix`: name suffix. 248 :Types: 249 - `family`: `unicode` 250 - `given`: `unicode` 251 - `middle`: `unicode` 252 - `prefix`: `unicode` 253 - `suffix`: `unicode`"""
254 - def __init__(self,name,value,rfc2425parameters=None):
255 """Initialize a `VCardName` object. 256 257 :Parameters: 258 - `name`: field name 259 - `value`: field value as string or an XML node 260 - `rfc2425parameters`: optional RFC 2425 parameters 261 :Types: 262 - `name`: `str` 263 - `value`: `str` or `libxml2.xmlNode` 264 - `rfc2425parameters`: `dict`""" 265 _unused = rfc2425parameters 266 VCardField.__init__(self,name) 267 if self.name.upper()!="N": 268 raise RuntimeError,"VCardName handles only 'N' type" 269 if isinstance(value,libxml2.xmlNode): 270 self.family,self.given,self.middle,self.prefix,self.suffix=[u""]*5 271 empty=1 272 n=value.children 273 vns=get_node_ns(value) 274 while n: 275 if n.type!='element': 276 n=n.next 277 continue 278 ns=get_node_ns(n) 279 if (ns and vns and ns.getContent()!=vns.getContent()): 280 n=n.next 281 continue 282 if n.name=='FAMILY': 283 self.family=unicode(n.getContent(),"utf-8") 284 empty=0 285 if n.name=='GIVEN': 286 self.given=unicode(n.getContent(),"utf-8") 287 empty=0 288 if n.name=='MIDDLE': 289 self.middle=unicode(n.getContent(),"utf-8") 290 empty=0 291 if n.name=='PREFIX': 292 self.prefix=unicode(n.getContent(),"utf-8") 293 empty=0 294 if n.name=='SUFFIX': 295 self.suffix=unicode(n.getContent(),"utf-8") 296 empty=0 297 n=n.next 298 if empty: 299 raise Empty, "Empty N value" 300 else: 301 v=value.split(";") 302 value=[u""]*5 303 value[:len(v)]=v 304 self.family,self.given,self.middle,self.prefix,self.suffix=value
305 - def rfc2426(self):
306 """RFC2426-encode the field content. 307 308 :return: the field in the RFC 2426 format. 309 :returntype: `str`""" 310 return rfc2425encode("n",u"%s;%s;%s;%s;%s" % 311 (self.family,self.given,self.middle,self.prefix,self.suffix))
312 - def as_xml(self,parent):
313 """Create vcard-tmp XML representation of the field. 314 315 :Parameters: 316 - `parent`: parent node for the element 317 :Types: 318 - `parent`: `libxml2.xmlNode` 319 320 :return: xml node with the field data. 321 :returntype: `libxml2.xmlNode`""" 322 n=parent.newChild(None,"N",None) 323 n.newTextChild(None,"FAMILY",to_utf8(self.family)) 324 n.newTextChild(None,"GIVEN",to_utf8(self.given)) 325 n.newTextChild(None,"MIDDLE",to_utf8(self.middle)) 326 n.newTextChild(None,"PREFIX",to_utf8(self.prefix)) 327 n.newTextChild(None,"SUFFIX",to_utf8(self.suffix)) 328 return n
329 - def __unicode__(self):
330 r=[] 331 if self.prefix: 332 r.append(self.prefix.replace(u",",u" ")) 333 if self.given: 334 r.append(self.given.replace(u",",u" ")) 335 if self.middle: 336 r.append(self.middle.replace(u",",u" ")) 337 if self.family: 338 r.append(self.family.replace(u",",u" ")) 339 if self.suffix: 340 r.append(self.suffix.replace(u",",u" ")) 341 return u" ".join(r)
342 - def __str__(self):
343 return self.__unicode__().encode("utf-8")
344
345 -class VCardImage(VCardField):
346 """Image vCard field. 347 348 :Ivariables: 349 - `image`: image binary data (when `uri` is None) 350 - `uri`: image URI (when `image` is None) 351 - `type`: optional image type 352 :Types: 353 - `image`: `str` 354 - `uri`: `unicode` 355 - `type`: `unicode`"""
356 - def __init__(self,name,value,rfc2425parameters=None):
357 """Initialize a `VCardImage` object. 358 359 :Parameters: 360 - `name`: field name 361 - `value`: field value as string or an XML node 362 - `rfc2425parameters`: optional RFC 2425 parameters 363 :Types: 364 - `name`: `str` 365 - `value`: `str` or `libxml2.xmlNode` 366 - `rfc2425parameters`: `dict`""" 367 VCardField.__init__(self,name) 368 if not rfc2425parameters: 369 rfc2425parameters={} 370 self.uri,self.type,self.image=[None]*3 371 if isinstance(value,libxml2.xmlNode): 372 n=value.children 373 vns=get_node_ns(value) 374 while n: 375 if n.type!='element': 376 n=n.next 377 continue 378 ns=get_node_ns(n) 379 if (ns and vns and ns.getContent()!=vns.getContent()): 380 n=n.next 381 continue 382 if n.name=='TYPE': 383 self.type=unicode(n.getContent(),"utf-8","replace") 384 if n.name=='BINVAL': 385 self.image=base64.decodestring(n.getContent()) 386 if n.name=='EXTVAL': 387 self.uri=unicode(n.getContent(),"utf-8","replace") 388 n=n.next 389 if (self.uri and self.image) or (not self.uri and not self.image): 390 raise ValueError,"Bad %s value in vcard" % (name,) 391 if (not self.uri and not self.image): 392 raise Empty,"Bad %s value in vcard" % (name,) 393 else: 394 if rfc2425parameters.get("value", "").lower()=="uri": 395 self.uri=value 396 self.type=None 397 else: 398 self.type=rfc2425parameters.get("type") 399 self.image=value
400 - def rfc2426(self):
401 """RFC2426-encode the field content. 402 403 :return: the field in the RFC 2426 format. 404 :returntype: `str`""" 405 if self.uri: 406 return rfc2425encode(self.name,self.uri,{"value":"uri"}) 407 elif self.image: 408 if self.type: 409 p={"type":self.type} 410 else: 411 p={} 412 return rfc2425encode(self.name,self.image,p)
413 - def as_xml(self,parent):
414 """Create vcard-tmp XML representation of the field. 415 416 :Parameters: 417 - `parent`: parent node for the element 418 :Types: 419 - `parent`: `libxml2.xmlNode` 420 421 :return: xml node with the field data. 422 :returntype: `libxml2.xmlNode`""" 423 n=parent.newChild(None,self.name.upper(),None) 424 if self.uri: 425 n.newTextChild(None,"EXTVAL",to_utf8(self.uri)) 426 else: 427 if self.type: 428 n.newTextChild(None,"TYPE",self.type) 429 n.newTextChild(None,"BINVAL",binascii.b2a_base64(self.image)) 430 return n
431 - def __unicode__(self):
432 if self.uri: 433 return self.uri 434 if self.type: 435 return u"(%s data)" % (self.type,) 436 return u"(binary data)"
437 - def __str__(self):
438 return self.__unicode__().encode("utf-8")
439 440
441 -class VCardAdr(VCardField):
442 """Address vCard field. 443 444 :Ivariables: 445 - `type`: type of the address. 446 - `pobox`: the post office box. 447 - `extadr`: the extended address. 448 - `street`: the street address. 449 - `locality`: the locality (e.g. city). 450 - `region`: the region. 451 - `pcode`: the postal code. 452 - `ctry`: the country. 453 :Types: 454 - `type`: `list` of "home","work","postal","parcel","dom","intl" or "pref" 455 - `pobox`: `unicode` 456 - `extadr`: `unicode` 457 - `street`: `unicode` 458 - `locality`: `unicode` 459 - `region`: `unicode` 460 - `pcode`: `unicode` 461 - `ctry`: `unicode`"""
462 - def __init__(self,name,value,rfc2425parameters=None):
463 """Initialize a `VCardAdr` object. 464 465 :Parameters: 466 - `name`: field name 467 - `value`: field value as string or an XML node 468 - `rfc2425parameters`: optional RFC 2425 parameters 469 :Types: 470 - `name`: `str` 471 - `value`: `str` or `libxml2.xmlNode` 472 - `rfc2425parameters`: `dict`""" 473 VCardField.__init__(self,name) 474 if not rfc2425parameters: 475 rfc2425parameters={} 476 if self.name.upper()!="ADR": 477 raise RuntimeError,"VCardAdr handles only 'ADR' type" 478 (self.pobox,self.extadr,self.street,self.locality, 479 self.region,self.pcode,self.ctry)=[""]*7 480 self.type=[] 481 if isinstance(value,libxml2.xmlNode): 482 self.__from_xml(value) 483 else: 484 t=rfc2425parameters.get("type") 485 if t: 486 self.type=t.split(",") 487 else: 488 self.type=["intl","postal","parcel","work"] 489 v=value.split(";") 490 value=[""]*7 491 value[:len(v)]=v 492 (self.pobox,self.extadr,self.street,self.locality, 493 self.region,self.pcode,self.ctry)=value
494
495 - def __from_xml(self,value):
496 """Initialize a `VCardAdr` object from and XML element. 497 498 :Parameters: 499 - `value`: field value as an XML node 500 :Types: 501 - `value`: `libxml2.xmlNode`""" 502 n=value.children 503 vns=get_node_ns(value) 504 while n: 505 if n.type!='element': 506 n=n.next 507 continue 508 ns=get_node_ns(n) 509 if (ns and vns and ns.getContent()!=vns.getContent()): 510 n=n.next 511 continue 512 if n.name=='POBOX': 513 self.pobox=unicode(n.getContent(),"utf-8","replace") 514 elif n.name in ('EXTADR', 'EXTADD'): 515 self.extadr=unicode(n.getContent(),"utf-8","replace") 516 elif n.name=='STREET': 517 self.street=unicode(n.getContent(),"utf-8","replace") 518 elif n.name=='LOCALITY': 519 self.locality=unicode(n.getContent(),"utf-8","replace") 520 elif n.name=='REGION': 521 self.region=unicode(n.getContent(),"utf-8","replace") 522 elif n.name=='PCODE': 523 self.pcode=unicode(n.getContent(),"utf-8","replace") 524 elif n.name=='CTRY': 525 self.ctry=unicode(n.getContent(),"utf-8","replace") 526 elif n.name in ("HOME","WORK","POSTAL","PARCEL","DOM","INTL", 527 "PREF"): 528 self.type.append(n.name.lower()) 529 n=n.next 530 if self.type==[]: 531 self.type=["intl","postal","parcel","work"] 532 elif "dom" in self.type and "intl" in self.type: 533 raise ValueError,"Both 'dom' and 'intl' specified in vcard ADR"
534
535 - def rfc2426(self):
536 """RFC2426-encode the field content. 537 538 :return: the field in the RFC 2426 format. 539 :returntype: `str`""" 540 return rfc2425encode("adr",u"%s;%s;%s;%s;%s;%s;%s" % 541 (self.pobox,self.extadr,self.street,self.locality, 542 self.region,self.pcode,self.ctry), 543 {"type":",".join(self.type)})
544
545 - def as_xml(self,parent):
546 """Create vcard-tmp XML representation of the field. 547 548 :Parameters: 549 - `parent`: parent node for the element 550 :Types: 551 - `parent`: `libxml2.xmlNode` 552 553 :return: xml node with the field data. 554 :returntype: `libxml2.xmlNode`""" 555 n=parent.newChild(None,"ADR",None) 556 for t in ("home","work","postal","parcel","dom","intl","pref"): 557 if t in self.type: 558 n.newChild(None,t.upper(),None) 559 n.newTextChild(None,"POBOX",to_utf8(self.pobox)) 560 n.newTextChild(None,"EXTADD",to_utf8(self.extadr)) 561 n.newTextChild(None,"STREET",to_utf8(self.street)) 562 n.newTextChild(None,"LOCALITY",to_utf8(self.locality)) 563 n.newTextChild(None,"REGION",to_utf8(self.region)) 564 n.newTextChild(None,"PCODE",to_utf8(self.pcode)) 565 n.newTextChild(None,"CTRY",to_utf8(self.ctry)) 566 return n
567
568 -class VCardLabel(VCardField):
569 """Address label vCard field. 570 571 :Ivariables: 572 - `lines`: list of label text lines. 573 - `type`: type of the label. 574 :Types: 575 - `lines`: `list` of `unicode` 576 - `type`: `list` of "home","work","postal","parcel","dom","intl" or "pref" 577 """
578 - def __init__(self,name,value,rfc2425parameters=None):
579 """Initialize a `VCardLabel` object. 580 581 :Parameters: 582 - `name`: field name 583 - `value`: field value as string or an XML node 584 - `rfc2425parameters`: optional RFC 2425 parameters 585 :Types: 586 - `name`: `str` 587 - `value`: `str` or `libxml2.xmlNode` 588 - `rfc2425parameters`: `dict`""" 589 VCardField.__init__(self,name) 590 if not rfc2425parameters: 591 rfc2425parameters={} 592 if self.name.upper()!="LABEL": 593 raise RuntimeError,"VCardAdr handles only 'LABEL' type" 594 if isinstance(value,libxml2.xmlNode): 595 self.lines=[] 596 self.type=[] 597 n=value.children 598 vns=get_node_ns(value) 599 while n: 600 if n.type!='element': 601 n=n.next 602 continue 603 ns=get_node_ns(n) 604 if (ns and vns and ns.getContent()!=vns.getContent()): 605 n=n.next 606 continue 607 if n.name=='LINE': 608 l=unicode(n.getContent(),"utf-8","replace").strip() 609 l=l.replace("\n"," ").replace("\r"," ") 610 self.lines.append(l) 611 elif n.name in ("HOME","WORK","POSTAL","PARCEL","DOM","INTL", 612 "PREF"): 613 self.type.append(n.name.lower()) 614 n=n.next 615 if self.type==[]: 616 self.type=["intl","postal","parcel","work"] 617 elif "dom" in self.type and "intl" in self.type: 618 raise ValueError,"Both 'dom' and 'intl' specified in vcard LABEL" 619 if not self.lines: 620 self.lines=[""] 621 else: 622 t=rfc2425parameters.get("type") 623 if t: 624 self.type=t.split(",") 625 else: 626 self.type=["intl","postal","parcel","work"] 627 self.lines=value.split("\\n")
628
629 - def rfc2426(self):
630 """RFC2426-encode the field content. 631 632 :return: the field in the RFC 2426 format. 633 :returntype: `str`""" 634 return rfc2425encode("label",u"\n".join(self.lines), 635 {"type":",".join(self.type)})
636 - def as_xml(self,parent):
637 """Create vcard-tmp XML representation of the field. 638 639 :Parameters: 640 - `parent`: parent node for the element 641 :Types: 642 - `parent`: `libxml2.xmlNode` 643 644 :return: xml node with the field data. 645 :returntype: `libxml2.xmlNode`""" 646 n=parent.newChild(None,"ADR",None) 647 for t in ("home","work","postal","parcel","dom","intl","pref"): 648 if t in self.type: 649 n.newChild(None,t.upper(),None) 650 for l in self.lines: 651 n.newTextChild(None,"LINE",l) 652 return n
653
654 -class VCardTel(VCardField):
655 """Telephone vCard field. 656 657 :Ivariables: 658 - `number`: phone number. 659 - `type`: type of the phone number. 660 :Types: 661 - `number`: `unicode` 662 - `type`: `list` of "home","work","voice","fax","pager","msg","cell","video","bbs","modem","isdn","pcs" or "pref". 663 """
664 - def __init__(self,name,value,rfc2425parameters=None):
665 """Initialize a `VCardTel` object. 666 667 :Parameters: 668 - `name`: field name 669 - `value`: field value as string or an XML node 670 - `rfc2425parameters`: optional RFC 2425 parameters 671 :Types: 672 - `name`: `str` 673 - `value`: `str` or `libxml2.xmlNode` 674 - `rfc2425parameters`: `dict`""" 675 VCardField.__init__(self,name) 676 if not rfc2425parameters: 677 rfc2425parameters={} 678 if self.name.upper()!="TEL": 679 raise RuntimeError,"VCardTel handles only 'TEL' type" 680 if isinstance(value,libxml2.xmlNode): 681 self.number=None 682 self.type=[] 683 n=value.children 684 vns=get_node_ns(value) 685 while n: 686 if n.type!='element': 687 n=n.next 688 continue 689 ns=get_node_ns(n) 690 if (ns and vns and ns.getContent()!=vns.getContent()): 691 n=n.next 692 continue 693 if n.name=='NUMBER': 694 self.number=unicode(n.getContent(),"utf-8","replace") 695 elif n.name in ("HOME","WORK","VOICE","FAX","PAGER","MSG", 696 "CELL","VIDEO","BBS","MODEM","ISDN","PCS", 697 "PREF"): 698 self.type.append(n.name.lower()) 699 n=n.next 700 if self.type==[]: 701 self.type=["voice"] 702 if not self.number: 703 raise Empty,"No tel number" 704 else: 705 t=rfc2425parameters.get("type") 706 if t: 707 self.type=t.split(",") 708 else: 709 self.type=["voice"] 710 self.number=value
711 - def rfc2426(self):
712 """RFC2426-encode the field content. 713 714 :return: the field in the RFC 2426 format. 715 :returntype: `str`""" 716 return rfc2425encode("tel",self.number,{"type":",".join(self.type)})
717 - def as_xml(self,parent):
718 """Create vcard-tmp XML representation of the field. 719 720 :Parameters: 721 - `parent`: parent node for the element 722 :Types: 723 - `parent`: `libxml2.xmlNode` 724 725 :return: xml node with the field data. 726 :returntype: `libxml2.xmlNode`""" 727 n=parent.newChild(None,"TEL",None) 728 for t in ("home","work","voice","fax","pager","msg","cell","video", 729 "bbs","modem","isdn","pcs","pref"): 730 if t in self.type: 731 n.newChild(None,t.upper(),None) 732 n.newTextChild(None,"NUMBER",to_utf8(self.number)) 733 return n
734
735 -class VCardEmail(VCardField):
736 """E-mail vCard field. 737 738 :Ivariables: 739 - `address`: e-mail address. 740 - `type`: type of the address. 741 :Types: 742 - `address`: `unicode` 743 - `type`: `list` of "home","work","internet" or "x400". 744 """
745 - def __init__(self,name,value,rfc2425parameters=None):
746 """Initialize a `VCardEmail` object. 747 748 :Parameters: 749 - `name`: field name 750 - `value`: field value as string or an XML node 751 - `rfc2425parameters`: optional RFC 2425 parameters 752 :Types: 753 - `name`: `str` 754 - `value`: `str` or `libxml2.xmlNode` 755 - `rfc2425parameters`: `dict`""" 756 VCardField.__init__(self,name) 757 if not rfc2425parameters: 758 rfc2425parameters={} 759 if self.name.upper()!="EMAIL": 760 raise RuntimeError,"VCardEmail handles only 'EMAIL' type" 761 if isinstance(value,libxml2.xmlNode): 762 self.address=None 763 self.type=[] 764 n=value.children 765 vns=get_node_ns(value) 766 while n: 767 if n.type!='element': 768 n=n.next 769 continue 770 ns=get_node_ns(n) 771 if (ns and vns and ns.getContent()!=vns.getContent()): 772 n=n.next 773 continue 774 if n.name=='USERID': 775 self.address=unicode(n.getContent(),"utf-8","replace") 776 elif n.name in ("HOME","WORK","INTERNET","X400"): 777 self.type.append(n.name.lower()) 778 n=n.next 779 if self.type==[]: 780 self.type=["internet"] 781 if not self.address: 782 raise Empty,"No USERID" 783 else: 784 t=rfc2425parameters.get("type") 785 if t: 786 self.type=t.split(",") 787 else: 788 self.type=["internet"] 789 self.address=value
790 - def rfc2426(self):
791 """RFC2426-encode the field content. 792 793 :return: the field in the RFC 2426 format. 794 :returntype: `str`""" 795 return rfc2425encode("email",self.address,{"type":",".join(self.type)})
796 - def as_xml(self,parent):
797 """Create vcard-tmp XML representation of the field. 798 799 :Parameters: 800 - `parent`: parent node for the element 801 :Types: 802 - `parent`: `libxml2.xmlNode` 803 804 :return: xml node with the field data. 805 :returntype: `libxml2.xmlNode`""" 806 n=parent.newChild(None,"EMAIL",None) 807 for t in ("home","work","internet","x400"): 808 if t in self.type: 809 n.newChild(None,t.upper(),None) 810 n.newTextChild(None,"USERID",to_utf8(self.address)) 811 return n
812
813 -class VCardGeo(VCardField):
814 """Geographical location vCard field. 815 816 :Ivariables: 817 - `lat`: the latitude. 818 - `lon`: the longitude. 819 :Types: 820 - `lat`: `unicode` 821 - `lon`: `unicode` 822 """
823 - def __init__(self,name,value,rfc2425parameters=None):
824 """Initialize a `VCardGeo` object. 825 826 :Parameters: 827 - `name`: field name 828 - `value`: field value as string or an XML node 829 - `rfc2425parameters`: optional RFC 2425 parameters 830 :Types: 831 - `name`: `str` 832 - `value`: `str` or `libxml2.xmlNode` 833 - `rfc2425parameters`: `dict`""" 834 _unused = rfc2425parameters 835 VCardField.__init__(self,name) 836 if self.name.upper()!="GEO": 837 raise RuntimeError,"VCardName handles only 'GEO' type" 838 if isinstance(value,libxml2.xmlNode): 839 self.lat,self.lon=[None]*2 840 n=value.children 841 vns=get_node_ns(value) 842 while n: 843 if n.type!='element': 844 n=n.next 845 continue 846 ns=get_node_ns(n) 847 if (ns and vns and ns.getContent()!=vns.getContent()): 848 n=n.next 849 continue 850 if n.name=='LAT': 851 self.lat=unicode(n.getContent(),"utf-8") 852 if n.name=='LON': 853 self.lon=unicode(n.getContent(),"utf-8") 854 n=n.next 855 if not self.lat or not self.lon: 856 raise ValueError,"Bad vcard GEO value" 857 else: 858 self.lat,self.lon=value.split(";")
859 - def rfc2426(self):
860 """RFC2426-encode the field content. 861 862 :return: the field in the RFC 2426 format. 863 :returntype: `str`""" 864 return rfc2425encode("geo",u"%s;%s" % 865 (self.lat,self.lon))
866 - def as_xml(self,parent):
867 """Create vcard-tmp XML representation of the field. 868 869 :Parameters: 870 - `parent`: parent node for the element 871 :Types: 872 - `parent`: `libxml2.xmlNode` 873 874 :return: xml node with the field data. 875 :returntype: `libxml2.xmlNode`""" 876 n=parent.newChild(None,"GEO",None) 877 n.newTextChild(None,"LAT",to_utf8(self.lat)) 878 n.newTextChild(None,"LON",to_utf8(self.lon)) 879 return n
880
881 -class VCardOrg(VCardField):
882 """Organization vCard field. 883 884 :Ivariables: 885 - `name`: organization name. 886 - `unit`: organizational unit. 887 :Types: 888 - `name`: `unicode` 889 - `unit`: `unicode` 890 """
891 - def __init__(self,name,value,rfc2425parameters=None):
892 """Initialize a `VCardOrg` object. 893 894 :Parameters: 895 - `name`: field name 896 - `value`: field value as string or an XML node 897 - `rfc2425parameters`: optional RFC 2425 parameters 898 :Types: 899 - `name`: `str` 900 - `value`: `str` or `libxml2.xmlNode` 901 - `rfc2425parameters`: `dict`""" 902 _unused = rfc2425parameters 903 VCardField.__init__(self,name) 904 if self.name.upper()!="ORG": 905 raise RuntimeError,"VCardName handles only 'ORG' type" 906 if isinstance(value,libxml2.xmlNode): 907 self.name,self.unit=None,"" 908 n=value.children 909 vns=get_node_ns(value) 910 while n: 911 if n.type!='element': 912 n=n.next 913 continue 914 ns=get_node_ns(n) 915 if (ns and vns and ns.getContent()!=vns.getContent()): 916 n=n.next 917 continue 918 if n.name=='ORGNAME': 919 self.name=unicode(n.getContent(),"utf-8") 920 if n.name=='ORGUNIT': 921 self.unit=unicode(n.getContent(),"utf-8") 922 n=n.next 923 if not self.name: 924 raise Empty,"Bad vcard ORG value" 925 else: 926 sp=value.split(";",1) 927 if len(sp)>1: 928 self.name,self.unit=sp 929 else: 930 self.name=sp[0] 931 self.unit=None
932 - def rfc2426(self):
933 """RFC2426-encode the field content. 934 935 :return: the field in the RFC 2426 format. 936 :returntype: `str`""" 937 if self.unit: 938 return rfc2425encode("org",u"%s;%s" % (self.name,self.unit)) 939 else: 940 return rfc2425encode("org",u"%s" % (self.name,))
941 - def as_xml(self,parent):
942 """Create vcard-tmp XML representation of the field. 943 944 :Parameters: 945 - `parent`: parent node for the element 946 :Types: 947 - `parent`: `libxml2.xmlNode` 948 949 :return: xml node with the field data. 950 :returntype: `libxml2.xmlNode`""" 951 n=parent.newChild(None,"ORG",None) 952 n.newTextChild(None,"ORGNAME",to_utf8(self.name)) 953 n.newTextChild(None,"ORGUNIT",to_utf8(self.unit)) 954 return n
955
956 -class VCardCategories(VCardField):
957 """Categories vCard field. 958 959 :Ivariables: 960 - `keywords`: category keywords. 961 :Types: 962 - `keywords`: `list` of `unicode` 963 """
964 - def __init__(self,name,value,rfc2425parameters=None):
965 """Initialize a `VCardCategories` object. 966 967 :Parameters: 968 - `name`: field name 969 - `value`: field value as string or an XML node 970 - `rfc2425parameters`: optional RFC 2425 parameters 971 :Types: 972 - `name`: `str` 973 - `value`: `str` or `libxml2.xmlNode` 974 - `rfc2425parameters`: `dict`""" 975 _unused = rfc2425parameters 976 VCardField.__init__(self,name) 977 self.name=name 978 if self.name.upper()!="CATEGORIES": 979 raise RuntimeError,"VCardName handles only 'CATEGORIES' type" 980 if isinstance(value,libxml2.xmlNode): 981 self.keywords=[] 982 n=value.children 983 vns=get_node_ns(value) 984 while n: 985 if n.type!='element': 986 n=n.next 987 continue 988 ns=get_node_ns(n) 989 if (ns and vns and ns.getContent()!=vns.getContent()): 990 n=n.next 991 continue 992 if n.name=='KEYWORD': 993 self.keywords.append(unicode(n.getContent(),"utf-8")) 994 n=n.next 995 if not self.keywords: 996 raise Empty,"Bad vcard CATEGORIES value" 997 else: 998 self.keywords=value.split(",")
999 - def rfc2426(self):
1000 """RFC2426-encode the field content. 1001 1002 :return: the field in the RFC 2426 format. 1003 :returntype: `str`""" 1004 return rfc2425encode("keywords",u",".join(self.keywords))
1005 - def as_xml(self,parent):
1006 """Create vcard-tmp XML representation of the field. 1007 1008 :Parameters: 1009 - `parent`: parent node for the element 1010 :Types: 1011 - `parent`: `libxml2.xmlNode` 1012 1013 :return: xml node with the field data. 1014 :returntype: `libxml2.xmlNode`""" 1015 n=parent.newChild(None,"CATEGORIES",None) 1016 for k in self.keywords: 1017 n.newTextChild(None,"KEYWORD",to_utf8(k)) 1018 return n
1019
1020 -class VCardSound(VCardField):
1021 """Sound vCard field. 1022 1023 :Ivariables: 1024 - `sound`: binary sound data (when `uri` is None) 1025 - `uri`: sound URI (when `sound` is None) 1026 - `phonetic`: phonetic transcription 1027 :Types: 1028 - `sound`: `str` 1029 - `uri`: `unicode` 1030 - `phonetic`: `unicode`"""
1031 - def __init__(self,name,value,rfc2425parameters=None):
1032 """Initialize a `VCardSound` object. 1033 1034 :Parameters: 1035 - `name`: field name 1036 - `value`: field value as string or an XML node 1037 - `rfc2425parameters`: optional RFC 2425 parameters 1038 :Types: 1039 - `name`: `str` 1040 - `value`: `str` or `libxml2.xmlNode` 1041 - `rfc2425parameters`: `dict`""" 1042 VCardField.__init__(self,name) 1043 if not rfc2425parameters: 1044 rfc2425parameters={} 1045 self.uri,self.sound,self.phonetic=[None]*3 1046 if isinstance(value,libxml2.xmlNode): 1047 n=value.children 1048 vns=get_node_ns(value) 1049 while n: 1050 if n.type!='element': 1051 n=n.next 1052 continue 1053 ns=get_node_ns(n) 1054 if (ns and vns and ns.getContent()!=vns.getContent()): 1055 n=n.next 1056 continue 1057 if n.name=='BINVAL': 1058 if (self.phonetic or self.uri): 1059 raise ValueError,"Bad SOUND value in vcard" 1060 self.sound=base64.decodestring(n.getContent()) 1061 if n.name=='PHONETIC': 1062 if (self.sound or self.uri): 1063 raise ValueError,"Bad SOUND value in vcard" 1064 self.phonetic=unicode(n.getContent(),"utf-8","replace") 1065 if n.name=='EXTVAL': 1066 if (self.phonetic or self.sound): 1067 raise ValueError,"Bad SOUND value in vcard" 1068 self.uri=unicode(n.getContent(),"utf-8","replace") 1069 n=n.next 1070 if (not self.phonetic and not self.uri and not self.sound): 1071 raise Empty,"Bad SOUND value in vcard" 1072 else: 1073 if rfc2425parameters.get("value", "").lower()=="uri": 1074 self.uri=value 1075 self.sound=None 1076 self.phonetic=None 1077 else: 1078 self.sound=value 1079 self.uri=None 1080 self.phonetic=None
1081 - def rfc2426(self):
1082 """RFC2426-encode the field content. 1083 1084 :return: the field in the RFC 2426 format. 1085 :returntype: `str`""" 1086 if self.uri: 1087 return rfc2425encode(self.name,self.uri,{"value":"uri"}) 1088 elif self.sound: 1089 return rfc2425encode(self.name,self.sound)
1090 - def as_xml(self,parent):
1091 """Create vcard-tmp XML representation of the field. 1092 1093 :Parameters: 1094 - `parent`: parent node for the element 1095 :Types: 1096 - `parent`: `libxml2.xmlNode` 1097 1098 :return: xml node with the field data. 1099 :returntype: `libxml2.xmlNode`""" 1100 n=parent.newChild(None,self.name.upper(),None) 1101 if self.uri: 1102 n.newTextChild(None,"EXTVAL",to_utf8(self.uri)) 1103 elif self.phonetic: 1104 n.newTextChild(None,"PHONETIC",to_utf8(self.phonetic)) 1105 else: 1106 n.newTextChild(None,"BINVAL",binascii.b2a_base64(self.sound)) 1107 return n
1108
1109 -class VCardPrivacy(VCardField):
1110 """Privacy vCard field. 1111 1112 :Ivariables: 1113 - `value`: privacy information about the vcard data ("public", "private" 1114 or "confidental") 1115 :Types: 1116 - `value`: `str` """
1117 - def __init__(self,name,value,rfc2425parameters=None):
1118 """Initialize a `VCardPrivacy` object. 1119 1120 :Parameters: 1121 - `name`: field name 1122 - `value`: field value as string or an XML node 1123 - `rfc2425parameters`: optional RFC 2425 parameters 1124 :Types: 1125 - `name`: `str` 1126 - `value`: `str` or `libxml2.xmlNode` 1127 - `rfc2425parameters`: `dict`""" 1128 _unused = rfc2425parameters 1129 VCardField.__init__(self,name) 1130 if isinstance(value,libxml2.xmlNode): 1131 self.value=None 1132 n=value.children 1133 vns=get_node_ns(value) 1134 while n: 1135 if n.type!='element': 1136 n=n.next 1137 continue 1138 ns=get_node_ns(n) 1139 if (ns and vns and ns.getContent()!=vns.getContent()): 1140 n=n.next 1141 continue 1142 if n.name=='PUBLIC': 1143 self.value="public" 1144 elif n.name=='PRIVATE': 1145 self.value="private" 1146 elif n.name=='CONFIDENTAL': 1147 self.value="confidental" 1148 n=n.next 1149 if not self.value: 1150 raise Empty 1151 else: 1152 self.value=value
1153 - def rfc2426(self):
1154 """RFC2426-encode the field content. 1155 1156 :return: the field in the RFC 2426 format. 1157 :returntype: `str`""" 1158 return rfc2425encode(self.name,self.value)
1159 - def as_xml(self,parent):
1160 """Create vcard-tmp XML representation of the field. 1161 1162 :Parameters: 1163 - `parent`: parent node for the element 1164 :Types: 1165 - `parent`: `libxml2.xmlNode` 1166 1167 :return: xml node with the field data. 1168 :returntype: `libxml2.xmlNode`""" 1169 if self.value in ("public","private","confidental"): 1170 n=parent.newChild(None,self.name.upper(),None) 1171 n.newChild(None,self.value.upper(),None) 1172 return n 1173 return None
1174
1175 -class VCardKey(VCardField):
1176 """Key vCard field. 1177 1178 :Ivariables: 1179 - `type`: key type. 1180 - `cred`: key data. 1181 :Types: 1182 - `type`: `unicode` 1183 - `cred`: `str` """
1184 - def __init__(self,name,value,rfc2425parameters=None):
1185 """Initialize a `VCardKey` object. 1186 1187 :Parameters: 1188 - `name`: field name 1189 - `value`: field value as string or an XML node 1190 - `rfc2425parameters`: optional RFC 2425 parameters 1191 :Types: 1192 - `name`: `str` 1193 - `value`: `str` or `libxml2.xmlNode` 1194 - `rfc2425parameters`: `dict`""" 1195 VCardField.__init__(self,name) 1196 if not rfc2425parameters: 1197 rfc2425parameters={} 1198 if isinstance(value,libxml2.xmlNode): 1199 self.type,self.cred=None,None 1200 n=value.children 1201 vns=get_node_ns(value) 1202 while n: 1203 if n.type!='element': 1204 n=n.next 1205 continue 1206 ns=get_node_ns(n) 1207 if (ns and vns and ns.getContent()!=vns.getContent()): 1208 n=n.next 1209 continue 1210 if n.name=='TYPE': 1211 self.type=unicode(n.getContent(),"utf-8","replace") 1212 if n.name=='CRED': 1213 self.cred=base64.decodestring(n.getContent()) 1214 n=n.next 1215 if not self.cred: 1216 raise Empty,"Bad %s value in vcard" % (name,) 1217 else: 1218 self.type=rfc2425parameters.get("type") 1219 self.cred=value
1220 - def rfc2426(self):
1221 """RFC2426-encode the field content. 1222 1223 :return: the field in the RFC 2426 format. 1224 :returntype: `str`""" 1225 if self.type: 1226 p={"type":self.type} 1227 else: 1228 p={} 1229 return rfc2425encode(self.name,self.cred,p)
1230 - def as_xml(self,parent):
1231 """Create vcard-tmp XML representation of the field. 1232 1233 :Parameters: 1234 - `parent`: parent node for the element 1235 :Types: 1236 - `parent`: `libxml2.xmlNode` 1237 1238 :return: xml node with the field data. 1239 :returntype: `libxml2.xmlNode`""" 1240 n=parent.newChild(None,self.name.upper(),None) 1241 if self.type: 1242 n.newTextChild(None,"TYPE",self.type) 1243 n.newTextChild(None,"CRED",binascii.b2a_base64(self.cred)) 1244 return n
1245
1246 -class VCard(StanzaPayloadObject):
1247 """Jabber (vcard-temp) or RFC2426 vCard. 1248 1249 :Ivariables: 1250 - `fn`: full name. 1251 - `n`: structural name. 1252 - `nickname`: nickname(s). 1253 - `photo`: photo(s). 1254 - `bday`: birthday date(s). 1255 - `adr`: address(es). 1256 - `label`: address label(s). 1257 - `tel`: phone number(s). 1258 - `email`: e-mail address(es). 1259 - `jabberid`: JID(s). 1260 - `mailer`: mailer(s). 1261 - `tz`: timezone(s). 1262 - `geo`: geolocation(s). 1263 - `title`: title(s). 1264 - `role`: role(s). 1265 - `logo`: logo(s). 1266 - `org`: organization(s). 1267 - `categories`: categories. 1268 - `note`: note(s). 1269 - `prodid`: product id(s). 1270 - `rev`: revision(s). 1271 - `sort-string`: sort string(s). 1272 - `sound`: sound(s). 1273 - `uid`: user identifier(s). 1274 - `url`: URL(s). 1275 - `class`: class(es). 1276 - `key`: key(s). 1277 - `desc`: description. 1278 :Types: 1279 - `fn`: `VCardString`, 1280 - `n`: `VCardName`, 1281 - `nickname`: `list` of `VCardString` 1282 - `photo`: `list` of `VCardImage` 1283 - `bday`: `list` of `VCardString` 1284 - `adr`: `list` of `VCardAdr` 1285 - `label`: `list` of `VCardLabel` 1286 - `tel`: `list` of `VCardTel` 1287 - `email`: `list` of `VCardEmail` 1288 - `jabberid`: `list` of `VCardJID` 1289 - `mailer`: `list` of `VCardString` 1290 - `tz`: `list` of `VCardString` 1291 - `geo`: `list` of `VCardGeo` 1292 - `title`: `list` of `VCardString` 1293 - `role`: `list` of `VCardString` 1294 - `logo`: `list` of `VCardImage` 1295 - `org`: `list` of `VCardOrg` 1296 - `categories`: `list` of `VCardCategories` 1297 - `note`: `list` of `VCardString` 1298 - `prodid`: `list` of `VCardString` 1299 - `rev`: `list` of `VCardString` 1300 - `sort-string`: `list` of `VCardString` 1301 - `sound`: `list` of `VCardSound` 1302 - `uid`: `list` of `VCardString` 1303 - `url`: `list` of `VCardString` 1304 - `class`: `list` of `VCardString` 1305 - `key`: `list` of `VCardKey` 1306 - `desc`: `list` of `VCardXString` 1307 """ 1308 1309 xml_element_name = "vCard" 1310 xml_element_namespace = VCARD_NS 1311 1312 components={ 1313 #"VERSION": (VCardString,"optional"), 1314 "FN": (VCardString,"required"), 1315 "N": (VCardName,"required"), 1316 "NICKNAME": (VCardString,"multi"), 1317 "PHOTO": (VCardImage,"multi"), 1318 "BDAY": (VCardString,"multi"), 1319 "ADR": (VCardAdr,"multi"), 1320 "LABEL": (VCardLabel,"multi"), 1321 "TEL": (VCardTel,"multi"), 1322 "EMAIL": (VCardEmail,"multi"), 1323 "JABBERID": (VCardJID,"multi"), 1324 "MAILER": (VCardString,"multi"), 1325 "TZ": (VCardString,"multi"), 1326 "GEO": (VCardGeo,"multi"), 1327 "TITLE": (VCardString,"multi"), 1328 "ROLE": (VCardString,"multi"), 1329 "LOGO": (VCardImage,"multi"), 1330 "AGENT": ("VCardAgent","ignore"), #FIXME: agent field 1331 "ORG": (VCardOrg,"multi"), 1332 "CATEGORIES": (VCardCategories,"multi"), 1333 "NOTE": (VCardString,"multi"), 1334 "PRODID": (VCardString,"multi"), 1335 "REV": (VCardString,"multi"), 1336 "SORT-STRING": (VCardString,"multi"), 1337 "SOUND": (VCardSound,"multi"), 1338 "UID": (VCardString,"multi"), 1339 "URL": (VCardString,"multi"), 1340 "CLASS": (VCardString,"multi"), 1341 "KEY": (VCardKey,"multi"), 1342 "DESC": (VCardXString,"multi"), 1343 };
1344 - def __init__(self,data):
1345 """Initialize a VCard object from data which may be XML node 1346 or an RFC2426 string. 1347 1348 :Parameters: 1349 - `data`: vcard to parse. 1350 :Types: 1351 - `data`: `libxml2.xmlNode`, `unicode` or `str`""" 1352 1353 # to make pylint happy 1354 self.n = None 1355 del self.n 1356 1357 self.content={} 1358 if isinstance(data,libxml2.xmlNode): 1359 self.__from_xml(data) 1360 else: 1361 self.__from_rfc2426(data) 1362 if not self.content.get("N") and self.content.get("FN"): 1363 s=self.content['FN'].value.replace(";",",") 1364 s=s.split(None,2) 1365 if len(s)==2: 1366 s=u"%s;%s;;;" % (s[1],s[0]) 1367 elif len(s)==3: 1368 s=u"%s;%s;%s" % (s[2],s[0],s[1]) 1369 else: 1370 s=u"%s;;;;" % (s[0],) 1371 self.content["N"]=VCardName("N",s) 1372 elif not self.content.get("FN") and self.content.get("N"): 1373 self.__make_fn() 1374 for c, (_unused, tp) in self.components.items(): 1375 if self.content.has_key(c): 1376 continue 1377 if tp=="required": 1378 raise ValueError,"%s is missing" % (c,) 1379 elif tp=="multi": 1380 self.content[c]=[] 1381 elif tp=="optional": 1382 self.content[c]=None 1383 else: 1384 continue
1385
1386 - def __make_fn(self):
1387 """Initialize the mandatory `self.fn` from `self.n`. 1388 1389 This is a workaround for buggy clients which set only one of them.""" 1390 s=[] 1391 if self.n.prefix: 1392 s.append(self.n.prefix) 1393 if self.n.given: 1394 s.append(self.n.given) 1395 if self.n.middle: 1396 s.append(self.n.middle) 1397 if self.n.family: 1398 s.append(self.n.family) 1399 if self.n.suffix: 1400 s.append(self.n.suffix) 1401 s=u" ".join(s) 1402 self.content["FN"]=VCardString("FN", s, empty_ok = True)
1403
1404 - def __from_xml(self,data):
1405 """Initialize a VCard object from XML node. 1406 1407 :Parameters: 1408 - `data`: vcard to parse. 1409 :Types: 1410 - `data`: `libxml2.xmlNode`""" 1411 ns=get_node_ns(data) 1412 if ns and ns.getContent()!=VCARD_NS: 1413 raise ValueError, "Not in the %r namespace" % (VCARD_NS,) 1414 if data.name!="vCard": 1415 raise ValueError, "Bad root element name: %r" % (data.name,) 1416 n=data.children 1417 dns=get_node_ns(data) 1418 while n: 1419 if n.type!='element': 1420 n=n.next 1421 continue 1422 ns=get_node_ns(n) 1423 if (ns and dns and ns.getContent()!=dns.getContent()): 1424 n=n.next 1425 continue 1426 if not self.components.has_key(n.name): 1427 n=n.next 1428 continue 1429 cl,tp=self.components[n.name] 1430 if tp in ("required","optional"): 1431 if self.content.has_key(n.name): 1432 raise ValueError,"Duplicate %s" % (n.name,) 1433 try: 1434 self.content[n.name]=cl(n.name,n) 1435 except Empty: 1436 pass 1437 elif tp=="multi": 1438 if not self.content.has_key(n.name): 1439 self.content[n.name]=[] 1440 try: 1441 self.content[n.name].append(cl(n.name,n)) 1442 except Empty: 1443 pass 1444 n=n.next
1445
1446 - def __from_rfc2426(self,data):
1447 """Initialize a VCard object from an RFC2426 string. 1448 1449 :Parameters: 1450 - `data`: vcard to parse. 1451 :Types: 1452 - `data`: `libxml2.xmlNode`, `unicode` or `str`""" 1453 data=from_utf8(data) 1454 lines=data.split("\n") 1455 started=0 1456 current=None 1457 for l in lines: 1458 if not l: 1459 continue 1460 if l[-1]=="\r": 1461 l=l[:-1] 1462 if not l: 1463 continue 1464 if l[0] in " \t": 1465 if current is None: 1466 continue 1467 current+=l[1:] 1468 continue 1469 if not started and current and current.upper().strip()=="BEGIN:VCARD": 1470 started=1 1471 elif started and current.upper().strip()=="END:VCARD": 1472 current=None 1473 break 1474 elif current and started: 1475 self._process_rfc2425_record(current) 1476 current=l 1477 if started and current: 1478 self._process_rfc2425_record(current)
1479
1480 - def _process_rfc2425_record(self,data):
1481 """Parse single RFC2425 record and update attributes of `self`. 1482 1483 :Parameters: 1484 - `data`: the record (probably multiline) 1485 :Types: 1486 - `data`: `unicode`""" 1487 label,value=data.split(":",1) 1488 value=value.replace("\\n","\n").replace("\\N","\n") 1489 psplit=label.lower().split(";") 1490 name=psplit[0] 1491 params=psplit[1:] 1492 if u"." in name: 1493 name=name.split(".",1)[1] 1494 name=name.upper() 1495 if name in (u"X-DESC",u"X-JABBERID"): 1496 name=name[2:] 1497 if not self.components.has_key(name): 1498 return 1499 if params: 1500 params=dict([p.split("=",1) for p in params]) 1501 cl,tp=self.components[name] 1502 if tp in ("required","optional"): 1503 if self.content.has_key(name): 1504 raise ValueError,"Duplicate %s" % (name,) 1505 try: 1506 self.content[name]=cl(name,value,params) 1507 except Empty: 1508 pass 1509 elif tp=="multi": 1510 if not self.content.has_key(name): 1511 self.content[name]=[] 1512 try: 1513 self.content[name].append(cl(name,value,params)) 1514 except Empty: 1515 pass 1516 else: 1517 return
1518 - def __repr__(self):
1519 return "<vCard of %r>" % (self.content["FN"].value,)
1520 - def rfc2426(self):
1521 """Get the RFC2426 representation of `self`. 1522 1523 :return: the UTF-8 encoded RFC2426 representation. 1524 :returntype: `str`""" 1525 ret="begin:VCARD\r\n" 1526 ret+="version:3.0\r\n" 1527 for _unused, value in self.content.items(): 1528 if value is None: 1529 continue 1530 if type(value) is list: 1531 for v in value: 1532 ret+=v.rfc2426() 1533 else: 1534 v=value.rfc2426() 1535 ret+=v 1536 return ret+"end:VCARD\r\n"
1537
1538 - def complete_xml_element(self, xmlnode, _unused):
1539 """Complete the XML node with `self` content. 1540 1541 Should be overriden in classes derived from `StanzaPayloadObject`. 1542 1543 :Parameters: 1544 - `xmlnode`: XML node with the element being built. It has already 1545 right name and namespace, but no attributes or content. 1546 - `_unused`: document to which the element belongs. 1547 :Types: 1548 - `xmlnode`: `libxml2.xmlNode` 1549 - `_unused`: `libxml2.xmlDoc`""" 1550 for _unused1, value in self.content.items(): 1551 if value is None: 1552 continue 1553 if type(value) is list: 1554 for v in value: 1555 v.as_xml(xmlnode) 1556 else: 1557 value.as_xml(xmlnode)
1558
1559 - def __getattr__(self,name):
1560 try: 1561 return self.content[name.upper().replace("_","-")] 1562 except KeyError: 1563 raise AttributeError,"Attribute %r not found" % (name,)
1564 - def __getitem__(self,name):
1565 return self.content[name.upper()]
1566 1567 # vi: sts=4 et sw=4 1568