Home | News | Projects | Releases
Bugs | RFE | Repositories | Help
Improved checking of FN for meeting the base specification of vCard 4.0.
[xestiaab/.git] / source / vcard / vcard.cpp
1 // vcard.cpp - vCard Object
2 //
3 // (c) 2012-2015 Xestia Software Development.
4 //
5 // This file is part of Xestia Address Book.
6 //
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.
10 //
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.
15 //
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/>
19 #include "vcard.h"
20 #include <wx/file.h>
21 #include <wx/ffile.h>
22 #include <wx/tokenzr.h>
23 #include <cmath>
25 // vcard.cpp - Deals with vCard 4.0 formatted files meeting the
26 // RFC 6350 specification.
28 vCard::vCard(){
29     vCardBegin = FALSE;
30     vCardEnd = FALSE;
31     vCardFN = FALSE;
32     vCardVersion = 0.0;
33     SettingCount = 0;
34 }
36 void vCard::Add(wxString SettingName, wxString SettingValue, bool ReplaceMode){  
37     
38     // Check for backslashes used for commas, newlines and
39     // backslashes used for values.
40     
41     if (ReplaceMode == TRUE){
42     
43         SettingValue.Replace(wxT("\\n"), wxT("\n"));
44         SettingValue.Replace(wxT("\\,"), wxT(","));
45         SettingValue.Replace(wxT("\\:"), wxT(":"));
46         SettingValue.Replace(wxT("\\\\"), wxT("\\"));
47     
48     } else {
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");
55     
56     }
57   
58     // Check data to make sure that it meets the required
59     // vCard 4.0 specifications.
60     
61         if (SettingName == wxT("BEGIN") && SettingValue == wxT("VCARD")){
62                 vCardBegin = TRUE;
63         }
64     
65         if (SettingName == wxT("END") && SettingValue == wxT("VCARD")){
66                 vCardEnd = TRUE;
67         }
69         if (SettingName.Mid(0,2) == wxT("FN")){
70                 vCardFN = TRUE;
71         }
72     
73         if (SettingName == wxT("VERSION") && SettingValue == wxT("4.0")){
74                 vCardVersion = 4.0;
75         }
76     
77         if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){
78                 vCardVersion = 3.0;
79         }
80     
81         if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){
82                 vCardVersion = 2.0;
83         }
84     
85     SettingValue.Trim();    
86     
87     if (SettingValue.Right(2) != wxT("\r\n")){
88     
89         SettingValue.Append(wxT("\r\n"));
90     
91     }
92     
93     SettingNames.Add(SettingName, 1);
94     SettingValues.Add(SettingValue, 1);      
95     
96     ++SettingCount;
97 }
99 void vCard::AddRaw(wxString SettingName, wxString SettingValue){  
100   
101     // Check data to make sure that it meets the required
102     // vCard 4.0 specifications.
103     
104     if (SettingName == wxT("BEGIN") && SettingValue == wxT("VCARD")){
105         vCardBegin = TRUE;
106     }
107     
108     if (SettingName == wxT("END") && SettingValue == wxT("VCARD")){
109         vCardEnd = TRUE;
110     }
111     
112     if (SettingName.Mid(0,2) == wxT("FN")){
113         vCardFN = TRUE;
114     }
115     
116     if (SettingName == wxT("VERSION") && SettingValue == wxT("4.0")){   
117         vCardVersion = 4.0;
118     }
120     if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){   
121         vCardVersion = 3.0;
122     }
123     
124     if (SettingName == wxT("VERSION") && SettingValue == wxT("3.0")){   
125         vCardVersion = 2.0;
126     }
127     
128     SettingValue.Trim();
129     
130     if (SettingValue.Right(2) != wxT("\r\n")){
131     
132         SettingValue.Append(wxT("\r\n"));
133     
134     }
135         
136     SettingNames.Add(SettingName, 1);
137     SettingValues.Add(SettingValue, 1);      
138     
139     ++SettingCount;
142 wxString vCard::Get(wxString SettingName){
143   
144     wxString SettingValue;
145     
146     // Look for the setting name.
147     
148     for (int i = 0; i < SettingCount; i++){
149       
150         if (SettingNames[i] == SettingName){
151         
152             SettingValue = SettingValues[i];
153             SettingValue.Trim(TRUE);
154                     
155             while (SettingValues[(i + 1)].Mid(0, 1) == wxT(" ") || SettingValues[(i + 1)].Mid(0, 1) == wxT("\t")){
156                 
157                 SettingValue.Trim();
158                 SettingValue.Append(SettingValues[(i + 1)]);
159                 
160                 i++;
161             }
162             
163             return SettingValue;
164         }
165     }
167         return wxEmptyString;
171 vCardName vCard::GetName(){
173         vCardName NameData;
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;
180         
181         // Process the name data to get the required information.
182         
183         int intPropertyLen = NameDataGet.Len();
184         int intSplitSeek = 0;
185         int intSplitsFound = 0;
186         int intSplitSize = 0;
187         int intPrevValue = 0;                                   
188         
189         for (int i = 0; i <= intPropertyLen; i++){
191                 intSplitSize++;
192         
193                 if (NameDataGet.Mid(i, 1) == wxT(";") && NameDataGet.Mid((i - 1), 1) != wxT("\\")){
194         
195                         intSplitsFound++;
196                         SplitPoints.insert(std::make_pair(intSplitsFound, (i + 1)));
197                         
198                         if (intSplitsFound == 4){ 
199                         
200                                 SplitLength.insert(std::make_pair(intSplitsFound, (intSplitSize - 1)));
201                                 break; 
202                                 
203                         } else {
204                         
205                                 SplitLength.insert(std::make_pair(intSplitsFound, (intSplitSize - 1)));
206                         
207                         }
208                         
209                         intSplitSize = 0;                                       
210         
211                 }
213         }
214         
215         for (std::map<int, int>::iterator intiter = SplitPoints.begin(); 
216         intiter != SplitPoints.end(); ++intiter){
217         
218                 if (intiter->first == 1){
219                 
220                         // Deal with family name.
221                         
222                         SLiter = SplitLength.find(1);
224                         NameData.Surname = NameDataGet.Mid(0, SLiter->second);                          
225                         intPrevValue = intiter->second;
226                 
227                 } else if (intiter->first == 2){
228                 
229                         // Deal with given names.
230                         
231                         SLiter = SplitLength.find(2);
233                         NameData.Forename = NameDataGet.Mid(intPrevValue, SLiter->second);                      
234                         intPrevValue = intiter->second;
236                 
237                 } else if (intiter->first == 3){
238                 
239                         // Deal with additional names.
240                         
241                         SLiter = SplitLength.find(3);
243                         NameData.OtherNames = NameDataGet.Mid(intPrevValue, SLiter->second);
244                         intPrevValue = intiter->second;
245                 
246                 } else if (intiter->first == 4){
247                 
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);
254                 
255                 }
256         
257         }
258         
259         return NameData;
260         
264 ArrayvCardOutData vCard::GetByPartial(wxString SettingName){
266     ArrayvCardOutData vCardOutData;
267     wxArrayString SettingList;
268     wxString SettingValueCurrent;
269     wxString SettingValue;
270     int SettingNameLen;
271     int SettingNameSeek;
272     bool FirstToken = TRUE;
273     
274     SettingNameLen = SettingName.Len();
276     for (int i = 0; i < SettingCount; i++){
277     
278         if (SettingNames[i].Mid(0, SettingNameLen) == SettingName){
279             
280             SettingValue = SettingValues[i];
281             SettingNameSeek = i;            
282             
283             while (SettingValues[(i + 1)].Mid(0, 1) == wxT(" ") || SettingValues[(i + 1)].Mid(0, 1) == wxT("\t")){
284                 
285                 if (FirstToken == TRUE){
286                 
287                         SettingValue.Trim(FALSE);
288                         SettingValue.Trim(TRUE);                                
289                         FirstToken = FALSE;
290                 
291                 }
292                 
293                 SettingValueCurrent = SettingValues[(i + 1)];
294                 SettingValueCurrent.Trim(FALSE);
295                 SettingValueCurrent.Trim(TRUE);         
296                 
297                 SettingValue.Append(SettingValueCurrent);
298                 
299                 i++;
300                 
301             }
302             
303             //SettingList.Add(SettingNames[SettingNameSeek] + wxT(":") + SettingValue);
304             vCardOutData.PropData.Add(SettingNames[SettingNameSeek]);
305             vCardOutData.PropValues.Add(SettingValue);
306             vCardOutData.PropCount++;
307             
308         }
309     }
310     
311     /*for (int i = 0; i < SettingCount; i++){
312         if (SettingNames[i].Mid(0, SettingNameLen) == SettingName){
313             
314             SettingValue = SettingValues[i];
315             SettingNameSeek = i;            
316             
317             while (SettingValues[(i + 1)].Mid(0, 1) == wxT(" ") || SettingValues[(i + 1)].Mid(0, 1) == wxT("\t")){
318                 
319                 SettingValueCurrent = SettingValues[(i + 1)];
320                 SettingValueCurrent.Trim(FALSE);
321                 SettingValueCurrent.Trim(TRUE);         
322                 
323                 SettingValue.Append(SettingValueCurrent);
324                 
325                 i++;
326                 
327             }
328             
329             //SettingList.Add(SettingNames[SettingNameSeek] + wxT(":") + SettingValue);
330             vCardOutData.PropData.Add(SettingName);
331             vCardOutData.PropData.Add(SettingValue);
332             
333         }
334     }*/
335     
336     return vCardOutData;
340 wxString vCard::GetById(int id){
341         // Unimplemented.
342         return wxT("");
345 int vCard::WriteFile(wxString WriteFilename){
347     // Open the file and begin writing data into the file.
348     
349     wxString SettingName;
350     wxString SettingValue;
351     wxString SettingLine;
352     
353     SettingCount = SettingNames.GetCount();
354     
355     wxFile ContactFile;
356     if (ContactFile.Create(WriteFilename, TRUE, wxS_DEFAULT) == FALSE){
357         return 1;
358     }
359     
360     for (int i = 0; i < SettingCount; i++){
361     
362         SettingLine = SettingNames[i] + wxT(":") + SettingValues[i];
363     
364         int SettingLineLen = SettingLine.Len();
365         int intDivider = 74;
366         int intTimes = floor((SettingLine.Len() / intDivider));
367         int intSeek = 0;
368         int intLineSeek = 0;
369         int intPrevLine;
370         bool FirstLine = TRUE;
371     
372         // Remember to round down the calculation.
374         while (intSeek < SettingLineLen){
375         
376                 if ((intLineSeek == intDivider && FirstLine == TRUE) ||
377                 (intLineSeek == (intDivider - 1) && FirstLine == FALSE)){
378                 
379                         SettingLine.insert(intSeek, wxT("\r\n "));
380                         intSeek = intSeek + 3;
381                         SettingLineLen = SettingLineLen + 3;
382                         intLineSeek = 0;
383                         intPrevLine = intSeek;
384                         FirstLine = FALSE;
385                 
386                 }
387         
388                 intSeek++;
389                 intLineSeek++;
390         
391         }
393         /*
395         for (int x = 0; x < intTimes; x++){     
396         
397             if (x == 0){
398                 SettingLine.insert((intDivider - 1), wxT("\r\n "));
399             } else if (x == intTimes){
400             
401             } else {
402                 if (x < intDivider){
403                         SettingLine.insert((intDivider * (x+1)) + (x * 3), wxT("\r\n "));
404                 }
405             }
406             
407             intTimes = floor(SettingLine.Len() / intDivider);
408         
409         }
410         
411         */
412         
413         ContactFile.Write(SettingLine);
414         
415     }
416     
417     ContactFile.Close();
419     return 0;
423 int vCard::LoadFile(wxString LoadFilename){
425     wxFFile ContactFile;
426   
427     wxString wxSContactString;
428   
429     vCardFilename = LoadFilename;
430         
431     // Check if we are using wxWidgets version 2.8 or less and
432     // execute the required command accordingly.
433     
434 #if wxABI_VERSION < 20900
435     ContactFile.Open(LoadFilename.c_str(), wxT("r"));
436 #else
437     ContactFile.Open(LoadFilename, wxT("r"));
438 #endif  
439         
440     if (ContactFile.IsOpened() == FALSE){
441         
442                 return 1;
443         
444     }
445         
446     ContactFile.ReadAll(&wxSContactString, wxConvAuto());
447     
448     ContactFile.Close();
449     
450     ProcessString(&wxSContactString);
452         return 0;
456 int vCard::LoadString(wxString ContactData){
458     ProcessString(&ContactData);
460         return 0;
464 void vCard::ProcessString(wxString *ContactDataInc){
466     // Split the vCards (if there are more than one vCard in the file).
468     wxString ContactLine;
470     int ContactLineLen;
471     bool ExtraLineSeek = FALSE;
472     int QuoteBreakPoint = 0;
473     
474     bool PropertyFind = FALSE;
475     bool QuoteMode = FALSE;
476    
477     wxString wxSPropertyNextLine;
478     wxString wxSProperty;
479     wxString wxSPropertySeg1;
480     wxString wxSPropertySeg2;
481     
482     bool FoundBegin = FALSE;
483     bool FoundEnd = FALSE;
484     bool FirstContact = TRUE;
485     wxString FirstContactData;
486     wxString ContactData;
487     int ContactCount = 0;
488     
489     wxStringTokenizer wSTContactFileLines(*ContactDataInc, wxT("\r\n"));
490     
491     while(wSTContactFileLines.HasMoreTokens() == TRUE){
492     
493         ContactLine = wSTContactFileLines.GetNextToken();
494         
495         if (ContactLine == wxT("BEGIN:VCARD")){
496                 
497                 if (FoundBegin == TRUE){
498                 
499                         // No END:VCARD was found so discard current data.
500                         
501                         ContactData.Clear();
502                 
503                         if (FirstContact == TRUE){
504                         
505                                 FirstContactData.Clear();
506                         
507                         }
508                 
509                 }
510                 
511                 FoundBegin = TRUE;
512                 
513                 FirstContactData.Append(ContactLine + wxT("\r\n"));
514                 ContactData.Append(ContactLine + wxT("\r\n"));
515                 
516         } else if (ContactLine == wxT("END:VCARD") && FoundBegin == TRUE){
517         
518                 if (FirstContact == TRUE){
519                 
520                         FirstContact = FALSE;
521                         FirstContactData.Append(ContactLine + wxT("\r\n"));
522                 
523                 }
524                 
525                 ContactData.Append(ContactLine + wxT("\r\n"));
526                                 
527                 Cards.insert(std::make_pair(ContactCount, ContactData));
528         
529                 ContactCount++;
530         
531         } else if (FoundBegin == TRUE){
532         
533                 if (FirstContact == TRUE){
534                 
535                         FirstContactData.Append(ContactLine + wxT("\r\n"));
536                 
537                 }
538                 
539                 ContactData.Append(ContactLine + wxT("\r\n"));
540         
541         }
542     
543     }
545     ContactLine.Clear();
546     
547     // Split the lines.
548         
549     std::map<int, wxString> ContactFileLines;
550     std::map<int, wxString>::iterator striter;
551         
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));
560         ContactLineSeek++;              
561         
562     }
563     
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.
568         
569         ContactLine = iter->second;
570         
571         while (ExtraLineSeek == TRUE){
572         
573             // Check if there is extra data on the next line 
574             // (indicated by space or tab at the start) and add data.
575         
576             iter++;
577                 
578             if (iter == ContactFileLines.end()){
579                 
580                 iter--;
581                 break;
582                 
583             }                   
584         
585             wxSPropertyNextLine = iter->second;
586                 
587         
588             if (wxSPropertyNextLine.Mid(0, 1) == wxT(" ") || wxSPropertyNextLine.Mid(0, 1) == wxT("\t")){
589         
590                 wxSPropertyNextLine.Remove(0, 1);
591                 //wxSPropertyNextLine.Trim(FALSE);
592                 //ContactLine.Trim();
593                 ContactLine.Append(wxSPropertyNextLine);
594         
595             } else {
596                 
597                 iter--;
598                 ExtraLineSeek = FALSE;
599                 
600             }
601         
602         }
604         ContactLineLen = ContactLine.Len();
605         
606         // Make sure we are not in quotation mode.
607         // Make sure colon does not have \ or \\ before it.
608         
609         for (int i = 0; i <= ContactLineLen; i++){
610         
611             if ((ContactLine.Mid(i, 1) == wxT(";") || ContactLine.Mid(i, 1) == wxT(":")) && PropertyFind == TRUE){
612                 
613                         PropertyFind = FALSE;
614                 
615             } else if (PropertyFind == TRUE){
616                 
617                         wxSProperty.Append(ContactLine.Mid(i, 1));
618                 
619             }           
620         
621             if (ContactLine.Mid(i, 1) == wxT("\"")){
622                 
623                 if (QuoteMode == TRUE){
624                         
625                     QuoteMode = FALSE;
626                         
627                 } else {
628                 
629                     QuoteMode = TRUE;
630                                 
631                 }
632                 
633             }
634                 
635             if (ContactLine.Mid(i, 1) == wxT(":") && ContactLine.Mid((i - 1), 1) != wxT("\\") && QuoteMode == FALSE){
636                 
637                 QuoteBreakPoint = i;
638                 break;
639                 
640             }
641         
642         }
643         
644         // Split that line at the point into two variables (ignore the colon).
645         
646         wxSPropertySeg1 = ContactLine.Mid(0, QuoteBreakPoint);
647         wxSPropertySeg2 = ContactLine.Mid((QuoteBreakPoint + 1));
648         
649         // Insert both into the vCard data file.
650         
651         AddRaw(wxSPropertySeg1, wxSPropertySeg2);
652         
653         QuoteMode = FALSE;
654         PropertyFind = TRUE;
655         ExtraLineSeek = TRUE;
656         ContactLineLen = 0;
657         QuoteBreakPoint = 0;
658         ContactLine.Clear();
659         wxSProperty.Clear();
660         
661     }
666 wxString vCard::WriteString(){
668     // Open the file and begin writing data into the file.
669     
670     wxString SettingName;
671     wxString SettingValue;
672     wxString SettingLine;
673     wxString SettingFinal;
674     
675     SettingCount = SettingNames.GetCount();
676     
677     for (int i = 0; i < SettingCount; i++){
678     
679         SettingLine = SettingNames[i] + wxT(":") + SettingValues[i];
680     
681         int SettingLineLen = SettingLine.Len();
682         int intDivider = 74;
683         int intTimes = floor((SettingLine.Len() / intDivider));
684         int intSeek = 0;
685         int intLineSeek = 0;
686         int intPrevLine;
687         bool FirstLine = TRUE;
688     
689         // Remember to round down the calculation.
691         while (intSeek < SettingLineLen){
692         
693                 if ((intLineSeek == intDivider && FirstLine == TRUE) ||
694                 (intLineSeek == (intDivider - 1) && FirstLine == FALSE)){
695                 
696                         SettingLine.insert(intSeek, wxT("\r\n "));
697                         intSeek = intSeek + 3;
698                         SettingLineLen = SettingLineLen + 3;
699                         intLineSeek = 0;
700                         intPrevLine = intSeek;
701                         FirstLine = FALSE;
702                 
703                 }
704         
705                 intSeek++;
706                 intLineSeek++;
707         
708         }
709         
710         SettingFinal.Append(SettingLine);
711         
712     }
713     
714     return SettingFinal;
718 bool vCard::MeetBaseSpecification(){
719     // Check and see if the vCard object meets the base specification
720     // of vCard 4.0.
721     
722     if (vCardBegin == TRUE && vCardEnd == TRUE && vCardFN == TRUE &&
723         vCardVersion == 4.0){
724         return TRUE;
725     } else {
726         return FALSE;
727     }
728     
731 wxString vCard::Convert(wxString SettingValue, bool ReplaceMode){  
732     
733     // Check for backslashes used for commas, newlines and
734     // backslashes used for values.
735     
736     if (ReplaceMode == TRUE){
737     
738         SettingValue.Replace(wxT("\\n"), wxT("\n"));
739         SettingValue.Replace(wxT("\\,"), wxT(","));
740         SettingValue.Replace(wxT("\\;"), wxT(";"));
741         SettingValue.Replace(wxT("\\\\"), wxT("\\"));
742     
743     } else {
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");
750     
751     }
752     
753     return SettingValue;
754     
757 wxString vCard::GetFilename(){
759     return vCardFilename;
763 std::map<int,wxString>* vCard::GetAllCards(){
765     return &Cards;
Xestia Software Development
Yn Maystri
© 2006 - 2019 Xestia Software Development
Software

Xestia Address Book
Xestia Calendar
Development

Xestia Gelforn
Everything else

About
News
Privacy Policy