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