// frmContactEditor-Save.cpp - frmContactEditor save contact subroutines.
//
// (c) 2012-2016 Xestia Software Development.
//
// This file is part of Xestia Address Book.
//
// Xestia Address Book is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by the
// Free Software Foundation, version 3 of the license.
//
// Xestia Address Book is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with Xestia Address Book. If not, see
#include "frmContactEditor.h"
#include "../enums.h"
#include "../version.h"
#include "../vcard/vcard.h"
#include "../vcard/vcard34conv.h"
#include "../common/textprocessing.h"
#include "../common/preferences.h"
#include "../common/uuid.h"
#include "../common/dirs.h"
void frmContactEditor::SaveContact( wxCommandEvent& event )
{
// Do not save if the account is an unsupported account.
if (boolUnsupportedAccount == true){
wxMessageBox(_("Cannot make changes to a contact from an unsupported account type."), _("Unsupported account"), wxICON_ERROR);
return;
}
// Check if Display As combo box has a value in it.
// Do not go any further if there is no value.
wxString cmbDisplayAsValue = cmbDisplayAs->GetValue();
if (cmbDisplayAsValue.IsEmpty()){
wxMessageBox(_("Display As value cannot be left blank."), _("Display As value empty"), wxICON_ERROR);
return;
}
// Save the updated contact data.
//vCard ContactData;
wxString FilenameFinal;
bool ReplaceContact = FALSE;
if (StartupEditMode == TRUE){
if (cmbType->GetCurrentSelection() == 1 ||
cmbType->GetCurrentSelection() == 3 ||
cmbType->GetCurrentSelection() == 4){
if (IsGroup == TRUE){
// Mark contact for replacing.
ReplaceContact = TRUE;
IsGroup = FALSE;
}
} else if (cmbType->GetCurrentSelection() == 2){
if (IsGroup == FALSE){
// Mark contact for replacing.
ReplaceContact = TRUE;
IsGroup = TRUE;
}
}
if (ReplaceContact == TRUE){
wxString wxDelSplitFilename;
wxString wxDelFinalFilename;
wxString wxSDelDataURL;
wxStringTokenizer wSTDelFilename(wxSContactFilename, wxT("/"));
while(wSTDelFilename.HasMoreTokens()){
wxDelSplitFilename = wSTDelFilename.GetNextToken();
}
wxSDelDataURL = wxDelSplitFilename;
// Delete the contact from the server as it will be useless in certain
// address book clients.
ActMgrPtr->AddTask(2, cmbDisplayAs->GetValue(), wxSContactAccount, wxSDelDataURL, wxDelSplitFilename, wxSContactFilename, wxT(""));
// Clear the filename so the trigger to recreate the UID is done.
wxSContactFilename.Clear();
EditMode = FALSE;
}
}
if (wxSContactFilename.IsEmpty()){
// Generate a random UUID.
ContactEditorData.UIDToken = GenerateUUID();
ContactEditorData.UIDToken = ContactEditorData.UIDToken.MakeUpper();
// Setup the filename.
FilenameFinal = GetAccountDir(wxSContactAccount, FALSE);
#if defined(__HAIKU__)
#elif defined(__WIN32__)
FilenameFinal = GetAccountDir(wxSContactAccount, FALSE);
FilenameFinal.Append(ContactEditorData.UIDToken);
FilenameFinal.Append(wxT(".vcf"));
wxSContactFilename = FilenameFinal;
#else
FilenameFinal = GetAccountDir(wxSContactAccount, FALSE);
FilenameFinal.Append(ContactEditorData.UIDToken);
FilenameFinal.Append(wxT(".vcf"));
wxSContactFilename = FilenameFinal;
#endif
} else {
if (ContactEditorData.UIDToken.IsEmpty()){
// UID Token is empty. (Shouldn't be).
// Generate a new UID Token.
ContactEditorData.UIDToken = GenerateUUID();
ContactEditorData.UIDToken = ContactEditorData.UIDToken.MakeUpper();
}
FilenameFinal = wxSContactFilename;
}
// Setup the data and write it into the account folder.
// Begin preperations to write the contact to a file.
bool FNFirst = TRUE;
std::map::iterator intiter;
std::map::iterator striter;
// Set some values for saving.
ContactEditorData.NameForename = txtForename->GetValue();
ContactEditorData.NameSurname = txtSurname->GetValue();
ContactEditorData.NameOtherNames = txtOtherNames->GetValue();
ContactEditorData.NameTitle = txtTitle->GetValue();
ContactEditorData.NameSuffix = txtSuffix->GetValue();
ContactEditorData.GenderDetails = txtGenderDescription->GetValue();
// Process Birthday: Get Day, Month & Year.
wxDateTime BirthdayDate;
wxDateTime::Month BirthdayMonth;
int BirthdayDay;
int BirthdayYear;
wxString DataBeforeT;
wxString DataAfterT;
wxString FinalBirthdayString;
bool ProcessDataAfterT = FALSE;
BirthdayDate = dapBirthday->GetValue();
if (!txtBirthday->IsEmpty()){
// Birthday value is text so use this.
ContactEditorData.Birthday = txtBirthday->GetValue();
} else if (BirthdayDate.IsValid()){
BirthdayDay = BirthdayDate.GetDay();
BirthdayMonth = BirthdayDate.GetMonth();
BirthdayYear = BirthdayDate.GetYear();
// Look for T and replace data before this.
wxStringTokenizer wSTDate(ContactEditorData.Birthday, wxT("T"));
while (wSTDate.HasMoreTokens()){
if (ProcessDataAfterT == FALSE){
DataBeforeT = wSTDate.GetNextToken();
ProcessDataAfterT = TRUE;
} else {
DataAfterT = wSTDate.GetNextToken();
break;
}
}
// If there is not T then replace altogether.
wxString FinalBirthdayDay;
wxString FinalBirthdayMonth;
wxString FinalBirthdayYear;
if (BirthdayDay < 10){
FinalBirthdayDay = wxT("0") + wxString::Format(wxT("%i"), BirthdayDay);
} else {
FinalBirthdayDay = wxString::Format(wxT("%i"), BirthdayDay);
}
if (((int)BirthdayMonth + 1) < 10){
FinalBirthdayMonth = wxT("0") + wxString::Format(wxT("%i"), ((int)BirthdayMonth + 1));
} else {
FinalBirthdayMonth = wxString::Format(wxT("%i"), ((int)BirthdayMonth + 1));
}
if (BirthdayYear == 0){
FinalBirthdayYear = wxT("--");
} else {
FinalBirthdayYear = wxString::Format(wxT("%i"), BirthdayYear);
}
if (!DataAfterT.IsEmpty()){
FinalBirthdayString = FinalBirthdayYear + FinalBirthdayMonth + FinalBirthdayDay + wxT("T") + DataAfterT;
} else {
FinalBirthdayString = FinalBirthdayYear + FinalBirthdayMonth + FinalBirthdayDay;
}
if(!FinalBirthdayString.IsEmpty()){
ContactEditorData.Birthday = FinalBirthdayString;
}
}
// Process Anniversary: Get Day, Month & Year.
wxDateTime AnniversaryDate;
wxDateTime::Month AnniversaryMonth;
int AnniversaryDay;
int AnniversaryYear;
DataBeforeT = "";
DataAfterT = "";
wxString FinalAnniversaryString;
ProcessDataAfterT = FALSE;
AnniversaryDate = dapAnniversary->GetValue();
if (!txtAnniversary->IsEmpty()){
// Birthday value is text so use this.
ContactEditorData.Anniversary = txtAnniversary->GetValue();
} else if (AnniversaryDate.IsValid()){
AnniversaryDay = AnniversaryDate.GetDay();
AnniversaryMonth = AnniversaryDate.GetMonth();
AnniversaryYear = AnniversaryDate.GetYear();
// Look for T and replace data before this.
wxStringTokenizer wSTDate(ContactEditorData.Anniversary, wxT("T"));
while (wSTDate.HasMoreTokens()){
if (ProcessDataAfterT == FALSE){
DataBeforeT = wSTDate.GetNextToken();
ProcessDataAfterT = TRUE;
} else {
DataAfterT = wSTDate.GetNextToken();
break;
}
}
// If there is not T then replace altogether.
wxString FinalAnniversaryDay;
wxString FinalAnniversaryMonth;
wxString FinalAnniversaryYear;
if (AnniversaryDay < 10){
FinalAnniversaryDay = wxT("0") + wxString::Format(wxT("%i"), AnniversaryDay);
} else {
FinalAnniversaryDay = wxString::Format(wxT("%i"), AnniversaryDay);
}
if (((int)AnniversaryMonth + 1) < 10){
FinalAnniversaryMonth = wxT("0") + wxString::Format(wxT("%i"), ((int)AnniversaryMonth + 1));
} else {
FinalAnniversaryMonth = wxString::Format(wxT("%i"), ((int)AnniversaryMonth + 1));
}
if (AnniversaryYear == 0){
FinalAnniversaryYear = wxT("--");
} else {
FinalAnniversaryYear = wxString::Format(wxT("%i"), AnniversaryYear);
}
if (!DataAfterT.IsEmpty()){
FinalAnniversaryString = FinalAnniversaryYear + FinalAnniversaryMonth + FinalAnniversaryDay + wxT("T") + DataAfterT;
} else {
FinalAnniversaryString = FinalAnniversaryYear + FinalAnniversaryMonth + FinalAnniversaryDay;
}
if(!FinalAnniversaryString.IsEmpty()){
ContactEditorData.Birthday = FinalAnniversaryString;
}
}
// Process full name.
if (ContactEditorData.FullNamesList.size() > 0){
ContactEditorData.FullNamesList[0] = cmbDisplayAs->GetValue();
} else {
ContactEditorData.FullNamesList.insert(std::make_pair(0, cmbDisplayAs->GetValue()));
ContactEditorData.FullNamesListAltID.insert(std::make_pair(0, wxT("")));
ContactEditorData.FullNamesListPID.insert(std::make_pair(0, wxT("")));
ContactEditorData.FullNamesListType.insert(std::make_pair(0, wxT("")));
ContactEditorData.FullNamesListLanguage.insert(std::make_pair(0, wxT("")));
ContactEditorData.FullNamesListPref.insert(std::make_pair(0, 0));
ContactEditorData.FullNamesListTokens.insert(std::make_pair(0, wxT("")));
}
FMTimer.Stop();
ContactEditorData.SaveFile(FilenameFinal);
vCard34Conv ConvFileFun;
wxString wxSData;
ConvFileFun.ConvertToV3(FilenameFinal, &wxSData);
wxString AccountDirPrefix;
wxString AccountDir;
wxString PrefDir;
#if defined(__HAIKU__)
#elif defined(__APPLE__)
PrefDir = GetUserPrefDir();
wxStringTokenizer wSTFilename(wxSContactFilename, wxT("/"));
#elif defined(__WIN32__)
PrefDir = GetUserPrefDir();
wxStringTokenizer wSTFilename(wxSContactFilename, wxT("\\"));
#else
PrefDir = GetUserPrefDir();
wxStringTokenizer wSTFilename(wxSContactFilename, wxT("/"));
#endif
XABPreferences PrefData(PrefDir);
wxString AccountType;
for (int i = 0; i < PrefData.accounts.GetCount(); i++){
AccountDir = PrefData.accounts.GetAccountDirectory(i) + wxT(".carddav");
if (AccountDir == wxSContactAccount){
AccountDirPrefix = PrefData.accounts.GetAccountDirPrefix(i);
AccountDirPrefix.Trim();
AccountType = PrefData.accounts.GetAccountType(i);
break;
}
}
wxString wxSplitFilename;
wxString wxSDataURL;
while(wSTFilename.HasMoreTokens()){
wxSplitFilename = wSTFilename.GetNextToken();
}
wxSDataURL = wxSplitFilename;
// Find out if the filename exists in the table.
if (AccountType == wxT("CardDAV") || AccountType == wxT("carddav")){
wxString ETagResult;
wxString ETagOriginal;
ETagDB *ETagDBPtr = NULL;
ETagDBPtr = ETagTmrPtr->GetPointer(wxSContactAccount);
wxString wxSETag = ETagDBPtr->GetETag(wxSplitFilename);
wxString wxSETagOrig = ETagDBPtr->GetETagOriginal(wxSplitFilename);
if (wxSETagOrig.IsEmpty()){
// Generate the ETag.
wxSETagOrig = wxString::Format(wxT("%X%X%X%X"), rand() % 1024, rand() % 1024, rand() % 1024, rand() % 1024);
}
if (wxSETag.IsEmpty()){
// Update empty ETag.
wxSETag = wxSETagOrig;
ETagDBPtr->UpdateETag(wxSplitFilename, wxSETag, wxSETagOrig);
} else {
// Don't change original ETag.
wxSETag = wxString::Format(wxT("%X%X%X%X"), rand() % 1024, rand() % 1024, rand() % 1024, rand() % 1024);
ETagDBPtr->UpdateETag(wxSplitFilename, wxSETag);
}
if (EditMode == FALSE){
ActMgrPtr->AddTask(0, cmbDisplayAs->GetValue(), wxSContactAccount, wxSDataURL, wxSplitFilename, FilenameFinal, wxSData);
EditMode = TRUE;
FMTimer.SetFilename(FilenameFinal);
FMTimer.UpdateTimestamp();
FMTimer.Start(10000, FALSE);
wxCommandEvent reloadevent(RELOADCONTACTLIST);
reloadevent.SetString(wxSContactAccount);
wxPostEvent(this->GetParent(), reloadevent);
} else {
ActMgrPtr->AddTask(1, cmbDisplayAs->GetValue(), wxSContactAccount, wxSDataURL, wxSplitFilename, FilenameFinal, wxSData);
FMTimer.UpdateTimestamp();
FMTimer.Start(10000, FALSE);
}
}
// Send a notification to update the main window
// with the new details.
UCNotif *ucd;
ucd = new UCNotif;
// TODO: Workout nickname settings by priority and
// type.
vCardName NameData;
NameData.Forename = txtForename->GetValue();
NameData.Surname = txtSurname->GetValue();
NameData.OtherNames = txtOtherNames->GetValue();
NameData.Title = txtTitle->GetValue();
NameData.Suffix = txtSuffix->GetValue();
ucd->ContactAccount = wxSContactAccount;
ucd->ContactFilename = FilenameFinal;
ucd->ContactName = cmbDisplayAs->GetValue();
ucd->ContactNameArray = NameData;
for (std::map::iterator gniter = ContactEditorData.GeneralNicknamesList.begin();
gniter != ContactEditorData.GeneralNicknamesList.end(); gniter++){
ucd->ContactNickname = gniter->second;
break;
}
wxCommandEvent event2(CE_UPDATECONTACTLIST);
event2.SetClientData(ucd);
wxPostEvent(MainPtr, event2);
}
void frmContactEditor::SaveCloseContact( wxCommandEvent& event )
{
// Save the updated contact data and close the form.
wxCommandEvent NullEvent;
this->SaveContact(NullEvent);
this->Close();
}