// 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; }