1 // vcard.cpp - vCard Object
3 // (c) 2012-2015 Xestia Software Development.
5 // This file is part of Xestia Address Book.
7 // Xestia Address Book is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by the
9 // Free Software Foundation, version 3 of the license.
11 // Xestia Address Book is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License along
17 // with Xestia Address Book. If not, see <http://www.gnu.org/licenses/>
22 #include <wx/tokenzr.h>
25 // vcard.cpp - Deals with vCard 4.0 formatted files meeting the
26 // RFC 6350 specification.
36 void vCard::Add(wxString SettingName, wxString SettingValue, bool ReplaceMode){
38 // Check for backslashes used for commas, newlines and
39 // backslashes used for values.
41 if (ReplaceMode == TRUE){
43 SettingValue.Replace(wxT("\\n"), wxT("\n"));
44 SettingValue.Replace(wxT("\\,"), wxT(","));
45 SettingValue.Replace(wxT("\\:"), wxT(":"));
46 SettingValue.Replace(wxT("\\\\"), wxT("\\"));
50 SettingValue.Replace(wxT("\\"), wxT("\\\\"));
51 SettingValue.Replace(wxT("\n"), wxT("\\n"));
52 SettingValue.Replace(wxT(","), wxT("\\,"));
53 SettingValue.Replace(wxT(":"), wxT("\\:"));
54 SettingValue = SettingValue + wxT("\n");
58 // Check data to make sure that it meets the required
59 // vCard 4.0 specifications.
61 if (SettingName == wxT("BEGIN") && SettingValue == wxT("VCARD")){
65 if (SettingName == wxT("END") && SettingValue == wxT("VCARD")){
69 if (SettingName.Mid(0,2) == wxT("FN")){
73 if (SettingName == wxT("VERSION") && SettingValue == wxT("4.0")){
77 if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){
81 if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){
87 if (SettingValue.Right(2) != wxT("\r\n")){
89 SettingValue.Append(wxT("\r\n"));
93 SettingNames.Add(SettingName, 1);
94 SettingValues.Add(SettingValue, 1);
99 void vCard::AddRaw(wxString SettingName, wxString SettingValue){
101 // Check data to make sure that it meets the required
102 // vCard 4.0 specifications.
104 if (SettingName == wxT("BEGIN") && SettingValue == wxT("VCARD")){
108 if (SettingName == wxT("END") && SettingValue == wxT("VCARD")){
112 if (SettingName.Mid(0,2) == wxT("FN")){
116 if (SettingName == wxT("VERSION") && SettingValue == wxT("4.0")){
120 if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){
124 if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){
130 if (SettingValue.Right(2) != wxT("\r\n")){
132 SettingValue.Append(wxT("\r\n"));
136 SettingNames.Add(SettingName, 1);
137 SettingValues.Add(SettingValue, 1);
142 wxString vCard::Get(wxString SettingName){
144 wxString SettingValue;
146 // Look for the setting name.
148 for (int i = 0; i < SettingCount; i++){
150 if (SettingNames[i] == SettingName){
152 SettingValue = SettingValues[i];
153 SettingValue.Trim(TRUE);
155 while (SettingValues[(i + 1)].Mid(0, 1) == wxT(" ") || SettingValues[(i + 1)].Mid(0, 1) == wxT("\t")){
158 SettingValue.Append(SettingValues[(i + 1)]);
167 return wxEmptyString;
171 vCardName vCard::GetName(){
174 ArrayvCardOutData NameArray = this->GetByPartial(wxT("N"));
175 //wxString NameDataGet = NameArray.PropValues[0];
176 wxString NameDataGet = NameArray.PropValues[0];
177 std::map<int, int> SplitPoints;
178 std::map<int, int> SplitLength;
179 std::map<int, int>::iterator SLiter;
181 // Process the name data to get the required information.
183 int intPropertyLen = NameDataGet.Len();
184 int intSplitSeek = 0;
185 int intSplitsFound = 0;
186 int intSplitSize = 0;
187 int intPrevValue = 0;
189 for (int i = 0; i <= intPropertyLen; i++){
193 if (NameDataGet.Mid(i, 1) == wxT(";") && NameDataGet.Mid((i - 1), 1) != wxT("\\")){
196 SplitPoints.insert(std::make_pair(intSplitsFound, (i + 1)));
198 if (intSplitsFound == 4){
200 SplitLength.insert(std::make_pair(intSplitsFound, (intSplitSize - 1)));
205 SplitLength.insert(std::make_pair(intSplitsFound, (intSplitSize - 1)));
215 for (std::map<int, int>::iterator intiter = SplitPoints.begin();
216 intiter != SplitPoints.end(); ++intiter){
218 if (intiter->first == 1){
220 // Deal with family name.
222 SLiter = SplitLength.find(1);
224 NameData.Surname = NameDataGet.Mid(0, SLiter->second);
225 intPrevValue = intiter->second;
227 } else if (intiter->first == 2){
229 // Deal with given names.
231 SLiter = SplitLength.find(2);
233 NameData.Forename = NameDataGet.Mid(intPrevValue, SLiter->second);
234 intPrevValue = intiter->second;
237 } else if (intiter->first == 3){
239 // Deal with additional names.
241 SLiter = SplitLength.find(3);
243 NameData.OtherNames = NameDataGet.Mid(intPrevValue, SLiter->second);
244 intPrevValue = intiter->second;
246 } else if (intiter->first == 4){
248 // Deal with honorifix prefixes and suffixes.
249 SLiter = SplitLength.find(4);
251 NameData.Title = NameDataGet.Mid(intPrevValue, SLiter->second);
252 intPrevValue = intiter->second;
253 NameData.Suffix = NameDataGet.Mid(intPrevValue);
264 ArrayvCardOutData vCard::GetByPartial(wxString SettingName){
266 ArrayvCardOutData vCardOutData;
267 wxArrayString SettingList;
268 wxString SettingValueCurrent;
269 wxString SettingValue;
272 bool FirstToken = TRUE;
274 SettingNameLen = SettingName.Len();
276 for (int i = 0; i < SettingCount; i++){
278 if (SettingNames[i].Mid(0, SettingNameLen) == SettingName){
280 SettingValue = SettingValues[i];
283 while (SettingValues[(i + 1)].Mid(0, 1) == wxT(" ") || SettingValues[(i + 1)].Mid(0, 1) == wxT("\t")){
285 if (FirstToken == TRUE){
287 SettingValue.Trim(FALSE);
288 SettingValue.Trim(TRUE);
293 SettingValueCurrent = SettingValues[(i + 1)];
294 SettingValueCurrent.Trim(FALSE);
295 SettingValueCurrent.Trim(TRUE);
297 SettingValue.Append(SettingValueCurrent);
303 //SettingList.Add(SettingNames[SettingNameSeek] + wxT(":") + SettingValue);
304 vCardOutData.PropData.Add(SettingNames[SettingNameSeek]);
305 vCardOutData.PropValues.Add(SettingValue);
306 vCardOutData.PropCount++;
311 /*for (int i = 0; i < SettingCount; i++){
312 if (SettingNames[i].Mid(0, SettingNameLen) == SettingName){
314 SettingValue = SettingValues[i];
317 while (SettingValues[(i + 1)].Mid(0, 1) == wxT(" ") || SettingValues[(i + 1)].Mid(0, 1) == wxT("\t")){
319 SettingValueCurrent = SettingValues[(i + 1)];
320 SettingValueCurrent.Trim(FALSE);
321 SettingValueCurrent.Trim(TRUE);
323 SettingValue.Append(SettingValueCurrent);
329 //SettingList.Add(SettingNames[SettingNameSeek] + wxT(":") + SettingValue);
330 vCardOutData.PropData.Add(SettingName);
331 vCardOutData.PropData.Add(SettingValue);
340 wxString vCard::GetById(int id){
345 int vCard::WriteFile(wxString WriteFilename){
347 // Open the file and begin writing data into the file.
349 wxString SettingName;
350 wxString SettingValue;
351 wxString SettingLine;
353 SettingCount = SettingNames.GetCount();
356 if (ContactFile.Create(WriteFilename, TRUE, wxS_DEFAULT) == FALSE){
360 for (int i = 0; i < SettingCount; i++){
362 SettingLine = SettingNames[i] + wxT(":") + SettingValues[i];
364 int SettingLineLen = SettingLine.Len();
366 int intTimes = floor((SettingLine.Len() / intDivider));
370 bool FirstLine = TRUE;
372 // Remember to round down the calculation.
374 while (intSeek < SettingLineLen){
376 if ((intLineSeek == intDivider && FirstLine == TRUE) ||
377 (intLineSeek == (intDivider - 1) && FirstLine == FALSE)){
379 SettingLine.insert(intSeek, wxT("\r\n "));
380 intSeek = intSeek + 3;
381 SettingLineLen = SettingLineLen + 3;
383 intPrevLine = intSeek;
395 for (int x = 0; x < intTimes; x++){
398 SettingLine.insert((intDivider - 1), wxT("\r\n "));
399 } else if (x == intTimes){
403 SettingLine.insert((intDivider * (x+1)) + (x * 3), wxT("\r\n "));
407 intTimes = floor(SettingLine.Len() / intDivider);
413 ContactFile.Write(SettingLine);
423 int vCard::LoadFile(wxString LoadFilename){
427 wxString wxSContactString;
429 vCardFilename = LoadFilename;
431 // Check if we are using wxWidgets version 2.8 or less and
432 // execute the required command accordingly.
434 #if wxABI_VERSION < 20900
435 ContactFile.Open(LoadFilename.c_str(), wxT("r"));
437 ContactFile.Open(LoadFilename, wxT("r"));
440 if (ContactFile.IsOpened() == FALSE){
446 ContactFile.ReadAll(&wxSContactString, wxConvAuto());
450 ProcessString(&wxSContactString);
456 int vCard::LoadString(wxString ContactData){
458 ProcessString(&ContactData);
464 void vCard::ProcessString(wxString *ContactDataInc){
466 // Split the vCards (if there are more than one vCard in the file).
468 wxString ContactLine;
471 bool ExtraLineSeek = FALSE;
472 int QuoteBreakPoint = 0;
474 bool PropertyFind = FALSE;
475 bool QuoteMode = FALSE;
477 wxString wxSPropertyNextLine;
478 wxString wxSProperty;
479 wxString wxSPropertySeg1;
480 wxString wxSPropertySeg2;
482 bool FoundBegin = FALSE;
483 bool FoundEnd = FALSE;
484 bool FirstContact = TRUE;
485 wxString FirstContactData;
486 wxString ContactData;
487 int ContactCount = 0;
489 wxStringTokenizer wSTContactFileLines(*ContactDataInc, wxT("\r\n"));
491 while(wSTContactFileLines.HasMoreTokens() == TRUE){
493 ContactLine = wSTContactFileLines.GetNextToken();
495 if (ContactLine == wxT("BEGIN:VCARD")){
497 if (FoundBegin == TRUE){
499 // No END:VCARD was found so discard current data.
503 if (FirstContact == TRUE){
505 FirstContactData.Clear();
513 FirstContactData.Append(ContactLine + wxT("\r\n"));
514 ContactData.Append(ContactLine + wxT("\r\n"));
516 } else if (ContactLine == wxT("END:VCARD") && FoundBegin == TRUE){
518 if (FirstContact == TRUE){
520 FirstContact = FALSE;
521 FirstContactData.Append(ContactLine + wxT("\r\n"));
525 ContactData.Append(ContactLine + wxT("\r\n"));
527 Cards.insert(std::make_pair(ContactCount, ContactData));
531 } else if (FoundBegin == TRUE){
533 if (FirstContact == TRUE){
535 FirstContactData.Append(ContactLine + wxT("\r\n"));
539 ContactData.Append(ContactLine + wxT("\r\n"));
549 std::map<int, wxString> ContactFileLines;
550 std::map<int, wxString>::iterator striter;
552 wxStringTokenizer wSTFirstContactLines(FirstContactData, wxT("\r\n"));
554 int ContactLineSeek = 0;
556 while (wSTFirstContactLines.HasMoreTokens() == TRUE){
558 ContactLine = wSTFirstContactLines.GetNextToken();
559 ContactFileLines.insert(std::make_pair(ContactLineSeek, ContactLine));
564 for (std::map<int,wxString>::iterator iter = ContactFileLines.begin();
565 iter != ContactFileLines.end(); ++iter){
567 // Find the colon which splits the start bit from the data part.
569 ContactLine = iter->second;
571 while (ExtraLineSeek == TRUE){
573 // Check if there is extra data on the next line
574 // (indicated by space or tab at the start) and add data.
578 if (iter == ContactFileLines.end()){
585 wxSPropertyNextLine = iter->second;
588 if (wxSPropertyNextLine.Mid(0, 1) == wxT(" ") || wxSPropertyNextLine.Mid(0, 1) == wxT("\t")){
590 wxSPropertyNextLine.Remove(0, 1);
591 //wxSPropertyNextLine.Trim(FALSE);
592 //ContactLine.Trim();
593 ContactLine.Append(wxSPropertyNextLine);
598 ExtraLineSeek = FALSE;
604 ContactLineLen = ContactLine.Len();
606 // Make sure we are not in quotation mode.
607 // Make sure colon does not have \ or \\ before it.
609 for (int i = 0; i <= ContactLineLen; i++){
611 if ((ContactLine.Mid(i, 1) == wxT(";") || ContactLine.Mid(i, 1) == wxT(":")) && PropertyFind == TRUE){
613 PropertyFind = FALSE;
615 } else if (PropertyFind == TRUE){
617 wxSProperty.Append(ContactLine.Mid(i, 1));
621 if (ContactLine.Mid(i, 1) == wxT("\"")){
623 if (QuoteMode == TRUE){
635 if (ContactLine.Mid(i, 1) == wxT(":") && ContactLine.Mid((i - 1), 1) != wxT("\\") && QuoteMode == FALSE){
644 // Split that line at the point into two variables (ignore the colon).
646 wxSPropertySeg1 = ContactLine.Mid(0, QuoteBreakPoint);
647 wxSPropertySeg2 = ContactLine.Mid((QuoteBreakPoint + 1));
649 // Insert both into the vCard data file.
651 AddRaw(wxSPropertySeg1, wxSPropertySeg2);
655 ExtraLineSeek = TRUE;
666 wxString vCard::WriteString(){
668 // Open the file and begin writing data into the file.
670 wxString SettingName;
671 wxString SettingValue;
672 wxString SettingLine;
673 wxString SettingFinal;
675 SettingCount = SettingNames.GetCount();
677 for (int i = 0; i < SettingCount; i++){
679 SettingLine = SettingNames[i] + wxT(":") + SettingValues[i];
681 int SettingLineLen = SettingLine.Len();
683 int intTimes = floor((SettingLine.Len() / intDivider));
687 bool FirstLine = TRUE;
689 // Remember to round down the calculation.
691 while (intSeek < SettingLineLen){
693 if ((intLineSeek == intDivider && FirstLine == TRUE) ||
694 (intLineSeek == (intDivider - 1) && FirstLine == FALSE)){
696 SettingLine.insert(intSeek, wxT("\r\n "));
697 intSeek = intSeek + 3;
698 SettingLineLen = SettingLineLen + 3;
700 intPrevLine = intSeek;
710 SettingFinal.Append(SettingLine);
718 bool vCard::MeetBaseSpecification(){
719 // Check and see if the vCard object meets the base specification
722 if (vCardBegin == TRUE && vCardEnd == TRUE && vCardFN == TRUE &&
723 vCardVersion == 4.0){
731 wxString vCard::Convert(wxString SettingValue, bool ReplaceMode){
733 // Check for backslashes used for commas, newlines and
734 // backslashes used for values.
736 if (ReplaceMode == TRUE){
738 SettingValue.Replace(wxT("\\n"), wxT("\n"));
739 SettingValue.Replace(wxT("\\,"), wxT(","));
740 SettingValue.Replace(wxT("\\;"), wxT(";"));
741 SettingValue.Replace(wxT("\\\\"), wxT("\\"));
745 SettingValue.Replace(wxT("\\"), wxT("\\\\"));
746 SettingValue.Replace(wxT("\n"), wxT("\\n"));
747 SettingValue.Replace(wxT(","), wxT("\\,"));
748 SettingValue.Replace(wxT(";"), wxT("\\;"));
749 SettingValue = SettingValue + wxT("\n");
757 wxString vCard::GetFilename(){
759 return vCardFilename;
763 std::map<int,wxString>* vCard::GetAllCards(){