summaryrefslogtreecommitdiff
path: root/plugins/BasicHistory/Scheduler.cpp
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2012-06-05 19:31:43 +0000
committerGeorge Hazan <george.hazan@gmail.com>2012-06-05 19:31:43 +0000
commit528949c71a12f54dc7b71133a32d9ee91cb53298 (patch)
treea2b57251631adf14f00a4d775b6894da06f670fc /plugins/BasicHistory/Scheduler.cpp
parenta6fb825ecbf5313b010fd8cf37754f494cabddc5 (diff)
BasicHistory - the alternative for history++
git-svn-id: http://svn.miranda-ng.org/main/trunk@317 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/BasicHistory/Scheduler.cpp')
-rw-r--r--plugins/BasicHistory/Scheduler.cpp1576
1 files changed, 1576 insertions, 0 deletions
diff --git a/plugins/BasicHistory/Scheduler.cpp b/plugins/BasicHistory/Scheduler.cpp
new file mode 100644
index 0000000000..3b2ba18ab9
--- /dev/null
+++ b/plugins/BasicHistory/Scheduler.cpp
@@ -0,0 +1,1576 @@
+/*
+Basic History plugin
+Copyright (C) 2011-2012 Krzysztof Kral
+
+This program 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 2
+of the License.
+
+This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "StdAfx.h"
+#include "Options.h"
+#include "ExportManager.h"
+#include "HistoryWindow.h"
+#include "zip\zip.h"
+#include "zip\unzip.h"
+#include "zip\iowin32.h"
+
+// Sorry for plain C implementation
+#define MODULE "BasicHistory"
+extern HANDLE g_hMainThread;
+bool bPopupsEnabled;
+bool DoTask(TaskOptions& to);
+bool IsValidTask(TaskOptions& to, std::list<TaskOptions>* top = NULL, std::wstring* err = NULL, std::wstring* errDescr = NULL);
+std::wstring GetFileName(const std::wstring &baseName, std::wstring contactName, std::map<std::wstring, bool>& existingContacts, bool replaceContact);
+std::wstring GetDirectoryName(const std::wstring &path);
+std::wstring GetName(const std::wstring &path);
+bool DeleteDirectory(LPCTSTR lpszDir, bool noRecycleBin = true);
+void ListDirectory(const std::wstring &basePath, const std::wstring &path, std::list<std::wstring>& files);
+std::wstring ReplaceStr(const std::wstring& str, wchar_t oldCh, wchar_t newCh);
+time_t GetNextExportTime(TaskOptions& to);
+void SchedulerThreadFunc(void*);
+volatile bool finishThread = false;
+bool initTask = false;
+HANDLE thread = NULL;
+HANDLE threadEvent;
+time_t nextExportTime;
+void StartThread(bool init);
+void StopThread();
+bool GetNextExportTime(bool init, time_t now);
+bool ExecuteCurrentTask(time_t now);
+void GetZipFileTime(const TCHAR *file, uLong *dt);
+std::wstring ReplaceExt(const std::wstring& file, const TCHAR* ext);
+bool ZipFiles(const std::wstring& dir, std::wstring zipFilePath, const std::string& password);
+bool UnzipFiles(const std::wstring& dir, std::wstring& zipFilePath, const std::string& password);
+bool FtpFiles(const std::wstring& dir, const std::wstring& filePath, const std::wstring& ftpName);
+bool FtpGetFiles(const std::wstring& dir, const std::list<std::wstring>& files, const std::wstring& ftpName);
+void CreatePath(const TCHAR *szDir);
+void DoError(const TaskOptions& to, const std::wstring error);
+
+void OptionsSchedulerChanged()
+{
+ StartThread(false);
+}
+
+void InitScheduler()
+{
+ bPopupsEnabled = ServiceExists(MS_POPUP_ADDPOPUPT) || ServiceExists(MS_POPUP_ADDPOPUPCLASS);
+ if (ServiceExists(MS_POPUP_REGISTERCLASS))
+ {
+ //hPopupIcon = LoadIconEx(I_CHKUPD);
+ POPUPCLASS test = {0};
+ test.cbSize = sizeof(POPUPCLASS);
+ test.flags = PCF_TCHAR;
+ test.hIcon = LoadSkinnedIcon(SKINICON_OTHER_HISTORY);
+ test.iSeconds = 10;
+ test.ptszDescription = TranslateT("History task");
+ test.pszName = MODULE;
+ CallService(MS_POPUP_REGISTERCLASS, 0, (WPARAM)&test);
+ }
+
+ StartThread(true);
+}
+
+void DeinitScheduler()
+{
+ StopThread();
+}
+
+int DoLastTask(WPARAM, LPARAM)
+{
+ for(std::vector<TaskOptions>::iterator it = Options::instance->taskOptions.begin(); it != Options::instance->taskOptions.end(); ++it)
+ {
+ if(it->trigerType == TaskOptions::AtEnd && it->active)
+ {
+ DoTask(*it);
+ }
+ }
+
+ return 0;
+}
+
+bool IsValidTask(TaskOptions& to, std::list<TaskOptions>* top, std::wstring* err, std::wstring* errDescr)
+{
+ if(to.taskName.empty())
+ {
+ if(err != NULL)
+ *err = TranslateT("Name");
+ return false;
+ }
+ if(top != NULL)
+ {
+ for(std::list<TaskOptions>::iterator it = top->begin(); it != top->end(); ++it)
+ {
+ if(it->taskName == to.taskName)
+ {
+ if(err != NULL)
+ *err = TranslateT("Name");
+ return false;
+ }
+ }
+ }
+ if(!to.isSystem && to.contacts.size() == 0)
+ {
+ if(err != NULL)
+ *err = TranslateT("Contacts");
+ if(errDescr != NULL)
+ *errDescr = TranslateT("At least one contact should be selected.");
+ return false;
+ }
+
+ bool isImportTask = to.type == TaskOptions::Import || to.type == TaskOptions::ImportAndMarge;
+ if(!isImportTask)
+ {
+ if(to.filterId > 1)
+ {
+ int filter = 0;
+
+ for(int i = 0; i < (int)Options::instance->customFilters.size(); ++i)
+ {
+ if(to.filterName == Options::instance->customFilters[i].name)
+ {
+ filter = i + 2;
+ break;
+ }
+ }
+
+ if(filter < 2)
+ {
+ if(err != NULL)
+ *err = TranslateT("Filter");
+ return false;
+ }
+
+ to.filterId = filter;
+ }
+ else if(to.filterId < 0)
+ {
+ if(err != NULL)
+ *err = TranslateT("Filter");
+ return false;
+ }
+ }
+
+ if(to.type == TaskOptions::Delete)
+ {
+ return true;
+ }
+
+ if(!Options::FTPAvail() && to.useFtp)
+ {
+ if(err != NULL)
+ *err = TranslateT("Upload to FTP");
+ return false;
+ }
+ if(to.filePath.empty())
+ {
+ if(err != NULL)
+ *err = TranslateT("Path to output file");
+ return false;
+ }
+ if(to.useFtp && to.ftpName.empty())
+ {
+ if(err != NULL)
+ *err = TranslateT("Session name");
+ if(errDescr != NULL)
+ *errDescr = TranslateT("To create session open WinSCP, click New Session, enter data and save with specific name. Remember if FTP server using password you should save it in WinSCP.");
+ return false;
+ }
+ if(to.useFtp && (to.filePath.find(_T('\\')) < to.filePath.length() || to.filePath.find(_T(':')) < to.filePath.length() || to.filePath[0] != L'/'))
+ {
+ if(err != NULL)
+ *err = TranslateT("Path to file");
+ if(errDescr != NULL)
+ *errDescr = TranslateT("FTP path must contains '/' instead '\\' and starts from '/'.");
+ return false;
+ }
+ if(isImportTask && to.filePath.find(_T("<date>")) < to.filePath.length())
+ {
+ if(err != NULL)
+ *err = TranslateT("Path to file");
+ if(errDescr != NULL)
+ *errDescr = TranslateT("FTP path cannot contain <date> in import task.");
+ return false;
+ }
+ if(!isImportTask && (to.exportType < IExport::RichHtml || to.exportType > IExport::Dat))
+ {
+ if(err != NULL)
+ *err = TranslateT("Export to");
+ return false;
+ }
+ if(isImportTask && (to.importType < IImport::Binary || to.importType > IImport::Dat))
+ {
+ if(err != NULL)
+ *err = TranslateT("Import from");
+ return false;
+ }
+ if((to.trigerType == TaskOptions::Daily || to.trigerType == TaskOptions::Weekly || to.trigerType == TaskOptions::Monthly) && (to.dayTime < 0 || to.dayTime >= 24 * 60))
+ {
+ if(err != NULL)
+ *err = TranslateT("Time");
+ return false;
+ }
+ if(to.trigerType == TaskOptions::Weekly && (to.dayOfWeek < 0 || to.dayOfWeek >= 7))
+ {
+ if(err != NULL)
+ *err = TranslateT("Day of week");
+ return false;
+ }
+ if(to.trigerType == TaskOptions::Monthly && (to.dayOfMonth <= 0 || to.dayOfMonth >= 32))
+ {
+ if(err != NULL)
+ *err = TranslateT("Day");
+ return false;
+ }
+ if((to.trigerType == TaskOptions::DeltaMin || to.trigerType == TaskOptions::DeltaHour) && (to.deltaTime < 0 || to.deltaTime >= 10000))
+ {
+ if(err != NULL)
+ *err = TranslateT("Delta time");
+ return false;
+ }
+
+ return true;
+}
+
+static void CALLBACK DoRebuildEventsInMainAPCFunc(ULONG_PTR dwParam)
+{
+ HANDLE* contacts = (HANDLE*) dwParam;
+ size_t size = (size_t)contacts[0];
+ for(size_t i = 1; i <= size; ++i)
+ {
+ HistoryWindow::RebuildEvents(contacts[i]);
+ }
+
+ delete[] contacts;
+}
+
+bool DoTask(TaskOptions& to)
+{
+ std::wstring err;
+ std::wstring errDescr;
+ if(!IsValidTask(to, NULL, &err, &errDescr))
+ {
+ TCHAR msg[256];
+ if(err.empty())
+ _tcscpy_s(msg, TranslateT("Some value is invalid"));
+ else if(errDescr.empty())
+ {
+ _stprintf_s(msg, TranslateT("Invalid '%s' value."), err.c_str());
+ }
+ else
+ {
+ _stprintf_s(msg, TranslateT("Invalid '%s' value.\n%s"), err.c_str(), errDescr.c_str());
+ }
+ DoError(to, msg);
+ return true;
+ }
+
+ DWORD now = time(NULL);
+ long long int t = to.eventDeltaTime * 60;
+ if(to.eventUnit > TaskOptions::Minute)
+ t *= 60LL;
+ if(to.eventUnit > TaskOptions::Hour)
+ t *= 24LL;
+ if(t > 2147483647LL)
+ {
+ DoError(to, TranslateT("Unknown error"));
+ return true;
+ }
+
+ bool error = false;
+ std::wstring errorStr;
+ std::list<ExportManager*> managers;
+ if(to.type == TaskOptions::Delete)
+ {
+ if(to.isSystem)
+ {
+ ExportManager *exp = new ExportManager(NULL, NULL, to.filterId);
+ exp->SetDeleteWithoutExportEvents(t, now);
+ managers.push_back(exp);
+ }
+
+ for(size_t i = 0; i < to.contacts.size(); ++i)
+ {
+ ExportManager *exp = new ExportManager(NULL, to.contacts[i], to.filterId);
+ exp->SetDeleteWithoutExportEvents(t, now);
+ managers.push_back(exp);
+ }
+ }
+ else if(to.type == TaskOptions::Import || to.type == TaskOptions::ImportAndMarge)
+ {
+ std::map<std::wstring, bool> existingContacts1;
+ ExportManager mExp = ExportManager(NULL, NULL, 1);
+ std::wstring filePath = to.filePath;
+ std::wstring dir;
+ std::list<std::wstring> files;
+ std::vector<HANDLE> contacts;
+ if(to.useFtp || to.compress)
+ {
+ std::map<std::wstring, bool> existingContacts;
+ TCHAR temp[MAX_PATH];
+ temp[0] = 0;
+ GetTempPath(MAX_PATH, temp);
+ dir = temp;
+ dir += GetName(filePath);
+ dir = GetFileName(dir, L"", existingContacts, true);
+ dir = ReplaceExt(dir, L"");
+ size_t pos = dir.find_last_of(_T('.'));
+ if(pos < dir.length())
+ {
+ dir = dir.substr(0, pos);
+ }
+
+ DeleteDirectory(dir.c_str());
+ CreateDirectory(dir.c_str(), NULL);
+ }
+
+ const TCHAR* ext = ExportManager::GetExt(to.importType);
+ if(to.isSystem)
+ {
+ std::wstring n = GetFileName(filePath, mExp.GetContactName(), existingContacts1, true);
+ n = ReplaceExt(n, ext);
+ files.push_back(n);
+ contacts.push_back(NULL);
+ }
+
+ for(size_t i = 0; i < to.contacts.size(); ++i)
+ {
+ mExp.hContact = to.contacts[i];
+ std::wstring n = GetFileName(filePath, mExp.GetContactName(), existingContacts1, true);
+ n = ReplaceExt(n, ext);
+ files.push_back(n);
+ contacts.push_back(to.contacts[i]);
+ }
+
+ if(to.useFtp)
+ {
+ if(to.compress)
+ {
+ std::map<std::wstring, bool> existingContacts;
+ std::wstring n = GetFileName(filePath, L"", existingContacts, true);
+ n = ReplaceExt(n, L"zip");
+ files.clear();
+ files.push_back(n);
+ filePath = dir + L"\\" + GetName(filePath);
+ }
+
+ error = FtpGetFiles(dir, files, to.ftpName);
+ if(error)
+ {
+ if(!errorStr.empty())
+ {
+ errorStr += L"\n";
+ }
+
+ errorStr += TranslateT("Cannot get FTP file(s).");
+ }
+ }
+
+ if(!error && to.compress)
+ {
+ error = UnzipFiles(dir, filePath, to.zipPassword);
+ if(error)
+ {
+ if(!errorStr.empty())
+ {
+ errorStr += L"\n";
+ }
+
+ errorStr += TranslateT("Cannot unzip file(s).");
+ }
+
+ if(to.useFtp)
+ DeleteFile(filePath.c_str());
+ }
+
+ if(!error && (to.useFtp || to.compress))
+ {
+ files.clear();
+ std::list<std::wstring> files1;
+ ListDirectory(dir, L"\\", files1);
+ for(std::list<std::wstring>::iterator it = files1.begin(); it != files1.end(); ++it)
+ {
+ files.push_back(dir + *it);
+ }
+ }
+
+ if(!error)
+ {
+ std::list<HANDLE> contactList;
+ for(std::list<std::wstring>::iterator it = files.begin(); it != files.end(); ++it)
+ {
+ mExp.SetAutoImport(*it);
+ int ret = mExp.Import(to.importType, contacts);
+ if(ret == -3)
+ {
+ if(contacts.size() == 1)
+ {
+ ret = 0;
+ }
+ else
+ {
+ std::map<std::wstring, bool> existingContacts;
+ std::wstring name = GetName(*it);
+ for(ret = 0; ret < (int)contacts.size(); ++ret)
+ {
+ mExp.hContact = contacts[ret];
+ std::wstring n = GetFileName(to.filePath, mExp.GetContactName(), existingContacts, true);
+ n = ReplaceExt(n, ext);
+ n = GetName(n);
+ if(n == name)
+ break;
+ }
+
+ if(ret >= (int)contacts.size())
+ ret = -1;
+ }
+ }
+
+ if(ret >= 0)
+ {
+ mExp.hContact = contacts[ret];
+ if(to.type == TaskOptions::Import)
+ {
+ EventList::AddImporter(mExp.hContact, to.importType, *it);
+ contactList.push_back(mExp.hContact);
+ }
+ else
+ {
+ std::vector<IImport::ExternalMessage> messages;
+ if(mExp.Import(to.importType, messages, NULL))
+ {
+ mExp.MargeMessages(messages);
+ contactList.push_back(mExp.hContact);
+ }
+ }
+ }
+ else if(ret != -1)
+ {
+ if(!errorStr.empty())
+ {
+ errorStr += L"\n";
+ }
+
+ TCHAR msg[1024];
+
+ _stprintf_s(msg, TranslateT("Incorrect file format: %s."), GetName(*it).c_str());
+ errorStr += msg;
+ }
+ else
+ {
+ if(!errorStr.empty())
+ {
+ errorStr += L"\n";
+ }
+
+ TCHAR msg[1024];
+
+ _stprintf_s(msg, TranslateT("Unknown contact in file: %s."), GetName(*it).c_str());
+ errorStr += msg;
+ }
+ }
+
+ if(contactList.size() > 0)
+ {
+ HANDLE* contacts = new HANDLE[contactList.size() + 1];
+ contacts[0] = (HANDLE)contactList.size();
+ int i = 1;
+ for(std::list<HANDLE>::iterator it = contactList.begin(); it != contactList.end(); ++it)
+ {
+ contacts[i++] = *it;
+ }
+
+ QueueUserAPC(DoRebuildEventsInMainAPCFunc, g_hMainThread, (ULONG_PTR) contacts);
+ }
+ }
+
+ if(to.useFtp || to.compress)
+ {
+ DeleteDirectory(dir.c_str());
+ }
+ }
+ else
+ {
+ std::map<std::wstring, bool> existingContacts;
+ std::wstring filePath = to.filePath;
+ std::wstring dir;
+ if(!to.useFtp && !to.compress)
+ {
+ dir = GetDirectoryName(filePath);
+ if(!dir.empty())
+ {
+ CreateDirectory(dir.c_str(), NULL);
+ }
+ }
+ else
+ {
+ filePath = GetName(filePath);
+ TCHAR temp[MAX_PATH];
+ temp[0] = 0;
+ GetTempPath(MAX_PATH, temp);
+ dir = temp;
+ dir += filePath;
+ dir = GetFileName(dir, L"", existingContacts, true);
+ dir = ReplaceExt(dir, L"");
+ size_t pos = dir.find_last_of(_T('.'));
+ if(pos < dir.length())
+ {
+ dir = dir.substr(0, pos);
+ }
+
+ DeleteDirectory(dir.c_str());
+ CreateDirectory(dir.c_str(), NULL);
+ filePath = dir + L"\\" + filePath;
+ }
+ if(to.isSystem)
+ {
+ ExportManager *exp = new ExportManager(NULL, NULL, to.filterId);
+ exp->SetAutoExport(GetFileName(filePath, exp->GetContactName(), existingContacts, true), t, now);
+ exp->useImportedMessages = to.exportImported;
+ if(!exp->Export(to.exportType))
+ {
+ error = true;
+ if(!errorStr.empty())
+ {
+ errorStr += L"\n";
+ }
+
+ TCHAR msg[1024];
+
+ _stprintf_s(msg, TranslateT("Cannot export history for contact: %s."), exp->GetContactName().c_str());
+ errorStr += msg;
+ }
+
+ if(to.type == TaskOptions::Export)
+ {
+ delete exp;
+ }
+ else
+ {
+ managers.push_back(exp);
+ }
+ }
+
+ if(!error)
+ {
+ for(size_t i = 0; i < to.contacts.size(); ++i)
+ {
+ ExportManager *exp = new ExportManager(NULL, to.contacts[i], to.filterId);
+ exp->SetAutoExport(GetFileName(filePath, exp->GetContactName(), existingContacts, true), t, now);
+ exp->useImportedMessages = to.exportImported;
+ if(!exp->Export(to.exportType))
+ {
+ error = true;
+ if(!errorStr.empty())
+ {
+ errorStr += L"\n";
+ }
+
+ TCHAR msg[1024];
+
+ _stprintf_s(msg, TranslateT("Cannot export history for contact: %s."), exp->GetContactName().c_str());
+ errorStr += msg;
+ break;
+ }
+
+ if(to.type == TaskOptions::Export)
+ {
+ delete exp;
+ }
+ else
+ {
+ managers.push_back(exp);
+ }
+ }
+ }
+
+ if(error)
+ {
+ if(to.compress && !to.useFtp)
+ {
+ DeleteDirectory(dir.c_str());
+ }
+ }
+ else if(to.compress)
+ {
+ std::wstring zipFilePath = to.filePath;
+ std::wstring zipDir = dir;
+ if(!to.useFtp)
+ {
+ zipDir = GetDirectoryName(zipFilePath);
+ if(!zipDir.empty())
+ {
+ CreateDirectory(zipDir.c_str(), NULL);
+ }
+ }
+ else
+ {
+ zipFilePath = GetName(zipFilePath);
+ TCHAR temp[MAX_PATH];
+ temp[0] = 0;
+ GetTempPath(MAX_PATH, temp);
+ zipDir = temp;
+ zipDir += L"zip<date>";
+ zipDir = GetFileName(zipDir, L"", existingContacts, true);
+ DeleteDirectory(zipDir.c_str());
+ CreateDirectory(zipDir.c_str(), NULL);
+ zipFilePath = zipDir + L"\\" + zipFilePath;
+ }
+ error = ZipFiles(dir + L"\\", zipFilePath, to.zipPassword);
+ dir = zipDir;
+ if(error)
+ {
+ if(!errorStr.empty())
+ {
+ errorStr += L"\n";
+ }
+
+ errorStr += TranslateT("Cannot compress file(s).");
+ }
+ }
+
+ if(to.useFtp)
+ {
+ if(!error)
+ {
+ error = FtpFiles(dir, to.filePath, to.ftpName);
+ if(error)
+ {
+ if(!errorStr.empty())
+ {
+ errorStr += L"\n";
+ }
+
+ errorStr += TranslateT("Cannot send FTP file(s).");
+ }
+ }
+
+ DeleteDirectory(dir.c_str());
+ }
+ }
+
+ if(to.type == TaskOptions::Delete || to.type == TaskOptions::ExportAndDelete)
+ {
+ for(std::list<ExportManager*>::iterator it = managers.begin(); it != managers.end(); ++it)
+ {
+ if(!error)
+ {
+ (*it)->DeleteExportedEvents();
+ }
+
+ delete *it;
+ }
+ }
+
+ if(error)
+ {
+ DoError(to, errorStr.empty() ? TranslateT("Unknown error") : errorStr);
+ }
+
+ return error;
+}
+
+std::wstring GetFileName(const std::wstring &baseName, std::wstring contactName, std::map<std::wstring, bool>& existingContacts, bool replaceContact)
+{
+ std::wstring str = baseName;
+ size_t pos = baseName.find(_T("<contact>"));
+ if(replaceContact && pos < baseName.length())
+ {
+ str = baseName.substr(0, pos);
+ std::wstring baseName1 = contactName;
+ if(!baseName1.empty())
+ {
+ std::wstring name = baseName1;
+ int i = 0;
+ TCHAR buf[32];
+ std::map<std::wstring, bool>::iterator it = existingContacts.find(name);
+ while(it != existingContacts.end())
+ {
+ _itot_s(++i, buf, 10);
+ name = baseName1 + buf;
+ it = existingContacts.find(name);
+ }
+
+ str += name;
+ existingContacts[name] = true;
+ }
+ str += baseName.substr(pos + 9);
+ }
+
+ pos = str.find(_T("<date>"));
+ if(pos < str.length())
+ {
+ TCHAR time[256];
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ _stprintf_s(time, _T("%d-%02d-%02d %02d%02d"), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute);
+ std::wstring str1 = str.substr(0, pos);
+ str1 += time;
+ str1 += str.substr(pos + 6);
+ str = str1;
+ }
+
+ return str;
+}
+
+std::wstring GetDirectoryName(const std::wstring &path)
+{
+ size_t find = path.find_last_of(L"\\/");
+ if(find < path.length())
+ {
+ return path.substr(0, find);
+ }
+
+ return L"";
+}
+
+void ListDirectory(const std::wstring &basePath, const std::wstring &path, std::list<std::wstring>& files)
+{
+ WIN32_FIND_DATA findFileData;
+ HANDLE hFind = FindFirstFile((basePath + path + _T("*")).c_str(), &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ return;
+ do
+ {
+ if(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ std::wstring name = findFileData.cFileName;
+ if(name != L"." && name != L"..")
+ ListDirectory(basePath, path + findFileData.cFileName + _T("\\"), files);
+ }
+ else
+ {
+ files.push_back(path + findFileData.cFileName);
+ }
+ }
+ while(FindNextFile(hFind, &findFileData));
+ FindClose(hFind);
+}
+
+std::wstring ReplaceStr(const std::wstring& str, wchar_t oldCh, wchar_t newCh)
+{
+ std::wstring ret;
+ size_t start = 0;
+ size_t find;
+ while((find = str.find_first_of(oldCh, start)) < str.length())
+ {
+ ret += str.substr(start, find - start);
+ ret += newCh;
+ start = find + 1;
+ }
+
+ ret += str.substr(start, str.length() - start);
+ return ret;
+}
+
+time_t GetNextExportTime(TaskOptions& to)
+{
+ switch(to.trigerType)
+ {
+ case TaskOptions::Daily:
+ {
+ tm t;
+ localtime_s(&t, &to.lastExport);
+ t.tm_hour = to.dayTime/60;
+ t.tm_min = to.dayTime%60;
+ t.tm_sec = 0;
+ time_t newTime = mktime(&t);
+ if(newTime <= to.lastExport)
+ {
+ newTime += 60 * 60 * 24;
+ }
+
+ return newTime;
+ }
+ case TaskOptions::Weekly:
+ {
+ tm t;
+ localtime_s(&t, &to.lastExport);
+ t.tm_hour = to.dayTime/60;
+ t.tm_min = to.dayTime%60;
+ t.tm_sec = 0;
+ int dow = (to.dayOfWeek + 1) % 7;
+ time_t newTime = mktime(&t);
+ while(dow != t.tm_wday)
+ {
+ newTime += 60 * 60 * 24;
+ localtime_s(&t, &newTime);
+ newTime = mktime(&t);
+ }
+
+ if(newTime <= to.lastExport)
+ {
+ newTime += 7 * 60 * 60 * 24;
+ }
+
+ return newTime;
+ }
+ case TaskOptions::Monthly:
+ {
+ tm t;
+ localtime_s(&t, &to.lastExport);
+ t.tm_hour = to.dayTime/60;
+ t.tm_min = to.dayTime%60;
+ t.tm_sec = 0;
+ time_t newTime = mktime(&t);
+ int lastM = t.tm_mon;
+ int lastD;
+ while(to.dayOfMonth != t.tm_mday || newTime <= to.lastExport)
+ {
+ lastD = t.tm_mday;
+ newTime += 60 * 60 * 24;
+ localtime_s(&t, &newTime);
+ newTime = mktime(&t);
+ if(to.dayOfMonth > 28 && t.tm_mon != lastM && (newTime - 60 * 60 * 24) > to.lastExport)
+ {
+ lastM = t.tm_mon;
+ if(to.dayOfMonth > lastD)
+ {
+ newTime -= 60 * 60 * 24;
+ break;
+ }
+ }
+ }
+
+ return newTime;
+ }
+ case TaskOptions::DeltaMin:
+ return to.lastExport + to.deltaTime * 60;
+ case TaskOptions::DeltaHour:
+ return to.lastExport + to.deltaTime * 60 * 60;
+ default:
+ return to.lastExport;
+ }
+}
+
+void SchedulerThreadFunc(void*)
+{
+ if(initTask)
+ {
+ WaitForSingleObject(threadEvent, 5 * 1000);
+ initTask = false;
+ }
+
+ while(!finishThread)
+ {
+ DWORD timeWait;
+ time_t now = time(NULL);
+ while(nextExportTime <= now)
+ {
+ if(!ExecuteCurrentTask(now))
+ return;
+ }
+
+ time_t dif = nextExportTime - now;
+ timeWait = (dif > 60 * 60 * 24) ? (60 * 60 * 1000) : (60 * 1000);
+
+ WaitForSingleObject(threadEvent, timeWait);
+ }
+}
+
+void StartThread(bool init)
+{
+ StopThread();
+
+ initTask = false;
+ bool isExport = GetNextExportTime(init, time(NULL));
+ if(isExport)
+ {
+ finishThread = false;
+ threadEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ thread = mir_forkthread(SchedulerThreadFunc, NULL);
+ }
+}
+
+void StopThread()
+{
+ if(thread != NULL)
+ {
+ finishThread = true;
+ SetEvent(threadEvent);
+ WaitForSingleObject(thread, INFINITE);
+ //CloseHandle(thread);
+ CloseHandle(threadEvent);
+ thread = NULL;
+ threadEvent = NULL;
+ }
+}
+
+bool GetNextExportTime(bool init, time_t now)
+{
+ EnterCriticalSection(&Options::instance->criticalSection);
+ bool isExport = false;
+ for(std::vector<TaskOptions>::iterator it = Options::instance->taskOptions.begin(); it != Options::instance->taskOptions.end(); ++it)
+ {
+ if(it->forceExecute)
+ {
+ nextExportTime = now;
+ isExport = true;
+ initTask = init;
+ break;
+ }
+ else if(it->active && it->trigerType != TaskOptions::AtStart && it->trigerType != TaskOptions::AtEnd)
+ {
+ time_t t = GetNextExportTime(*it);
+ if(isExport)
+ {
+ if(t < nextExportTime)
+ nextExportTime = t;
+ }
+ else
+ {
+ nextExportTime = t;
+ isExport = true;
+ initTask = init;
+ }
+ }
+ else if(it->active && it->trigerType == TaskOptions::AtStart && init)
+ {
+ it->forceExecute = true;
+ it->showMBAfterExecute = false;
+ nextExportTime = now;
+ isExport = true;
+ initTask = true;
+ }
+ }
+
+ LeaveCriticalSection(&Options::instance->criticalSection);
+ return isExport;
+}
+
+static void CALLBACK DoTaskFinishInMainAPCFunc(ULONG_PTR dwParam)
+{
+ TCHAR *item = (TCHAR*) dwParam;
+ MessageBox(NULL, item, TranslateT("Task finished"), MB_OK | MB_ICONINFORMATION);
+ delete[] item;
+}
+
+bool ExecuteCurrentTask(time_t now)
+{
+ EnterCriticalSection(&Options::instance->criticalSection);
+ TaskOptions to;
+ bool isExport = false;
+ for(std::vector<TaskOptions>::iterator it = Options::instance->taskOptions.begin(); it != Options::instance->taskOptions.end(); ++it)
+ {
+ if(it->forceExecute)
+ {
+ it->lastExport = time(NULL);
+ Options::instance->SaveTaskTime(*it);
+ to = *it;
+ isExport = true;
+ break;
+ }
+ else if(it->active && it->trigerType != TaskOptions::AtStart && it->trigerType != TaskOptions::AtEnd)
+ {
+ time_t t = GetNextExportTime(*it);
+ if(t <= now)
+ {
+ it->lastExport = time(NULL);
+ Options::instance->SaveTaskTime(*it);
+ to = *it;
+ isExport = true;
+ break;
+ }
+ }
+ }
+
+ LeaveCriticalSection(&Options::instance->criticalSection);
+
+ if(isExport)
+ {
+ bool error = DoTask(to);
+ if(to.forceExecute)
+ {
+ EnterCriticalSection(&Options::instance->criticalSection);
+ for(std::vector<TaskOptions>::iterator it = Options::instance->taskOptions.begin(); it != Options::instance->taskOptions.end(); ++it)
+ {
+ if(it->taskName == to.taskName)
+ {
+ it->forceExecute = false;
+ it->showMBAfterExecute = false;
+ break;
+ }
+ }
+
+ LeaveCriticalSection(&Options::instance->criticalSection);
+
+ if(to.showMBAfterExecute)
+ {
+ size_t size = to.taskName.size() + 1024;
+ TCHAR* name = new TCHAR[size];
+ if(error)
+ {
+ _stprintf_s(name, size, TranslateT("Task '%s' execution failed"), to.taskName.c_str());
+ }
+ else
+ {
+ _stprintf_s(name, size, TranslateT("Task '%s' finished successfully"), to.taskName.c_str());
+ }
+
+ QueueUserAPC(DoTaskFinishInMainAPCFunc, g_hMainThread, (ULONG_PTR) name);
+ }
+ }
+ }
+
+ return GetNextExportTime(false, now);
+}
+
+void GetZipFileTime(const TCHAR *file, uLong *dt)
+{
+ FILETIME ftLocal;
+ HANDLE hFind;
+ WIN32_FIND_DATA ff32;
+
+ hFind = FindFirstFile(file, &ff32);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
+ FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
+ FindClose(hFind);
+ }
+}
+
+/* calculate the CRC32 of a file,
+ because to encrypt a file, we need known the CRC32 of the file before */
+bool GetFileCrc(const TCHAR* filenameinzip, unsigned char* buf, unsigned long size_buf, unsigned long* result_crc)
+{
+ unsigned long calculate_crc = 0;
+ bool error = true;
+ HANDLE hFile = CreateFile(filenameinzip, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if(hFile != INVALID_HANDLE_VALUE)
+ {
+ DWORD readed;
+ do
+ {
+ if(!ReadFile(hFile, buf, 1024, &readed, NULL))
+ {
+ error = false;
+ break;
+ }
+
+ if (readed > 0)
+ {
+ calculate_crc = crc32(calculate_crc, buf, readed);
+ }
+ }
+ while (readed > 0);
+ CloseHandle(hFile);
+ }
+ else
+ {
+ error = false;
+ }
+
+ *result_crc=calculate_crc;
+ return error;
+}
+
+bool ZipFiles(const std::wstring& dir, std::wstring zipFilePath, const std::string& password)
+{
+ std::list<std::wstring> files;
+ std::map<std::wstring, bool> existingContacts;
+ ListDirectory(dir, L"", files);
+ bool error = false;
+ if(files.size() > 0)
+ {
+ zlib_filefunc_def pzlib_filefunc_def;
+ fill_win32_filefunc(&pzlib_filefunc_def);
+ zipFilePath = GetFileName(zipFilePath, L"", existingContacts, true);
+ zipFilePath = ReplaceExt(zipFilePath, L"zip");
+ zipFile zf = zipOpen2((LPCSTR)(LPTSTR)zipFilePath.c_str(), APPEND_STATUS_CREATE, NULL, &pzlib_filefunc_def);
+ if (zf != NULL)
+ {
+ unsigned char buf[1024];
+ char bufF[MAX_PATH + 20];
+ while(files.size() > 0)
+ {
+ std::wstring zipDir = *files.begin();
+ std::wstring localDir = dir + L"\\" + zipDir;
+ zip_fileinfo zi = {0};
+ GetZipFileTime(localDir.c_str(), &zi.dosDate);
+ if(zipDir.size() > MAX_PATH + 19)
+ {
+ error = true;
+ break;
+ }
+
+ BOOL badChar;
+ WideCharToMultiByte(CP_OEMCP, WC_NO_BEST_FIT_CHARS, zipDir.c_str(), -1, bufF, MAX_PATH + 20, NULL, &badChar);
+ int flag = 0;
+ if(badChar)
+ {
+ flag = 0x800; // UTF
+ WideCharToMultiByte(CP_UTF8, 0, zipDir.c_str(), -1, bufF, MAX_PATH + 20, NULL, NULL);
+ }
+
+ unsigned long calculate_crc = 0;
+ const char* passwordCh = NULL;
+ if(password.size() > 0)
+ {
+ if(!GetFileCrc(localDir.c_str(), buf, 1024, &calculate_crc))
+ {
+ error = true;
+ break;
+ }
+
+ passwordCh = password.c_str();
+ }
+
+ int err = zipOpenNewFileInZip4_64 (zf, bufF, &zi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, passwordCh, calculate_crc, 0, flag, 0);
+ if (err == ZIP_OK)
+ {
+ HANDLE hFile = CreateFile(localDir.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if(hFile != INVALID_HANDLE_VALUE)
+ {
+ DWORD readed;
+ do
+ {
+ err = ZIP_OK;
+ if(!ReadFile(hFile, buf, 1024, &readed, NULL))
+ {
+ error = true;
+ break;
+ }
+
+ if (readed > 0)
+ {
+ err = zipWriteInFileInZip(zf, buf, readed);
+ }
+ }
+ while ((err == ZIP_OK) && (readed > 0));
+ CloseHandle(hFile);
+ }
+
+ if(zipCloseFileInZip(zf) != ZIP_OK)
+ {
+ error = true;
+ break;
+ }
+ }
+ else
+ {
+ error = true;
+ break;
+ }
+
+ files.pop_front();
+ }
+
+ zipClose(zf, NULL);
+ }
+ else
+ {
+ error = true;
+ }
+ }
+
+ DeleteDirectory(dir.c_str());
+ return error;
+}
+
+bool UnzipFiles(const std::wstring& dir, std::wstring& zipFilePath, const std::string& password)
+{
+ std::list<std::wstring> files;
+ bool error = false;
+ zlib_filefunc_def pzlib_filefunc_def;
+ fill_win32_filefunc(&pzlib_filefunc_def);
+ std::wstring fileNameInZip;
+ std::map<std::wstring, bool> existingContacts;
+ zipFilePath = GetFileName(zipFilePath, L"", existingContacts, true);
+ zipFilePath = ReplaceExt(zipFilePath, L"zip");
+ unzFile zf = unzOpen2((LPCSTR)(LPTSTR)zipFilePath.c_str(), &pzlib_filefunc_def);
+ if (zf != NULL)
+ {
+ char buf[8192];
+ char bufF[MAX_PATH + 20];
+ unz_file_info file_info;
+ do
+ {
+ int err = unzGetCurrentFileInfo(zf, &file_info, bufF, MAX_PATH + 20, buf, 8192, NULL, 0);
+ if (err == UNZ_OK)
+ {
+ UINT cp = CP_OEMCP;
+ if(file_info.flag & 0x800)// UTF
+ {
+ cp = CP_UTF8;
+ }
+
+ // Get Unicode file name for InfoZip style archives, otherwise assume PKZip/WinZip style
+ if (file_info.size_file_extra)
+ {
+ char *p = buf;
+ unsigned long size = min(file_info.size_file_extra, 8192);
+ while (size > 0)
+ {
+ unsigned short id = *(unsigned short*)p;
+ unsigned len = *(unsigned short*)(p + 2);
+
+ if (size < (len + 4)) break;
+
+ if (id == 0x7075 && len > 5 && (len - 5) < MAX_PATH + 20 && *(p + 4) == 1)
+ {
+ memcpy(bufF, p + 9, len - 5);
+ bufF[len - 5] = 0;
+ cp = CP_UTF8;
+ break;
+ }
+ size -= len + 4;
+ p += len + 4;
+ }
+ }
+
+ int sizeC = (int)strlen(bufF);
+ int sizeW = MultiByteToWideChar(cp, 0, bufF, sizeC, NULL, 0);
+ fileNameInZip.resize(sizeW);
+ MultiByteToWideChar(cp, 0, bufF, sizeC, (wchar_t*)fileNameInZip.c_str(), sizeW);
+ fileNameInZip = dir + L"\\" + fileNameInZip;
+ for (size_t i = 0; i < fileNameInZip.length(); ++i)
+ {
+ if (fileNameInZip[i] == L'/')
+ fileNameInZip[i] = L'\\';
+ }
+
+ if (file_info.external_fa & FILE_ATTRIBUTE_DIRECTORY)
+ CreatePath(fileNameInZip.c_str());
+ else
+ {
+ const char* passwordCh = NULL;
+ if(password.size() > 0)
+ {
+ passwordCh = password.c_str();
+ }
+
+ err = unzOpenCurrentFilePassword(zf, passwordCh);
+ if (err == UNZ_OK)
+ {
+ CreatePath(GetDirectoryName(fileNameInZip).c_str());
+ HANDLE hFile = CreateFile(fileNameInZip.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
+ if(hFile != INVALID_HANDLE_VALUE)
+ {
+ DWORD writed;
+ for (;;)
+ {
+ err = unzReadCurrentFile(zf, buf, 8192);
+ if (err <= 0) break;
+
+ if (!WriteFile(hFile, buf, err, &writed, FALSE))
+ {
+ err = -1;
+ break;
+ }
+ }
+
+ CloseHandle(hFile);
+ if(err < 0)
+ {
+ error = true;
+ break;
+ }
+ }
+ else
+ {
+ unzCloseCurrentFile(zf);
+ error = true;
+ break;
+ }
+
+ if(unzCloseCurrentFile(zf) != ZIP_OK)
+ {
+ error = true;
+ break;
+ }
+ }
+ else
+ {
+ error = true;
+ break;
+ }
+ }
+ }
+ else
+ {
+ error = true;
+ break;
+ }
+ }
+ while (unzGoToNextFile(zf) == UNZ_OK);
+
+ unzClose(zf);
+ }
+ else
+ {
+ error = true;
+ }
+
+ return error;
+}
+
+bool FtpFiles(const std::wstring& dir, const std::wstring& filePath, const std::wstring& ftpName)
+{
+ std::list<std::wstring> files;
+ std::map<std::wstring, bool> existingContacts;
+ ListDirectory(dir, L"\\", files);
+ if(files.size() > 0)
+ {
+ std::wofstream stream ((dir + _T("\\script.sc")).c_str());
+ if(stream.is_open())
+ {
+ std::wstring ftpDir = GetDirectoryName(filePath);
+ ftpDir = GetFileName(ftpDir, L"", existingContacts, false);
+ stream << "option batch continue\noption confirm off\nopen \""
+ << ftpName << "\"\noption transfer binary\n";
+ std::wstring lastCD;
+ size_t filSize = files.size();
+ while(files.size() > 0)
+ {
+ std::wstring localDir = *files.begin();
+ std::wstring currentCD = ftpDir + GetDirectoryName(ReplaceStr(localDir, L'\\', L'/'));
+ if(currentCD != lastCD)
+ {
+ if(!currentCD.empty() && currentCD != L"/")
+ stream << "mkdir \"" << currentCD << "\"\n";
+ stream << "cd \"" << currentCD << "\"\n";
+ lastCD = currentCD;
+ }
+
+ std::wstring name = GetName(localDir);
+ stream << "call MDTM " << name << "\n";
+ stream << "put \"." << localDir << "\"\n";
+ stream << "call MDTM " << name << "\n";
+ files.pop_front();
+ }
+
+ stream.close();
+ std::wstring &log = Options::instance->ftpLogPath;
+ CreateDirectory(GetDirectoryName(log).c_str(), NULL);
+ DeleteFile(log.c_str());
+ TCHAR cmdLine[MAX_PATH];
+ _stprintf_s(cmdLine, _T("\"%s\" /nointeractiveinput /log=\"%s\" /script=script.sc"), Options::instance->ftpExePath.c_str(), log.c_str());
+ STARTUPINFO startupInfo = {0};
+ PROCESS_INFORMATION processInfo;
+ startupInfo.cb = sizeof(STARTUPINFO);
+ if(CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, dir.c_str(), &startupInfo, &processInfo))
+ {
+ WaitForSingleObject(processInfo.hProcess, INFINITE);
+ CloseHandle(processInfo.hThread);
+ CloseHandle(processInfo.hProcess);
+ if(log.empty())
+ {
+ return false;
+ }
+
+ std::wifstream logStream (log.c_str());
+ if(logStream.is_open())
+ {
+ bool isInMDTM = false;
+ std::list<std::wstring> dates;
+ while(!logStream.eof())
+ {
+ std::wstring lineStr;
+ std::getline(logStream, lineStr);
+ if(lineStr.length() > 1)
+ {
+ if(lineStr[0] == L'>')
+ {
+ if(isInMDTM)
+ {
+ if(lineStr.find(L"Script:") < lineStr.length())
+ {
+ dates.push_back(L"");
+ isInMDTM = false;
+ }
+ }
+
+ if(lineStr.find(L"Script: call MDTM") < lineStr.length())
+ {
+ isInMDTM = true;
+ }
+ }
+ else if(isInMDTM && lineStr[0] == L'<')
+ {
+ size_t ss = lineStr.find(L"Script: 213 ");
+ if(ss < lineStr.length())
+ {
+ ss += 12;
+ if(ss < lineStr.length())
+ {
+ lineStr = lineStr.substr(ss);
+ if(lineStr.size() == 14)
+ {
+ dates.push_back(lineStr);
+ isInMDTM = false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(dates.size() > 0 && dates.size() == filSize * 2)
+ {
+ for(std::list<std::wstring>::const_iterator it = dates.begin(); it != dates.end(); ++it)
+ {
+ std::wstring date1 = *it++;
+ if(it->empty() || date1 == *it)
+ return true;
+
+ }
+
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool FtpGetFiles(const std::wstring& dir, const std::list<std::wstring>& files, const std::wstring& ftpName)
+{
+ std::map<std::wstring, bool> existingContacts;
+ std::wstring script = dir + _T("\\script.sc");
+ std::wofstream stream (script.c_str());
+ if(stream.is_open())
+ {
+ stream << "option batch continue\noption confirm off\nopen \""
+ << ftpName << "\"\noption transfer binary\n";
+ std::wstring lastCD;
+ std::list<std::wstring> localFiles;
+ for(std::list<std::wstring>::const_iterator it = files.begin(); it != files.end(); ++it)
+ {
+ std::wstring fileName = GetName(*it);
+ localFiles.push_back(dir + L"\\" + fileName);
+ std::wstring currentCD = GetDirectoryName(*it);
+ if(currentCD != lastCD)
+ {
+ stream << "cd \"" << currentCD << "\"\n";
+ lastCD = currentCD;
+ }
+
+ stream << "get \"" << fileName << "\"\n";
+ }
+
+ stream.close();
+ std::wstring &log = Options::instance->ftpLogPath;
+ CreateDirectory(GetDirectoryName(log).c_str(), NULL);
+ DeleteFile(log.c_str());
+ TCHAR cmdLine[MAX_PATH];
+ _stprintf_s(cmdLine, _T("\"%s\" /nointeractiveinput /log=\"%s\" /script=script.sc"), Options::instance->ftpExePath.c_str(), log.c_str());
+ STARTUPINFO startupInfo = {0};
+ PROCESS_INFORMATION processInfo;
+ startupInfo.cb = sizeof(STARTUPINFO);
+ if(CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, dir.c_str(), &startupInfo, &processInfo))
+ {
+ WaitForSingleObject(processInfo.hProcess, INFINITE);
+ CloseHandle(processInfo.hThread);
+ CloseHandle(processInfo.hProcess);
+ }
+
+ DeleteFile(script.c_str());
+ for(std::list<std::wstring>::const_iterator it = localFiles.begin(); it != localFiles.end(); ++it)
+ {
+ DWORD atr = GetFileAttributes(it->c_str());
+ if(atr == INVALID_FILE_ATTRIBUTES || atr & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return true;
+}
+
+void CreatePath(const TCHAR *szDir)
+{
+ if (!szDir) return;
+
+ DWORD dwAttributes;
+ TCHAR *pszLastBackslash, szTestDir[ MAX_PATH ];
+
+ lstrcpyn( szTestDir, szDir, SIZEOF( szTestDir ));
+ if (( dwAttributes = GetFileAttributes( szTestDir )) != INVALID_FILE_ATTRIBUTES && ( dwAttributes & FILE_ATTRIBUTE_DIRECTORY ))
+ return;
+
+ pszLastBackslash = _tcsrchr( szTestDir, '\\' );
+ if ( pszLastBackslash == NULL )
+ return;
+
+ *pszLastBackslash = '\0';
+ CreatePath( szTestDir );
+ *pszLastBackslash = '\\';
+
+ CreateDirectory( szTestDir, NULL );
+}
+
+INT_PTR ExecuteTaskService(WPARAM wParam, LPARAM lParam)
+{
+ EnterCriticalSection(&Options::instance->criticalSection);
+ int taskNr = (int)wParam;
+ if(taskNr < 0 || taskNr >= (int)Options::instance->taskOptions.size())
+ {
+ LeaveCriticalSection(&Options::instance->criticalSection);
+ return FALSE;
+ }
+
+ Options::instance->taskOptions[taskNr].forceExecute = true;
+ Options::instance->taskOptions[taskNr].showMBAfterExecute = true;
+ LeaveCriticalSection(&Options::instance->criticalSection);
+ StartThread(false);
+ return TRUE;
+}
+
+void DoError(const TaskOptions& to, const std::wstring _error)
+{
+ TCHAR msg[256];
+ _stprintf_s(msg, TranslateT("Task '%s' execution failed:"), to.taskName.c_str());
+ if(Options::instance->schedulerHistoryAlerts)
+ {
+ std::wstring error = msg;
+ error += L"\n";
+ error += _error;
+ DBEVENTINFO dbei = {0};
+ dbei.cbSize = sizeof(DBEVENTINFO);
+ dbei.szModule = MODULE;
+ dbei.flags = DBEF_UTF | DBEF_READ;
+ dbei.timestamp = time(NULL);
+ // For now I do not convert event data from string to blob, and event type must be message to handle it properly
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ int len = (int)error.length() + 1;
+ dbei.cbBlob = WideCharToMultiByte(CP_UTF8, 0, error.c_str(), len, NULL, 0, NULL, NULL);
+ char* buf = new char[dbei.cbBlob];
+ dbei.cbBlob = WideCharToMultiByte(CP_UTF8, 0, error.c_str(), len, buf, dbei.cbBlob, NULL, NULL);
+ dbei.pBlob = (PBYTE)buf;
+ CallService(MS_DB_EVENT_ADD, NULL, (LPARAM) & dbei);
+ }
+
+
+ if(Options::instance->schedulerAlerts)
+ {
+ if(CallService(MS_SYSTEM_TERMINATED, 0, 0)) return;
+ if(ServiceExists(MS_POPUP_ADDPOPUPCLASS))
+ {
+ ShowClassPopupT(MODULE, msg, (wchar_t*)_error.c_str());
+ }
+ else if (ServiceExists( MS_POPUP_ADDPOPUPT ))
+ {
+ POPUPDATAT ppd = {0};
+ ppd.lchIcon = LoadSkinnedIcon(SKINICON_OTHER_HISTORY);
+ _tcscpy_s(ppd.lptzContactName, msg);
+ _tcscpy_s(ppd.lptzText, _error.c_str());
+ CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&ppd, 0);
+ }
+ }
+}