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