summaryrefslogtreecommitdiff
path: root/protocols/GmailNotifier/src
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2019-03-02 12:32:44 +0300
committerGeorge Hazan <ghazan@miranda.im>2019-03-02 12:32:55 +0300
commit931a7dc1ac0dbc7e6c1083583ced915e572f5b47 (patch)
tree9fe9a6448d44030e26aa7107ce16044ed413e0d0 /protocols/GmailNotifier/src
parentdd7d9954042254e66e3bbbec7195c6be8b1a0663 (diff)
all protocols (even virtual ones) moved to the Protocols folder
Diffstat (limited to 'protocols/GmailNotifier/src')
-rw-r--r--protocols/GmailNotifier/src/check.cpp149
-rw-r--r--protocols/GmailNotifier/src/main.cpp162
-rw-r--r--protocols/GmailNotifier/src/notify.cpp206
-rw-r--r--protocols/GmailNotifier/src/options.cpp284
-rw-r--r--protocols/GmailNotifier/src/resource.h47
-rw-r--r--protocols/GmailNotifier/src/stdafx.cxx18
-rw-r--r--protocols/GmailNotifier/src/stdafx.h100
-rw-r--r--protocols/GmailNotifier/src/utility.cpp77
-rw-r--r--protocols/GmailNotifier/src/version.h13
9 files changed, 1056 insertions, 0 deletions
diff --git a/protocols/GmailNotifier/src/check.cpp b/protocols/GmailNotifier/src/check.cpp
new file mode 100644
index 0000000000..06a1926ef1
--- /dev/null
+++ b/protocols/GmailNotifier/src/check.cpp
@@ -0,0 +1,149 @@
+#include "stdafx.h"
+
+#pragma comment(lib, "Wininet.lib")
+
+static int ParsePage(char *page, resultLink *prst)
+{
+ char *str_head;
+ char *str_tail;
+ char name[64], title[64];
+ int num = 0;
+ wchar_t str[64];
+
+ prst->next = nullptr;
+ if (!(str_head = strstr(page, "<entry>")))
+ return 0;
+
+ while (str_head = strstr(str_head, "<title>")) {
+ prst = prst->next = (resultLink *)malloc(sizeof(resultLink));
+ str_head += 7;
+ str_tail = strstr(str_head, "</title>");
+ *str_tail = '\0';
+ mir_strncpy(title, str_head, 41);
+ if (mir_strlen(title) == 40)
+ mir_strcat(title, "...");
+ *str_tail = ' ';
+
+ str_head = strstr(str_head, "<name>") + 6;
+ str_tail = strstr(str_head, "</name>");
+ *str_tail = '\0';
+ mir_strncpy(name, str_head, 11);
+ mir_strcat(name, ": ");
+ *str_tail = ' ';
+
+ mir_strcpy(prst->content, name);
+ mir_strcat(prst->content, title);
+ MultiByteToWideChar(CP_UTF8, 0, prst->content, -1, str, 64);
+ WideCharToMultiByte(CP_ACP, 0, str, -1, prst->content, 64, nullptr, nullptr);
+ num++;
+ }
+ prst->next = nullptr;
+ return num;
+}
+
+void CheckMailInbox(Account *curAcc)
+{
+ if (curAcc->IsChecking)
+ return;
+
+ curAcc->IsChecking = true;
+
+ ptrA szNick(db_get_sa(curAcc->hContact, "CList", "MyHandle", curAcc->name));
+
+ char *tail = strstr(szNick, " [");
+ if (tail) *tail = 0;
+
+ db_set_s(curAcc->hContact, "CList", "MyHandle", CMStringA(FORMAT, "%s [%s]", szNick.get(), Translate("Checking...")));
+
+ if (curAcc->hosted[0]) {
+ CMStringA szUrl(FORMAT, "https://www.google.com/a/%s/LoginAction", curAcc->hosted);
+ CMStringA szBody("continue=https%3A%2F%2Fmail.google.com%2Fa%2F");
+ szBody.Append(curAcc->hosted);
+ szBody.Append("%2Ffeed%2Fatom&service=mail&userName=");
+ tail = strchr(curAcc->name, '@');
+ if (tail) *tail = 0;
+ szBody.Append(curAcc->name);
+ if (tail) *tail = '@';
+ szBody.Append("&password=");
+ szBody.Append(curAcc->pass);
+
+ NETLIBHTTPHEADER headers[1] = {
+ { "Content-Type", "application/x-www-form-urlencoded" }
+ };
+
+ NETLIBHTTPREQUEST nlr = {};
+ nlr.cbSize = sizeof(nlr);
+ nlr.szUrl = szUrl.GetBuffer();
+ nlr.requestType = REQUEST_POST;
+ nlr.headersCount = _countof(headers);
+ nlr.headers = headers;
+ nlr.dataLength = szBody.GetLength();
+ nlr.pData = szBody.GetBuffer();
+
+ NETLIBHTTPREQUEST *nlu = Netlib_HttpTransaction(hNetlibUser, &nlr);
+ if (nlu == nullptr || nlu->resultCode != 200) {
+ mir_strcpy(curAcc->results.content, Translate("Can't send account data!"));
+
+ Netlib_FreeHttpRequest(nlu);
+ curAcc->results_num = -1;
+ mir_strcat(curAcc->results.content, "]");
+ curAcc->IsChecking = false;
+ return;
+ }
+
+ Netlib_FreeHttpRequest(nlu);
+ }
+
+ // go!
+ CMStringA loginPass(FORMAT, "%s:%s", curAcc->name, curAcc->pass);
+ ptrA loginPassEncoded(mir_base64_encode(loginPass.c_str(), loginPass.GetLength()));
+
+ CMStringA szUrl("https://mail.google.com"), szAuth(FORMAT, "Basic %s", loginPassEncoded.get());
+ if (curAcc->hosted[0])
+ szUrl.AppendFormat("/a/%s/feed/atom", curAcc->hosted);
+ else
+ szUrl.Append("/mail/feed/atom");
+
+ NETLIBHTTPHEADER headers[1] = {
+ { "Authorization", szAuth.GetBuffer() }
+ };
+
+ NETLIBHTTPREQUEST nlr = {};
+ nlr.cbSize = sizeof(nlr);
+ nlr.szUrl = szUrl.GetBuffer();
+ nlr.requestType = REQUEST_GET;
+ nlr.headers = headers;
+ nlr.headersCount = _countof(headers);
+
+ NETLIBHTTPREQUEST *nlu = Netlib_HttpTransaction(hNetlibUser, &nlr);
+ if (nlu == nullptr) {
+ mir_snprintf(curAcc->results.content, "%s [%s]", szNick.get(),
+ (nlr.resultCode == 401) ? Translate("Wrong name or password!") : Translate("Can't get RSS feed!"));
+ Netlib_FreeHttpRequest(nlu);
+
+ curAcc->results_num = -1;
+ curAcc->IsChecking = false;
+ return;
+ }
+
+ curAcc->results_num = ParsePage(nlu->pData, &curAcc->results);
+ mir_snprintf(curAcc->results.content, "%s [%d]", szNick.get(), curAcc->results_num);
+
+ curAcc->IsChecking = false;
+}
+
+void __cdecl Check_ThreadFunc(void *lpParam)
+{
+ if (lpParam) {
+ CheckMailInbox((Account *)lpParam);
+ NotifyUser((Account *)lpParam);
+ }
+ else {
+ for (auto &it : g_accs) {
+ if (GetContactProto(it->hContact)) {
+ CheckMailInbox(it);
+ NotifyUser(it);
+ }
+ }
+ }
+}
diff --git a/protocols/GmailNotifier/src/main.cpp b/protocols/GmailNotifier/src/main.cpp
new file mode 100644
index 0000000000..42158bd826
--- /dev/null
+++ b/protocols/GmailNotifier/src/main.cpp
@@ -0,0 +1,162 @@
+/*
+Miranda plugin template, originally by Richard Hughes
+http://miranda-icq.sourceforge.net/
+
+This file is placed in the public domain. Anybody is free to use or
+modify it as they wish with no restriction.
+There is no warranty.
+*/
+
+#include "stdafx.h"
+#include "version.h"
+
+CMPlugin g_plugin;
+
+UINT hTimer;
+HNETLIBUSER hNetlibUser;
+NOTIFYICONDATA niData;
+optionSettings opt;
+
+OBJLIST<Account> g_accs(1);
+BOOL optionWindowIsOpen = FALSE;
+short ID_STATUS_NONEW;
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static PLUGININFOEX pluginInfoEx =
+{
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {243955E0-75D9-4CC3-9B28-6F9C5AF4532D}
+ { 0x243955e0, 0x75d9, 0x4cc3, { 0x9b, 0x28, 0x6f, 0x9c, 0x5a, 0xf4, 0x53, 0x2d } }
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(MODULENAME, pluginInfoEx)
+{
+ RegisterProtocol(PROTOTYPE_VIRTUAL);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+INT_PTR GetCaps(WPARAM wParam, LPARAM)
+{
+ if (wParam == PFLAGNUM_2 && opt.ShowCustomIcon)
+ return PF2_ONLINE | PF2_LIGHTDND | PF2_SHORTAWAY;
+
+ return 0;
+}
+
+INT_PTR GetStatus(WPARAM, LPARAM)
+{
+ return ID_STATUS_ONLINE;
+}
+
+INT_PTR GetName(WPARAM wParam, LPARAM lParam)
+{
+ mir_strncpy((char*)lParam, MODULENAME, wParam);
+ return 0;
+}
+
+void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD)
+{
+ PluginMenuCommand(0, 0);
+}
+
+INT_PTR PluginMenuCommand(WPARAM hContact, LPARAM)
+{
+ if (!optionWindowIsOpen)
+ mir_forkthread(Check_ThreadFunc, GetAccountByContact(hContact));
+
+ return 0;
+}
+
+static int OnMirandaStart(WPARAM, LPARAM)
+{
+ PluginMenuCommand(0, 0);
+ return 0;
+}
+
+int CMPlugin::Load()
+{
+ g_plugin.addSound("Gmail", LPGENW("Other"), LPGENW("Gmail: New thread(s)"));
+ HookEvent(ME_CLIST_DOUBLECLICKED, OpenBrowser);
+
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS | NUF_NOHTTPSOPTION | NUF_UNICODE;
+ nlu.szSettingsModule = MODULENAME;
+ nlu.szDescriptiveName.w = TranslateT("Gmail Notifier connection");
+ hNetlibUser = Netlib_RegisterUser(&nlu);
+
+ CreateProtoServiceFunction(MODULENAME, PS_GETCAPS, GetCaps);
+ CreateProtoServiceFunction(MODULENAME, PS_GETSTATUS, GetStatus);
+ CreateProtoServiceFunction(MODULENAME, PS_GETNAME, GetName);
+ CreateServiceFunction("GmailMNotifier/Notifying", Notifying);
+
+ opt.circleTime = g_plugin.getDword("circleTime", 30);
+ opt.notifierOnTray = g_plugin.getDword("notifierOnTray", TRUE);
+ opt.notifierOnPop = g_plugin.getDword("notifierOnPop", TRUE);
+ opt.popupDuration = g_plugin.getDword("popupDuration", -1);
+ opt.popupBgColor = g_plugin.getDword("popupBgColor", RGB(173, 206, 247));
+ opt.popupTxtColor = g_plugin.getDword("popupTxtColor", RGB(0, 0, 0));
+ opt.OpenUsePrg = g_plugin.getDword("OpenUsePrg", 0);
+ opt.ShowCustomIcon = g_plugin.getDword("ShowCustomIcon", FALSE);
+ opt.UseOnline = g_plugin.getDword("UseOnline", FALSE);
+ opt.AutoLogin = g_plugin.getDword("AutoLogin", TRUE);
+ opt.LogThreads = g_plugin.getDword("LogThreads", FALSE);
+
+ DBVARIANT dbv;
+ if (db_get_s(0, "SkinIcons", "core_status_" MODULENAME "4", &dbv)) {
+ db_set_s(0, "SkinIcons", "core_status_" MODULENAME "0", "plugins\\GmailNotifier.dll,2");
+ db_set_s(0, "SkinIcons", "core_status_" MODULENAME "1", "plugins\\GmailNotifier.dll,2");
+ db_set_s(0, "SkinIcons", "core_status_" MODULENAME "2", "plugins\\GmailNotifier.dll,0");
+ db_set_s(0, "SkinIcons", "core_status_" MODULENAME "4", "plugins\\GmailNotifier.dll,1");
+ }
+ else db_free(&dbv);
+
+ BuildList();
+ ID_STATUS_NONEW = opt.UseOnline ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE;
+ for (auto &it : g_accs)
+ db_set_dw(it->hContact, MODULENAME, "Status", ID_STATUS_NONEW);
+
+ hTimer = SetTimer(nullptr, 0, opt.circleTime * 60000, TimerProc);
+ HookEvent(ME_SYSTEM_MODULESLOADED, OnMirandaStart);
+ HookEvent(ME_OPT_INITIALISE, OptInit);
+
+ CreateServiceFunction(MODULENAME "/MenuCommand", PluginMenuCommand);
+
+ CMenuItem mi(&g_plugin);
+ SET_UID(mi, 0xbe16f37, 0x17be, 0x4494, 0xaa, 0xb2, 0x3a, 0xa7, 0x38, 0xfa, 0xf9, 0xcc);
+ mi.position = -0x7FFFFFFF;
+ mi.hIcolibItem = Skin_LoadProtoIcon(MODULENAME, ID_STATUS_ONLINE);
+ mi.name.a = LPGEN("&Check all Gmail inboxes");
+ mi.pszService = MODULENAME "/MenuCommand";
+ Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0x22c6ace1, 0xba0c, 0x44b5, 0xa4, 0xd2, 0x1, 0x7d, 0xb1, 0xe0, 0x51, 0xeb);
+ mi.name.a = LPGEN("&Check Gmail inbox");
+ mi.pszService = "/MenuCommand";
+ Menu_AddContactMenuItem(&mi, MODULENAME);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Unload()
+{
+ if (hTimer)
+ KillTimer(nullptr, hTimer);
+
+ for (auto &it : g_accs)
+ DeleteResults(it->results.next);
+ g_accs.destroy();
+
+ Netlib_CloseHandle(hNetlibUser);
+ return 0;
+}
diff --git a/protocols/GmailNotifier/src/notify.cpp b/protocols/GmailNotifier/src/notify.cpp
new file mode 100644
index 0000000000..54b47560a6
--- /dev/null
+++ b/protocols/GmailNotifier/src/notify.cpp
@@ -0,0 +1,206 @@
+#include "stdafx.h"
+
+static void __cdecl Login_ThreadFunc(Account *curAcc)
+{
+ if (curAcc == nullptr)
+ return;
+
+ HANDLE hTempFile;
+ DWORD dwBytesWritten, dwBufSize = 1024;
+ char szTempName[MAX_PATH];
+ char buffer[1024];
+ char *str_temp;
+ char lpPathBuffer[1024];
+
+ if (GetBrowser(lpPathBuffer)) {
+ if (opt.AutoLogin == 0) {
+ if (curAcc->hosted[0]) {
+ mir_strcat(lpPathBuffer, "https://mail.google.com/a/");
+ mir_strcat(lpPathBuffer, curAcc->hosted);
+ mir_strcat(lpPathBuffer, "/?logout");
+ }
+ else {
+ mir_strcat(lpPathBuffer, "https://mail.google.com/mail/?logout");
+ }
+ }
+ else {
+ if (curAcc->hosted[0]) {
+ GetTempPathA(dwBufSize, buffer);
+ GetTempFileNameA(buffer, "gmail", 0, szTempName);
+
+ hTempFile = CreateFileA(szTempName, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+ mir_strcpy(buffer, FORMDATA1);
+ mir_strcat(buffer, curAcc->hosted);
+ mir_strcat(buffer, FORMDATA2);
+ mir_strcat(buffer, curAcc->hosted);
+ mir_strcat(buffer, FORMDATA3);
+ mir_strcat(buffer, "<input type=hidden name=userName value=");
+ mir_strcat(buffer, curAcc->name);
+ if ((str_temp = strstr(buffer, "@")) != nullptr)
+ *str_temp = '\0';
+ mir_strcat(buffer, "><input type=hidden name=password value=");
+ mir_strcat(buffer, curAcc->pass);
+ mir_strcat(buffer, "></form></body>");
+ WriteFile(hTempFile, buffer, (DWORD)mir_strlen(buffer), &dwBytesWritten, nullptr);
+ CloseHandle(hTempFile);
+ mir_strcat(lpPathBuffer, szTempName);
+ }
+ else {
+ mir_strcat(lpPathBuffer, LINK);
+ mir_strcat(lpPathBuffer, mir_urlEncode(curAcc->name));
+ if (opt.AutoLogin == 1)
+ mir_strcat(lpPathBuffer, "&PersistentCookie=yes");
+ }
+ }
+ }
+
+ STARTUPINFOA suInfo = { 0 };
+ PROCESS_INFORMATION procInfo;
+ suInfo.cb = sizeof(suInfo);
+ suInfo.wShowWindow = SW_MAXIMIZE;
+ if (CreateProcessA(nullptr, lpPathBuffer, nullptr, nullptr, FALSE, 0, nullptr, nullptr, &suInfo, &procInfo))
+ CloseHandle(procInfo.hProcess);
+
+ if (curAcc->hosted[0]) {
+ Sleep(30000);
+ DeleteFileA(szTempName);
+ }
+}
+
+int OpenBrowser(WPARAM hContact, LPARAM)
+{
+ char *proto = GetContactProto(hContact);
+ if (proto && !mir_strcmp(proto, MODULENAME)) {
+ Account *curAcc = GetAccountByContact(hContact);
+ PUDeletePopup(curAcc->popUpHwnd);
+ g_clistApi.pfnRemoveEvent(curAcc->hContact, 1);
+ if (GetKeyState(VK_SHIFT) >> 8 || optionWindowIsOpen)
+ return FALSE;
+
+ if (curAcc->oldResults_num != 0) {
+ g_plugin.setWord(curAcc->hContact, "Status", ID_STATUS_NONEW);
+ curAcc->oldResults_num = 0;
+ DeleteResults(curAcc->results.next);
+ curAcc->results.next = nullptr;
+ }
+ mir_forkThread<Account>(Login_ThreadFunc, curAcc);
+ }
+ return FALSE;
+}
+
+INT_PTR Notifying(WPARAM, LPARAM lParam)
+{
+ OpenBrowser(((CLISTEVENT*)lParam)->hContact, 0);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ MCONTACT hContact = PUGetContact(hWnd);
+ Account *curAcc = GetAccountByContact(hContact);
+
+ switch (message) {
+ case UM_INITPOPUP:
+ curAcc->popUpHwnd = hWnd;
+ break;
+
+ case WM_COMMAND:
+ if (HIWORD(wParam) == STN_CLICKED)
+ OpenBrowser((WPARAM)hContact, 0);
+ break;
+
+ case WM_CONTEXTMENU:
+ PUDeletePopup(hWnd);
+ curAcc->popUpHwnd = nullptr;
+ g_clistApi.pfnRemoveEvent(hContact, 1);
+ }
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+void NotifyUser(Account *curAcc)
+{
+ if (optionWindowIsOpen)
+ return;
+
+ db_set_s(curAcc->hContact, "CList", "MyHandle", curAcc->results.content);
+ switch (curAcc->results_num) {
+ case 0:
+ PUDeletePopup(curAcc->popUpHwnd);
+ g_clistApi.pfnRemoveEvent(curAcc->hContact, 1);
+ if (curAcc->oldResults_num != 0)
+ g_plugin.setWord(curAcc->hContact, "Status", ID_STATUS_NONEW);
+ break;
+
+ case -1:
+ g_plugin.setWord(curAcc->hContact, "Status", ID_STATUS_AWAY);
+ break;
+
+ default:
+ g_plugin.setWord(curAcc->hContact, "Status", ID_STATUS_OCCUPIED);
+ int newMails = (curAcc->oldResults_num == -1) ? (curAcc->results_num) : (curAcc->results_num - curAcc->oldResults_num);
+ if (opt.LogThreads&&newMails > 0) {
+ DBEVENTINFO dbei = {};
+ dbei.eventType = EVENTTYPE_MESSAGE;
+ dbei.flags = DBEF_READ;
+ dbei.szModule = MODULENAME;
+ dbei.timestamp = time(0);
+
+ resultLink *prst = curAcc->results.next;
+ for (int i = 0; i < newMails; i++) {
+ dbei.cbBlob = (DWORD)mir_strlen(prst->content) + 1;
+ dbei.pBlob = (PBYTE)prst->content;
+ db_event_add(curAcc->hContact, &dbei);
+ prst = prst->next;
+ }
+ }
+ if (opt.notifierOnTray&&newMails > 0) {
+ g_clistApi.pfnRemoveEvent(curAcc->hContact, 1);
+
+ CLISTEVENT cle = {};
+ cle.hContact = curAcc->hContact;
+ cle.hDbEvent = 1;
+ cle.flags = CLEF_URGENT;
+ cle.hIcon = Skin_LoadProtoIcon(MODULENAME, ID_STATUS_OCCUPIED);
+ cle.pszService = "GmailMNotifier/Notifying";
+ cle.szTooltip.a = curAcc->results.next->content;
+ g_clistApi.pfnAddEvent(&cle);
+ }
+
+ if (opt.notifierOnPop&&newMails > 0) {
+ POPUPDATA ppd = { 0 };
+
+ ppd.lchContact = curAcc->hContact;
+ ppd.lchIcon = Skin_LoadProtoIcon(MODULENAME, ID_STATUS_OCCUPIED);
+ mir_strcpy(ppd.lpzContactName, curAcc->results.content);
+ resultLink *prst = curAcc->results.next;
+ for (int i = 0; i < 5 && i < newMails; i++) {
+ mir_strcat(ppd.lpzText, prst->content);
+ mir_strcat(ppd.lpzText, "\n");
+ prst = prst->next;
+ }
+ ppd.colorBack = opt.popupBgColor;
+ ppd.colorText = opt.popupTxtColor;
+ ppd.PluginWindowProc = PopupDlgProc;
+ ppd.PluginData = nullptr;
+ ppd.iSeconds = opt.popupDuration;
+ PUDeletePopup(curAcc->popUpHwnd);
+ PUAddPopup(&ppd);
+ }
+ if (newMails > 0)
+ Skin_PlaySound("Gmail");
+ }
+ curAcc->oldResults_num = curAcc->results_num;
+ DeleteResults(curAcc->results.next);
+ curAcc->results.next = nullptr;
+}
+
+void DeleteResults(resultLink *prst)
+{
+ if (prst != nullptr) {
+ if (prst->next != nullptr)
+ DeleteResults(prst->next);
+ free(prst);
+ }
+}
diff --git a/protocols/GmailNotifier/src/options.cpp b/protocols/GmailNotifier/src/options.cpp
new file mode 100644
index 0000000000..3d83fe4671
--- /dev/null
+++ b/protocols/GmailNotifier/src/options.cpp
@@ -0,0 +1,284 @@
+#include "stdafx.h"
+
+static void SaveButton(HWND hwndDlg, HWND hwndCombo, int curIndex)
+{
+ if (curIndex < 0 || curIndex >= g_accs.getCount())
+ return;
+
+ Account &acc = g_accs[curIndex];
+ if (GetDlgItemTextA(hwndDlg, IDC_NAME, acc.name, _countof(acc.name))) {
+ char *tail = strstr(acc.name, "@");
+ if (tail && mir_strcmp(tail + 1, "gmail.com") != 0)
+ mir_strcpy(acc.hosted, tail + 1);
+ SendMessageA(hwndCombo, CB_DELETESTRING, curIndex, 0);
+ SendMessageA(hwndCombo, CB_INSERTSTRING, curIndex, (LPARAM)acc.name);
+ SendMessageA(hwndCombo, CB_SETCURSEL, curIndex, 0);
+ g_plugin.setString(acc.hContact, "name", acc.name);
+ g_plugin.setString(acc.hContact, "Nick", acc.name);
+
+ GetDlgItemTextA(hwndDlg, IDC_PASS, acc.pass, _countof(acc.pass));
+ g_plugin.setString(acc.hContact, "Password", acc.pass);
+ }
+}
+
+static INT_PTR CALLBACK DlgProcOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ int ShowControl;
+ char str[MAX_PATH] = { 0 };
+ static int curIndex = 0;
+ static bool bInit = false;
+ HWND hwndCombo = GetDlgItem(hwndDlg, IDC_NAME);
+
+ if (g_accs.getCount()) {
+ EnableWindow(hwndCombo, TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PASS), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTNSAV), TRUE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTNDEL), TRUE);
+ }
+ else {
+ EnableWindow(hwndCombo, FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PASS), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTNSAV), FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BTNDEL), FALSE);
+ }
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ bInit = true;
+ TranslateDialogDefault(hwndDlg);
+ optionWindowIsOpen = TRUE;
+ BuildList();
+
+ for (auto &it : g_accs)
+ SendMessageA(hwndCombo, CB_ADDSTRING, 0, (LONG_PTR)it->name);
+ SendMessage(hwndCombo, CB_SETCURSEL, curIndex, 0);
+ if (curIndex < g_accs.getCount())
+ SetDlgItemTextA(hwndDlg, IDC_PASS, g_accs[curIndex].pass);
+
+ SetDlgItemInt(hwndDlg, IDC_CIRCLE, opt.circleTime, FALSE);
+ if (opt.notifierOnTray)
+ CheckDlgButton(hwndDlg, IDC_OPTTRAY, BST_CHECKED);
+ if (opt.notifierOnPop) {
+ CheckDlgButton(hwndDlg, IDC_OPTPOP, BST_CHECKED);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_DURATION), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_BGCOLOR), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_TEXTCOLOR), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_DURATION), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_COLOR), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_LESS), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_SEC), SW_SHOW);
+ }
+
+ SetDlgItemInt(hwndDlg, IDC_DURATION, opt.popupDuration, TRUE);
+ SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_SETCOLOUR, 0, opt.popupBgColor);
+ SendDlgItemMessage(hwndDlg, IDC_TEXTCOLOR, CPM_SETCOLOUR, 0, opt.popupTxtColor);
+
+ if (opt.OpenUsePrg == 0)
+ CheckDlgButton(hwndDlg, IDC_SYSDEF, BST_CHECKED);
+ else if (opt.OpenUsePrg == 1)
+ CheckDlgButton(hwndDlg, IDC_USEIE, BST_CHECKED);
+ else if (opt.OpenUsePrg == 2) {
+ CheckDlgButton(hwndDlg, IDC_STARTPRG, BST_CHECKED);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PRG), SW_SHOW);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PRGBROWSE), SW_SHOW);
+ }
+ {
+ DBVARIANT dbv;
+ if (!g_plugin.getString("OpenUsePrgPath", &dbv)) {
+ mir_strcpy(str, dbv.pszVal);
+ db_free(&dbv);
+ }
+ }
+ SetDlgItemTextA(hwndDlg, IDC_PRG, str);
+
+ if (opt.UseOnline)
+ CheckDlgButton(hwndDlg, IDC_ONLINE, BST_CHECKED);
+ if (opt.ShowCustomIcon)
+ CheckDlgButton(hwndDlg, IDC_SHOWICON, BST_CHECKED);
+ if (opt.AutoLogin == 0)
+ CheckDlgButton(hwndDlg, IDC_AUTOLOGIN, BST_CHECKED);
+ else if (opt.AutoLogin == 1)
+ CheckDlgButton(hwndDlg, IDC_AUTOLOGIN, BST_UNCHECKED);
+ else if (opt.AutoLogin == 2)
+ CheckDlgButton(hwndDlg, IDC_AUTOLOGIN, BST_INDETERMINATE);
+ if (opt.LogThreads)
+ CheckDlgButton(hwndDlg, IDC_LOGTHREADS, BST_CHECKED);
+
+ bInit = false;
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_SYSDEF:
+ case IDC_USEIE:
+ case IDC_STARTPRG:
+ ShowControl = IsDlgButtonChecked(hwndDlg, IDC_STARTPRG) ? SW_SHOW : SW_HIDE;
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PRG), ShowControl);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PRGBROWSE), ShowControl);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_OPTPOP:
+ ShowControl = IsDlgButtonChecked(hwndDlg, IDC_OPTPOP) ? SW_SHOW : SW_HIDE;
+ ShowWindow(GetDlgItem(hwndDlg, IDC_DURATION), ShowControl);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_BGCOLOR), ShowControl);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_TEXTCOLOR), ShowControl);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_DURATION), ShowControl);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_COLOR), ShowControl);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_LESS), ShowControl);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_SEC), ShowControl);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_PRGBROWSE:
+ wchar_t szName[_MAX_PATH];
+ GetDlgItemText(hwndDlg, IDC_PRG, szName, _countof(szName));
+ {
+ OPENFILENAME OpenFileName = {};
+ OpenFileName.lStructSize = sizeof(OPENFILENAME);
+ OpenFileName.hwndOwner = hwndDlg;
+ OpenFileName.lpstrFilter = L"Executables (*.exe;*.com;*.bat)\0*.exe;*.com;*.bat\0\0";
+ OpenFileName.lpstrFile = szName;
+ OpenFileName.nMaxFile = _countof(szName);
+ OpenFileName.Flags = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
+ if (!GetOpenFileName(&OpenFileName))
+ return 0;
+ SetDlgItemText(hwndDlg, IDC_PRG, szName);
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_BTNADD:
+ {
+ Account *p = new Account();
+ p->hContact = db_add_contact();
+ Proto_AddToContact(p->hContact, MODULENAME);
+ g_accs.insert(p);
+
+ curIndex = SendMessageA(hwndCombo, CB_ADDSTRING, 0, (LPARAM)"");
+ SendMessage(hwndCombo, CB_SETCURSEL, curIndex, 0);
+ SetDlgItemTextA(hwndDlg, IDC_PASS, "");
+ SetFocus(hwndCombo);
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_BTNSAV:
+ SaveButton(hwndDlg, hwndCombo, curIndex);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_BTNDEL:
+ {
+ SendMessage(hwndCombo, CB_DELETESTRING, curIndex, 0);
+
+ Account &acc = g_accs[curIndex];
+ DeleteResults(acc.results.next);
+ db_delete_contact(acc.hContact);
+ g_accs.remove(curIndex);
+
+ curIndex = 0;
+ SendMessage(hwndCombo, CB_SETCURSEL, 0, 0);
+ if (g_accs.getCount())
+ SetDlgItemTextA(hwndDlg, IDC_PASS, g_accs[0].pass);
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_NAME:
+ if (HIWORD(wParam) == CBN_SELCHANGE) {
+ curIndex = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ SetDlgItemTextA(hwndDlg, IDC_PASS, g_accs[curIndex].pass);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+
+ case IDC_CIRCLE:
+ case IDC_DURATION:
+ if (!bInit && (HIWORD(wParam) == EN_CHANGE))
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_ONLINE:
+ case IDC_SHOWICON:
+ case IDC_AUTOLOGIN:
+ case IDC_LOGTHREADS:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+
+ return TRUE;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_APPLY:
+ SaveButton(hwndDlg, hwndCombo, curIndex);
+ opt.circleTime = GetDlgItemInt(hwndDlg, IDC_CIRCLE, nullptr, FALSE);
+ if (opt.circleTime > 0) {
+ KillTimer(nullptr, hTimer);
+ hTimer = SetTimer(nullptr, 0, opt.circleTime * 60000, TimerProc);
+ g_plugin.setDword("circleTime", opt.circleTime);
+ }
+ opt.notifierOnTray = IsDlgButtonChecked(hwndDlg, IDC_OPTTRAY);
+ opt.notifierOnPop = IsDlgButtonChecked(hwndDlg, IDC_OPTPOP);
+ g_plugin.setDword("notifierOnTray", opt.notifierOnTray);
+ g_plugin.setDword("notifierOnPop", opt.notifierOnPop);
+
+ opt.popupDuration = GetDlgItemInt(hwndDlg, IDC_DURATION, nullptr, TRUE);
+ g_plugin.setDword("popupDuration", opt.popupDuration);
+
+ opt.popupBgColor = SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_GETCOLOUR, 0, opt.popupBgColor);
+ opt.popupTxtColor = SendDlgItemMessage(hwndDlg, IDC_TEXTCOLOR, CPM_GETCOLOUR, 0, opt.popupBgColor);
+ g_plugin.setDword("popupBgColor", opt.popupBgColor);
+ g_plugin.setDword("popupTxtColor", opt.popupTxtColor);
+
+ if (IsDlgButtonChecked(hwndDlg, IDC_SYSDEF) == BST_CHECKED)
+ opt.OpenUsePrg = 0;
+ else if (IsDlgButtonChecked(hwndDlg, IDC_USEIE) == BST_CHECKED)
+ opt.OpenUsePrg = 1;
+ else if (IsDlgButtonChecked(hwndDlg, IDC_STARTPRG) == BST_CHECKED) {
+ opt.OpenUsePrg = 2;
+ }
+ GetDlgItemTextA(hwndDlg, IDC_PRG, str, _countof(str));
+
+ g_plugin.setDword("OpenUsePrg", opt.OpenUsePrg);
+ g_plugin.setString("OpenUsePrgPath", str);
+
+ opt.ShowCustomIcon = IsDlgButtonChecked(hwndDlg, IDC_SHOWICON);
+ opt.UseOnline = IsDlgButtonChecked(hwndDlg, IDC_ONLINE);
+ if (IsDlgButtonChecked(hwndDlg, IDC_AUTOLOGIN) == BST_CHECKED)
+ opt.AutoLogin = 0;
+ else if (IsDlgButtonChecked(hwndDlg, IDC_AUTOLOGIN) == BST_UNCHECKED)
+ opt.AutoLogin = 1;
+ else if (IsDlgButtonChecked(hwndDlg, IDC_AUTOLOGIN) == BST_INDETERMINATE)
+ opt.AutoLogin = 2;
+ opt.LogThreads = IsDlgButtonChecked(hwndDlg, IDC_LOGTHREADS);
+ g_plugin.setDword("ShowCustomIcon", opt.ShowCustomIcon);
+ g_plugin.setDword("UseOnline", opt.UseOnline);
+ g_plugin.setDword("AutoLogin", opt.AutoLogin);
+ g_plugin.setDword("LogThreads", opt.LogThreads);
+
+ ID_STATUS_NONEW = opt.UseOnline ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE;
+ for (auto &it : g_accs)
+ g_plugin.setWord(it->hContact, "Status", ID_STATUS_NONEW);
+ }
+ return TRUE;
+
+ case WM_CLOSE:
+ optionWindowIsOpen = FALSE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int OptInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.position = -790000000;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT);
+ odp.szTitle.a = LPGEN("GmailNotifier");
+ odp.szGroup.a = LPGEN("Network");
+ odp.flags = ODPF_BOLDGROUPS;
+ odp.pfnDlgProc = DlgProcOpts;
+ g_plugin.addOptions(wParam, &odp);
+ return 0;
+}
diff --git a/protocols/GmailNotifier/src/resource.h b/protocols/GmailNotifier/src/resource.h
new file mode 100644
index 0000000000..7979aabf00
--- /dev/null
+++ b/protocols/GmailNotifier/src/resource.h
@@ -0,0 +1,47 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by C:\Users\xx\Documents\Visual Studio 2010\Projects\miranda-ng\plugins\GmailNotifier\res\options.rc
+//
+#define IDD_OPT 101
+#define IDI_ICONNEW 106
+#define IDI_ICONERR 109
+#define IDI_ICONEPT 111
+#define IDC_GROUPMAIN 1000
+#define IDC_CONFIG 1001
+#define IDC_CONFIRM 1002
+#define IDC_OPTTRAY 1002
+#define IDC_OPTPOP 1003
+#define IDC_USEIE 1004
+#define IDC_STATIC_DURATION 1006
+#define IDC_BGCOLOR 1007
+#define IDC_TEXTCOLOR 1008
+#define IDC_PRG 1009
+#define IDC_SYSDEF 1010
+#define IDC_STARTPRG 1011
+#define IDC_PRGBROWSE 1012
+#define IDC_STATIC_COLOR 1014
+#define IDC_STATIC_LESS 1016
+#define IDC_STATIC_SEC 1017
+#define IDC_STATIC_CUSTOM 1018
+#define IDC_BTNADD 1019
+#define IDC_PASS 1020
+#define IDC_BTNSAV 1021
+#define IDC_NAME 1022
+#define IDC_CIRCLE 1023
+#define IDC_DURATION 1024
+#define IDC_SHOWICON 1025
+#define IDC_BTNDEL 1026
+#define IDC_AUTOLOGIN 1028
+#define IDC_LOGTHREADS 1029
+#define IDC_ONLINE 1036
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 113
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1008
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/GmailNotifier/src/stdafx.cxx b/protocols/GmailNotifier/src/stdafx.cxx
new file mode 100644
index 0000000000..1b563fc866
--- /dev/null
+++ b/protocols/GmailNotifier/src/stdafx.cxx
@@ -0,0 +1,18 @@
+/*
+Copyright (C) 2012-19 Miranda NG team (https://miranda-ng.org)
+
+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" \ No newline at end of file
diff --git a/protocols/GmailNotifier/src/stdafx.h b/protocols/GmailNotifier/src/stdafx.h
new file mode 100644
index 0000000000..da6bc1039d
--- /dev/null
+++ b/protocols/GmailNotifier/src/stdafx.h
@@ -0,0 +1,100 @@
+#pragma once
+
+#include <windows.h>
+#include <time.h>
+#include <stdio.h>
+#include "resource.h"
+
+#include "newpluginapi.h"
+#include "m_clistint.h"
+#include "m_skin.h"
+#include "m_langpack.h"
+#include "m_database.h"
+#include "m_system.h"
+#include "m_protocols.h"
+#include "m_userinfo.h"
+#include "m_options.h"
+#include "m_protosvc.h"
+#include "m_utils.h"
+#include "m_ignore.h"
+#include "m_clc.h"
+#include "m_popup.h"
+#include "m_netlib.h"
+
+#define WM_SHELLNOTIFY WM_USER+5
+#define IDI_TRAY WM_USER+6
+#define MODULENAME "GmailMNotifier"
+#define _MAX_DOWN_BUFFER 65536
+#define LINK "https://accounts.google.com/ServiceLogin?continue=https%3A%2F%2Fmail.google.com%2Fmail&service=mail&passive=true&Email="
+#define FORMDATA1 "<body onload=document.gmail.submit();><form name=gmail action=https://www.google.com/a/"
+#define FORMDATA2 "/LoginAction method=POST><input type=hidden name=continue value=https://mail.google.com/a/"
+#define FORMDATA3 "><INPUT type=hidden value=mail name=service>"
+// #define STR1 "javascript:document.write('<form name=gmail action=https://www.google.com/a/"
+// #define STR2 "/LoginAction method=post><input type=hidden name=continue value=https://mail.google.com/hosted/"
+// #define STR3 "><input type=hidden value=mail name=service><input type=hidden name=userName value="
+// #define STR4 "><input type=hidden name=password value="
+// #define STR5 ">');document.gmail.submit();"
+//#define LINK2 "https://www.google.com/a/altmanoptik.com/LoginAction?continue=https%3A%2F%2Fmail.google.com%2Fhosted%2Faltmanoptik.com&service=mail&userName=test&password=123456"
+
+struct resultLink
+{
+ char content[64];
+ struct resultLink *next;
+};
+
+struct Account : public MZeroedObject
+{
+ char name[256];
+ char pass[256];
+ char hosted[64];
+ MCONTACT hContact;
+ int oldResults_num;
+ int results_num;
+ resultLink results;
+ HWND popUpHwnd;
+ bool IsChecking;
+};
+
+struct optionSettings
+{
+ int circleTime;
+ BOOL notifierOnTray;
+ BOOL notifierOnPop;
+ int popupDuration;
+ COLORREF popupTxtColor;
+ COLORREF popupBgColor;
+ int OpenUsePrg;
+ BOOL ShowCustomIcon;
+ BOOL UseOnline;
+ int AutoLogin;
+ BOOL LogThreads;
+};
+
+extern OBJLIST<Account> g_accs;
+extern optionSettings opt;
+extern HNETLIBUSER hNetlibUser;
+extern UINT hTimer;
+extern short ID_STATUS_NONEW;
+extern BOOL optionWindowIsOpen;
+
+INT_PTR Notifying(WPARAM, LPARAM);
+INT_PTR PluginMenuCommand(WPARAM, LPARAM);
+void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD);
+BOOL GetBrowser(char *);
+
+void NotifyUser(Account *);
+int OptInit(WPARAM, LPARAM);
+void Check_ThreadFunc(void *);
+int OpenBrowser(WPARAM, LPARAM);
+void DeleteResults(resultLink *);
+void BuildList(void);
+
+Account* GetAccountByContact(MCONTACT hContact);
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
diff --git a/protocols/GmailNotifier/src/utility.cpp b/protocols/GmailNotifier/src/utility.cpp
new file mode 100644
index 0000000000..cda56e956c
--- /dev/null
+++ b/protocols/GmailNotifier/src/utility.cpp
@@ -0,0 +1,77 @@
+#include "stdafx.h"
+
+void BuildList(void)
+{
+ g_accs.destroy();
+
+ for (auto &hContact : Contacts(MODULENAME)) {
+ ptrA szName(g_plugin.getStringA(hContact, "name"));
+ if (szName != nullptr) {
+ Account *p = new Account;
+ p->hContact = hContact;
+ mir_strcpy(p->name, szName);
+ CallService(MS_IGNORE_IGNORE, hContact, IGNOREEVENT_USERONLINE);
+
+ ptrA szPassword(g_plugin.getStringA(hContact, "Password"));
+ if (szPassword != nullptr)
+ mir_strcpy(p->pass, szPassword);
+ g_accs.insert(p);
+ }
+ }
+
+ for (auto &acc : g_accs) {
+ char *tail = strchr(acc->name, '@');
+ if (tail && mir_strcmp(tail + 1, "gmail.com") != 0)
+ mir_strcpy(acc->hosted, tail + 1);
+ acc->IsChecking = false;
+ }
+}
+
+BOOL GetBrowser(char *str)
+{
+ HKEY hKey = nullptr;
+ char *strKey;
+ char strIE[] = "Applications\\iexplore.exe\\shell\\open\\command";
+ char strDefault[] = "https\\shell\\open\\command";
+ DBVARIANT dbv;
+
+ if (opt.OpenUsePrg == 1)
+ strKey = strIE;
+ else if (opt.OpenUsePrg == 0)
+ strKey = strDefault;
+ else {
+ if (!g_plugin.getString("OpenUsePrgPath", &dbv)) {
+ mir_strcpy(str, dbv.pszVal);
+ db_free(&dbv);
+ }
+ else *str = 0;
+ return FALSE;
+ }
+
+ // Open the registry
+ if (RegOpenKeyExA(HKEY_CLASSES_ROOT, strKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
+ // Data size
+ DWORD cbData = 0;
+ // Get the default value
+ if (RegQueryValueExA(hKey, nullptr, nullptr, nullptr, nullptr, &cbData) == ERROR_SUCCESS && cbData > 0) {
+ if (RegQueryValueExA(hKey, nullptr, nullptr, nullptr, (LPBYTE)str, &cbData) == ERROR_SUCCESS) {
+ if ((strKey = strstr(str, "%1")) != nullptr)
+ *(strKey--) = '\0';
+ if ((strKey = strstr(str, "-")) != nullptr)
+ *(strKey--) = '\0';
+ RegCloseKey(hKey);
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+Account* GetAccountByContact(MCONTACT hContact)
+{
+ for (auto &it : g_accs)
+ if (it->hContact == hContact)
+ return it;
+
+ return nullptr;
+}
diff --git a/protocols/GmailNotifier/src/version.h b/protocols/GmailNotifier/src/version.h
new file mode 100644
index 0000000000..8eeed10480
--- /dev/null
+++ b/protocols/GmailNotifier/src/version.h
@@ -0,0 +1,13 @@
+#define __MAJOR_VERSION 1
+#define __MINOR_VERSION 0
+#define __RELEASE_NUM 1
+#define __BUILD_NUM 2
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "Gmail Multiple Notifier"
+#define __FILENAME "GmailNotifier.dll"
+#define __DESCRIPTION "Check your Gmail inboxes locally."
+#define __AUTHOR "Mixwind"
+#define __AUTHORWEB "https://miranda-ng.org/p/GmailNotifier/"
+#define __COPYRIGHT "© 2005 Sun Zhuo"