/*
 * xmpp_vcard.cpp - classes for handling vCards
 * Copyright (C) 2003  Michail Pishchagin
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */

#include "xmpp_vcard.h"

#include "base64.h"

#include <tqdom.h>
#include <tqdatetime.h>

#include <tqimage.h> // needed for image format recognition
#include <tqbuffer.h>

// Justin's XML helper functions

static TQDomElement textTag(TQDomDocument *doc, const TQString &name, const TQString &content)
{
	TQDomElement tag = doc->createElement(name);
	TQDomText text = doc->createTextNode(content);
	tag.appendChild(text);

	return tag;
}

static TQDomElement findSubTag(const TQDomElement &e, const TQString &name, bool *found)
{
	if(found)
		*found = FALSE;

	for(TQDomNode n = e.firstChild(); !n.isNull(); n = n.nextSibling()) {
		TQDomElement i = n.toElement();
		if(i.isNull())
			continue;
		if(i.tagName().upper() == name.upper()) { // mblsha: ignore case when searching
			if(found)
				*found = TRUE;
			return i;
		}
	}

	TQDomElement tmp;
	return tmp;
}

// mblsha's own functions

static TQDomElement emptyTag(TQDomDocument *doc, const TQString &name)
{
	TQDomElement tag = doc->createElement(name);

	return tag;
}

static bool hasSubTag(const TQDomElement &e, const TQString &name)
{
	bool found;
	findSubTag(e, name, &found);
	return found;
}

static TQString subTagText(const TQDomElement &e, const TQString &name)
{
	bool found;
	TQDomElement i = findSubTag(e, name, &found);
	if ( found )
		return i.text().stripWhiteSpace();
	return TQString();
}

using namespace XMPP;

//----------------------------------------------------------------------------
// VCard
//----------------------------------------------------------------------------
static TQString image2type(const TQByteArray &ba)
{
	TQBuffer buf(ba);
	buf.open(IO_ReadOnly);
	TQString format = TQImageIO::imageFormat( TQT_TQIODEVICE(&buf) );

	// TODO: add more formats
	if ( format == "PNG" || format == "PsiPNG" )
		return "image/png";
	if ( format == "MNG" )
		return "video/x-mng";
	if ( format == "GIF" )
		return "image/gif";
	if ( format == "BMP" )
		return "image/bmp";
	if ( format == "XPM" )
		return "image/x-xpm";
	if ( format == "SVG" )
		return "image/svg+xml";
	if ( format == "JPEG" )
		return "image/jpeg";

	tqWarning("WARNING! VCard::image2type: unknown format = '%s'", format.latin1());

	return "image/unknown";
}

// Long lines of encoded binary data SHOULD BE folded to 75 characters using the folding method defined in [MIME-DIR].
static TQString foldString(const TQString &s)
{
	TQString ret;

	for (int i = 0; i < (int)s.length(); i++) {
		if ( !(i % 75) )
			ret += '\n';
		ret += s[i];
	}

	return ret;
}

class VCard::Private
{
public:
	Private();
	~Private();

	TQString version;
	TQString fullName;
	TQString familyName, givenName, middleName, prefixName, suffixName;
	TQString nickName;

	TQByteArray photo;
	TQString photoURI;

	TQString bday;
	AddressList addressList;
	LabelList labelList;
	PhoneList phoneList;
	EmailList emailList;
	TQString jid;
	TQString mailer;
	TQString timezone;
	Geo geo;
	TQString title;
	TQString role;

	TQByteArray logo;
	TQString logoURI;

	VCard *agent;
	TQString agentURI;

	Org org;
	TQStringList categories;
	TQString note;
	TQString prodId;
	TQString rev;
	TQString sortString;

	TQByteArray sound;
	TQString soundURI, soundPhonetic;

	TQString uid;
	TQString url;
	TQString desc;
	PrivacyClass privacyClass;
	TQByteArray key;

	bool isEmpty();
};

VCard::Private::Private()
{
	privacyClass = pcNone;
	agent = 0;
}

VCard::Private::~Private()
{
	delete agent;
}

