|
|
|
/*
|
|
|
|
libvcard - vCard parsing library for vCard version 3.0
|
|
|
|
|
|
|
|
Copyright (C) 1998 Rik Hemsley rik@kde.org
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to
|
|
|
|
deal in the Software without restriction, including without limitation the
|
|
|
|
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
|
|
sell copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
|
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <tqcstring.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#include <VCardEnum.h>
|
|
|
|
|
|
|
|
using namespace VCARD;
|
|
|
|
|
|
|
|
// There are 31 possible types, not including extensions.
|
|
|
|
// URI is a custom field designed to store the upstream URI for each contact
|
|
|
|
// in order to handle certain limited CardDAV systems such as Zimbra
|
|
|
|
const TQCString
|
|
|
|
VCARD::paramNames [] =
|
|
|
|
{
|
|
|
|
"NAME",
|
|
|
|
"PROFILE",
|
|
|
|
"SOURCE",
|
|
|
|
"FN",
|
|
|
|
"N",
|
|
|
|
"NICKNAME",
|
|
|
|
"PHOTO",
|
|
|
|
"BDAY",
|
|
|
|
"ADR",
|
|
|
|
"LABEL",
|
|
|
|
"TEL",
|
|
|
|
"EMAIL",
|
|
|
|
"MAILER",
|
|
|
|
"TZ",
|
|
|
|
"GEO",
|
|
|
|
"TITLE",
|
|
|
|
"ROLE",
|
|
|
|
"LOGO",
|
|
|
|
"AGENT",
|
|
|
|
"ORG",
|
|
|
|
"CATEGORIES",
|
|
|
|
"NOTE",
|
|
|
|
"PRODID",
|
|
|
|
"REV",
|
|
|
|
"SORT-STRING",
|
|
|
|
"SOUND",
|
|
|
|
"UID",
|
|
|
|
"URL",
|
|
|
|
"VERSION",
|
|
|
|
"CLASS",
|
|
|
|
"KEY",
|
|
|
|
"URI"
|
|
|
|
};
|
|
|
|
|
|
|
|
const ParamType
|
|
|
|
VCARD::paramTypesTable[] = {
|
|
|
|
ParamNone, // NAME
|
|
|
|
ParamNone, // PROFILE
|
|
|
|
ParamSource, // SOURCE
|
|
|
|
ParamText, // FN
|
|
|
|
ParamText, // N
|
|
|
|
ParamText, // NICKNAME
|
|
|
|
ParamImage, // PHOTO (inline/refer)
|
|
|
|
ParamDate, // BDAY ("VALUE = "date-time/date)
|
|
|
|
ParamAddrText, // ADR (adr-param/text-param)
|
|
|
|
ParamAddrText, // LABEL (adr-param/text-param)
|
|
|
|
ParamTel, // TEL
|
|
|
|
ParamEmail, // EMAIL
|
|
|
|
ParamText, // MAILER
|
|
|
|
ParamNone, // TZ
|
|
|
|
ParamNone, // GEO
|
|
|
|
ParamText, // TITLE
|
|
|
|
ParamText, // ROLE
|
|
|
|
ParamImage, // LOGO
|
|
|
|
ParamAgent, // AGENT
|
|
|
|
ParamText, // ORG
|
|
|
|
ParamText, // CATEGORIES
|
|
|
|
ParamText, // NOTE
|
|
|
|
ParamNone, // PRODID
|
|
|
|
ParamDate, // REV
|
|
|
|
ParamText, // SORT-STRING
|
|
|
|
ParamSound, // SOUND
|
|
|
|
ParamNone, // UID
|
|
|
|
ParamNone, // URL
|
|
|
|
ParamNone, // VERSION
|
|
|
|
ParamNone, // CLASS
|
|
|
|
ParamTextBin, // KEY
|
|
|
|
ParamTextNS, // X
|
|
|
|
ParamNone // URI
|
|
|
|
};
|
|
|
|
|
|
|
|
ParamType
|
|
|
|
VCARD::EntityTypeToParamType(EntityType e)
|
|
|
|
{
|
|
|
|
ParamType t(ParamUnknown);
|
|
|
|
|
|
|
|
switch (e) {
|
|
|
|
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityAgent: t = ParamAgent; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntitySound: t = ParamSound; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntitySource: t = ParamSource; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityTelephone: t = ParamTel; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityEmail: t = ParamEmail; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityKey: t = ParamTextBin; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityExtension: t = ParamTextNS; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityAddress:
|
|
|
|
case EntityLabel: t = ParamAddrText; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityBirthday:
|
|
|
|
case EntityRevision: t = ParamDate; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityPhoto:
|
|
|
|
case EntityLogo: t = ParamImage; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityOrganisation:
|
|
|
|
case EntityTitle:
|
|
|
|
case EntityRole:
|
|
|
|
case EntityFullName:
|
|
|
|
case EntityMailer:
|
|
|
|
case EntityN:
|
|
|
|
case EntitySortString:
|
|
|
|
case EntityNickname:
|
|
|
|
case EntityCategories:
|
|
|
|
case EntityNote: t = ParamText; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityProductID:
|
|
|
|
case EntityTimeZone:
|
|
|
|
case EntityUID:
|
|
|
|
case EntityURL:
|
|
|
|
case EntityClass:
|
|
|
|
case EntityGeo:
|
|
|
|
case EntityName:
|
|
|
|
case EntityVersion:
|
|
|
|
case EntityProfile:
|
|
|
|
case EntityURI:
|
|
|
|
default: t = ParamNone; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
ValueType
|
|
|
|
VCARD::EntityTypeToValueType(EntityType e)
|
|
|
|
{
|
|
|
|
ValueType t(ValueUnknown);
|
|
|
|
|
|
|
|
switch (e) {
|
|
|
|
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntitySound: t = ValueSound; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityAgent: t = ValueAgent; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityAddress: t = ValueAddress; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityTelephone: t = ValueTel; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityKey: t = ValueTextBin; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityOrganisation: t = ValueOrg; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityN: t = ValueN; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityTimeZone: t = ValueUTC; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityClass: t = ValueClass; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityGeo: t = ValueGeo; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntitySource:
|
|
|
|
case EntityURL: t = ValueURI; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityPhoto:
|
|
|
|
case EntityLogo: t = ValueImage; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityBirthday:
|
|
|
|
case EntityRevision: t = ValueDate; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityCategories:
|
|
|
|
case EntityNickname: t = ValueTextList; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
case EntityLabel:
|
|
|
|
case EntityExtension:
|
|
|
|
case EntityEmail:
|
|
|
|
case EntityTitle:
|
|
|
|
case EntityRole:
|
|
|
|
case EntityFullName:
|
|
|
|
case EntityMailer:
|
|
|
|
case EntityProductID:
|
|
|
|
case EntityName:
|
|
|
|
case EntitySortString:
|
|
|
|
case EntityVersion:
|
|
|
|
case EntityProfile:
|
|
|
|
case EntityUID:
|
|
|
|
case EntityNote:
|
|
|
|
case EntityURI:
|
|
|
|
default: t = ValueText; break;
|
|
|
|
//---------------------------------------------------------------//
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQCString
|
|
|
|
VCARD::EntityTypeToParamName(EntityType e)
|
|
|
|
{
|
|
|
|
if ( e > EntityUnknown ) e = EntityUnknown;
|
|
|
|
return paramNames[ int( e ) ];
|
|
|
|
}
|
|
|
|
|
|
|
|
EntityType
|
|
|
|
VCARD::EntityNameToEntityType(const TQCString & s)
|
|
|
|
{
|
|
|
|
if (s.isEmpty()) return EntityUnknown;
|
|
|
|
|
|
|
|
EntityType t(EntityUnknown);
|
|
|
|
|
|
|
|
switch (s[0]) {
|
|
|
|
|
|
|
|
case 'A':
|
|
|
|
if (s == "ADR")
|
|
|
|
t = EntityAddress;
|
|
|
|
else if (s == "AGENT")
|
|
|
|
t = EntityAgent;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'B':
|
|
|
|
if (s == "BDAY")
|
|
|
|
t = EntityBirthday;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'C':
|
|
|
|
if (s == "CATEGORIES")
|
|
|
|
t = EntityCategories;
|
|
|
|
else if (s == "CLASS")
|
|
|
|
t = EntityClass;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'E':
|
|
|
|
if (s == "EMAIL")
|
|
|
|
t = EntityEmail;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'F':
|
|
|
|
if (s == "FN")
|
|
|
|
t = EntityFullName;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'G':
|
|
|
|
if (s == "GEO")
|
|
|
|
t = EntityGeo;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'K':
|
|
|
|
if (s == "KEY")
|
|
|
|
t = EntityKey;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'L':
|
|
|
|
if (s == "LABEL")
|
|
|
|
t = EntityLabel;
|
|
|
|
else if (s == "LOGO")
|
|
|
|
t = EntityLogo;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'M':
|
|
|
|
if (s == "MAILER")
|
|
|
|
t = EntityMailer;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'N':
|
|
|
|
if (s == "N")
|
|
|
|
t = EntityN;
|
|
|
|
else if (s == "NAME")
|
|
|
|
t = EntityName;
|
|
|
|
else if (s == "NICKNAME")
|
|
|
|
t = EntityNickname;
|
|
|
|
else if (s == "NOTE")
|
|
|
|
t = EntityNote;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'O':
|
|
|
|
if (s == "ORG")
|
|
|
|
t = EntityOrganisation;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'P':
|
|
|
|
if (s == "PHOTO")
|
|
|
|
t = EntityPhoto;
|
|
|
|
else if (s == "PRODID")
|
|
|
|
t = EntityProductID;
|
|
|
|
else if (s == "PROFILE")
|
|
|
|
t = EntityProfile;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'R':
|
|
|
|
if (s == "REV")
|
|
|
|
t = EntityRevision;
|
|
|
|
else if (s == "ROLE")
|
|
|
|
t = EntityRole;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'S':
|
|
|
|
if (s == "SORT-STRING")
|
|
|
|
t = EntitySortString;
|
|
|
|
else if (s == "SOUND")
|
|
|
|
t = EntitySound;
|
|
|
|
else if (s == "SOURCE")
|
|
|
|
t = EntitySource;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'T':
|
|
|
|
if (s == "TEL")
|
|
|
|
t = EntityTelephone;
|
|
|
|
else if (s == "TITLE")
|
|
|
|
t = EntityTitle;
|
|
|
|
else if (s == "TZ")
|
|
|
|
t = EntityTimeZone;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'U':
|
|
|
|
if (s == "UID")
|
|
|
|
t = EntityUID;
|
|
|
|
else if (s == "URL")
|
|
|
|
t = EntityURL;
|
|
|
|
else if (s == "URI")
|
|
|
|
t = EntityURI;
|
|
|
|
case 'V':
|
|
|
|
if (s == "VERSION")
|
|
|
|
t = EntityVersion;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'X':
|
|
|
|
if (s.left(2) == "X-")
|
|
|
|
t = EntityExtension;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
t = EntityUnknown;
|
|
|
|
}
|
|
|
|
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The copyright notice below refers to the base64 codec functions used below,
|
|
|
|
// which are modified from the original sources.
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Original version Copyright 1988 by The Leland Stanford Junior University
|
|
|
|
* Copyright 1998 by the University of Washington
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software and its
|
|
|
|
* documentation for any purpose and without fee is hereby granted, provided
|
|
|
|
* that the above copyright notices appear in all copies and that both the
|
|
|
|
* above copyright notices and this permission notice appear in supporting
|
|
|
|
* documentation, and that the name of the University of Washington or The
|
|
|
|
* Leland Stanford Junior University not be used in advertising or publicity
|
|
|
|
* pertaining to distribution of the software without specific, written prior
|
|
|
|
* permission. This software is made available "as is", and
|
|
|
|
* THE UNIVERSITY OF WASHINGTON AND THE LELAND STANFORD JUNIOR UNIVERSITY
|
|
|
|
* DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, WITH REGARD TO THIS SOFTWARE,
|
|
|
|
* INCLUDING WITHOUT LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE, AND IN NO EVENT SHALL THE UNIVERSITY OF
|
|
|
|
* WASHINGTON OR THE LELAND STANFORD JUNIOR UNIVERSITY BE LIABLE FOR ANY
|
|
|
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
|
|
|
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
|
|
|
|
* CONTRACT, TORT (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static char B64[] =
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
|
|
|
|
|
|
// the mime base64 disctionary used for decoding
|
|
|
|
static signed char b64dec[] = {
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 10
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 20
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 30
|
|
|
|
-1, -1, -1,-19, -1, -1, -1,-16, -4, -4, // 40 -19 == '+' -16 == '/'
|
|
|
|
-4, -4, -4, -4, -4, -4, -4, -4, -1, -1, // 50 -4 == '0'
|
|
|
|
-1, 0, -1, -1, -1, 65, 65, 65, 65, 65, // 60 0 == '=' 65 == 'A'
|
|
|
|
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, // 70
|
|
|
|
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, // 80
|
|
|
|
65, -1, -1, -1, -1, -1, -1, 71, 71, 71, // 90 71 == 'a'
|
|
|
|
71, 71, 71, 71, 71, 71, 71, 71, 71, 71, // 100
|
|
|
|
71, 71, 71, 71, 71, 71, 71, 71, 71, 71, // 110
|
|
|
|
71, 71, 71, -1, -1, -1, -1, -1, -1, -1, // 120
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 130
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 140
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 150
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 170
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 180
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 190
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 200
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 210
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 220
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 230
|
|
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 240
|
|
|
|
-1, -1, -1, -1, -1, -1, -1 // 250
|
|
|
|
};
|
|
|
|
|
|
|
|
char *
|
|
|
|
VCARD::decodeBase64(const char * s, unsigned long srcl, unsigned long & len)
|
|
|
|
{
|
|
|
|
unsigned char c;
|
|
|
|
unsigned long e(0);
|
|
|
|
len = 0;
|
|
|
|
unsigned const char * src = (unsigned const char *)s;
|
|
|
|
char * ret = new char[srcl + (srcl / 4 + 1)];
|
|
|
|
char *d = ret;
|
|
|
|
while (srcl--) { // Critical loop
|
|
|
|
c = *src++;
|
|
|
|
int dec = b64dec[c];
|
|
|
|
if (dec == -1) continue;
|
|
|
|
if (c == '=') {
|
|
|
|
switch (e++) {
|
|
|
|
case 3: e = 0; break;
|
|
|
|
case 2: if (*src == '=') break;
|
|
|
|
default: delete [] ret; ret = 0; return 0; break;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
c -= dec;
|
|
|
|
if (e == 0) { *d = c << 2; ++e; continue; }
|
|
|
|
switch (e) {
|
|
|
|
case 1: *d |= c >> 4; *++d = c << 4; break;
|
|
|
|
case 2: *d |= c >> 2; *++d = c << 6; break;
|
|
|
|
case 3: *d++ |= c; e = 0; continue; break;
|
|
|
|
}
|
|
|
|
++e;
|
|
|
|
}
|
|
|
|
len = d - (char *)ret;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
VCARD::encodeBase64(const char * src, unsigned long srcl, unsigned long & destl)
|
|
|
|
{
|
|
|
|
const unsigned char *s = (unsigned char *)src;
|
|
|
|
unsigned long i = ((srcl + 2) / 3) * 4;
|
|
|
|
destl = i += 2 * ((i / 60) + 1);
|
|
|
|
i = 0;
|
|
|
|
char * ret = new char[destl];
|
|
|
|
unsigned char *d((unsigned char *)ret);
|
|
|
|
while (srcl != 0) { // Critical loop
|
|
|
|
*d++ = B64[s[0] >> 2];
|
|
|
|
*d++ = B64[((s[0] << 4) + (--srcl == 0 ? 0 : s[1] >> 4)) & 0x3f];
|
|
|
|
*d++ = srcl == 0 ? '=' :
|
|
|
|
B64[((s[1] << 2) + (--srcl == 0 ? 0 : s[2] >> 6)) & 0x3f];
|
|
|
|
*d++ = srcl == 0 ? '=' : B64[s[2] & 0x3f];
|
|
|
|
if (srcl != 0) srcl--;
|
|
|
|
if (++i == 15) { i = 0; *d++ = '\r'; *d++ = '\n'; }
|
|
|
|
s += 3;
|
|
|
|
}
|
|
|
|
*d = '\r'; *++d = '\n'; *++d = '\0';
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|