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);
41 // Check if Display As combo box has a value in it.
42 // Do not go any further if there is no value.
44 wxString cmbDisplayAsValue = cmbDisplayAs->GetValue();
46 if (cmbDisplayAsValue.IsEmpty()){
48 wxMessageBox(_("Display As value cannot be left blank."), _("Display As value empty"), wxICON_ERROR);
53 // Check if a value has been entered either in the Title,
54 // Forename, Surname, Other Names and Suffix text boxes.
56 if (txtTitle->IsEmpty() && txtForename->IsEmpty() && txtSurname->IsEmpty()
57 && txtOtherNames->IsEmpty() && txtSuffix->IsEmpty())
60 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);
66 // Save the updated contact data.
69 wxString FilenameFinal;
70 bool ReplaceContact = FALSE;
72 if (StartupEditMode == TRUE){
74 if (cmbType->GetCurrentSelection() == 1 ||
75 cmbType->GetCurrentSelection() == 3 ||
76 cmbType->GetCurrentSelection() == 4){
80 // Mark contact for replacing.
82 ReplaceContact = TRUE;
87 } else if (cmbType->GetCurrentSelection() == 2){
89 if (IsGroup == FALSE){
91 // Mark contact for replacing.
93 ReplaceContact = TRUE;
100 if (ReplaceContact == TRUE){
102 wxString wxDelSplitFilename;
103 wxString wxDelFinalFilename;
104 wxString wxSDelDataURL;
105 wxStringTokenizer wSTDelFilename(wxSContactFilename, wxT("/"));
107 while(wSTDelFilename.HasMoreTokens()){
109 wxDelSplitFilename = wSTDelFilename.GetNextToken();
113 wxSDelDataURL = wxDelSplitFilename;
115 // Delete the contact from the server as it will be useless in certain
116 // address book clients.
118 ActMgrPtr->AddTask(2, cmbDisplayAs->GetValue(), wxSContactAccount, wxSDelDataURL, wxDelSplitFilename, wxSContactFilename, wxT(""));
120 // Clear the filename so the trigger to recreate the UID is done.
122 wxSContactFilename.Clear();
129 if (wxSContactFilename.IsEmpty()){
131 // Generate a random UUID.
133 ContactEditorData.UIDToken = GenerateUUID();
134 ContactEditorData.UIDToken = ContactEditorData.UIDToken.MakeUpper();
136 // Setup the filename.
138 FilenameFinal = GetAccountDir(wxSContactAccount, FALSE);
140 #if defined(__HAIKU__)
142 #elif defined(__WIN32__)
144 FilenameFinal = GetAccountDir(wxSContactAccount, FALSE);
145 FilenameFinal.Append(ContactEditorData.UIDToken);
146 FilenameFinal.Append(wxT(".vcf"));
147 wxSContactFilename = FilenameFinal;
151 FilenameFinal = GetAccountDir(wxSContactAccount, FALSE);
152 FilenameFinal.Append(ContactEditorData.UIDToken);
153 FilenameFinal.Append(wxT(".vcf"));
154 wxSContactFilename = FilenameFinal;
160 if (ContactEditorData.UIDToken.IsEmpty()){
162 // UID Token is empty. (Shouldn't be).
163 // Generate a new UID Token.
165 ContactEditorData.UIDToken = GenerateUUID();
166 ContactEditorData.UIDToken = ContactEditorData.UIDToken.MakeUpper();
170 FilenameFinal = wxSContactFilename;
174 // Setup the data and write it into the account folder.
176 // Begin preperations to write the contact to a file.
179 std::map<int,int>::iterator intiter;
180 std::map<int,wxString>::iterator striter;
182 // Set some values for saving.
184 ContactEditorData.NameForename = txtForename->GetValue();
185 ContactEditorData.NameSurname = txtSurname->GetValue();
186 ContactEditorData.NameOtherNames = txtOtherNames->GetValue();
187 ContactEditorData.NameTitle = txtTitle->GetValue();
188 ContactEditorData.NameSuffix = txtSuffix->GetValue();
190 ContactEditorData.GenderDetails = txtGenderDescription->GetValue();
192 // Process Birthday: Get Day, Month & Year.
194 wxDateTime BirthdayDate;
195 wxDateTime::Month BirthdayMonth;
198 wxString DataBeforeT;
200 wxString FinalBirthdayString;
201 bool ProcessDataAfterT = FALSE;
203 BirthdayDate = dapBirthday->GetValue();
205 if (!txtBirthday->IsEmpty()){
207 // Birthday value is text so use this.
209 ContactEditorData.Birthday = txtBirthday->GetValue();
211 } else if (BirthdayDate.IsValid()){
213 BirthdayDay = BirthdayDate.GetDay();
214 BirthdayMonth = BirthdayDate.GetMonth();
215 BirthdayYear = BirthdayDate.GetYear();
217 // Look for T and replace data before this.
219 wxStringTokenizer wSTDate(ContactEditorData.Birthday, wxT("T"));
221 while (wSTDate.HasMoreTokens()){
223 if (ProcessDataAfterT == FALSE){
225 DataBeforeT = wSTDate.GetNextToken();
226 ProcessDataAfterT = TRUE;
230 DataAfterT = wSTDate.GetNextToken();
237 // If there is not T then replace altogether.
239 wxString FinalBirthdayDay;
240 wxString FinalBirthdayMonth;
241 wxString FinalBirthdayYear;
243 if (BirthdayDay < 10){
245 FinalBirthdayDay = wxT("0") + wxString::Format(wxT("%i"), BirthdayDay);
249 FinalBirthdayDay = wxString::Format(wxT("%i"), BirthdayDay);
253 if (((int)BirthdayMonth + 1) < 10){
255 FinalBirthdayMonth = wxT("0") + wxString::Format(wxT("%i"), ((int)BirthdayMonth + 1));
259 FinalBirthdayMonth = wxString::Format(wxT("%i"), ((int)BirthdayMonth + 1));
263 if (BirthdayYear == 0){
265 FinalBirthdayYear = wxT("--");
269 FinalBirthdayYear = wxString::Format(wxT("%i"), BirthdayYear);
273 if (!DataAfterT.IsEmpty()){
275 FinalBirthdayString = FinalBirthdayYear + FinalBirthdayMonth + FinalBirthdayDay + wxT("T") + DataAfterT;
279 FinalBirthdayString = FinalBirthdayYear + FinalBirthdayMonth + FinalBirthdayDay;
283 if(!FinalBirthdayString.IsEmpty()){
285 ContactEditorData.Birthday = FinalBirthdayString;
291 // Process Anniversary: Get Day, Month & Year.
293 wxDateTime AnniversaryDate;
294 wxDateTime::Month AnniversaryMonth;
299 wxString FinalAnniversaryString;
300 ProcessDataAfterT = FALSE;
302 AnniversaryDate = dapAnniversary->GetValue();
304 if (!txtAnniversary->IsEmpty()){
306 // Birthday value is text so use this.
308 ContactEditorData.Anniversary = txtAnniversary->GetValue();
310 } else if (AnniversaryDate.IsValid()){
312 AnniversaryDay = AnniversaryDate.GetDay();
313 AnniversaryMonth = AnniversaryDate.GetMonth();
314 AnniversaryYear = AnniversaryDate.GetYear();
316 // Look for T and replace data before this.
318 wxStringTokenizer wSTDate(ContactEditorData.Anniversary, wxT("T"));
320 while (wSTDate.HasMoreTokens()){
322 if (ProcessDataAfterT == FALSE){
324 DataBeforeT = wSTDate.GetNextToken();
325 ProcessDataAfterT = TRUE;
329 DataAfterT = wSTDate.GetNextToken();
336 // If there is not T then replace altogether.
338 wxString FinalAnniversaryDay;
339 wxString FinalAnniversaryMonth;
340 wxString FinalAnniversaryYear;
342 if (AnniversaryDay < 10){
344 FinalAnniversaryDay = wxT("0") + wxString::Format(wxT("%i"), AnniversaryDay);
348 FinalAnniversaryDay = wxString::Format(wxT("%i"), AnniversaryDay);
352 if (((int)AnniversaryMonth + 1) < 10){
354 FinalAnniversaryMonth = wxT("0") + wxString::Format(wxT("%i"), ((int)AnniversaryMonth + 1));
358 FinalAnniversaryMonth = wxString::Format(wxT("%i"), ((int)AnniversaryMonth + 1));
362 if (AnniversaryYear == 0){
364 FinalAnniversaryYear = wxT("--");
368 FinalAnniversaryYear = wxString::Format(wxT("%i"), AnniversaryYear);
372 if (!DataAfterT.IsEmpty()){
374 FinalAnniversaryString = FinalAnniversaryYear + FinalAnniversaryMonth + FinalAnniversaryDay + wxT("T") + DataAfterT;
378 FinalAnniversaryString = FinalAnniversaryYear + FinalAnniversaryMonth + FinalAnniversaryDay;
382 if(!FinalAnniversaryString.IsEmpty()){
384 ContactEditorData.Birthday = FinalAnniversaryString;
390 // Process full name.
392 if (ContactEditorData.FullNamesList.size() > 0){
394 ContactEditorData.FullNamesList[0] = cmbDisplayAs->GetValue();
398 ContactEditorData.FullNamesList.insert(std::make_pair(0, cmbDisplayAs->GetValue()));
399 ContactEditorData.FullNamesListAltID.insert(std::make_pair(0, wxT("")));
400 ContactEditorData.FullNamesListPID.insert(std::make_pair(0, wxT("")));
401 ContactEditorData.FullNamesListType.insert(std::make_pair(0, wxT("")));
402 ContactEditorData.FullNamesListLanguage.insert(std::make_pair(0, wxT("")));
403 ContactEditorData.FullNamesListPref.insert(std::make_pair(0, 0));
404 ContactEditorData.FullNamesListTokens.insert(std::make_pair(0, wxT("")));
409 ContactEditorData.SaveFile(FilenameFinal);
411 vCard34Conv ConvFileFun;
415 ConvFileFun.ConvertToV3(FilenameFinal, &wxSData);
417 wxString AccountDirPrefix;
421 #if defined(__HAIKU__)
423 #elif defined(__APPLE__)
425 PrefDir = GetUserPrefDir();
427 wxStringTokenizer wSTFilename(wxSContactFilename, wxT("/"));
429 #elif defined(__WIN32__)
431 PrefDir = GetUserPrefDir();
433 wxStringTokenizer wSTFilename(wxSContactFilename, wxT("\\"));
437 PrefDir = GetUserPrefDir();
439 wxStringTokenizer wSTFilename(wxSContactFilename, wxT("/"));
443 XABPreferences PrefData(PrefDir);
445 wxString AccountType;
447 for (int i = 0; i < PrefData.accounts.GetCount(); i++){
449 AccountDir = PrefData.accounts.GetAccountDirectory(i) + wxT(".carddav");
451 if (AccountDir == wxSContactAccount){
453 AccountDirPrefix = PrefData.accounts.GetAccountDirPrefix(i);
454 AccountDirPrefix.Trim();
455 AccountType = PrefData.accounts.GetAccountType(i);
462 wxString wxSplitFilename;
465 while(wSTFilename.HasMoreTokens()){
467 wxSplitFilename = wSTFilename.GetNextToken();
471 wxSDataURL = wxSplitFilename;
473 // Find out if the filename exists in the table.
475 if (AccountType == wxT("CardDAV") || AccountType == wxT("carddav")){
478 wxString ETagOriginal;
480 ETagDB *ETagDBPtr = NULL;
482 ETagDBPtr = ETagTmrPtr->GetPointer(wxSContactAccount);
484 wxString wxSETag = ETagDBPtr->GetETag(wxSplitFilename);
485 wxString wxSETagOrig = ETagDBPtr->GetETagOriginal(wxSplitFilename);
487 if (wxSETagOrig.IsEmpty()){
489 // Generate the ETag.
491 wxSETagOrig = wxString::Format(wxT("%X%X%X%X"), rand() % 1024, rand() % 1024, rand() % 1024, rand() % 1024);
495 if (wxSETag.IsEmpty()){
497 // Update empty ETag.
499 wxSETag = wxSETagOrig;
500 ETagDBPtr->AddETag(wxSplitFilename, wxSETag, "");
504 // Don't change original ETag.
506 wxSETag = wxString::Format(wxT("%X%X%X%X"), rand() % 1024, rand() % 1024, rand() % 1024, rand() % 1024);
507 ETagDBPtr->UpdateETag(wxSplitFilename, wxSETag);
511 if (EditMode == FALSE){
513 ActMgrPtr->AddTask(0, cmbDisplayAs->GetValue(), wxSContactAccount, wxSDataURL, wxSplitFilename, FilenameFinal, wxSData);
515 FMTimer.SetFilename(FilenameFinal);
516 FMTimer.UpdateTimestamp();
517 FMTimer.Start(10000, FALSE);
519 wxCommandEvent reloadevent(RELOADCONTACTLIST);
520 reloadevent.SetString(wxSContactAccount);
521 wxPostEvent(this->GetParent(), reloadevent);
525 ActMgrPtr->AddTask(1, cmbDisplayAs->GetValue(), wxSContactAccount, wxSDataURL, wxSplitFilename, FilenameFinal, wxSData);
526 FMTimer.UpdateTimestamp();
527 FMTimer.Start(10000, FALSE);
533 // Send a notification to update the main window
534 // with the new details.
539 // TODO: Workout nickname settings by priority and
544 NameData.Forename = txtForename->GetValue();
545 NameData.Surname = txtSurname->GetValue();
546 NameData.OtherNames = txtOtherNames->GetValue();
547 NameData.Title = txtTitle->GetValue();
548 NameData.Suffix = txtSuffix->GetValue();
550 if (this->GetParent() != nullptr)
552 ucd->ContactAccount = wxSContactAccount;
553 ucd->ContactFilename = FilenameFinal;
554 ucd->ContactName = cmbDisplayAs->GetValue();
555 ucd->ContactNameArray = NameData;
557 for (std::map<int,wxString>::iterator gniter = ContactEditorData.GeneralNicknamesList.begin();
558 gniter != ContactEditorData.GeneralNicknamesList.end(); gniter++){
560 ucd->ContactNickname = gniter->second;
565 wxCommandEvent event2(CE_UPDATECONTACTLIST);
566 event2.SetClientData(ucd);
567 wxPostEvent(MainPtr, event2);
572 void frmContactEditor::SaveCloseContact( wxCommandEvent& event )
575 // Save the updated contact data and close the form.
577 wxCommandEvent NullEvent;
578 this->SaveContact(NullEvent);