1   
   2   
   3   
   4   
   5   
   6   
   7   
   8   
   9   
  10   
  11   
  12   
  13   
  14   
  15   
  16   
  17   
  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   
  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   
  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   
  91      """Base class for vCard fields. 
  92   
  93      :Ivariables: 
  94          - `name`: name of the field. 
  95      """ 
  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 
  107          return "<%s %r>" % (self.__class__,self.rfc2426()) 
  109          """RFC2426-encode the field content. 
 110   
 111          :return: the field in the RFC 2426 format. 
 112          :returntype: `str`""" 
 113          return "" 
   114   
 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" 
  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) 
  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)) 
  165          return self.value.encode("utf-8") 
   166   
 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`""" 
 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   
 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" 
  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()) 
  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) 
   238   
 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 
  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)) 
  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 
  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) 
   344   
 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 
  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) 
  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 
  432          if self.uri: 
 433              return self.uri 
 434          if self.type: 
 435              return u"(%s data)" % (self.type,) 
 436          return u"(binary data)" 
   439   
 440   
 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   
 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   
 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   
 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   
 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   
 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)}) 
  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   
 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 
  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)}) 
  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   
 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 
  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)}) 
  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   
 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(";") 
  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)) 
  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   
 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 
  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,)) 
  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   
 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(",") 
 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)) 
 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   
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 
 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) 
 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   
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 
 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) 
 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   
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 
 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) 
 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               
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"),  
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          }; 
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           
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   
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   
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   
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   
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 
 1519          return "<vCard of %r>" % (self.content["FN"].value,) 
 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   
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   
1560          try: 
1561              return self.content[name.upper().replace("_","-")] 
1562          except KeyError: 
1563              raise AttributeError,"Attribute %r not found" % (name,) 
 1565          return self.content[name.upper()] 
  1566   
1567   
1568