bool VCard::Private::isEmpty()
{
	if (	!version.isEmpty() ||
		!fullName.isEmpty() ||
		!familyName.isEmpty() || !givenName.isEmpty() || !middleName.isEmpty() || !prefixName.isEmpty() || !suffixName.isEmpty() ||
		!nickName.isEmpty() ||
		!photo.isEmpty() || !photoURI.isEmpty() ||
		!bday.isEmpty() ||
		!addressList.isEmpty() ||
		!labelList.isEmpty() ||
		!phoneList.isEmpty() ||
		!emailList.isEmpty() ||
		!jid.isEmpty() ||
		!mailer.isEmpty() ||
		!timezone.isEmpty() ||
		!geo.lat.isEmpty() || !geo.lon.isEmpty() ||
		!title.isEmpty() ||
		!role.isEmpty() ||
		!logo.isEmpty() || !logoURI.isEmpty() ||
		(agent && !agent->isEmpty()) || !agentURI.isEmpty() ||
		!org.name.isEmpty() || !org.unit.isEmpty() ||
		!categories.isEmpty() ||
		!note.isEmpty() ||
		!prodId.isEmpty() ||
		!rev.isEmpty() ||
		!sortString.isEmpty() ||
		!sound.isEmpty() || !soundURI.isEmpty() || !soundPhonetic.isEmpty() ||
		!uid.isEmpty() ||
		!url.isEmpty() ||
		!desc.isEmpty() ||
		(privacyClass != pcNone) ||
		!key.isEmpty() )
	{
		return false;
	}
	return true;
}

VCard::VCard()
{
	d = new Private;
}

VCard::VCard(const VCard &from)
{
	d = new Private;
	*this = from;
}

VCard & VCard::operator=(const VCard &from)
{
	if(d->agent) {
		delete d->agent;
		d->agent = 0;
	}

	*d = *from.d;

	if(from.d->agent) {
		// dup the agent
		d->agent = new VCard(*from.d->agent);
	}

	return *this;
}

VCard::~VCard()
{
	delete d;
}

