From b1bb4a6c3ceab2d8f528e87589b43f08d60e00f3 Mon Sep 17 00:00:00 2001 From: henrypp Date: Fri, 17 Apr 2020 16:32:43 +0600 Subject: [PATCH] adds editor code --- src/editor.cpp | 1013 ++++++++++++++++++++++++++++++++++++++++++++++++ src/editor.hpp | 9 + 2 files changed, 1022 insertions(+) create mode 100644 src/editor.cpp create mode 100644 src/editor.hpp diff --git a/src/editor.cpp b/src/editor.cpp new file mode 100644 index 00000000..5dfe3ca2 --- /dev/null +++ b/src/editor.cpp @@ -0,0 +1,1013 @@ +// simplewall +// Copyright (c) 2016-2020 Henry++ + +#include "global.hpp" + +INT_PTR CALLBACK AddRuleProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + static PEDITOR_CONTEXT pcontext; + + switch (msg) + { + case WM_INITDIALOG: + { + pcontext = (PEDITOR_CONTEXT)lparam; + +#if !defined(_APP_NO_DARKTHEME) + _r_wnd_setdarktheme (hwnd); +#endif // !_APP_NO_DARKTHEME + + _r_wnd_center (hwnd, GetParent (hwnd)); + + // localize window + SetWindowText (hwnd, app.LocaleString (IDS_OPENRULESEDITOR, nullptr)); + + SetDlgItemText (hwnd, IDC_RULE, app.LocaleString (IDS_RULE, L":")); + + if (pcontext->item_id != INVALID_INT) + SetDlgItemText (hwnd, IDC_RULE_ID, _r_listview_getitemtext (pcontext->hwnd, pcontext->listview_id, pcontext->item_id, 0)); + + SetDlgItemText (hwnd, IDC_RULE_HINT, L"eg. 192.168.0.1\r\neg. [fe80::]\r\neg. 192.168.0.1:443\r\neg. [fe80::]:443\r\neg. 192.168.0.1-192.168.0.255\r\neg. 192.168.0.1-192.168.0.255:443\r\neg. 192.168.0.0/16\r\neg. fe80::/10\r\neg. 80\r\neg. 443\r\neg. 20-21\r\neg. 49152-65534"); + + SetDlgItemText (hwnd, IDC_SAVE, app.LocaleString (pcontext->item_id != INVALID_INT ? IDS_SAVE : IDS_ADD, nullptr)); + SetDlgItemText (hwnd, IDC_CLOSE, app.LocaleString (IDS_CLOSE, nullptr)); + + _r_wnd_addstyle (hwnd, IDC_SAVE, app.IsClassicUI () ? WS_EX_STATICEDGE : 0, WS_EX_STATICEDGE, GWL_EXSTYLE); + _r_wnd_addstyle (hwnd, IDC_CLOSE, app.IsClassicUI () ? WS_EX_STATICEDGE : 0, WS_EX_STATICEDGE, GWL_EXSTYLE); + + _r_ctrl_enable (hwnd, IDC_SAVE, false); + + break; + } + + case WM_NCCREATE: + { + _r_wnd_enablenonclientscaling (hwnd); + break; + } + + case WM_CLOSE: + { + EndDialog (hwnd, 0); + break; + } + + case WM_SETTINGCHANGE: + { + _r_wnd_changesettings (hwnd, wparam, lparam); + break; + } + + case WM_COMMAND: + { + const INT ctrl_id = LOWORD (wparam); + const INT notify_code = HIWORD (wparam); + + if (notify_code == EN_CHANGE) + { + _r_ctrl_enable (hwnd, IDC_SAVE, SendDlgItemMessage (hwnd, IDC_RULE_ID, WM_GETTEXTLENGTH, 0, 0) > 0); // enable apply button + return FALSE; + } + + switch (ctrl_id) + { + case IDOK: // process Enter key + case IDC_SAVE: + { + if (!_r_ctrl_isenabled (hwnd, IDC_SAVE)) + return FALSE; + + rstring rule_single = _r_ctrl_gettext (hwnd, IDC_RULE_ID); + _r_str_trim (rule_single, DIVIDER_TRIM DIVIDER_RULE); + + if (rule_single.IsEmpty ()) + return FALSE; + + if (!_app_parserulestring (rule_single, nullptr)) + { + _r_ctrl_showtip (hwnd, IDC_RULE_ID, 0, nullptr, app.LocaleString (IDS_STATUS_SYNTAX_ERROR, nullptr)); + _r_ctrl_enable (hwnd, IDC_SAVE, false); + + return FALSE; + } + + if (pcontext->item_id == INVALID_INT) + { + INT new_item_id = _r_listview_getitemcount (pcontext->hwnd, pcontext->listview_id); + _r_listview_additem (pcontext->hwnd, pcontext->listview_id, new_item_id, 0, rule_single, I_IMAGENONE, I_GROUPIDNONE, new_item_id); + } + else + { + _r_listview_setitem (pcontext->hwnd, pcontext->listview_id, pcontext->item_id, 0, rule_single); + } + + [[fallthrough]]; + } + + case IDCANCEL: // process Esc key + case IDC_CLOSE: + { + EndDialog (hwnd, 0); + break; + } + } + + break; + } + } + + return FALSE; +} + +INT_PTR CALLBACK EditorPagesProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + static PITEM_RULE ptr_rule = nullptr; + + switch (msg) + { + case WM_INITDIALOG: + { + ptr_rule = (PITEM_RULE)lparam; + +#ifndef _APP_NO_DARKTHEME + _r_wnd_setdarktheme (hwnd); +#endif // _APP_NO_DARKTHEME + + EnableThemeDialogTexture (hwnd, ETDT_ENABLETAB); + + SetWindowPos (hwnd, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED); + + // name + if (GetDlgItem (hwnd, IDC_RULE_NAME_ID)) + { + SetDlgItemText (hwnd, IDC_RULE_NAME, app.LocaleString (IDS_NAME, L":")); + + if (!_r_str_isempty (ptr_rule->pname)) + SetDlgItemText (hwnd, IDC_RULE_NAME_ID, ptr_rule->pname); + + SendDlgItemMessage (hwnd, IDC_RULE_NAME_ID, EM_LIMITTEXT, RULE_NAME_CCH_MAX - 1, 0); + SendDlgItemMessage (hwnd, IDC_RULE_NAME_ID, EM_SETREADONLY, ptr_rule->is_readonly, 0); + } + + const rstring text_any = app.LocaleString (IDS_ANY, nullptr); + + // direction + if (GetDlgItem (hwnd, IDC_RULE_DIRECTION)) + { + SetDlgItemText (hwnd, IDC_RULE_DIRECTION, app.LocaleString (IDS_DIRECTION, L":")); + + SetDlgItemText (hwnd, IDC_RULE_DIRECTION_OUTBOUND, app.LocaleString (IDS_DIRECTION_1, nullptr)); + SetDlgItemText (hwnd, IDC_RULE_DIRECTION_INBOUND, app.LocaleString (IDS_DIRECTION_2, nullptr)); + SetDlgItemText (hwnd, IDC_RULE_DIRECTION_ANY, text_any); + + if (ptr_rule->direction == FWP_DIRECTION_OUTBOUND) + CheckRadioButton (hwnd, IDC_RULE_DIRECTION_OUTBOUND, IDC_RULE_DIRECTION_ANY, IDC_RULE_DIRECTION_OUTBOUND); + + else if (ptr_rule->direction == FWP_DIRECTION_INBOUND) + CheckRadioButton (hwnd, IDC_RULE_DIRECTION_OUTBOUND, IDC_RULE_DIRECTION_ANY, IDC_RULE_DIRECTION_INBOUND); + + else if (ptr_rule->direction == FWP_DIRECTION_MAX) + CheckRadioButton (hwnd, IDC_RULE_DIRECTION_OUTBOUND, IDC_RULE_DIRECTION_ANY, IDC_RULE_DIRECTION_ANY); + + _r_ctrl_enable (hwnd, IDC_RULE_DIRECTION_OUTBOUND, !ptr_rule->is_readonly); + _r_ctrl_enable (hwnd, IDC_RULE_DIRECTION_INBOUND, !ptr_rule->is_readonly); + _r_ctrl_enable (hwnd, IDC_RULE_DIRECTION_ANY, !ptr_rule->is_readonly); + } + + // action + if (GetDlgItem (hwnd, IDC_RULE_ACTION)) + { + SetDlgItemText (hwnd, IDC_RULE_ACTION, app.LocaleString (IDS_ACTION, L":")); + + SetDlgItemText (hwnd, IDC_RULE_ACTION_BLOCK, app.LocaleString (IDS_ACTION_BLOCK, nullptr)); + SetDlgItemText (hwnd, IDC_RULE_ACTION_ALLOW, app.LocaleString (IDS_ACTION_ALLOW, nullptr)); + + CheckRadioButton (hwnd, IDC_RULE_ACTION_BLOCK, IDC_RULE_ACTION_ALLOW, ptr_rule->is_block ? IDC_RULE_ACTION_BLOCK : IDC_RULE_ACTION_ALLOW); + + _r_ctrl_enable (hwnd, IDC_RULE_ACTION_ALLOW, !ptr_rule->is_readonly); + _r_ctrl_enable (hwnd, IDC_RULE_ACTION_BLOCK, !ptr_rule->is_readonly); + } + + // protocols + if (GetDlgItem (hwnd, IDC_RULE_PROTOCOL_ID)) + { + SetDlgItemText (hwnd, IDC_RULE_PROTOCOL, app.LocaleString (IDS_PROTOCOL, L":")); + + const UINT8 protos[] = { + IPPROTO_ICMP, + IPPROTO_IGMP, + IPPROTO_IPV4, + IPPROTO_TCP, + IPPROTO_UDP, + IPPROTO_RDP, + IPPROTO_IPV6, + IPPROTO_ICMPV6, + IPPROTO_L2TP, + IPPROTO_SCTP, + }; + + INT index = 0; + + SendDlgItemMessage (hwnd, IDC_RULE_PROTOCOL_ID, CB_INSERTSTRING, index, (LPARAM)text_any.GetString ()); + SendDlgItemMessage (hwnd, IDC_RULE_PROTOCOL_ID, CB_SETITEMDATA, index, 0); + + if (ptr_rule->protocol == 0) + SendDlgItemMessage (hwnd, IDC_RULE_PROTOCOL_ID, CB_SETCURSEL, index, 0); + + index += 1; + + for (auto &proto : protos) + { + SendDlgItemMessage (hwnd, IDC_RULE_PROTOCOL_ID, CB_INSERTSTRING, index, (LPARAM)_r_fmt (L"%s (%" PRIu8 L")", _app_getprotoname (proto, AF_UNSPEC).GetString (), proto).GetString ()); + SendDlgItemMessage (hwnd, IDC_RULE_PROTOCOL_ID, CB_SETITEMDATA, index, (LPARAM)proto); + + if (ptr_rule->protocol == proto) + SendDlgItemMessage (hwnd, IDC_RULE_PROTOCOL_ID, CB_SETCURSEL, (WPARAM)index, 0); + + index += 1; + } + + // unknown protocol + if (SendDlgItemMessage (hwnd, IDC_RULE_PROTOCOL_ID, CB_GETCURSEL, 0, 0) == CB_ERR) + { + SendDlgItemMessage (hwnd, IDC_RULE_PROTOCOL_ID, CB_INSERTSTRING, index, (LPARAM)_r_fmt (L"%s (%" PRIu8 L")", _app_getprotoname (ptr_rule->protocol, AF_UNSPEC).GetString (), ptr_rule->protocol).GetString ()); + SendDlgItemMessage (hwnd, IDC_RULE_PROTOCOL_ID, CB_SETITEMDATA, index, (LPARAM)ptr_rule->protocol); + + SendDlgItemMessage (hwnd, IDC_RULE_PROTOCOL_ID, CB_SETCURSEL, (WPARAM)index, 0); + } + + _r_ctrl_enable (hwnd, IDC_RULE_PROTOCOL_ID, !ptr_rule->is_readonly); + } + + // rule (remote) + if (GetDlgItem (hwnd, IDC_RULE_REMOTE_ID)) + { + SetDlgItemText (hwnd, IDC_RULE_REMOTE, app.LocaleString (IDS_RULE, L" (" SZ_DIRECTION_REMOTE L"):")); + + _r_listview_setstyle (hwnd, IDC_RULE_REMOTE_ID, LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_LABELTIP); + _r_listview_addcolumn (hwnd, IDC_RULE_REMOTE_ID, 0, nullptr, -100, 0); + + if (!_r_str_isempty (ptr_rule->prule_remote)) + { + rstringvec rvc; + _r_str_split (ptr_rule->prule_remote, INVALID_SIZE_T, DIVIDER_RULE[0], rvc); + + INT index = 0; + + for (auto &rule_single : rvc) + { + _r_str_trim (rule_single, DIVIDER_TRIM DIVIDER_RULE); + + _r_listview_additem (hwnd, IDC_RULE_REMOTE_ID, index, 0, rule_single, I_IMAGENONE, I_GROUPIDNONE, index); + + index += 1; + } + + _r_listview_setcolumn (hwnd, IDC_RULE_REMOTE_ID, 0, nullptr, -100); + } + + SetDlgItemText (hwnd, IDC_RULE_REMOTE_ADD, app.LocaleString (IDS_ADD, L"...")); + SetDlgItemText (hwnd, IDC_RULE_REMOTE_EDIT, app.LocaleString (IDS_EDIT2, L"...")); + SetDlgItemText (hwnd, IDC_RULE_REMOTE_DELETE, app.LocaleString (IDS_DELETE, nullptr)); + + _r_ctrl_enable (hwnd, IDC_RULE_REMOTE_ADD, !ptr_rule->is_readonly); + _r_ctrl_enable (hwnd, IDC_RULE_REMOTE_EDIT, false); + _r_ctrl_enable (hwnd, IDC_RULE_REMOTE_DELETE, false); + + _r_wnd_addstyle (hwnd, IDC_RULE_REMOTE_ADD, app.IsClassicUI () ? WS_EX_STATICEDGE : 0, WS_EX_STATICEDGE, GWL_EXSTYLE); + _r_wnd_addstyle (hwnd, IDC_RULE_REMOTE_EDIT, app.IsClassicUI () ? WS_EX_STATICEDGE : 0, WS_EX_STATICEDGE, GWL_EXSTYLE); + _r_wnd_addstyle (hwnd, IDC_RULE_REMOTE_DELETE, app.IsClassicUI () ? WS_EX_STATICEDGE : 0, WS_EX_STATICEDGE, GWL_EXSTYLE); + } + + // rule (local) + if (GetDlgItem (hwnd, IDC_RULE_LOCAL_ID)) + { + SetDlgItemText (hwnd, IDC_RULE_LOCAL, app.LocaleString (IDS_RULE, L" (" SZ_DIRECTION_LOCAL L"):")); + + _r_listview_setstyle (hwnd, IDC_RULE_LOCAL_ID, LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_LABELTIP); + _r_listview_addcolumn (hwnd, IDC_RULE_LOCAL_ID, 0, nullptr, -100, 0); + + if (!_r_str_isempty (ptr_rule->prule_local)) + { + rstringvec rvc; + _r_str_split (ptr_rule->prule_local, INVALID_SIZE_T, DIVIDER_RULE[0], rvc); + + INT index = 0; + + for (auto &rule_single : rvc) + { + _r_str_trim (rule_single, DIVIDER_TRIM DIVIDER_RULE); + + _r_listview_additem (hwnd, IDC_RULE_LOCAL_ID, index, 0, rule_single, I_IMAGENONE, I_GROUPIDNONE, index); + + index += 1; + } + + _r_listview_setcolumn (hwnd, IDC_RULE_LOCAL_ID, 0, nullptr, -100); + } + + SetDlgItemText (hwnd, IDC_RULE_LOCAL_ADD, app.LocaleString (IDS_ADD, L"...")); + SetDlgItemText (hwnd, IDC_RULE_LOCAL_EDIT, app.LocaleString (IDS_EDIT2, L"...")); + SetDlgItemText (hwnd, IDC_RULE_LOCAL_DELETE, app.LocaleString (IDS_DELETE, nullptr)); + + _r_ctrl_enable (hwnd, IDC_RULE_LOCAL_ADD, !ptr_rule->is_readonly); + _r_ctrl_enable (hwnd, IDC_RULE_LOCAL_EDIT, false); + _r_ctrl_enable (hwnd, IDC_RULE_LOCAL_DELETE, false); + + _r_wnd_addstyle (hwnd, IDC_RULE_LOCAL_ADD, app.IsClassicUI () ? WS_EX_STATICEDGE : 0, WS_EX_STATICEDGE, GWL_EXSTYLE); + _r_wnd_addstyle (hwnd, IDC_RULE_LOCAL_EDIT, app.IsClassicUI () ? WS_EX_STATICEDGE : 0, WS_EX_STATICEDGE, GWL_EXSTYLE); + _r_wnd_addstyle (hwnd, IDC_RULE_LOCAL_DELETE, app.IsClassicUI () ? WS_EX_STATICEDGE : 0, WS_EX_STATICEDGE, GWL_EXSTYLE); + } + + // apps + if (GetDlgItem (hwnd, IDC_RULE_APPS_ID)) + { + _app_listviewsetfont (hwnd, IDC_RULE_APPS_ID, false); + _app_listviewsetview (hwnd, IDC_RULE_APPS_ID); + + _r_listview_setstyle (hwnd, IDC_RULE_APPS_ID, LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT | LVS_EX_INFOTIP | LVS_EX_LABELTIP | LVS_EX_CHECKBOXES); + _r_listview_addcolumn (hwnd, IDC_RULE_APPS_ID, 0, app.LocaleString (IDS_NAME, nullptr), -100, LVCFMT_LEFT); + + // apps (apply to) + { + INT item = 0; + + _r_fastlock_acquireshared (&lock_access); + + for (auto &p : apps) + { + PR_OBJECT ptr_app_object = _r_obj_reference (p.second); + + if (!ptr_app_object) + continue; + + PITEM_APP ptr_app = (PITEM_APP)ptr_app_object->pdata; + + if (!ptr_app) + { + _r_obj_dereference (ptr_app_object); + continue; + } + + // windows store apps (win8+) + if (ptr_app->type == DataAppUWP && !_r_sys_validversion (6, 2)) + { + _r_obj_dereference (ptr_app_object); + continue; + } + + // check for services + const bool is_enabled = (ptr_rule->apps.find (p.first) != ptr_rule->apps.end ()) || ptr_rule->is_forservices && (p.first == config.ntoskrnl_hash || p.first == config.svchost_hash); + + _r_fastlock_acquireshared (&lock_checkbox); + + _r_listview_additem (hwnd, IDC_RULE_APPS_ID, item, 0, _r_path_getfilename (ptr_app->display_name), ptr_app->icon_id, I_GROUPIDNONE, p.first); + _r_listview_setitemcheck (hwnd, IDC_RULE_APPS_ID, item, is_enabled); + + _r_fastlock_releaseshared (&lock_checkbox); + + item += 1; + + _r_obj_dereference (ptr_app_object); + } + + _r_fastlock_releaseshared (&lock_access); + + // resize column + _r_listview_setcolumn (hwnd, IDC_RULE_APPS_ID, 0, nullptr, -100); + + // sort column + _app_listviewsort (hwnd, IDC_RULE_APPS_ID); + } + } + + // hints + if (GetDlgItem (hwnd, IDC_RULE_HINT)) + SetDlgItemText (hwnd, IDC_RULE_HINT, app.LocaleString (IDS_RULE_HINT, nullptr)); + + if (GetDlgItem (hwnd, IDC_RULE_APPS_HINT)) + SetDlgItemText (hwnd, IDC_RULE_APPS_HINT, app.LocaleString (IDS_RULE_APPS_HINT, nullptr)); + + break; + } + + case WM_NOTIFY: + { + LPNMHDR nmlp = (LPNMHDR)lparam; + + switch (nmlp->code) + { + case NM_CUSTOMDRAW: + { + LONG result = CDRF_DODEFAULT; + + if (_r_fastlock_tryacquireshared (&lock_access)) + { + result = _app_nmcustdraw_listview ((LPNMLVCUSTOMDRAW)lparam); + _r_fastlock_releaseshared (&lock_access); + } + + SetWindowLongPtr (hwnd, DWLP_MSGRESULT, result); + return result; + } + + case NM_DBLCLK: + { + LPNMITEMACTIVATE lpnmlv = (LPNMITEMACTIVATE)lparam; + + if (lpnmlv->iItem == INVALID_INT) + break; + + INT command_id = 0; + const INT ctrl_id = static_cast(lpnmlv->hdr.idFrom); + + if (ctrl_id == IDC_RULE_REMOTE_ID) + { + command_id = IDC_RULE_REMOTE_EDIT; + } + else if (ctrl_id == IDC_RULE_LOCAL_ID) + { + command_id = IDC_RULE_LOCAL_EDIT; + } + + if (command_id) + PostMessage (hwnd, WM_COMMAND, MAKEWPARAM (command_id, 0), 0); + + break; + } + + case NM_RCLICK: + { + LPNMITEMACTIVATE lpnmlv = (LPNMITEMACTIVATE)lparam; + + const INT listview_id = static_cast(lpnmlv->hdr.idFrom); + + if ( + listview_id != IDC_RULE_REMOTE_ID && + listview_id != IDC_RULE_LOCAL_ID && + listview_id != IDC_RULE_APPS_ID + ) + { + break; + } + + const HMENU hsubmenu = CreatePopupMenu (); + + if (!hsubmenu) + break; + + const bool is_selected = (INT)SendDlgItemMessage (hwnd, listview_id, LVM_GETSELECTEDCOUNT, 0, 0) != 0; + + if (listview_id == IDC_RULE_REMOTE_ID || listview_id == IDC_RULE_LOCAL_ID) + { + const bool is_remote = listview_id == IDC_RULE_REMOTE_ID; + + const UINT id_add = is_remote ? IDC_RULE_REMOTE_ADD : IDC_RULE_LOCAL_ADD; + const UINT id_edit = is_remote ? IDC_RULE_REMOTE_EDIT : IDC_RULE_LOCAL_EDIT; + const UINT id_delete = is_remote ? IDC_RULE_REMOTE_DELETE : IDC_RULE_LOCAL_DELETE; + + AppendMenu (hsubmenu, MF_BYCOMMAND, id_add, app.LocaleString (IDS_ADD, L"...")); + AppendMenu (hsubmenu, MF_BYCOMMAND, id_edit, app.LocaleString (IDS_EDIT2, L"...")); + AppendMenu (hsubmenu, MF_BYCOMMAND, id_delete, app.LocaleString (IDS_DELETE, nullptr)); + AppendMenu (hsubmenu, MF_SEPARATOR, 0, nullptr); + AppendMenu (hsubmenu, MF_BYCOMMAND, IDM_COPY, app.LocaleString (IDS_COPY, nullptr)); + + if (ptr_rule->is_readonly) + { + _r_menu_enableitem (hsubmenu, id_add, MF_BYCOMMAND, false); + _r_menu_enableitem (hsubmenu, id_edit, MF_BYCOMMAND, false); + _r_menu_enableitem (hsubmenu, id_delete, MF_BYCOMMAND, false); + } + + if (!is_selected) + { + _r_menu_enableitem (hsubmenu, id_edit, MF_BYCOMMAND, false); + _r_menu_enableitem (hsubmenu, id_delete, MF_BYCOMMAND, false); + _r_menu_enableitem (hsubmenu, IDM_COPY, MF_BYCOMMAND, false); + } + } + else if (listview_id == IDC_RULE_APPS_ID) + { + AppendMenu (hsubmenu, MF_BYCOMMAND, IDM_CHECK, app.LocaleString (IDS_CHECK, nullptr)); + AppendMenu (hsubmenu, MF_BYCOMMAND, IDM_UNCHECK, app.LocaleString (IDS_UNCHECK, nullptr)); + AppendMenu (hsubmenu, MF_SEPARATOR, 0, nullptr); + AppendMenu (hsubmenu, MF_BYCOMMAND, IDM_PROPERTIES, app.LocaleString (IDS_SHOWINLIST, nullptr)); + AppendMenu (hsubmenu, MF_SEPARATOR, 0, nullptr); + AppendMenu (hsubmenu, MF_BYCOMMAND, IDM_COPY, app.LocaleString (IDS_COPY, nullptr)); + + if (ptr_rule->type != DataRuleCustom) + { + _r_menu_enableitem (hsubmenu, IDM_CHECK, MF_BYCOMMAND, false); + _r_menu_enableitem (hsubmenu, IDM_UNCHECK, MF_BYCOMMAND, false); + } + + if (!is_selected) + { + _r_menu_enableitem (hsubmenu, IDM_CHECK, MF_BYCOMMAND, false); + _r_menu_enableitem (hsubmenu, IDM_UNCHECK, MF_BYCOMMAND, false); + _r_menu_enableitem (hsubmenu, IDM_PROPERTIES, MF_BYCOMMAND, false); + _r_menu_enableitem (hsubmenu, IDM_COPY, MF_BYCOMMAND, false); + } + } + + _r_menu_popup (hsubmenu, hwnd, nullptr, true); + + DestroyMenu (hsubmenu); + + break; + } + + case LVN_COLUMNCLICK: + { + LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lparam; + _app_listviewsort (hwnd, static_cast(lpnmlv->hdr.idFrom), lpnmlv->iSubItem, true); + + break; + } + + case LVN_ITEMCHANGING: + { + LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lparam; + + const INT listview_id = static_cast(lpnmlv->hdr.idFrom); + + if ((lpnmlv->uChanged & LVIF_STATE) != 0) + { + if (listview_id == IDC_RULE_APPS_ID) + { + if ((lpnmlv->uNewState & LVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK (1) || ((lpnmlv->uNewState & LVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK (2))) + { + if (!_r_fastlock_islocked (&lock_checkbox) && ptr_rule->type != DataRuleCustom) + { + SetWindowLongPtr (hwnd, DWLP_MSGRESULT, TRUE); + return TRUE; + } + } + } + } + + break; + } + + case LVN_ITEMCHANGED: + { + LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lparam; + + const INT listview_id = static_cast(lpnmlv->hdr.idFrom); + + if ((lpnmlv->uChanged & LVIF_STATE) != 0) + { + if (listview_id == IDC_RULE_APPS_ID) + { + if ((lpnmlv->uNewState & LVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK (1) || ((lpnmlv->uNewState & LVIS_STATEIMAGEMASK) == INDEXTOSTATEIMAGEMASK (2))) + { + if (_r_fastlock_islocked (&lock_checkbox)) + break; + + _app_listviewsort (hwnd, listview_id); + } + } + else if (listview_id == IDC_RULE_REMOTE_ID || listview_id == IDC_RULE_LOCAL_ID) + { + if ((lpnmlv->uOldState & LVIS_SELECTED) != 0 || (lpnmlv->uNewState & LVIS_SELECTED) != 0) + { + if (!ptr_rule->is_readonly) + { + const bool is_selected = (lpnmlv->uNewState & LVIS_SELECTED) != 0; + + if (listview_id == IDC_RULE_REMOTE_ID) + { + _r_ctrl_enable (hwnd, IDC_RULE_REMOTE_EDIT, is_selected); + _r_ctrl_enable (hwnd, IDC_RULE_REMOTE_DELETE, is_selected); + } + else if (listview_id == IDC_RULE_LOCAL_ID) + { + _r_ctrl_enable (hwnd, IDC_RULE_LOCAL_EDIT, is_selected); + _r_ctrl_enable (hwnd, IDC_RULE_LOCAL_DELETE, is_selected); + } + } + } + } + } + + break; + } + + case LVN_GETINFOTIP: + { + LPNMLVGETINFOTIP lpnmlv = (LPNMLVGETINFOTIP)lparam; + + const INT listview_id = static_cast(lpnmlv->hdr.idFrom); + const size_t app_hash = _r_listview_getitemlparam (hwnd, listview_id, lpnmlv->iItem); + + _r_str_copy (lpnmlv->pszText, lpnmlv->cchTextMax, _app_gettooltip (hwnd, listview_id, app_hash)); + + break; + } + + case LVN_GETEMPTYMARKUP: + { + NMLVEMPTYMARKUP* lpnmlv = (NMLVEMPTYMARKUP*)lparam; + + lpnmlv->dwFlags = EMF_CENTERED; + _r_str_copy (lpnmlv->szMarkup, _countof (lpnmlv->szMarkup), app.LocaleString (IDS_STATUS_EMPTY, nullptr)); + + SetWindowLongPtr (hwnd, DWLP_MSGRESULT, TRUE); + return TRUE; + } + } + + break; + } + + case WM_COMMAND: + { + const INT ctrl_id = LOWORD (wparam); + + switch (ctrl_id) + { + case IDC_RULE_REMOTE_ADD: + case IDC_RULE_LOCAL_ADD: + case IDC_RULE_REMOTE_EDIT: + case IDC_RULE_LOCAL_EDIT: + { + if (!_r_ctrl_isenabled (hwnd, ctrl_id)) + break; + + const INT listview_id = ((ctrl_id == IDC_RULE_REMOTE_ADD || ctrl_id == IDC_RULE_REMOTE_EDIT) ? IDC_RULE_REMOTE_ID : IDC_RULE_LOCAL_ID); + INT item_id; + + if ((ctrl_id == IDC_RULE_REMOTE_EDIT || ctrl_id == IDC_RULE_LOCAL_EDIT)) + { + // edit rule + item_id = (INT)SendDlgItemMessage (hwnd, listview_id, LVM_GETNEXTITEM, (WPARAM)INVALID_INT, LVNI_SELECTED); + + if (item_id == INVALID_INT) + break; + } + else + { + // create new rule + item_id = INVALID_INT; + } + + PEDITOR_CONTEXT pcontext = (PEDITOR_CONTEXT)_r_mem_allocex (sizeof (EDITOR_CONTEXT), HEAP_ZERO_MEMORY); + + if (pcontext) + { + pcontext->hwnd = hwnd; + pcontext->listview_id = listview_id; + pcontext->item_id = item_id; + + DialogBoxParam (nullptr, MAKEINTRESOURCE (IDD_EDITOR_ADDRULE), hwnd, &AddRuleProc, (LPARAM)pcontext); + + _r_mem_free (pcontext); + } + + break; + } + + case IDC_RULE_REMOTE_DELETE: + case IDC_RULE_LOCAL_DELETE: + { + const INT listview_id = ((ctrl_id == IDC_RULE_REMOTE_DELETE) ? IDC_RULE_REMOTE_ID : IDC_RULE_LOCAL_ID); + const INT selected = (INT)SendDlgItemMessage (hwnd, listview_id, LVM_GETSELECTEDCOUNT, 0, 0); + + if (!selected || app.ShowMessage (hwnd, MB_YESNO | MB_ICONEXCLAMATION, nullptr, nullptr, _r_fmt (app.LocaleString (IDS_QUESTION_DELETE, nullptr), selected)) != IDYES) + break; + + const INT count = _r_listview_getitemcount (hwnd, listview_id) - 1; + + for (INT i = count; i != INVALID_INT; i--) + { + if ((UINT)SendDlgItemMessage (hwnd, listview_id, LVM_GETITEMSTATE, i, LVNI_SELECTED) == LVNI_SELECTED) + SendDlgItemMessage (hwnd, listview_id, LVM_DELETEITEM, i, 0); + } + + break; + } + + case IDM_CHECK: + case IDM_UNCHECK: + { + const bool new_val = ((ctrl_id == IDM_CHECK) ? true : false); + INT item = INVALID_INT; + + _r_fastlock_acquireshared (&lock_checkbox); + + while ((item = (INT)SendDlgItemMessage (hwnd, IDC_RULE_APPS_ID, LVM_GETNEXTITEM, (WPARAM)item, LVNI_SELECTED)) != INVALID_INT) + _r_listview_setitemcheck (hwnd, IDC_RULE_APPS_ID, item, new_val); + + _r_fastlock_releaseshared (&lock_checkbox); + + _app_listviewsort (hwnd, IDC_RULE_APPS_ID, 0); + + break; + } + + case IDM_PROPERTIES: + { + INT item = INVALID_INT; + + while ((item = (INT)SendDlgItemMessage (hwnd, IDC_RULE_APPS_ID, LVM_GETNEXTITEM, (WPARAM)item, LVNI_SELECTED)) != INVALID_INT) + { + size_t app_hash = _r_listview_getitemlparam (hwnd, IDC_RULE_APPS_ID, item); + INT app_listview_id = 0; + + if (_app_getappinfo (app_hash, InfoListviewId, &app_listview_id, sizeof (app_listview_id))) + { + _app_showitem (app.GetHWND (), app_listview_id, _app_getposition (app.GetHWND (), app_listview_id, app_hash)); + } + } + + break; + } + + case IDM_COPY: + { + HWND hlistview = GetFocus (); + + if (!hlistview) + break; + + INT listview_id = GetDlgCtrlID (hlistview); + + if (!listview_id || !_r_listview_getitemcount (hwnd, listview_id)) + break; + + INT item = INVALID_INT; + + rstring buffer; + + while ((item = (INT)SendDlgItemMessage (hwnd, listview_id, LVM_GETNEXTITEM, (WPARAM)item, LVNI_SELECTED)) != INVALID_INT) + { + buffer.AppendFormat (L"%s\r\n", _r_listview_getitemtext (hwnd, listview_id, item, 0).GetString ()); + } + + _r_str_trim (buffer, DIVIDER_TRIM); + + _r_clipboard_set (hwnd, buffer, buffer.GetLength ()); + + break; + } + } + + break; + } + } + + return FALSE; +} + +INT_PTR CALLBACK EditorProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) +{ + static PR_OBJECT ptr_rule_object = nullptr; + static PITEM_RULE ptr_rule = nullptr; + + switch (msg) + { + case WM_INITDIALOG: + { + ptr_rule_object = (PR_OBJECT)lparam; + + if (!ptr_rule_object) + { + EndDialog (hwnd, 0); + return FALSE; + } + + ptr_rule = (PITEM_RULE)ptr_rule_object->pdata; + + if (!ptr_rule) + { + EndDialog (hwnd, 0); + return FALSE; + } + + //// configure window + _r_wnd_center (hwnd, GetParent (hwnd)); + + //// configure tabs + _r_tab_additem (hwnd, IDC_TAB, 0, app.LocaleString (IDS_SETTINGS_GENERAL, nullptr), INVALID_INT, (LPARAM)CreateDialogParam (app.GetHINSTANCE (), MAKEINTRESOURCE (IDD_EDITOR_GENERAL), hwnd, &EditorPagesProc, (LPARAM)ptr_rule)); + _r_tab_additem (hwnd, IDC_TAB, 1, app.LocaleString (IDS_RULE, nullptr), INVALID_INT, (LPARAM)CreateDialogParam (app.GetHINSTANCE (), MAKEINTRESOURCE (IDD_EDITOR_RULE), hwnd, &EditorPagesProc, (LPARAM)ptr_rule)); + _r_tab_additem (hwnd, IDC_TAB, 2, app.LocaleString (IDS_TAB_APPS, nullptr), INVALID_INT, (LPARAM)CreateDialogParam (app.GetHINSTANCE (), MAKEINTRESOURCE (IDD_EDITOR_APPS), hwnd, &EditorPagesProc, (LPARAM)ptr_rule)); + +#if !defined(_APP_NO_DARKTHEME) + _r_wnd_setdarktheme (hwnd); +#endif // !_APP_NO_DARKTHEME + + // localize window + { + rstring title = app.LocaleString (IDS_EDITOR, nullptr); + + if (!_r_str_isempty (ptr_rule->pname)) + title.AppendFormat (L" \"%s\"", !_r_str_isempty (ptr_rule->pname) ? ptr_rule->pname : SZ_RULE_NEW_TITLE); + + if (ptr_rule->is_readonly) + title.AppendFormat (L" (%s)", SZ_RULE_INTERNAL_TITLE); + + SetWindowText (hwnd, title); + } + + SetDlgItemText (hwnd, IDC_ENABLE_CHK, app.LocaleString (IDS_ENABLE_CHK, nullptr)); + + SetDlgItemText (hwnd, IDC_SAVE, app.LocaleString (IDS_SAVE, nullptr)); + SetDlgItemText (hwnd, IDC_CLOSE, app.LocaleString (IDS_CLOSE, nullptr)); + + _r_wnd_addstyle (hwnd, IDC_SAVE, app.IsClassicUI () ? WS_EX_STATICEDGE : 0, WS_EX_STATICEDGE, GWL_EXSTYLE); + _r_wnd_addstyle (hwnd, IDC_CLOSE, app.IsClassicUI () ? WS_EX_STATICEDGE : 0, WS_EX_STATICEDGE, GWL_EXSTYLE); + + // state + CheckDlgButton (hwnd, IDC_ENABLE_CHK, ptr_rule->is_enabled ? BST_CHECKED : BST_UNCHECKED); + + _r_tab_selectitem (hwnd, IDC_TAB, 0); + + break; + } + + case WM_NCCREATE: + { + _r_wnd_enablenonclientscaling (hwnd); + break; + } + + case WM_CLOSE: + { + EndDialog (hwnd, 0); + break; + } + + case WM_SETTINGCHANGE: + { + _r_wnd_changesettings (hwnd, wparam, lparam); + break; + } + + case WM_NOTIFY: + { + LPNMHDR nmlp = (LPNMHDR)lparam; + + switch (nmlp->code) + { + case TCN_SELCHANGING: + { + const HWND hpage = (HWND)_r_tab_getlparam (hwnd, IDC_TAB, INVALID_INT); + + if (hpage) + ShowWindow (hpage, SW_HIDE); + + break; + } + + case TCN_SELCHANGE: + { + const HWND hpage = (HWND)_r_tab_getlparam (hwnd, IDC_TAB, INVALID_INT); + + if (hpage) + { + _r_tab_adjustchild (hwnd, IDC_TAB, hpage); + + ShowWindow (hpage, SW_SHOW); + } + + break; + } + } + + break; + } + + case WM_COMMAND: + { + const INT ctrl_id = LOWORD (wparam); + + switch (ctrl_id) + { + case IDOK: // process Enter key + case IDC_SAVE: + { + const HWND hpage_general = (HWND)_r_tab_getlparam (hwnd, IDC_TAB, 0); + const HWND hpage_rule = (HWND)_r_tab_getlparam (hwnd, IDC_TAB, 1); + const HWND hpage_apps = (HWND)_r_tab_getlparam (hwnd, IDC_TAB, 2); + + if (!SendDlgItemMessage (hpage_general, IDC_RULE_NAME_ID, WM_GETTEXTLENGTH, 0, 0)) + return FALSE; + + ptr_rule->is_haveerrors = false; // reset errors + + // do not change read-only rules + if (!ptr_rule->is_readonly) + { + // name + { + rstring name = _r_ctrl_gettext (hpage_general, IDC_RULE_NAME_ID); + + _r_str_trim (name, DIVIDER_TRIM DIVIDER_RULE); + _r_str_alloc (&ptr_rule->pname, min (name.GetLength (), RULE_NAME_CCH_MAX), name); + } + + // rule (remote) + { + rstring buffer; + + for (INT i = 0; i < _r_listview_getitemcount (hpage_rule, IDC_RULE_REMOTE_ID); i++) + { + rstring rule = _r_listview_getitemtext (hpage_rule, IDC_RULE_REMOTE_ID, i, 0); + _r_str_trim (rule, DIVIDER_TRIM DIVIDER_RULE); + + if (!rule.IsEmpty ()) + { + // check maximum length of one rule + if ((buffer.GetLength () + rule.GetLength ()) > RULE_RULE_CCH_MAX) + break; + + buffer.AppendFormat (L"%s" DIVIDER_RULE, rule.GetString ()); + } + } + + _r_str_trim (buffer, DIVIDER_TRIM DIVIDER_RULE); + _r_str_alloc (&ptr_rule->prule_remote, buffer.GetLength (), buffer); + } + + // rule (local) + { + rstring buffer; + + for (INT i = 0; i < _r_listview_getitemcount (hpage_rule, IDC_RULE_LOCAL_ID); i++) + { + rstring rule = _r_listview_getitemtext (hpage_rule, IDC_RULE_LOCAL_ID, i, 0); + _r_str_trim (rule, DIVIDER_TRIM DIVIDER_RULE); + + if (!rule.IsEmpty ()) + { + // check maximum length of one rule + if ((buffer.GetLength () + rule.GetLength ()) > RULE_RULE_CCH_MAX) + break; + + buffer.AppendFormat (L"%s" DIVIDER_RULE, rule.GetString ()); + } + } + + _r_str_trim (buffer, DIVIDER_TRIM DIVIDER_RULE); + _r_str_alloc (&ptr_rule->prule_local, buffer.GetLength (), buffer); + } + + ptr_rule->protocol = (UINT8)SendDlgItemMessage (hpage_general, IDC_RULE_PROTOCOL_ID, CB_GETITEMDATA, SendDlgItemMessage (hpage_general, IDC_RULE_PROTOCOL_ID, CB_GETCURSEL, 0, 0), 0); + + ptr_rule->direction = std::clamp ((FWP_DIRECTION)(_r_ctrl_isradiobuttonchecked (hpage_general, IDC_RULE_DIRECTION_OUTBOUND, IDC_RULE_DIRECTION_ANY) - IDC_RULE_DIRECTION_OUTBOUND), FWP_DIRECTION_OUTBOUND, FWP_DIRECTION_MAX); + ptr_rule->is_block = _r_ctrl_isradiobuttonchecked (hpage_general, IDC_RULE_ACTION_BLOCK, IDC_RULE_ACTION_ALLOW) == IDC_RULE_ACTION_BLOCK; + + if (ptr_rule->type == DataRuleCustom) + ptr_rule->weight = (ptr_rule->is_block ? FILTER_WEIGHT_CUSTOM_BLOCK : FILTER_WEIGHT_CUSTOM); + } + + // save rule apps + if (ptr_rule->type == DataRuleCustom) + { + ptr_rule->apps.clear (); + + for (INT i = 0; i < _r_listview_getitemcount (hpage_apps, IDC_RULE_APPS_ID); i++) + { + const size_t app_hash = _r_listview_getitemlparam (hpage_apps, IDC_RULE_APPS_ID, i); + + if (_app_isappfound (app_hash)) + { + if (_r_listview_isitemchecked (hpage_apps, IDC_RULE_APPS_ID, i)) + ptr_rule->apps[app_hash] = true; + } + } + } + + // enable rule + _app_ruleenable (ptr_rule, (IsDlgButtonChecked (hwnd, IDC_ENABLE_CHK) == BST_CHECKED)); + + // apply filter + { + OBJECTS_VEC rules; + rules.push_back (ptr_rule_object); + + _wfp_create4filters (_wfp_getenginehandle (), rules, __LINE__); + + // note: do not needed! + //_app_dereferenceobjects (rules, &_app_dereferencerule); + } + + EndDialog (hwnd, TRUE); + + break; + } + + case IDCANCEL: // process Esc key + case IDC_CLOSE: + { + EndDialog (hwnd, 0); + break; + } + } + + break; + } + } + + return FALSE; +} diff --git a/src/editor.hpp b/src/editor.hpp new file mode 100644 index 00000000..01bff497 --- /dev/null +++ b/src/editor.hpp @@ -0,0 +1,9 @@ +// simplewall +// Copyright (c) 2016-2020 Henry++ + +#pragma once + +INT_PTR CALLBACK AddRuleProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); + +INT_PTR CALLBACK EditorPagesProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); +INT_PTR CALLBACK EditorProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);