summaryrefslogtreecommitdiff
path: root/protocols/ConnectionNotify/src
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/ConnectionNotify/src')
-rw-r--r--protocols/ConnectionNotify/src/ConnectionNotify.cpp880
-rw-r--r--protocols/ConnectionNotify/src/debug.cpp13
-rw-r--r--protocols/ConnectionNotify/src/debug.h9
-rw-r--r--protocols/ConnectionNotify/src/filter.cpp141
-rw-r--r--protocols/ConnectionNotify/src/filter.h9
-rw-r--r--protocols/ConnectionNotify/src/netstat.cpp148
-rw-r--r--protocols/ConnectionNotify/src/netstat.h18
-rw-r--r--protocols/ConnectionNotify/src/pid2name.cpp21
-rw-r--r--protocols/ConnectionNotify/src/pid2name.h8
-rw-r--r--protocols/ConnectionNotify/src/resource.h34
-rw-r--r--protocols/ConnectionNotify/src/stdafx.cxx18
-rw-r--r--protocols/ConnectionNotify/src/stdafx.h51
-rw-r--r--protocols/ConnectionNotify/src/version.h38
13 files changed, 1388 insertions, 0 deletions
diff --git a/protocols/ConnectionNotify/src/ConnectionNotify.cpp b/protocols/ConnectionNotify/src/ConnectionNotify.cpp
new file mode 100644
index 0000000000..01f00983ca
--- /dev/null
+++ b/protocols/ConnectionNotify/src/ConnectionNotify.cpp
@@ -0,0 +1,880 @@
+#include "stdafx.h"
+
+CMPlugin g_plugin;
+
+static HWND hTimerWnd = (HWND)nullptr;
+static UINT TID = (UINT)12021;
+HANDLE hCheckEvent = nullptr;
+HANDLE hCheckHook = nullptr;
+HANDLE hConnectionCheckThread = nullptr;
+HANDLE hFilterOptionsThread = nullptr;
+HANDLE killCheckThreadEvent = nullptr;
+HANDLE hExceptionsMutex = nullptr;
+
+DWORD FilterOptionsThreadId;
+DWORD ConnectionCheckThreadId;
+BYTE settingSetColours = 0;
+COLORREF settingBgColor;
+COLORREF settingFgColor;
+int settingInterval = 0;
+int settingInterval1 = 0;
+BYTE settingResolveIp = 0;
+BOOL settingStatus[STATUS_COUNT];
+int settingFiltersCount = 0;
+BOOL settingDefaultAction = TRUE;
+WORD settingStatusMask = 0;
+
+struct CONNECTION *first = nullptr;
+struct CONNECTION *connExceptions = nullptr;
+struct CONNECTION *connCurrentEdit;
+struct CONNECTION *connExceptionsTmp = nullptr;
+struct CONNECTION *connCurrentEditModal = nullptr;
+int currentStatus = ID_STATUS_OFFLINE, diffstat = 0;
+BOOL bOptionsOpen = FALSE;
+wchar_t *tcpStates[] = { L"CLOSED", L"LISTEN", L"SYN_SENT", L"SYN_RCVD", L"ESTAB", L"FIN_WAIT1", L"FIN_WAIT2", L"CLOSE_WAIT", L"CLOSING", L"LAST_ACK", L"TIME_WAIT", L"DELETE_TCB" };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PLUGININFOEX pluginInfoEx = {
+ sizeof(PLUGININFOEX),
+ PLUGINNAME,
+ __VERSION_DWORD,
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE, //not transient
+ // 4BB5B4AA-C364-4F23-9746-D5B708A286A5
+ { 0x4bb5b4aa, 0xc364, 0x4f23, { 0x97, 0x46, 0xd5, 0xb7, 0x8, 0xa2, 0x86, 0xa5 } }
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(PLUGINNAME, pluginInfoEx)
+{
+ RegisterProtocol(PROTOTYPE_PROTOCOL);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = { MIID_PROTOCOL, MIID_LAST };
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// authentication callback futnction from extension manager
+
+BOOL strrep(wchar_t *src, wchar_t *needle, wchar_t *newstring)
+{
+ wchar_t *found, begining[MAX_SETTING_STR], tail[MAX_SETTING_STR];
+ size_t pos = 0;
+
+ //strset(begining, ' ');
+ //strset(tail, ' ');
+ if (!(found = wcsstr(src, needle)))
+ return FALSE;
+
+ pos = (found - src);
+ wcsncpy_s(begining, src, pos);
+ begining[pos] = 0;
+
+ pos = pos + mir_wstrlen(needle);
+ wcsncpy_s(tail, src + pos, _TRUNCATE);
+ begining[pos] = 0;
+
+ pos = mir_snwprintf(src, mir_wstrlen(src), L"%s%s%s", begining, newstring, tail);
+ return TRUE;
+}
+
+void saveSettingsConnections(struct CONNECTION *connHead)
+{
+ char buff[128];
+ int i = 0;
+ struct CONNECTION *tmp = connHead;
+ while (tmp != nullptr) {
+
+ mir_snprintf(buff, "%dFilterIntIp", i);
+ g_plugin.setWString(buff, tmp->strIntIp);
+ mir_snprintf(buff, "%dFilterExtIp", i);
+ g_plugin.setWString(buff, tmp->strExtIp);
+ mir_snprintf(buff, "%dFilterPName", i);
+ g_plugin.setWString(buff, tmp->PName);
+ mir_snprintf(buff, "%dFilterIntPort", i);
+ g_plugin.setDword(buff, tmp->intIntPort);
+ mir_snprintf(buff, "%dFilterExtPort", i);
+ g_plugin.setDword(buff, tmp->intExtPort);
+ mir_snprintf(buff, "%dFilterAction", i);
+ g_plugin.setDword(buff, tmp->Pid);
+ i++;
+ tmp = tmp->next;
+ }
+ settingFiltersCount = i;
+ g_plugin.setDword("FiltersCount", settingFiltersCount);
+
+}
+
+//load filters from db
+struct CONNECTION* LoadSettingsConnections()
+{
+ struct CONNECTION *connHead = nullptr;
+ DBVARIANT dbv;
+ char buff[128];
+ int i = 0;
+ for (i = settingFiltersCount - 1; i >= 0; i--) {
+ struct CONNECTION *conn = (struct CONNECTION*)mir_alloc(sizeof(struct CONNECTION));
+ mir_snprintf(buff, "%dFilterIntIp", i);
+ if (!g_plugin.getWString(buff, &dbv))
+ wcsncpy(conn->strIntIp, dbv.pwszVal, _countof(conn->strIntIp));
+ db_free(&dbv);
+ mir_snprintf(buff, "%dFilterExtIp", i);
+ if (!g_plugin.getWString(buff, &dbv))
+ wcsncpy(conn->strExtIp, dbv.pwszVal, _countof(conn->strExtIp));
+ db_free(&dbv);
+ mir_snprintf(buff, "%dFilterPName", i);
+ if (!g_plugin.getWString(buff, &dbv))
+ wcsncpy(conn->PName, dbv.pwszVal, _countof(conn->PName));
+ db_free(&dbv);
+
+ mir_snprintf(buff, "%dFilterIntPort", i);
+ conn->intIntPort = g_plugin.getDword(buff, -1);
+
+ mir_snprintf(buff, "%dFilterExtPort", i);
+ conn->intExtPort = g_plugin.getDword(buff, -1);
+
+ mir_snprintf(buff, "%dFilterAction", i);
+ conn->Pid = g_plugin.getDword(buff, 0);
+
+ conn->next = connHead;
+ connHead = conn;
+ }
+ return connHead;
+}
+//called to load settings from database
+void LoadSettings()
+{
+ settingInterval = g_plugin.getDword("Interval", 500);
+ settingInterval1 = g_plugin.getDword("PopupInterval", 0);
+ settingResolveIp = g_plugin.getByte("ResolveIp", TRUE);
+ settingDefaultAction = g_plugin.getByte("FilterDefaultAction", TRUE);
+
+ settingSetColours = g_plugin.getByte("PopupSetColours", 0);
+ settingBgColor = g_plugin.getDword("PopupBgColor", (DWORD)0xFFFFFF);
+ settingFgColor = g_plugin.getDword("PopupFgColor", (DWORD)0x000000);
+ settingFiltersCount = g_plugin.getDword("FiltersCount", 0);
+ settingStatusMask = g_plugin.getWord("StatusMask", 16);
+ for (int i = 0; i < STATUS_COUNT; i++) {
+ char buff[128];
+ mir_snprintf(buff, "Status%d", i);
+ settingStatus[i] = (g_plugin.getByte(buff, 0) == 1);
+ }
+}
+
+void fillExceptionsListView(HWND hwndDlg)
+{
+ LVITEM lvI = { 0 };
+
+ int i = 0;
+ struct CONNECTION *tmp = connExceptionsTmp;
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS);
+ ListView_DeleteAllItems(hwndList);
+
+ // Some code to create the list-view control.
+ // Initialize LVITEM members that are common to all
+ // items.
+ lvI.mask = LVIF_TEXT;
+ while (tmp) {
+ wchar_t tmpAddress[25];
+ lvI.iItem = i++;
+ lvI.iSubItem = 0;
+ lvI.pszText = tmp->PName;
+ ListView_InsertItem(hwndList, &lvI);
+ lvI.iSubItem = 1;
+ if (tmp->intIntPort == -1)
+ mir_snwprintf(tmpAddress, L"%s:*", tmp->strIntIp);
+ else
+ mir_snwprintf(tmpAddress, L"%s:%d", tmp->strIntIp, tmp->intIntPort);
+ lvI.pszText = tmpAddress;
+ ListView_SetItem(hwndList, &lvI);
+ lvI.iSubItem = 2;
+ if (tmp->intExtPort == -1)
+ mir_snwprintf(tmpAddress, L"%s:*", tmp->strExtIp);
+ else
+ mir_snwprintf(tmpAddress, L"%s:%d", tmp->strExtIp, tmp->intExtPort);
+ lvI.pszText = tmpAddress;
+ ListView_SetItem(hwndList, &lvI);
+ lvI.iSubItem = 3;
+ lvI.pszText = tmp->Pid ? LPGENW("Show") : LPGENW("Hide");
+ ListView_SetItem(hwndList, &lvI);
+
+ tmp = tmp->next;
+ }
+
+}
+//filter editor dialog box procedure opened modally from options dialog
+static INT_PTR CALLBACK FilterEditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_INITDIALOG:
+ {
+ struct CONNECTION *conn = (struct CONNECTION*)lParam;
+ TranslateDialogDefault(hWnd);
+ connCurrentEditModal = conn;
+ SetDlgItemText(hWnd, ID_TEXT_NAME, conn->PName);
+ SetDlgItemText(hWnd, ID_TXT_LOCAL_IP, conn->strIntIp);
+ SetDlgItemText(hWnd, ID_TXT_REMOTE_IP, conn->strExtIp);
+
+ if (conn->intIntPort == -1)
+ SetDlgItemText(hWnd, ID_TXT_LOCAL_PORT, L"*");
+ else
+ SetDlgItemInt(hWnd, ID_TXT_LOCAL_PORT, conn->intIntPort, FALSE);
+
+ if (conn->intExtPort == -1)
+ SetDlgItemText(hWnd, ID_TXT_REMOTE_PORT, L"*");
+ else
+ SetDlgItemInt(hWnd, ID_TXT_REMOTE_PORT, conn->intExtPort, FALSE);
+
+ SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("Always show popup"));
+ SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("Never show popup"));
+ SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_SETCURSEL, conn->Pid == 0 ? 1 : 0, 0);
+ return TRUE;
+ }
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case ID_OK:
+ {
+ wchar_t tmpPort[6];
+ GetDlgItemText(hWnd, ID_TXT_LOCAL_PORT, tmpPort, _countof(tmpPort));
+ if (tmpPort[0] == '*')
+ connCurrentEditModal->intIntPort = -1;
+ else
+ connCurrentEditModal->intIntPort = GetDlgItemInt(hWnd, ID_TXT_LOCAL_PORT, nullptr, FALSE);
+ GetDlgItemText(hWnd, ID_TXT_REMOTE_PORT, tmpPort, _countof(tmpPort));
+ if (tmpPort[0] == '*')
+ connCurrentEditModal->intExtPort = -1;
+ else
+ connCurrentEditModal->intExtPort = GetDlgItemInt(hWnd, ID_TXT_REMOTE_PORT, nullptr, FALSE);
+
+ GetDlgItemText(hWnd, ID_TXT_LOCAL_IP, connCurrentEditModal->strIntIp, _countof(connCurrentEditModal->strIntIp));
+ GetDlgItemText(hWnd, ID_TXT_REMOTE_IP, connCurrentEditModal->strExtIp, _countof(connCurrentEditModal->strExtIp));
+ GetDlgItemText(hWnd, ID_TEXT_NAME, connCurrentEditModal->PName, _countof(connCurrentEditModal->PName));
+
+ connCurrentEditModal->Pid = !(BOOL)SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_GETCURSEL, 0, 0);
+
+ connCurrentEditModal = nullptr;
+ EndDialog(hWnd, IDOK);
+ return TRUE;
+ }
+ case ID_CANCEL:
+ connCurrentEditModal = nullptr;
+ EndDialog(hWnd, IDCANCEL);
+ return TRUE;
+ }
+ return FALSE;
+ break;
+ case WM_CLOSE:
+ {
+ connCurrentEditModal = nullptr;
+ EndDialog(hWnd, IDCANCEL);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+//options page on miranda called
+INT_PTR CALLBACK DlgProcConnectionNotifyOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndList;
+ switch (msg) {
+ case WM_INITDIALOG://initialize dialog, so set properties from db.
+ {
+ LVCOLUMN lvc = { 0 };
+ LVITEM lvI = { 0 };
+ wchar_t buff[256];
+ bOptionsOpen = TRUE;
+ TranslateDialogDefault(hwndDlg);//translate miranda function
+ #ifdef _WIN64
+ mir_snwprintf(buff, L"%d.%d.%d.%d/64", HIBYTE(HIWORD(pluginInfoEx.version)), LOBYTE(HIWORD(pluginInfoEx.version)), HIBYTE(LOWORD(pluginInfoEx.version)), LOBYTE(LOWORD(pluginInfoEx.version)));
+ #else
+ mir_snwprintf(buff, L"%d.%d.%d.%d/32", HIBYTE(HIWORD(pluginInfoEx.version)), LOBYTE(HIWORD(pluginInfoEx.version)), HIBYTE(LOWORD(pluginInfoEx.version)), LOBYTE(LOWORD(pluginInfoEx.version)));
+ #endif
+ SetDlgItemText(hwndDlg, IDC_VERSION, buff);
+ LoadSettings();
+ //connExceptionsTmp=LoadSettingsConnections();
+ SetDlgItemInt(hwndDlg, IDC_INTERVAL, settingInterval, FALSE);
+ SetDlgItemInt(hwndDlg, IDC_INTERVAL1, settingInterval1, TRUE);
+ CheckDlgButton(hwndDlg, IDC_SETCOLOURS, settingSetColours ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_RESOLVEIP, settingResolveIp ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, ID_CHK_DEFAULTACTION, settingDefaultAction ? BST_CHECKED : BST_UNCHECKED);
+
+ SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_SETCOLOUR, 0, (LPARAM)settingBgColor);
+ SendDlgItemMessage(hwndDlg, IDC_FGCOLOR, CPM_SETCOLOUR, 0, (LPARAM)settingFgColor);
+ if (!settingSetColours) {
+ HWND hwnd = GetDlgItem(hwndDlg, IDC_BGCOLOR);
+ CheckDlgButton(hwndDlg, IDC_SETCOLOURS, BST_UNCHECKED);
+ EnableWindow(hwnd, FALSE);
+ hwnd = GetDlgItem(hwndDlg, IDC_FGCOLOR);
+ EnableWindow(hwnd, FALSE);
+ }
+ SendDlgItemMessage(hwndDlg, ID_ADD, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ICON6), IMAGE_ICON, 16, 16, 0));
+ SendDlgItemMessage(hwndDlg, ID_DELETE, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ICON3), IMAGE_ICON, 16, 16, 0));
+ SendDlgItemMessage(hwndDlg, ID_DOWN, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ICON4), IMAGE_ICON, 16, 16, 0));
+ SendDlgItemMessage(hwndDlg, ID_UP, BM_SETIMAGE, IMAGE_ICON, (LPARAM)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ICON5), IMAGE_ICON, 16, 16, 0));
+ // initialise and fill listbox
+ hwndList = GetDlgItem(hwndDlg, IDC_STATUS);
+ ListView_DeleteAllItems(hwndList);
+ SendMessage(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
+ // Initialize the LVCOLUMN structure.
+ // The mask specifies that the format, width, text, and
+ // subitem members of the structure are valid.
+ lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
+ lvc.fmt = LVCFMT_LEFT;
+ lvc.iSubItem = 0;
+ lvc.pszText = TranslateT("Status");
+ lvc.cx = 120; // width of column in pixels
+ ListView_InsertColumn(hwndList, 0, &lvc);
+ // Some code to create the list-view control.
+ // Initialize LVITEM members that are common to all
+ // items.
+ lvI.mask = LVIF_TEXT;
+ for (int i = 0; i < STATUS_COUNT; i++) {
+ lvI.pszText = Clist_GetStatusModeDescription(ID_STATUS_ONLINE + i, 0);
+ lvI.iItem = i;
+ ListView_InsertItem(hwndList, &lvI);
+ ListView_SetCheckState(hwndList, i, settingStatus[i]);
+ }
+
+ connExceptionsTmp = LoadSettingsConnections();
+ hwndList = GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS);
+ SendMessage(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT);
+
+ lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
+ lvc.fmt = LVCFMT_LEFT;
+ lvc.iSubItem = 0;
+ lvc.cx = 120; // width of column in pixels
+ lvc.pszText = TranslateT("Application");
+ ListView_InsertColumn(hwndList, 1, &lvc);
+ lvc.pszText = TranslateT("Internal socket");
+ ListView_InsertColumn(hwndList, 2, &lvc);
+ lvc.pszText = TranslateT("External socket");
+ ListView_InsertColumn(hwndList, 3, &lvc);
+ lvc.pszText = TranslateT("Action");
+ lvc.cx = 50;
+ ListView_InsertColumn(hwndList, 4, &lvc);
+
+ //fill exceptions list
+ fillExceptionsListView(hwndDlg);
+ }
+ break;
+
+ case WM_COMMAND://user changed something, so get changes to variables
+ PostMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ switch (LOWORD(wParam)) {
+ case IDC_INTERVAL: settingInterval = GetDlgItemInt(hwndDlg, IDC_INTERVAL, nullptr, FALSE); break;
+ case IDC_INTERVAL1: settingInterval1 = GetDlgItemInt(hwndDlg, IDC_INTERVAL1, nullptr, TRUE); break;
+ case IDC_RESOLVEIP: settingResolveIp = (BYTE)IsDlgButtonChecked(hwndDlg, IDC_RESOLVEIP); break;
+ case ID_CHK_DEFAULTACTION: settingDefaultAction = (BYTE)IsDlgButtonChecked(hwndDlg, ID_CHK_DEFAULTACTION); break;
+ case ID_ADD:
+ {
+ struct CONNECTION *cur = (struct CONNECTION *)mir_alloc(sizeof(struct CONNECTION));
+ memset(cur, 0, sizeof(struct CONNECTION));
+ cur->intExtPort = -1;
+ cur->intIntPort = -1;
+ cur->Pid = 0;
+ cur->PName[0] = '*';
+ cur->strExtIp[0] = '*';
+ cur->strIntIp[0] = '*';
+
+ if (DialogBoxParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_FILTER_DIALOG), hwndDlg, FilterEditProc, (LPARAM)cur) == IDCANCEL) {
+ mir_free(cur);
+ cur = nullptr;
+ }
+ else {
+ cur->next = connExceptionsTmp;
+ connExceptionsTmp = cur;
+ }
+
+ fillExceptionsListView(hwndDlg);
+ ListView_SetItemState(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), 0, LVNI_FOCUSED | LVIS_SELECTED, LVNI_FOCUSED | LVIS_SELECTED);
+ SetFocus(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS));
+ }
+ break;
+
+ case ID_DELETE:
+ {
+ int pos, pos1;
+ struct CONNECTION *cur = connExceptionsTmp, *pre = nullptr;
+
+ pos = (int)ListView_GetNextItem(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), -1, LVNI_FOCUSED);
+ if (pos == -1)break;
+ pos1 = pos;
+ while (pos--) {
+ pre = cur;
+ cur = cur->next;
+ }
+ if (pre == nullptr)
+ connExceptionsTmp = connExceptionsTmp->next;
+ else
+ (pre)->next = cur->next;
+ mir_free(cur);
+ fillExceptionsListView(hwndDlg);
+ ListView_SetItemState(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), pos1, LVNI_FOCUSED | LVIS_SELECTED, LVNI_FOCUSED | LVIS_SELECTED);
+ SetFocus(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS));
+ break;
+ }
+ case ID_UP:
+ {
+ int pos, pos1;
+ struct CONNECTION *cur = nullptr, *pre = nullptr, *prepre = nullptr;
+
+ cur = connExceptionsTmp;
+
+ pos = (int)ListView_GetNextItem(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), -1, LVNI_FOCUSED);
+ if (pos == -1)break;
+ pos1 = pos;
+ while (pos--) {
+ prepre = pre;
+ pre = cur;
+ cur = cur->next;
+ }
+ if (prepre != nullptr) {
+ pre->next = cur->next;
+ cur->next = pre;
+ prepre->next = cur;
+ }
+ else if (pre != nullptr) {
+ pre->next = cur->next;
+ cur->next = pre;
+ connExceptionsTmp = cur;
+ }
+ fillExceptionsListView(hwndDlg);
+ ListView_SetItemState(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), pos1 - 1, LVNI_FOCUSED | LVIS_SELECTED, LVNI_FOCUSED | LVIS_SELECTED);
+ SetFocus(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS));
+ break;
+ }
+ case ID_DOWN:
+ {
+ int pos, pos1;
+ struct CONNECTION *cur = nullptr, *pre = nullptr;
+
+ cur = connExceptionsTmp;
+
+ pos = (int)ListView_GetNextItem(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), -1, LVNI_FOCUSED);
+ if (pos == -1)break;
+ pos1 = pos;
+ while (pos--) {
+ pre = cur;
+ cur = cur->next;
+ }
+ if (cur == connExceptionsTmp&&cur->next != nullptr) {
+ connExceptionsTmp = cur->next;
+ cur->next = cur->next->next;
+ connExceptionsTmp->next = cur;
+ }
+ else if (cur->next != nullptr) {
+ struct CONNECTION *tmp = cur->next->next;
+ pre->next = cur->next;
+ cur->next->next = cur;
+ cur->next = tmp;
+ }
+ fillExceptionsListView(hwndDlg);
+ ListView_SetItemState(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), pos1 + 1, LVNI_FOCUSED | LVIS_SELECTED, LVNI_FOCUSED | LVIS_SELECTED);
+ SetFocus(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS));
+ break;
+ }
+ case IDC_SETCOLOURS:
+ {
+ HWND hwnd = GetDlgItem(hwndDlg, IDC_BGCOLOR);
+ settingSetColours = IsDlgButtonChecked(hwndDlg, IDC_SETCOLOURS);
+ EnableWindow(hwnd, settingSetColours);
+ hwnd = GetDlgItem(hwndDlg, IDC_FGCOLOR);
+ EnableWindow(hwnd, settingSetColours);
+ break;
+ }
+ case IDC_BGCOLOR: settingBgColor = (COLORREF)SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_GETCOLOUR, 0, 0); break;
+ case IDC_FGCOLOR: settingFgColor = (COLORREF)SendDlgItemMessage(hwndDlg, IDC_FGCOLOR, CPM_GETCOLOUR, 0, 0); break;
+
+ }
+ break;
+
+ case WM_NOTIFY://apply changes so write it to db
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case 0:
+ switch (((LPNMHDR)lParam)->code) {
+ case PSN_RESET:
+ LoadSettings();
+ deleteConnectionsTable(connExceptionsTmp);
+ connExceptionsTmp = LoadSettingsConnections();
+ return TRUE;
+
+ case PSN_APPLY:
+ g_plugin.setDword("Interval", settingInterval);
+ g_plugin.setDword("PopupInterval", settingInterval1);
+ g_plugin.setByte("PopupSetColours", settingSetColours);
+ g_plugin.setDword("PopupBgColor", settingBgColor);
+ g_plugin.setDword("PopupFgColor", settingFgColor);
+ g_plugin.setByte("ResolveIp", settingResolveIp);
+ g_plugin.setByte("FilterDefaultAction", settingDefaultAction);
+
+ for (int i = 0; i < STATUS_COUNT; i++) {
+ char buff[128];
+ mir_snprintf(buff, "Status%d", i);
+ settingStatus[i] = (ListView_GetCheckState(GetDlgItem(hwndDlg, IDC_STATUS), i) ? TRUE : FALSE);
+ g_plugin.setByte(buff, settingStatus[i] ? 1 : 0);
+ }
+ if (WAIT_OBJECT_0 == WaitForSingleObject(hExceptionsMutex, 100)) {
+ deleteConnectionsTable(connExceptions);
+ saveSettingsConnections(connExceptionsTmp);
+ connExceptions = connExceptionsTmp;
+ connExceptionsTmp = LoadSettingsConnections();
+ ReleaseMutex(hExceptionsMutex);
+ }
+ return TRUE;
+ }
+ break;
+ }
+
+ if (GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS) == ((LPNMHDR)lParam)->hwndFrom) {
+ switch (((LPNMHDR)lParam)->code) {
+ case NM_DBLCLK:
+ {
+ int pos, pos1;
+ struct CONNECTION *cur = nullptr;
+
+ cur = connExceptionsTmp;
+
+ pos = (int)ListView_GetNextItem(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), -1, LVNI_FOCUSED);
+ if (pos == -1)break;
+ pos1 = pos;
+ while (pos--) {
+ cur = cur->next;
+ }
+ DialogBoxParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_FILTER_DIALOG), hwndDlg, FilterEditProc, (LPARAM)cur);
+ fillExceptionsListView(hwndDlg);
+ ListView_SetItemState(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS), pos1, LVNI_FOCUSED | LVIS_SELECTED, LVNI_FOCUSED | LVIS_SELECTED);
+ SetFocus(GetDlgItem(hwndDlg, IDC_LIST_EXCEPTIONS));
+ break;
+ }
+ }
+ }
+
+ if (GetDlgItem(hwndDlg, IDC_STATUS) == ((LPNMHDR)lParam)->hwndFrom) {
+ switch (((LPNMHDR)lParam)->code) {
+ case LVN_ITEMCHANGED:
+ NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam;
+ if ((nmlv->uNewState ^ nmlv->uOldState) & LVIS_STATEIMAGEMASK)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+ }
+ }
+ break;
+
+ case WM_DESTROY:
+ bOptionsOpen = FALSE;
+ deleteConnectionsTable(connExceptionsTmp);
+ connExceptionsTmp = nullptr;
+ return TRUE;
+ }
+ return 0;
+}
+
+//options page on miranda called
+int ConnectionNotifyOptInit(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_DIALOG);
+ odp.szTitle.w = _A2W(PLUGINNAME);
+ odp.szGroup.w = LPGENW("Plugins");
+ odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE;
+ odp.pfnDlgProc = DlgProcConnectionNotifyOpts;//callback function name
+ g_plugin.addOptions(wParam, &odp);
+ return 0;
+}
+
+//gives protocol avainable statuses
+INT_PTR GetCaps(WPARAM wParam, LPARAM)
+{
+ if (wParam == PFLAGNUM_1)
+ return 0;
+ if (wParam == PFLAGNUM_2)
+ return PF2_ONLINE; // add the possible statuses here.
+ if (wParam == PFLAGNUM_3)
+ return 0;
+ return 0;
+}
+
+//gives name to protocol module
+INT_PTR GetName(WPARAM wParam, LPARAM lParam)
+{
+ mir_strncpy((char*)lParam, PLUGINNAME, wParam);
+ return 0;
+}
+
+//gives icon for proto module
+INT_PTR TMLoadIcon(WPARAM wParam, LPARAM)
+{
+ UINT id;
+
+ switch (wParam & 0xFFFF) {
+ case PLI_PROTOCOL:
+ id = IDI_ICON1;
+ break; // IDI_TM is the main icon for the protocol
+ default:
+ return 0;
+ }
+ return (INT_PTR)LoadImage(g_plugin.getInst(), MAKEINTRESOURCE(id), IMAGE_ICON, GetSystemMetrics(wParam&PLIF_SMALL ? SM_CXSMICON : SM_CXICON), GetSystemMetrics(wParam&PLIF_SMALL ? SM_CYSMICON : SM_CYICON), 0);
+}
+//=======================================================
+//SetStatus
+//=======================================================
+INT_PTR SetStatus(WPARAM wParam, LPARAM lParam)
+{
+ if (wParam == ID_STATUS_OFFLINE) {
+ diffstat = 0;
+ //PostThreadMessage(ConnectionCheckThreadId,WM_QUIT ,0, 0);
+ SetEvent(killCheckThreadEvent);
+
+ }
+ else if (wParam == ID_STATUS_ONLINE) {
+ diffstat = 0;
+ ResetEvent(killCheckThreadEvent);
+ if (!hConnectionCheckThread)
+ hConnectionCheckThread = (HANDLE)mir_forkthreadex(checkthread, nullptr, (unsigned int*)&ConnectionCheckThreadId);
+ }
+ else {
+ int retv = 0;
+
+ if (settingStatus[wParam - ID_STATUS_ONLINE])
+ retv = SetStatus(ID_STATUS_OFFLINE, lParam);
+ else
+ retv = SetStatus(ID_STATUS_ONLINE, lParam);
+ //LNEnableMenuItem(hMenuHandle ,TRUE);
+ diffstat = wParam;
+ return retv;
+
+ // the status has been changed to unknown (maybe run some more code)
+ }
+ //broadcast the message
+
+ //oldStatus = currentStatus;
+ if (currentStatus != (int)wParam)
+ ProtoBroadcastAck(PLUGINNAME, NULL, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)currentStatus, wParam);
+ currentStatus = wParam;
+ return 0;
+
+}
+//=======================================================
+//GetStatus
+//=======================================================
+INT_PTR GetStatus(WPARAM, LPARAM)
+{
+ return currentStatus;
+}
+
+//thread function with connections check loop
+static unsigned __stdcall checkthread(void *)
+{
+
+ #ifdef _DEBUG
+ _OutputDebugString(L"check thread started");
+ #endif
+ while (1) {
+ struct CONNECTION* conn = nullptr, *connOld = first, *cur = nullptr;
+ #ifdef _DEBUG
+ _OutputDebugString(L"checking connections table...");
+ #endif
+ if (WAIT_OBJECT_0 == WaitForSingleObject(killCheckThreadEvent, 100)) {
+ hConnectionCheckThread = nullptr;
+ return 0;
+ }
+
+ conn = GetConnectionsTable();
+ cur = conn;
+ while (cur != nullptr) {
+ if (searchConnection(first, cur->strIntIp, cur->strExtIp, cur->intIntPort, cur->intExtPort, cur->state) == nullptr && (settingStatusMask & (1 << (cur->state - 1)))) {
+
+ #ifdef _DEBUG
+ wchar_t msg[1024];
+ mir_snwprintf(msg, L"%s:%d\n%s:%d", cur->strIntIp, cur->intIntPort, cur->strExtIp, cur->intExtPort);
+ _OutputDebugString(L"New connection: %s", msg);
+ #endif
+ pid2name(cur->Pid, cur->PName, _countof(cur->PName));
+ if (WAIT_OBJECT_0 == WaitForSingleObject(hExceptionsMutex, 100)) {
+ if (checkFilter(connExceptions, cur)) {
+ showMsg(cur->PName, cur->Pid, cur->strIntIp, cur->strExtIp, cur->intIntPort, cur->intExtPort, cur->state);
+ Skin_PlaySound(PLUGINNAME_NEWSOUND);
+ }
+ ReleaseMutex(hExceptionsMutex);
+ }
+ }
+ cur = cur->next;
+ }
+
+ first = conn;
+ deleteConnectionsTable(connOld);
+ Sleep(settingInterval);
+ }
+ hConnectionCheckThread = nullptr;
+ return 1;
+}
+
+//popup reactions
+static LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_COMMAND:
+ if (HIWORD(wParam) == STN_CLICKED)//client clicked on popup with left mouse button
+ {
+ struct CONNECTION *conn = (struct CONNECTION*)mir_alloc(sizeof(struct CONNECTION));
+ struct CONNECTION *mpd = (struct CONNECTION*) PUGetPluginData(hWnd);
+
+ memcpy(conn, mpd, sizeof(struct CONNECTION));
+ PUDeletePopup(hWnd);
+ PostThreadMessage(FilterOptionsThreadId, WM_ADD_FILTER, 0, (LPARAM)conn);
+ }
+ break;
+
+ case WM_RBUTTONUP:
+ PUDeletePopup(hWnd);
+ break;
+
+ case UM_INITPOPUP:
+ //struct CONNECTON *conn=NULL;
+ //conn = (struct CONNECTION*)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd,(LPARAM)conn);
+ //MessageBox(NULL,conn->extIp);
+ //PUDeletePopUp(hWnd);
+ break;
+
+ case UM_FREEPLUGINDATA:
+ struct CONNECTION *mpd = (struct CONNECTION*)PUGetPluginData(hWnd);
+ if (mpd > 0) mir_free(mpd);
+ return TRUE; //TRUE or FALSE is the same, it gets ignored.
+ }
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+
+//show popup
+void showMsg(wchar_t *pName, DWORD pid, wchar_t *intIp, wchar_t *extIp, int intPort, int extPort, int state)
+{
+
+ POPUPDATAW ppd;
+ //hContact = A_VALID_HANDLE_YOU_GOT_FROM_SOMEWHERE;
+ //hIcon = A_VALID_HANDLE_YOU_GOT_SOMEWHERE;
+ //char * lpzContactName = (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME,(WPARAM)lhContact,0);
+ //99% of the times you'll just copy this line.
+ //1% of the times you may wish to change the contact's name. I don't know why you should, but you can.
+ //char * lpzText;
+ //The text for the second line. You could even make something like: char lpzText[128]; mir_wstrcpy(lpzText, "Hello world!"); It's your choice.
+
+ struct CONNECTION *mpd = (struct CONNECTION*)mir_alloc(sizeof(struct CONNECTION));
+ //MessageBox(NULL,"aaa","aaa",1);
+ memset(&ppd, 0, sizeof(ppd)); //This is always a good thing to do.
+ ppd.lchContact = NULL;//(HANDLE)hContact; //Be sure to use a GOOD handle, since this will not be checked.
+ ppd.lchIcon = LoadIcon(g_plugin.getInst(), MAKEINTRESOURCE(IDI_ICON1));
+ if (settingResolveIp) {
+ wchar_t hostName[128];
+ getDnsName(extIp, hostName, _countof(hostName));
+ mir_snwprintf(ppd.lpwzText, L"%s:%d\n%s:%d", hostName, extPort, intIp, intPort);
+ }
+ else mir_snwprintf(ppd.lpwzText, L"%s:%d\n%s:%d", extIp, extPort, intIp, intPort);
+
+ mir_snwprintf(ppd.lpwzContactName, L"%s (%s)", pName, tcpStates[state - 1]);
+
+ if (settingSetColours) {
+ ppd.colorBack = settingBgColor;
+ ppd.colorText = settingFgColor;
+ }
+ ppd.PluginWindowProc = PopupDlgProc;
+
+ ppd.iSeconds = settingInterval1;
+ //Now the "additional" data.
+ wcsncpy_s(mpd->strIntIp, intIp, _TRUNCATE);
+ wcsncpy_s(mpd->strExtIp, extIp, _TRUNCATE);
+ wcsncpy_s(mpd->PName, pName, _TRUNCATE);
+ mpd->intIntPort = intPort;
+ mpd->intExtPort = extPort;
+ mpd->Pid = pid;
+
+ //Now that the plugin data has been filled, we add it to the PopUpData.
+ ppd.PluginData = mpd;
+
+ //Now that every field has been filled, we want to see the popup.
+ PUAddPopupW(&ppd);
+}
+
+//called after all plugins loaded.
+//all Connection staff will be called, that will not hang miranda on startup
+static int modulesloaded(WPARAM, LPARAM)
+{
+
+ #ifdef _DEBUG
+ _OutputDebugString(L"Modules loaded, lets start TN...");
+ #endif
+ // hConnectionCheckThread = (HANDLE)mir_forkthreadex(checkthread, 0, 0, ConnectionCheckThreadId);
+
+ //#ifdef _DEBUG
+ // _OutputDebugString("started check thread %d",hConnectionCheckThread);
+ //#endif
+ killCheckThreadEvent = CreateEvent(nullptr, FALSE, FALSE, L"killCheckThreadEvent");
+ hFilterOptionsThread = startFilterThread();
+ //updaterRegister();
+
+ return 0;
+}
+//function hooks before unload
+static int preshutdown(WPARAM, LPARAM)
+{
+ deleteConnectionsTable(first);
+ deleteConnectionsTable(connExceptions);
+ deleteConnectionsTable(connExceptionsTmp);
+
+ PostThreadMessage(ConnectionCheckThreadId, WM_QUIT, 0, 0);
+ PostThreadMessage(FilterOptionsThreadId, WM_QUIT, 0, 0);
+
+ return 0;
+}
+
+int CMPlugin::Load()
+{
+ #ifdef _DEBUG
+ _OutputDebugString(L"Entering Load dll");
+ #endif
+
+ hExceptionsMutex = CreateMutex(nullptr, FALSE, L"ExceptionsMutex");
+
+ LoadSettings();
+ connExceptions = LoadSettingsConnections();
+
+ // set all contacts to offline
+ for (auto &hContact : Contacts(PLUGINNAME))
+ g_plugin.setWord(hContact, "status", ID_STATUS_OFFLINE);
+
+ CreateProtoServiceFunction(PLUGINNAME, PS_GETCAPS, GetCaps);
+ CreateProtoServiceFunction(PLUGINNAME, PS_GETNAME, GetName);
+ CreateProtoServiceFunction(PLUGINNAME, PS_LOADICON, TMLoadIcon);
+ CreateProtoServiceFunction(PLUGINNAME, PS_SETSTATUS, SetStatus);
+ CreateProtoServiceFunction(PLUGINNAME, PS_GETSTATUS, GetStatus);
+
+ g_plugin.addSound(PLUGINNAME_NEWSOUND, _A2W(PLUGINNAME), LPGENW("New Connection Notification"));
+
+ HookEvent(ME_OPT_INITIALISE, ConnectionNotifyOptInit); // register service to hook option call
+ HookEvent(ME_SYSTEM_MODULESLOADED, modulesloaded); // hook event that all plugins are loaded
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, preshutdown);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int CMPlugin::Unload()
+{
+ WaitForSingleObjectEx(hConnectionCheckThread, INFINITE, FALSE);
+
+ if (hConnectionCheckThread) CloseHandle(hConnectionCheckThread);
+ if (hCheckEvent) DestroyHookableEvent(hCheckEvent);
+ if (hCheckHook) UnhookEvent(hCheckHook);
+ if (killCheckThreadEvent) CloseHandle(killCheckThreadEvent);
+ if (hExceptionsMutex) CloseHandle(hExceptionsMutex);
+
+ #ifdef _DEBUG
+ _OutputDebugString(L"Unloaded");
+ #endif
+ return 0;
+}
diff --git a/protocols/ConnectionNotify/src/debug.cpp b/protocols/ConnectionNotify/src/debug.cpp
new file mode 100644
index 0000000000..8abe549a22
--- /dev/null
+++ b/protocols/ConnectionNotify/src/debug.cpp
@@ -0,0 +1,13 @@
+#include "stdafx.h"
+
+void _OutputDebugString(wchar_t* lpOutputString, ...)
+{
+ CMStringW format;
+ va_list args;
+ va_start(args, lpOutputString);
+ format.FormatV(lpOutputString, args);
+ va_end(args);
+
+ format.AppendChar('\n');
+ OutputDebugString(format);
+}
diff --git a/protocols/ConnectionNotify/src/debug.h b/protocols/ConnectionNotify/src/debug.h
new file mode 100644
index 0000000000..044e81fe9f
--- /dev/null
+++ b/protocols/ConnectionNotify/src/debug.h
@@ -0,0 +1,9 @@
+#pragma once
+#ifndef _INC_DEBUG
+#define _INC_DEBUG
+
+#include <windows.h>
+#include <stdio.h>
+
+void _OutputDebugString(wchar_t* lpOutputString, ...);
+#endif \ No newline at end of file
diff --git a/protocols/ConnectionNotify/src/filter.cpp b/protocols/ConnectionNotify/src/filter.cpp
new file mode 100644
index 0000000000..e5cc01e98e
--- /dev/null
+++ b/protocols/ConnectionNotify/src/filter.cpp
@@ -0,0 +1,141 @@
+#include "stdafx.h"
+
+HWND filterAddDlg = nullptr;
+extern struct CONNECTION *connExceptions;
+extern HANDLE hFilterOptionsThread;
+extern DWORD FilterOptionsThreadId;
+extern struct CONNECTION *connCurrentEdit;
+extern BOOL settingDefaultAction;
+extern HANDLE hExceptionsMutex;
+extern BOOL bOptionsOpen;
+static unsigned __stdcall filterQueue(void *dummy);
+static INT_PTR CALLBACK ConnectionFilterEditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+HANDLE startFilterThread()
+{
+ return (HANDLE)mir_forkthreadex(filterQueue, nullptr, (unsigned int*)&FilterOptionsThreadId);
+}
+
+static unsigned __stdcall filterQueue(void *)
+{
+ BOOL bRet;
+ MSG msg;
+ //while(1)
+ while ((bRet = GetMessage(&msg, nullptr, 0, 0)) != 0)
+ {
+ if (msg.message == WM_ADD_FILTER)
+ {
+ struct CONNECTION *conn = (struct CONNECTION *)msg.lParam;
+ filterAddDlg = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_FILTER_DIALOG), nullptr, ConnectionFilterEditProc, (LPARAM)conn);
+ ShowWindow(filterAddDlg, SW_SHOW);
+
+ }
+ if (nullptr == filterAddDlg || !IsDialogMessage(filterAddDlg, &msg)) { /* Wine fix. */
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ hFilterOptionsThread = nullptr;
+ return TRUE;
+}
+
+static INT_PTR CALLBACK ConnectionFilterEditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ {
+ struct CONNECTION *conn = (struct CONNECTION*)lParam;
+ TranslateDialogDefault(hWnd);
+
+ SetDlgItemText(hWnd, ID_TEXT_NAME, conn->PName);
+ SetDlgItemText(hWnd, ID_TXT_LOCAL_IP, conn->strIntIp);
+ SetDlgItemText(hWnd, ID_TXT_REMOTE_IP, conn->strExtIp);
+ SetDlgItemInt(hWnd, ID_TXT_LOCAL_PORT, conn->intIntPort, FALSE);
+ SetDlgItemInt(hWnd, ID_TXT_REMOTE_PORT, conn->intExtPort, FALSE);
+ SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("Always show popup"));
+ SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_ADDSTRING, 0, (LPARAM)TranslateT("Never show popup"));
+ SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_SETCURSEL, 0, 0);
+ mir_free(conn);
+ return TRUE;
+ }
+ case WM_ACTIVATE:
+ if (0 == wParam) // becoming inactive
+ filterAddDlg = nullptr;
+ else // becoming active
+ filterAddDlg = hWnd;
+ return FALSE;
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case ID_OK:
+ {
+ wchar_t tmpPort[6];
+ if (bOptionsOpen)
+ {
+ MessageBox(hWnd, TranslateT("First close options window"), L"ConnectionNotify", MB_OK | MB_ICONSTOP);
+ break;
+ }
+ if (WAIT_OBJECT_0 == WaitForSingleObject(hExceptionsMutex, 100))
+ {
+ if (connCurrentEdit == nullptr)
+ {
+ connCurrentEdit = (struct CONNECTION*)mir_alloc(sizeof(struct CONNECTION));
+ connCurrentEdit->next = connExceptions;
+ connExceptions = connCurrentEdit;
+ }
+ GetDlgItemText(hWnd, ID_TXT_LOCAL_PORT, tmpPort, _countof(tmpPort));
+ if (tmpPort[0] == '*')
+ connCurrentEdit->intIntPort = -1;
+ else
+ connCurrentEdit->intIntPort = GetDlgItemInt(hWnd, ID_TXT_LOCAL_PORT, nullptr, FALSE);
+ GetDlgItemText(hWnd, ID_TXT_REMOTE_PORT, tmpPort, _countof(tmpPort));
+ if (tmpPort[0] == '*')
+ connCurrentEdit->intExtPort = -1;
+ else
+ connCurrentEdit->intExtPort = GetDlgItemInt(hWnd, ID_TXT_REMOTE_PORT, nullptr, FALSE);
+
+ GetDlgItemText(hWnd, ID_TXT_LOCAL_IP, connCurrentEdit->strIntIp, _countof(connCurrentEdit->strIntIp));
+ GetDlgItemText(hWnd, ID_TXT_REMOTE_IP, connCurrentEdit->strExtIp, _countof(connCurrentEdit->strExtIp));
+ GetDlgItemText(hWnd, ID_TEXT_NAME, connCurrentEdit->PName, _countof(connCurrentEdit->PName));
+
+ connCurrentEdit->Pid = !(BOOL)SendDlgItemMessage(hWnd, ID_CBO_ACTION, CB_GETCURSEL, 0, 0);
+ connCurrentEdit = nullptr;
+ saveSettingsConnections(connExceptions);
+ ReleaseMutex(hExceptionsMutex);
+ }
+ //EndDialog(hWnd,IDOK);
+ DestroyWindow(hWnd);
+ return TRUE;
+ }
+ case ID_CANCEL:
+ connCurrentEdit = nullptr;
+ DestroyWindow(hWnd);
+ //EndDialog(hWnd,IDCANCEL);
+ return TRUE;
+ }
+ return FALSE;
+
+ break;
+ case WM_CLOSE:
+ DestroyWindow(hWnd);
+ case WM_DESTROY:
+ filterAddDlg = nullptr;
+ connCurrentEdit = nullptr;
+ //DestroyWindow(hWnd);
+ //PostQuitMessage(0);
+ break;
+ }
+ return FALSE;
+}
+
+BOOL checkFilter(struct CONNECTION *head, struct CONNECTION *conn)
+{
+ for (struct CONNECTION *cur = head; cur != nullptr; cur = cur->next)
+ if (wildcmpw(conn->PName, cur->PName) && wildcmpw(conn->strIntIp, cur->strIntIp) && wildcmpw(conn->strExtIp, cur->strExtIp)
+ && (cur->intIntPort == -1 || cur->intIntPort == conn->intIntPort) && (cur->intExtPort == -1 || cur->intExtPort == conn->intExtPort))
+ return cur->Pid;
+
+ return settingDefaultAction;
+}
+
diff --git a/protocols/ConnectionNotify/src/filter.h b/protocols/ConnectionNotify/src/filter.h
new file mode 100644
index 0000000000..f21ba7c95a
--- /dev/null
+++ b/protocols/ConnectionNotify/src/filter.h
@@ -0,0 +1,9 @@
+#pragma once
+#ifndef _INC_FILTER
+#define _INC_FILTER
+
+HANDLE startFilterThread();
+BOOL checkFilter(struct CONNECTION *head, struct CONNECTION *conn);
+
+#define WM_ADD_FILTER (WM_APP + 1)
+#endif
diff --git a/protocols/ConnectionNotify/src/netstat.cpp b/protocols/ConnectionNotify/src/netstat.cpp
new file mode 100644
index 0000000000..93d906cc4f
--- /dev/null
+++ b/protocols/ConnectionNotify/src/netstat.cpp
@@ -0,0 +1,148 @@
+#include "stdafx.h"
+
+struct CONNECTION *GetConnectionsTable()
+{
+ // Declare and initialize variables
+ MIB_TCPTABLE_OWNER_PID *pTcpTable = (MIB_TCPTABLE_OWNER_PID *)MALLOC(sizeof(MIB_TCPTABLE_OWNER_PID));
+ if (pTcpTable == nullptr) {
+ //printf("Error allocating memory!\n");
+ return nullptr;
+ }
+
+ DWORD dwSize = sizeof(MIB_TCPTABLE_OWNER_PID);
+ // Make an initial call to GetTcpTable to
+ // get the necessary size into the dwSize variable
+ DWORD dwRetVal = GetExtendedTcpTable(pTcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
+ if (dwRetVal == ERROR_INSUFFICIENT_BUFFER) {
+ FREE(pTcpTable);
+ pTcpTable = (MIB_TCPTABLE_OWNER_PID *)MALLOC(dwSize);
+ if (pTcpTable == nullptr) {
+ //printf("Error allocating memory\n");
+ return nullptr;
+ }
+ }
+
+ // Make a second call to GetTcpTable to get
+ // the actual data we require
+ if ((dwRetVal = GetExtendedTcpTable(pTcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0)) != NO_ERROR) {
+ //printf("\tGetTcpTable() failed with return value %d\n", dwRetVal);
+ FREE(pTcpTable);
+ return nullptr;
+ }
+ //printf("\tLocal Addr\tLocal Port\tRemote Addr\tRemote Port\n");
+ //printf("Number of entries: %d\n", (int) pTcpTable->dwNumEntries);
+ struct in_addr IpAddr;
+ struct CONNECTION *connHead = nullptr;
+ for (DWORD i = 0; i < pTcpTable->dwNumEntries; i++) {
+ struct CONNECTION *newConn = (struct CONNECTION*)mir_alloc(sizeof(struct CONNECTION));
+ memset(newConn, 0, sizeof(struct CONNECTION));
+ //pid2name(pTcpTable->table[i].dwOwningPid,&newConn->Pname);
+
+ if (pTcpTable->table[i].dwLocalAddr) {
+ IpAddr.S_un.S_addr = (ULONG)pTcpTable->table[i].dwLocalAddr;
+ //_snprintf(newConn->strIntIp,_countof(newConn->strIntIp),"%d.%d.%d.%d",IpAddr.S_un.S_un_b.s_b1,IpAddr.S_un.S_un_b.s_b2,IpAddr.S_un.S_un_b.s_b3,IpAddr.S_un.S_un_b.s_b4);
+ wchar_t *strIntIp = mir_a2u(inet_ntoa(IpAddr));
+ wcsncpy(newConn->strIntIp, strIntIp, _countof(newConn->strIntIp) - 1);
+ mir_free(strIntIp);
+ }
+
+ if (pTcpTable->table[i].dwRemoteAddr) {
+ IpAddr.S_un.S_addr = (u_long)pTcpTable->table[i].dwRemoteAddr;
+ wchar_t *strExtIp = mir_a2u(inet_ntoa(IpAddr));
+ wcsncpy(newConn->strExtIp, strExtIp, _countof(newConn->strExtIp) - 1);
+ mir_free(strExtIp);
+ }
+ newConn->state = pTcpTable->table[i].dwState;
+ newConn->intIntPort = ntohs((u_short)pTcpTable->table[i].dwLocalPort);
+ newConn->intExtPort = ntohs((u_short)pTcpTable->table[i].dwRemotePort);
+ newConn->Pid = pTcpTable->table[i].dwOwningPid;
+ switch (pTcpTable->table[i].dwState) {
+ case MIB_TCP_STATE_CLOSED:
+ //printf("CLOSED\n");
+ break;
+ case MIB_TCP_STATE_LISTEN:
+ //printf("LISTEN\n");
+ break;
+ case MIB_TCP_STATE_SYN_SENT:
+ //printf("SYN-SENT\n");
+ break;
+ case MIB_TCP_STATE_SYN_RCVD:
+ //printf("SYN-RECEIVED\n");
+ break;
+ case MIB_TCP_STATE_ESTAB:
+ //printf("ESTABLISHED\n");
+ break;
+ case MIB_TCP_STATE_FIN_WAIT1:
+ //printf("FIN-WAIT-1\n");
+ break;
+ case MIB_TCP_STATE_FIN_WAIT2:
+ //printf("FIN-WAIT-2 \n");
+ break;
+ case MIB_TCP_STATE_CLOSE_WAIT:
+ //printf("CLOSE-WAIT\n");
+ break;
+ case MIB_TCP_STATE_CLOSING:
+ //printf("CLOSING\n");
+ break;
+ case MIB_TCP_STATE_LAST_ACK:
+ //printf("LAST-ACK\n");
+ break;
+ case MIB_TCP_STATE_TIME_WAIT:
+ //printf("TIME-WAIT\n");
+ break;
+ case MIB_TCP_STATE_DELETE_TCB:
+ //printf("DELETE-TCB\n");
+ break;
+ default:
+ //printf("UNKNOWN dwState value\n");
+ break;
+ }
+ newConn->next = connHead;
+ connHead = newConn;
+ //printf("TCP[%d]:%s%15d%20s%15d\n", i, szLocalAddr,ntohs((u_short)pTcpTable->table[i].dwLocalPort), szRemoteAddr,ntohs((u_short)pTcpTable->table[i].dwRemotePort));
+ //printf("\tTCP[%d] Local Addr: %s\n", i, szLocalAddr);
+ // printf("\tTCP[%d] Local Port: %d \n", i, ntohs((u_short)pTcpTable->table[i].dwLocalPort));
+ //printf("\tTCP[%d] Remote Addr: %s\n", i, szRemoteAddr);
+ //printf("\tTCP[%d] Remote Port: %d\n", i, ntohs((u_short)pTcpTable->table[i].dwRemotePort));
+ }
+ FREE(pTcpTable);
+
+ return connHead;
+}
+
+void deleteConnectionsTable(struct CONNECTION *head)
+{
+ struct CONNECTION *cur = head, *del;
+
+ while (cur != nullptr) {
+ del = cur;
+ cur = cur->next;
+ mir_free(del);
+ head = cur;
+ }
+ head = nullptr;
+}
+
+struct CONNECTION *searchConnection(struct CONNECTION *head, wchar_t *intIp, wchar_t *extIp, int intPort, int extPort, int state)
+{
+ for (struct CONNECTION *cur = head; cur != nullptr; cur = cur->next) {
+ if (mir_wstrcmp(cur->strIntIp, intIp) == 0 &&
+ mir_wstrcmp(cur->strExtIp, extIp) == 0 &&
+ cur->intExtPort == extPort &&
+ cur->intIntPort == intPort &&
+ cur->state == state)
+ return cur;
+ }
+ return nullptr;
+}
+
+void getDnsName(wchar_t *strIp, wchar_t *strHostName, size_t len)
+{
+ in_addr iaHost;
+
+ char *szStrIP = mir_u2a(strIp);
+ iaHost.s_addr = inet_addr(szStrIP);
+ mir_free(szStrIP);
+ hostent *h = gethostbyaddr((char *)&iaHost, sizeof(struct in_addr), AF_INET);
+ wcsncpy_s(strHostName, len, (h == nullptr) ? strIp : _A2T(h->h_name), _TRUNCATE);
+}
diff --git a/protocols/ConnectionNotify/src/netstat.h b/protocols/ConnectionNotify/src/netstat.h
new file mode 100644
index 0000000000..e4d1631775
--- /dev/null
+++ b/protocols/ConnectionNotify/src/netstat.h
@@ -0,0 +1,18 @@
+#pragma once
+
+struct CONNECTION
+{
+ wchar_t strIntIp[16];
+ wchar_t strExtIp[16];
+ int intIntPort;
+ int intExtPort;
+ int state;
+ DWORD Pid;
+ wchar_t PName[260];
+ struct CONNECTION *next;
+};
+
+struct CONNECTION* GetConnectionsTable();
+void deleteConnectionsTable(struct CONNECTION* head);
+struct CONNECTION* searchConnection(struct CONNECTION* head, wchar_t *intIp, wchar_t *extIp, int intPort, int extPort, int state);
+void getDnsName(wchar_t *strIp, wchar_t *strHostName, size_t len);
diff --git a/protocols/ConnectionNotify/src/pid2name.cpp b/protocols/ConnectionNotify/src/pid2name.cpp
new file mode 100644
index 0000000000..f5c10ca9e6
--- /dev/null
+++ b/protocols/ConnectionNotify/src/pid2name.cpp
@@ -0,0 +1,21 @@
+#include "stdafx.h"
+
+void pid2name(DWORD procid, wchar_t *buffer, size_t bufLen)
+{
+ PROCESSENTRY32 ProcessStruct;
+ ProcessStruct.dwSize = sizeof(PROCESSENTRY32);
+ HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (hSnap == INVALID_HANDLE_VALUE)
+ return;
+ if (Process32First(hSnap, &ProcessStruct) == FALSE)
+ return;
+
+ do {
+ if (ProcessStruct.th32ProcessID == procid) {
+ wcsncpy_s(buffer, bufLen, ProcessStruct.szExeFile, _TRUNCATE);
+ break;
+ }
+ } while (Process32Next(hSnap, &ProcessStruct));
+
+ CloseHandle(hSnap);
+}
diff --git a/protocols/ConnectionNotify/src/pid2name.h b/protocols/ConnectionNotify/src/pid2name.h
new file mode 100644
index 0000000000..96338a14b1
--- /dev/null
+++ b/protocols/ConnectionNotify/src/pid2name.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#ifndef _INC_PID2NAME
+#define _INC_PID2NAME
+
+void pid2name(DWORD, wchar_t*, size_t);
+#endif
+
diff --git a/protocols/ConnectionNotify/src/resource.h b/protocols/ConnectionNotify/src/resource.h
new file mode 100644
index 0000000000..0215e70270
--- /dev/null
+++ b/protocols/ConnectionNotify/src/resource.h
@@ -0,0 +1,34 @@
+#ifndef IDC_STATIC
+#define IDC_STATIC (-1)
+#endif
+
+#define IDI_ICON1 101
+#define IDD_OPT_DIALOG 102
+#define IDI_ICON2 103
+#define IDD_FILTER_DIALOG 105
+#define IDI_ICON3 110
+#define IDI_ICON4 111
+#define IDI_ICON5 114
+#define IDI_ICON6 115
+#define ID_TEXT_NAME 1000
+#define IDC_RESOLVEIP 1001
+#define IDC_LIST_EXCEPTIONS 1002
+#define IDC_INTERVAL 1003
+#define ID_CHK_DEFAULTACTION 1004
+#define ID_DELETE 1005
+#define ID_DOWN 1006
+#define ID_ADD 1007
+#define ID_UP 1008
+#define IDC_SETCOLOURS 1009
+#define IDC_INTERVAL1 1010
+#define IDC_BGCOLOR 1011
+#define IDC_FGCOLOR 1012
+#define IDC_STATUS 1016
+#define IDC_VERSION 1017
+#define ID_TXT_LOCAL_IP 1070
+#define ID_TXT_REMOTE_IP 1071
+#define ID_CBO_ACTION 1074
+#define ID_TXT_REMOTE_PORT 1075
+#define ID_TXT_LOCAL_PORT 1076
+#define ID_CANCEL 1077
+#define ID_OK 1078
diff --git a/protocols/ConnectionNotify/src/stdafx.cxx b/protocols/ConnectionNotify/src/stdafx.cxx
new file mode 100644
index 0000000000..1b563fc866
--- /dev/null
+++ b/protocols/ConnectionNotify/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/ConnectionNotify/src/stdafx.h b/protocols/ConnectionNotify/src/stdafx.h
new file mode 100644
index 0000000000..98123939fd
--- /dev/null
+++ b/protocols/ConnectionNotify/src/stdafx.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <windows.h>
+#include <Commctrl.h>
+#include <assert.h>
+#include <iphlpapi.h>
+#include <Tlhelp32.h>
+
+#include <newpluginapi.h>
+#include <m_core.h>
+#include <m_clistint.h>
+#include <m_skin.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#include <m_popup.h>
+#include <m_utils.h>
+#include <m_protosvc.h>
+#include <m_system.h>
+
+#ifdef _DEBUG
+#include "debug.h"
+#endif
+#include "resource.h"
+#include "netstat.h"
+#include "filter.h"
+#include "version.h"
+#include "pid2name.h"
+
+#define MAX_SETTING_STR 512
+#define MAX_LENGTH 512
+#define STATUS_COUNT 9
+
+// Note: could also use malloc() and free()
+#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
+#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
+
+#define PLUGINNAME "ConnectionNotify"
+#define PLUGINNAME_NEWSOUND PLUGINNAME "_new_sound"
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
+
+void showMsg(wchar_t *pName,DWORD pid,wchar_t *intIp,wchar_t *extIp,int intPort,int extPort,int state);
+static unsigned __stdcall checkthread(void *dummy);
+struct CONNECTION * LoadSettingsConnections();
+void saveSettingsConnections(struct CONNECTION *connHead);
diff --git a/protocols/ConnectionNotify/src/version.h b/protocols/ConnectionNotify/src/version.h
new file mode 100644
index 0000000000..6ca2e3eb6f
--- /dev/null
+++ b/protocols/ConnectionNotify/src/version.h
@@ -0,0 +1,38 @@
+/*
+Exchange notifier plugin for Miranda IM
+
+Copyright © 2006 Cristian Libotean, Attila Vajda
+
+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; either version 2
+of the License, or (at your option) any later version.
+
+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, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef M_NONNECTIONNOTIFY_VERSION_H
+#define M_NONNECTIONNOTIFY_VERSION_H
+
+#define __MAJOR_VERSION 0
+#define __MINOR_VERSION 1
+#define __RELEASE_NUM 0
+#define __BUILD_NUM 5
+
+#include <stdver.h>
+
+#define __PLUGIN_NAME "Connection Notify"
+#define __FILENAME "ConnectionNotify.dll"
+#define __DESCRIPTION "Notify with popup if some connection established"
+#define __AUTHOR "MaKaR"
+#define __COPYRIGHT "© 2011-13 MaKaRSoFT"
+#define __AUTHORWEB "https://miranda-ng.org/p/ConnectionNotify/"
+
+#endif //M_EXCHANGE_VERSION_H