File indexing completed on 2024-06-02 04:07:12
0001 /* 0002 * xmpp_vcard.cpp - classes for handling vCards 0003 * Copyright (C) 2003 Michail Pishchagin 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Lesser General Public 0007 * License as published by the Free Software Foundation; either 0008 * either version 2 0009 of the License, or (at your option) any later version.1 of the License, or (at your option) any later version. 0010 * 0011 * This library is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 * Lesser General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU Lesser General Public 0017 * License along with this library; if not, write to the Free Software 0018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 0019 * 0020 */ 0021 0022 #include "xmpp_vcard.h" 0023 0024 #include <QDateTime> 0025 0026 #include <QImage> // needed for image format recognition 0027 #include <QBuffer> 0028 #include <QImageReader> 0029 #include <QImageWriter> 0030 #include <QtCrypto> 0031 0032 #include "xmpp_xmlcommon.h" 0033 0034 using namespace XMPP; 0035 using namespace XMLHelper; 0036 0037 //---------------------------------------------------------------------------- 0038 // VCard 0039 //---------------------------------------------------------------------------- 0040 QString image2type(const QByteArray &ba) 0041 { 0042 QBuffer buf; 0043 buf.setData(ba); 0044 buf.open(QIODevice::ReadOnly); 0045 QString format = QImageReader::imageFormat( &buf ); 0046 0047 // TODO: add more formats 0048 if ( format.toUpper() == "PNG" || format == "PsiPNG" ) 0049 return "image/png"; 0050 if ( format.toUpper() == "MNG" ) 0051 return "video/x-mng"; 0052 if ( format.toUpper() == "GIF" ) 0053 return "image/gif"; 0054 if ( format.toUpper() == "BMP" ) 0055 return "image/bmp"; 0056 if ( format.toUpper() == "XPM" ) 0057 return "image/x-xpm"; 0058 if ( format.toUpper() == "SVG" ) 0059 return "image/svg+xml"; 0060 if ( format.toUpper() == "JPEG" ) 0061 return "image/jpeg"; 0062 0063 const QByteArray formatAscii = format.toLatin1(); 0064 qWarning("WARNING! VCard::image2type: unknown format = '%s'", format.isNull() ? "UNKNOWN" : formatAscii.constData()); 0065 0066 return "image/unknown"; 0067 } 0068 0069 // Long lines of encoded binary data SHOULD BE folded to 75 characters using the folding method defined in [MIME-DIR]. 0070 static QString foldString(const QString &s) 0071 { 0072 QString ret; 0073 0074 for (int i = 0; i < (int)s.length(); i++) { 0075 if ( !(i % 75) ) 0076 ret += '\n'; 0077 ret += s[i]; 0078 } 0079 0080 return ret; 0081 } 0082 0083 class VCard::Private 0084 { 0085 public: 0086 Private(); 0087 ~Private(); 0088 0089 QString version; 0090 QString fullName; 0091 QString familyName, givenName, middleName, prefixName, suffixName; 0092 QString nickName; 0093 0094 QByteArray photo; 0095 QString photoURI; 0096 0097 QString bday; 0098 AddressList addressList; 0099 LabelList labelList; 0100 PhoneList phoneList; 0101 EmailList emailList; 0102 QString jid; 0103 QString mailer; 0104 QString timezone; 0105 Geo geo; 0106 QString title; 0107 QString role; 0108 0109 QByteArray logo; 0110 QString logoURI; 0111 0112 VCard *agent; 0113 QString agentURI; 0114 0115 Org org; 0116 QStringList categories; 0117 QString note; 0118 QString prodId; 0119 QString rev; 0120 QString sortString; 0121 0122 QByteArray sound; 0123 QString soundURI, soundPhonetic; 0124 0125 QString uid; 0126 QString url; 0127 QString desc; 0128 PrivacyClass privacyClass; 0129 QByteArray key; 0130 0131 bool isEmpty(); 0132 }; 0133 0134 VCard::Private::Private() 0135 { 0136 privacyClass = pcNone; 0137 agent = 0; 0138 } 0139 0140 VCard::Private::~Private() 0141 { 0142 delete agent; 0143 } 0144 0145 bool VCard::Private::isEmpty() 0146 { 0147 if ( !version.isEmpty() || 0148 !fullName.isEmpty() || 0149 !familyName.isEmpty() || !givenName.isEmpty() || !middleName.isEmpty() || !prefixName.isEmpty() || !suffixName.isEmpty() || 0150 !nickName.isEmpty() || 0151 !photo.isEmpty() || !photoURI.isEmpty() || 0152 !bday.isEmpty() || 0153 !addressList.isEmpty() || 0154 !labelList.isEmpty() || 0155 !phoneList.isEmpty() || 0156 !emailList.isEmpty() || 0157 !jid.isEmpty() || 0158 !mailer.isEmpty() || 0159 !timezone.isEmpty() || 0160 !geo.lat.isEmpty() || !geo.lon.isEmpty() || 0161 !title.isEmpty() || 0162 !role.isEmpty() || 0163 !logo.isEmpty() || !logoURI.isEmpty() || 0164 (agent && !agent->isEmpty()) || !agentURI.isEmpty() || 0165 !org.name.isEmpty() || !org.unit.isEmpty() || 0166 !categories.isEmpty() || 0167 !note.isEmpty() || 0168 !prodId.isEmpty() || 0169 !rev.isEmpty() || 0170 !sortString.isEmpty() || 0171 !sound.isEmpty() || !soundURI.isEmpty() || !soundPhonetic.isEmpty() || 0172 !uid.isEmpty() || 0173 !url.isEmpty() || 0174 !desc.isEmpty() || 0175 (privacyClass != pcNone) || 0176 !key.isEmpty() ) 0177 { 0178 return false; 0179 } 0180 return true; 0181 } 0182 0183 VCard::VCard() 0184 { 0185 d = new Private; 0186 } 0187 0188 VCard::VCard(const VCard &from) 0189 { 0190 d = new Private; 0191 *this = from; 0192 } 0193 0194 VCard & VCard::operator=(const VCard &from) 0195 { 0196 if(d->agent) { 0197 delete d->agent; 0198 d->agent = 0; 0199 } 0200 0201 *d = *from.d; 0202 0203 if(from.d->agent) { 0204 // dup the agent 0205 d->agent = new VCard(*from.d->agent); 0206 } 0207 0208 return *this; 0209 } 0210 0211 VCard::~VCard() 0212 { 0213 delete d; 0214 } 0215 0216 QDomElement VCard::toXml(QDomDocument *doc) const 0217 { 0218 QDomElement v = doc->createElement("vCard"); 0219 v.setAttribute("version", "2.0"); 0220 v.setAttribute("prodid", "-//HandGen//NONSGML vGen v1.0//EN"); 0221 v.setAttribute("xmlns", "vcard-temp"); 0222 0223 if ( !d->version.isEmpty() ) 0224 v.appendChild( textTag(doc, "VERSION", d->version) ); 0225 if ( !d->fullName.isEmpty() ) 0226 v.appendChild( textTag(doc, "FN", d->fullName) ); 0227 0228 if ( !d->familyName.isEmpty() || !d->givenName.isEmpty() || !d->middleName.isEmpty() || 0229 !d->prefixName.isEmpty() || !d->suffixName.isEmpty() ) { 0230 QDomElement w = doc->createElement("N"); 0231 0232 if ( !d->familyName.isEmpty() ) 0233 w.appendChild( textTag(doc, "FAMILY", d->familyName) ); 0234 if ( !d->givenName.isEmpty() ) 0235 w.appendChild( textTag(doc, "GIVEN", d->givenName) ); 0236 if ( !d->middleName.isEmpty() ) 0237 w.appendChild( textTag(doc, "MIDDLE", d->middleName) ); 0238 if ( !d->prefixName.isEmpty() ) 0239 w.appendChild( textTag(doc, "PREFIX", d->prefixName) ); 0240 if ( !d->suffixName.isEmpty() ) 0241 w.appendChild( textTag(doc, "SUFFIX", d->suffixName) ); 0242 0243 v.appendChild(w); 0244 } 0245 0246 if ( !d->nickName.isEmpty() ) 0247 v.appendChild( textTag(doc, "NICKNAME", d->nickName) ); 0248 0249 if ( !d->photo.isEmpty() || !d->photoURI.isEmpty() ) { 0250 QDomElement w = doc->createElement("PHOTO"); 0251 0252 if ( !d->photo.isEmpty() ) { 0253 w.appendChild( textTag(doc, "TYPE", image2type(d->photo)) ); 0254 w.appendChild( textTag(doc, "BINVAL", foldString( QCA::Base64().arrayToString(d->photo)) ) ); 0255 } 0256 else if ( !d->photoURI.isEmpty() ) 0257 w.appendChild( textTag(doc, "EXTVAL", d->photoURI) ); 0258 0259 v.appendChild(w); 0260 } 0261 0262 if ( !d->bday.isEmpty() ) 0263 v.appendChild( textTag(doc, "BDAY", d->bday) ); 0264 0265 if ( !d->addressList.isEmpty() ) { 0266 AddressList::Iterator it = d->addressList.begin(); 0267 for ( ; it != d->addressList.end(); ++it ) { 0268 QDomElement w = doc->createElement("ADR"); 0269 Address a = *it; 0270 0271 if ( a.home ) 0272 w.appendChild( emptyTag(doc, "HOME") ); 0273 if ( a.work ) 0274 w.appendChild( emptyTag(doc, "WORK") ); 0275 if ( a.postal ) 0276 w.appendChild( emptyTag(doc, "POSTAL") ); 0277 if ( a.parcel ) 0278 w.appendChild( emptyTag(doc, "PARCEL") ); 0279 if ( a.dom ) 0280 w.appendChild( emptyTag(doc, "DOM") ); 0281 if ( a.intl ) 0282 w.appendChild( emptyTag(doc, "INTL") ); 0283 if ( a.pref ) 0284 w.appendChild( emptyTag(doc, "PREF") ); 0285 0286 if ( !a.pobox.isEmpty() ) 0287 w.appendChild( textTag(doc, "POBOX", a.pobox) ); 0288 if ( !a.extaddr.isEmpty() ) 0289 w.appendChild( textTag(doc, "EXTADR", a.extaddr) ); 0290 if ( !a.street.isEmpty() ) 0291 w.appendChild( textTag(doc, "STREET", a.street) ); 0292 if ( !a.locality.isEmpty() ) 0293 w.appendChild( textTag(doc, "LOCALITY", a.locality) ); 0294 if ( !a.region.isEmpty() ) 0295 w.appendChild( textTag(doc, "REGION", a.region) ); 0296 if ( !a.pcode.isEmpty() ) 0297 w.appendChild( textTag(doc, "PCODE", a.pcode) ); 0298 if ( !a.country.isEmpty() ) 0299 w.appendChild( textTag(doc, "CTRY", a.country) ); 0300 0301 v.appendChild(w); 0302 } 0303 } 0304 0305 if ( !d->labelList.isEmpty() ) { 0306 LabelList::Iterator it = d->labelList.begin(); 0307 for ( ; it != d->labelList.end(); ++it ) { 0308 QDomElement w = doc->createElement("LABEL"); 0309 Label l = *it; 0310 0311 if ( l.home ) 0312 w.appendChild( emptyTag(doc, "HOME") ); 0313 if ( l.work ) 0314 w.appendChild( emptyTag(doc, "WORK") ); 0315 if ( l.postal ) 0316 w.appendChild( emptyTag(doc, "POSTAL") ); 0317 if ( l.parcel ) 0318 w.appendChild( emptyTag(doc, "PARCEL") ); 0319 if ( l.dom ) 0320 w.appendChild( emptyTag(doc, "DOM") ); 0321 if ( l.intl ) 0322 w.appendChild( emptyTag(doc, "INTL") ); 0323 if ( l.pref ) 0324 w.appendChild( emptyTag(doc, "PREF") ); 0325 0326 if ( !l.lines.isEmpty() ) { 0327 QStringList::Iterator it = l.lines.begin(); 0328 for ( ; it != l.lines.end(); ++it ) 0329 w.appendChild( textTag(doc, "LINE", *it) ); 0330 } 0331 0332 v.appendChild(w); 0333 } 0334 } 0335 0336 if ( !d->phoneList.isEmpty() ) { 0337 PhoneList::Iterator it = d->phoneList.begin(); 0338 for ( ; it != d->phoneList.end(); ++it ) { 0339 QDomElement w = doc->createElement("TEL"); 0340 Phone p = *it; 0341 0342 if ( p.home ) 0343 w.appendChild( emptyTag(doc, "HOME") ); 0344 if ( p.work ) 0345 w.appendChild( emptyTag(doc, "WORK") ); 0346 if ( p.voice ) 0347 w.appendChild( emptyTag(doc, "VOICE") ); 0348 if ( p.fax ) 0349 w.appendChild( emptyTag(doc, "FAX") ); 0350 if ( p.pager ) 0351 w.appendChild( emptyTag(doc, "PAGER") ); 0352 if ( p.msg ) 0353 w.appendChild( emptyTag(doc, "MSG") ); 0354 if ( p.cell ) 0355 w.appendChild( emptyTag(doc, "CELL") ); 0356 if ( p.video ) 0357 w.appendChild( emptyTag(doc, "VIDEO") ); 0358 if ( p.bbs ) 0359 w.appendChild( emptyTag(doc, "BBS") ); 0360 if ( p.modem ) 0361 w.appendChild( emptyTag(doc, "MODEM") ); 0362 if ( p.isdn ) 0363 w.appendChild( emptyTag(doc, "ISDN") ); 0364 if ( p.pcs ) 0365 w.appendChild( emptyTag(doc, "PCS") ); 0366 if ( p.pref ) 0367 w.appendChild( emptyTag(doc, "PREF") ); 0368 0369 if ( !p.number.isEmpty() ) 0370 w.appendChild( textTag(doc, "NUMBER", p.number) ); 0371 0372 v.appendChild(w); 0373 } 0374 } 0375 0376 if ( !d->emailList.isEmpty() ) { 0377 EmailList::Iterator it = d->emailList.begin(); 0378 for ( ; it != d->emailList.end(); ++it ) { 0379 QDomElement w = doc->createElement("EMAIL"); 0380 Email e = *it; 0381 0382 if ( e.home ) 0383 w.appendChild( emptyTag(doc, "HOME") ); 0384 if ( e.work ) 0385 w.appendChild( emptyTag(doc, "WORK") ); 0386 if ( e.internet ) 0387 w.appendChild( emptyTag(doc, "INTERNET") ); 0388 if ( e.x400 ) 0389 w.appendChild( emptyTag(doc, "X400") ); 0390 0391 if ( !e.userid.isEmpty() ) 0392 w.appendChild( textTag(doc, "USERID", e.userid) ); 0393 0394 v.appendChild(w); 0395 } 0396 } 0397 0398 if ( !d->jid.isEmpty() ) 0399 v.appendChild( textTag(doc, "JABBERID", d->jid) ); 0400 if ( !d->mailer.isEmpty() ) 0401 v.appendChild( textTag(doc, "MAILER", d->mailer) ); 0402 if ( !d->timezone.isEmpty() ) 0403 v.appendChild( textTag(doc, "TZ", d->timezone) ); 0404 0405 if ( !d->geo.lat.isEmpty() || !d->geo.lon.isEmpty() ) { 0406 QDomElement w = doc->createElement("GEO"); 0407 0408 if ( !d->geo.lat.isEmpty() ) 0409 w.appendChild( textTag(doc, "LAT", d->geo.lat) ); 0410 if ( !d->geo.lon.isEmpty() ) 0411 w.appendChild( textTag(doc, "LON", d->geo.lon)); 0412 0413 v.appendChild(w); 0414 } 0415 0416 if ( !d->title.isEmpty() ) 0417 v.appendChild( textTag(doc, "TITLE", d->title) ); 0418 if ( !d->role.isEmpty() ) 0419 v.appendChild( textTag(doc, "ROLE", d->role) ); 0420 0421 if ( !d->logo.isEmpty() || !d->logoURI.isEmpty() ) { 0422 QDomElement w = doc->createElement("LOGO"); 0423 0424 if ( !d->logo.isEmpty() ) { 0425 w.appendChild( textTag(doc, "TYPE", image2type(d->logo)) ); 0426 w.appendChild( textTag(doc, "BINVAL", foldString( QCA::Base64().arrayToString(d->logo)) ) ); 0427 } 0428 else if ( !d->logoURI.isEmpty() ) 0429 w.appendChild( textTag(doc, "EXTVAL", d->logoURI) ); 0430 0431 v.appendChild(w); 0432 } 0433 0434 if ( !d->agentURI.isEmpty() || (d->agent && d->agent->isEmpty()) ) { 0435 QDomElement w = doc->createElement("AGENT"); 0436 0437 if ( d->agent && !d->agent->isEmpty() ) 0438 w.appendChild( d->agent->toXml(doc) ); 0439 else if ( !d->agentURI.isEmpty() ) 0440 w.appendChild( textTag(doc, "EXTVAL", d->agentURI) ); 0441 0442 v.appendChild(w); 0443 } 0444 0445 if ( !d->org.name.isEmpty() || !d->org.unit.isEmpty() ) { 0446 QDomElement w = doc->createElement("ORG"); 0447 0448 if ( !d->org.name.isEmpty() ) 0449 w.appendChild( textTag(doc, "ORGNAME", d->org.name) ); 0450 0451 if ( !d->org.unit.isEmpty() ) { 0452 QStringList::Iterator it = d->org.unit.begin(); 0453 for ( ; it != d->org.unit.end(); ++it ) 0454 w.appendChild( textTag(doc, "ORGUNIT", *it) ); 0455 } 0456 0457 v.appendChild(w); 0458 } 0459 0460 if ( !d->categories.isEmpty() ) { 0461 QDomElement w = doc->createElement("CATEGORIES"); 0462 0463 QStringList::Iterator it = d->categories.begin(); 0464 for ( ; it != d->categories.end(); ++it ) 0465 w.appendChild( textTag(doc, "KEYWORD", *it) ); 0466 0467 v.appendChild(w); 0468 } 0469 0470 if ( !d->note.isEmpty() ) 0471 v.appendChild( textTag(doc, "NOTE", d->note) ); 0472 if ( !d->prodId.isEmpty() ) 0473 v.appendChild( textTag(doc, "PRODID", d->prodId) ); 0474 if ( !d->rev.isEmpty() ) 0475 v.appendChild( textTag(doc, "REV", d->rev) ); 0476 if ( !d->sortString.isEmpty() ) 0477 v.appendChild( textTag(doc, "SORT-STRING", d->sortString) ); 0478 0479 if ( !d->sound.isEmpty() || !d->soundURI.isEmpty() || !d->soundPhonetic.isEmpty() ) { 0480 QDomElement w = doc->createElement("SOUND"); 0481 0482 if ( !d->sound.isEmpty() ) 0483 w.appendChild( textTag(doc, "BINVAL", foldString( QCA::Base64().arrayToString(d->sound)) ) ); 0484 else if ( !d->soundURI.isEmpty() ) 0485 w.appendChild( textTag(doc, "EXTVAL", d->soundURI) ); 0486 else if ( !d->soundPhonetic.isEmpty() ) 0487 w.appendChild( textTag(doc, "PHONETIC", d->soundPhonetic) ); 0488 0489 v.appendChild(w); 0490 } 0491 0492 if ( !d->uid.isEmpty() ) 0493 v.appendChild( textTag(doc, "UID", d->uid) ); 0494 if ( !d->url.isEmpty() ) 0495 v.appendChild( textTag(doc, "URL", d->url) ); 0496 if ( !d->desc.isEmpty() ) 0497 v.appendChild( textTag(doc, "DESC", d->desc) ); 0498 0499 if ( d->privacyClass != pcNone ) { 0500 QDomElement w = doc->createElement("CLASS"); 0501 0502 if ( d->privacyClass == pcPublic ) 0503 w.appendChild( emptyTag(doc, "PUBLIC") ); 0504 else if ( d->privacyClass == pcPrivate ) 0505 w.appendChild( emptyTag(doc, "PRIVATE") ); 0506 else if ( d->privacyClass == pcConfidential ) 0507 w.appendChild( emptyTag(doc, "CONFIDENTIAL") ); 0508 0509 v.appendChild(w); 0510 } 0511 0512 if ( !d->key.isEmpty() ) { 0513 QDomElement w = doc->createElement("KEY"); 0514 0515 // TODO: Justin, please check out this code 0516 w.appendChild( textTag(doc, "TYPE", "text/plain")); // FIXME 0517 w.appendChild( textTag(doc, "CRED", QString::fromUtf8(d->key)) ); // FIXME 0518 0519 v.appendChild(w); 0520 } 0521 0522 return v; 0523 } 0524 0525 bool VCard::fromXml(const QDomElement &q) 0526 { 0527 if ( q.tagName().toUpper() != "VCARD" ) 0528 return false; 0529 0530 QDomNode n = q.firstChild(); 0531 for ( ; !n.isNull(); n = n.nextSibling() ) { 0532 QDomElement i = n.toElement(); 0533 if ( i.isNull() ) 0534 continue; 0535 0536 QString tag = i.tagName().toUpper(); 0537 0538 bool found; 0539 QDomElement e; 0540 0541 if ( tag == "VERSION" ) 0542 d->version = i.text().trimmed(); 0543 else if ( tag == "FN" ) 0544 d->fullName = i.text().trimmed(); 0545 else if ( tag == "N" ) { 0546 d->familyName = subTagText(i, "FAMILY"); 0547 d->givenName = subTagText(i, "GIVEN"); 0548 d->middleName = subTagText(i, "MIDDLE"); 0549 d->prefixName = subTagText(i, "PREFIX"); 0550 d->suffixName = subTagText(i, "SUFFIX"); 0551 } 0552 else if ( tag == "NICKNAME" ) 0553 d->nickName = i.text().trimmed(); 0554 else if ( tag == "PHOTO" ) { 0555 d->photo = QCA::Base64().stringToArray(subTagText(i, "BINVAL").replace("\n","")).toByteArray(); 0556 d->photoURI = subTagText(i, "EXTVAL"); 0557 } 0558 else if ( tag == "BDAY" ) 0559 d->bday = i.text().trimmed(); 0560 else if ( tag == "ADR" ) { 0561 Address a; 0562 0563 a.home = hasSubTag(i, "HOME"); 0564 a.work = hasSubTag(i, "WORK"); 0565 a.postal = hasSubTag(i, "POSTAL"); 0566 a.parcel = hasSubTag(i, "PARCEL"); 0567 a.dom = hasSubTag(i, "DOM"); 0568 a.intl = hasSubTag(i, "INTL"); 0569 a.pref = hasSubTag(i, "PREF"); 0570 0571 a.pobox = subTagText(i, "POBOX"); 0572 a.extaddr = subTagText(i, "EXTADR"); 0573 a.street = subTagText(i, "STREET"); 0574 a.locality = subTagText(i, "LOCALITY"); 0575 a.region = subTagText(i, "REGION"); 0576 a.pcode = subTagText(i, "PCODE"); 0577 a.country = subTagText(i, "CTRY"); 0578 0579 if ( a.country.isEmpty() ) // FIXME: Workaround for Psi prior to 0.9 0580 if ( hasSubTag(i, "COUNTRY") ) 0581 a.country = subTagText(i, "COUNTRY"); 0582 0583 if ( a.extaddr.isEmpty() ) // FIXME: Workaround for Psi prior to 0.9 0584 if ( hasSubTag(i, "EXTADD") ) 0585 a.extaddr = subTagText(i, "EXTADD"); 0586 0587 d->addressList.append ( a ); 0588 } 0589 else if ( tag == "LABEL" ) { 0590 Label l; 0591 0592 l.home = hasSubTag(i, "HOME"); 0593 l.work = hasSubTag(i, "WORK"); 0594 l.postal = hasSubTag(i, "POSTAL"); 0595 l.parcel = hasSubTag(i, "PARCEL"); 0596 l.dom = hasSubTag(i, "DOM"); 0597 l.intl = hasSubTag(i, "INTL"); 0598 l.pref = hasSubTag(i, "PREF"); 0599 0600 QDomNode nn = i.firstChild(); 0601 for ( ; !nn.isNull(); nn = nn.nextSibling() ) { 0602 QDomElement ii = nn.toElement(); 0603 if ( ii.isNull() ) 0604 continue; 0605 0606 if ( ii.tagName().toUpper() == "LINE" ) 0607 l.lines.append ( ii.text().trimmed() ); 0608 } 0609 0610 d->labelList.append ( l ); 0611 } 0612 else if ( tag == "TEL" ) { 0613 Phone p; 0614 0615 p.home = hasSubTag(i, "HOME"); 0616 p.work = hasSubTag(i, "WORK"); 0617 p.voice = hasSubTag(i, "VOICE"); 0618 p.fax = hasSubTag(i, "FAX"); 0619 p.pager = hasSubTag(i, "PAGER"); 0620 p.msg = hasSubTag(i, "MSG"); 0621 p.cell = hasSubTag(i, "CELL"); 0622 p.video = hasSubTag(i, "VIDEO"); 0623 p.bbs = hasSubTag(i, "BBS"); 0624 p.modem = hasSubTag(i, "MODEM"); 0625 p.isdn = hasSubTag(i, "ISDN"); 0626 p.pcs = hasSubTag(i, "PCS"); 0627 p.pref = hasSubTag(i, "PREF"); 0628 0629 p.number = subTagText(i, "NUMBER"); 0630 0631 if ( p.number.isEmpty() ) // FIXME: Workaround for Psi prior to 0.9 0632 if ( hasSubTag(i, "VOICE") ) 0633 p.number = subTagText(i, "VOICE"); 0634 0635 d->phoneList.append ( p ); 0636 } 0637 else if ( tag == "EMAIL" ) { 0638 Email m; 0639 0640 m.home = hasSubTag(i, "HOME"); 0641 m.work = hasSubTag(i, "WORK"); 0642 m.internet = hasSubTag(i, "INTERNET"); 0643 m.x400 = hasSubTag(i, "X400"); 0644 0645 m.userid = subTagText(i, "USERID"); 0646 0647 if ( m.userid.isEmpty() ) // FIXME: Workaround for Psi prior to 0.9 0648 if ( !i.text().isEmpty() ) 0649 m.userid = i.text().trimmed(); 0650 0651 d->emailList.append ( m ); 0652 } 0653 else if ( tag == "JABBERID" ) 0654 d->jid = i.text().trimmed(); 0655 else if ( tag == "MAILER" ) 0656 d->mailer = i.text().trimmed(); 0657 else if ( tag == "TZ" ) 0658 d->timezone = i.text().trimmed(); 0659 else if ( tag == "GEO" ) { 0660 d->geo.lat = subTagText(i, "LAT"); 0661 d->geo.lon = subTagText(i, "LON"); 0662 } 0663 else if ( tag == "TITLE" ) 0664 d->title = i.text().trimmed(); 0665 else if ( tag == "ROLE" ) 0666 d->role = i.text().trimmed(); 0667 else if ( tag == "LOGO" ) { 0668 d->logo = QCA::Base64().stringToArray( subTagText(i, "BINVAL").replace("\n","") ).toByteArray(); 0669 d->logoURI = subTagText(i, "EXTVAL"); 0670 } 0671 else if ( tag == "AGENT" ) { 0672 e = findSubTag(i, "VCARD", &found); 0673 if ( found ) { 0674 VCard a; 0675 if ( a.fromXml(e) ) { 0676 if ( !d->agent ) 0677 d->agent = new VCard; 0678 *(d->agent) = a; 0679 } 0680 } 0681 0682 d->agentURI = subTagText(i, "EXTVAL"); 0683 } 0684 else if ( tag == "ORG" ) { 0685 d->org.name = subTagText(i, "ORGNAME"); 0686 0687 QDomNode nn = i.firstChild(); 0688 for ( ; !nn.isNull(); nn = nn.nextSibling() ) { 0689 QDomElement ii = nn.toElement(); 0690 if ( ii.isNull() ) 0691 continue; 0692 0693 if ( ii.tagName().toUpper() == "ORGUNIT" ) 0694 d->org.unit.append( ii.text().trimmed() ); 0695 } 0696 } 0697 else if ( tag == "CATEGORIES") { 0698 QDomNode nn = i.firstChild(); 0699 for ( ; !nn.isNull(); nn = nn.nextSibling() ) { 0700 QDomElement ee = nn.toElement(); 0701 if ( ee.isNull() ) 0702 continue; 0703 0704 if ( ee.tagName().toUpper() == "KEYWORD" ) 0705 d->categories << ee.text().trimmed(); 0706 } 0707 } 0708 else if ( tag == "NOTE" ) 0709 d->note = i.text().trimmed(); 0710 else if ( tag == "PRODID" ) 0711 d->prodId = i.text().trimmed(); 0712 else if ( tag == "REV" ) 0713 d->rev = i.text().trimmed(); 0714 else if ( tag == "SORT-STRING" ) 0715 d->sortString = i.text().trimmed(); 0716 else if ( tag == "SOUND" ) { 0717 d->sound = QCA::Base64().stringToArray( subTagText(i, "BINVAL").replace("\n","") ).toByteArray(); 0718 d->soundURI = subTagText(i, "EXTVAL"); 0719 d->soundPhonetic = subTagText(i, "PHONETIC"); 0720 } 0721 else if ( tag == "UID" ) 0722 d->uid = i.text().trimmed(); 0723 else if ( tag == "URL") 0724 d->url = i.text().trimmed(); 0725 else if ( tag == "DESC" ) 0726 d->desc = i.text().trimmed(); 0727 else if ( tag == "CLASS" ) { 0728 if ( hasSubTag(i, "PUBLIC") ) 0729 d->privacyClass = pcPublic; 0730 else if ( hasSubTag(i, "PRIVATE") ) 0731 d->privacyClass = pcPrivate; 0732 else if ( hasSubTag(i, "CONFIDENTIAL") ) 0733 d->privacyClass = pcConfidential; 0734 } 0735 else if ( tag == "KEY" ) { 0736 // TODO: Justin, please check out this code 0737 e = findSubTag(i, "TYPE", &found); 0738 QString type = "text/plain"; 0739 if ( found ) 0740 type = e.text().trimmed(); 0741 0742 e = findSubTag(i, "CRED", &found ); 0743 if ( !found ) 0744 e = findSubTag(i, "BINVAL", &found); // case for very clever clients ;-) 0745 0746 if ( found ) 0747 d->key = e.text().toUtf8(); // FIXME 0748 } 0749 } 0750 0751 return true; 0752 } 0753 0754 bool VCard::isEmpty() const 0755 { 0756 return d->isEmpty(); 0757 } 0758 0759 // Some constructors 0760 0761 VCard::Address::Address() 0762 { 0763 home = work = postal = parcel = dom = intl = pref = false; 0764 } 0765 0766 VCard::Label::Label() 0767 { 0768 home = work = postal = parcel = dom = intl = pref = false; 0769 } 0770 0771 VCard::Phone::Phone() 0772 { 0773 home = work = voice = fax = pager = msg = cell = video = bbs = modem = isdn = pcs = pref = false; 0774 } 0775 0776 VCard::Email::Email() 0777 { 0778 home = work = internet = x400 = false; 0779 } 0780 0781 VCard::Geo::Geo() 0782 { 0783 } 0784 0785 VCard::Org::Org() 0786 { 0787 } 0788 0789 // vCard properties... 0790 0791 const QString &VCard::version() const 0792 { 0793 return d->version; 0794 } 0795 0796 void VCard::setVersion(const QString &v) 0797 { 0798 d->version = v; 0799 } 0800 0801 const QString &VCard::fullName() const 0802 { 0803 return d->fullName; 0804 } 0805 0806 void VCard::setFullName(const QString &n) 0807 { 0808 d->fullName = n; 0809 } 0810 0811 const QString &VCard::familyName() const 0812 { 0813 return d->familyName; 0814 } 0815 0816 void VCard::setFamilyName(const QString &n) 0817 { 0818 d->familyName = n; 0819 } 0820 0821 const QString &VCard::givenName() const 0822 { 0823 return d->givenName; 0824 } 0825 0826 void VCard::setGivenName(const QString &n) 0827 { 0828 d->givenName = n; 0829 } 0830 0831 const QString &VCard::middleName() const 0832 { 0833 return d->middleName; 0834 } 0835 0836 void VCard::setMiddleName(const QString &n) 0837 { 0838 d->middleName = n; 0839 } 0840 0841 const QString &VCard::prefixName() const 0842 { 0843 return d->prefixName; 0844 } 0845 0846 void VCard::setPrefixName(const QString &p) 0847 { 0848 d->prefixName = p; 0849 } 0850 0851 const QString &VCard::suffixName() const 0852 { 0853 return d->suffixName; 0854 } 0855 0856 void VCard::setSuffixName(const QString &s) 0857 { 0858 d->suffixName = s; 0859 } 0860 0861 const QString &VCard::nickName() const 0862 { 0863 return d->nickName; 0864 } 0865 0866 void VCard::setNickName(const QString &n) 0867 { 0868 d->nickName = n; 0869 } 0870 0871 const QByteArray &VCard::photo() const 0872 { 0873 return d->photo; 0874 } 0875 0876 void VCard::setPhoto(const QByteArray &i) 0877 { 0878 d->photo = i; 0879 } 0880 0881 const QString &VCard::photoURI() const 0882 { 0883 return d->photoURI; 0884 } 0885 0886 void VCard::setPhotoURI(const QString &p) 0887 { 0888 d->photoURI = p; 0889 } 0890 0891 const QDate VCard::bday() const 0892 { 0893 return QDate::fromString(d->bday); 0894 } 0895 0896 void VCard::setBday(const QDate &date) 0897 { 0898 d->bday = date.toString(); 0899 } 0900 0901 const QString &VCard::bdayStr() const 0902 { 0903 return d->bday; 0904 } 0905 0906 void VCard::setBdayStr(const QString &date) 0907 { 0908 d->bday = date; 0909 } 0910 0911 const VCard::AddressList &VCard::addressList() const 0912 { 0913 return d->addressList; 0914 } 0915 0916 void VCard::setAddressList(const VCard::AddressList &a) 0917 { 0918 d->addressList = a; 0919 } 0920 0921 const VCard::LabelList &VCard::labelList() const 0922 { 0923 return d->labelList; 0924 } 0925 0926 void VCard::setLabelList(const VCard::LabelList &l) 0927 { 0928 d->labelList = l; 0929 } 0930 0931 const VCard::PhoneList &VCard::phoneList() const 0932 { 0933 return d->phoneList; 0934 } 0935 0936 void VCard::setPhoneList(const VCard::PhoneList &p) 0937 { 0938 d->phoneList = p; 0939 } 0940 0941 const VCard::EmailList &VCard::emailList() const 0942 { 0943 return d->emailList; 0944 } 0945 0946 void VCard::setEmailList(const VCard::EmailList &e) 0947 { 0948 d->emailList = e; 0949 } 0950 0951 const QString &VCard::jid() const 0952 { 0953 return d->jid; 0954 } 0955 0956 void VCard::setJid(const QString &j) 0957 { 0958 d->jid = j; 0959 } 0960 0961 const QString &VCard::mailer() const 0962 { 0963 return d->mailer; 0964 } 0965 0966 void VCard::setMailer(const QString &m) 0967 { 0968 d->mailer = m; 0969 } 0970 0971 const QString &VCard::timezone() const 0972 { 0973 return d->timezone; 0974 } 0975 0976 void VCard::setTimezone(const QString &t) 0977 { 0978 d->timezone = t; 0979 } 0980 0981 const VCard::Geo &VCard::geo() const 0982 { 0983 return d->geo; 0984 } 0985 0986 void VCard::setGeo(const VCard::Geo &g) 0987 { 0988 d->geo = g; 0989 } 0990 0991 const QString &VCard::title() const 0992 { 0993 return d->title; 0994 } 0995 0996 void VCard::setTitle(const QString &t) 0997 { 0998 d->title = t; 0999 } 1000 1001 const QString &VCard::role() const 1002 { 1003 return d->role; 1004 } 1005 1006 void VCard::setRole(const QString &r) 1007 { 1008 d->role = r; 1009 } 1010 1011 const QByteArray &VCard::logo() const 1012 { 1013 return d->logo; 1014 } 1015 1016 void VCard::setLogo(const QByteArray &i) 1017 { 1018 d->logo = i; 1019 } 1020 1021 const QString &VCard::logoURI() const 1022 { 1023 return d->logoURI; 1024 } 1025 1026 void VCard::setLogoURI(const QString &l) 1027 { 1028 d->logoURI = l; 1029 } 1030 1031 const VCard *VCard::agent() const 1032 { 1033 return d->agent; 1034 } 1035 1036 void VCard::setAgent(const VCard &v) 1037 { 1038 if ( !d->agent ) 1039 d->agent = new VCard; 1040 *(d->agent) = v; 1041 } 1042 1043 const QString VCard::agentURI() const 1044 { 1045 return d->agentURI; 1046 } 1047 1048 void VCard::setAgentURI(const QString &a) 1049 { 1050 d->agentURI = a; 1051 } 1052 1053 const VCard::Org &VCard::org() const 1054 { 1055 return d->org; 1056 } 1057 1058 void VCard::setOrg(const VCard::Org &o) 1059 { 1060 d->org = o; 1061 } 1062 1063 const QStringList &VCard::categories() const 1064 { 1065 return d->categories; 1066 } 1067 1068 void VCard::setCategories(const QStringList &c) 1069 { 1070 d->categories = c; 1071 } 1072 1073 const QString &VCard::note() const 1074 { 1075 return d->note; 1076 } 1077 1078 void VCard::setNote(const QString &n) 1079 { 1080 d->note = n; 1081 } 1082 1083 const QString &VCard::prodId() const 1084 { 1085 return d->prodId; 1086 } 1087 1088 void VCard::setProdId(const QString &p) 1089 { 1090 d->prodId = p; 1091 } 1092 1093 const QString &VCard::rev() const 1094 { 1095 return d->rev; 1096 } 1097 1098 void VCard::setRev(const QString &r) 1099 { 1100 d->rev = r; 1101 } 1102 1103 const QString &VCard::sortString() const 1104 { 1105 return d->sortString; 1106 } 1107 1108 void VCard::setSortString(const QString &s) 1109 { 1110 d->sortString = s; 1111 } 1112 1113 const QByteArray &VCard::sound() const 1114 { 1115 return d->sound; 1116 } 1117 1118 void VCard::setSound(const QByteArray &s) 1119 { 1120 d->sound = s; 1121 } 1122 1123 const QString &VCard::soundURI() const 1124 { 1125 return d->soundURI; 1126 } 1127 1128 void VCard::setSoundURI(const QString &s) 1129 { 1130 d->soundURI = s; 1131 } 1132 1133 const QString &VCard::soundPhonetic() const 1134 { 1135 return d->soundPhonetic; 1136 } 1137 1138 void VCard::setSoundPhonetic(const QString &s) 1139 { 1140 d->soundPhonetic = s; 1141 } 1142 1143 const QString &VCard::uid() const 1144 { 1145 return d->uid; 1146 } 1147 1148 void VCard::setUid(const QString &u) 1149 { 1150 d->uid = u; 1151 } 1152 1153 const QString &VCard::url() const 1154 { 1155 return d->url; 1156 } 1157 1158 void VCard::setUrl(const QString &u) 1159 { 1160 d->url = u; 1161 } 1162 1163 const QString &VCard::desc() const 1164 { 1165 return d->desc; 1166 } 1167 1168 void VCard::setDesc(const QString &desc) 1169 { 1170 d->desc = desc; 1171 } 1172 1173 const VCard::PrivacyClass &VCard::privacyClass() const 1174 { 1175 return d->privacyClass; 1176 } 1177 1178 void VCard::setPrivacyClass(const VCard::PrivacyClass &c) 1179 { 1180 d->privacyClass = c; 1181 } 1182 1183 const QByteArray &VCard::key() const 1184 { 1185 return d->key; 1186 } 1187 1188 void VCard::setKey(const QByteArray &k) 1189 { 1190 d->key = k; 1191 }