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