TQDomElement VCard::toXml(TQDomDocument *doc) const
{
	TQDomElement v = doc->createElement("vCard");
	v.setAttribute("version", "2.0");
	v.setAttribute("prodid", "-//HandGen//NONSGML vGen v1.0//EN");
	v.setAttribute("xmlns", "vcard-temp");

	if ( !d->version.isEmpty() )
		v.appendChild( textTag(doc, "VERSION",	d->version) );
	if ( !d->fullName.isEmpty() )
		v.appendChild( textTag(doc, "FN",	d->fullName) );

	if ( !d->familyName.isEmpty() || !d->givenName.isEmpty() || !d->middleName.isEmpty() ||
	     !d->prefixName.isEmpty() || !d->suffixName.isEmpty() ) {
		TQDomElement w = doc->createElement("N");

		if ( !d->familyName.isEmpty() )
			w.appendChild( textTag(doc, "FAMILY",	d->familyName) );
		if ( !d->givenName.isEmpty() )
			w.appendChild( textTag(doc, "GIVEN",	d->givenName) );
		if ( !d->middleName.isEmpty() )
			w.appendChild( textTag(doc, "MIDDLE",	d->middleName) );
		if ( !d->prefixName.isEmpty() )
			w.appendChild( textTag(doc, "PREFIX",	d->prefixName) );
		if ( !d->suffixName.isEmpty() )
			w.appendChild( textTag(doc, "SUFFIX",	d->suffixName) );

		v.appendChild(w);
	}

	if ( !d->nickName.isEmpty() )
		v.appendChild( textTag(doc, "NICKNAME",	d->nickName) );

	if ( !d->photo.isEmpty() || !d->photoURI.isEmpty() ) {
		TQDomElement w = doc->createElement("PHOTO");

		if ( !d->photo.isEmpty() ) {
			w.appendChild( textTag(doc, "TYPE",	image2type(d->photo)) );
			w.appendChild( textTag(doc, "BINVAL",	foldString( Base64::arrayToString(d->photo)) ) );
		}
		else if ( !d->photoURI.isEmpty() )
			w.appendChild( textTag(doc, "EXTVAL",	d->photoURI) );

		v.appendChild(w);
	}

	if ( !d->bday.isEmpty() )
		v.appendChild( textTag(doc, "BDAY",	d->bday) );

	if ( !d->addressList.isEmpty() ) {
		AddressList::Iterator it = d->addressList.begin();
		for ( ; it != d->addressList.end(); ++it ) {
			TQDomElement w = doc->createElement("ADR");
			Address a = *it;

			if ( a.home )
				w.appendChild( emptyTag(doc, "HOME") );
			if ( a.work )
				w.appendChild( emptyTag(doc, "WORK") );
			if ( a.postal )
				w.appendChild( emptyTag(doc, "POSTAL") );
			if ( a.parcel )
				w.appendChild( emptyTag(doc, "PARCEL") );
			if ( a.dom )
				w.appendChild( emptyTag(doc, "DOM") );
			if ( a.intl )
				w.appendChild( emptyTag(doc, "INTL") );
			if ( a.pref )
				w.appendChild( emptyTag(doc, "PREF") );

			if ( !a.pobox.isEmpty() )
				w.appendChild( textTag(doc, "POBOX",	a.pobox) );
			if ( !a.extaddr.isEmpty() )
				w.appendChild( textTag(doc, "EXTADR",	a.extaddr) );
			if ( !a.street.isEmpty() )
				w.appendChild( textTag(doc, "STREET",	a.street) );
			if ( !a.locality.isEmpty() )
				w.appendChild( textTag(doc, "LOCALITY",	a.locality) );
			if ( !a.region.isEmpty() )
				w.appendChild( textTag(doc, "REGION",	a.region) );
			if ( !a.pcode.isEmpty() )
				w.appendChild( textTag(doc, "PCODE",	a.pcode) );
			if ( !a.country.isEmpty() )
				w.appendChild( textTag(doc, "CTRY",	a.country) );

			v.appendChild(w);
		}
	}

	if ( !d->labelList.isEmpty() ) {
		LabelList::Iterator it = d->labelList.begin();
		for ( ; it != d->labelList.end(); ++it ) {
			TQDomElement w = doc->createElement("LABEL");
			Label l = *it;

			if ( l.home )
				w.appendChild( emptyTag(doc, "HOME") );
			if ( l.work )
				w.appendChild( emptyTag(doc, "WORK") );
			if ( l.postal )
				w.appendChild( emptyTag(doc, "POSTAL") );
			if ( l.parcel )
				w.appendChild( emptyTag(doc, "PARCEL") );
			if ( l.dom )
				w.appendChild( emptyTag(doc, "DOM") );
			if ( l.intl )
				w.appendChild( emptyTag(doc, "INTL") );
			if ( l.pref )
				w.appendChild( emptyTag(doc, "PREF") );

			if ( !l.lines.isEmpty() ) {
				TQStringList::Iterator it = l.lines.begin();
				for ( ; it != l.lines.end(); ++it )
					w.appendChild( textTag(doc, "LINE", *it) );
			}

			v.appendChild(w);
		}
	}

	if ( !d->phoneList.isEmpty() ) {
		PhoneList::Iterator it = d->phoneList.begin();
		for ( ; it != d->phoneList.end(); ++it ) {
			TQDomElement w = doc->createElement("TEL");
			Phone p = *it;

			if ( p.home )
				w.appendChild( emptyTag(doc, "HOME") );
			if ( p.work )
				w.appendChild( emptyTag(doc, "WORK") );
			if ( p.voice )
				w.appendChild( emptyTag(doc, "VOICE") );
			if ( p.fax )
				w.appendChild( emptyTag(doc, "FAX") );
			if ( p.pager )
				w.appendChild( emptyTag(doc, "PAGER") );
			if ( p.msg )
				w.appendChild( emptyTag(doc, "MSG") );
			if ( p.cell )
				w.appendChild( emptyTag(doc, "CELL") );
			if ( p.video )
				w.appendChild( emptyTag(doc, "VIDEO") );
			if ( p.bbs )
				w.appendChild( emptyTag(doc, "BBS") );
			if ( p.modem )
				w.appendChild( emptyTag(doc, "MODEM") );
			if ( p.isdn )
				w.appendChild( emptyTag(doc, "ISDN") );
			if ( p.pcs )
				w.appendChild( emptyTag(doc, "PCS") );
			if ( p.pref )
				w.appendChild( emptyTag(doc, "PREF") );

			if ( !p.number.isEmpty() )
				w.appendChild( textTag(doc, "NUMBER",	p.number) );

			v.appendChild(w);
		}
	}

	if ( !d->emailList.isEmpty() ) {
		EmailList::Iterator it = d->emailList.begin();
		for ( ; it != d->emailList.end(); ++it ) {
			TQDomElement w = doc->createElement("EMAIL");
			Email e = *it;

			if ( e.home )
				w.appendChild( emptyTag(doc, "HOME") );
			if ( e.work )
				w.appendChild( emptyTag(doc, "WORK") );
			if ( e.internet )
				w.appendChild( emptyTag(doc, "INTERNET") );
			if ( e.x400 )
				w.appendChild( emptyTag(doc, "X400") );

			if ( !e.userid.isEmpty() )
				w.appendChild( textTag(doc, "USERID",	e.userid) );

			v.appendChild(w);
		}
	}

	if ( !d->jid.isEmpty() )
		v.appendChild( textTag(doc, "JABBERID",	d->jid) );
	if ( !d->mailer.isEmpty() )
		v.appendChild( textTag(doc, "MAILER",	d->mailer) );
	if ( !d->timezone.isEmpty() )
		v.appendChild( textTag(doc, "TZ",	d->timezone) );

	if ( !d->geo.lat.isEmpty() || !d->geo.lon.isEmpty() ) {
		TQDomElement w = doc->createElement("GEO");

		if ( !d->geo.lat.isEmpty() )
			w.appendChild( textTag(doc, "LAT",	d->geo.lat) );
		if ( !d->geo.lon.isEmpty() )
			w.appendChild( textTag(doc, "LON",	d->geo.lon));

		v.appendChild(w);
	}

	if ( !d->title.isEmpty() )
		v.appendChild( textTag(doc, "TITLE",	d->title) );
	if ( !d->role.isEmpty() )
		v.appendChild( textTag(doc, "ROLE",	d->role) );

	if ( !d->logo.isEmpty() || !d->logoURI.isEmpty() ) {
		TQDomElement w = doc->createElement("LOGO");

		if ( !d->logo.isEmpty() ) {
			w.appendChild( textTag(doc, "TYPE",	image2type(d->logo)) );
			w.appendChild( textTag(doc, "BINVAL",	foldString( Base64::arrayToString(d->logo)) ) );
		}
		else if ( !d->logoURI.isEmpty() )
			w.appendChild( textTag(doc, "EXTVAL",	d->logoURI) );

		v.appendChild(w);
	}

	if ( !d->agentURI.isEmpty() || (d->agent && d->agent->isEmpty()) ) {
		TQDomElement w = doc->createElement("AGENT");

		if ( d->agent && !d->agent->isEmpty() )
			w.appendChild( d->agent->toXml(doc) );
		else if ( !d->agentURI.isEmpty() )
			w.appendChild( textTag(doc, "EXTVAL",	d->agentURI) );

		v.appendChild(w);
	}

	if ( !d->org.name.isEmpty() || !d->org.unit.isEmpty() ) {
		TQDomElement w = doc->createElement("ORG");

		if ( !d->org.name.isEmpty() )
			w.appendChild( textTag(doc, "ORGNAME",	d->org.name) );

		if ( !d->org.unit.isEmpty() ) {
			TQStringList::Iterator it = d->org.unit.begin();
			for ( ; it != d->org.unit.end(); ++it )
				w.appendChild( textTag(doc, "ORGUNIT",	*it) );
		}

		v.appendChild(w);
	}

	if ( !d->categories.isEmpty() ) {
		TQDomElement w = doc->createElement("CATEGORIES");

		TQStringList::Iterator it = d->categories.begin();
		for ( ; it != d->categories.end(); ++it )
			w.appendChild( textTag(doc, "KEYWORD", *it) );

		v.appendChild(w);
	}

	if ( !d->note.isEmpty() )
		v.appendChild( textTag(doc, "NOTE",	d->note) );
	if ( !d->prodId.isEmpty() )
		v.appendChild( textTag(doc, "PRODID",	d->prodId) );
	if ( !d->rev.isEmpty() )
		v.appendChild( textTag(doc, "REV",	d->rev) );
	if ( !d->sortString.isEmpty() )
		v.appendChild( textTag(doc, "SORT-STRING",	d->sortString) );

	if ( !d->sound.isEmpty() || !d->soundURI.isEmpty() || !d->soundPhonetic.isEmpty() ) {
		TQDomElement w = doc->createElement("SOUND");

		if ( !d->sound.isEmpty() )
			w.appendChild( textTag(doc, "BINVAL",	foldString( Base64::arrayToString(d->sound)) ) );
		else if ( !d->soundURI.isEmpty() )
			w.appendChild( textTag(doc, "EXTVAL",	d->soundURI) );
		else if ( !d->soundPhonetic.isEmpty() )
			w.appendChild( textTag(doc, "PHONETIC",	d->soundPhonetic) );

		v.appendChild(w);
	}

	if ( !d->uid.isEmpty() )
		v.appendChild( textTag(doc, "UID",	d->uid) );
	if ( !d->url.isEmpty() )
		v.appendChild( textTag(doc, "URL",	d->url) );
	if ( !d->desc.isEmpty() )
		v.appendChild( textTag(doc, "DESC",	d->desc) );

	if ( d->privacyClass != pcNone ) {
		TQDomElement w = doc->createElement("CLASS");

		if ( d->privacyClass == pcPublic )
			w.appendChild( emptyTag(doc, "PUBLIC") );
		else if ( d->privacyClass == pcPrivate )
			w.appendChild( emptyTag(doc, "PRIVATE") );
		else if ( d->privacyClass == pcConfidential )
			w.appendChild( emptyTag(doc, "CONFIDENTIAL") );

		v.appendChild(w);
	}

	if ( !d->key.isEmpty() ) {
		TQDomElement w = doc->createElement("KEY");

		// TODO: Justin, please check out this code
		w.appendChild( textTag(doc, "TYPE", "text/plain")); // FIXME
		w.appendChild( textTag(doc, "CRED", TQString::fromUtf8(d->key)) ); // FIXME

		v.appendChild(w);
	}

	return v;
}

