serialiser.cpp Example File
samplephonebook/serialiser.cpp
#include "serialiser.h"
#include <QUuid>
QString Serialiser::escaped(const QString& input)
{
QString retn = "";
for (int i = 0; i < input.length(); i++) {
QChar currChar = input.at(i);
if (currChar == '\\' ||
currChar == '=' ||
currChar == ',' ||
currChar == ';' ||
currChar == ':') {
retn += '\\';
}
retn += currChar;
}
return retn;
}
QString Serialiser::convertDetail(const QContact& contact, const QContactDetail& detail, const QString& vcardField)
{
QString retn = "X-com-nokia-mobility-contacts-vcard-detail-";
retn += escaped(QUuid::createUuid().toString());
retn += ":";
retn += escaped(vcardField);
retn += ";";
retn += escaped(detail.definitionName());
retn += ";";
QVariantMap vals = detail.values();
foreach (const QString& key, vals.keys()) {
retn += escaped(key);
retn += "=";
retn += escaped(vals.value(key).toString());
retn += ",";
}
retn.chop(1);
retn += ";";
retn += "preferredFor=";
foreach(const QContactActionDescriptor& actionDescr, contact.availableActions(QString())) {
if (contact.isPreferredDetail(actionDescr.actionName(), detail)) {
retn += escaped(actionDescr.actionName()) + ",";
}
}
if (retn.endsWith(","))
retn.chop(1);
return retn;
}
QStringList Serialiser::findActionIdsFromCustomString(const QString& customString)
{
QString pref = "preferredFor=";
int startPos = customString.indexOf(pref) + pref.length();
if (startPos <= pref.length() || startPos >= customString.length())
return QStringList();
QStringList retn;
QString currentActionId = "";
for (int i = startPos; i < customString.length(); i++) {
QChar currChar = customString.at(i);
if (currChar == '\\') {
i += 1;
currentActionId += customString.at(i);
} else if (currChar == ',') {
if (currentActionId.length() > 0) {
retn << currentActionId;
}
currentActionId = "";
}
}
if (currentActionId.length() > 0)
retn << currentActionId;
return retn;
}
QString Serialiser::findLinkStringFromCustomString(const QString& customString)
{
if (customString.indexOf("X-com-nokia-mobility-contacts-vcard-detail-") != 0) {
return QString();
}
int sectionCount = 0;
QString linkString = "";
for (int i = 0; i < customString.length(); i++) {
QChar currChar = customString.at(i);
if (sectionCount > 0) {
if (currChar == '\\') {
linkString += customString.at(i+1);
} else {
linkString += currChar;
}
}
if (currChar == ';' || currChar == ':') {
sectionCount += 1;
if (sectionCount == 2) {
linkString.chop(1);
return linkString;
}
} else if (currChar == '\\') {
i += 1;
}
}
return QString();
}
QContactDetail Serialiser::convertCustomString(const QString& customString)
{
int nextSection = 0;
int oldNextSection = 0;
if (customString.indexOf("X-com-nokia-mobility-contacts-vcard-detail-") != 0) {
return QContactDetail();
}
int sectionCount = 0;
for (int i = nextSection; i < customString.length(); i++) {
QChar currChar = customString.at(i);
if (currChar == ';' || currChar == ':') {
sectionCount += 1;
if (sectionCount == 2) {
nextSection = i + 1;
break;
}
} else if (currChar == '\\') {
i += 1;
}
}
QString definitionName = "";
for (int i = nextSection; i < customString.length(); i++) {
QChar currChar = customString.at(i);
if (currChar == ';') {
nextSection = i + 1;
break;
} else if (currChar == '\\') {
i += 1;
}
definitionName += customString.at(i);
}
if (nextSection == oldNextSection) {
return QContactDetail();
}
QVariantMap values;
QString currKey = "";
QString currVal = "";
for (int i = nextSection; i < customString.length(); i++) {
QChar currChar = customString.at(i);
if (currChar == ';') {
nextSection = i+1;
break;
} else if (currChar == '=') {
for (int j = i + 1; j < customString.length(); j++) {
currChar = customString.at(j);
if (currChar == ',') {
i = j;
break;
} else if (currChar == ';') {
i = j - 1;
break;
} else if (currChar == '\\') {
j += 1;
currVal += customString.at(j);
} else {
currVal += currChar;
}
}
values.insert(currKey, currVal);
currKey = "";
currVal = "";
} else if (currChar == ',') {
currKey = "";
currVal = "";
} else if (currChar == '\\') {
i += 1;
currKey += customString.at(i);
} else {
currKey += currChar;
}
}
if (nextSection == oldNextSection) {
return QContactDetail();
}
QMap<QString, QString> attrs;
currKey = "";
QString currAttr = "";
for (int i = nextSection; i < customString.length(); i++) {
QChar currChar = customString.at(i);
if (currChar == ';') {
nextSection = i+1;
break;
} else if (currChar == '=') {
for (int j = i + 1; j < customString.length(); j++) {
currChar = customString.at(j);
if (currChar == ',') {
i = j;
break;
} else if (currChar == ';') {
i = j - 1;
break;
} else if (currChar == '\\') {
j += 1;
currAttr += customString.at(j);
} else {
currAttr += currChar;
}
}
values.insert(currKey, currAttr);
currKey = "";
currAttr = "";
} else if (currChar == ',') {
currKey = "";
currVal = "";
} else if (currChar == '\\') {
i += 1;
currKey += customString.at(i);
} else {
currKey += currChar;
}
}
if (nextSection == oldNextSection) {
return QContactDetail();
}
QContactDetail retn(definitionName);
QStringList keys = values.keys();
foreach (const QString& key, keys)
retn.setValue(key, values.value(key));
return retn;
}
QContact Serialiser::convertVcard(const QStringList& vcardLines)
{
QMultiMap<QString, QContactDetail> vcardDetails;
QMultiMap<QString, QContactDetail> customDetails;
QList<QContactDetail> unlinkedCustomDetails;
QMap<QString, QContactDetail> customPreferredForUuid;
QMap<QString, QStringList> customPreferredFor;
QList<QContactDetail> vcardPreferredFor;
QContact retn;
QStringList strippedVcardLines = removeClutter(vcardLines);
foreach (const QString& line, strippedVcardLines) {
if (line.startsWith("X-com-nokia-mobility-contacts-vcard-detail-")) {
QContactDetail det = convertCustomString(line);
if (!det.isEmpty()) {
QString linkString = findLinkStringFromCustomString(line);
if (linkString.isEmpty()) {
unlinkedCustomDetails.append(det);
} else {
customDetails.insert(linkString, det);
}
QString detailUuid = QUuid::createUuid().toString();
customPreferredForUuid.insert(detailUuid, det);
customPreferredFor.insert(detailUuid, findActionIdsFromCustomString(line));
}
} else {
QContactDetail det = parsePropertyType(line);
QString defId = det.definitionName();
if (defId.isEmpty()) {
} else {
QStringList contexts = parseContext(line);
if (!contexts.isEmpty())
det.setContexts(contexts);
if (defId == QContactPhoneNumber::DefinitionName) {
det.setValue(QContactPhoneNumber::FieldSubTypes, parseAttributes(line));
det.setValue(QContactPhoneNumber::FieldNumber, parseValue(line));
vcardDetails.insert("TEL", det);
} else if (defId == QContactEmailAddress::DefinitionName) {
det.setValue(QContactEmailAddress::FieldEmailAddress, parseValue(line));
vcardDetails.insert("EMAIL", det);
} else if (defId == "Url") {
det.setValue(QContactUrl::FieldSubType, parseAttributes(line));
det.setValue(QContactUrl::DefinitionName, parseValue(line));
vcardDetails.insert("URL", det);
} else if (defId == QContactAvatar::DefinitionName) {
det.setValue(QContactAvatar::FieldSubType, parseAttributes(line));
det.setValue(QContactAvatar::FieldAvatar, parseValue(line));
vcardDetails.insert("PHOTO", det);
} else if (defId == QContactGuid::DefinitionName) {
det.setValue(QContactGuid::FieldGuid, parseValue(line));
vcardDetails.insert("UID", det);
} else if (defId == QContactAddress::DefinitionName) {
det.setValue(QContactAddress::FieldSubTypes, parseAttributes(line));
QStringList fieldValues = parseValue(line).split(";");
det.setValue(QContactAddress::FieldStreet, fieldValues.value(2));
det.setValue(QContactAddress::FieldLocality, fieldValues.value(3));
det.setValue(QContactAddress::FieldRegion, fieldValues.value(4));
det.setValue(QContactAddress::FieldPostcode, fieldValues.value(5));
det.setValue(QContactAddress::FieldCountry, fieldValues.value(6));
vcardDetails.insert("ADR", det);
} else if (defId == QContactName::DefinitionName) {
QStringList fieldValues = parseValue(line).split(";");
if (vcardDetails.contains("N")) {
QContactDetail currName = vcardDetails.value("N");
currName.setValue(QContactName::FieldPrefix, fieldValues.value(3));
currName.setValue(QContactName::FieldFirst, fieldValues.value(1));
currName.setValue(QContactName::FieldMiddle, fieldValues.value(2));
currName.setValue(QContactName::FieldLast, fieldValues.value(0));
currName.setValue(QContactName::FieldSuffix, fieldValues.value(4));
vcardDetails.replace("N", currName);
} else {
det.setValue(QContactName::FieldPrefix, fieldValues.value(3));
det.setValue(QContactName::FieldFirst, fieldValues.value(1));
det.setValue(QContactName::FieldMiddle, fieldValues.value(2));
det.setValue(QContactName::FieldLast, fieldValues.value(0));
det.setValue(QContactName::FieldSuffix, fieldValues.value(4));
vcardDetails.insert("N", det);
}
} else {
continue;
}
if (parsePreferred(line)) {
vcardPreferredFor.append(det);
}
}
}
}
foreach (const QString& linkString, customDetails.keys()) {
foreach (const QContactDetail& linkedDetail, customDetails.values(linkString)) {
bool found = false;
QContactDetail toRemove;
foreach (const QContactDetail& vcardDetail, vcardDetails.values(linkString)) {
if (linkedDetail.values() == vcardDetail.values()) {
toRemove = vcardDetail;
found = true;
break;
}
}
if (!found) {
} else {
!
vcardDetails.remove(linkString, toRemove);
vcardPreferredFor.removeOne(toRemove);
toRemove = linkedDetail;
retn.saveDetail(&toRemove);
}
}
}
foreach (const QContactDetail& det, vcardDetails.values()) {
QContactDetail temp = det;
retn.saveDetail(&temp);
}
foreach (const QContactDetail& det, unlinkedCustomDetails) {
QContactDetail temp = det;
retn.saveDetail(&temp);
}
foreach (const QString& detailUuid, customPreferredForUuid.keys()) {
QContactDetail det = customPreferredForUuid.value(detailUuid);
foreach (const QStringList& actionIds, customPreferredFor.values(detailUuid)) {
foreach (const QString& actionId, actionIds) {
retn.setPreferredDetail(actionId, det);
}
}
}
return retn;
}
QStringList Serialiser::removeClutter(const QStringList& vcard)
{
QStringList copy;
foreach (QString line, vcard) {
QString firstBit = line.split(":", QString::SkipEmptyParts).value(0);
if (firstBit == "BEGIN" || firstBit == "VERSION" || firstBit == "CLASS" || firstBit == "PRODID" || firstBit == "REV" || firstBit == "END") {
} else {
copy.append(line);
}
}
return copy;
}
QContactDetail Serialiser::parsePropertyType(const QString& line)
{
QStringList semiColonSplit = line.split(";");
QStringList colonSplit = line.split(":");
if (semiColonSplit.size() == 0 && colonSplit.size() == 0)
return QContactDetail();
if (semiColonSplit.size() != 0) {
if (semiColonSplit.at(0) == "TEL") {
return QContactPhoneNumber();
} else if (semiColonSplit.at(0) == "EMAIL") {
return QContactEmailAddress();
} else if (semiColonSplit.at(0) == "ADR") {
return QContactAddress();
} else if (semiColonSplit.at(0) == "PHOTO") {
return QContactAvatar();
} else if (semiColonSplit.at(0) == "UID") {
return QContactGuid();
}
}
if (colonSplit.size() != 0) {
if (colonSplit.at(0) == "URL") {
return QContactDetail("Url");
} else if (colonSplit.at(0) == "N") {
QContactName name;
return name;
} else if (colonSplit.at(0) == "FN") {
QContactDisplayLabel label;
return label;
}
}
return QContactDetail();
}
QStringList Serialiser::parseContext(const QString& line)
{
QStringList result;
QStringList contexts;
contexts << QContactDetail::ContextHome << QContactDetail::ContextWork << QContactDetail::ContextOther;
QStringList semiColonSplit = line.split(";");
for (int i = 0; i < semiColonSplit.size(); i++) {
QString currSplit = semiColonSplit.at(i);
if (currSplit.startsWith("TYPE=")) {
for (int j = 0; j < contexts.size(); j++) {
QString currContext = contexts.at(j);
if (currSplit.contains(currContext.toLower()) && !result.contains(currContext)) {
result.append(currContext);
return result;
}
}
}
}
return result;
}
QString Serialiser::parseValue(const QString& line)
{
QStringList colonSplit = line.split(":");
if (colonSplit.size() != 2) {
return QString();
}
return colonSplit.at(1);
}
QString Serialiser::parseAttributes(const QString& line)
{
QString result = "";
QStringList contexts;
contexts << QContactDetail::ContextHome << QContactDetail::ContextWork << QContactDetail::ContextOther;
QStringList semiColonSplit = line.split(";");
for (int i = 0; i < semiColonSplit.size(); i++) {
QString currSplit = semiColonSplit.at(i);
if (currSplit.startsWith("TYPE=")) {
QString possibleAttrs = currSplit.remove(0,5);
int startIndex = -1;
startIndex = possibleAttrs.indexOf("pref");
if (startIndex != -1)
possibleAttrs = possibleAttrs.remove(startIndex, 4);
for (int j = 0; j < contexts.size(); j++) {
startIndex = possibleAttrs.indexOf(contexts.at(j).toLower());
if (startIndex != -1) {
possibleAttrs = possibleAttrs.remove(startIndex, contexts.at(j).length());
}
}
startIndex = possibleAttrs.indexOf(":");
if (startIndex != -1) {
possibleAttrs = possibleAttrs.left(startIndex);
}
QStringList attributes = possibleAttrs.split(",", QString::SkipEmptyParts);
foreach (QString attribute, attributes) {
if (attribute == "cell") {
result += "Mobile,";
} else if (attribute == "fax") {
result += "Facsimile,";
} else if (attribute == "msg") {
result += "Messaging,";
} else if (attribute == "dom") {
result += "Domestic,";
} else if (attribute == "intl") {
result += "International,";
} else {
QString firstLetter = "";
firstLetter += attribute.at(0);
firstLetter = firstLetter.toUpper();
QString rest = attribute.remove(0,1);
result += firstLetter + rest + ",";
}
}
result.chop(1);
}
}
return result;
}
bool Serialiser::parsePreferred(const QString& line)
{
QStringList semiColonSplit = line.split(";");
for (int i = 0; i < semiColonSplit.size(); i++) {
QString currSplit = semiColonSplit.at(i);
if (currSplit.startsWith("TYPE=")) {
if (currSplit.contains("pref")) {
return true;
}
}
}
return false;
}
bool Serialiser::detailIsPreferredForAnything(const QContact& contact, const QContactDetail& detail)
{
foreach (const QContactActionDescriptor& actionDescr, contact.availableActions(QString())) {
if (contact.isPreferredDetail(actionDescr.actionName(), detail)) {
return true;
}
}
return false;
}
QStringList Serialiser::convertContact(const QContact& contact)
{
QStringList vcard;
QContact c = contact;
QDateTime curr = QDateTime::currentDateTime();
QString entry = "REV:" + curr.toString("yyyy-MM-dd hh:mm:ss");
vcard << "BEGIN:VCARD" << "VERSION:3.0" << "CLASS:PUBLIC" << "PRODID:-
QStringList customVcardFields;
QStringList vcardFieldsWithValues;
foreach (const QContactDetail& det, contact.details()) {
QString definitionName = det.definitionName();
if (definitionName == QContactName::DefinitionName) {
bool saved = false;
if (!vcardFieldsWithValues.contains("N")) {
entry = "N:" + det.value(QContactName::FieldLast) + ";" + det.value(QContactName::FieldFirst) + ";" + det.value(QContactName::FieldMiddle) + ";" + det.value(QContactName::FieldPrefix) + det.value(QContactName::FieldSuffix);
vcardFieldsWithValues << "N";
vcard << entry;
customVcardFields << convertDetail(contact, det, "N");
saved = true;
}
if (!saved) {
customVcardFields << convertDetail(contact, det);
}
} else if (definitionName == QContactDisplayLabel::DefinitionName) {
if (!vcardFieldsWithValues.contains("FN")) {
entry = "FN:" + det.value(QContactDisplayLabel::FieldLabel);
vcard << entry;
vcardFieldsWithValues << "FN";
customVcardFields << convertDetail(contact, det, "FN");
}
} else if (definitionName == QContactAddress::DefinitionName) {
entry = "ADR;TYPE=";
QString typestr = "";
QStringList subTypes = det.value<QStringList>(QContactAddress::FieldSubTypes);
QStringList contexts = det.contexts();
if (contexts.contains(QContactDetail::ContextHome)) typestr += "home,";
if (contexts.contains(QContactDetail::ContextWork)) typestr += "work,";
if (contexts.contains(QContactDetail::ContextOther)) typestr += "other,";
if (subTypes.contains(QContactAddress::SubTypeDomestic)) typestr += "dom,";
if (subTypes.contains(QContactAddress::SubTypeInternational)) typestr += "intl,";
if (subTypes.contains(QContactAddress::SubTypeParcel)) typestr += "parcel,";
if (subTypes.contains(QContactAddress::SubTypePostal)) typestr += "postal,";
if (detailIsPreferredForAnything(contact, det)) typestr += "pref,";
typestr.chop(1);
entry += typestr + ":;;" + det.value(QContactAddress::FieldStreet) + ";" + det.value(QContactAddress::FieldLocality) + ";" + det.value(QContactAddress::FieldRegion) + ";" + det.value(QContactAddress::FieldPostcode) + ";" + det.value(QContactAddress::FieldCountry);
vcard << entry;
vcardFieldsWithValues << "ADR";
vcardFieldsWithValues << "LABEL";
customVcardFields << convertDetail(contact, det, "ADR");
} else if (definitionName == "Url") {
entry = "URL:" + det.value("Url");
vcard << entry;
vcardFieldsWithValues << "URL";
customVcardFields << convertDetail(contact, det, "URL");
} else if (definitionName == QContactEmailAddress::DefinitionName) {
entry = "EMAIL;TYPE=internet";
if (detailIsPreferredForAnything(contact, det)) entry += ",pref";
entry += ":" + det.value(QContactEmailAddress::FieldEmailAddress);
vcard << entry;
vcardFieldsWithValues << "EMAIL";
customVcardFields << convertDetail(contact, det, "EMAIL");
} else if (definitionName == QContactPhoneNumber::DefinitionName) {
entry = "TEL;TYPE=";
QString typeStr = "";
QStringList subTypes = det.value<QStringList>(QContactPhoneNumber::FieldSubTypes);
QStringList contexts = det.contexts();
if (subTypes.contains(QContactPhoneNumber::SubTypeMobile)) typeStr += "cell,";
if (subTypes.contains(QContactPhoneNumber::SubTypeFacsimile)) typeStr += "fax,";
if (subTypes.contains(QContactPhoneNumber::SubTypeVideo)) typeStr += "video,";
if (subTypes.contains(QContactPhoneNumber::SubTypePager)) typeStr += "pager,";
if (subTypes.contains(QContactPhoneNumber::SubTypeModem)) typeStr += "modem,";
if (subTypes.contains(QContactPhoneNumber::SubTypeBulletinBoardSystem)) typeStr += "bbs,";
if (subTypes.contains(QContactPhoneNumber::SubTypeMessagingCapable)) typeStr += "msg,";
if (subTypes.contains(QContactPhoneNumber::SubTypeLandline) || typeStr.isEmpty()) typeStr += "voice,";
if (contexts.contains(QContactDetail::ContextHome)) typeStr = "home," + typeStr;
if (contexts.contains(QContactDetail::ContextWork)) typeStr = "work," + typeStr;
if (contexts.contains(QContactDetail::ContextOther)) typeStr = "other," + typeStr;
if (detailIsPreferredForAnything(contact, det)) typeStr += "pref,";
typeStr.chop(1);
entry += typeStr + ":" + det.value(QContactPhoneNumber::FieldNumber);
vcard << entry;
vcardFieldsWithValues << "TEL";
customVcardFields << convertDetail(contact, det, "TEL");
} else if (definitionName == QContactAvatar::DefinitionName) {
if (vcardFieldsWithValues.contains("PHOTO")) {
customVcardFields << convertDetail(contact, det);
} else {
vcardFieldsWithValues << "PHOTO";
entry = "PHOTO;VALUE=uri:" + det.value(QContactAvatar::FieldAvatar);
customVcardFields << convertDetail(contact, det, "PHOTO");
}
} else if (definitionName == QContactGuid::DefinitionName) {
if (vcardFieldsWithValues.contains("UID")) {
customVcardFields << convertDetail(contact, det);
} else {
vcardFieldsWithValues << "UID";
entry = "UID:" + det.value(QContactGuid::FieldGuid);
customVcardFields << convertDetail(contact, det, "UID");
}
} else {
customVcardFields << convertDetail(contact, det);
}
}
vcard << customVcardFields;
vcard << "END:VCARD";
return vcard;
}