// ContactDataObject.cpp - Client Data 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 "ContactDataObject.h" ContactLoadStatus ContactDataObject::LoadFile(wxString Filename){ if (!wxFileExists(Filename)){ return CONTACTLOAD_FILEMISSING; } wxFile ContactFile; if (!ContactFile.Open(Filename, wxFile::read, wxS_DEFAULT)){ return CONTACTLOAD_FILEERROR; } // Check that the vCard is a valid vCard 4.0 file. vCard vCard4FormatCheck; vCard4FormatCheck.LoadFile(Filename); if (vCard4FormatCheck.Get("VERSION") != wxT("4.0")){ return CONTACTLOAD_FILEINVALIDFORMAT; } // Check that the vCard meets the base specification. if (!vCard4FormatCheck.MeetBaseSpecification()){ return CONTACTLOAD_FILEBASESPECFAIL; } wxStringTokenizer wSTContactFileLines(vCard4FormatCheck.WriteString(), wxT("\r\n")); std::map ContactFileLines; int ContactLineSeek = 0; while (wSTContactFileLines.HasMoreTokens() == TRUE){ wxString ContactLine = wSTContactFileLines.GetNextToken(); ContactFileLines.insert(std::make_pair(ContactLineSeek, ContactLine)); ContactLineSeek++; } wxString wxSPropertyNextLine; bool ExtraLineSeek = TRUE; bool QuoteMode = FALSE; bool PropertyFind = TRUE; bool KindProcessed = FALSE; bool NameProcessed = FALSE; int ContactLineLen = 0; int QuoteBreakPoint = 0; int GroupCount = 0; int FNCount = 0; wxString ContactLine; wxString PropertyLine; wxString PropertySeg1; wxString PropertySeg2; wxString PropertyNextLine; wxString Property; for (std::map::iterator iter = ContactFileLines.begin(); iter != ContactFileLines.end(); ++iter){ ExtraLineSeek = TRUE; QuoteMode = FALSE; PropertyFind = TRUE; ContactLineLen = 0; QuoteBreakPoint = 0; ContactLine.Clear(); PropertyLine.Clear(); PropertySeg1.Clear(); PropertySeg2.Clear(); Property.Clear(); 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; } PropertyNextLine = iter->second; if (PropertyNextLine.Mid(0, 1) == wxT(" ") || PropertyNextLine.Mid(0, 1) == wxT("\t")){ PropertyNextLine.Remove(0, 1); ContactLine.Append(PropertyNextLine); } 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){ Property.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). PropertySeg1 = ContactLine.Mid(0, QuoteBreakPoint); PropertySeg2 = ContactLine.Mid((QuoteBreakPoint + 1)); if (Property == wxT("KIND") && KindProcessed == FALSE){ ProcessKind(PropertySeg2); } else if (Property == wxT("MEMBER")){ ProcessMember(PropertySeg1, PropertySeg2, &GroupCount); GroupCount++; } else if (Property == wxT("FN")){ ProcessFN(PropertySeg1, PropertySeg2, &FNCount); FNCount++; } else if (Property == wxT("N") && NameProcessed == FALSE){ ProcessN(PropertySeg1, PropertySeg2); NameProcessed = TRUE; } } return CONTACTLOAD_OK; } void ContactDataObject::ProcessKind(wxString KindType){ if (KindType == wxT("individual")){ ContactKind = CONTACTKIND_INDIVIDUAL; } else if (KindType == wxT("group")){ ContactKind = CONTACTKIND_GROUP; } else if (KindType == wxT("org")){ ContactKind = CONTACTKIND_ORGANISATION; } else if (KindType == wxT("location")){ ContactKind = CONTACTKIND_LOCATION; } else { ContactKind = CONTACTKIND_NONE; } } void ContactDataObject::ProcessMember(wxString PropertySeg1, wxString PropertySeg2, int *GroupCount){ std::map SplitPoints; std::map SplitLength; int intPrevValue = 8; int intPref = 0; int intType = 0; SplitValues(&PropertySeg1, &SplitPoints, &SplitLength, intPrevValue); intPrevValue = 7; wxString PropertyName; wxString PropertyValue; wxString PropertyData; wxString PropertyTokens; std::map::iterator SLiter; bool FirstToken = TRUE; for (std::map::iterator intiter = SplitPoints.begin(); intiter != SplitPoints.end(); ++intiter){ SLiter = SplitLength.find(intiter->first); PropertyData = PropertySeg1.Mid(intPrevValue, (SLiter->second)); wxStringTokenizer PropertyElement (PropertyData, wxT("=")); PropertyName = PropertyElement.GetNextToken(); PropertyValue = PropertyElement.GetNextToken(); intPrevValue = intiter->second; CaptureString(&PropertyValue, FALSE); if (PropertyName == wxT("ALTID")){ GroupsListAltID.erase(*GroupCount); GroupsListAltID.insert(std::make_pair(*GroupCount, PropertyValue)); } else if (PropertyName == wxT("PID")){ GroupsListPID.erase(*GroupCount); GroupsListPID.insert(std::make_pair(*GroupCount, PropertyValue)); } else if (PropertyName == wxT("PREF")){ int PriorityNumber = 0; bool ValidNumber = TRUE; try{ PriorityNumber = std::stoi(PropertyValue.ToStdString()); } catch(std::invalid_argument &e){ ValidNumber = FALSE; } if (ValidNumber == TRUE){ GroupsListPref.erase(*GroupCount); GroupsListPref.insert(std::make_pair(*GroupCount, PriorityNumber)); } } else if (PropertyName == wxT("MEDIATYPE")){ GroupsListMediaType.erase(*GroupCount); GroupsListMediaType.insert(std::make_pair(*GroupCount, PropertyValue)); } else if (!PropertyName.IsEmpty() && !PropertyValue.IsEmpty()){ if (FirstToken == TRUE){ PropertyTokens.Append(PropertyName + wxT("=") + PropertyValue); FirstToken = FALSE; } else { PropertyTokens.Append(wxT(";") + PropertyName + wxT("=") + PropertyValue); } } } GroupsList.insert(std::make_pair(*GroupCount, PropertySeg2)); if (!PropertyTokens.IsEmpty()){ GroupsListTokens.insert(std::make_pair(*GroupCount, PropertyTokens)); } } void ContactDataObject::ProcessFN(wxString PropertySeg1, wxString PropertySeg2, int *FNCount){ std::map SplitPoints; std::map SplitLength; int intPrevValue = 4; int intPref = 0; int intType = 0; SplitValues(&PropertySeg1, &SplitPoints, &SplitLength, intPrevValue); intPrevValue = 3; wxString PropertyName; wxString PropertyValue; wxString PropertyData; wxString PropertyTokens; std::map::iterator SLiter; bool FirstToken = TRUE; for (std::map::iterator intiter = SplitPoints.begin(); intiter != SplitPoints.end(); ++intiter){ SLiter = SplitLength.find(intiter->first); PropertyData = PropertySeg1.Mid(intPrevValue, (SLiter->second)); wxStringTokenizer PropertyElement (PropertyData, wxT("=")); PropertyName = PropertyElement.GetNextToken(); PropertyValue = PropertyElement.GetNextToken(); intPrevValue = intiter->second; CaptureString(&PropertyValue, FALSE); if (PropertyName == wxT("TYPE")){ if (!PropertyValue.IsEmpty() || PropertyValue == wxT("home") || PropertyValue == wxT("work") ){ FullNamesListType.erase(*FNCount); FullNamesListType.insert(std::make_pair(*FNCount, PropertyValue)); } } else if (PropertyName == wxT("LANGUAGE")){ FullNamesListLanguage.erase(*FNCount); FullNamesListLanguage.insert(std::make_pair(*FNCount, PropertyValue)); } else if (PropertyName == wxT("ALTID")){ FullNamesListAltID.erase(*FNCount); FullNamesListAltID.insert(std::make_pair(*FNCount, PropertyValue)); } else if (PropertyName == wxT("PID")){ FullNamesListPID.erase(*FNCount); FullNamesListPID.insert(std::make_pair(*FNCount, PropertyValue)); } else if (PropertyName == wxT("PREF")){ int PriorityNumber = 0; bool ValidNumber = TRUE; try{ PriorityNumber = std::stoi(PropertyValue.ToStdString()); } catch(std::invalid_argument &e){ ValidNumber = FALSE; } if (ValidNumber == TRUE){ FullNamesListPref.erase(*FNCount); FullNamesListPref.insert(std::make_pair(*FNCount, PriorityNumber)); } } else if (!PropertyName.IsEmpty() && !PropertyValue.IsEmpty()){ if (FirstToken == TRUE){ PropertyTokens.Append(PropertyName + wxT("=") + PropertyValue); FirstToken = FALSE; } else { PropertyTokens.Append(wxT(";") + PropertyName + wxT("=") + PropertyValue); } } } FullNamesList.insert(std::make_pair(*FNCount, PropertySeg2)); if (!PropertyTokens.IsEmpty()){ FullNamesListTokens.insert(std::make_pair(*FNCount, PropertyTokens)); } } void ContactDataObject::ProcessN(wxString PropertySeg1, wxString PropertySeg2){ std::map SplitPoints; std::map SplitLength; int intPrevValue = 3; int intPref = 0; int intType = 0; SplitValues(&PropertySeg1, &SplitPoints, &SplitLength, intPrevValue); intPrevValue = 2; NameForename = PropertySeg2; wxString PropertyName; wxString PropertyValue; wxString PropertyData; wxString PropertyTokens; std::map::iterator SLiter; bool FirstToken = TRUE; for (std::map::iterator intiter = SplitPoints.begin(); intiter != SplitPoints.end(); ++intiter){ SLiter = SplitLength.find(intiter->first); PropertyData = PropertySeg1.Mid(intPrevValue, (SLiter->second)); wxStringTokenizer PropertyElement (PropertyData, wxT("=")); PropertyName = PropertyElement.GetNextToken(); PropertyValue = PropertyElement.GetNextToken(); intPrevValue = intiter->second; CaptureString(&PropertyValue, FALSE); if (PropertyName == wxT("ALTID")){ NameAltID = PropertyValue; } else if (PropertyName == wxT("LANGUAGE")){ NameLanguage = PropertyValue; } } } void SplitValues(wxString *PropertyLine, std::map *SplitPoints, std::map *SplitLength, int intSize){ size_t intPropertyLen = PropertyLine->Len(); int intSplitsFound = 0; int intSplitSize = 0; int intSplitSeek = 0; for (int i = intSize; i <= intPropertyLen; i++){ intSplitSize++; if (PropertyLine->Mid(i, 1) == wxT(";") && PropertyLine->Mid((i - 1), 1) != wxT("\\")){ if (intSplitsFound == 0){ SplitLength->insert(std::make_pair(intSplitsFound, (intSplitSize))); } else { SplitLength->insert(std::make_pair(intSplitsFound, (intSplitSize - 1))); } SplitPoints->insert(std::make_pair(intSplitsFound, (i + 1))); intSplitsFound++; intSplitSeek = i; intSplitSize = 0; } } if (intSplitsFound == 0){ SplitPoints->insert(std::make_pair(intSplitsFound, (8 + 1))); SplitLength->insert(std::make_pair(intSplitsFound, intSplitSize)); } else { SplitPoints->insert(std::make_pair(intSplitsFound, (intSplitSeek + 1))); SplitLength->insert(std::make_pair(intSplitsFound, intSplitSize)); } }