bool VCard::fromXml(const TQDomElement &q)
{
	if ( q.tagName().upper() != "VCARD" )
		return false;

	TQDomNode n = q.firstChild();
	for ( ; !n.isNull(); n = n.nextSibling() ) {
		TQDomElement i = n.toElement();
		if ( i.isNull() )
			continue;

		TQString tag = i.tagName().upper();

		bool found;
		TQDomElement e;

		if ( tag == "VERSION" )
			d->version = i.text().stripWhiteSpace();
		else if ( tag == "FN" )
			d->fullName = i.text().stripWhiteSpace();
		else if ( tag == "N" ) {
			d->familyName = subTagText(i, "FAMILY");
			d->givenName  = subTagText(i, "GIVEN");
			d->middleName = subTagText(i, "MIDDLE");
			d->prefixName = subTagText(i, "PREFIX");
			d->suffixName = subTagText(i, "SUFFIX");
		}
		else if ( tag == "NICKNAME" )
			d->nickName = i.text().stripWhiteSpace();
		else if ( tag == "PHOTO" ) {
			d->photo = Base64::stringToArray( subTagText(i, "BINVAL") );
			d->photoURI = subTagText(i, "EXTVAL");
		}
		else if ( tag == "BDAY" )
			d->bday = i.text().stripWhiteSpace();
		else if ( tag == "ADR" ) {
			Address a;

			a.home   = hasSubTag(i, "HOME");
			a.work   = hasSubTag(i, "WORK");
			a.postal = hasSubTag(i, "POSTAL");
			a.parcel = hasSubTag(i, "PARCEL");
			a.dom    = hasSubTag(i, "DOM");
			a.intl   = hasSubTag(i, "INTL");
			a.pref   = hasSubTag(i, "PREF");

			a.pobox    = subTagText(i, "POBOX");
			a.extaddr  = subTagText(i, "EXTADR");
			a.street   = subTagText(i, "STREET");
			a.locality = subTagText(i, "LOCALITY");
			a.region   = subTagText(i, "REGION");
			a.pcode    = subTagText(i, "PCODE");
			a.country  = subTagText(i, "CTRY");

			if ( a.country.isEmpty() ) // FIXME: Workaround for Psi prior to 0.9
				if ( hasSubTag(i, "COUNTRY") )
					a.country = subTagText(i, "COUNTRY");

			if ( a.extaddr.isEmpty() ) // FIXME: Workaround for Psi prior to 0.9
				if ( hasSubTag(i, "EXTADD") )
					a.extaddr = subTagText(i, "EXTADD");

			d->addressList.append ( a );
		}
		else if ( tag == "LABEL" ) {
			Label l;

			l.home   = hasSubTag(i, "HOME");
			l.work   = hasSubTag(i, "WORK");
			l.postal = hasSubTag(i, "POSTAL");
			l.parcel = hasSubTag(i, "PARCEL");
			l.dom    = hasSubTag(i, "DOM");
			l.intl   = hasSubTag(i, "INTL");
			l.pref   = hasSubTag(i, "PREF");

			TQDomNode nn = i.firstChild();
			for ( ; !nn.isNull(); nn = nn.nextSibling() ) {
				TQDomElement ii = nn.toElement();
				if ( ii.isNull() )
					continue;

				if ( ii.tagName().upper() == "LINE" )
					l.lines.append ( ii.text().stripWhiteSpace() );
			}

			d->labelList.append ( l );
		}
		else if ( tag == "TEL" ) {
			Phone p;

			p.home  = hasSubTag(i, "HOME");
			p.work  = hasSubTag(i, "WORK");
			p.voice = hasSubTag(i, "VOICE");
			p.fax   = hasSubTag(i, "FAX");
			p.pager = hasSubTag(i, "PAGER");
			p.msg   = hasSubTag(i, "MSG");
			p.cell  = hasSubTag(i, "CELL");
			p.video = hasSubTag(i, "VIDEO");
			p.bbs   = hasSubTag(i, "BBS");
			p.modem = hasSubTag(i, "MODEM");
			p.isdn  = hasSubTag(i, "ISDN");
			p.pcs   = hasSubTag(i, "PCS");
			p.pref  = hasSubTag(i, "PREF");

			p.number = subTagText(i, "NUMBER");

			if ( p.number.isEmpty() ) // FIXME: Workaround for Psi prior to 0.9
				if ( hasSubTag(i, "VOICE") )
					p.number = subTagText(i, "VOICE");

			d->phoneList.append ( p );
		}
		else if ( tag == "EMAIL" ) {
			Email m;

			m.home     = hasSubTag(i, "HOME");
			m.work     = hasSubTag(i, "WORK");
			m.internet = hasSubTag(i, "INTERNET");
			m.x400     = hasSubTag(i, "X400");

			m.userid = subTagText(i, "USERID");

			if ( m.userid.isEmpty() ) // FIXME: Workaround for Psi prior to 0.9
				if ( !i.text().isEmpty() )
					m.userid = i.text().stripWhiteSpace();

			d->emailList.append ( m );
		}
		else if ( tag == "JABBERID" )
			d->jid = i.text().stripWhiteSpace();
		else if ( tag == "MAILER" )
			d->mailer = i.text().stripWhiteSpace();
		else if ( tag == "TZ" )
			d->timezone = i.text().stripWhiteSpace();
		else if ( tag == "GEO" ) {
			d->geo.lat = subTagText(i, "LAT");
			d->geo.lon = subTagText(i, "LON");
		}
		else if ( tag == "TITLE" )
			d->title = i.text().stripWhiteSpace();
		else if ( tag == "ROLE" )
			d->role = i.text().stripWhiteSpace();
		else if ( tag == "LOGO" ) {
			d->logo = Base64::stringToArray( subTagText(i, "BINVAL") );
			d->logoURI = subTagText(i, "EXTVAL");
		}
		else if ( tag == "AGENT" ) {
			e = findSubTag(i, "VCARD", &found);
			if ( found ) {
				VCard a;
				if ( a.fromXml(e) ) {
					if ( !d->agent )
						d->agent = new VCard;
					*(d->agent) = a;
				}
			}

			d->agentURI = subTagText(i, "EXTVAL");
		}
		else if ( tag == "ORG" ) {
			d->org.name = subTagText(i, "ORGNAME");

			TQDomNode nn = i.firstChild();
			for ( ; !nn.isNull(); nn = nn.nextSibling() ) {
				TQDomElement ii = nn.toElement();
				if ( ii.isNull() )
					continue;

				if ( ii.tagName().upper() == "ORGUNIT" )
					d->org.unit.append( ii.text().stripWhiteSpace() );
			}
		}
		else if ( tag == "CATEGORIES") {
			TQDomNode nn = i.firstChild();
			for ( ; !nn.isNull(); nn = nn.nextSibling() ) {
				TQDomElement ee = nn.toElement();
				if ( ee.isNull() )
					continue;

				if ( ee.tagName().upper() == "KEYWORD" )
					d->categories << ee.text().stripWhiteSpace();
			}
		}
		else if ( tag == "NOTE" )
			d->note = i.text().stripWhiteSpace();
		else if ( tag == "PRODID" )
			d->prodId = i.text().stripWhiteSpace();
		else if ( tag == "REV" )
			d->rev = i.text().stripWhiteSpace();
		else if ( tag == "SORT-STRING" )
			d->sortString = i.text().stripWhiteSpace();
		else if ( tag == "SOUND" ) {
			d->sound = Base64::stringToArray( subTagText(i, "BINVAL") );
			d->soundURI      = subTagText(i, "EXTVAL");
			d->soundPhonetic = subTagText(i, "PHONETIC");
		}
		else if ( tag == "UID" )
			d->uid = i.text().stripWhiteSpace();
		else if ( tag == "URL")
			d->url = i.text().stripWhiteSpace();
		else if ( tag == "DESC" )
			d->desc = i.text().stripWhiteSpace();
		else if ( tag == "CLASS" ) {
			if ( hasSubTag(i, "PUBLIC") )
				d->privacyClass = pcPublic;
			else if ( hasSubTag(i, "PRIVATE") )
				d->privacyClass = pcPrivate;
			else if ( hasSubTag(i, "CONFIDENTIAL") )
				d->privacyClass = pcConfidential;
		}
		else if ( tag == "KEY" ) {
			// TODO: Justin, please check out this code
			e = findSubTag(i, "TYPE", &found);
			TQString type = "text/plain";
			if ( found )
				type = e.text().stripWhiteSpace();

			e = findSubTag(i, "CRED", &found );
			if ( !found )
				e = findSubTag(i, "BINVAL", &found); // case for very clever clients ;-)

			if ( found )
				d->key = e.text().utf8(); // FIXME
		}
	}

	return true;
}

