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.
38 void vCard::Add(wxString SettingName, wxString SettingValue, bool ReplaceMode){
40 // Check for backslashes used for commas, newlines and
41 // backslashes used for values.
43 if (ReplaceMode == TRUE){
45 SettingValue.Replace(wxT("\\n"), wxT("\n"));
46 SettingValue.Replace(wxT("\\,"), wxT(","));
47 SettingValue.Replace(wxT("\\:"), wxT(":"));
48 SettingValue.Replace(wxT("\\\\"), wxT("\\"));
52 SettingValue.Replace(wxT("\\"), wxT("\\\\"));
53 SettingValue.Replace(wxT("\n"), wxT("\\n"));
54 SettingValue.Replace(wxT(","), wxT("\\,"));
55 SettingValue.Replace(wxT(":"), wxT("\\:"));
56 SettingValue = SettingValue + wxT("\n");
60 // Check data to make sure that it meets the required
61 // vCard 4.0 specifications.
63 if (SettingName == wxT("BEGIN") && SettingValue == wxT("VCARD")){
67 if (SettingName == wxT("END") && SettingValue == wxT("VCARD")){
71 if (SettingName.Mid(0,2) == wxT("FN")){
75 if (SettingName == wxT("VERSION") && SettingValue == wxT("4.0")){
79 if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){
83 if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){
89 if (SettingValue.Right(2) != wxT("\r\n")){
91 SettingValue.Append(wxT("\r\n"));
95 SettingNames.Add(SettingName, 1);
96 SettingValues.Add(SettingValue, 1);
102 void vCard::AddRaw(wxString SettingName, wxString SettingValue){
104 // Check data to make sure that it meets the required
105 // vCard 4.0 specifications.
107 if (SettingName == wxT("BEGIN") && SettingValue == wxT("VCARD")){
111 if (SettingName == wxT("END") && SettingValue == wxT("VCARD")){
115 if (SettingName.Mid(0,2) == wxT("FN")){
119 if (SettingName == wxT("VERSION") && SettingValue == wxT("4.0")){
123 if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){
127 if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){
133 if (SettingValue.Right(2) != wxT("\r\n")){
135 SettingValue.Append(wxT("\r\n"));
139 SettingNames.Add(SettingName, 1);
140 SettingValues.Add(SettingValue, 1);
146 wxString vCard::Get(wxString SettingName){
148 wxString SettingValue;
150 // Look for the setting name.
152 for (int i = 0; i < SettingCount; i++){
154 if (SettingNames[i] == SettingName){
156 SettingValue = SettingValues[i];
157 SettingValue.Trim(TRUE);
159 while (SettingValues[(i + 1)].Mid(0, 1) == wxT(" ") || SettingValues[(i + 1)].Mid(0, 1) == wxT("\t")){
162 SettingValue.Append(SettingValues[(i + 1)]);
174 return wxEmptyString;
178 vCardName vCard::GetName(){
181 ArrayvCardOutData NameArray = this->GetByPartial(wxT("N"));
182 //wxString NameDataGet = NameArray.PropValues[0];
183 wxString NameDataGet = NameArray.PropValues[0];
184 std::map<int, int> SplitPoints;
185 std::map<int, int> SplitLength;
186 std::map<int, int>::iterator SLiter;
188 // Process the name data to get the required information.
190 int intPropertyLen = NameDataGet.Len();
191 int intSplitSeek = 0;
192 int intSplitsFound = 0;
193 int intSplitSize = 0;
194 int intPrevValue = 0;
196 for (int i = 0; i <= intPropertyLen; i++){
200 if (NameDataGet.Mid(i, 1) == wxT(";") && NameDataGet.Mid((i - 1), 1) != wxT("\\")){
203 SplitPoints.insert(std::make_pair(intSplitsFound, (i + 1)));
205 if (intSplitsFound == 4){
207 SplitLength.insert(std::make_pair(intSplitsFound, (intSplitSize - 1)));
212 SplitLength.insert(std::make_pair(intSplitsFound, (intSplitSize - 1)));
222 for (std::map<int, int>::iterator intiter = SplitPoints.begin();
223 intiter != SplitPoints.end(); ++intiter){
225 if (intiter->first == 1){
227 // Deal with family name.
229 SLiter = SplitLength.find(1);
231 NameData.Surname = NameDataGet.Mid(0, SLiter->second);
232 intPrevValue = intiter->second;
234 } else if (intiter->first == 2){
236 // Deal with given names.
238 SLiter = SplitLength.find(2);
240 NameData.Forename = NameDataGet.Mid(intPrevValue, SLiter->second);
241 intPrevValue = intiter->second;
244 } else if (intiter->first == 3){
246 // Deal with additional names.
248 SLiter = SplitLength.find(3);
250 NameData.OtherNames = NameDataGet.Mid(intPrevValue, SLiter->second);
251 intPrevValue = intiter->second;
253 } else if (intiter->first == 4){
255 // Deal with honorifix prefixes and suffixes.
256 SLiter = SplitLength.find(4);
258 NameData.Title = NameDataGet.Mid(intPrevValue, SLiter->second);
259 intPrevValue = intiter->second;
260 NameData.Suffix = NameDataGet.Mid(intPrevValue);
271 ArrayvCardOutData vCard::GetByPartial(wxString SettingName){
273 ArrayvCardOutData vCardOutData;
274 wxArrayString SettingList;
275 wxString SettingValueCurrent;
276 wxString SettingValue;
279 bool FirstToken = TRUE;
281 SettingNameLen = SettingName.Len();
283 for (int i = 0; i < SettingCount; i++){
285 if (SettingNames[i].Mid(0, SettingNameLen) == SettingName){
287 SettingValue = SettingValues[i];
290 while (SettingValues[(i + 1)].Mid(0, 1) == wxT(" ") || SettingValues[(i + 1)].Mid(0, 1) == wxT("\t")){
292 if (FirstToken == TRUE){
294 SettingValue.Trim(FALSE);
295 SettingValue.Trim(TRUE);
300 SettingValueCurrent = SettingValues[(i + 1)];
301 SettingValueCurrent.Trim(FALSE);
302 SettingValueCurrent.Trim(TRUE);
304 SettingValue.Append(SettingValueCurrent);
310 //SettingList.Add(SettingNames[SettingNameSeek] + wxT(":") + SettingValue);
311 vCardOutData.PropData.Add(SettingNames[SettingNameSeek]);
312 vCardOutData.PropValues.Add(SettingValue);
313 vCardOutData.PropCount++;
318 /*for (int i = 0; i < SettingCount; i++){
319 if (SettingNames[i].Mid(0, SettingNameLen) == SettingName){
321 SettingValue = SettingValues[i];
324 while (SettingValues[(i + 1)].Mid(0, 1) == wxT(" ") || SettingValues[(i + 1)].Mid(0, 1) == wxT("\t")){
326 SettingValueCurrent = SettingValues[(i + 1)];
327 SettingValueCurrent.Trim(FALSE);
328 SettingValueCurrent.Trim(TRUE);
330 SettingValue.Append(SettingValueCurrent);
336 //SettingList.Add(SettingNames[SettingNameSeek] + wxT(":") + SettingValue);
337 vCardOutData.PropData.Add(SettingName);
338 vCardOutData.PropData.Add(SettingValue);
347 wxString vCard::GetById(int id){
354 int vCard::WriteFile(wxString WriteFilename){
356 // Open the file and begin writing data into the file.
358 wxString SettingName;
359 wxString SettingValue;
360 wxString SettingLine;
362 SettingCount = SettingNames.GetCount();
365 if (ContactFile.Create(WriteFilename, TRUE, wxS_DEFAULT) == FALSE){
369 for (int i = 0; i < SettingCount; i++){
371 SettingLine = SettingNames[i] + wxT(":") + SettingValues[i];
373 int SettingLineLen = SettingLine.Len();
375 int intTimes = floor((SettingLine.Len() / intDivider));
379 bool FirstLine = TRUE;
381 // Remember to round down the calculation.
383 while (intSeek < SettingLineLen){
385 if ((intLineSeek == intDivider && FirstLine == TRUE) ||
386 (intLineSeek == (intDivider - 1) && FirstLine == FALSE)){
388 SettingLine.insert(intSeek, wxT("\r\n "));
389 intSeek = intSeek + 3;
390 SettingLineLen = SettingLineLen + 3;
392 intPrevLine = intSeek;
404 for (int x = 0; x < intTimes; x++){
407 SettingLine.insert((intDivider - 1), wxT("\r\n "));
408 } else if (x == intTimes){
412 SettingLine.insert((intDivider * (x+1)) + (x * 3), wxT("\r\n "));
416 intTimes = floor(SettingLine.Len() / intDivider);
422 ContactFile.Write(SettingLine);
432 int vCard::LoadFile(wxString LoadFilename){
436 wxString wxSContactString;
438 vCardFilename = LoadFilename;
440 // Check if we are using wxWidgets version 2.8 or less and
441 // execute the required command accordingly.
443 #if wxABI_VERSION < 20900
444 ContactFile.Open(LoadFilename.c_str(), wxT("r"));
446 ContactFile.Open(LoadFilename, wxT("r"));
449 if (ContactFile.IsOpened() == FALSE){
455 ContactFile.ReadAll(&wxSContactString, wxConvAuto());
459 ProcessString(&wxSContactString);
465 int vCard::LoadString(wxString ContactData){
467 ProcessString(&ContactData);
473 void vCard::ProcessString(wxString *ContactDataInc){
475 // Split the vCards (if there are more than one vCard in the file).
477 wxString ContactLine;
480 bool ExtraLineSeek = FALSE;
481 int QuoteBreakPoint = 0;
483 bool PropertyFind = FALSE;
484 bool QuoteMode = FALSE;
486 wxString wxSPropertyNextLine;
487 wxString wxSProperty;
488 wxString wxSPropertySeg1;
489 wxString wxSPropertySeg2;
491 bool FoundBegin = FALSE;
492 bool FoundEnd = FALSE;
493 bool FirstContact = TRUE;
494 wxString FirstContactData;
495 wxString ContactData;
496 int ContactCount = 0;
498 wxStringTokenizer wSTContactFileLines(*ContactDataInc, wxT("\r\n"));
500 while(wSTContactFileLines.HasMoreTokens() == TRUE){
502 ContactLine = wSTContactFileLines.GetNextToken();
504 if (ContactLine == wxT("BEGIN:VCARD")){
506 if (FoundBegin == TRUE){
508 // No END:VCARD was found so discard current data.
512 if (FirstContact == TRUE){
514 FirstContactData.Clear();
522 FirstContactData.Append(ContactLine + wxT("\r\n"));
523 ContactData.Append(ContactLine + wxT("\r\n"));
525 } else if (ContactLine == wxT("END:VCARD") && FoundBegin == TRUE){
527 if (FirstContact == TRUE){
529 FirstContact = FALSE;
530 FirstContactData.Append(ContactLine + wxT("\r\n"));
534 ContactData.Append(ContactLine + wxT("\r\n"));
536 Cards.insert(std::make_pair(ContactCount, ContactData));
540 } else if (FoundBegin == TRUE){
542 if (FirstContact == TRUE){
544 FirstContactData.Append(ContactLine + wxT("\r\n"));
548 ContactData.Append(ContactLine + wxT("\r\n"));
558 std::map<int, wxString> ContactFileLines;
559 std::map<int, wxString>::iterator striter;
561 wxStringTokenizer wSTFirstContactLines(FirstContactData, wxT("\r\n"));
563 int ContactLineSeek = 0;
565 while (wSTFirstContactLines.HasMoreTokens() == TRUE){
567 ContactLine = wSTFirstContactLines.GetNextToken();
568 ContactFileLines.insert(std::make_pair(ContactLineSeek, ContactLine));
573 for (std::map<int,wxString>::iterator iter = ContactFileLines.begin();
574 iter != ContactFileLines.end(); ++iter){
576 // Find the colon which splits the start bit from the data part.
578 ContactLine = iter->second;
580 while (ExtraLineSeek == TRUE){
582 // Check if there is extra data on the next line
583 // (indicated by space or tab at the start) and add data.
587 if (iter == ContactFileLines.end()){
594 wxSPropertyNextLine = iter->second;
596 if (wxSPropertyNextLine.Mid(0, 1) == wxT(" ") || wxSPropertyNextLine.Mid(0, 1) == wxT("\t")){
598 wxSPropertyNextLine.Remove(0, 1);
599 //wxSPropertyNextLine.Trim(FALSE);
600 //ContactLine.Trim();
601 ContactLine.Append(wxSPropertyNextLine);
606 ExtraLineSeek = FALSE;
612 ContactLineLen = ContactLine.Len();
614 // Make sure we are not in quotation mode.
615 // Make sure colon does not have \ or \\ before it.
617 for (int i = 0; i <= ContactLineLen; i++){
619 if ((ContactLine.Mid(i, 1) == wxT(";") || ContactLine.Mid(i, 1) == wxT(":")) && PropertyFind == TRUE){
621 PropertyFind = FALSE;
623 } else if (PropertyFind == TRUE){
625 wxSProperty.Append(ContactLine.Mid(i, 1));
629 if (ContactLine.Mid(i, 1) == wxT("\"")){
631 if (QuoteMode == TRUE){
643 if (ContactLine.Mid(i, 1) == wxT(":") && ContactLine.Mid((i - 1), 1) != wxT("\\") && QuoteMode == FALSE){
652 // Split that line at the point into two variables (ignore the colon).
654 wxSPropertySeg1 = ContactLine.Mid(0, QuoteBreakPoint);
655 wxSPropertySeg2 = ContactLine.Mid((QuoteBreakPoint + 1));
657 // Insert both into the vCard data file.
659 AddRaw(wxSPropertySeg1, wxSPropertySeg2);
663 ExtraLineSeek = TRUE;
674 wxString vCard::WriteString(){
676 // Open the file and begin writing data into the file.
678 wxString SettingName;
679 wxString SettingValue;
680 wxString SettingLine;
681 wxString SettingFinal;
683 SettingCount = SettingNames.GetCount();
685 for (int i = 0; i < SettingCount; i++){
687 SettingLine = SettingNames[i] + wxT(":") + SettingValues[i];
689 int SettingLineLen = SettingLine.Len();
691 int intTimes = floor((SettingLine.Len() / intDivider));
695 bool FirstLine = TRUE;
697 // Remember to round down the calculation.
699 while (intSeek < SettingLineLen){
701 if ((intLineSeek == intDivider && FirstLine == TRUE) ||
702 (intLineSeek == (intDivider - 1) && FirstLine == FALSE)){
704 SettingLine.insert(intSeek, wxT("\r\n "));
705 intSeek = intSeek + 3;
706 SettingLineLen = SettingLineLen + 3;
708 intPrevLine = intSeek;
718 SettingFinal.Append(SettingLine);
726 bool vCard::MeetBaseSpecification(){
728 // Check and see if the vCard object meets the base specification
731 if (vCardBegin == TRUE && vCardEnd == TRUE && vCardFN == TRUE &&
732 vCardVersion == 4.0){
744 wxString vCard::Convert(wxString SettingValue, bool ReplaceMode){
746 // Check for backslashes used for commas, newlines and
747 // backslashes used for values.
749 if (ReplaceMode == TRUE){
751 SettingValue.Replace(wxT("\\n"), wxT("\n"));
752 SettingValue.Replace(wxT("\\,"), wxT(","));
753 SettingValue.Replace(wxT("\\;"), wxT(";"));
754 SettingValue.Replace(wxT("\\\\"), wxT("\\"));
758 SettingValue.Replace(wxT("\\"), wxT("\\\\"));
759 SettingValue.Replace(wxT("\n"), wxT("\\n"));
760 SettingValue.Replace(wxT(","), wxT("\\,"));
761 SettingValue.Replace(wxT(";"), wxT("\\;"));
762 SettingValue = SettingValue + wxT("\n");
770 wxString vCard::GetFilename(){
772 return vCardFilename;
776 std::map<int,wxString>* vCard::GetAllCards(){