// vcard.cpp - vCard Object
//
// (c) 2012-2015 Xestia Software Development.
//
// This file is part of Xestia Address Book.
//
// Xestia Address Book is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by the
// Free Software Foundation, version 3 of the license.
//
// Xestia Address Book 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with Xestia Address Book. If not, see
#include "vcard.h"
#include
#include
#include
#include
// vcard.cpp - Deals with vCard 4.0 formatted files meeting the
// RFC 6350 specification.
vCard::vCard(){
// Setup the vCard object.
vCardBegin = FALSE;
vCardEnd = FALSE;
vCardFN = FALSE;
vCardVersion = 0.0;
SettingCount = 0;
}
void vCard::Add(wxString SettingName, wxString SettingValue, bool ReplaceMode){
// Add data to vCard object.
// Check for backslashes used for commas, newlines and
// backslashes used for values.
if (ReplaceMode == TRUE){
SettingValue.Replace(wxT("\\n"), wxT("\n"));
SettingValue.Replace(wxT("\\,"), wxT(","));
SettingValue.Replace(wxT("\\:"), wxT(":"));
SettingValue.Replace(wxT("\\\\"), wxT("\\"));
} else {
SettingValue.Replace(wxT("\\"), wxT("\\\\"));
SettingValue.Replace(wxT("\n"), wxT("\\n"));
SettingValue.Replace(wxT(","), wxT("\\,"));
SettingValue.Replace(wxT(":"), wxT("\\:"));
SettingValue = SettingValue + wxT("\n");
}
// Check data to make sure that it meets the required
// vCard 4.0 specifications.
if (SettingName == wxT("BEGIN") && SettingValue == wxT("VCARD")){
vCardBegin = TRUE;
}
if (SettingName == wxT("END") && SettingValue == wxT("VCARD")){
vCardEnd = TRUE;
}
if (SettingName.Mid(0,2) == wxT("FN")){
vCardFN = TRUE;
}
if (SettingName == wxT("VERSION") && SettingValue == wxT("4.0")){
vCardVersion = 4.0;
}
if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){
vCardVersion = 3.0;
}
if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){
vCardVersion = 2.0;
}
SettingValue.Trim();
if (SettingValue.Right(2) != wxT("\r\n")){
SettingValue.Append(wxT("\r\n"));
}
SettingNames.Add(SettingName, 1);
SettingValues.Add(SettingValue, 1);
++SettingCount;
}
void vCard::AddRaw(wxString SettingName, wxString SettingValue){
// Add data to the vCard in raw mode.
// Check data to make sure that it meets the required
// vCard 4.0 specifications.
if (SettingName == wxT("BEGIN") && SettingValue == wxT("VCARD")){
vCardBegin = TRUE;
}
if (SettingName == wxT("END") && SettingValue == wxT("VCARD")){
vCardEnd = TRUE;
}
if (SettingName.Mid(0,2) == wxT("FN")){
vCardFN = TRUE;
}
if (SettingName == wxT("VERSION") && SettingValue == wxT("4.0")){
vCardVersion = 4.0;
}
if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){
vCardVersion = 3.0;
}
if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){
vCardVersion = 2.0;
}
SettingValue.Trim();
if (SettingValue.Right(2) != wxT("\r\n")){
SettingValue.Append(wxT("\r\n"));
}
SettingNames.Add(SettingName, 1);
SettingValues.Add(SettingValue, 1);
++SettingCount;
}
wxString vCard::Get(wxString SettingName){
// Get values from the vCard object.
wxString SettingValue;
// Look for the setting name.
for (int i = 0; i < SettingCount; i++){
if (SettingNames[i] == SettingName){
SettingValue = SettingValues[i];
SettingValue.Trim(TRUE);
while (SettingValues[(i + 1)].Mid(0, 1) == wxT(" ") || SettingValues[(i + 1)].Mid(0, 1) == wxT("\t")){
SettingValue.Trim();
SettingValue.Append(SettingValues[(i + 1)]);
i++;
}
return SettingValue;
}
}
return wxEmptyString;
}
vCardName vCard::GetName(){
// Get the name from the vCard object.
vCardName NameData;
ArrayvCardOutData NameArray = this->GetByPartial(wxT("N"));
//wxString NameDataGet = NameArray.PropValues[0];
if (NameArray.PropValues.Count() == 0)
{
// Use FN if there is no N values set.
wxString fullName = this->Get(wxT("FN"));
NameData.Forename = fullName;
return NameData;
}
wxString NameDataGet = NameArray.PropValues[0];
std::map SplitPoints;
std::map SplitLength;
std::map::iterator SLiter;
// Process the name data to get the required information.
int intPropertyLen = NameDataGet.Len();
int intSplitsFound = 0;
int intSplitSize = 0;
int intPrevValue = 0;
for (int i = 0; i <= intPropertyLen; i++){
intSplitSize++;
if (NameDataGet.Mid(i, 1) == wxT(";") && NameDataGet.Mid((i - 1), 1) != wxT("\\")){
intSplitsFound++;
SplitPoints.insert(std::make_pair(intSplitsFound, (i + 1)));
if (intSplitsFound == 4){
SplitLength.insert(std::make_pair(intSplitsFound, (intSplitSize - 1)));
break;
} else {
SplitLength.insert(std::make_pair(intSplitsFound, (intSplitSize - 1)));
}
intSplitSize = 0;
}
}
for (std::map::iterator intiter = SplitPoints.begin();
intiter != SplitPoints.end(); ++intiter){
if (intiter->first == 1){
// Deal with family name.
SLiter = SplitLength.find(1);
NameData.Surname = NameDataGet.Mid(0, SLiter->second);
intPrevValue = intiter->second;
} else if (intiter->first == 2){
// Deal with given names.
SLiter = SplitLength.find(2);
NameData.Forename = NameDataGet.Mid(intPrevValue, SLiter->second);
intPrevValue = intiter->second;
} else if (intiter->first == 3){
// Deal with additional names.
SLiter = SplitLength.find(3);
NameData.OtherNames = NameDataGet.Mid(intPrevValue, SLiter->second);
intPrevValue = intiter->second;
} else if (intiter->first == 4){
// Deal with honorifix prefixes and suffixes.
SLiter = SplitLength.find(4);
NameData.Title = NameDataGet.Mid(intPrevValue, SLiter->second);
intPrevValue = intiter->second;
NameData.Suffix = NameDataGet.Mid(intPrevValue);
}
}
return NameData;
}
ArrayvCardOutData vCard::GetByPartial(wxString SettingName){
// Get data from the vCard object based on a partial match.
ArrayvCardOutData vCardOutData;
wxArrayString SettingList;
wxString SettingValueCurrent;
wxString SettingValue;
int SettingNameLen;
int SettingNameSeek;
bool FirstToken = TRUE;
SettingNameLen = SettingName.Len();
for (int i = 0; i < SettingCount; i++){
if (SettingNames[i].Mid(0, SettingNameLen) == SettingName){
SettingValue = SettingValues[i];
SettingNameSeek = i;
while (SettingValues[(i + 1)].Mid(0, 1) == wxT(" ") || SettingValues[(i + 1)].Mid(0, 1) == wxT("\t")){
if (FirstToken == TRUE){
SettingValue.Trim(FALSE);
SettingValue.Trim(TRUE);
FirstToken = FALSE;
}
SettingValueCurrent = SettingValues[(i + 1)];
SettingValueCurrent.Trim(FALSE);
SettingValueCurrent.Trim(TRUE);
SettingValue.Append(SettingValueCurrent);
i++;
}
//SettingList.Add(SettingNames[SettingNameSeek] + wxT(":") + SettingValue);
vCardOutData.PropData.Add(SettingNames[SettingNameSeek]);
vCardOutData.PropValues.Add(SettingValue);
vCardOutData.PropCount++;
}
}
/*for (int i = 0; i < SettingCount; i++){
if (SettingNames[i].Mid(0, SettingNameLen) == SettingName){
SettingValue = SettingValues[i];
SettingNameSeek = i;
while (SettingValues[(i + 1)].Mid(0, 1) == wxT(" ") || SettingValues[(i + 1)].Mid(0, 1) == wxT("\t")){
SettingValueCurrent = SettingValues[(i + 1)];
SettingValueCurrent.Trim(FALSE);
SettingValueCurrent.Trim(TRUE);
SettingValue.Append(SettingValueCurrent);
i++;
}
//SettingList.Add(SettingNames[SettingNameSeek] + wxT(":") + SettingValue);
vCardOutData.PropData.Add(SettingName);
vCardOutData.PropData.Add(SettingValue);
}
}*/
return vCardOutData;
}
wxString vCard::GetById(int id){
// Get data from the vCard object based on ID.
// Unimplemented.
return wxT("");
}
int vCard::WriteFile(wxString WriteFilename){
// Write the vCard to a file using the WriteFilename given.
// Open the file and begin writing data into the file.
wxString SettingName;
wxString SettingValue;
wxString SettingLine;
SettingCount = SettingNames.GetCount();
wxFile ContactFile;
if (ContactFile.Create(WriteFilename, TRUE, wxS_DEFAULT) == FALSE){
return 1;
}
for (int i = 0; i < SettingCount; i++){
SettingLine = SettingNames[i] + wxT(":") + SettingValues[i];
int SettingLineLen = SettingLine.Len();
int intDivider = 74;
int intSeek = 0;
int intLineSeek = 0;
bool FirstLine = TRUE;
// Remember to round down the calculation.
while (intSeek < SettingLineLen){
if ((intLineSeek == intDivider && FirstLine == TRUE) ||
(intLineSeek == (intDivider - 1) && FirstLine == FALSE)){
SettingLine.insert(intSeek, wxT("\r\n "));
intSeek = intSeek + 3;
SettingLineLen = SettingLineLen + 3;
intLineSeek = 0;
FirstLine = FALSE;
}
intSeek++;
intLineSeek++;
}
ContactFile.Write(SettingLine);
}
ContactFile.Close();
return 0;
}
int vCard::LoadFile(wxString LoadFilename){
// Load data from a file using the LoadFilename given.
wxFFile ContactFile;
wxString wxSContactString;
vCardFilename = LoadFilename;
// Check if we are using wxWidgets version 2.8 or less and
// execute the required command accordingly.
#if wxABI_VERSION < 20900
ContactFile.Open(LoadFilename.c_str(), wxT("r"));
#else
ContactFile.Open(LoadFilename, wxT("r"));
#endif
if (ContactFile.IsOpened() == FALSE){
return 1;
}
ContactFile.ReadAll(&wxSContactString, wxConvAuto());
ContactFile.Close();
ProcessString(&wxSContactString);
return 0;
}
int vCard::LoadString(wxString ContactData){
// Load data from a wxString.
ProcessString(&ContactData);
return 0;
}
void vCard::ProcessString(wxString *ContactDataInc){
// Process data from a wxString pointer.
// Split the vCards (if there are more than one vCard in the file).
wxString ContactLine;
int ContactLineLen;
bool ExtraLineSeek = FALSE;
int QuoteBreakPoint = 0;
bool PropertyFind = FALSE;
bool QuoteMode = FALSE;
wxString wxSPropertyNextLine;
wxString wxSProperty;
wxString wxSPropertySeg1;
wxString wxSPropertySeg2;
bool FoundBegin = FALSE;
bool FirstContact = TRUE;
wxString FirstContactData;
wxString ContactData;
int ContactCount = 0;
wxStringTokenizer wSTContactFileLines(*ContactDataInc, wxT("\r\n"));
while(wSTContactFileLines.HasMoreTokens() == TRUE){
ContactLine = wSTContactFileLines.GetNextToken();
if (ContactLine == wxT("BEGIN:VCARD")){
if (FoundBegin == TRUE){
// No END:VCARD was found so discard current data.
ContactData.Clear();
if (FirstContact == TRUE){
FirstContactData.Clear();
}
}
FoundBegin = TRUE;
FirstContactData.Append(ContactLine + wxT("\r\n"));
ContactData.Append(ContactLine + wxT("\r\n"));
} else if (ContactLine == wxT("END:VCARD") && FoundBegin == TRUE){
if (FirstContact == TRUE){
FirstContact = FALSE;
FirstContactData.Append(ContactLine + wxT("\r\n"));
}
ContactData.Append(ContactLine + wxT("\r\n"));
Cards.insert(std::make_pair(ContactCount, ContactData));
ContactCount++;
} else if (FoundBegin == TRUE){
if (FirstContact == TRUE){
FirstContactData.Append(ContactLine + wxT("\r\n"));
}
ContactData.Append(ContactLine + wxT("\r\n"));
}
}
ContactLine.Clear();
// Split the lines.
std::map ContactFileLines;
std::map::iterator striter;
wxStringTokenizer wSTFirstContactLines(FirstContactData, wxT("\r\n"));
int ContactLineSeek = 0;
while (wSTFirstContactLines.HasMoreTokens() == TRUE){
ContactLine = wSTFirstContactLines.GetNextToken();
ContactFileLines.insert(std::make_pair(ContactLineSeek, ContactLine));
ContactLineSeek++;
}
for (std::map::iterator iter = ContactFileLines.begin();
iter != ContactFileLines.end(); ++iter){
// Find the colon which splits the start bit from the data part.
ContactLine = iter->second;
while (ExtraLineSeek == TRUE){
// Check if there is extra data on the next line
// (indicated by space or tab at the start) and add data.
iter++;
if (iter == ContactFileLines.end()){
iter--;
break;
}
wxSPropertyNextLine = iter->second;
if (wxSPropertyNextLine.Mid(0, 1) == wxT(" ") || wxSPropertyNextLine.Mid(0, 1) == wxT("\t")){
wxSPropertyNextLine.Remove(0, 1);
//wxSPropertyNextLine.Trim(FALSE);
//ContactLine.Trim();
ContactLine.Append(wxSPropertyNextLine);
} else {
iter--;
ExtraLineSeek = FALSE;
}
}
ContactLineLen = ContactLine.Len();
// Make sure we are not in quotation mode.
// Make sure colon does not have \ or \\ before it.
for (int i = 0; i <= ContactLineLen; i++){
if ((ContactLine.Mid(i, 1) == wxT(";") || ContactLine.Mid(i, 1) == wxT(":")) && PropertyFind == TRUE){
PropertyFind = FALSE;
} else if (PropertyFind == TRUE){
wxSProperty.Append(ContactLine.Mid(i, 1));
}
if (ContactLine.Mid(i, 1) == wxT("\"")){
if (QuoteMode == TRUE){
QuoteMode = FALSE;
} else {
QuoteMode = TRUE;
}
}
if (ContactLine.Mid(i, 1) == wxT(":") && ContactLine.Mid((i - 1), 1) != wxT("\\") && QuoteMode == FALSE){
QuoteBreakPoint = i;
break;
}
}
// Split that line at the point into two variables (ignore the colon).
wxSPropertySeg1 = ContactLine.Mid(0, QuoteBreakPoint);
wxSPropertySeg2 = ContactLine.Mid((QuoteBreakPoint + 1));
// Insert both into the vCard data file.
AddRaw(wxSPropertySeg1, wxSPropertySeg2);
QuoteMode = FALSE;
PropertyFind = TRUE;
ExtraLineSeek = TRUE;
ContactLineLen = 0;
QuoteBreakPoint = 0;
ContactLine.Clear();
wxSProperty.Clear();
}
}
wxString vCard::WriteString(){
// Write the vCard file into a wxString.
// Open the file and begin writing data into the file.
wxString SettingName;
wxString SettingValue;
wxString SettingLine;
wxString SettingFinal;
SettingCount = SettingNames.GetCount();
for (int i = 0; i < SettingCount; i++){
SettingLine = SettingNames[i] + wxT(":") + SettingValues[i];
int SettingLineLen = SettingLine.Len();
int intDivider = 74;
int intSeek = 0;
int intLineSeek = 0;
bool FirstLine = TRUE;
// Remember to round down the calculation.
while (intSeek < SettingLineLen){
if ((intLineSeek == intDivider && FirstLine == TRUE) ||
(intLineSeek == (intDivider - 1) && FirstLine == FALSE)){
SettingLine.insert(intSeek, wxT("\r\n "));
intSeek = intSeek + 3;
SettingLineLen = SettingLineLen + 3;
intLineSeek = 0;
FirstLine = FALSE;
}
intSeek++;
intLineSeek++;
}
SettingFinal.Append(SettingLine);
}
return SettingFinal;
}
bool vCard::MeetBaseSpecification(){
// Check and see if the vCard object meets the base specification
// of vCard 4.0.
if (vCardBegin == TRUE && vCardEnd == TRUE && vCardFN == TRUE &&
vCardVersion == 4.0){
return TRUE;
} else {
return FALSE;
}
}
wxString vCard::Convert(wxString SettingValue, bool ReplaceMode){
// Check for backslashes used for commas, newlines and
// backslashes used for values.
if (ReplaceMode == TRUE){
SettingValue.Replace(wxT("\\n"), wxT("\n"));
SettingValue.Replace(wxT("\\,"), wxT(","));
SettingValue.Replace(wxT("\\;"), wxT(";"));
SettingValue.Replace(wxT("\\\\"), wxT("\\"));
} else {
SettingValue.Replace(wxT("\\"), wxT("\\\\"));
SettingValue.Replace(wxT("\n"), wxT("\\n"));
SettingValue.Replace(wxT(","), wxT("\\,"));
SettingValue.Replace(wxT(";"), wxT("\\;"));
SettingValue = SettingValue + wxT("\n");
}
return SettingValue;
}
wxString vCard::GetFilename(){
// Get the filename associated with the vCard object.
return vCardFilename;
}
std::map* vCard::GetAllCards(){
// Get all of vCards within the vCard object.
return &Cards;
}