bool VCard::isEmpty() const
{
	return d->isEmpty();
}

// Some constructors

VCard::Address::Address()
{
	home = work = postal = parcel = dom = intl = pref = false;
}

VCard::Label::Label()
{
	home = work = postal = parcel = dom = intl = pref = false;
}

VCard::Phone::Phone()
{
	home = work = voice = fax = pager = msg = cell = video = bbs = modem = isdn = pcs = pref = false;
}

VCard::Email::Email()
{
	home = work = internet = x400 = false;
}

VCard::Geo::Geo()
{
}

VCard::Org::Org()
{
}

// vCard properties...

const TQString &VCard::version() const
{
	return d->version;
}

void VCard::setVersion(const TQString &v)
{
	d->version = v;
}

const TQString &VCard::fullName() const
{
	return d->fullName;
}

void VCard::setFullName(const TQString &n)
{
	d->fullName = n;
}

const TQString &VCard::familyName() const
{
	return d->familyName;
}

void VCard::setFamilyName(const TQString &n)
{
	d->familyName = n;
}

const TQString &VCard::givenName() const
{
	return d->givenName;
}

void VCard::setGivenName(const TQString &n)
{
	d->givenName = n;
}

const TQString &VCard::middleName() const
{
	return d->middleName;
}

void VCard::setMiddleName(const TQString &n)
{
	d->middleName = n;
}

