1 /*
2 * xmpp_vcard.cpp - classes for handling vCards
3 * Copyright (C) 2003 Michail Pishchagin
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * either version 2
9 of the License, or (at your option) any later version.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22 #include "xmpp_vcard.h"
23
24 #include <QDateTime>
25
26 #include <QImage> // needed for image format recognition
27 #include <QBuffer>
28 #include <QImageReader>
29 #include <QImageWriter>
30 #include <QtCrypto>
31
32 #include "xmpp_xmlcommon.h"
33
34 using namespace XMPP;
35 using namespace XMLHelper;
36
37 //----------------------------------------------------------------------------
38 // VCard
39 //----------------------------------------------------------------------------
image2type(const QByteArray & ba)40 QString image2type(const QByteArray &ba)
41 {
42 QBuffer buf;
43 buf.setData(ba);
44 buf.open(QIODevice::ReadOnly);
45 QString format = QImageReader::imageFormat( &buf );
46
47 // TODO: add more formats
48 if ( format.toUpper() == "PNG" || format == "PsiPNG" )
49 return "image/png";
50 if ( format.toUpper() == "MNG" )
51 return "video/x-mng";
52 if ( format.toUpper() == "GIF" )
53 return "image/gif";
54 if ( format.toUpper() == "BMP" )
55 return "image/bmp";
56 if ( format.toUpper() == "XPM" )
57 return "image/x-xpm";
58 if ( format.toUpper() == "SVG" )
59 return "image/svg+xml";
60 if ( format.toUpper() == "JPEG" )
61 return "image/jpeg";
62
63 const QByteArray formatAscii = format.toLatin1();
64 qWarning("WARNING! VCard::image2type: unknown format = '%s'", format.isNull() ? "UNKNOWN" : formatAscii.constData());
65
66 return "image/unknown";
67 }
68
69 // Long lines of encoded binary data SHOULD BE folded to 75 characters using the folding method defined in [MIME-DIR].
foldString(const QString & s)70 static QString foldString(const QString &s)
71 {
72 QString ret;
73
74 for (int i = 0; i < (int)s.length(); i++) {
75 if ( !(i % 75) )
76 ret += '\n';
77 ret += s[i];
78 }
79
80 return ret;
81 }
82
83 class VCard::Private
84 {
85 public:
86 Private();
87 ~Private();
88
89 QString version;
90 QString fullName;
91 QString familyName, givenName, middleName, prefixName, suffixName;
92 QString nickName;
93
94 QByteArray photo;
95 QString photoURI;
96
97 QString bday;
98 AddressList addressList;
99 LabelList labelList;
100 PhoneList phoneList;
101 EmailList emailList;
102 QString jid;
103 QString mailer;
104 QString timezone;
105 Geo geo;
106 QString title;
107 QString role;
108
109 QByteArray logo;
110 QString logoURI;
111
112 VCard *agent;
113 QString agentURI;
114
115 Org org;
116 QStringList categories;
117 QString note;
118 QString prodId;
119 QString rev;
120 QString sortString;
121
122 QByteArray sound;
123 QString soundURI, soundPhonetic;
124
125 QString uid;
126 QString url;
127 QString desc;
128 PrivacyClass privacyClass;
129 QByteArray key;
130
131 bool isEmpty();
132 };
133
Private()134 VCard::Private::Private()
135 {
136 privacyClass = pcNone;
137 agent = 0;
138 }
139
~Private()140 VCard::Private::~Private()
141 {
142 delete agent;
143 }
144
isEmpty()145 bool VCard::Private::isEmpty()
146 {
147 if ( !version.isEmpty() ||
148 !fullName.isEmpty() ||
149 !familyName.isEmpty() || !givenName.isEmpty() || !middleName.isEmpty() || !prefixName.isEmpty() || !suffixName.isEmpty() ||
150 !nickName.isEmpty() ||
151 !photo.isEmpty() || !photoURI.isEmpty() ||
152 !bday.isEmpty() ||
153 !addressList.isEmpty() ||
154 !labelList.isEmpty() ||
155 !phoneList.isEmpty() ||
156 !emailList.isEmpty() ||
157 !jid.isEmpty() ||
158 !mailer.isEmpty() ||
159 !timezone.isEmpty() ||
160 !geo.lat.isEmpty() || !geo.lon.isEmpty() ||
161 !title.isEmpty() ||
162 !role.isEmpty() ||
163 !logo.isEmpty() || !logoURI.isEmpty() ||
164 (agent && !agent->isEmpty()) || !agentURI.isEmpty() ||
165 !org.name.isEmpty() || !org.unit.isEmpty() ||
166 !categories.isEmpty() ||
167 !note.isEmpty() ||
168 !prodId.isEmpty() ||
169 !rev.isEmpty() ||
170 !sortString.isEmpty() ||
171 !sound.isEmpty() || !soundURI.isEmpty() || !soundPhonetic.isEmpty() ||
172 !uid.isEmpty() ||
173 !url.isEmpty() ||
174 !desc.isEmpty() ||
175 (privacyClass != pcNone) ||
176 !key.isEmpty() )
177 {
178 return false;
179 }
180 return true;
181 }
182
VCard()183 VCard::VCard()
184 {
185 d = new Private;
186 }
187
VCard(const VCard & from)188 VCard::VCard(const VCard &from)
189 {
190 d = new Private;
191 *this = from;
192 }
193
operator =(const VCard & from)194 VCard & VCard::operator=(const VCard &from)
195 {
196 if(d->agent) {
197 delete d->agent;
198 d->agent = 0;
199 }
200
201 *d = *from.d;
202
203 if(from.d->agent) {
204 // dup the agent
205 d->agent = new VCard(*from.d->agent);
206 }
207
208 return *this;
209 }
210
~VCard()211 VCard::~VCard()
212 {
213 delete d;
214 }
215
toXml(QDomDocument * doc) const216 QDomElement VCard::toXml(QDomDocument *doc) const
217 {
218 QDomElement v = doc->createElement("vCard");
219 v.setAttribute("version", "2.0");
220 v.setAttribute("prodid", "-//HandGen//NONSGML vGen v1.0//EN");
221 v.setAttribute("xmlns", "vcard-temp");
222
223 if ( !d->version.isEmpty() )
224 v.appendChild( textTag(doc, "VERSION", d->version) );
225 if ( !d->fullName.isEmpty() )
226 v.appendChild( textTag(doc, "FN", d->fullName) );
227
228 if ( !d->familyName.isEmpty() || !d->givenName.isEmpty() || !d->middleName.isEmpty() ||
229 !d->prefixName.isEmpty() || !d->suffixName.isEmpty() ) {
230 QDomElement w = doc->createElement("N");
231
232 if ( !d->familyName.isEmpty() )
233 w.appendChild( textTag(doc, "FAMILY", d->familyName) );
234 if ( !d->givenName.isEmpty() )
235 w.appendChild( textTag(doc, "GIVEN", d->givenName) );
236 if ( !d->middleName.isEmpty() )
237 w.appendChild( textTag(doc, "MIDDLE", d->middleName) );
238 if ( !d->prefixName.isEmpty() )
239 w.appendChild( textTag(doc, "PREFIX", d->prefixName) );
240 if ( !d->suffixName.isEmpty() )
241 w.appendChild( textTag(doc, "SUFFIX", d->suffixName) );
242
243 v.appendChild(w);
244 }
245
246 if ( !d->nickName.isEmpty() )
247 v.appendChild( textTag(doc, "NICKNAME", d->nickName) );
248
249 if ( !d->photo.isEmpty() || !d->photoURI.isEmpty() ) {
250 QDomElement w = doc->createElement("PHOTO");
251
252 if ( !d->photo.isEmpty() ) {
253 w.appendChild( textTag(doc, "TYPE", image2type(d->photo)) );
254 w.appendChild( textTag(doc, "BINVAL", foldString( QCA::Base64().arrayToString(d->photo)) ) );
255 }
256 else if ( !d->photoURI.isEmpty() )
257 w.appendChild( textTag(doc, "EXTVAL", d->photoURI) );
258
259 v.appendChild(w);
260 }
261
262 if ( !d->bday.isEmpty() )
263 v.appendChild( textTag(doc, "BDAY", d->bday) );
264
265 if ( !d->addressList.isEmpty() ) {
266 AddressList::Iterator it = d->addressList.begin();
267 for ( ; it != d->addressList.end(); ++it ) {
268 QDomElement w = doc->createElement("ADR");
269 Address a = *it;
270
271 if ( a.home )
272 w.appendChild( emptyTag(doc, "HOME") );
273 if ( a.work )
274 w.appendChild( emptyTag(doc, "WORK") );
275 if ( a.postal )
276 w.appendChild( emptyTag(doc, "POSTAL") );
277 if ( a.parcel )
278 w.appendChild( emptyTag(doc, "PARCEL") );
279 if ( a.dom )
280 w.appendChild( emptyTag(doc, "DOM") );
281 if ( a.intl )
282 w.appendChild( emptyTag(doc, "INTL") );
283 if ( a.pref )
284 w.appendChild( emptyTag(doc, "PREF") );
285
286 if ( !a.pobox.isEmpty() )
287 w.appendChild( textTag(doc, "POBOX", a.pobox) );
288 if ( !a.extaddr.isEmpty() )
289 w.appendChild( textTag(doc, "EXTADR", a.extaddr) );
290 if ( !a.street.isEmpty() )
291 w.appendChild( textTag(doc, "STREET", a.street) );
292 if ( !a.locality.isEmpty() )
293 w.appendChild( textTag(doc, "LOCALITY", a.locality) );
294 if ( !a.region.isEmpty() )
295 w.appendChild( textTag(doc, "REGION", a.region) );
296 if ( !a.pcode.isEmpty() )
297 w.appendChild( textTag(doc, "PCODE", a.pcode) );
298 if ( !a.country.isEmpty() )
299 w.appendChild( textTag(doc, "CTRY", a.country) );
300
301 v.appendChild(w);
302 }
303 }
304
305 if ( !d->labelList.isEmpty() ) {
306 LabelList::Iterator it = d->labelList.begin();
307 for ( ; it != d->labelList.end(); ++it ) {
308 QDomElement w = doc->createElement("LABEL");
309 Label l = *it;
310
311 if ( l.home )
312 w.appendChild( emptyTag(doc, "HOME") );
313 if ( l.work )
314 w.appendChild( emptyTag(doc, "WORK") );
315 if ( l.postal )
316 w.appendChild( emptyTag(doc, "POSTAL") );
317 if ( l.parcel )
318 w.appendChild( emptyTag(doc, "PARCEL") );
319 if ( l.dom )
320 w.appendChild( emptyTag(doc, "DOM") );
321 if ( l.intl )
322 w.appendChild( emptyTag(doc, "INTL") );
323 if ( l.pref )
324 w.appendChild( emptyTag(doc, "PREF") );
325
326 if ( !l.lines.isEmpty() ) {
327 QStringList::Iterator it = l.lines.begin();
328 for ( ; it != l.lines.end(); ++it )
329 w.appendChild( textTag(doc, "LINE", *it) );
330 }
331
332 v.appendChild(w);
333 }
334 }
335
336 if ( !d->phoneList.isEmpty() ) {
337 PhoneList::Iterator it = d->phoneList.begin();
338 for ( ; it != d->phoneList.end(); ++it ) {
339 QDomElement w = doc->createElement("TEL");
340 Phone p = *it;
341
342 if ( p.home )
343 w.appendChild( emptyTag(doc, "HOME") );
344 if ( p.work )
345 w.appendChild( emptyTag(doc, "WORK") );
346 if ( p.voice )
347 w.appendChild( emptyTag(doc, "VOICE") );
348 if ( p.fax )
349 w.appendChild( emptyTag(doc, "FAX") );
350 if ( p.pager )
351 w.appendChild( emptyTag(doc, "PAGER") );
352 if ( p.msg )
353 w.appendChild( emptyTag(doc, "MSG") );
354 if ( p.cell )
355 w.appendChild( emptyTag(doc, "CELL") );
356 if ( p.video )
357 w.appendChild( emptyTag(doc, "VIDEO") );
358 if ( p.bbs )
359 w.appendChild( emptyTag(doc, "BBS") );
360 if ( p.modem )
361 w.appendChild( emptyTag(doc, "MODEM") );
362 if ( p.isdn )
363 w.appendChild( emptyTag(doc, "ISDN") );
364 if ( p.pcs )
365 w.appendChild( emptyTag(doc, "PCS") );
366 if ( p.pref )
367 w.appendChild( emptyTag(doc, "PREF") );
368
369 if ( !p.number.isEmpty() )
370 w.appendChild( textTag(doc, "NUMBER", p.number) );
371
372 v.appendChild(w);
373 }
374 }
375
376 if ( !d->emailList.isEmpty() ) {
377 EmailList::Iterator it = d->emailList.begin();
378 for ( ; it != d->emailList.end(); ++it ) {
379 QDomElement w = doc->createElement("EMAIL");
380 Email e = *it;
381
382 if ( e.home )
383 w.appendChild( emptyTag(doc, "HOME") );
384 if ( e.work )
385 w.appendChild( emptyTag(doc, "WORK") );
386 if ( e.internet )
387 w.appendChild( emptyTag(doc, "INTERNET") );
388 if ( e.x400 )
389 w.appendChild( emptyTag(doc, "X400") );
390
391 if ( !e.userid.isEmpty() )
392 w.appendChild( textTag(doc, "USERID", e.userid) );
393
394 v.appendChild(w);
395 }
396 }
397
398 if ( !d->jid.isEmpty() )
399 v.appendChild( textTag(doc, "JABBERID", d->jid) );
400 if ( !d->mailer.isEmpty() )
401 v.appendChild( textTag(doc, "MAILER", d->mailer) );
402 if ( !d->timezone.isEmpty() )
403 v.appendChild( textTag(doc, "TZ", d->timezone) );
404
405 if ( !d->geo.lat.isEmpty() || !d->geo.lon.isEmpty() ) {
406 QDomElement w = doc->createElement("GEO");
407
408 if ( !d->geo.lat.isEmpty() )
409 w.appendChild( textTag(doc, "LAT", d->geo.lat) );
410 if ( !d->geo.lon.isEmpty() )
411 w.appendChild( textTag(doc, "LON", d->geo.lon));
412
413 v.appendChild(w);
414 }
415
416 if ( !d->title.isEmpty() )
417 v.appendChild( textTag(doc, "TITLE", d->title) );
418 if ( !d->role.isEmpty() )
419 v.appendChild( textTag(doc, "ROLE", d->role) );
420
421 if ( !d->logo.isEmpty() || !d->logoURI.isEmpty() ) {
422 QDomElement w = doc->createElement("LOGO");
423
424 if ( !d->logo.isEmpty() ) {
425 w.appendChild( textTag(doc, "TYPE", image2type(d->logo)) );
426 w.appendChild( textTag(doc, "BINVAL", foldString( QCA::Base64().arrayToString(d->logo)) ) );
427 }
428 else if ( !d->logoURI.isEmpty() )
429 w.appendChild( textTag(doc, "EXTVAL", d->logoURI) );
430
431 v.appendChild(w);
432 }
433
434 if ( !d->agentURI.isEmpty() || (d->agent && d->agent->isEmpty()) ) {
435 QDomElement w = doc->createElement("AGENT");
436
437 if ( d->agent && !d->agent->isEmpty() )
438 w.appendChild( d->agent->toXml(doc) );
439 else if ( !d->agentURI.isEmpty() )
440 w.appendChild( textTag(doc, "EXTVAL", d->agentURI) );
441
442 v.appendChild(w);
443 }
444
445 if ( !d->org.name.isEmpty() || !d->org.unit.isEmpty() ) {
446 QDomElement w = doc->createElement("ORG");
447
448 if ( !d->org.name.isEmpty() )
449 w.appendChild( textTag(doc, "ORGNAME", d->org.name) );
450
451 if ( !d->org.unit.isEmpty() ) {
452 QStringList::Iterator it = d->org.unit.begin();
453 for ( ; it != d->org.unit.end(); ++it )
454 w.appendChild( textTag(doc, "ORGUNIT", *it) );
455 }
456
457 v.appendChild(w);
458 }
459
460 if ( !d->categories.isEmpty() ) {
461 QDomElement w = doc->createElement("CATEGORIES");
462
463 QStringList::Iterator it = d->categories.begin();
464 for ( ; it != d->categories.end(); ++it )
465 w.appendChild( textTag(doc, "KEYWORD", *it) );
466
467 v.appendChild(w);
468 }
469
470 if ( !d->note.isEmpty() )
471 v.appendChild( textTag(doc, "NOTE", d->note) );
472 if ( !d->prodId.isEmpty() )
473 v.appendChild( textTag(doc, "PRODID", d->prodId) );
474 if ( !d->rev.isEmpty() )
475 v.appendChild( textTag(doc, "REV", d->rev) );
476 if ( !d->sortString.isEmpty() )
477 v.appendChild( textTag(doc, "SORT-STRING", d->sortString) );
478
479 if ( !d->sound.isEmpty() || !d->soundURI.isEmpty() || !d->soundPhonetic.isEmpty() ) {
480 QDomElement w = doc->createElement("SOUND");
481
482 if ( !d->sound.isEmpty() )
483 w.appendChild( textTag(doc, "BINVAL", foldString( QCA::Base64().arrayToString(d->sound)) ) );
484 else if ( !d->soundURI.isEmpty() )
485 w.appendChild( textTag(doc, "EXTVAL", d->soundURI) );
486 else if ( !d->soundPhonetic.isEmpty() )
487 w.appendChild( textTag(doc, "PHONETIC", d->soundPhonetic) );
488
489 v.appendChild(w);
490 }
491
492 if ( !d->uid.isEmpty() )
493 v.appendChild( textTag(doc, "UID", d->uid) );
494 if ( !d->url.isEmpty() )
495 v.appendChild( textTag(doc, "URL", d->url) );
496 if ( !d->desc.isEmpty() )
497 v.appendChild( textTag(doc, "DESC", d->desc) );
498
499 if ( d->privacyClass != pcNone ) {
500 QDomElement w = doc->createElement("CLASS");
501
502 if ( d->privacyClass == pcPublic )
503 w.appendChild( emptyTag(doc, "PUBLIC") );
504 else if ( d->privacyClass == pcPrivate )
505 w.appendChild( emptyTag(doc, "PRIVATE") );
506 else if ( d->privacyClass == pcConfidential )
507 w.appendChild( emptyTag(doc, "CONFIDENTIAL") );
508
509 v.appendChild(w);
510 }
511
512 if ( !d->key.isEmpty() ) {
513 QDomElement w = doc->createElement("KEY");
514
515 // TODO: Justin, please check out this code
516 w.appendChild( textTag(doc, "TYPE", "text/plain")); // FIXME
517 w.appendChild( textTag(doc, "CRED", QString::fromUtf8(d->key)) ); // FIXME
518
519 v.appendChild(w);
520 }
521
522 return v;
523 }
524
fromXml(const QDomElement & q)525 bool VCard::fromXml(const QDomElement &q)
526 {
527 if ( q.tagName().toUpper() != "VCARD" )
528 return false;
529
530 QDomNode n = q.firstChild();
531 for ( ; !n.isNull(); n = n.nextSibling() ) {
532 QDomElement i = n.toElement();
533 if ( i.isNull() )
534 continue;
535
536 QString tag = i.tagName().toUpper();
537
538 bool found;
539 QDomElement e;
540
541 if ( tag == "VERSION" )
542 d->version = i.text().trimmed();
543 else if ( tag == "FN" )
544 d->fullName = i.text().trimmed();
545 else if ( tag == "N" ) {
546 d->familyName = subTagText(i, "FAMILY");
547 d->givenName = subTagText(i, "GIVEN");
548 d->middleName = subTagText(i, "MIDDLE");
549 d->prefixName = subTagText(i, "PREFIX");
550 d->suffixName = subTagText(i, "SUFFIX");
551 }
552 else if ( tag == "NICKNAME" )
553 d->nickName = i.text().trimmed();
554 else if ( tag == "PHOTO" ) {
555 d->photo = QCA::Base64().stringToArray(subTagText(i, "BINVAL").replace("\n","")).toByteArray();
556 d->photoURI = subTagText(i, "EXTVAL");
557 }
558 else if ( tag == "BDAY" )
559 d->bday = i.text().trimmed();
560 else if ( tag == "ADR" ) {
561 Address a;
562
563 a.home = hasSubTag(i, "HOME");
564 a.work = hasSubTag(i, "WORK");
565 a.postal = hasSubTag(i, "POSTAL");
566 a.parcel = hasSubTag(i, "PARCEL");
567 a.dom = hasSubTag(i, "DOM");
568 a.intl = hasSubTag(i, "INTL");
569 a.pref = hasSubTag(i, "PREF");
570
571 a.pobox = subTagText(i, "POBOX");
572 a.extaddr = subTagText(i, "EXTADR");
573 a.street = subTagText(i, "STREET");
574 a.locality = subTagText(i, "LOCALITY");
575 a.region = subTagText(i, "REGION");
576 a.pcode = subTagText(i, "PCODE");
577 a.country = subTagText(i, "CTRY");
578
579 if ( a.country.isEmpty() ) // FIXME: Workaround for Psi prior to 0.9
580 if ( hasSubTag(i, "COUNTRY") )
581 a.country = subTagText(i, "COUNTRY");
582
583 if ( a.extaddr.isEmpty() ) // FIXME: Workaround for Psi prior to 0.9
584 if ( hasSubTag(i, "EXTADD") )
585 a.extaddr = subTagText(i, "EXTADD");
586
587 d->addressList.append ( a );
588 }
589 else if ( tag == "LABEL" ) {
590 Label l;
591
592 l.home = hasSubTag(i, "HOME");
593 l.work = hasSubTag(i, "WORK");
594 l.postal = hasSubTag(i, "POSTAL");
595 l.parcel = hasSubTag(i, "PARCEL");
596 l.dom = hasSubTag(i, "DOM");
597 l.intl = hasSubTag(i, "INTL");
598 l.pref = hasSubTag(i, "PREF");
599
600 QDomNode nn = i.firstChild();
601 for ( ; !nn.isNull(); nn = nn.nextSibling() ) {
602 QDomElement ii = nn.toElement();
603 if ( ii.isNull() )
604 continue;
605
606 if ( ii.tagName().toUpper() == "LINE" )
607 l.lines.append ( ii.text().trimmed() );
608 }
609
610 d->labelList.append ( l );
611 }
612 else if ( tag == "TEL" ) {
613 Phone p;
614
615 p.home = hasSubTag(i, "HOME");
616 p.work = hasSubTag(i, "WORK");
617 p.voice = hasSubTag(i, "VOICE");
618 p.fax = hasSubTag(i, "FAX");
619 p.pager = hasSubTag(i, "PAGER");
620 p.msg = hasSubTag(i, "MSG");
621 p.cell = hasSubTag(i, "CELL");
622 p.video = hasSubTag(i, "VIDEO");
623 p.bbs = hasSubTag(i, "BBS");
624 p.modem = hasSubTag(i, "MODEM");
625 p.isdn = hasSubTag(i, "ISDN");
626 p.pcs = hasSubTag(i, "PCS");
627 p.pref = hasSubTag(i, "PREF");
628
629 p.number = subTagText(i, "NUMBER");
630
631 if ( p.number.isEmpty() ) // FIXME: Workaround for Psi prior to 0.9
632 if ( hasSubTag(i, "VOICE") )
633 p.number = subTagText(i, "VOICE");
634
635 d->phoneList.append ( p );
636 }
637 else if ( tag == "EMAIL" ) {
638 Email m;
639
640 m.home = hasSubTag(i, "HOME");
641 m.work = hasSubTag(i, "WORK");
642 m.internet = hasSubTag(i, "INTERNET");
643 m.x400 = hasSubTag(i, "X400");
644
645 m.userid = subTagText(i, "USERID");
646
647 if ( m.userid.isEmpty() ) // FIXME: Workaround for Psi prior to 0.9
648 if ( !i.text().isEmpty() )
649 m.userid = i.text().trimmed();
650
651 d->emailList.append ( m );
652 }
653 else if ( tag == "JABBERID" )
654 d->jid = i.text().trimmed();
655 else if ( tag == "MAILER" )
656 d->mailer = i.text().trimmed();
657 else if ( tag == "TZ" )
658 d->timezone = i.text().trimmed();
659 else if ( tag == "GEO" ) {
660 d->geo.lat = subTagText(i, "LAT");
661 d->geo.lon = subTagText(i, "LON");
662 }
663 else if ( tag == "TITLE" )
664 d->title = i.text().trimmed();
665 else if ( tag == "ROLE" )
666 d->role = i.text().trimmed();
667 else if ( tag == "LOGO" ) {
668 d->logo = QCA::Base64().stringToArray( subTagText(i, "BINVAL").replace("\n","") ).toByteArray();
669 d->logoURI = subTagText(i, "EXTVAL");
670 }
671 else if ( tag == "AGENT" ) {
672 e = findSubTag(i, "VCARD", &found);
673 if ( found ) {
674 VCard a;
675 if ( a.fromXml(e) ) {
676 if ( !d->agent )
677 d->agent = new VCard;
678 *(d->agent) = a;
679 }
680 }
681
682 d->agentURI = subTagText(i, "EXTVAL");
683 }
684 else if ( tag == "ORG" ) {
685 d->org.name = subTagText(i, "ORGNAME");
686
687 QDomNode nn = i.firstChild();
688 for ( ; !nn.isNull(); nn = nn.nextSibling() ) {
689 QDomElement ii = nn.toElement();
690 if ( ii.isNull() )
691 continue;
692
693 if ( ii.tagName().toUpper() == "ORGUNIT" )
694 d->org.unit.append( ii.text().trimmed() );
695 }
696 }
697 else if ( tag == "CATEGORIES") {
698 QDomNode nn = i.firstChild();
699 for ( ; !nn.isNull(); nn = nn.nextSibling() ) {
700 QDomElement ee = nn.toElement();
701 if ( ee.isNull() )
702 continue;
703
704 if ( ee.tagName().toUpper() == "KEYWORD" )
705 d->categories << ee.text().trimmed();
706 }
707 }
708 else if ( tag == "NOTE" )
709 d->note = i.text().trimmed();
710 else if ( tag == "PRODID" )
711 d->prodId = i.text().trimmed();
712 else if ( tag == "REV" )
713 d->rev = i.text().trimmed();
714 else if ( tag == "SORT-STRING" )
715 d->sortString = i.text().trimmed();
716 else if ( tag == "SOUND" ) {
717 d->sound = QCA::Base64().stringToArray( subTagText(i, "BINVAL").replace("\n","") ).toByteArray();
718 d->soundURI = subTagText(i, "EXTVAL");
719 d->soundPhonetic = subTagText(i, "PHONETIC");
720 }
721 else if ( tag == "UID" )
722 d->uid = i.text().trimmed();
723 else if ( tag == "URL")
724 d->url = i.text().trimmed();
725 else if ( tag == "DESC" )
726 d->desc = i.text().trimmed();
727 else if ( tag == "CLASS" ) {
728 if ( hasSubTag(i, "PUBLIC") )
729 d->privacyClass = pcPublic;
730 else if ( hasSubTag(i, "PRIVATE") )
731 d->privacyClass = pcPrivate;
732 else if ( hasSubTag(i, "CONFIDENTIAL") )
733 d->privacyClass = pcConfidential;
734 }
735 else if ( tag == "KEY" ) {
736 // TODO: Justin, please check out this code
737 e = findSubTag(i, "TYPE", &found);
738 QString type = "text/plain";
739 if ( found )
740 type = e.text().trimmed();
741
742 e = findSubTag(i, "CRED", &found );
743 if ( !found )
744 e = findSubTag(i, "BINVAL", &found); // case for very clever clients ;-)
745
746 if ( found )
747 d->key = e.text().toUtf8(); // FIXME
748 }
749 }
750
751 return true;
752 }
753
isEmpty() const754 bool VCard::isEmpty() const
755 {
756 return d->isEmpty();
757 }
758
759 // Some constructors
760
Address()761 VCard::Address::Address()
762 {
763 home = work = postal = parcel = dom = intl = pref = false;
764 }
765
Label()766 VCard::Label::Label()
767 {
768 home = work = postal = parcel = dom = intl = pref = false;
769 }
770
Phone()771 VCard::Phone::Phone()
772 {
773 home = work = voice = fax = pager = msg = cell = video = bbs = modem = isdn = pcs = pref = false;
774 }
775
Email()776 VCard::Email::Email()
777 {
778 home = work = internet = x400 = false;
779 }
780
Geo()781 VCard::Geo::Geo()
782 {
783 }
784
Org()785 VCard::Org::Org()
786 {
787 }
788
789 // vCard properties...
790
version() const791 const QString &VCard::version() const
792 {
793 return d->version;
794 }
795
setVersion(const QString & v)796 void VCard::setVersion(const QString &v)
797 {
798 d->version = v;
799 }
800
fullName() const801 const QString &VCard::fullName() const
802 {
803 return d->fullName;
804 }
805
setFullName(const QString & n)806 void VCard::setFullName(const QString &n)
807 {
808 d->fullName = n;
809 }
810
familyName() const811 const QString &VCard::familyName() const
812 {
813 return d->familyName;
814 }
815
setFamilyName(const QString & n)816 void VCard::setFamilyName(const QString &n)
817 {
818 d->familyName = n;
819 }
820
givenName() const821 const QString &VCard::givenName() const
822 {
823 return d->givenName;
824 }
825
setGivenName(const QString & n)826 void VCard::setGivenName(const QString &n)
827 {
828 d->givenName = n;
829 }
830
middleName() const831 const QString &VCard::middleName() const
832 {
833 return d->middleName;
834 }
835
setMiddleName(const QString & n)836 void VCard::setMiddleName(const QString &n)
837 {
838 d->middleName = n;
839 }
840
prefixName() const841 const QString &VCard::prefixName() const
842 {
843 return d->prefixName;
844 }
845
setPrefixName(const QString & p)846 void VCard::setPrefixName(const QString &p)
847 {
848 d->prefixName = p;
849 }
850
suffixName() const851 const QString &VCard::suffixName() const
852 {
853 return d->suffixName;
854 }
855
setSuffixName(const QString & s)856 void VCard::setSuffixName(const QString &s)
857 {
858 d->suffixName = s;
859 }
860
nickName() const861 const QString &VCard::nickName() const
862 {
863 return d->nickName;
864 }
865
setNickName(const QString & n)866 void VCard::setNickName(const QString &n)
867 {
868 d->nickName = n;
869 }
870
photo() const871 const QByteArray &VCard::photo() const
872 {
873 return d->photo;
874 }
875
setPhoto(const QByteArray & i)876 void VCard::setPhoto(const QByteArray &i)
877 {
878 d->photo = i;
879 }
880
photoURI() const881 const QString &VCard::photoURI() const
882 {
883 return d->photoURI;
884 }
885
setPhotoURI(const QString & p)886 void VCard::setPhotoURI(const QString &p)
887 {
888 d->photoURI = p;
889 }
890
bday() const891 const QDate VCard::bday() const
892 {
893 return QDate::fromString(d->bday);
894 }
895
setBday(const QDate & date)896 void VCard::setBday(const QDate &date)
897 {
898 d->bday = date.toString();
899 }
900
bdayStr() const901 const QString &VCard::bdayStr() const
902 {
903 return d->bday;
904 }
905
setBdayStr(const QString & date)906 void VCard::setBdayStr(const QString &date)
907 {
908 d->bday = date;
909 }
910
addressList() const911 const VCard::AddressList &VCard::addressList() const
912 {
913 return d->addressList;
914 }
915
setAddressList(const VCard::AddressList & a)916 void VCard::setAddressList(const VCard::AddressList &a)
917 {
918 d->addressList = a;
919 }
920
labelList() const921 const VCard::LabelList &VCard::labelList() const
922 {
923 return d->labelList;
924 }
925
setLabelList(const VCard::LabelList & l)926 void VCard::setLabelList(const VCard::LabelList &l)
927 {
928 d->labelList = l;
929 }
930
phoneList() const931 const VCard::PhoneList &VCard::phoneList() const
932 {
933 return d->phoneList;
934 }
935
setPhoneList(const VCard::PhoneList & p)936 void VCard::setPhoneList(const VCard::PhoneList &p)
937 {
938 d->phoneList = p;
939 }
940
emailList() const941 const VCard::EmailList &VCard::emailList() const
942 {
943 return d->emailList;
944 }
945
setEmailList(const VCard::EmailList & e)946 void VCard::setEmailList(const VCard::EmailList &e)
947 {
948 d->emailList = e;
949 }
950
jid() const951 const QString &VCard::jid() const
952 {
953 return d->jid;
954 }
955
setJid(const QString & j)956 void VCard::setJid(const QString &j)
957 {
958 d->jid = j;
959 }
960
mailer() const961 const QString &VCard::mailer() const
962 {
963 return d->mailer;
964 }
965
setMailer(const QString & m)966 void VCard::setMailer(const QString &m)
967 {
968 d->mailer = m;
969 }
970
timezone() const971 const QString &VCard::timezone() const
972 {
973 return d->timezone;
974 }
975
setTimezone(const QString & t)976 void VCard::setTimezone(const QString &t)
977 {
978 d->timezone = t;
979 }
980
geo() const981 const VCard::Geo &VCard::geo() const
982 {
983 return d->geo;
984 }
985
setGeo(const VCard::Geo & g)986 void VCard::setGeo(const VCard::Geo &g)
987 {
988 d->geo = g;
989 }
990
title() const991 const QString &VCard::title() const
992 {
993 return d->title;
994 }
995
setTitle(const QString & t)996 void VCard::setTitle(const QString &t)
997 {
998 d->title = t;
999 }
1000
role() const1001 const QString &VCard::role() const
1002 {
1003 return d->role;
1004 }
1005
setRole(const QString & r)1006 void VCard::setRole(const QString &r)
1007 {
1008 d->role = r;
1009 }
1010
logo() const1011 const QByteArray &VCard::logo() const
1012 {
1013 return d->logo;
1014 }
1015
setLogo(const QByteArray & i)1016 void VCard::setLogo(const QByteArray &i)
1017 {
1018 d->logo = i;
1019 }
1020
logoURI() const1021 const QString &VCard::logoURI() const
1022 {
1023 return d->logoURI;
1024 }
1025
setLogoURI(const QString & l)1026 void VCard::setLogoURI(const QString &l)
1027 {
1028 d->logoURI = l;
1029 }
1030
agent() const1031 const VCard *VCard::agent() const
1032 {
1033 return d->agent;
1034 }
1035
setAgent(const VCard & v)1036 void VCard::setAgent(const VCard &v)
1037 {
1038 if ( !d->agent )
1039 d->agent = new VCard;
1040 *(d->agent) = v;
1041 }
1042
agentURI() const1043 const QString VCard::agentURI() const
1044 {
1045 return d->agentURI;
1046 }
1047
setAgentURI(const QString & a)1048 void VCard::setAgentURI(const QString &a)
1049 {
1050 d->agentURI = a;
1051 }
1052
org() const1053 const VCard::Org &VCard::org() const
1054 {
1055 return d->org;
1056 }
1057
setOrg(const VCard::Org & o)1058 void VCard::setOrg(const VCard::Org &o)
1059 {
1060 d->org = o;
1061 }
1062
categories() const1063 const QStringList &VCard::categories() const
1064 {
1065 return d->categories;
1066 }
1067
setCategories(const QStringList & c)1068 void VCard::setCategories(const QStringList &c)
1069 {
1070 d->categories = c;
1071 }
1072
note() const1073 const QString &VCard::note() const
1074 {
1075 return d->note;
1076 }
1077
setNote(const QString & n)1078 void VCard::setNote(const QString &n)
1079 {
1080 d->note = n;
1081 }
1082
prodId() const1083 const QString &VCard::prodId() const
1084 {
1085 return d->prodId;
1086 }
1087
setProdId(const QString & p)1088 void VCard::setProdId(const QString &p)
1089 {
1090 d->prodId = p;
1091 }
1092
rev() const1093 const QString &VCard::rev() const
1094 {
1095 return d->rev;
1096 }
1097
setRev(const QString & r)1098 void VCard::setRev(const QString &r)
1099 {
1100 d->rev = r;
1101 }
1102
sortString() const1103 const QString &VCard::sortString() const
1104 {
1105 return d->sortString;
1106 }
1107
setSortString(const QString & s)1108 void VCard::setSortString(const QString &s)
1109 {
1110 d->sortString = s;
1111 }
1112
sound() const1113 const QByteArray &VCard::sound() const
1114 {
1115 return d->sound;
1116 }
1117
setSound(const QByteArray & s)1118 void VCard::setSound(const QByteArray &s)
1119 {
1120 d->sound = s;
1121 }
1122
soundURI() const1123 const QString &VCard::soundURI() const
1124 {
1125 return d->soundURI;
1126 }
1127
setSoundURI(const QString & s)1128 void VCard::setSoundURI(const QString &s)
1129 {
1130 d->soundURI = s;
1131 }
1132
soundPhonetic() const1133 const QString &VCard::soundPhonetic() const
1134 {
1135 return d->soundPhonetic;
1136 }
1137
setSoundPhonetic(const QString & s)1138 void VCard::setSoundPhonetic(const QString &s)
1139 {
1140 d->soundPhonetic = s;
1141 }
1142
uid() const1143 const QString &VCard::uid() const
1144 {
1145 return d->uid;
1146 }
1147
setUid(const QString & u)1148 void VCard::setUid(const QString &u)
1149 {
1150 d->uid = u;
1151 }
1152
url() const1153 const QString &VCard::url() const
1154 {
1155 return d->url;
1156 }
1157
setUrl(const QString & u)1158 void VCard::setUrl(const QString &u)
1159 {
1160 d->url = u;
1161 }
1162
desc() const1163 const QString &VCard::desc() const
1164 {
1165 return d->desc;
1166 }
1167
setDesc(const QString & desc)1168 void VCard::setDesc(const QString &desc)
1169 {
1170 d->desc = desc;
1171 }
1172
privacyClass() const1173 const VCard::PrivacyClass &VCard::privacyClass() const
1174 {
1175 return d->privacyClass;
1176 }
1177
setPrivacyClass(const VCard::PrivacyClass & c)1178 void VCard::setPrivacyClass(const VCard::PrivacyClass &c)
1179 {
1180 d->privacyClass = c;
1181 }
1182
key() const1183 const QByteArray &VCard::key() const
1184 {
1185 return d->key;
1186 }
1187
setKey(const QByteArray & k)1188 void VCard::setKey(const QByteArray &k)
1189 {
1190 d->key = k;
1191 }
1192