1 // frmContactEditor-Save.cpp - frmContactEditor save contact subroutines.
3 // (c) 2012-2016 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/>
19 #include "frmContactEditor.h"
21 #include "../version.h"
22 #include "../vcard/vcard.h"
23 #include "../vcard/vcard34conv.h"
24 #include "../common/textprocessing.h"
25 #include "../common/preferences.h"
26 #include "../common/uuid.h"
27 #include "../common/dirs.h"
29 void frmContactEditor::SaveContact( wxCommandEvent& event )
32 // Do not save if the account is an unsupported account.
34 if (boolUnsupportedAccount == true){
36 wxMessageBox(_("Cannot make changes to a contact from an unsupported account type."), _("Unsupported account"), wxICON_ERROR);
42 // Check if Display As combo box has a value in it.
43 // Do not go any further if there is no value.
45 wxString cmbDisplayAsValue = cmbDisplayAs->GetValue();
47 if (cmbDisplayAsValue.IsEmpty()){
49 wxMessageBox(_("Display As value cannot be left blank."), _("Display As value empty"), wxICON_ERROR);
55 // Check if a value has been entered either in the Title,
56 // Forename, Surname, Other Names and Suffix text boxes.
58 if (txtTitle->IsEmpty() && txtForename->IsEmpty() && txtSurname->IsEmpty()
59 && txtOtherNames->IsEmpty() && txtSuffix->IsEmpty())
62 wxMessageBox(_("A value must be as minimum eithered in either the Title, Forename, Surname, Other Names or Suffix text boxes."), _("No name information entered"), wxICON_ERROR);
68 // Save the updated contact data.
71 wxString FilenameFinal;
72 bool ReplaceContact = FALSE;
74 if (StartupEditMode == TRUE){
76 if (cmbType->GetCurrentSelection() == 1 ||
77 cmbType->GetCurrentSelection() == 3 ||
78 cmbType->GetCurrentSelection() == 4){
82 // Mark contact for replacing.
84 ReplaceContact = TRUE;
89 } else if (cmbType->GetCurrentSelection() == 2){
91 if (IsGroup == FALSE){
93 // Mark contact for replacing.
95 ReplaceContact = TRUE;
102 if (ReplaceContact == TRUE){
104 wxString wxDelSplitFilename;
105 wxString wxDelFinalFilename;
106 wxString wxSDelDataURL;
107 wxStringTokenizer wSTDelFilename(wxSContactFilename, wxT("/"));
109 while(wSTDelFilename.HasMoreTokens()){
111 wxDelSplitFilename = wSTDelFilename.GetNextToken();
115 wxSDelDataURL = wxDelSplitFilename;
117 // Delete the contact from the server as it will be useless in certain
118 // address book clients.
120 ActMgrPtr->AddTask(2, cmbDisplayAs->GetValue(), wxSContactAccount, wxSDelDataURL, wxDelSplitFilename, wxSContactFilename, wxT(""));
122 // Clear the filename so the trigger to recreate the UID is done.
124 wxSContactFilename.Clear();
131 if (wxSContactFilename.IsEmpty()){
133 // Generate a random UUID.
135 ContactEditorData.UIDToken = GenerateUUID();
136 ContactEditorData.UIDToken = ContactEditorData.UIDToken.MakeUpper();
138 // Setup the filename.
140 FilenameFinal = GetAccountDir(wxSContactAccount, FALSE);
142 #if defined(__HAIKU__)
144 #elif defined(__WIN32__)
146 FilenameFinal = GetAccountDir(wxSContactAccount, FALSE);
147 FilenameFinal.Append(ContactEditorData.UIDToken);
148 FilenameFinal.Append(wxT(".vcf"));
149 wxSContactFilename = FilenameFinal;
153 FilenameFinal = GetAccountDir(wxSContactAccount, FALSE);
154 FilenameFinal.Append(ContactEditorData.UIDToken);
155 FilenameFinal.Append(wxT(".vcf"));
156 wxSContactFilename = FilenameFinal;
162 if (ContactEditorData.UIDToken.IsEmpty()){
164 // UID Token is empty. (Shouldn't be).
165 // Generate a new UID Token.
167 ContactEditorData.UIDToken = GenerateUUID();
168 ContactEditorData.UIDToken = ContactEditorData.UIDToken.MakeUpper();
172 FilenameFinal = wxSContactFilename;
176 // Setup the data and write it into the account folder.
178 // Begin preperations to write the contact to a file.
181 std::map<int,int>::iterator intiter;
182 std::map<int,wxString>::iterator striter;
184 // Set some values for saving.
186 ContactEditorData.NameForename = txtForename->GetValue();
187 ContactEditorData.NameSurname = txtSurname->GetValue();
188 ContactEditorData.NameOtherNames = txtOtherNames->GetValue();
189 ContactEditorData.NameTitle = txtTitle->GetValue();
190 ContactEditorData.NameSuffix = txtSuffix->GetValue();
192 ContactEditorData.GenderDetails = txtGenderDescription->GetValue();
194 // Process Birthday: Get Day, Month & Year.
196 wxDateTime BirthdayDate;
197 wxDateTime::Month BirthdayMonth;
200 wxString DataBeforeT;
202 wxString FinalBirthdayString;
203 bool ProcessDataAfterT = FALSE;
205 BirthdayDate = dapBirthday->GetValue();
207 if (!txtBirthday->IsEmpty()){
209 // Birthday value is text so use this.
211 ContactEditorData.Birthday = txtBirthday->GetValue();
213 } else if (BirthdayDate.IsValid()){
215 BirthdayDay = BirthdayDate.GetDay();
216 BirthdayMonth = BirthdayDate.GetMonth();
217 BirthdayYear = BirthdayDate.GetYear();
219 // Look for T and replace data before this.
221 wxStringTokenizer wSTDate(ContactEditorData.Birthday, wxT("T"));
223 while (wSTDate.HasMoreTokens()){
225 if (ProcessDataAfterT == FALSE){
227 DataBeforeT = wSTDate.GetNextToken();
228 ProcessDataAfterT = TRUE;
232 DataAfterT = wSTDate.GetNextToken();
239 // If there is not T then replace altogether.
241 wxString FinalBirthdayDay;
242 wxString FinalBirthdayMonth;
243 wxString FinalBirthdayYear;
245 if (BirthdayDay < 10){
247 FinalBirthdayDay = wxT("0") + wxString::Format(wxT("%i"), BirthdayDay);
251 FinalBirthdayDay = wxString::Format(wxT("%i"), BirthdayDay);
255 if (((int)BirthdayMonth + 1) < 10){
257 FinalBirthdayMonth = wxT("0") + wxString::Format(wxT("%i"), ((int)BirthdayMonth + 1));
261 FinalBirthdayMonth = wxString::Format(wxT("%i"), ((int)BirthdayMonth + 1));
265 if (BirthdayYear == 0){
267 FinalBirthdayYear = wxT("--");
271 FinalBirthdayYear = wxString::Format(wxT("%i"), BirthdayYear);
275 if (!DataAfterT.IsEmpty()){
277 FinalBirthdayString = FinalBirthdayYear + FinalBirthdayMonth + FinalBirthdayDay + wxT("T") + DataAfterT;
281 FinalBirthdayString = FinalBirthdayYear + FinalBirthdayMonth + FinalBirthdayDay;
285 if(!FinalBirthdayString.IsEmpty()){
287 ContactEditorData.Birthday = FinalBirthdayString;
293 // Process Anniversary: Get Day, Month & Year.
295 wxDateTime AnniversaryDate;
296 wxDateTime::Month AnniversaryMonth;
301 wxString FinalAnniversaryString;
302 ProcessDataAfterT = FALSE;
304 AnniversaryDate = dapAnniversary->GetValue();
306 if (!txtAnniversary->IsEmpty()){
308 // Birthday value is text so use this.
310 ContactEditorData.Anniversary = txtAnniversary->GetValue();
312 } else if (AnniversaryDate.IsValid()){
314 AnniversaryDay = AnniversaryDate.GetDay();
315 AnniversaryMonth = AnniversaryDate.GetMonth();
316 AnniversaryYear = AnniversaryDate.GetYear();
318 // Look for T and replace data before this.
320 wxStringTokenizer wSTDate(ContactEditorData.Anniversary, wxT("T"));
322 while (wSTDate.HasMoreTokens()){
324 if (ProcessDataAfterT == FALSE){
326 DataBeforeT = wSTDate.GetNextToken();
327 ProcessDataAfterT = TRUE;
331 DataAfterT = wSTDate.GetNextToken();
338 // If there is not T then replace altogether.
340 wxString FinalAnniversaryDay;
341 wxString FinalAnniversaryMonth;
342 wxString FinalAnniversaryYear;
344 if (AnniversaryDay < 10){
346 FinalAnniversaryDay = wxT("0") + wxString::Format(wxT("%i"), AnniversaryDay);
350 FinalAnniversaryDay = wxString::Format(wxT("%i"), AnniversaryDay);
354 if (((int)AnniversaryMonth + 1) < 10){
356 FinalAnniversaryMonth = wxT("0") + wxString::Format(wxT("%i"), ((int)AnniversaryMonth + 1));
360 FinalAnniversaryMonth = wxString::Format(wxT("%i"), ((int)AnniversaryMonth + 1));
364 if (AnniversaryYear == 0){
366 FinalAnniversaryYear = wxT("--");
370 FinalAnniversaryYear = wxString::Format(wxT("%i"), AnniversaryYear);
374 if (!DataAfterT.IsEmpty()){
376 FinalAnniversaryString = FinalAnniversaryYear + FinalAnniversaryMonth + FinalAnniversaryDay + wxT("T") + DataAfterT;
380 FinalAnniversaryString = FinalAnniversaryYear + FinalAnniversaryMonth + FinalAnniversaryDay;
384 if(!FinalAnniversaryString.IsEmpty()){
386 ContactEditorData.Anniversary = FinalAnniversaryString;
392 // Process full name.
394 if (ContactEditorData.FullNamesList.size() > 0){
396 ContactEditorData.FullNamesList[0] = cmbDisplayAs->GetValue();
400 ContactEditorData.FullNamesList.insert(std::make_pair(0, cmbDisplayAs->GetValue()));
401 ContactEditorData.FullNamesListAltID.insert(std::make_pair(0, wxT("")));
402 ContactEditorData.FullNamesListPID.insert(std::make_pair(0, wxT("")));
403 ContactEditorData.FullNamesListType.insert(std::make_pair(0, wxT("")));
404 ContactEditorData.FullNamesListLanguage.insert(std::make_pair(0, wxT("")));
405 ContactEditorData.FullNamesListPref.insert(std::make_pair(0, 0));
406 ContactEditorData.FullNamesListTokens.insert(std::make_pair(0, wxT("")));
411 ContactEditorData.SaveFile(FilenameFinal);
413 vCard34Conv ConvFileFun;
417 ConvFileFun.ConvertToV3(FilenameFinal, &wxSData);
419 wxString AccountDirPrefix;
423 #if defined(__HAIKU__)
425 #elif defined(__APPLE__)
427 PrefDir = GetUserPrefDir();
429 wxStringTokenizer wSTFilename(wxSContactFilename, wxT("/"));
431 #elif defined(__WIN32__)
433 PrefDir = GetUserPrefDir();
435 wxStringTokenizer wSTFilename(wxSContactFilename, wxT("\\"));
439 PrefDir = GetUserPrefDir();
441 wxStringTokenizer wSTFilename(wxSContactFilename, wxT("/"));
445 XABPreferences PrefData(PrefDir);
447 wxString AccountType;
449 for (int i = 0; i < PrefData.accounts.GetCount(); i++){
451 AccountDir = PrefData.accounts.GetAccountDirectory(i) + wxT(".carddav");
453 if (AccountDir == wxSContactAccount){
455 AccountDirPrefix = PrefData.accounts.GetAccountDirPrefix(i);
456 AccountDirPrefix.Trim();
457 AccountType = PrefData.accounts.GetAccountType(i);
464 wxString wxSplitFilename;
467 while(wSTFilename.HasMoreTokens()){
469 wxSplitFilename = wSTFilename.GetNextToken();
473 wxSDataURL = wxSplitFilename;
475 // Find out if the filename exists in the table.
477 if (AccountType == wxT("CardDAV") || AccountType == wxT("carddav")){
480 wxString ETagOriginal;
482 ETagDB *ETagDBPtr = NULL;
484 ETagDBPtr = ETagTmrPtr->GetPointer(wxSContactAccount);
486 wxString wxSETag = ETagDBPtr->GetETag(wxSplitFilename);
487 wxString wxSETagOrig = ETagDBPtr->GetETagOriginal(wxSplitFilename);
489 if (wxSETagOrig.IsEmpty()){
491 // Generate the ETag.
493 wxSETagOrig = wxString::Format(wxT("%X%X%X%X"), rand() % 1024, rand() % 1024, rand() % 1024, rand() % 1024);
497 if (wxSETag.IsEmpty()){
499 // Update empty ETag.
501 wxSETag = wxSETagOrig;
502 ETagDBPtr->AddETag(wxSplitFilename, wxSETag, "");
506 // Don't change original ETag.
508 wxSETag = wxString::Format(wxT("%X%X%X%X"), rand() % 1024, rand() % 1024, rand() % 1024, rand() % 1024);
509 ETagDBPtr->UpdateETag(wxSplitFilename, wxSETag);
513 if (EditMode == FALSE){
515 ActMgrPtr->AddTask(0, cmbDisplayAs->GetValue(), wxSContactAccount, wxSDataURL, wxSplitFilename, FilenameFinal, wxSData);
517 FMTimer.SetFilename(FilenameFinal);
518 FMTimer.UpdateTimestamp();
519 FMTimer.Start(10000, FALSE);
521 wxCommandEvent reloadevent(RELOADCONTACTLIST);
522 reloadevent.SetString(wxSContactAccount);
523 wxPostEvent(this->GetParent(), reloadevent);
527 ActMgrPtr->AddTask(1, cmbDisplayAs->GetValue(), wxSContactAccount, wxSDataURL, wxSplitFilename, FilenameFinal, wxSData);
528 FMTimer.UpdateTimestamp();
529 FMTimer.Start(10000, FALSE);
535 // Send a notification to update the main window
536 // with the new details.
541 // TODO: Workout nickname settings by priority and
546 NameData.Forename = txtForename->GetValue();
547 NameData.Surname = txtSurname->GetValue();
548 NameData.OtherNames = txtOtherNames->GetValue();
549 NameData.Title = txtTitle->GetValue();
550 NameData.Suffix = txtSuffix->GetValue();
552 if (this->GetParent() != nullptr)
554 ucd->ContactAccount = wxSContactAccount;
555 ucd->ContactFilename = FilenameFinal;
556 ucd->ContactName = cmbDisplayAs->GetValue();
557 ucd->ContactNameArray = NameData;
559 for (std::map<int,wxString>::iterator gniter = ContactEditorData.GeneralNicknamesList.begin();
560 gniter != ContactEditorData.GeneralNicknamesList.end(); gniter++){
562 ucd->ContactNickname = gniter->second;
567 wxCommandEvent event2(CE_UPDATECONTACTLIST);
568 event2.SetClientData(ucd);
569 wxPostEvent(MainPtr, event2);
576 void frmContactEditor::SaveCloseContact( wxCommandEvent& event )
579 // Save the updated contact data and close the form.
581 wxCommandEvent NullEvent;
582 this->SaveContact(NullEvent);