const TQString &VCard::prefixName() const
{
	return d->prefixName;
}

void VCard::setPrefixName(const TQString &p)
{
	d->prefixName = p;
}

const TQString &VCard::suffixName() const
{
	return d->suffixName;
}

void VCard::setSuffixName(const TQString &s)
{
	d->suffixName = s;
}

const TQString &VCard::nickName() const
{
	return d->nickName;
}

void VCard::setNickName(const TQString &n)
{
	d->nickName = n;
}

const TQByteArray &VCard::photo() const
{
	return d->photo;
}

void VCard::setPhoto(const TQByteArray &i)
{
	d->photo = i;
}

const TQString &VCard::photoURI() const
{
	return d->photoURI;
}

void VCard::setPhotoURI(const TQString &p)
{
	d->photoURI = p;
}

const TQDate VCard::bday() const
{
	return TQDate::fromString(d->bday);
}

void VCard::setBday(const TQDate &date)
{
	d->bday = date.toString();
}

const TQString &VCard::bdayStr() const
{
	return d->bday;
}

void VCard::setBdayStr(const TQString &date)
{
	d->bday = date;
}

const VCard::AddressList &VCard::addressList() const
{
	return d->addressList;
}

void VCard::setAddressList(const VCard::AddressList &a)
{
	d->addressList = a;
}

const VCard::LabelList &VCard::labelList() const
{
	return d->labelList;
}

void VCard::setLabelList(const VCard::LabelList &l)
{
	d->labelList = l;
}

const VCard::PhoneList &VCard::phoneList() const
{
	return d->phoneList;
}

void VCard::setPhoneList(const VCard::PhoneList &p)
{
	d->phoneList = p;
}

const VCard::EmailList &VCard::emailList() const
{
	return d->emailList;
}

void VCard::setEmailList(const VCard::EmailList &e)
{
	d->emailList = e;
}

const TQString &VCard::jid() const
{
	return d->jid;
}

void VCard::setJid(const TQString &j)
{
	d->jid = j;
}

const TQString &VCard::mailer() const
{
	return d->mailer;
}

void VCard::setMailer(const TQString &m)
{
	d->mailer = m;
}

const TQString &VCard::timezone() const
{
	return d->timezone;
}

void VCard::setTimezone(const TQString &t)
{
	d->timezone = t;
}

const VCard::Geo &VCard::geo() const
{
	return d->geo;
}

void VCard::setGeo(const VCard::Geo &g)
{
	d->geo = g;
}

const TQString &VCard::title() const
{
	return d->title;
}

void VCard::setTitle(const TQString &t)
{
	d->title = t;
}

const TQString &VCard::role() const
{
	return d->role;
}

void VCard::setRole(const TQString &r)
{
	d->role = r;
}

const TQByteArray &VCard::logo() const
{
	return d->logo;
}

void VCard::setLogo(const TQByteArray &i)
{
	d->logo = i;
}

const TQString &VCard::logoURI() const
{
	return d->logoURI;
}

void VCard::setLogoURI(const TQString &l)
{
	d->logoURI = l;
}

const VCard *VCard::agent() const
{
	return d->agent;
}

void VCard::setAgent(const VCard &v)
{
	if ( !d->agent )
		d->agent = new VCard;
	*(d->agent) = v;
}

const TQString VCard::agentURI() const
{
	return d->agentURI;
}

void VCard::setAgentURI(const TQString &a)
{
	d->agentURI = a;
}

const VCard::Org &VCard::org() const
{
	return d->org;
}

void VCard::setOrg(const VCard::Org &o)
{
	d->org = o;
}

const TQStringList &VCard::categories() const
{
	return d->categories;
}

void VCard::setCategories(const TQStringList &c)
{
	d->categories = c;
}

const TQString &VCard::note() const
{
	return d->note;
}

void VCard::setNote(const TQString &n)
{
	d->note = n;
}

const TQString &VCard::prodId() const
{
	return d->prodId;
}

void VCard::setProdId(const TQString &p)
{
	d->prodId = p;
}

const TQString &VCard::rev() const
{
	return d->rev;
}

void VCard::setRev(const TQString &r)
{
	d->rev = r;
}

const TQString &VCard::sortString() const
{
	return d->sortString;
}

void VCard::setSortString(const TQString &s)
{
	d->sortString = s;
}

const TQByteArray &VCard::sound() const
{
	return d->sound;
}

void VCard::setSound(const TQByteArray &s)
{
	d->sound = s;
}

const TQString &VCard::soundURI() const
{
	return d->soundURI;
}

void VCard::setSoundURI(const TQString &s)
{
	d->soundURI = s;
}

const TQString &VCard::soundPhonetic() const
{
	return d->soundPhonetic;
}

void VCard::setSoundPhonetic(const TQString &s)
{
	d->soundPhonetic = s;
}

const TQString &VCard::uid() const
{
	return d->uid;
}

void VCard::setUid(const TQString &u)
{
	d->uid = u;
}

const TQString &VCard::url() const
{
	return d->url;
}

void VCard::setUrl(const TQString &u)
{
	d->url = u;
}

const TQString &VCard::desc() const
{
	return d->desc;
}

void VCard::setDesc(const TQString &desc)
{
	d->desc = desc;
}

const VCard::PrivacyClass &VCard::privacyClass() const
{
	return d->privacyClass;
}

void VCard::setPrivacyClass(const VCard::PrivacyClass &c)
{
	d->privacyClass = c;
}

const TQByteArray &VCard::key() const
{
	return d->key;
}

void VCard::setKey(const TQByteArray &k)
{
	d->key = k;
}
