From 3d88a792fb2f3950989d95d91e7de57fa1b74923 Mon Sep 17 00:00:00 2001 From: ghazan Date: Sun, 7 Nov 2021 16:48:40 +0300 Subject: first version of mir_core that builds under Linux --- .gitignore | 1 + codeblocks/Miranda.workspace | 6 + codeblocks/Miranda.workspace.layout | 6 + include/m_clc.h | 562 ++-- include/m_core.h | 1260 ++++---- include/m_database.h | 1586 +++++----- include/m_db_int.h | 810 ++--- include/m_gui.h | 3169 ++++++++++---------- include/m_netlib.h | 1730 +++++------ include/m_protoint.h | 620 ++-- include/m_string.h | 1998 ++++++------ include/m_string.inl | 2932 +++++++++--------- include/m_system.h | 1306 ++++---- include/m_timezones.h | 273 +- include/m_types.h | 170 +- include/m_xml.h | 389 ++- include/newpluginapi.h | 1015 +++---- libs/Pcre16/pcre16.cbp | 11 + libs/Pcre16/pcre16.layout | 5 + libs/freeimage/freeimage.cbp | 11 + libs/freeimage/freeimage.layout | 5 + libs/libjson/libjson.cbp | 11 + libs/libjson/libjson.layout | 5 + libs/libsignal/libsignal.cbp | 11 + libs/libsignal/libsignal.layout | 5 + libs/sqlite3/sqlite3.cbp | 11 + libs/sqlite3/sqlite3.layout | 5 + libs/zlib/zlib.cbp | 11 + libs/zlib/zlib.layout | 5 + plugins/AVS/avs.cbp | 11 + plugins/AVS/avs.layout | 5 + plugins/Clist_modern/clist_modern.cbp | 11 + plugins/Clist_modern/clist_modern.layout | 5 + plugins/Clist_modern/icons_pack/Toolbar_icons.cbp | 11 + .../Clist_modern/icons_pack/Toolbar_icons.layout | 5 + plugins/Cln_skinedit/skinedit.cbp | 11 + plugins/Cln_skinedit/skinedit.layout | 5 + plugins/DbChecker/dbchecker.cbp | 11 + plugins/DbChecker/dbchecker.layout | 5 + plugins/Dbx_sqlite/dbx_sqlite.cbp | 11 + plugins/Dbx_sqlite/dbx_sqlite.layout | 5 + plugins/Import/import.cbp | 11 + plugins/Import/import.layout | 5 + plugins/PluginUpdater/PluginUpdater.cbp | 11 + plugins/PluginUpdater/PluginUpdater.layout | 5 + .../TabSRMM/TabSRMM_icons/NOVA/ICONS_NOVA_16.cbp | 138 + .../TabSRMM_icons/NOVA/ICONS_NOVA_16.layout | 5 + plugins/TabSRMM/tabsrmm.cbp | 11 + plugins/TabSRMM/tabsrmm.layout | 5 + plugins/TopToolBar/TopToolBar.cbp | 11 + plugins/TopToolBar/TopToolBar.layout | 5 + protocols/Facebook/facebook.cbp | 11 + protocols/Facebook/facebook.layout | 5 + .../Facebook/proto_facebook/Proto_Facebook.cbp | 11 + .../Facebook/proto_facebook/Proto_Facebook.layout | 5 + protocols/Gadu-Gadu/gadugadu.cbp | 11 + protocols/Gadu-Gadu/gadugadu.layout | 5 + protocols/Gadu-Gadu/proto_gg/Proto_GG.cbp | 11 + protocols/Gadu-Gadu/proto_gg/Proto_GG.layout | 5 + protocols/ICQ-WIM/ICQ-WIM.cbp | 11 + protocols/ICQ-WIM/ICQ-WIM.layout | 5 + protocols/ICQ-WIM/proto_icq/Proto_ICQ.cbp | 11 + protocols/ICQ-WIM/proto_icq/Proto_ICQ.layout | 5 + protocols/IRCG/IRC.cbp | 11 + protocols/IRCG/IRC.layout | 5 + protocols/IRCG/proto_irc/Proto_IRC.cbp | 11 + protocols/IRCG/proto_irc/Proto_IRC.layout | 5 + protocols/JabberG/jabber.cbp | 11 + protocols/JabberG/jabber.layout | 5 + .../JabberG/jabber_xstatus/xStatus_Jabber.cbp | 11 + .../JabberG/jabber_xstatus/xStatus_Jabber.layout | 5 + protocols/JabberG/proto_jabber/Proto_Jabber.cbp | 11 + protocols/JabberG/proto_jabber/Proto_Jabber.layout | 5 + src/core/stdautoaway/stdautoaway.cbp | 11 + src/core/stdautoaway/stdautoaway.layout | 5 + src/core/stdaway/stdaway.cbp | 11 + src/core/stdaway/stdaway.layout | 5 + src/core/stdclist/stdclist.cbp | 11 + src/core/stdclist/stdclist.layout | 5 + src/core/stdcrypt/stdcrypt.cbp | 11 + src/core/stdcrypt/stdcrypt.layout | 5 + src/core/stdemail/stdemail.cbp | 11 + src/core/stdemail/stdemail.layout | 5 + src/core/stdfile/stdfile.cbp | 11 + src/core/stdfile/stdfile.layout | 5 + src/core/stdmsg/stdmsg.cbp | 11 + src/core/stdmsg/stdmsg.layout | 5 + src/core/stdpopup/stdpopup.cbp | 11 + src/core/stdpopup/stdpopup.layout | 5 + src/core/stduihist/stduihist.cbp | 11 + src/core/stduihist/stduihist.layout | 5 + src/core/stduserinfo/stduserinfo.cbp | 11 + src/core/stduserinfo/stduserinfo.layout | 5 + src/core/stduseronline/stduseronline.cbp | 11 + src/core/stduseronline/stduseronline.layout | 5 + .../proto_metacontacts/Proto_MetaContacts.cbp | 11 + .../proto_metacontacts/Proto_MetaContacts.layout | 5 + src/mir_app/mir_app.cbp | 11 + src/mir_app/mir_app.layout | 5 + src/mir_core/main.cpp | 1 + src/mir_core/mir_core.cbp | 75 + src/mir_core/mir_core.depend | 231 ++ src/mir_core/mir_core.layout | 10 + src/mir_core/src/Linux/fileutil.cpp | 23 + src/mir_core/src/db.cpp | 1071 +++---- src/mir_core/src/logger.cpp | 424 ++- src/mir_core/src/md5.cpp | 716 ++--- src/mir_core/src/memory.cpp | 580 ++-- src/mir_core/src/miranda.h | 186 +- src/mir_core/src/mstring.cpp | 282 +- src/mir_core/src/sha256.cpp | 578 ++-- src/mir_core/src/stdafx.h | 152 +- src/mir_core/src/utf.cpp | 878 +++--- src/mir_core/src/utils.cpp | 1126 +++---- src/miranda32/miranda32.cbp | 11 + src/miranda32/miranda32.layout | 5 + 116 files changed, 13172 insertions(+), 11793 deletions(-) create mode 100644 codeblocks/Miranda.workspace create mode 100644 codeblocks/Miranda.workspace.layout create mode 100644 libs/Pcre16/pcre16.cbp create mode 100644 libs/Pcre16/pcre16.layout create mode 100644 libs/freeimage/freeimage.cbp create mode 100644 libs/freeimage/freeimage.layout create mode 100644 libs/libjson/libjson.cbp create mode 100644 libs/libjson/libjson.layout create mode 100644 libs/libsignal/libsignal.cbp create mode 100644 libs/libsignal/libsignal.layout create mode 100644 libs/sqlite3/sqlite3.cbp create mode 100644 libs/sqlite3/sqlite3.layout create mode 100644 libs/zlib/zlib.cbp create mode 100644 libs/zlib/zlib.layout create mode 100644 plugins/AVS/avs.cbp create mode 100644 plugins/AVS/avs.layout create mode 100644 plugins/Clist_modern/clist_modern.cbp create mode 100644 plugins/Clist_modern/clist_modern.layout create mode 100644 plugins/Clist_modern/icons_pack/Toolbar_icons.cbp create mode 100644 plugins/Clist_modern/icons_pack/Toolbar_icons.layout create mode 100644 plugins/Cln_skinedit/skinedit.cbp create mode 100644 plugins/Cln_skinedit/skinedit.layout create mode 100644 plugins/DbChecker/dbchecker.cbp create mode 100644 plugins/DbChecker/dbchecker.layout create mode 100644 plugins/Dbx_sqlite/dbx_sqlite.cbp create mode 100644 plugins/Dbx_sqlite/dbx_sqlite.layout create mode 100644 plugins/Import/import.cbp create mode 100644 plugins/Import/import.layout create mode 100644 plugins/PluginUpdater/PluginUpdater.cbp create mode 100644 plugins/PluginUpdater/PluginUpdater.layout create mode 100644 plugins/TabSRMM/TabSRMM_icons/NOVA/ICONS_NOVA_16.cbp create mode 100644 plugins/TabSRMM/TabSRMM_icons/NOVA/ICONS_NOVA_16.layout create mode 100644 plugins/TabSRMM/tabsrmm.cbp create mode 100644 plugins/TabSRMM/tabsrmm.layout create mode 100644 plugins/TopToolBar/TopToolBar.cbp create mode 100644 plugins/TopToolBar/TopToolBar.layout create mode 100644 protocols/Facebook/facebook.cbp create mode 100644 protocols/Facebook/facebook.layout create mode 100644 protocols/Facebook/proto_facebook/Proto_Facebook.cbp create mode 100644 protocols/Facebook/proto_facebook/Proto_Facebook.layout create mode 100644 protocols/Gadu-Gadu/gadugadu.cbp create mode 100644 protocols/Gadu-Gadu/gadugadu.layout create mode 100644 protocols/Gadu-Gadu/proto_gg/Proto_GG.cbp create mode 100644 protocols/Gadu-Gadu/proto_gg/Proto_GG.layout create mode 100644 protocols/ICQ-WIM/ICQ-WIM.cbp create mode 100644 protocols/ICQ-WIM/ICQ-WIM.layout create mode 100644 protocols/ICQ-WIM/proto_icq/Proto_ICQ.cbp create mode 100644 protocols/ICQ-WIM/proto_icq/Proto_ICQ.layout create mode 100644 protocols/IRCG/IRC.cbp create mode 100644 protocols/IRCG/IRC.layout create mode 100644 protocols/IRCG/proto_irc/Proto_IRC.cbp create mode 100644 protocols/IRCG/proto_irc/Proto_IRC.layout create mode 100644 protocols/JabberG/jabber.cbp create mode 100644 protocols/JabberG/jabber.layout create mode 100644 protocols/JabberG/jabber_xstatus/xStatus_Jabber.cbp create mode 100644 protocols/JabberG/jabber_xstatus/xStatus_Jabber.layout create mode 100644 protocols/JabberG/proto_jabber/Proto_Jabber.cbp create mode 100644 protocols/JabberG/proto_jabber/Proto_Jabber.layout create mode 100644 src/core/stdautoaway/stdautoaway.cbp create mode 100644 src/core/stdautoaway/stdautoaway.layout create mode 100644 src/core/stdaway/stdaway.cbp create mode 100644 src/core/stdaway/stdaway.layout create mode 100644 src/core/stdclist/stdclist.cbp create mode 100644 src/core/stdclist/stdclist.layout create mode 100644 src/core/stdcrypt/stdcrypt.cbp create mode 100644 src/core/stdcrypt/stdcrypt.layout create mode 100644 src/core/stdemail/stdemail.cbp create mode 100644 src/core/stdemail/stdemail.layout create mode 100644 src/core/stdfile/stdfile.cbp create mode 100644 src/core/stdfile/stdfile.layout create mode 100644 src/core/stdmsg/stdmsg.cbp create mode 100644 src/core/stdmsg/stdmsg.layout create mode 100644 src/core/stdpopup/stdpopup.cbp create mode 100644 src/core/stdpopup/stdpopup.layout create mode 100644 src/core/stduihist/stduihist.cbp create mode 100644 src/core/stduihist/stduihist.layout create mode 100644 src/core/stduserinfo/stduserinfo.cbp create mode 100644 src/core/stduserinfo/stduserinfo.layout create mode 100644 src/core/stduseronline/stduseronline.cbp create mode 100644 src/core/stduseronline/stduseronline.layout create mode 100644 src/icons/proto_metacontacts/Proto_MetaContacts.cbp create mode 100644 src/icons/proto_metacontacts/Proto_MetaContacts.layout create mode 100644 src/mir_app/mir_app.cbp create mode 100644 src/mir_app/mir_app.layout create mode 100644 src/mir_core/main.cpp create mode 100644 src/mir_core/mir_core.cbp create mode 100644 src/mir_core/mir_core.depend create mode 100644 src/mir_core/mir_core.layout create mode 100644 src/mir_core/src/Linux/fileutil.cpp create mode 100644 src/miranda32/miranda32.cbp create mode 100644 src/miranda32/miranda32.layout diff --git a/.gitignore b/.gitignore index 9e5fe41ad1..c723e4e5e4 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,4 @@ vsbuild.cmd #Langpacks Tools Template langpacks/tool/VersionInfo.txt +/.project diff --git a/codeblocks/Miranda.workspace b/codeblocks/Miranda.workspace new file mode 100644 index 0000000000..0cbe23aca2 --- /dev/null +++ b/codeblocks/Miranda.workspace @@ -0,0 +1,6 @@ + + + + + + diff --git a/codeblocks/Miranda.workspace.layout b/codeblocks/Miranda.workspace.layout new file mode 100644 index 0000000000..b94ee8d407 --- /dev/null +++ b/codeblocks/Miranda.workspace.layout @@ -0,0 +1,6 @@ + + + + + + diff --git a/include/m_clc.h b/include/m_clc.h index c087d085a6..dd4e697d70 100644 --- a/include/m_clc.h +++ b/include/m_clc.h @@ -1,280 +1,282 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) -Copyright (c) 2000-08 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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_CLC_H__ -#define M_CLC_H__ 1 - -#define CLISTCONTROL_CLASS "CListControl" -#define CLISTCONTROL_CLASSW L"CListControl" - -//styles -#define CLS_MANUALUPDATE 0x0001 //todo -#define CLS_SHOWHIDDEN 0x0002 -#define CLS_HIDEOFFLINE 0x0004 //hides all offline users -#define CLS_CHECKBOXES 0x0008 -#define CLS_MULTICOLUMN 0x0010 //not true multi-column, just for ignore/vis options -#define CLS_HIDEEMPTYGROUPS 0x0020 //note: this flag will be spontaneously removed if the 'new subgroup' menu item is clicked, for obvious reasons -#define CLS_USEGROUPS 0x0040 -#define CLS_NOHIDEOFFLINE 0x0080 //overrides CLS_HIDEOFFLINE and the per-group hideoffline setting -#define CLS_GREYALTERNATE 0x0100 //make every other line slightly grey -#define CLS_GROUPCHECKBOXES 0x0200 //put checkboxes on groups too (managed by CLC) -#define CLS_CONTACTLIST 0x0400 //this control will be the main contact list (v. 0.3.4.3+ 2004/11/02) - -#define CLS_EX_DISABLEDRAGDROP 0x00000001 -#define CLS_EX_EDITLABELS 0x00000002 -#define CLS_EX_SHOWSELALWAYS 0x00000004 -#define CLS_EX_TRACKSELECT 0x00000008 -#define CLS_EX_SHOWGROUPCOUNTS 0x00000010 -#define CLS_EX_DIVIDERONOFF 0x00000020 -#define CLS_EX_HIDECOUNTSWHENEMPTY 0x00000040 -#define CLS_EX_NOTRANSLUCENTSEL 0x00000080 -#define CLS_EX_LINEWITHGROUPS 0x00000100 -#define CLS_EX_QUICKSEARCHVISONLY 0x00000200 -#define CLS_EX_SORTGROUPSALPHA 0x00000400 -#define CLS_EX_NOSMOOTHSCROLLING 0x00000800 - -#define CLM_FIRST 0x1000 //this is the same as LVM_FIRST -#define CLM_LAST 0x1100 - -//messages, compare with equivalent TVM_s in the MSDN -#define CLM_ADDCONTACT (CLM_FIRST+0) //wParam = hContact -#define CLM_ADDGROUP (CLM_FIRST+1) //wParam = hGroup -#define CLM_AUTOREBUILD (CLM_FIRST+2) -#define CLM_DELETEITEM (CLM_FIRST+3) //wParam = hItem -#define CLM_EDITLABEL (CLM_FIRST+4) //wParam = hItem -#define CLM_ENDEDITLABELNOW (CLM_FIRST+5) //wParam = cancel, 0 to save -#define CLM_ENSUREVISIBLE (CLM_FIRST+6) //wParam = hItem, lParam = partialOk -#define CLE_TOGGLE -1 -#define CLE_COLLAPSE 0 -#define CLE_EXPAND 1 -#define CLE_INVALID 0xFFFF -#define CLM_EXPAND (CLM_FIRST+7) //wParam = hItem, lParam = CLE_ -#define CLM_FINDCONTACT (CLM_FIRST+8) //wParam = hContact, returns an hItem -#define CLM_FINDGROUP (CLM_FIRST+9) //wParam = hGroup, returns an hItem -#define CLM_GETBKCOLOR (CLM_FIRST+10) //returns a COLORREF -#define CLM_GETCHECKMARK (CLM_FIRST+11) //wParam = hItem, returns 1 or 0 -#define CLM_GETCOUNT (CLM_FIRST+12) //returns the total number of items -#define CLM_GETEDITCONTROL (CLM_FIRST+13) //returns the HWND, or NULL -#define CLM_GETEXPAND (CLM_FIRST+14) //wParam = hItem, returns a CLE_, CLE_INVALID if not a group -#define CLM_GETEXTRACOLUMNS (CLM_FIRST+15) //returns number of extra columns -#define CLM_GETEXTRAIMAGE (CLM_FIRST+16) //wParam = hItem, lParam = MAKELPARAM(iColumn (0 based),0), returns iImage or EMPTY_EXTRA_ICON -#define CLM_GETEXTRAIMAGELIST (CLM_FIRST+17) //returns HIMAGELIST -#define CLM_GETFONT (CLM_FIRST+18) //wParam = fontId, see clm_setfont. returns hFont. -#define CLM_GETINDENT (CLM_FIRST+19) //wParam = new group indent -#define CLM_GETISEARCHSTRING (CLM_FIRST+20) //lParam = (char*)pszStr, max 120 bytes, returns number of chars in string -#define CLM_GETITEMTEXT (CLM_FIRST+21) //wParam = hItem, lParam = (wchar_t*)pszStr, max 120 bytes -#define CLM_GETSCROLLTIME (CLM_FIRST+22) //returns time in ms -#define CLM_GETSELECTION (CLM_FIRST+23) //returns hItem -#define CLM_SETEXTRASPACE (CLM_FIRST+24) //wParam=extra space between icons - -#define CLCHT_ABOVE 0x0001 //above client area -#define CLCHT_BELOW 0x0002 //below client area -#define CLCHT_TOLEFT 0x0004 //left of client area -#define CLCHT_TORIGHT 0x0008 //right of client area -#define CLCHT_NOWHERE 0x0010 //in client area, not on an item -#define CLCHT_ONITEMICON 0x0020 -#define CLCHT_ONITEMCHECK 0x0040 -#define CLCHT_ONITEMLABEL 0x0080 -#define CLCHT_ONITEMINDENT 0x0100 //to the left of an item icon -#define CLCHT_ONITEMEXTRA 0x0200 //on an extra icon, HIBYTE(HIWORD()) says which -#define CLCHT_ONITEM 0x03E0 -#define CLCHT_INLEFTMARGIN 0x0400 -#define CLCHT_BELOWITEMS 0x0800 //in client area but below last item -#define CLM_HITTEST (CLM_FIRST+25) //lParam = MAKELPARAM(x,y) (relative to control), wParam = (PDWORD)&hitTest (see encoding of HitTest() in clc.h, can be NULL) returns hItem or NULL -#define CLM_SELECTITEM (CLM_FIRST+26) //wParam = hItem -#define CLB_TOPLEFT 0 -#define CLB_STRETCHV 1 -#define CLB_STRETCHH 2 //and tile vertically -#define CLB_STRETCH 3 -#define CLBM_TYPE 0x00FF -#define CLBF_TILEH 0x1000 -#define CLBF_TILEV 0x2000 -#define CLBF_PROPORTIONAL 0x4000 -#define CLBF_SCROLL 0x8000 - -#define CLM_SETBKCOLOR (CLM_FIRST+28) //wParam = a COLORREF, default is GetSysColor(COLOR_3DFACE) -#define CLM_SETCHECKMARK (CLM_FIRST+29) //wParam = hItem, lParam = 1 or 0 -#define CLM_SETEXTRACOLUMNS (CLM_FIRST+30) //wParam = number of extra columns (zero to EXTRA_ICON_COUNT from clc.h, currently 16) -#define CLM_SETEXTRAIMAGE (CLM_FIRST+31) //wParam = hItem, lParam = MAKELPARAM(iColumn (0 based),iImage). iImage = EMPTY_EXTRA_ICON is a blank -#define CLM_SETEXTRAIMAGELIST (CLM_FIRST+32) //lParam = HIMAGELIST - -#define FONTID_CONTACTS 0 -#define FONTID_INVIS 1 -#define FONTID_OFFLINE 2 -#define FONTID_NOTONLIST 3 -#define FONTID_GROUPS 4 -#define FONTID_GROUPCOUNTS 5 -#define FONTID_DIVIDERS 6 -#define FONTID_OFFINVIS 7 -#define FONTID_STATUSMSG 8 -#define FONTID_GROUPSCLOSED 9 -#define FONTID_CONTACTSHOVER 10 -#define FONTID_MAX 18 - -#define CLM_SETFONT (CLM_FIRST+33) //wParam = hFont, lParam = MAKELPARAM(fRedraw,fontId) -#define CLM_SETITEMTEXT (CLM_FIRST+35) //wParam = hItem, lParam = (char*)pszNewText -#define CLM_SETSCROLLTIME (CLM_FIRST+36) //wParam = time in ms, default 200 - -#define CLM_SETHIDEEMPTYGROUPS (CLM_FIRST+38) //wParam = TRUE/FALSE -#define GREYF_UNFOCUS 0x80000000 -#define MODEF_OFFLINE 0x40000000 -//and use the PF2_ #defines from m_protosvc.h - -#define CLM_GETHIDEOFFLINEROOT (CLM_FIRST+40) //returns TRUE/FALSE -#define CLM_SETHIDEOFFLINEROOT (CLM_FIRST+41) //wParam = TRUE/FALSE -#define CLM_SETUSEGROUPS (CLM_FIRST+42) //wParam = TRUE/FALSE -#define CLM_SETOFFLINEMODES (CLM_FIRST+43) //for 'hide offline', wParam = PF2_ flags and MODEF_OFFLINE -#define CLM_GETEXSTYLE (CLM_FIRST+44) //returns CLS_EX_ flags -#define CLM_SETEXSTYLE (CLM_FIRST+45) //wParam = CLS_EX_ flags - -typedef struct { - int cbSize; - const wchar_t *pszText; - HANDLE hParentGroup; - DWORD flags; - HICON hIcon; //todo -} CLCINFOITEM; -#define CLCIIF_BELOWGROUPS 1 //put it between groups and contacts, default is at top -#define CLCIIF_BELOWCONTACTS 2 //put it at the bottom -#define CLCIIF_CHECKBOX 0x40 //give this item a check box -#define CLCIIF_GROUPFONT 0x80 //draw the item using FONTID_GROUPS - -#define CLM_ADDINFOITEMA (CLM_FIRST+48) //lParam = &cii, returns hItem -#define CLM_ADDINFOITEMW (CLM_FIRST+53) //lParam = &cii, returns hItem -#if defined(_UNICODE) - #define CLM_ADDINFOITEM CLM_ADDINFOITEMW -#else - #define CLM_ADDINFOITEM CLM_ADDINFOITEMA -#endif - - //the order of info items is never changed, so make sure you add them in the - // order you want them to remain -#define CLCIT_INVALID -1 -#define CLCIT_GROUP 0 -#define CLCIT_CONTACT 1 -#define CLCIT_DIVIDER 2 -#define CLCIT_INFO 3 -#define CLM_GETITEMTYPE (CLM_FIRST+49) //wParam = hItem, returns a CLCIT_ -#define CLGN_ROOT 0 -#define CLGN_CHILD 1 -#define CLGN_PARENT 2 -#define CLGN_NEXT 3 -#define CLGN_PREVIOUS 4 -#define CLGN_NEXTCONTACT 5 -#define CLGN_PREVIOUSCONTACT 6 -#define CLGN_NEXTGROUP 7 -#define CLGN_PREVIOUSGROUP 8 - -#define CLM_GETNEXTITEM (CLM_FIRST+50) //wParam = flag, lParam = hItem, returns an hItem -#define CLM_GETTEXTCOLOR (CLM_FIRST+51) //wParam = FONTID_, returns COLORREF -#define CLM_SETTEXTCOLOR (CLM_FIRST+52) //wParam = FONTID_, lParam = COLORREF - -//notifications (most are omitted because the control processes everything) -#define CLNF_ISGROUP 1 -#define CLNF_ISINFO 2 -typedef struct { - NMHDR hdr; - HANDLE hItem; - int action; - int iColumn; //-1 if not on an extra column - DWORD flags; - POINT pt; -} NMCLISTCONTROL; -#define CLN_FIRST (0U-100U) -#define CLN_EXPANDED (CLN_FIRST-0) //hItem = hGroup, action = CLE_* -#define CLN_LISTREBUILT (CLN_FIRST-1) -#define CLN_ITEMCHECKED (CLN_FIRST-2) //todo //hItem, action, flags valid -#define CLN_DRAGGING (CLN_FIRST-3) //hItem, pt, flags valid. only sent when cursor outside window, return nonzero if processed -#define CLN_DROPPED (CLN_FIRST-4) //hItem, pt, flags valid. only sent when cursor outside window, return nonzero if processed -#define CLN_LISTSIZECHANGE (CLN_FIRST-5) //pt.y valid. the vertical height of the visible items in the list has changed. -#define CLN_OPTIONSCHANGED (CLN_FIRST-6) //nothing valid. If you set some extended options they have been overwritten and should be re-set -#define CLN_DRAGSTOP (CLN_FIRST-7) //hItem, flags valid. sent when cursor goes back in to the window having been outside, return nonzero if processed -#define CLN_NEWCONTACT (CLN_FIRST-8) //hItem, flags valid. sent when a new contact is added without a full list rebuild -#define CLN_CONTACTMOVED (CLN_FIRST-9) //hItem, flags valid. sent when contact is moved without a full list rebuild -#define CLN_CHECKCHANGED (CLN_FIRST-10) //hItem, flags valid. sent when any check mark is changed, but only for one change if there are many -//NM_CLICK //hItem, iColumn, pt, flags valid -//NM_KEYDOWN //NMKEY structure, only sent when key is not already processed, return nonzero to prevent further processing - -// clist window tree messages -#define M_CREATECLC (WM_USER+1) -#define M_SETALLEXTRAICONS (WM_USER+2) - -//an infotip for an item should be shown now -//wParam = 0 -//lParam = (LPARAM)(CLCINFOTIP*)&it -//Return nonzero if you process this, because it makes no sense for more than -//one plugin to grab it. -//It is up to the plugin to decide the best place to put the infotip. Normally -//it's a few pixels below and to the right of the cursor -//This event is called after the mouse has been stationary over a contact for -//(by default) 200ms, but see below. -//Everything is in screen coordinates. -typedef struct { - int cbSize; - int isTreeFocused; //so the plugin can provide an option - int isGroup; //0 if it's a contact, 1 if it's a group - HANDLE hItem; //handle to group or contact - POINT ptCursor; - RECT rcItem; -} CLCINFOTIP; -#define ME_CLC_SHOWINFOTIP "CLC/ShowInfoTip" - -typedef struct { - int cbSize; - int isTreeFocused; //so the plugin can provide an option - HANDLE hItem; //handle to group or contact - POINT ptCursor; - RECT rcItem; - int extraIndex; - HWND hwnd; -} CLCEXTRAINFOTIP; -#define ME_CLC_SHOWEXTRAINFOTIP "CLC/ShowExtraInfoTip" - -//it's time to destroy an infotip -//wParam = 0 -//lParam = (LPARAM)(CLCINFOTIP*)&it -//Only cbSize, isGroup and hItem are set -//Return nonzero if you process this. -//This is sent when the mouse moves off a contact when clc/showinfotip has -//previously been called. -//If you don't want this behaviour, you should have grabbed the mouse capture -//yourself and made your own arrangements. -#define ME_CLC_HIDEINFOTIP "CLC/HideInfoTip" - -//set the hover time before the infotip hooks are called -//wParam = newTime -//lParam = 0 -//Returns 0 on success or nonzero on failure -//The value of this setting is applied to all current CLC windows, and saved -//to be applied to all future windows, including after restarts. -//newTime is in ms. -//The default is 750ms. -#define MS_CLC_SETINFOTIPHOVERTIME "CLC/SetInfoTipHoverTime" - -//get the hover time before the infotip hooks are called -//wParam = lParam = 0 -//Returns the time in ms -#define MS_CLC_GETINFOTIPHOVERTIME "CLC/GetInfoTipHoverTime" - -#endif // M_CLC_H__ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2000-08 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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_CLC_H__ +#define M_CLC_H__ 1 + +#define CLISTCONTROL_CLASS "CListControl" +#define CLISTCONTROL_CLASSW L"CListControl" + +//styles +#define CLS_MANUALUPDATE 0x0001 //todo +#define CLS_SHOWHIDDEN 0x0002 +#define CLS_HIDEOFFLINE 0x0004 //hides all offline users +#define CLS_CHECKBOXES 0x0008 +#define CLS_MULTICOLUMN 0x0010 //not true multi-column, just for ignore/vis options +#define CLS_HIDEEMPTYGROUPS 0x0020 //note: this flag will be spontaneously removed if the 'new subgroup' menu item is clicked, for obvious reasons +#define CLS_USEGROUPS 0x0040 +#define CLS_NOHIDEOFFLINE 0x0080 //overrides CLS_HIDEOFFLINE and the per-group hideoffline setting +#define CLS_GREYALTERNATE 0x0100 //make every other line slightly grey +#define CLS_GROUPCHECKBOXES 0x0200 //put checkboxes on groups too (managed by CLC) +#define CLS_CONTACTLIST 0x0400 //this control will be the main contact list (v. 0.3.4.3+ 2004/11/02) + +#define CLS_EX_DISABLEDRAGDROP 0x00000001 +#define CLS_EX_EDITLABELS 0x00000002 +#define CLS_EX_SHOWSELALWAYS 0x00000004 +#define CLS_EX_TRACKSELECT 0x00000008 +#define CLS_EX_SHOWGROUPCOUNTS 0x00000010 +#define CLS_EX_DIVIDERONOFF 0x00000020 +#define CLS_EX_HIDECOUNTSWHENEMPTY 0x00000040 +#define CLS_EX_NOTRANSLUCENTSEL 0x00000080 +#define CLS_EX_LINEWITHGROUPS 0x00000100 +#define CLS_EX_QUICKSEARCHVISONLY 0x00000200 +#define CLS_EX_SORTGROUPSALPHA 0x00000400 +#define CLS_EX_NOSMOOTHSCROLLING 0x00000800 + +#define CLM_FIRST 0x1000 //this is the same as LVM_FIRST +#define CLM_LAST 0x1100 + +//messages, compare with equivalent TVM_s in the MSDN +#define CLM_ADDCONTACT (CLM_FIRST+0) //wParam = hContact +#define CLM_ADDGROUP (CLM_FIRST+1) //wParam = hGroup +#define CLM_AUTOREBUILD (CLM_FIRST+2) +#define CLM_DELETEITEM (CLM_FIRST+3) //wParam = hItem +#define CLM_EDITLABEL (CLM_FIRST+4) //wParam = hItem +#define CLM_ENDEDITLABELNOW (CLM_FIRST+5) //wParam = cancel, 0 to save +#define CLM_ENSUREVISIBLE (CLM_FIRST+6) //wParam = hItem, lParam = partialOk +#define CLE_TOGGLE -1 +#define CLE_COLLAPSE 0 +#define CLE_EXPAND 1 +#define CLE_INVALID 0xFFFF +#define CLM_EXPAND (CLM_FIRST+7) //wParam = hItem, lParam = CLE_ +#define CLM_FINDCONTACT (CLM_FIRST+8) //wParam = hContact, returns an hItem +#define CLM_FINDGROUP (CLM_FIRST+9) //wParam = hGroup, returns an hItem +#define CLM_GETBKCOLOR (CLM_FIRST+10) //returns a COLORREF +#define CLM_GETCHECKMARK (CLM_FIRST+11) //wParam = hItem, returns 1 or 0 +#define CLM_GETCOUNT (CLM_FIRST+12) //returns the total number of items +#define CLM_GETEDITCONTROL (CLM_FIRST+13) //returns the HWND, or NULL +#define CLM_GETEXPAND (CLM_FIRST+14) //wParam = hItem, returns a CLE_, CLE_INVALID if not a group +#define CLM_GETEXTRACOLUMNS (CLM_FIRST+15) //returns number of extra columns +#define CLM_GETEXTRAIMAGE (CLM_FIRST+16) //wParam = hItem, lParam = MAKELPARAM(iColumn (0 based),0), returns iImage or EMPTY_EXTRA_ICON +#define CLM_GETEXTRAIMAGELIST (CLM_FIRST+17) //returns HIMAGELIST +#define CLM_GETFONT (CLM_FIRST+18) //wParam = fontId, see clm_setfont. returns hFont. +#define CLM_GETINDENT (CLM_FIRST+19) //wParam = new group indent +#define CLM_GETISEARCHSTRING (CLM_FIRST+20) //lParam = (char*)pszStr, max 120 bytes, returns number of chars in string +#define CLM_GETITEMTEXT (CLM_FIRST+21) //wParam = hItem, lParam = (wchar_t*)pszStr, max 120 bytes +#define CLM_GETSCROLLTIME (CLM_FIRST+22) //returns time in ms +#define CLM_GETSELECTION (CLM_FIRST+23) //returns hItem +#define CLM_SETEXTRASPACE (CLM_FIRST+24) //wParam=extra space between icons + +#define CLCHT_ABOVE 0x0001 //above client area +#define CLCHT_BELOW 0x0002 //below client area +#define CLCHT_TOLEFT 0x0004 //left of client area +#define CLCHT_TORIGHT 0x0008 //right of client area +#define CLCHT_NOWHERE 0x0010 //in client area, not on an item +#define CLCHT_ONITEMICON 0x0020 +#define CLCHT_ONITEMCHECK 0x0040 +#define CLCHT_ONITEMLABEL 0x0080 +#define CLCHT_ONITEMINDENT 0x0100 //to the left of an item icon +#define CLCHT_ONITEMEXTRA 0x0200 //on an extra icon, HIBYTE(HIWORD()) says which +#define CLCHT_ONITEM 0x03E0 +#define CLCHT_INLEFTMARGIN 0x0400 +#define CLCHT_BELOWITEMS 0x0800 //in client area but below last item +#define CLM_HITTEST (CLM_FIRST+25) //lParam = MAKELPARAM(x,y) (relative to control), wParam = (PDWORD)&hitTest (see encoding of HitTest() in clc.h, can be NULL) returns hItem or NULL +#define CLM_SELECTITEM (CLM_FIRST+26) //wParam = hItem +#define CLB_TOPLEFT 0 +#define CLB_STRETCHV 1 +#define CLB_STRETCHH 2 //and tile vertically +#define CLB_STRETCH 3 +#define CLBM_TYPE 0x00FF +#define CLBF_TILEH 0x1000 +#define CLBF_TILEV 0x2000 +#define CLBF_PROPORTIONAL 0x4000 +#define CLBF_SCROLL 0x8000 + +#define CLM_SETBKCOLOR (CLM_FIRST+28) //wParam = a COLORREF, default is GetSysColor(COLOR_3DFACE) +#define CLM_SETCHECKMARK (CLM_FIRST+29) //wParam = hItem, lParam = 1 or 0 +#define CLM_SETEXTRACOLUMNS (CLM_FIRST+30) //wParam = number of extra columns (zero to EXTRA_ICON_COUNT from clc.h, currently 16) +#define CLM_SETEXTRAIMAGE (CLM_FIRST+31) //wParam = hItem, lParam = MAKELPARAM(iColumn (0 based),iImage). iImage = EMPTY_EXTRA_ICON is a blank +#define CLM_SETEXTRAIMAGELIST (CLM_FIRST+32) //lParam = HIMAGELIST + +#define FONTID_CONTACTS 0 +#define FONTID_INVIS 1 +#define FONTID_OFFLINE 2 +#define FONTID_NOTONLIST 3 +#define FONTID_GROUPS 4 +#define FONTID_GROUPCOUNTS 5 +#define FONTID_DIVIDERS 6 +#define FONTID_OFFINVIS 7 +#define FONTID_STATUSMSG 8 +#define FONTID_GROUPSCLOSED 9 +#define FONTID_CONTACTSHOVER 10 +#define FONTID_MAX 18 + +#define CLM_SETFONT (CLM_FIRST+33) //wParam = hFont, lParam = MAKELPARAM(fRedraw,fontId) +#define CLM_SETITEMTEXT (CLM_FIRST+35) //wParam = hItem, lParam = (char*)pszNewText +#define CLM_SETSCROLLTIME (CLM_FIRST+36) //wParam = time in ms, default 200 + +#define CLM_SETHIDEEMPTYGROUPS (CLM_FIRST+38) //wParam = TRUE/FALSE +#define GREYF_UNFOCUS 0x80000000 +#define MODEF_OFFLINE 0x40000000 +//and use the PF2_ #defines from m_protosvc.h + +#define CLM_GETHIDEOFFLINEROOT (CLM_FIRST+40) //returns TRUE/FALSE +#define CLM_SETHIDEOFFLINEROOT (CLM_FIRST+41) //wParam = TRUE/FALSE +#define CLM_SETUSEGROUPS (CLM_FIRST+42) //wParam = TRUE/FALSE +#define CLM_SETOFFLINEMODES (CLM_FIRST+43) //for 'hide offline', wParam = PF2_ flags and MODEF_OFFLINE +#define CLM_GETEXSTYLE (CLM_FIRST+44) //returns CLS_EX_ flags +#define CLM_SETEXSTYLE (CLM_FIRST+45) //wParam = CLS_EX_ flags + +typedef struct { + int cbSize; + const wchar_t *pszText; + HANDLE hParentGroup; + DWORD flags; + HICON hIcon; //todo +} CLCINFOITEM; +#define CLCIIF_BELOWGROUPS 1 //put it between groups and contacts, default is at top +#define CLCIIF_BELOWCONTACTS 2 //put it at the bottom +#define CLCIIF_CHECKBOX 0x40 //give this item a check box +#define CLCIIF_GROUPFONT 0x80 //draw the item using FONTID_GROUPS + +#define CLM_ADDINFOITEMA (CLM_FIRST+48) //lParam = &cii, returns hItem +#define CLM_ADDINFOITEMW (CLM_FIRST+53) //lParam = &cii, returns hItem +#if defined(_UNICODE) + #define CLM_ADDINFOITEM CLM_ADDINFOITEMW +#else + #define CLM_ADDINFOITEM CLM_ADDINFOITEMA +#endif + + //the order of info items is never changed, so make sure you add them in the + // order you want them to remain +#define CLCIT_INVALID -1 +#define CLCIT_GROUP 0 +#define CLCIT_CONTACT 1 +#define CLCIT_DIVIDER 2 +#define CLCIT_INFO 3 +#define CLM_GETITEMTYPE (CLM_FIRST+49) //wParam = hItem, returns a CLCIT_ +#define CLGN_ROOT 0 +#define CLGN_CHILD 1 +#define CLGN_PARENT 2 +#define CLGN_NEXT 3 +#define CLGN_PREVIOUS 4 +#define CLGN_NEXTCONTACT 5 +#define CLGN_PREVIOUSCONTACT 6 +#define CLGN_NEXTGROUP 7 +#define CLGN_PREVIOUSGROUP 8 + +#define CLM_GETNEXTITEM (CLM_FIRST+50) //wParam = flag, lParam = hItem, returns an hItem +#define CLM_GETTEXTCOLOR (CLM_FIRST+51) //wParam = FONTID_, returns COLORREF +#define CLM_SETTEXTCOLOR (CLM_FIRST+52) //wParam = FONTID_, lParam = COLORREF + +//notifications (most are omitted because the control processes everything) +#define CLNF_ISGROUP 1 +#define CLNF_ISINFO 2 +#ifdef _MSC_VER +typedef struct { + NMHDR hdr; + HANDLE hItem; + int action; + int iColumn; //-1 if not on an extra column + DWORD flags; + POINT pt; +} NMCLISTCONTROL; +#endif +#define CLN_FIRST (0U-100U) +#define CLN_EXPANDED (CLN_FIRST-0) //hItem = hGroup, action = CLE_* +#define CLN_LISTREBUILT (CLN_FIRST-1) +#define CLN_ITEMCHECKED (CLN_FIRST-2) //todo //hItem, action, flags valid +#define CLN_DRAGGING (CLN_FIRST-3) //hItem, pt, flags valid. only sent when cursor outside window, return nonzero if processed +#define CLN_DROPPED (CLN_FIRST-4) //hItem, pt, flags valid. only sent when cursor outside window, return nonzero if processed +#define CLN_LISTSIZECHANGE (CLN_FIRST-5) //pt.y valid. the vertical height of the visible items in the list has changed. +#define CLN_OPTIONSCHANGED (CLN_FIRST-6) //nothing valid. If you set some extended options they have been overwritten and should be re-set +#define CLN_DRAGSTOP (CLN_FIRST-7) //hItem, flags valid. sent when cursor goes back in to the window having been outside, return nonzero if processed +#define CLN_NEWCONTACT (CLN_FIRST-8) //hItem, flags valid. sent when a new contact is added without a full list rebuild +#define CLN_CONTACTMOVED (CLN_FIRST-9) //hItem, flags valid. sent when contact is moved without a full list rebuild +#define CLN_CHECKCHANGED (CLN_FIRST-10) //hItem, flags valid. sent when any check mark is changed, but only for one change if there are many +//NM_CLICK //hItem, iColumn, pt, flags valid +//NM_KEYDOWN //NMKEY structure, only sent when key is not already processed, return nonzero to prevent further processing + +// clist window tree messages +#define M_CREATECLC (WM_USER+1) +#define M_SETALLEXTRAICONS (WM_USER+2) + +//an infotip for an item should be shown now +//wParam = 0 +//lParam = (LPARAM)(CLCINFOTIP*)&it +//Return nonzero if you process this, because it makes no sense for more than +//one plugin to grab it. +//It is up to the plugin to decide the best place to put the infotip. Normally +//it's a few pixels below and to the right of the cursor +//This event is called after the mouse has been stationary over a contact for +//(by default) 200ms, but see below. +//Everything is in screen coordinates. +typedef struct { + int cbSize; + int isTreeFocused; //so the plugin can provide an option + int isGroup; //0 if it's a contact, 1 if it's a group + HANDLE hItem; //handle to group or contact + POINT ptCursor; + RECT rcItem; +} CLCINFOTIP; +#define ME_CLC_SHOWINFOTIP "CLC/ShowInfoTip" + +typedef struct { + int cbSize; + int isTreeFocused; //so the plugin can provide an option + HANDLE hItem; //handle to group or contact + POINT ptCursor; + RECT rcItem; + int extraIndex; + HWND hwnd; +} CLCEXTRAINFOTIP; +#define ME_CLC_SHOWEXTRAINFOTIP "CLC/ShowExtraInfoTip" + +//it's time to destroy an infotip +//wParam = 0 +//lParam = (LPARAM)(CLCINFOTIP*)&it +//Only cbSize, isGroup and hItem are set +//Return nonzero if you process this. +//This is sent when the mouse moves off a contact when clc/showinfotip has +//previously been called. +//If you don't want this behaviour, you should have grabbed the mouse capture +//yourself and made your own arrangements. +#define ME_CLC_HIDEINFOTIP "CLC/HideInfoTip" + +//set the hover time before the infotip hooks are called +//wParam = newTime +//lParam = 0 +//Returns 0 on success or nonzero on failure +//The value of this setting is applied to all current CLC windows, and saved +//to be applied to all future windows, including after restarts. +//newTime is in ms. +//The default is 750ms. +#define MS_CLC_SETINFOTIPHOVERTIME "CLC/SetInfoTipHoverTime" + +//get the hover time before the infotip hooks are called +//wParam = lParam = 0 +//Returns the time in ms +#define MS_CLC_GETINFOTIPHOVERTIME "CLC/GetInfoTipHoverTime" + +#endif // M_CLC_H__ diff --git a/include/m_core.h b/include/m_core.h index 6a9cda3b39..8726e189a1 100644 --- a/include/m_core.h +++ b/include/m_core.h @@ -1,600 +1,660 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) -Copyright (c) 2000-08 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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_CORE_H__ -#define M_CORE_H__ 1 - -#ifdef _MSC_VER - #include -#endif - -#include -#include - -#ifndef M_TYPES_H__ - #include -#endif - -#ifdef MIR_CORE_EXPORTS - #define MIR_CORE_EXPORT __declspec(dllexport) -#else - #define MIR_CORE_EXPORT __declspec(dllimport) -#endif - -#define MIR_CORE_DLL(T) MIR_CORE_EXPORT T __stdcall -#define MIR_C_CORE_DLL(T) MIR_CORE_EXPORT T __cdecl - -#ifdef MIR_APP_EXPORTS - #define MIR_APP_EXPORT __declspec(dllexport) - typedef struct NetlibUser* HNETLIBUSER; - typedef struct NetlibConnection* HNETLIBCONN; - typedef struct NetlibBoundPort* HNETLIBBIND; -#else - #define MIR_APP_EXPORT __declspec(dllimport) - DECLARE_HANDLE(HNETLIBUSER); - DECLARE_HANDLE(HNETLIBCONN); - DECLARE_HANDLE(HNETLIBBIND); -#endif - -typedef struct TMO_IntMenuItem* HGENMENU; - -class CMPluginBase; -typedef const CMPluginBase* HPLUGIN; - -#define MIR_APP_DLL(T) MIR_APP_EXPORT T __stdcall - -#pragma warning(disable:4201 4127 4312 4706) - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/////////////////////////////////////////////////////////////////////////////// -// command line support - -MIR_CORE_DLL(void) CmdLine_Parse(const wchar_t *ptszCmdLine); -MIR_CORE_DLL(const wchar_t*) CmdLine_GetOption(const wchar_t *ptszParameter); - -/////////////////////////////////////////////////////////////////////////////// -// database functions - -typedef uint32_t MCONTACT; -#define INVALID_CONTACT_ID (MCONTACT(-1)) - -typedef uint32_t MEVENT; - -/////////////////////////////////////////////////////////////////////////////// -// events, hooks & services - -#define MAXMODULELABELLENGTH 64 - -typedef int (*MIRANDAHOOK)(WPARAM, LPARAM); -typedef int (*MIRANDAHOOKPARAM)(WPARAM, LPARAM, LPARAM); -typedef int (*MIRANDAHOOKOBJ)(void*, WPARAM, LPARAM); -typedef int (*MIRANDAHOOKOBJPARAM)(void*, WPARAM, LPARAM, LPARAM); - -typedef INT_PTR (*MIRANDASERVICE)(WPARAM, LPARAM); -typedef INT_PTR (*MIRANDASERVICEPARAM)(WPARAM, LPARAM, LPARAM); -typedef INT_PTR (*MIRANDASERVICEOBJ)(void*, WPARAM, LPARAM); -typedef INT_PTR (*MIRANDASERVICEOBJPARAM)(void*, WPARAM, LPARAM, LPARAM); - -#ifdef _WIN64 - #define CALLSERVICE_NOTFOUND ((INT_PTR)0x8000000000000000) -#else - #define CALLSERVICE_NOTFOUND ((int)0x80000000) -#endif - -MIR_CORE_DLL(HANDLE) CreateHookableEvent(const char *name); -MIR_CORE_DLL(int) DestroyHookableEvent(HANDLE hEvent); -MIR_CORE_DLL(int) SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook); -MIR_CORE_DLL(int) CallPluginEventHook(HINSTANCE hInst, HANDLE hEvent, WPARAM wParam = 0, LPARAM lParam = 0); -MIR_CORE_DLL(int) CallObjectEventHook(void *pObject, HANDLE hEvent, WPARAM wParam = 0, LPARAM lParam = 0); -MIR_CORE_DLL(int) NotifyEventHooks(HANDLE hEvent, WPARAM wParam = 0, LPARAM lParam = 0); -MIR_CORE_DLL(int) NotifyFastHook(HANDLE hEvent, WPARAM wParam = 0, LPARAM lParam = 0); - -MIR_CORE_DLL(HANDLE) HookEvent(const char *name, MIRANDAHOOK hookProc); -MIR_CORE_DLL(HANDLE) HookEventParam(const char *name, MIRANDAHOOKPARAM hookProc, LPARAM lParam = 0); -MIR_CORE_DLL(HANDLE) HookEventObj(const char *name, MIRANDAHOOKOBJ hookProc, void* object); -MIR_CORE_DLL(HANDLE) HookEventObjParam(const char *name, MIRANDAHOOKOBJPARAM hookProc, void* object, LPARAM lParam); -MIR_CORE_DLL(HANDLE) HookEventMessage(const char *name, HWND hwnd, UINT message); - -// executes the event handler if event is missing -MIR_CORE_DLL(HANDLE) HookTemporaryEvent(const char *name, MIRANDAHOOK hookProc); - -MIR_CORE_DLL(int) UnhookEvent(HANDLE hHook); -MIR_CORE_DLL(void) KillObjectEventHooks(void* pObject); -MIR_CORE_DLL(void) KillModuleEventHooks(HINSTANCE pModule); - -MIR_CORE_DLL(HANDLE) CreateServiceFunction(const char *name, MIRANDASERVICE serviceProc); -MIR_CORE_DLL(HANDLE) CreateServiceFunctionParam(const char *name, MIRANDASERVICEPARAM serviceProc, LPARAM lParam); -MIR_CORE_DLL(HANDLE) CreateServiceFunctionObj(const char *name, MIRANDASERVICEOBJ serviceProc, void* object); -MIR_CORE_DLL(HANDLE) CreateServiceFunctionObjParam(const char *name, MIRANDASERVICEOBJPARAM serviceProc, void* object, LPARAM lParam); -MIR_CORE_DLL(HANDLE) CreateProtoServiceFunction(const char *szModule, const char *szService, MIRANDASERVICE serviceProc); -MIR_CORE_DLL(int) DestroyServiceFunction(HANDLE hService); -MIR_CORE_DLL(bool) ServiceExists(const char *name); - -MIR_CORE_DLL(INT_PTR) CallService(const char *name, WPARAM wParam = 0, LPARAM lParam = 0); -MIR_CORE_DLL(INT_PTR) CallServiceSync(const char *name, WPARAM wParam = 0, LPARAM lParam = 0); - -MIR_CORE_DLL(INT_PTR) CallFunctionSync(INT_PTR(__stdcall *func)(void *), void *arg); -MIR_CORE_DLL(int) CallFunctionAsync(void (__stdcall *func)(void *), void *arg); -MIR_CORE_DLL(void) KillModuleServices(HINSTANCE hInst); -MIR_CORE_DLL(void) KillObjectServices(void* pObject); - -MIR_APP_DLL(int) ProtoServiceExists(const char *szModule, const char *szService); -MIR_APP_DLL(INT_PTR) CallProtoService(const char *szModule, const char *szService, WPARAM wParam = 0, LPARAM lParam = 0); - -/////////////////////////////////////////////////////////////////////////////// -// exceptions - -typedef DWORD (__cdecl *pfnExceptionFilter)(DWORD code, EXCEPTION_POINTERS* info); - -MIR_CORE_DLL(pfnExceptionFilter) GetExceptionFilter(void); -MIR_CORE_DLL(pfnExceptionFilter) SetExceptionFilter(pfnExceptionFilter pMirandaExceptFilter); - -/////////////////////////////////////////////////////////////////////////////// -// icons support - -struct IconItem -{ - char *szDescr, *szName; - int defIconID, size; - HANDLE hIcolib; -}; - -struct IconItemT -{ - wchar_t *tszDescr; - char *szName; - int defIconID, size; - HANDLE hIcolib; -}; - -MIR_CORE_DLL(void) Icon_Register(HINSTANCE hInst, const char *szSection, IconItem *pIcons, size_t iCount, const char *prefix, HPLUGIN pPlugin); -MIR_CORE_DLL(void) Icon_RegisterT(HINSTANCE hInst, const wchar_t *szSection, IconItemT *pIcons, size_t iCount, const char *prefix, HPLUGIN pPlugin); - -/////////////////////////////////////////////////////////////////////////////// -// language packs support - -MIR_CORE_DLL(unsigned int) mir_hash(const void *key, unsigned int len); - -#pragma optimize("gt", on) -__forceinline unsigned int mir_hashstr(const char *key) -{ - if (key == nullptr) return 0; - else { - unsigned int len = (unsigned int)strlen((const char*)key); - return mir_hash(key, len); -} } - -__forceinline unsigned int mir_hashstrW(const wchar_t *key) -{ - if (key == nullptr) return 0; - else { - unsigned int len = (unsigned int)wcslen((const wchar_t*)key); - return mir_hash(key, len * sizeof(wchar_t)); -} } -#pragma optimize("", on) - -#define mir_hashstrT mir_hashstrW - -/////////////////////////////////////////////////////////////////////////////// -// lists - -typedef int (*FSortFunc)(void*, void*); // sort function prototype - -// Assumes first 32 bit value of the data is the numeric key -// and uses it to perform sort/search operations, this results -// in much better performance as no compare function calls needed -// Incredibly useful for Hash Tables -#define NumericKeySort (FSortFunc)(void*) -1 -#define HandleKeySort (FSortFunc)(void*) -2 -#define PtrKeySort (FSortFunc)(void*) -3 - -typedef struct -{ - void** items; - int realCount; - int limit; - int increment; - - FSortFunc sortFunc; -} - SortedList; - -MIR_CORE_DLL(SortedList*) List_Create(int p_limit, int p_increment); -MIR_CORE_DLL(void) List_Destroy(SortedList* p_list); -MIR_CORE_DLL(void*) List_Find(SortedList* p_list, void* p_value); -MIR_CORE_DLL(int) List_GetIndex(SortedList* p_list, void* p_value, int* p_index); -MIR_CORE_DLL(int) List_IndexOf(SortedList* p_list, void* p_value); -MIR_CORE_DLL(int) List_Insert(SortedList* p_list, void* p_value, int p_index); -MIR_CORE_DLL(int) List_InsertPtr(SortedList* list, void* p); -MIR_CORE_DLL(int) List_Remove(SortedList* p_list, int index); -MIR_CORE_DLL(int) List_RemovePtr(SortedList* list, void* p); -MIR_CORE_DLL(void) List_Copy(SortedList* s, SortedList* d, size_t itemSize); -MIR_CORE_DLL(void) List_ObjCopy(SortedList* s, SortedList* d, size_t itemSize); - -/////////////////////////////////////////////////////////////////////////////// -// logging functions - -MIR_CORE_DLL(HANDLE) mir_createLog(const char *pszName, const wchar_t *ptszDescr, const wchar_t *ptszFile, unsigned options); -MIR_CORE_DLL(void) mir_closeLog(HANDLE hLogger); - -MIR_C_CORE_DLL(int) mir_writeLogA(HANDLE hLogger, const char *format, ...); -MIR_C_CORE_DLL(int) mir_writeLogW(HANDLE hLogger, const wchar_t *format, ...); - -MIR_CORE_DLL(int) mir_writeLogVA(HANDLE hLogger, const char *format, va_list args); -MIR_CORE_DLL(int) mir_writeLogVW(HANDLE hLogger, const wchar_t *format, va_list args); - -/////////////////////////////////////////////////////////////////////////////// -// md5 functions - -typedef struct mir_md5_state_s { - UINT32 count[2]; /* message length in bits, lsw first */ - UINT32 abcd[4]; /* digest buffer */ - BYTE buf[64]; /* accumulate block */ -} mir_md5_state_t; - -MIR_CORE_DLL(void) mir_md5_init(mir_md5_state_t *pms); -MIR_CORE_DLL(void) mir_md5_append(mir_md5_state_t *pms, const BYTE *data, size_t nbytes); -MIR_CORE_DLL(void) mir_md5_finish(mir_md5_state_t *pms, BYTE digest[16]); -MIR_CORE_DLL(void) mir_md5_hash(const BYTE *data, size_t len, BYTE digest[16]); - -/////////////////////////////////////////////////////////////////////////////// -// memory functions - -MIR_C_CORE_DLL(void*) mir_alloc(size_t); -MIR_C_CORE_DLL(void*) mir_calloc(size_t); -MIR_C_CORE_DLL(void*) mir_realloc(void* ptr, size_t); -MIR_C_CORE_DLL(void) mir_free(void* ptr); - -MIR_CORE_DLL(size_t) mir_strlen(const char *p); -MIR_CORE_DLL(size_t) mir_wstrlen(const wchar_t *p); - -MIR_CORE_DLL(char*) mir_strcpy(char *dest, const char *src); -MIR_CORE_DLL(wchar_t*) mir_wstrcpy(wchar_t *dest, const wchar_t *src); - -MIR_CORE_DLL(char*) mir_strncpy(char *dest, const char *src, size_t len); -MIR_CORE_DLL(wchar_t*) mir_wstrncpy(wchar_t *dest, const wchar_t *src, size_t len); - -MIR_CORE_DLL(char*) mir_strcat(char *dest, const char *src); -MIR_CORE_DLL(wchar_t*) mir_wstrcat(wchar_t *dest, const wchar_t *src); - -MIR_CORE_DLL(char*) mir_strncat(char *dest, const char *src, size_t len); -MIR_CORE_DLL(wchar_t*) mir_wstrncat(wchar_t *dest, const wchar_t *src, size_t len); - -MIR_CORE_DLL(int) mir_strcmp(const char *p1, const char *p2); -MIR_CORE_DLL(int) mir_strncmp(const char *p1, const char *p2, size_t n); -MIR_CORE_DLL(int) mir_wstrcmp(const wchar_t *p1, const wchar_t *p2); -MIR_CORE_DLL(int) mir_wstrncmp(const wchar_t *p1, const wchar_t *p2, size_t n); - -MIR_CORE_DLL(int) mir_strcmpi(const char *p1, const char *p2); -MIR_CORE_DLL(int) mir_strncmpi(const char *p1, const char *p2, size_t n); -MIR_CORE_DLL(int) mir_wstrcmpi(const wchar_t *p1, const wchar_t *p2); -MIR_CORE_DLL(int) mir_wstrncmpi(const wchar_t *p1, const wchar_t *p2, size_t n); - -MIR_CORE_DLL(char*) mir_strdup(const char* str); -MIR_CORE_DLL(wchar_t*) mir_wstrdup(const wchar_t* str); - -MIR_CORE_DLL(char*) mir_strndup(const char* str, size_t len); -MIR_CORE_DLL(wchar_t*) mir_wstrndup(const wchar_t *str, size_t len); - -MIR_CORE_DLL(const wchar_t*) mir_wstrstri(const wchar_t *s1, const wchar_t *s2); - -/////////////////////////////////////////////////////////////////////////////// -// print functions - -MIR_CORE_DLL(int) mir_snprintf(_Pre_notnull_ _Always_(_Post_z_) char *buffer, size_t count, _Printf_format_string_ const char* fmt, ...); -MIR_CORE_DLL(int) mir_snwprintf(_Pre_notnull_ _Always_(_Post_z_) wchar_t *buffer, size_t count, _Printf_format_string_ const wchar_t* fmt, ...); -MIR_CORE_DLL(int) mir_vsnprintf(_Pre_notnull_ _Always_(_Post_z_) char *buffer, size_t count, _Printf_format_string_ const char* fmt, va_list va); -MIR_CORE_DLL(int) mir_vsnwprintf(_Pre_notnull_ _Always_(_Post_z_) wchar_t *buffer, size_t count, _Printf_format_string_ const wchar_t* fmt, va_list va); - -/////////////////////////////////////////////////////////////////////////////// -// protocol functions - -struct PROTO_INTERFACE; - -MIR_APP_DLL(INT_PTR) ProtoBroadcastAck(const char *szModule, MCONTACT hContact, int type, int result, HANDLE hProcess, LPARAM lParam = 0); -MIR_APP_DLL(void) ProtoBroadcastAsync(const char *szModule, MCONTACT hContact, int type, int result, HANDLE hProcess, LPARAM lParam = 0); - -// avatar support functions - -// returns image extension by a PA_* constant or empty string for PA_FORMAT_UNKNOWN -MIR_APP_DLL(const wchar_t*) ProtoGetAvatarExtension(int format); - -// detects image format by extension -MIR_APP_DLL(int) ProtoGetAvatarFormat(const wchar_t *ptszFileName); - -// detects image format by its contents -MIR_APP_DLL(int) ProtoGetAvatarFileFormat(const wchar_t *ptszFileName); - -// returns the mime type according to a picture type (PA_*) passed -MIR_APP_DLL(const char*) ProtoGetAvatarMimeType(int iFileType); - -// returns the picture type (PA_*) according to a mime type passed -MIR_APP_DLL(int) ProtoGetAvatarFormatByMimeType(const char *pwszMimeType); - -// returns the image format and extension by the first bytes of picture -// ptszExtension might be NULL -#if defined( __cplusplus ) - MIR_APP_DLL(int) ProtoGetBufferFormat(const void *buf, const wchar_t **ptszExtension = nullptr); -#else - MIR_APP_DLL(int) ProtoGetBufferFormat(const void *buf, const wchar_t **ptszExtension); -#endif - -/////////////////////////////////////////////////////////////////////////////// -// sha1 functions - -#define MIR_SHA1_HASH_SIZE 20 -#define MIR_SHA_BLOCKSIZE 64 - -struct mir_sha1_ctx -{ - ULONG H[5]; - ULONG W[80]; - int lenW; - ULONG sizeHi, sizeLo; -}; - -MIR_CORE_DLL(void) mir_sha1_init(mir_sha1_ctx *ctx); -MIR_CORE_DLL(void) mir_sha1_append(mir_sha1_ctx *ctx, const BYTE *dataIn, size_t len); -MIR_CORE_DLL(void) mir_sha1_finish(mir_sha1_ctx *ctx, BYTE hashout[MIR_SHA1_HASH_SIZE]); -MIR_CORE_DLL(void) mir_sha1_hash(BYTE *dataIn, size_t len, BYTE hashout[MIR_SHA1_HASH_SIZE]); - -/////////////////////////////////////////////////////////////////////////////// -// sha256 functions - -#define MIR_SHA256_HASH_SIZE 32 - -struct SHA256_CONTEXT -{ - UINT32 h0, h1, h2, h3, h4, h5, h6, h7; - UINT32 nblocks; - BYTE buf[MIR_SHA_BLOCKSIZE]; - int count; -}; - -MIR_CORE_DLL(void) mir_sha256_init(SHA256_CONTEXT *ctx); -MIR_CORE_DLL(void) mir_sha256_write(SHA256_CONTEXT *ctx, const void *dataIn, size_t len); -MIR_CORE_DLL(void) mir_sha256_final(SHA256_CONTEXT *ctx, BYTE hashout[MIR_SHA256_HASH_SIZE]); -MIR_CORE_DLL(void) mir_sha256_hash(const void *dataIn, size_t len, BYTE hashout[MIR_SHA256_HASH_SIZE]); - -/////////////////////////////////////////////////////////////////////////////// -// strings - -MIR_CORE_DLL(void*) mir_base64_decode(const char *input, size_t *outputLen); -MIR_CORE_DLL(char*) mir_base64_encode(const void *input, size_t inputLen); -MIR_CORE_DLL(char*) mir_base64_encodebuf(const void *input, size_t inputLen, char *output, size_t outLen); - -__forceinline size_t mir_base64_encode_bufsize(size_t inputLen) -{ - return 4 * ((inputLen + 2) / 3) + 1; -} - -MIR_CORE_DLL(char*) rtrim(char *str); -MIR_CORE_DLL(wchar_t*) rtrimw(wchar_t *str); - -MIR_CORE_DLL(char*) ltrim(char *str); // returns pointer to the beginning of string -MIR_CORE_DLL(wchar_t*) ltrimw(wchar_t *str); - -MIR_CORE_DLL(char*) ltrimp(char *str); // returns pointer to the trimmed portion of string -MIR_CORE_DLL(wchar_t*) ltrimpw(wchar_t *str); - -MIR_CORE_DLL(char*) strdel(char *str, size_t len); -MIR_CORE_DLL(wchar_t*) strdelw(wchar_t *str, size_t len); - -MIR_CORE_DLL(int) wildcmp(const char *name, const char *mask); -MIR_CORE_DLL(int) wildcmpw(const wchar_t *name, const wchar_t *mask); - -MIR_CORE_DLL(int) wildcmpi(const char *name, const char *mask); -MIR_CORE_DLL(int) wildcmpiw(const wchar_t *name, const wchar_t *mask); - -MIR_CORE_DLL(char*) bin2hex(const void *pData, size_t len, char *dest); -MIR_CORE_DLL(wchar_t*) bin2hexW(const void *pData, size_t len, wchar_t *dest); - -MIR_CORE_DLL(bool) hex2bin(const char *pSrc, void *pData, size_t len); -MIR_CORE_DLL(bool) hex2binW(const wchar_t *pSrc, void *pData, size_t len); - -__forceinline char* lrtrim(char *str) { return ltrim(rtrim(str)); }; -__forceinline char* lrtrimp(char *str) { return ltrimp(rtrim(str)); }; - -#if defined( __cplusplus ) - MIR_CORE_DLL(char*) replaceStr(char* &dest, const char *src); - MIR_CORE_DLL(wchar_t*) replaceStrW(wchar_t* &dest, const wchar_t *src); -#else - MIR_CORE_DLL(char*) replaceStr(char **dest, const char *src); - MIR_CORE_DLL(wchar_t*) replaceStrW(wchar_t **dest, const wchar_t *src); -#endif - -/////////////////////////////////////////////////////////////////////////////// -// text conversion functions - -union MAllStrings -{ - char *a; // utf8 or ansi strings - wchar_t *w; // strings of WCHARs -}; - -union MAllCStrings -{ - const char *a; // utf8 or ansi strings - const wchar_t *w; // strings of WCHARs -}; - -union MAllStringArray -{ - char **a; // array of utf8 or ansi strings - wchar_t **w; // array of strings of WCHARs -}; - -union MAllCStringArray -{ - const char **a; // array of utf8 or ansi strings - const wchar_t **w; // array of strings of WCHARs -}; - -MIR_CORE_DLL(wchar_t*) mir_a2u_cp(const char* src, int codepage); -MIR_CORE_DLL(wchar_t*) mir_a2u(const char* src); -MIR_CORE_DLL(char*) mir_u2a_cp(const wchar_t* src, int codepage); -MIR_CORE_DLL(char*) mir_u2a(const wchar_t* src); - -/////////////////////////////////////////////////////////////////////////////// -// threads - -typedef void (__cdecl *pThreadFunc)(void *param); -typedef unsigned (__stdcall *pThreadFuncEx)(void *param); -typedef unsigned (__cdecl *pThreadFuncOwner)(void *owner, void *param); - -#if defined( __cplusplus ) - MIR_CORE_DLL(INT_PTR) Thread_Push(HINSTANCE hInst, void* pOwner = nullptr); -#else - MIR_CORE_DLL(INT_PTR) Thread_Push(HINSTANCE hInst, void* pOwner); -#endif -MIR_CORE_DLL(INT_PTR) Thread_Pop(void); -MIR_CORE_DLL(void) Thread_Wait(void); - -#if defined( __cplusplus ) -MIR_CORE_DLL(HANDLE) mir_forkthread(pThreadFunc aFunc, void *arg = nullptr); -MIR_CORE_DLL(HANDLE) mir_forkthreadex(pThreadFuncEx aFunc, void *arg = nullptr, unsigned *pThreadID = nullptr); -MIR_CORE_DLL(HANDLE) mir_forkthreadowner(pThreadFuncOwner aFunc, void *owner, void *arg = nullptr, unsigned *pThreadID = nullptr); -#else -MIR_CORE_DLL(HANDLE) mir_forkthread(pThreadFunc aFunc, void *arg); -MIR_CORE_DLL(HANDLE) mir_forkthreadex(pThreadFuncEx aFunc, void *arg, unsigned *pThreadID); -MIR_CORE_DLL(HANDLE) mir_forkthreadowner(pThreadFuncOwner aFunc, void *owner, void *arg, unsigned *pThreadID); -#endif - -MIR_CORE_DLL(void) Thread_SetName(const char *szThreadName); - -MIR_CORE_DLL(void) KillObjectThreads(void* pObject); - -/////////////////////////////////////////////////////////////////////////////// -// utf8 interface - -MIR_CORE_DLL(BOOL) Utf8CheckString(const char* str); -MIR_CORE_DLL(int) Utf8toUcs2(const char *src, size_t srclen, wchar_t *dst, size_t dstlen); // returns 0 on error - -MIR_CORE_DLL(char*) mir_utf8decode(char* str, wchar_t** ucs2); -MIR_CORE_DLL(char*) mir_utf8decodecp(char* str, int codepage, wchar_t** ucs2); -MIR_CORE_DLL(wchar_t*) mir_utf8decodeW(const char* str); - -MIR_CORE_DLL(char*) mir_utf8encode(const char* str); -MIR_CORE_DLL(char*) mir_utf8encodecp(const char* src, int codepage); -MIR_CORE_DLL(char*) mir_utf8encodeW(const wchar_t* str); - -MIR_CORE_DLL(int) mir_utf8lenW(const wchar_t *src); - -__forceinline char* mir_utf8decodeA(const char* src) -{ - char *tmp = mir_strdup(src); - mir_utf8decode(tmp, nullptr); - return tmp; -} - -/////////////////////////////////////////////////////////////////////////////// -// Window subclassing - -MIR_CORE_DLL(void) mir_subclassWindow(HWND hWnd, WNDPROC wndProc); -MIR_CORE_DLL(void) mir_subclassWindowFull(HWND hWnd, WNDPROC wndProc, WNDPROC oldWndProc); -MIR_CORE_DLL(LRESULT) mir_callNextSubclass(HWND hWnd, WNDPROC wndProc, UINT uMsg, WPARAM wParam, LPARAM lParam); -MIR_CORE_DLL(void) mir_unsubclassWindow(HWND hWnd, WNDPROC wndProc); - -MIR_CORE_DLL(void) KillModuleSubclassing(HMODULE hInst); - -/////////////////////////////////////////////////////////////////////////////// -// Windows utilities - -MIR_CORE_DLL(BOOL) IsWinVerVistaPlus(); -MIR_CORE_DLL(BOOL) IsWinVer7Plus(); -MIR_CORE_DLL(BOOL) IsWinVer8Plus(); -MIR_CORE_DLL(BOOL) IsWinVer81Plus(); -MIR_CORE_DLL(BOOL) IsWinVer10Plus(); - -MIR_CORE_DLL(BOOL) IsFullScreen(); -MIR_CORE_DLL(BOOL) IsWorkstationLocked(); -MIR_CORE_DLL(BOOL) IsScreenSaverRunning(); -MIR_CORE_DLL(BOOL) IsTerminalDisconnected(); - -// returns OS version in version of Windows NT xx.xx -MIR_CORE_DLL(BOOL) OS_GetShortString(char *buf, size_t bufSize); - -// returns full OS version -MIR_CORE_DLL(BOOL) OS_GetDisplayString(char *buf, size_t bufSize); - -/////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(void) UnloadCoreModule(void); - -#if defined(__cplusplus) -} - -template -HANDLE mir_forkThread(void(__cdecl *pFunc)(T* param), T *arg) -{ - return mir_forkthread((pThreadFunc)pFunc, arg); -} - -template -inline int mir_snprintf(_Pre_notnull_ _Always_(_Post_z_) char(&buffer)[_Size], _In_z_ _Printf_format_string_ const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - int ret = mir_vsnprintf(buffer, _Size, fmt, args); - va_end(args); - return ret; -} - -template -inline int mir_snwprintf(_Pre_notnull_ _Always_(_Post_z_) wchar_t(&buffer)[_Size], _In_z_ _Printf_format_string_ const wchar_t* fmt, ...) -{ - va_list args; - va_start(args, fmt); - int ret = mir_vsnwprintf(buffer, _Size, fmt, args); - va_end(args); - return ret; -} - -template -inline int mir_vsnprintf(_Pre_notnull_ _Always_(_Post_z_) char(&buffer)[_Size], _In_z_ _Printf_format_string_ const char* fmt, va_list va) -{ - return mir_vsnprintf(buffer, _Size, fmt, va); -} - -template -inline int mir_vsnwprintf(_Pre_notnull_ _Always_(_Post_z_) wchar_t(&buffer)[_Size], _In_z_ _Printf_format_string_ const wchar_t* fmt, va_list va) -{ - return mir_vsnwprintf(buffer, _Size, fmt, va); -} - -#endif - -#ifndef MIR_CORE_EXPORTS - #pragma comment(lib, "mir_core.lib") -#endif - -#ifndef MIR_APP_EXPORTS - #pragma comment(lib, "mir_app.lib") -#endif - -#endif // M_CORE_H +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2000-08 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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_CORE_H__ +#define M_CORE_H__ 1 + +#ifdef _MSC_VER + #include +#endif + +#include +#include + +#ifndef M_TYPES_H__ + #include +#endif + +#ifdef MIR_CORE_EXPORTS + #define MIR_CORE_EXPORT MIR_EXPORT +#else + #define MIR_CORE_EXPORT MIR_IMPORT +#endif + +#define MIR_CORE_DLL(T) MIR_CORE_EXPORT T MIR_SYSCALL +#define MIR_C_CORE_DLL(T) MIR_CORE_EXPORT T MIR_CDECL + +#ifdef MIR_APP_EXPORTS + #define MIR_APP_EXPORT MIR_EXPORT + typedef struct NetlibUser* HNETLIBUSER; + typedef struct NetlibConnection* HNETLIBCONN; + typedef struct NetlibBoundPort* HNETLIBBIND; +#else + #define MIR_APP_EXPORT MIR_IMPORT + DECLARE_HANDLE(HNETLIBUSER); + DECLARE_HANDLE(HNETLIBCONN); + DECLARE_HANDLE(HNETLIBBIND); +#endif + +typedef struct TMO_IntMenuItem* HGENMENU; + +class CMPluginBase; +typedef const CMPluginBase* HPLUGIN; + +#define MIR_APP_DLL(T) MIR_APP_EXPORT T MIR_SYSCALL + +#pragma warning(disable:4201 4127 4312 4706) + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/////////////////////////////////////////////////////////////////////////////// +// command line support + +MIR_CORE_DLL(void) CmdLine_Parse(const wchar_t *ptszCmdLine); +MIR_CORE_DLL(const wchar_t*) CmdLine_GetOption(const wchar_t *ptszParameter); + +/////////////////////////////////////////////////////////////////////////////// +// database functions + +typedef uint32_t MCONTACT; +#define INVALID_CONTACT_ID (MCONTACT(-1)) + +typedef uint32_t MEVENT; + +/////////////////////////////////////////////////////////////////////////////// +// events, hooks & services + +#define MAXMODULELABELLENGTH 64 + +typedef int (*MIRANDAHOOK)(WPARAM, LPARAM); +typedef int (*MIRANDAHOOKPARAM)(WPARAM, LPARAM, LPARAM); +typedef int (*MIRANDAHOOKOBJ)(void*, WPARAM, LPARAM); +typedef int (*MIRANDAHOOKOBJPARAM)(void*, WPARAM, LPARAM, LPARAM); + +typedef INT_PTR (*MIRANDASERVICE)(WPARAM, LPARAM); +typedef INT_PTR (*MIRANDASERVICEPARAM)(WPARAM, LPARAM, LPARAM); +typedef INT_PTR (*MIRANDASERVICEOBJ)(void*, WPARAM, LPARAM); +typedef INT_PTR (*MIRANDASERVICEOBJPARAM)(void*, WPARAM, LPARAM, LPARAM); + +#ifdef _WIN64 + #define CALLSERVICE_NOTFOUND ((INT_PTR)0x8000000000000000) +#else + #define CALLSERVICE_NOTFOUND ((int)0x80000000) +#endif + +MIR_CORE_DLL(HANDLE) CreateHookableEvent(const char *name); +MIR_CORE_DLL(int) DestroyHookableEvent(HANDLE hEvent); +MIR_CORE_DLL(int) SetHookDefaultForHookableEvent(HANDLE hEvent, MIRANDAHOOK pfnHook); +MIR_CORE_DLL(int) CallPluginEventHook(HINSTANCE hInst, HANDLE hEvent, WPARAM wParam = 0, LPARAM lParam = 0); +MIR_CORE_DLL(int) CallObjectEventHook(void *pObject, HANDLE hEvent, WPARAM wParam = 0, LPARAM lParam = 0); +MIR_CORE_DLL(int) NotifyEventHooks(HANDLE hEvent, WPARAM wParam = 0, LPARAM lParam = 0); +MIR_CORE_DLL(int) NotifyFastHook(HANDLE hEvent, WPARAM wParam = 0, LPARAM lParam = 0); + +MIR_CORE_DLL(HANDLE) HookEvent(const char *name, MIRANDAHOOK hookProc); +MIR_CORE_DLL(HANDLE) HookEventParam(const char *name, MIRANDAHOOKPARAM hookProc, LPARAM lParam = 0); +MIR_CORE_DLL(HANDLE) HookEventObj(const char *name, MIRANDAHOOKOBJ hookProc, void* object); +MIR_CORE_DLL(HANDLE) HookEventObjParam(const char *name, MIRANDAHOOKOBJPARAM hookProc, void* object, LPARAM lParam); +MIR_CORE_DLL(HANDLE) HookEventMessage(const char *name, HWND hwnd, UINT message); + +// executes the event handler if event is missing +MIR_CORE_DLL(HANDLE) HookTemporaryEvent(const char *name, MIRANDAHOOK hookProc); + +MIR_CORE_DLL(int) UnhookEvent(HANDLE hHook); +MIR_CORE_DLL(void) KillObjectEventHooks(void* pObject); +MIR_CORE_DLL(void) KillModuleEventHooks(HINSTANCE pModule); + +MIR_CORE_DLL(HANDLE) CreateServiceFunction(const char *name, MIRANDASERVICE serviceProc); +MIR_CORE_DLL(HANDLE) CreateServiceFunctionParam(const char *name, MIRANDASERVICEPARAM serviceProc, LPARAM lParam); +MIR_CORE_DLL(HANDLE) CreateServiceFunctionObj(const char *name, MIRANDASERVICEOBJ serviceProc, void* object); +MIR_CORE_DLL(HANDLE) CreateServiceFunctionObjParam(const char *name, MIRANDASERVICEOBJPARAM serviceProc, void* object, LPARAM lParam); +MIR_CORE_DLL(HANDLE) CreateProtoServiceFunction(const char *szModule, const char *szService, MIRANDASERVICE serviceProc); +MIR_CORE_DLL(int) DestroyServiceFunction(HANDLE hService); +MIR_CORE_DLL(bool) ServiceExists(const char *name); + +MIR_CORE_DLL(INT_PTR) CallService(const char *name, WPARAM wParam = 0, LPARAM lParam = 0); +MIR_CORE_DLL(INT_PTR) CallServiceSync(const char *name, WPARAM wParam = 0, LPARAM lParam = 0); + +MIR_CORE_DLL(INT_PTR) CallFunctionSync(INT_PTR(MIR_SYSCALL *func)(void *), void *arg); +MIR_CORE_DLL(int) CallFunctionAsync(void (MIR_SYSCALL *func)(void *), void *arg); +MIR_CORE_DLL(void) KillModuleServices(HINSTANCE hInst); +MIR_CORE_DLL(void) KillObjectServices(void* pObject); + +MIR_APP_DLL(int) ProtoServiceExists(const char *szModule, const char *szService); +MIR_APP_DLL(INT_PTR) CallProtoService(const char *szModule, const char *szService, WPARAM wParam = 0, LPARAM lParam = 0); + +/////////////////////////////////////////////////////////////////////////////// +// exceptions + +typedef DWORD (MIR_CDECL *pfnExceptionFilter)(DWORD code, EXCEPTION_POINTERS *info); + +MIR_CORE_DLL(pfnExceptionFilter) GetExceptionFilter(void); +MIR_CORE_DLL(pfnExceptionFilter) SetExceptionFilter(pfnExceptionFilter pMirandaExceptFilter); + +/////////////////////////////////////////////////////////////////////////////// +// icons support + +struct IconItem +{ + char *szDescr, *szName; + int defIconID, size; + HANDLE hIcolib; +}; + +struct IconItemT +{ + wchar_t *tszDescr; + char *szName; + int defIconID, size; + HANDLE hIcolib; +}; + +MIR_CORE_DLL(void) Icon_Register(HINSTANCE hInst, const char *szSection, IconItem *pIcons, size_t iCount, const char *prefix, HPLUGIN pPlugin); +MIR_CORE_DLL(void) Icon_RegisterT(HINSTANCE hInst, const wchar_t *szSection, IconItemT *pIcons, size_t iCount, const char *prefix, HPLUGIN pPlugin); + +/////////////////////////////////////////////////////////////////////////////// +// language packs support + +MIR_CORE_DLL(unsigned int) mir_hash(const void *key, unsigned int len); + +#pragma optimize("gt", on) +__forceinline unsigned int mir_hashstr(const char *key) +{ + if (key == nullptr) return 0; + else { + unsigned int len = (unsigned int)strlen((const char*)key); + return mir_hash(key, len); +} } + +__forceinline unsigned int mir_hashstrW(const wchar_t *key) +{ + if (key == nullptr) return 0; + else { + unsigned int len = (unsigned int)wcslen((const wchar_t*)key); + return mir_hash(key, len * sizeof(wchar_t)); +} } +#pragma optimize("", on) + +#define mir_hashstrT mir_hashstrW + +/////////////////////////////////////////////////////////////////////////////// +// lists + +typedef int (*FSortFunc)(void*, void*); // sort function prototype + +// Assumes first 32 bit value of the data is the numeric key +// and uses it to perform sort/search operations, this results +// in much better performance as no compare function calls needed +// Incredibly useful for Hash Tables +#define NumericKeySort (FSortFunc)(void*) -1 +#define HandleKeySort (FSortFunc)(void*) -2 +#define PtrKeySort (FSortFunc)(void*) -3 + +typedef struct +{ + void** items; + int realCount; + int limit; + int increment; + + FSortFunc sortFunc; +} + SortedList; + +MIR_CORE_DLL(SortedList*) List_Create(int p_limit, int p_increment); +MIR_CORE_DLL(void) List_Destroy(SortedList* p_list); +MIR_CORE_DLL(void*) List_Find(SortedList* p_list, void* p_value); +MIR_CORE_DLL(int) List_GetIndex(SortedList* p_list, void* p_value, int* p_index); +MIR_CORE_DLL(int) List_IndexOf(SortedList* p_list, void* p_value); +MIR_CORE_DLL(int) List_Insert(SortedList* p_list, void* p_value, int p_index); +MIR_CORE_DLL(int) List_InsertPtr(SortedList* list, void* p); +MIR_CORE_DLL(int) List_Remove(SortedList* p_list, int index); +MIR_CORE_DLL(int) List_RemovePtr(SortedList* list, void* p); +MIR_CORE_DLL(void) List_Copy(SortedList* s, SortedList* d, size_t itemSize); +MIR_CORE_DLL(void) List_ObjCopy(SortedList* s, SortedList* d, size_t itemSize); + +/////////////////////////////////////////////////////////////////////////////// +// logging functions + +MIR_CORE_DLL(HANDLE) mir_createLog(const char *pszName, const wchar_t *ptszDescr, const wchar_t *ptszFile, unsigned options); +MIR_CORE_DLL(void) mir_closeLog(HANDLE hLogger); + +MIR_C_CORE_DLL(int) mir_writeLogA(HANDLE hLogger, const char *format, ...); +MIR_C_CORE_DLL(int) mir_writeLogW(HANDLE hLogger, const wchar_t *format, ...); + +MIR_CORE_DLL(int) mir_writeLogVA(HANDLE hLogger, const char *format, va_list args); +MIR_CORE_DLL(int) mir_writeLogVW(HANDLE hLogger, const wchar_t *format, va_list args); + +/////////////////////////////////////////////////////////////////////////////// +// md5 functions + +typedef struct mir_md5_state_s { + uint32_t count[2]; /* message length in bits, lsw first */ + uint32_t abcd[4]; /* digest buffer */ + uint8_t buf[64]; /* accumulate block */ +} mir_md5_state_t; + +MIR_CORE_DLL(void) mir_md5_init(mir_md5_state_t *pms); +MIR_CORE_DLL(void) mir_md5_append(mir_md5_state_t *pms, const BYTE *data, size_t nbytes); +MIR_CORE_DLL(void) mir_md5_finish(mir_md5_state_t *pms, BYTE digest[16]); +MIR_CORE_DLL(void) mir_md5_hash(const BYTE *data, size_t len, BYTE digest[16]); + +/////////////////////////////////////////////////////////////////////////////// +// memory functions + +MIR_C_CORE_DLL(void*) mir_alloc(size_t); +MIR_C_CORE_DLL(void*) mir_calloc(size_t); +MIR_C_CORE_DLL(void*) mir_realloc(void* ptr, size_t); +MIR_C_CORE_DLL(void) mir_free(void* ptr); + +MIR_CORE_DLL(size_t) mir_strlen(const char *p); +MIR_CORE_DLL(size_t) mir_wstrlen(const wchar_t *p); + +MIR_CORE_DLL(char*) mir_strcpy(char *dest, const char *src); +MIR_CORE_DLL(wchar_t*) mir_wstrcpy(wchar_t *dest, const wchar_t *src); + +MIR_CORE_DLL(char*) mir_strncpy(char *dest, const char *src, size_t len); +MIR_CORE_DLL(wchar_t*) mir_wstrncpy(wchar_t *dest, const wchar_t *src, size_t len); + +MIR_CORE_DLL(char*) mir_strcat(char *dest, const char *src); +MIR_CORE_DLL(wchar_t*) mir_wstrcat(wchar_t *dest, const wchar_t *src); + +MIR_CORE_DLL(char*) mir_strncat(char *dest, const char *src, size_t len); +MIR_CORE_DLL(wchar_t*) mir_wstrncat(wchar_t *dest, const wchar_t *src, size_t len); + +MIR_CORE_DLL(int) mir_strcmp(const char *p1, const char *p2); +MIR_CORE_DLL(int) mir_strncmp(const char *p1, const char *p2, size_t n); +MIR_CORE_DLL(int) mir_wstrcmp(const wchar_t *p1, const wchar_t *p2); +MIR_CORE_DLL(int) mir_wstrncmp(const wchar_t *p1, const wchar_t *p2, size_t n); + +MIR_CORE_DLL(int) mir_strcmpi(const char *p1, const char *p2); +MIR_CORE_DLL(int) mir_strncmpi(const char *p1, const char *p2, size_t n); +MIR_CORE_DLL(int) mir_wstrcmpi(const wchar_t *p1, const wchar_t *p2); +MIR_CORE_DLL(int) mir_wstrncmpi(const wchar_t *p1, const wchar_t *p2, size_t n); + +MIR_CORE_DLL(char*) mir_strdup(const char* str); +MIR_CORE_DLL(wchar_t*) mir_wstrdup(const wchar_t* str); + +MIR_CORE_DLL(char*) mir_strndup(const char* str, size_t len); +MIR_CORE_DLL(wchar_t*) mir_wstrndup(const wchar_t *str, size_t len); + +MIR_CORE_DLL(const wchar_t*) mir_wstrstri(const wchar_t *s1, const wchar_t *s2); + +/////////////////////////////////////////////////////////////////////////////// +// print functions + +MIR_CORE_DLL(int) mir_snprintf(_Pre_notnull_ _Always_(_Post_z_) char *buffer, size_t count, _Printf_format_string_ const char* fmt, ...); +MIR_CORE_DLL(int) mir_snwprintf(_Pre_notnull_ _Always_(_Post_z_) wchar_t *buffer, size_t count, _Printf_format_string_ const wchar_t* fmt, ...); +MIR_CORE_DLL(int) mir_vsnprintf(_Pre_notnull_ _Always_(_Post_z_) char *buffer, size_t count, _Printf_format_string_ const char* fmt, va_list va); +MIR_CORE_DLL(int) mir_vsnwprintf(_Pre_notnull_ _Always_(_Post_z_) wchar_t *buffer, size_t count, _Printf_format_string_ const wchar_t* fmt, va_list va); + +/////////////////////////////////////////////////////////////////////////////// +// protocol functions + +struct PROTO_INTERFACE; + +MIR_APP_DLL(INT_PTR) ProtoBroadcastAck(const char *szModule, MCONTACT hContact, int type, int result, HANDLE hProcess, LPARAM lParam = 0); +MIR_APP_DLL(void) ProtoBroadcastAsync(const char *szModule, MCONTACT hContact, int type, int result, HANDLE hProcess, LPARAM lParam = 0); + +// avatar support functions + +// returns image extension by a PA_* constant or empty string for PA_FORMAT_UNKNOWN +MIR_APP_DLL(const wchar_t*) ProtoGetAvatarExtension(int format); + +// detects image format by extension +MIR_APP_DLL(int) ProtoGetAvatarFormat(const wchar_t *ptszFileName); + +// detects image format by its contents +MIR_APP_DLL(int) ProtoGetAvatarFileFormat(const wchar_t *ptszFileName); + +// returns the mime type according to a picture type (PA_*) passed +MIR_APP_DLL(const char*) ProtoGetAvatarMimeType(int iFileType); + +// returns the picture type (PA_*) according to a mime type passed +MIR_APP_DLL(int) ProtoGetAvatarFormatByMimeType(const char *pwszMimeType); + +// returns the image format and extension by the first bytes of picture +// ptszExtension might be NULL +#if defined( __cplusplus ) + MIR_APP_DLL(int) ProtoGetBufferFormat(const void *buf, const wchar_t **ptszExtension = nullptr); +#else + MIR_APP_DLL(int) ProtoGetBufferFormat(const void *buf, const wchar_t **ptszExtension); +#endif + +/////////////////////////////////////////////////////////////////////////////// +// sha1 functions + +#define MIR_SHA1_HASH_SIZE 20 +#define MIR_SHA_BLOCKSIZE 64 + +struct mir_sha1_ctx +{ + uint32_t H[5]; + uint32_t W[80]; + int lenW; + uint32_t sizeHi, sizeLo; +}; + +MIR_CORE_DLL(void) mir_sha1_init(mir_sha1_ctx *ctx); +MIR_CORE_DLL(void) mir_sha1_append(mir_sha1_ctx *ctx, const BYTE *dataIn, size_t len); +MIR_CORE_DLL(void) mir_sha1_finish(mir_sha1_ctx *ctx, BYTE hashout[MIR_SHA1_HASH_SIZE]); +MIR_CORE_DLL(void) mir_sha1_hash(BYTE *dataIn, size_t len, BYTE hashout[MIR_SHA1_HASH_SIZE]); + +/////////////////////////////////////////////////////////////////////////////// +// sha256 functions + +#define MIR_SHA256_HASH_SIZE 32 + +struct SHA256_CONTEXT +{ + uint32_t h0, h1, h2, h3, h4, h5, h6, h7; + uint32_t nblocks; + BYTE buf[MIR_SHA_BLOCKSIZE]; + int count; +}; + +MIR_CORE_DLL(void) mir_sha256_init(SHA256_CONTEXT *ctx); +MIR_CORE_DLL(void) mir_sha256_write(SHA256_CONTEXT *ctx, const void *dataIn, size_t len); +MIR_CORE_DLL(void) mir_sha256_final(SHA256_CONTEXT *ctx, BYTE hashout[MIR_SHA256_HASH_SIZE]); +MIR_CORE_DLL(void) mir_sha256_hash(const void *dataIn, size_t len, BYTE hashout[MIR_SHA256_HASH_SIZE]); + +/////////////////////////////////////////////////////////////////////////////// +// strings + +MIR_CORE_DLL(void*) mir_base64_decode(const char *input, size_t *outputLen); +MIR_CORE_DLL(char*) mir_base64_encode(const void *input, size_t inputLen); +MIR_CORE_DLL(char*) mir_base64_encodebuf(const void *input, size_t inputLen, char *output, size_t outLen); + +__forceinline size_t mir_base64_encode_bufsize(size_t inputLen) +{ + return 4 * ((inputLen + 2) / 3) + 1; +} + +MIR_CORE_DLL(char*) rtrim(char *str); +MIR_CORE_DLL(wchar_t*) rtrimw(wchar_t *str); + +MIR_CORE_DLL(char*) ltrim(char *str); // returns pointer to the beginning of string +MIR_CORE_DLL(wchar_t*) ltrimw(wchar_t *str); + +MIR_CORE_DLL(char*) ltrimp(char *str); // returns pointer to the trimmed portion of string +MIR_CORE_DLL(wchar_t*) ltrimpw(wchar_t *str); + +MIR_CORE_DLL(char*) strdel(char *str, size_t len); +MIR_CORE_DLL(wchar_t*) strdelw(wchar_t *str, size_t len); + +MIR_CORE_DLL(int) wildcmp(const char *name, const char *mask); +MIR_CORE_DLL(int) wildcmpw(const wchar_t *name, const wchar_t *mask); + +MIR_CORE_DLL(int) wildcmpi(const char *name, const char *mask); +MIR_CORE_DLL(int) wildcmpiw(const wchar_t *name, const wchar_t *mask); + +MIR_CORE_DLL(char*) bin2hex(const void *pData, size_t len, char *dest); +MIR_CORE_DLL(wchar_t*) bin2hexW(const void *pData, size_t len, wchar_t *dest); + +MIR_CORE_DLL(bool) hex2bin(const char *pSrc, void *pData, size_t len); +MIR_CORE_DLL(bool) hex2binW(const wchar_t *pSrc, void *pData, size_t len); + +__forceinline char* lrtrim(char *str) { return ltrim(rtrim(str)); }; +__forceinline char* lrtrimp(char *str) { return ltrimp(rtrim(str)); }; + +#if defined( __cplusplus ) + MIR_CORE_DLL(char*) replaceStr(char* &dest, const char *src); + MIR_CORE_DLL(wchar_t*) replaceStrW(wchar_t* &dest, const wchar_t *src); +#else + MIR_CORE_DLL(char*) replaceStr(char **dest, const char *src); + MIR_CORE_DLL(wchar_t*) replaceStrW(wchar_t **dest, const wchar_t *src); +#endif + +/////////////////////////////////////////////////////////////////////////////// +// text conversion functions + +union MAllStrings +{ + char *a; // utf8 or ansi strings + wchar_t *w; // strings of WCHARs +}; + +union MAllCStrings +{ + const char *a; // utf8 or ansi strings + const wchar_t *w; // strings of WCHARs +}; + +union MAllStringArray +{ + char **a; // array of utf8 or ansi strings + wchar_t **w; // array of strings of WCHARs +}; + +union MAllCStringArray +{ + const char **a; // array of utf8 or ansi strings + const wchar_t **w; // array of strings of WCHARs +}; + +MIR_CORE_DLL(wchar_t*) mir_a2u_cp(const char* src, int codepage); +MIR_CORE_DLL(wchar_t*) mir_a2u(const char* src); +MIR_CORE_DLL(char*) mir_u2a_cp(const wchar_t* src, int codepage); +MIR_CORE_DLL(char*) mir_u2a(const wchar_t* src); + +/////////////////////////////////////////////////////////////////////////////// +// threads + +typedef void (MIR_CDECL *pThreadFunc)(void *param); +typedef unsigned (MIR_SYSCALL *pThreadFuncEx)(void *param); +typedef unsigned (MIR_CDECL *pThreadFuncOwner)(void *owner, void *param); + +#if defined( __cplusplus ) + MIR_CORE_DLL(INT_PTR) Thread_Push(HINSTANCE hInst, void* pOwner = nullptr); +#else + MIR_CORE_DLL(INT_PTR) Thread_Push(HINSTANCE hInst, void* pOwner); +#endif +MIR_CORE_DLL(INT_PTR) Thread_Pop(void); +MIR_CORE_DLL(void) Thread_Wait(void); + +#if defined( __cplusplus ) +MIR_CORE_DLL(HANDLE) mir_forkthread(pThreadFunc aFunc, void *arg = nullptr); +MIR_CORE_DLL(HANDLE) mir_forkthreadex(pThreadFuncEx aFunc, void *arg = nullptr, unsigned *pThreadID = nullptr); +MIR_CORE_DLL(HANDLE) mir_forkthreadowner(pThreadFuncOwner aFunc, void *owner, void *arg = nullptr, unsigned *pThreadID = nullptr); +#else +MIR_CORE_DLL(HANDLE) mir_forkthread(pThreadFunc aFunc, void *arg); +MIR_CORE_DLL(HANDLE) mir_forkthreadex(pThreadFuncEx aFunc, void *arg, unsigned *pThreadID); +MIR_CORE_DLL(HANDLE) mir_forkthreadowner(pThreadFuncOwner aFunc, void *owner, void *arg, unsigned *pThreadID); +#endif + +MIR_CORE_DLL(void) Thread_SetName(const char *szThreadName); + +MIR_CORE_DLL(void) KillObjectThreads(void* pObject); + +/////////////////////////////////////////////////////////////////////////////// +// utf8 interface + +MIR_CORE_DLL(BOOL) Utf8CheckString(const char* str); +MIR_CORE_DLL(int) Utf8toUcs2(const char *src, size_t srclen, wchar_t *dst, size_t dstlen); // returns 0 on error + +MIR_CORE_DLL(char*) mir_utf8decode(char* str, wchar_t** ucs2); +MIR_CORE_DLL(char*) mir_utf8decodecp(char* str, int codepage, wchar_t** ucs2); +MIR_CORE_DLL(wchar_t*) mir_utf8decodeW(const char* str); + +MIR_CORE_DLL(char*) mir_utf8encode(const char* str); +MIR_CORE_DLL(char*) mir_utf8encodecp(const char* src, int codepage); +MIR_CORE_DLL(char*) mir_utf8encodeW(const wchar_t* str); + +MIR_CORE_DLL(int) mir_utf8lenW(const wchar_t *src); + +__forceinline char* mir_utf8decodeA(const char* src) +{ + char *tmp = mir_strdup(src); + mir_utf8decode(tmp, nullptr); + return tmp; +} + +/////////////////////////////////////////////////////////////////////////////// +// The UUID structure below is used to for plugin UUID's and module type definitions + +struct MUUID +{ + unsigned long a; + unsigned short b; + unsigned short c; + unsigned char d[8]; +}; + +__forceinline bool operator==(const MUUID &p1, const MUUID &p2) +{ + return memcmp(&p1, &p2, sizeof(MUUID)) == 0; +} +__forceinline bool operator!=(const MUUID &p1, const MUUID &p2) +{ + return memcmp(&p1, &p2, sizeof(MUUID)) != 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// Window subclassing + +#ifdef _MSC_VER + +MIR_CORE_DLL(void) mir_subclassWindow(HWND hWnd, WNDPROC wndProc); +MIR_CORE_DLL(void) mir_subclassWindowFull(HWND hWnd, WNDPROC wndProc, WNDPROC oldWndProc); +MIR_CORE_DLL(LRESULT) mir_callNextSubclass(HWND hWnd, WNDPROC wndProc, UINT uMsg, WPARAM wParam, LPARAM lParam); +MIR_CORE_DLL(void) mir_unsubclassWindow(HWND hWnd, WNDPROC wndProc); + +MIR_CORE_DLL(void) KillModuleSubclassing(HMODULE hInst); + +/////////////////////////////////////////////////////////////////////////////// +// Windows utilities + +MIR_CORE_DLL(BOOL) IsWinVerVistaPlus(); +MIR_CORE_DLL(BOOL) IsWinVer7Plus(); +MIR_CORE_DLL(BOOL) IsWinVer8Plus(); +MIR_CORE_DLL(BOOL) IsWinVer81Plus(); +MIR_CORE_DLL(BOOL) IsWinVer10Plus(); + +MIR_CORE_DLL(BOOL) IsFullScreen(); +MIR_CORE_DLL(BOOL) IsWorkstationLocked(); +MIR_CORE_DLL(BOOL) IsScreenSaverRunning(); +MIR_CORE_DLL(BOOL) IsTerminalDisconnected(); + +#endif // _MSC_VER + +// returns OS version in version of Windows NT xx.xx +MIR_CORE_DLL(BOOL) OS_GetShortString(char *buf, size_t bufSize); + +// returns full OS version +MIR_CORE_DLL(BOOL) OS_GetDisplayString(char *buf, size_t bufSize); + +/////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(void) UnloadCoreModule(void); + +#if defined(__cplusplus) +} + +template +HANDLE mir_forkThread(void(MIR_CDECL *pFunc)(T* param), T *arg) +{ + return mir_forkthread((pThreadFunc)pFunc, arg); +} + +template +inline int mir_snprintf(_Pre_notnull_ _Always_(_Post_z_) char(&buffer)[_Size], _In_z_ _Printf_format_string_ const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + int ret = mir_vsnprintf(buffer, _Size, fmt, args); + va_end(args); + return ret; +} + +template +inline int mir_snwprintf(_Pre_notnull_ _Always_(_Post_z_) wchar_t(&buffer)[_Size], _In_z_ _Printf_format_string_ const wchar_t* fmt, ...) +{ + va_list args; + va_start(args, fmt); + int ret = mir_vsnwprintf(buffer, _Size, fmt, args); + va_end(args); + return ret; +} + +template +inline int mir_vsnprintf(_Pre_notnull_ _Always_(_Post_z_) char(&buffer)[_Size], _In_z_ _Printf_format_string_ const char* fmt, va_list va) +{ + return mir_vsnprintf(buffer, _Size, fmt, va); +} + +template +inline int mir_vsnwprintf(_Pre_notnull_ _Always_(_Post_z_) wchar_t(&buffer)[_Size], _In_z_ _Printf_format_string_ const wchar_t* fmt, va_list va) +{ + return mir_vsnwprintf(buffer, _Size, fmt, va); +} + +#endif + +#ifdef _MSC_VER + #ifndef MIR_CORE_EXPORTS + #pragma comment(lib, "mir_core.lib") + #endif + + #ifndef MIR_APP_EXPORTS + #pragma comment(lib, "mir_app.lib") + #endif +#else + MIR_CORE_DLL(FILE*) _wfopen(const wchar_t *pwszFileName, const wchar_t *pwszMode); + + template + inline wchar_t* wcsncpy_s(wchar_t(&buffer)[_Size], const wchar_t *src, size_t len) + { + return wcsncpy(buffer, src, (len == _TRUNCATE) ? _Size : len); + } + + inline wchar_t* wcsncpy_s(wchar_t *dst, size_t dstLen, const wchar_t *src, size_t len) + { + return wcsncpy(dst, src, (len == _TRUNCATE) ? dstLen : len); + } + + inline wchar_t* wcsncat_s(wchar_t *dst, size_t dstLen, const wchar_t *src, size_t len) + { + return wcsncat(dst, src, (len == _TRUNCATE) ? dstLen : len); + } + + template + inline char* strncpy_s(char(&buffer)[_Size], const char *src, size_t len) + { + return strncpy(buffer, src, (len == _TRUNCATE) ? _Size : len); + } + + inline char* strncpy_s(char *dst, size_t dstLen, const char *src, size_t len) + { + return strncpy(dst, src, (len == _TRUNCATE) ? dstLen : len); + } + + inline char* strncat_s(char *dst, size_t dstLen, const char *src, size_t len) + { + return strncat(dst, src, (len == _TRUNCATE) ? dstLen : len); + } +#endif + +#endif // M_CORE_H diff --git a/include/m_database.h b/include/m_database.h index 5947ce1c4f..bf4e411815 100644 --- a/include/m_database.h +++ b/include/m_database.h @@ -1,793 +1,793 @@ -///////////////////////////////////////////////////////////////////////////////////////// -// Miranda NG: the free IM client for Microsoft* Windows* -// -// Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) -// Copyright (c) 2000-08 Miranda ICQ/IM project, -// all portions of this codebase are copyrighted to the people -// listed in contributors.txt. -// -// 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_DATABASE_H__ -#define M_DATABASE_H__ 1 - -///////////////////////////////////////////////////////////////////////////////////////// -// GENERALLY USEFUL STUFF - -#if !defined(M_SYSTEM_H__) - #include "m_system.h" -#endif - -#if !defined(M_UTILS_H__) - #include "m_utils.h" -#endif - -#ifdef _MSC_VER - #pragma warning(disable:4201 4204) -#endif - -///////////////////////////////////////////////////////////////////////////////////////// -// database functions - -// Switches safety settings on or off -// newSetting is TRUE initially. -// Miranda's database is normally protected against corruption by agressively -// flushing data to the disk on writes. If you're doing a lot of writes (eg in -// an import plugin) it can sometimes be desirable to switch this feature off to -// speed up the process. If you do switch it off, you must remember that crashes -// are far more likely to be catastrophic, so switch it back on at the earliest -// possible opportunity. -// Note that if you're doing a lot of setting writes, the flush is already delayed -// so you need not use this service for that purpose. - -EXTERN_C MIR_CORE_DLL(void) db_set_safety_mode(BOOL bNewMode); - -// Gets the number of contacts in the database, which does not count the user -// Returns the number of contacts. They can be retrieved using contact/findfirst and contact/findnext - -EXTERN_C MIR_CORE_DLL(int) db_get_contact_count(void); - -// Removes all settings for the specified module. -// hContact is 0 for global settings or matches the concrete contact - -EXTERN_C MIR_CORE_DLL(int) db_delete_module(MCONTACT hContact, const char *szModuleName); - -///////////////////////////////////////////////////////////////////////////////////////// -// contact functions - -// Adds a new contact to the database. New contacts initially have no settings -// whatsoever, they must all be added with db/contacts/writesetting. -// Returns a handle to the newly created contact on success, or NULL otherwise. -// Triggers a db/contact/added event just before it returns. - -EXTERN_C MIR_CORE_DLL(MCONTACT) db_add_contact(void); - -// Deletes the contact hContact from the database and all events and settings associated with it. -// Returns 0 on success or nonzero if hContact was invalid -// Please don't try to delete the user contact (hContact = NULL) -// Triggers a db/contact/deleted event just *before* it removes anything -// Because all events are deleted, lots of people may end up with invalid event -// handles from this operation, which they should be prepared for. - -EXTERN_C MIR_CORE_DLL(int) db_delete_contact(MCONTACT hContact); - -// Checks if a given value is a valid contact handle, note that due -// to the nature of multiple threading, a valid contact can still become -// invalid after a call to this service. -// Returns 1 if the contact is a contact, or 0 if the contact is not valid. - -EXTERN_C MIR_CORE_DLL(int) db_is_contact(MCONTACT hContact); - -///////////////////////////////////////////////////////////////////////////////////////// -// enumerators - -// Enumerates the names of all modules that have stored or requested information from the database. -// Returns the value returned by the last call to dbmep -// This service is only really useful for debugging, in conjunction with db/contact/enumsettings -// dbmep should return 0 to continue enumeration, or nonzero to stop. -// -// Modules names will be enumerated in no particular order -// Writing to the database while module names are being enumerated will cause -// unpredictable results in the enumeration, but the write will work. -// szModuleName is only guaranteed to be valid for the duration of the callback. -// If you want to keep it for longer you must allocation your own storage. - -typedef int(*DBMODULEENUMPROC)(const char *szModuleName, void *param); - -EXTERN_C MIR_CORE_DLL(int) db_enum_modules(DBMODULEENUMPROC dbmep, void *param = nullptr); - -// Lists all resident settings - -EXTERN_C MIR_CORE_DLL(int) db_enum_residents(DBMODULEENUMPROC pFunc, void *param = nullptr); - -// Lists all the settings a specific modules has stored in the database for a specific contact. -// Returns the return value of the last call to pfnEnumProc, or -1 if there are -// no settings for that module/contact pair -// Writing to or deleting from the database while enumerating will have -// unpredictable results for the enumeration, but the write will succeed. -// Use db/modules/enum to get a complete list of module names -// szSetting is only guaranteed to be valid for the duration of the callback. If -// you want to keep it for longer you must allocation your own storage. - -typedef int (*DBSETTINGENUMPROC)(const char *szSetting, void *param); - -EXTERN_C MIR_CORE_DLL(int) db_enum_settings(MCONTACT hContact, DBSETTINGENUMPROC pfnEnumProc, const char *szModule, void *param = nullptr); - -///////////////////////////////////////////////////////////////////////////////////////// -// DBVARIANT: used by db/contact/getsetting and db/contact/writesetting - -#define DBVT_DELETED 0 // this setting just got deleted, no other values are valid -#define DBVT_BYTE 1 // bVal and cVal are valid -#define DBVT_WORD 2 // wVal and sVal are valid -#define DBVT_DWORD 4 // dVal and lVal are valid -#define DBVT_ASCIIZ 255 // pszVal is valid -#define DBVT_BLOB 254 // cpbVal and pbVal are valid -#define DBVT_UTF8 253 // pszVal is valid -#define DBVT_WCHAR 252 // pwszVal is valid -#define DBVT_ENCRYPTED 250 // blob of encrypted bytesw - - -#define DBVTF_VARIABLELENGTH 0x80 - -struct DBVARIANT -{ - BYTE type; - union { - BYTE bVal; char cVal; - WORD wVal; short sVal; - DWORD dVal; long lVal; - struct { - union { - char *pszVal; - wchar_t *pwszVal; - }; - WORD cchVal; //only used for db/contact/getsettingstatic - }; - struct { - WORD cpbVal; - BYTE *pbVal; - }; - }; -}; - -#define DBEF_TEMPORARY 0x0001 // disable notifications about temporary database events -#define DBEF_SENT 0x0002 // this event was sent by the user. If not set this event was received. -#define DBEF_READ 0x0004 // event has been read by the user. It does not need to be processed any more except for history. -#define DBEF_RTL 0x0008 // event contains the right-to-left aligned text -#define DBEF_UTF 0x0010 // event contains a text in utf-8 -#define DBEF_ENCRYPTED 0x0020 // event is encrypted (never reported outside a driver) -#define DBEF_HAS_ID 0x0040 // event has unique server id - -struct DBEVENTINFO -{ - const char *szModule; // pointer to name of the module that 'owns' this event - DWORD timestamp; // seconds since 00:00, 01/01/1970. Gives us times until 2106 - // unless you use the standard C library which is - // signed and can only do until 2038. In GMT. - DWORD flags; // combination of DBEF_* flags - WORD eventType; // module-defined event type field - int cbBlob; // size of pBlob in bytes - PBYTE pBlob; // pointer to buffer containing module-defined event data - const char *szId; // server id - - bool __forceinline markedRead() const { - return (flags & (DBEF_SENT | DBEF_READ)) != 0; - } - - wchar_t* getString(const char *str) const { - return (flags & DBEF_UTF) ? mir_utf8decodeW(str) : mir_a2u(str); - } - - bool __forceinline operator==(const DBEVENTINFO &e) { - return (timestamp == e.timestamp && eventType == e.eventType && cbBlob == e.cbBlob && (flags & DBEF_SENT) == (e.flags & DBEF_SENT)); - } -}; - -EXTERN_C MIR_CORE_DLL(INT_PTR) db_free(DBVARIANT *dbv); - -///////////////////////////////////////////////////////////////////////////////////////// -// Database contacts - -// Gets the handle of the first contact in the database. This handle can be used -// with loads of functions. It does not need to be closed. -// You can specify szProto to find only its contacts -// Returns a handle to the first contact in the db on success, or NULL if there -// are no contacts in the db. - -EXTERN_C MIR_CORE_DLL(MCONTACT) db_find_first(const char *szProto = nullptr); - -// Gets the handle of the next contact after hContact in the database. This handle -// can be used with loads of functions. It does not need to be closed. -// You can specify szProto to find only its contacts -// Returns a handle to the contact after hContact in the db on success or NULL if -// hContact was the last contact in the db or hContact was invalid. - -EXTERN_C MIR_CORE_DLL(MCONTACT) db_find_next(MCONTACT hContact, const char *szProto = nullptr); - -class Contacts -{ - const char *m_szModule; - -public: - Contacts(const char *m = nullptr) : - m_szModule(m) - {} - - class iterator - { - MCONTACT hContact; - const char *m_szModule; - - public: - __inline iterator(const char *_m, MCONTACT _h) : - hContact(_h), - m_szModule(_m) - {} - - __inline iterator operator++() { hContact = ::db_find_next(hContact, m_szModule); return *this; } - __inline bool operator!=(const iterator &p) { return hContact != p.hContact; } - __inline operator const MCONTACT*() const { return &hContact; } - }; - - __inline iterator begin() const { return iterator(m_szModule, ::db_find_first(m_szModule)); } - __inline iterator end() const { return iterator(m_szModule, 0); } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Database events - -// Adds a new event to a contact's event list -// Returns a handle to the newly added event, or NULL on failure -// Triggers a db/event/added event just before it returns. -// Events are sorted chronologically as they are entered, so you cannot guarantee -// that the new hEvent is the last event in the chain, however if a new event is -// added that has a timestamp less than 90 seconds *before* the event that should -// be after it, it will be added afterwards, to allow for protocols that only -// store times to the nearest minute, and slight delays in transports. -// There are a few predefined eventTypes below for easier compatibility, but -// modules are free to define their own, beginning at 2000 -// DBEVENTINFO.timestamp is in GMT, as returned by time(). There are services -// db/time/x below with useful stuff for dealing with it. - -#define EVENTTYPE_MESSAGE 0 -#define EVENTTYPE_CONTACTS 2 //v0.1.2.2+ -#define EVENTTYPE_ADDED 1000 //v0.1.1.0+: these used to be module- -#define EVENTTYPE_AUTHREQUEST 1001 //specific codes, hence the module- -#define EVENTTYPE_FILE 1002 //specific limit has been raised to 2000 - -EXTERN_C MIR_CORE_DLL(MEVENT) db_event_add(MCONTACT hContact, const DBEVENTINFO *dbei); - -// Gets the number of events in the chain belonging to a contact in the database. -// Returns the number of events in the chain owned by hContact or -1 if hContact -// is invalid. They can be retrieved using the db_event_first/last() services. - -EXTERN_C MIR_CORE_DLL(int) db_event_count(MCONTACT hContact); - -// Removes a single event from the database -// hDbEvent should have been returned by db_event_add/first/last/next/prev() -// Returns 0 on success, or nonzero if hDbEvent was invalid -// Triggers a db/event/deleted event just *before* the event is deleted - -EXTERN_C MIR_CORE_DLL(int) db_event_delete(MEVENT hDbEvent); - -// Edits an event in the database -// Returns 0 on success, or nonzero on error - -EXTERN_C MIR_CORE_DLL(int) db_event_edit(MCONTACT hContact, MEVENT hDbEvent, const DBEVENTINFO *dbei); - -// Retrieves a handle to the first event in the chain for hContact -// Returns the handle, or NULL if hContact is invalid or has no events -// Events in a chain are sorted chronologically automatically - -EXTERN_C MIR_CORE_DLL(MEVENT) db_event_first(MCONTACT hContact); - -// Retrieves a handle to the first unread event in the chain for hContact -// Returns the handle, or NULL if hContact is invalid or all its events have been read -// -// Events in a chain are sorted chronologically automatically, but this does not -// necessarily mean that all events after the first unread are unread too. They -// should be checked individually with db_event_next() and db_event_get() -// This service is designed for startup, reloading all the events that remained -// unread from last time - -EXTERN_C MIR_CORE_DLL(MEVENT) db_event_firstUnread(MCONTACT hContact); - -// Retrieves all the information stored in hDbEvent -// hDbEvent should have been returned by db_event_add/first/last/next/prev() -// Returns 0 on success or nonzero if hDbEvent is invalid -// Don't forget to set dbe.cbSize, dbe.pBlob and dbe.cbBlob before calling this function -// The correct value dbe.cbBlob can be got using db_event_getBlobSize -// If successful, all the fields of dbe are filled. dbe.cbBlob is set to the -// actual number of bytes retrieved and put in dbe.pBlob -// If dbe.cbBlob is too small, dbe.pBlob is filled up to the size of dbe.cbBlob -// and then dbe.cbBlob is set to the required size of data to go in dbe.pBlob -// On return, dbe.szModule is a pointer to the database module's own internal list -// of modules. Look but don't touch. - -EXTERN_C MIR_CORE_DLL(int) db_event_get(MEVENT hDbEvent, DBEVENTINFO *dbei); - -// Retrieves the space in bytes required to store the blob in hDbEvent -// hDbEvent should have been returned by db_event_add/first/last/next/prev() -// Returns the space required in bytes, or -1 if hDbEvent is invalid - -EXTERN_C MIR_CORE_DLL(int) db_event_getBlobSize(MEVENT hDbEvent); - -// Retrieves a handle to the contact that owns hDbEvent. -// hDbEvent should have been returned by db_event_add/first/last/next/prev() -// NULL is a valid return value, meaning, as usual, the user. -// Returns INVALID_CONTACT_ID if hDbEvent is invalid, or the handle to the contact on success - -EXTERN_C MIR_CORE_DLL(MCONTACT) db_event_getContact(MEVENT hDbEvent); - -// Retrieves a handle to the last event in the chain for hContact -// Returns the handle, or NULL if hContact is invalid or has no events -// Events in a chain are sorted chronologically automatically - -EXTERN_C MIR_CORE_DLL(MEVENT) db_event_last(MCONTACT hContact); - -// Changes the flags for an event to mark it as read. -// hDbEvent should have been returned by db_event_add/first/last/next/prev() -// Returns the entire flag DWORD for the event after the change, or -1 if hDbEvent is invalid. -// This is the one database write operation that does not trigger an event. -// Modules should not save flags states for any length of time. - -EXTERN_C MIR_CORE_DLL(int) db_event_markRead(MCONTACT hContact, MEVENT hDbEvent); - -// Retrieves a handle to the next event in a chain after hDbEvent -// Returns the handle, or NULL if hDbEvent is invalid or is the last event -// Events in a chain are sorted chronologically automatically - -EXTERN_C MIR_CORE_DLL(MEVENT) db_event_next(MCONTACT hContact, MEVENT hDbEvent); - -// Retrieves a handle to the previous event in a chain before hDbEvent -// Returns the handle, or NULL if hDbEvent is invalid or is the first event -// Events in a chain are sorted chronologically automatically - -EXTERN_C MIR_CORE_DLL(MEVENT) db_event_prev(MCONTACT hContact, MEVENT hDbEvent); - -// Retrieves a handle to the event identified by its module and unique identifier - -EXTERN_C MIR_CORE_DLL(MEVENT) db_event_getById(const char *szModule, const char *szId); - -///////////////////////////////////////////////////////////////////////////////////////// -// Database settings - -EXTERN_C MIR_CORE_DLL(INT_PTR) db_get(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv); - -EXTERN_C MIR_CORE_DLL(int) db_get_b(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue = 0); -EXTERN_C MIR_CORE_DLL(int) db_get_w(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue = 0); -EXTERN_C MIR_CORE_DLL(DWORD) db_get_dw(MCONTACT hContact, const char *szModule, const char *szSetting, DWORD errorValue = 0); - -EXTERN_C MIR_CORE_DLL(char*) db_get_sa(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue = nullptr); -EXTERN_C MIR_CORE_DLL(char*) db_get_utfa(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue = nullptr); -EXTERN_C MIR_CORE_DLL(wchar_t*) db_get_wsa(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *szValue = nullptr); - -MIR_CORE_DLL(CMStringA) db_get_sm(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue = nullptr); -MIR_CORE_DLL(CMStringW) db_get_wsm(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *szValue = nullptr); - -EXTERN_C MIR_CORE_DLL(int) db_get_static(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest); -EXTERN_C MIR_CORE_DLL(int) db_get_static_utf(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest); -EXTERN_C MIR_CORE_DLL(int) db_get_wstatic(MCONTACT hContact, const char *szModule, const char *szSetting, wchar_t *pDest, int cbDest); - -EXTERN_C MIR_CORE_DLL(INT_PTR) db_set(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv); -EXTERN_C MIR_CORE_DLL(INT_PTR) db_set_b(MCONTACT hContact, const char *szModule, const char *szSetting, BYTE val); -EXTERN_C MIR_CORE_DLL(INT_PTR) db_set_w(MCONTACT hContact, const char *szModule, const char *szSetting, WORD val); -EXTERN_C MIR_CORE_DLL(INT_PTR) db_set_dw(MCONTACT hContact, const char *szModule, const char *szSetting, DWORD val); -EXTERN_C MIR_CORE_DLL(INT_PTR) db_set_s(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val); -EXTERN_C MIR_CORE_DLL(INT_PTR) db_set_ws(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *val); -EXTERN_C MIR_CORE_DLL(INT_PTR) db_set_utf(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val); -EXTERN_C MIR_CORE_DLL(INT_PTR) db_set_blob(MCONTACT hContact, const char *szModule, const char *szSetting, void *val, unsigned len); - -EXTERN_C MIR_CORE_DLL(INT_PTR) db_unset(MCONTACT hContact, const char *szModule, const char *szSetting); - -EXTERN_C MIR_CORE_DLL(BOOL) db_set_resident(const char *szModule, const char *szService, BOOL bEnable = true); - -EXTERN_C MIR_CORE_DLL(INT_PTR) db_get_s(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv, const int nType = DBVT_ASCIIZ); -#define db_get_ws(a,b,c,d) db_get_s(a,b,c,d,DBVT_WCHAR) -#define db_get_utf(a,b,c,d) db_get_s(a,b,c,d,DBVT_UTF8) - -///////////////////////////////////////////////////////////////////////////////////////// -// Profile services - -// Gets the name of the profile currently being used by the database module. -// This is the same as the filename of the database -// Returns 0 on success or nonzero otherwise - -EXTERN_C MIR_APP_DLL(int) Profile_GetNameA(size_t cbLen, char *pszDest); -EXTERN_C MIR_APP_DLL(int) Profile_GetNameW(size_t cbLen, wchar_t *pwszDest); - -// Get the path of the base folder where Miranda will store all individual profiles -// The returned path does NOT include a trailing backslash. -// Essentially this is what has been set in mirandaboot.ini as ProfileDir. -// For more options to retrieve profile paths check MS_UTILS_REPLACEVARS -// Returns 0 on success or nonzero otherwise - -EXTERN_C MIR_APP_DLL(int) Profile_GetPathA(size_t cbLen, char *pszDest); -EXTERN_C MIR_APP_DLL(int) Profile_GetPathW(size_t cbLen, wchar_t *pwszDest); - -// Sets the default profile name programmatically -// Analog of Database/DefaultProfile in mirandaboot.ini -EXTERN_C MIR_APP_DLL(void) Profile_SetDefault(const wchar_t *pwszPath); - -// Checks if a profile is opened -EXTERN_C MIR_APP_DLL(bool) Profile_CheckOpened(const wchar_t *pwszProfileName); - -// Read an option from mirandaboot.ini -EXTERN_C MIR_APP_DLL(int) Profile_GetSettingInt(const wchar_t *pwszSetting, int iDefault = 0); -EXTERN_C MIR_APP_DLL(bool) Profile_GetSetting(const wchar_t *pwszSetting, wchar_t *pwszBuf, size_t cbLen, const wchar_t *pwszDefault = nullptr); - -template -bool Profile_GetSetting(const wchar_t *pwszSetting, wchar_t(&pwszBuf)[_Size], const wchar_t *pwszDefault = nullptr) -{ - return Profile_GetSetting(pwszSetting, pwszBuf, _Size, pwszDefault); -} - -// Checks the specified profile like dbtool did. -// Implemented in the dbchecker plugins, thus it might not exist -// wParam = (WPARAM)(wchar_t*)ptszProfileName -// lParam = (BOOL)bConversionMode - -#define MS_DB_CHECKPROFILE "DB/CheckProfile" - -///////////////////////////////////////////////////////////////////////////////////////// -// Contact services - -struct DBCONTACTGETSETTING -{ - const char *szModule; // pointer to name of the module that wrote the setting to get - const char *szSetting; // pointer to name of the setting to get - DBVARIANT *pValue; // pointer to variant to receive the value -}; - -struct DBCONTACTWRITESETTING -{ - const char *szModule; // pointer to name of the module that wrote the setting to get - const char *szSetting; // pointer to name of the setting to get - DBVARIANT value; // variant containing the value to set -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Event services - -// Registers the specified database event type, with module, id & description. -// When someone needs to retrieve an event's text, a service named Module/GetEventText -// will be called. For example, for module named 'foo' and event id 2000 a service -// foo/GetEventText2000 should be defined to process this request. That handler should -// decode a blob and return the event text in the required format, its prototype is identical -// to a call of DbEvent_GetText (see below) -// -// Returns -1 on error (e.g., event type already registred), 0 on success - -struct DBEVENTTYPEDESCR -{ - LPSTR module; // event module name - DWORD flags; // flags, combination of the DETF_* - int eventType; // event id, unique for this module - LPSTR descr; // event type description (i.e. "File Transfer") - LPSTR textService; // service name for MS_DB_EVENT_GETTEXT (0.8+, default Module+'/GetEventText'+EvtID) - LPSTR iconService; // service name for MS_DB_EVENT_GETICON (0.8+, default Module+'/GetEventIcon'+EvtID) - HANDLE eventIcon; // icolib handle to eventicon (0.8+, default 'eventicon_'+Module+EvtID) -}; - -// constants for default event behaviour -#define DETF_HISTORY 1 // show event in history -#define DETF_MSGWINDOW 2 // show event in message window -#define DETF_NONOTIFY 4 // block event notify (e.g. Popups) - -EXTERN_C MIR_APP_DLL(int) DbEvent_RegisterType(DBEVENTTYPEDESCR*); - -///////////////////////////////////////////////////////////////////////////////////////// -// Retrieves the previously registered database event type, by module & id. -// Returns DBEVENTTYPEDESCR* or NULL, if an event isn't found. - -EXTERN_C MIR_APP_DLL(DBEVENTTYPEDESCR*) DbEvent_GetType(const char *szModule, int eventType); - -///////////////////////////////////////////////////////////////////////////////////////// -// macro to extract MCONTACT from the auth blob - -__forceinline MCONTACT DbGetAuthEventContact(DBEVENTINFO *dbei) -{ - return (MCONTACT)(*(DWORD*)&dbei->pBlob[sizeof(DWORD)]); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Retrieves the event's text -// * dbei should be the valid database event read via db_event_get() -// * codepage is any valid codepage, CP_ACP by default. -// -// Function returns a pointer to a string in the required format. -// This string should be freed by a call of mir_free - -EXTERN_C MIR_APP_DLL(char*) DbEvent_GetTextA(DBEVENTINFO *dbei, int codepage); -EXTERN_C MIR_APP_DLL(wchar_t*) DbEvent_GetTextW(DBEVENTINFO *dbei, int codepage); - -///////////////////////////////////////////////////////////////////////////////////////// -// Retrieves the event's icon -// * use LR_SHARED in flags for shared HICON -// dbei should be a valid database event read via db_event_get() -// -// Function returns HICON (use DestroyIcon to release resources if not LR_SHARED) -// -// A plugin can register the standard event icon in IcoLib named -// 'eventicon_'+Module+EvtID, like eventicon_ICQ2001. Otherwise, to declare an icon -// with the non-standard name, you can declare the special service, Module/GetEventIcon, -// which will retrieve the custom icon handle (HICON). This service function has the -// same parameters MS_DB_EVENT_GETICON does. - -EXTERN_C MIR_APP_DLL(HICON) DbEvent_GetIcon(DBEVENTINFO *dbei, int flags); - -///////////////////////////////////////////////////////////////////////////////////////// -// Converts the event's string to wchar_t* depending on the event's format -// returns wchar_t* - the converted string -// Caller must free the result using mir_free - -EXTERN_C MIR_APP_DLL(wchar_t*) DbEvent_GetString(DBEVENTINFO *dbei, const char *str); - -///////////////////////////////////////////////////////////////////////////////////////// -// Database events - -///////////////////////////////////////////////////////////////////////////////////////// -// DB/Event/Added event -// Called when a new event has been added to the event chain for a contact -// wParam = (MCONTACT)hContact -// lParam = (LPARAM)(HANDLE)hDbEvent -// hDbEvent is a valid handle to the event. hContact is a valid handle to the -// contact to which hDbEvent refers. -// Since events are sorted chronologically, you cannot guarantee that hDbEvent is -// at any particular position in the chain. - -#define ME_DB_EVENT_ADDED "DB/Event/Added" - -///////////////////////////////////////////////////////////////////////////////////////// -// DB/Event/Edited event -// Called when the existing event was changed -// wParam = (MCONTACT)hContact -// lParam = (LPARAM)(HANDLE)hDbEvent -// hDbEvent is a valid handle to the event. hContact is a valid handle to the -// contact to which hDbEvent refers. - -#define ME_DB_EVENT_EDITED "DB/Event/Edited" - -///////////////////////////////////////////////////////////////////////////////////////// -// DB/Event/FilterAdd (NOTE: Added during 0.3.3+ development!) -// Called **before** a new event is made of a DBEVENTINFO structure, this -// hook is not SAFE unless you know what you're doing with it, the arguments -// are passed as-is (with errors, pointer problems, if any) from any arguments -// passed to db_event_add. - -// The point of this hook is to stop any unwanted database events, to stop -// an event being added, return 1, to allow the event to pass through return 0. -// wParam = (MCONTACT)hContact -// lParam = (LPARAM)&DBEVENTINFO -// -// Any changed made to the said DBEVENTINFO are also passed along to the database, -// therefore it is possible to shape the data, however DO NOT DO THIS. - -#define ME_DB_EVENT_FILTER_ADD "DB/Event/FilterAdd" - -///////////////////////////////////////////////////////////////////////////////////////// -// DB/Event/Marked/Read event -// Called when an event is marked read -// wParam = (MCONTACT)hContact -// lParam = (LPARAM)(HANDLE)hDbEvent -// hDbEvent is a valid handle to the event. -// hContact is a valid handle to the contact to which hDbEvent refers, and will remain valid. - -#define ME_DB_EVENT_MARKED_READ "DB/Event/Marked/Read" - -///////////////////////////////////////////////////////////////////////////////////////// -// DB/Event/Deleted event -// Called when an event is about to be deleted from the event chain for a contact -// wParam = (MCONTACT)hContact -// lParam = (LPARAM)(HANDLE)hDbEvent -// hDbEvent is a valid handle to the event which is about to be deleted, but it -// won't be once your hook has returned. -// hContact is a valid handle to the contact to which hDbEvent refers, and will -// remain valid. -// Returning nonzero from your hook will not stop the deletion, but it will, as -// usual, stop other hooks from being called. - -#define ME_DB_EVENT_DELETED "DB/Event/Deleted" - -///////////////////////////////////////////////////////////////////////////////////////// -// DB/Contact/Added event -// Called when a new contact has been added to the database -// wParam = (MCONTACT)hContact -// lParam = 0 -// hContact is a valid handle to the new contact. -// Contacts are initially created without any settings, so if you hook this event -// you will almost certainly also want to hook db/contact/settingchanged as well. - -#define ME_DB_CONTACT_ADDED "DB/Contact/Added" - -///////////////////////////////////////////////////////////////////////////////////////// -// DB/Contact/Deleted event -// Called when an contact is about to be deleted -// wParam = (MCONTACT)hContact -// lParam = 0 -// hContact is a valid handle to the contact which is about to be deleted, but it -// won't be once your hook has returned. -// Returning nonzero from your hook will not stop the deletion, but it will, as -// usual, stop other hooks from being called. -// Deleting a contact invalidates all events in its chain. - -#define ME_DB_CONTACT_DELETED "DB/Contact/Deleted" - -///////////////////////////////////////////////////////////////////////////////////////// -// DB/Contact/SettingChanged event -// Called when a contact has had one of its settings changed -// wParam = (MCONTACT)hContact -// lParam = (LPARAM)(DBCONTACTWRITESETTING*)&dbcws -// hContact is a valid handle to the contact that has changed. -// This event will be triggered many times rapidly when a whole bunch of values are set. -// Modules which hook this should be aware of this fact and quickly return if they -// are not interested in the value that has been changed. -// Careful not to get into infinite loops with this event. -// The structure dbcws is the same one as is passed to the original service, so -// don't change any of the members. - -#define ME_DB_CONTACT_SETTINGCHANGED "DB/Contact/SettingChanged" - -///////////////////////////////////////////////////////////////////////////////////////// -// Settings helper functions - -#ifndef DB_NOHELPERFUNCTIONS - -///////////////////////////////////////////////////////////////////////////////////////// inlined range tolerate versions */ - -__inline BYTE DBGetContactSettingRangedByte(MCONTACT hContact, const char *szModule, const char *szSetting, BYTE errorValue, BYTE minValue, BYTE maxValue) -{ - BYTE bVal = db_get_b(hContact, szModule, szSetting, errorValue); - return (bVal < minValue || bVal > maxValue) ? errorValue : bVal; -} - -__inline WORD DBGetContactSettingRangedWord(MCONTACT hContact, const char *szModule, const char *szSetting, WORD errorValue, WORD minValue, WORD maxValue) -{ - WORD wVal = db_get_w(hContact, szModule, szSetting, errorValue); - return (wVal < minValue || wVal > maxValue) ? errorValue : wVal; -} - -__inline DWORD DBGetContactSettingRangedDword(MCONTACT hContact, const char *szModule, const char *szSetting, DWORD errorValue, DWORD minValue, DWORD maxValue) -{ - DWORD dwVal = db_get_dw(hContact, szModule, szSetting, errorValue); - return (dwVal < minValue || dwVal > maxValue) ? errorValue : dwVal; -} - -#endif - -namespace DB -{ - - ///////////////////////////////////////////////////////////////////////////////////////// - // Helper to free event contents automatically - - struct EventInfo : public DBEVENTINFO - { - __forceinline explicit EventInfo() - { - memset(this, 0, sizeof(*this)); - } - - __forceinline ~EventInfo() - { - mir_free(pBlob); - } - }; - - ///////////////////////////////////////////////////////////////////////////////////////// - // Helper to process the auth req body - // blob is: 0(DWORD), hContact(DWORD), nick(UTF8), firstName(UTF8), lastName(UTF8), email(UTF8), reason(UTF8) - - #pragma warning(disable : 4251) - - class MIR_APP_EXPORT AUTH_BLOB - { - MCONTACT m_hContact; - DWORD m_dwUin; - ptrA m_szNick, m_szFirstName, m_szLastName, m_szEmail, m_szReason; - DWORD m_size; - - PBYTE makeBlob(); - - public: - explicit AUTH_BLOB(MCONTACT hContact, const char *nick, const char *fname, const char *lname, const char *id, const char *reason); - explicit AUTH_BLOB(PBYTE blob); - ~AUTH_BLOB(); - - __forceinline operator char*() { return (char*)makeBlob(); } - __forceinline operator BYTE*() { return makeBlob(); } - - __forceinline DWORD size() const { return m_size; } - - __forceinline MCONTACT get_contact() const { return m_hContact; } - __forceinline const char* get_nick() const { return m_szNick; } - __forceinline const char* get_firstName() const { return m_szFirstName; } - __forceinline const char* get_lastName() const { return m_szLastName; } - __forceinline const char* get_email() const { return m_szEmail; } - __forceinline const char* get_reason() const { return m_szReason; } - - __forceinline DWORD get_uin() const { return m_dwUin; } - __forceinline void set_uin(DWORD dwValue) { m_dwUin = dwValue; } - }; - - ///////////////////////////////////////////////////////////////////////////////////////// - // Event cursors - - class MIR_CORE_EXPORT EventCursor : public MZeroedObject - { - friend class EventIterator; - - protected: - MCONTACT hContact; - - public: - EventCursor(MCONTACT _1) : - hContact(_1) - { } - - virtual ~EventCursor(); - virtual MEVENT FetchNext() = 0; - - __forceinline MEVENT begin() { - return FetchNext(); - } - - __forceinline MEVENT end() { - return 0; - } - }; - - class MIR_CORE_EXPORT ECPTR : public MNonCopyable - { - EventCursor *m_cursor; - MEVENT m_prevFetched, m_currEvent; - - public: - ECPTR(EventCursor *_1); - ~ECPTR(); - - void DeleteEvent(); - MEVENT FetchNext(); - }; - - class EventIterator - { - EventCursor *cursor; - MEVENT hCurr = 0; - - public: - EventIterator(EventCursor *_1) : - cursor(_1) - {} - - EventIterator operator++() { - hCurr = cursor->FetchNext(); - return *this; - } - - bool operator!=(const EventIterator &p) { - return hCurr != p.hCurr; - } - - operator MEVENT() const { - return hCurr; - } - }; - - MIR_CORE_DLL(EventCursor*) Events(MCONTACT, MEVENT iStartEvent = 0); - MIR_CORE_DLL(EventCursor*) EventsRev(MCONTACT, MEVENT iStartEvent = 0); -}; - -#endif // M_DATABASE_H__ +///////////////////////////////////////////////////////////////////////////////////////// +// Miranda NG: the free IM client for Microsoft* Windows* +// +// Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) +// Copyright (c) 2000-08 Miranda ICQ/IM project, +// all portions of this codebase are copyrighted to the people +// listed in contributors.txt. +// +// 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_DATABASE_H__ +#define M_DATABASE_H__ 1 + +///////////////////////////////////////////////////////////////////////////////////////// +// GENERALLY USEFUL STUFF + +#if !defined(M_SYSTEM_H__) + #include "m_system.h" +#endif + +#if !defined(M_UTILS_H__) + #include "m_utils.h" +#endif + +#ifdef _MSC_VER + #pragma warning(disable:4201 4204) +#endif + +///////////////////////////////////////////////////////////////////////////////////////// +// database functions + +// Switches safety settings on or off +// newSetting is TRUE initially. +// Miranda's database is normally protected against corruption by agressively +// flushing data to the disk on writes. If you're doing a lot of writes (eg in +// an import plugin) it can sometimes be desirable to switch this feature off to +// speed up the process. If you do switch it off, you must remember that crashes +// are far more likely to be catastrophic, so switch it back on at the earliest +// possible opportunity. +// Note that if you're doing a lot of setting writes, the flush is already delayed +// so you need not use this service for that purpose. + +EXTERN_C MIR_CORE_DLL(void) db_set_safety_mode(BOOL bNewMode); + +// Gets the number of contacts in the database, which does not count the user +// Returns the number of contacts. They can be retrieved using contact/findfirst and contact/findnext + +EXTERN_C MIR_CORE_DLL(int) db_get_contact_count(void); + +// Removes all settings for the specified module. +// hContact is 0 for global settings or matches the concrete contact + +EXTERN_C MIR_CORE_DLL(int) db_delete_module(MCONTACT hContact, const char *szModuleName); + +///////////////////////////////////////////////////////////////////////////////////////// +// contact functions + +// Adds a new contact to the database. New contacts initially have no settings +// whatsoever, they must all be added with db/contacts/writesetting. +// Returns a handle to the newly created contact on success, or NULL otherwise. +// Triggers a db/contact/added event just before it returns. + +EXTERN_C MIR_CORE_DLL(MCONTACT) db_add_contact(void); + +// Deletes the contact hContact from the database and all events and settings associated with it. +// Returns 0 on success or nonzero if hContact was invalid +// Please don't try to delete the user contact (hContact = NULL) +// Triggers a db/contact/deleted event just *before* it removes anything +// Because all events are deleted, lots of people may end up with invalid event +// handles from this operation, which they should be prepared for. + +EXTERN_C MIR_CORE_DLL(int) db_delete_contact(MCONTACT hContact); + +// Checks if a given value is a valid contact handle, note that due +// to the nature of multiple threading, a valid contact can still become +// invalid after a call to this service. +// Returns 1 if the contact is a contact, or 0 if the contact is not valid. + +EXTERN_C MIR_CORE_DLL(int) db_is_contact(MCONTACT hContact); + +///////////////////////////////////////////////////////////////////////////////////////// +// enumerators + +// Enumerates the names of all modules that have stored or requested information from the database. +// Returns the value returned by the last call to dbmep +// This service is only really useful for debugging, in conjunction with db/contact/enumsettings +// dbmep should return 0 to continue enumeration, or nonzero to stop. +// +// Modules names will be enumerated in no particular order +// Writing to the database while module names are being enumerated will cause +// unpredictable results in the enumeration, but the write will work. +// szModuleName is only guaranteed to be valid for the duration of the callback. +// If you want to keep it for longer you must allocation your own storage. + +typedef int(*DBMODULEENUMPROC)(const char *szModuleName, void *param); + +EXTERN_C MIR_CORE_DLL(int) db_enum_modules(DBMODULEENUMPROC dbmep, void *param = nullptr); + +// Lists all resident settings + +EXTERN_C MIR_CORE_DLL(int) db_enum_residents(DBMODULEENUMPROC pFunc, void *param = nullptr); + +// Lists all the settings a specific modules has stored in the database for a specific contact. +// Returns the return value of the last call to pfnEnumProc, or -1 if there are +// no settings for that module/contact pair +// Writing to or deleting from the database while enumerating will have +// unpredictable results for the enumeration, but the write will succeed. +// Use db/modules/enum to get a complete list of module names +// szSetting is only guaranteed to be valid for the duration of the callback. If +// you want to keep it for longer you must allocation your own storage. + +typedef int (*DBSETTINGENUMPROC)(const char *szSetting, void *param); + +EXTERN_C MIR_CORE_DLL(int) db_enum_settings(MCONTACT hContact, DBSETTINGENUMPROC pfnEnumProc, const char *szModule, void *param = nullptr); + +///////////////////////////////////////////////////////////////////////////////////////// +// DBVARIANT: used by db/contact/getsetting and db/contact/writesetting + +#define DBVT_DELETED 0 // this setting just got deleted, no other values are valid +#define DBVT_BYTE 1 // bVal and cVal are valid +#define DBVT_WORD 2 // wVal and sVal are valid +#define DBVT_DWORD 4 // dVal and lVal are valid +#define DBVT_ASCIIZ 255 // pszVal is valid +#define DBVT_BLOB 254 // cpbVal and pbVal are valid +#define DBVT_UTF8 253 // pszVal is valid +#define DBVT_WCHAR 252 // pwszVal is valid +#define DBVT_ENCRYPTED 250 // blob of encrypted bytesw + + +#define DBVTF_VARIABLELENGTH 0x80 + +struct DBVARIANT +{ + BYTE type; + union { + BYTE bVal; char cVal; + WORD wVal; short sVal; + DWORD dVal; long lVal; + struct { + union { + char *pszVal; + wchar_t *pwszVal; + }; + WORD cchVal; //only used for db/contact/getsettingstatic + }; + struct { + WORD cpbVal; + BYTE *pbVal; + }; + }; +}; + +#define DBEF_TEMPORARY 0x0001 // disable notifications about temporary database events +#define DBEF_SENT 0x0002 // this event was sent by the user. If not set this event was received. +#define DBEF_READ 0x0004 // event has been read by the user. It does not need to be processed any more except for history. +#define DBEF_RTL 0x0008 // event contains the right-to-left aligned text +#define DBEF_UTF 0x0010 // event contains a text in utf-8 +#define DBEF_ENCRYPTED 0x0020 // event is encrypted (never reported outside a driver) +#define DBEF_HAS_ID 0x0040 // event has unique server id + +struct DBEVENTINFO +{ + const char *szModule; // pointer to name of the module that 'owns' this event + DWORD timestamp; // seconds since 00:00, 01/01/1970. Gives us times until 2106 + // unless you use the standard C library which is + // signed and can only do until 2038. In GMT. + DWORD flags; // combination of DBEF_* flags + WORD eventType; // module-defined event type field + int cbBlob; // size of pBlob in bytes + uint8_t *pBlob; // pointer to buffer containing module-defined event data + const char *szId; // server id + + bool __forceinline markedRead() const { + return (flags & (DBEF_SENT | DBEF_READ)) != 0; + } + + wchar_t* getString(const char *str) const { + return (flags & DBEF_UTF) ? mir_utf8decodeW(str) : mir_a2u(str); + } + + bool __forceinline operator==(const DBEVENTINFO &e) { + return (timestamp == e.timestamp && eventType == e.eventType && cbBlob == e.cbBlob && (flags & DBEF_SENT) == (e.flags & DBEF_SENT)); + } +}; + +EXTERN_C MIR_CORE_DLL(INT_PTR) db_free(DBVARIANT *dbv); + +///////////////////////////////////////////////////////////////////////////////////////// +// Database contacts + +// Gets the handle of the first contact in the database. This handle can be used +// with loads of functions. It does not need to be closed. +// You can specify szProto to find only its contacts +// Returns a handle to the first contact in the db on success, or NULL if there +// are no contacts in the db. + +EXTERN_C MIR_CORE_DLL(MCONTACT) db_find_first(const char *szProto = nullptr); + +// Gets the handle of the next contact after hContact in the database. This handle +// can be used with loads of functions. It does not need to be closed. +// You can specify szProto to find only its contacts +// Returns a handle to the contact after hContact in the db on success or NULL if +// hContact was the last contact in the db or hContact was invalid. + +EXTERN_C MIR_CORE_DLL(MCONTACT) db_find_next(MCONTACT hContact, const char *szProto = nullptr); + +class Contacts +{ + const char *m_szModule; + +public: + Contacts(const char *m = nullptr) : + m_szModule(m) + {} + + class iterator + { + MCONTACT hContact; + const char *m_szModule; + + public: + __inline iterator(const char *_m, MCONTACT _h) : + hContact(_h), + m_szModule(_m) + {} + + __inline iterator operator++() { hContact = ::db_find_next(hContact, m_szModule); return *this; } + __inline bool operator!=(const iterator &p) { return hContact != p.hContact; } + __inline operator const MCONTACT*() const { return &hContact; } + }; + + __inline iterator begin() const { return iterator(m_szModule, ::db_find_first(m_szModule)); } + __inline iterator end() const { return iterator(m_szModule, 0); } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Database events + +// Adds a new event to a contact's event list +// Returns a handle to the newly added event, or NULL on failure +// Triggers a db/event/added event just before it returns. +// Events are sorted chronologically as they are entered, so you cannot guarantee +// that the new hEvent is the last event in the chain, however if a new event is +// added that has a timestamp less than 90 seconds *before* the event that should +// be after it, it will be added afterwards, to allow for protocols that only +// store times to the nearest minute, and slight delays in transports. +// There are a few predefined eventTypes below for easier compatibility, but +// modules are free to define their own, beginning at 2000 +// DBEVENTINFO.timestamp is in GMT, as returned by time(). There are services +// db/time/x below with useful stuff for dealing with it. + +#define EVENTTYPE_MESSAGE 0 +#define EVENTTYPE_CONTACTS 2 //v0.1.2.2+ +#define EVENTTYPE_ADDED 1000 //v0.1.1.0+: these used to be module- +#define EVENTTYPE_AUTHREQUEST 1001 //specific codes, hence the module- +#define EVENTTYPE_FILE 1002 //specific limit has been raised to 2000 + +EXTERN_C MIR_CORE_DLL(MEVENT) db_event_add(MCONTACT hContact, const DBEVENTINFO *dbei); + +// Gets the number of events in the chain belonging to a contact in the database. +// Returns the number of events in the chain owned by hContact or -1 if hContact +// is invalid. They can be retrieved using the db_event_first/last() services. + +EXTERN_C MIR_CORE_DLL(int) db_event_count(MCONTACT hContact); + +// Removes a single event from the database +// hDbEvent should have been returned by db_event_add/first/last/next/prev() +// Returns 0 on success, or nonzero if hDbEvent was invalid +// Triggers a db/event/deleted event just *before* the event is deleted + +EXTERN_C MIR_CORE_DLL(int) db_event_delete(MEVENT hDbEvent); + +// Edits an event in the database +// Returns 0 on success, or nonzero on error + +EXTERN_C MIR_CORE_DLL(int) db_event_edit(MCONTACT hContact, MEVENT hDbEvent, const DBEVENTINFO *dbei); + +// Retrieves a handle to the first event in the chain for hContact +// Returns the handle, or NULL if hContact is invalid or has no events +// Events in a chain are sorted chronologically automatically + +EXTERN_C MIR_CORE_DLL(MEVENT) db_event_first(MCONTACT hContact); + +// Retrieves a handle to the first unread event in the chain for hContact +// Returns the handle, or NULL if hContact is invalid or all its events have been read +// +// Events in a chain are sorted chronologically automatically, but this does not +// necessarily mean that all events after the first unread are unread too. They +// should be checked individually with db_event_next() and db_event_get() +// This service is designed for startup, reloading all the events that remained +// unread from last time + +EXTERN_C MIR_CORE_DLL(MEVENT) db_event_firstUnread(MCONTACT hContact); + +// Retrieves all the information stored in hDbEvent +// hDbEvent should have been returned by db_event_add/first/last/next/prev() +// Returns 0 on success or nonzero if hDbEvent is invalid +// Don't forget to set dbe.cbSize, dbe.pBlob and dbe.cbBlob before calling this function +// The correct value dbe.cbBlob can be got using db_event_getBlobSize +// If successful, all the fields of dbe are filled. dbe.cbBlob is set to the +// actual number of bytes retrieved and put in dbe.pBlob +// If dbe.cbBlob is too small, dbe.pBlob is filled up to the size of dbe.cbBlob +// and then dbe.cbBlob is set to the required size of data to go in dbe.pBlob +// On return, dbe.szModule is a pointer to the database module's own internal list +// of modules. Look but don't touch. + +EXTERN_C MIR_CORE_DLL(int) db_event_get(MEVENT hDbEvent, DBEVENTINFO *dbei); + +// Retrieves the space in bytes required to store the blob in hDbEvent +// hDbEvent should have been returned by db_event_add/first/last/next/prev() +// Returns the space required in bytes, or -1 if hDbEvent is invalid + +EXTERN_C MIR_CORE_DLL(int) db_event_getBlobSize(MEVENT hDbEvent); + +// Retrieves a handle to the contact that owns hDbEvent. +// hDbEvent should have been returned by db_event_add/first/last/next/prev() +// NULL is a valid return value, meaning, as usual, the user. +// Returns INVALID_CONTACT_ID if hDbEvent is invalid, or the handle to the contact on success + +EXTERN_C MIR_CORE_DLL(MCONTACT) db_event_getContact(MEVENT hDbEvent); + +// Retrieves a handle to the last event in the chain for hContact +// Returns the handle, or NULL if hContact is invalid or has no events +// Events in a chain are sorted chronologically automatically + +EXTERN_C MIR_CORE_DLL(MEVENT) db_event_last(MCONTACT hContact); + +// Changes the flags for an event to mark it as read. +// hDbEvent should have been returned by db_event_add/first/last/next/prev() +// Returns the entire flag DWORD for the event after the change, or -1 if hDbEvent is invalid. +// This is the one database write operation that does not trigger an event. +// Modules should not save flags states for any length of time. + +EXTERN_C MIR_CORE_DLL(int) db_event_markRead(MCONTACT hContact, MEVENT hDbEvent); + +// Retrieves a handle to the next event in a chain after hDbEvent +// Returns the handle, or NULL if hDbEvent is invalid or is the last event +// Events in a chain are sorted chronologically automatically + +EXTERN_C MIR_CORE_DLL(MEVENT) db_event_next(MCONTACT hContact, MEVENT hDbEvent); + +// Retrieves a handle to the previous event in a chain before hDbEvent +// Returns the handle, or NULL if hDbEvent is invalid or is the first event +// Events in a chain are sorted chronologically automatically + +EXTERN_C MIR_CORE_DLL(MEVENT) db_event_prev(MCONTACT hContact, MEVENT hDbEvent); + +// Retrieves a handle to the event identified by its module and unique identifier + +EXTERN_C MIR_CORE_DLL(MEVENT) db_event_getById(const char *szModule, const char *szId); + +///////////////////////////////////////////////////////////////////////////////////////// +// Database settings + +EXTERN_C MIR_CORE_DLL(INT_PTR) db_get(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv); + +EXTERN_C MIR_CORE_DLL(int) db_get_b(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue = 0); +EXTERN_C MIR_CORE_DLL(int) db_get_w(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue = 0); +EXTERN_C MIR_CORE_DLL(DWORD) db_get_dw(MCONTACT hContact, const char *szModule, const char *szSetting, DWORD errorValue = 0); + +EXTERN_C MIR_CORE_DLL(char*) db_get_sa(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue = nullptr); +EXTERN_C MIR_CORE_DLL(char*) db_get_utfa(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue = nullptr); +EXTERN_C MIR_CORE_DLL(wchar_t*) db_get_wsa(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *szValue = nullptr); + +MIR_CORE_DLL(CMStringA) db_get_sm(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue = nullptr); +MIR_CORE_DLL(CMStringW) db_get_wsm(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *szValue = nullptr); + +EXTERN_C MIR_CORE_DLL(int) db_get_static(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest); +EXTERN_C MIR_CORE_DLL(int) db_get_static_utf(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest); +EXTERN_C MIR_CORE_DLL(int) db_get_wstatic(MCONTACT hContact, const char *szModule, const char *szSetting, wchar_t *pDest, int cbDest); + +EXTERN_C MIR_CORE_DLL(INT_PTR) db_set(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv); +EXTERN_C MIR_CORE_DLL(INT_PTR) db_set_b(MCONTACT hContact, const char *szModule, const char *szSetting, BYTE val); +EXTERN_C MIR_CORE_DLL(INT_PTR) db_set_w(MCONTACT hContact, const char *szModule, const char *szSetting, WORD val); +EXTERN_C MIR_CORE_DLL(INT_PTR) db_set_dw(MCONTACT hContact, const char *szModule, const char *szSetting, DWORD val); +EXTERN_C MIR_CORE_DLL(INT_PTR) db_set_s(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val); +EXTERN_C MIR_CORE_DLL(INT_PTR) db_set_ws(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *val); +EXTERN_C MIR_CORE_DLL(INT_PTR) db_set_utf(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val); +EXTERN_C MIR_CORE_DLL(INT_PTR) db_set_blob(MCONTACT hContact, const char *szModule, const char *szSetting, void *val, unsigned len); + +EXTERN_C MIR_CORE_DLL(INT_PTR) db_unset(MCONTACT hContact, const char *szModule, const char *szSetting); + +EXTERN_C MIR_CORE_DLL(BOOL) db_set_resident(const char *szModule, const char *szService, BOOL bEnable = true); + +EXTERN_C MIR_CORE_DLL(INT_PTR) db_get_s(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv, const int nType = DBVT_ASCIIZ); +#define db_get_ws(a,b,c,d) db_get_s(a,b,c,d,DBVT_WCHAR) +#define db_get_utf(a,b,c,d) db_get_s(a,b,c,d,DBVT_UTF8) + +///////////////////////////////////////////////////////////////////////////////////////// +// Profile services + +// Gets the name of the profile currently being used by the database module. +// This is the same as the filename of the database +// Returns 0 on success or nonzero otherwise + +EXTERN_C MIR_APP_DLL(int) Profile_GetNameA(size_t cbLen, char *pszDest); +EXTERN_C MIR_APP_DLL(int) Profile_GetNameW(size_t cbLen, wchar_t *pwszDest); + +// Get the path of the base folder where Miranda will store all individual profiles +// The returned path does NOT include a trailing backslash. +// Essentially this is what has been set in mirandaboot.ini as ProfileDir. +// For more options to retrieve profile paths check MS_UTILS_REPLACEVARS +// Returns 0 on success or nonzero otherwise + +EXTERN_C MIR_APP_DLL(int) Profile_GetPathA(size_t cbLen, char *pszDest); +EXTERN_C MIR_APP_DLL(int) Profile_GetPathW(size_t cbLen, wchar_t *pwszDest); + +// Sets the default profile name programmatically +// Analog of Database/DefaultProfile in mirandaboot.ini +EXTERN_C MIR_APP_DLL(void) Profile_SetDefault(const wchar_t *pwszPath); + +// Checks if a profile is opened +EXTERN_C MIR_APP_DLL(bool) Profile_CheckOpened(const wchar_t *pwszProfileName); + +// Read an option from mirandaboot.ini +EXTERN_C MIR_APP_DLL(int) Profile_GetSettingInt(const wchar_t *pwszSetting, int iDefault = 0); +EXTERN_C MIR_APP_DLL(bool) Profile_GetSetting(const wchar_t *pwszSetting, wchar_t *pwszBuf, size_t cbLen, const wchar_t *pwszDefault = nullptr); + +template +bool Profile_GetSetting(const wchar_t *pwszSetting, wchar_t(&pwszBuf)[_Size], const wchar_t *pwszDefault = nullptr) +{ + return Profile_GetSetting(pwszSetting, pwszBuf, _Size, pwszDefault); +} + +// Checks the specified profile like dbtool did. +// Implemented in the dbchecker plugins, thus it might not exist +// wParam = (WPARAM)(wchar_t*)ptszProfileName +// lParam = (BOOL)bConversionMode + +#define MS_DB_CHECKPROFILE "DB/CheckProfile" + +///////////////////////////////////////////////////////////////////////////////////////// +// Contact services + +struct DBCONTACTGETSETTING +{ + const char *szModule; // pointer to name of the module that wrote the setting to get + const char *szSetting; // pointer to name of the setting to get + DBVARIANT *pValue; // pointer to variant to receive the value +}; + +struct DBCONTACTWRITESETTING +{ + const char *szModule; // pointer to name of the module that wrote the setting to get + const char *szSetting; // pointer to name of the setting to get + DBVARIANT value; // variant containing the value to set +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Event services + +// Registers the specified database event type, with module, id & description. +// When someone needs to retrieve an event's text, a service named Module/GetEventText +// will be called. For example, for module named 'foo' and event id 2000 a service +// foo/GetEventText2000 should be defined to process this request. That handler should +// decode a blob and return the event text in the required format, its prototype is identical +// to a call of DbEvent_GetText (see below) +// +// Returns -1 on error (e.g., event type already registred), 0 on success + +struct DBEVENTTYPEDESCR +{ + LPSTR module; // event module name + DWORD flags; // flags, combination of the DETF_* + int eventType; // event id, unique for this module + LPSTR descr; // event type description (i.e. "File Transfer") + LPSTR textService; // service name for MS_DB_EVENT_GETTEXT (0.8+, default Module+'/GetEventText'+EvtID) + LPSTR iconService; // service name for MS_DB_EVENT_GETICON (0.8+, default Module+'/GetEventIcon'+EvtID) + HANDLE eventIcon; // icolib handle to eventicon (0.8+, default 'eventicon_'+Module+EvtID) +}; + +// constants for default event behaviour +#define DETF_HISTORY 1 // show event in history +#define DETF_MSGWINDOW 2 // show event in message window +#define DETF_NONOTIFY 4 // block event notify (e.g. Popups) + +EXTERN_C MIR_APP_DLL(int) DbEvent_RegisterType(DBEVENTTYPEDESCR*); + +///////////////////////////////////////////////////////////////////////////////////////// +// Retrieves the previously registered database event type, by module & id. +// Returns DBEVENTTYPEDESCR* or NULL, if an event isn't found. + +EXTERN_C MIR_APP_DLL(DBEVENTTYPEDESCR*) DbEvent_GetType(const char *szModule, int eventType); + +///////////////////////////////////////////////////////////////////////////////////////// +// macro to extract MCONTACT from the auth blob + +__forceinline MCONTACT DbGetAuthEventContact(DBEVENTINFO *dbei) +{ + return (MCONTACT)(*(DWORD*)&dbei->pBlob[sizeof(DWORD)]); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Retrieves the event's text +// * dbei should be the valid database event read via db_event_get() +// * codepage is any valid codepage, CP_ACP by default. +// +// Function returns a pointer to a string in the required format. +// This string should be freed by a call of mir_free + +EXTERN_C MIR_APP_DLL(char*) DbEvent_GetTextA(DBEVENTINFO *dbei, int codepage); +EXTERN_C MIR_APP_DLL(wchar_t*) DbEvent_GetTextW(DBEVENTINFO *dbei, int codepage); + +///////////////////////////////////////////////////////////////////////////////////////// +// Retrieves the event's icon +// * use LR_SHARED in flags for shared HICON +// dbei should be a valid database event read via db_event_get() +// +// Function returns HICON (use DestroyIcon to release resources if not LR_SHARED) +// +// A plugin can register the standard event icon in IcoLib named +// 'eventicon_'+Module+EvtID, like eventicon_ICQ2001. Otherwise, to declare an icon +// with the non-standard name, you can declare the special service, Module/GetEventIcon, +// which will retrieve the custom icon handle (HICON). This service function has the +// same parameters MS_DB_EVENT_GETICON does. + +EXTERN_C MIR_APP_DLL(HICON) DbEvent_GetIcon(DBEVENTINFO *dbei, int flags); + +///////////////////////////////////////////////////////////////////////////////////////// +// Converts the event's string to wchar_t* depending on the event's format +// returns wchar_t* - the converted string +// Caller must free the result using mir_free + +EXTERN_C MIR_APP_DLL(wchar_t*) DbEvent_GetString(DBEVENTINFO *dbei, const char *str); + +///////////////////////////////////////////////////////////////////////////////////////// +// Database events + +///////////////////////////////////////////////////////////////////////////////////////// +// DB/Event/Added event +// Called when a new event has been added to the event chain for a contact +// wParam = (MCONTACT)hContact +// lParam = (LPARAM)(HANDLE)hDbEvent +// hDbEvent is a valid handle to the event. hContact is a valid handle to the +// contact to which hDbEvent refers. +// Since events are sorted chronologically, you cannot guarantee that hDbEvent is +// at any particular position in the chain. + +#define ME_DB_EVENT_ADDED "DB/Event/Added" + +///////////////////////////////////////////////////////////////////////////////////////// +// DB/Event/Edited event +// Called when the existing event was changed +// wParam = (MCONTACT)hContact +// lParam = (LPARAM)(HANDLE)hDbEvent +// hDbEvent is a valid handle to the event. hContact is a valid handle to the +// contact to which hDbEvent refers. + +#define ME_DB_EVENT_EDITED "DB/Event/Edited" + +///////////////////////////////////////////////////////////////////////////////////////// +// DB/Event/FilterAdd (NOTE: Added during 0.3.3+ development!) +// Called **before** a new event is made of a DBEVENTINFO structure, this +// hook is not SAFE unless you know what you're doing with it, the arguments +// are passed as-is (with errors, pointer problems, if any) from any arguments +// passed to db_event_add. + +// The point of this hook is to stop any unwanted database events, to stop +// an event being added, return 1, to allow the event to pass through return 0. +// wParam = (MCONTACT)hContact +// lParam = (LPARAM)&DBEVENTINFO +// +// Any changed made to the said DBEVENTINFO are also passed along to the database, +// therefore it is possible to shape the data, however DO NOT DO THIS. + +#define ME_DB_EVENT_FILTER_ADD "DB/Event/FilterAdd" + +///////////////////////////////////////////////////////////////////////////////////////// +// DB/Event/Marked/Read event +// Called when an event is marked read +// wParam = (MCONTACT)hContact +// lParam = (LPARAM)(HANDLE)hDbEvent +// hDbEvent is a valid handle to the event. +// hContact is a valid handle to the contact to which hDbEvent refers, and will remain valid. + +#define ME_DB_EVENT_MARKED_READ "DB/Event/Marked/Read" + +///////////////////////////////////////////////////////////////////////////////////////// +// DB/Event/Deleted event +// Called when an event is about to be deleted from the event chain for a contact +// wParam = (MCONTACT)hContact +// lParam = (LPARAM)(HANDLE)hDbEvent +// hDbEvent is a valid handle to the event which is about to be deleted, but it +// won't be once your hook has returned. +// hContact is a valid handle to the contact to which hDbEvent refers, and will +// remain valid. +// Returning nonzero from your hook will not stop the deletion, but it will, as +// usual, stop other hooks from being called. + +#define ME_DB_EVENT_DELETED "DB/Event/Deleted" + +///////////////////////////////////////////////////////////////////////////////////////// +// DB/Contact/Added event +// Called when a new contact has been added to the database +// wParam = (MCONTACT)hContact +// lParam = 0 +// hContact is a valid handle to the new contact. +// Contacts are initially created without any settings, so if you hook this event +// you will almost certainly also want to hook db/contact/settingchanged as well. + +#define ME_DB_CONTACT_ADDED "DB/Contact/Added" + +///////////////////////////////////////////////////////////////////////////////////////// +// DB/Contact/Deleted event +// Called when an contact is about to be deleted +// wParam = (MCONTACT)hContact +// lParam = 0 +// hContact is a valid handle to the contact which is about to be deleted, but it +// won't be once your hook has returned. +// Returning nonzero from your hook will not stop the deletion, but it will, as +// usual, stop other hooks from being called. +// Deleting a contact invalidates all events in its chain. + +#define ME_DB_CONTACT_DELETED "DB/Contact/Deleted" + +///////////////////////////////////////////////////////////////////////////////////////// +// DB/Contact/SettingChanged event +// Called when a contact has had one of its settings changed +// wParam = (MCONTACT)hContact +// lParam = (LPARAM)(DBCONTACTWRITESETTING*)&dbcws +// hContact is a valid handle to the contact that has changed. +// This event will be triggered many times rapidly when a whole bunch of values are set. +// Modules which hook this should be aware of this fact and quickly return if they +// are not interested in the value that has been changed. +// Careful not to get into infinite loops with this event. +// The structure dbcws is the same one as is passed to the original service, so +// don't change any of the members. + +#define ME_DB_CONTACT_SETTINGCHANGED "DB/Contact/SettingChanged" + +///////////////////////////////////////////////////////////////////////////////////////// +// Settings helper functions + +#ifndef DB_NOHELPERFUNCTIONS + +///////////////////////////////////////////////////////////////////////////////////////// inlined range tolerate versions */ + +__inline BYTE DBGetContactSettingRangedByte(MCONTACT hContact, const char *szModule, const char *szSetting, BYTE errorValue, BYTE minValue, BYTE maxValue) +{ + BYTE bVal = db_get_b(hContact, szModule, szSetting, errorValue); + return (bVal < minValue || bVal > maxValue) ? errorValue : bVal; +} + +__inline WORD DBGetContactSettingRangedWord(MCONTACT hContact, const char *szModule, const char *szSetting, WORD errorValue, WORD minValue, WORD maxValue) +{ + WORD wVal = db_get_w(hContact, szModule, szSetting, errorValue); + return (wVal < minValue || wVal > maxValue) ? errorValue : wVal; +} + +__inline DWORD DBGetContactSettingRangedDword(MCONTACT hContact, const char *szModule, const char *szSetting, DWORD errorValue, DWORD minValue, DWORD maxValue) +{ + DWORD dwVal = db_get_dw(hContact, szModule, szSetting, errorValue); + return (dwVal < minValue || dwVal > maxValue) ? errorValue : dwVal; +} + +#endif + +namespace DB +{ + + ///////////////////////////////////////////////////////////////////////////////////////// + // Helper to free event contents automatically + + struct EventInfo : public DBEVENTINFO + { + __forceinline explicit EventInfo() + { + memset(this, 0, sizeof(*this)); + } + + __forceinline ~EventInfo() + { + mir_free(pBlob); + } + }; + + ///////////////////////////////////////////////////////////////////////////////////////// + // Helper to process the auth req body + // blob is: 0(DWORD), hContact(DWORD), nick(UTF8), firstName(UTF8), lastName(UTF8), email(UTF8), reason(UTF8) + + #pragma warning(disable : 4251) + + class MIR_APP_EXPORT AUTH_BLOB + { + MCONTACT m_hContact; + DWORD m_dwUin; + ptrA m_szNick, m_szFirstName, m_szLastName, m_szEmail, m_szReason; + DWORD m_size; + + uint8_t* makeBlob(); + + public: + explicit AUTH_BLOB(MCONTACT hContact, const char *nick, const char *fname, const char *lname, const char *id, const char *reason); + explicit AUTH_BLOB(uint8_t *blob); + ~AUTH_BLOB(); + + __forceinline operator char*() { return (char*)makeBlob(); } + __forceinline operator BYTE*() { return makeBlob(); } + + __forceinline DWORD size() const { return m_size; } + + __forceinline MCONTACT get_contact() const { return m_hContact; } + __forceinline const char* get_nick() const { return m_szNick; } + __forceinline const char* get_firstName() const { return m_szFirstName; } + __forceinline const char* get_lastName() const { return m_szLastName; } + __forceinline const char* get_email() const { return m_szEmail; } + __forceinline const char* get_reason() const { return m_szReason; } + + __forceinline DWORD get_uin() const { return m_dwUin; } + __forceinline void set_uin(DWORD dwValue) { m_dwUin = dwValue; } + }; + + ///////////////////////////////////////////////////////////////////////////////////////// + // Event cursors + + class MIR_CORE_EXPORT EventCursor : public MZeroedObject + { + friend class EventIterator; + + protected: + MCONTACT hContact; + + public: + EventCursor(MCONTACT _1) : + hContact(_1) + { } + + virtual ~EventCursor(); + virtual MEVENT FetchNext() = 0; + + __forceinline MEVENT begin() { + return FetchNext(); + } + + __forceinline MEVENT end() { + return 0; + } + }; + + class MIR_CORE_EXPORT ECPTR : public MNonCopyable + { + EventCursor *m_cursor; + MEVENT m_prevFetched, m_currEvent; + + public: + ECPTR(EventCursor *_1); + ~ECPTR(); + + void DeleteEvent(); + MEVENT FetchNext(); + }; + + class EventIterator + { + EventCursor *cursor; + MEVENT hCurr = 0; + + public: + EventIterator(EventCursor *_1) : + cursor(_1) + {} + + EventIterator operator++() { + hCurr = cursor->FetchNext(); + return *this; + } + + bool operator!=(const EventIterator &p) { + return hCurr != p.hCurr; + } + + operator MEVENT() const { + return hCurr; + } + }; + + MIR_CORE_DLL(EventCursor*) Events(MCONTACT, MEVENT iStartEvent = 0); + MIR_CORE_DLL(EventCursor*) EventsRev(MCONTACT, MEVENT iStartEvent = 0); +}; + +#endif // M_DATABASE_H__ diff --git a/include/m_db_int.h b/include/m_db_int.h index aadd36998d..3a96f6906e 100644 --- a/include/m_db_int.h +++ b/include/m_db_int.h @@ -1,405 +1,405 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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_DB_INT_H__ -#define M_DB_INT_H__ 1 - -#ifndef M_CORE_H__ - #include -#endif - -/////////////////////////////////////////////////////////////////////////////// -// basic database checker interface - -#define STATUS_MESSAGE 0 -#define STATUS_WARNING 1 -#define STATUS_ERROR 2 -#define STATUS_FATAL 3 -#define STATUS_SUCCESS 4 - -struct DATABASELINK; - -struct DBCHeckCallback -{ - DWORD spaceProcessed, spaceUsed; - - void (*pfnAddLogMessage)(int type, const wchar_t *ptszFormat, ...); -}; - -interface MIDatabaseChecker -{ - STDMETHOD_(BOOL, Start)(DBCHeckCallback *callback) PURE; - STDMETHOD_(BOOL, CheckDb)(int phase) PURE; - STDMETHOD_(VOID, Destroy)() PURE; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// basic database interface - -struct DBCachedGlobalValue -{ - char *name; - DBVARIANT value; -}; - -struct DBCachedContactValue -{ - char *name; - DBVARIANT value; - DBCachedContactValue *next; -}; - -struct DBCachedContactBase -{ - MCONTACT contactID; - char *szProto; - DBCachedContactValue *first, *last; - - // metacontacts - int nSubs; // == -1 -> not a metacontact - MCONTACT *pSubs; - MCONTACT parentID; // == 0 -> not a subcontact - int nDefault; // default sub number - - __forceinline bool IsMeta() const { return nSubs != -1; } - __forceinline bool IsSub() const { return parentID != 0; } -}; - -#ifndef OWN_CACHED_CONTACT -struct DBCachedContact : public DBCachedContactBase {}; -#else -struct DBCachedContact; -#endif - -interface MIDatabaseCache : public MZeroedObject -{ - STDMETHOD_(DBCachedContact*, AddContactToCache)(MCONTACT contactID) PURE; - STDMETHOD_(DBCachedContact*, GetCachedContact)(MCONTACT contactID) PURE; - STDMETHOD_(DBCachedContact*, GetFirstContact)(void) PURE; - STDMETHOD_(DBCachedContact*, GetNextContact)(MCONTACT contactID) PURE; - STDMETHOD_(void, FreeCachedContact)(MCONTACT contactID) PURE; - - STDMETHOD_(char*, InsertCachedSetting)(const char *szName, size_t) PURE; - STDMETHOD_(char*, GetCachedSetting)(const char *szModuleName, const char *szSettingName, size_t, size_t) PURE; - STDMETHOD_(void, SetCachedVariant)(DBVARIANT *s, DBVARIANT *d) PURE; - STDMETHOD_(DBVARIANT*, GetCachedValuePtr)(MCONTACT contactID, char *szSetting, int bAllocate) PURE; -}; - -interface MIR_APP_EXPORT MIDatabase -{ - STDMETHOD_(BOOL, IsRelational)(void) PURE; - STDMETHOD_(void, SetCacheSafetyMode)(BOOL) PURE; - - STDMETHOD_(LONG, GetContactCount)(void) PURE; - STDMETHOD_(MCONTACT, FindFirstContact)(const char *szProto = nullptr) PURE; - STDMETHOD_(MCONTACT, FindNextContact)(MCONTACT contactID, const char *szProto = nullptr) PURE; - - STDMETHOD_(LONG, DeleteContact)(MCONTACT contactID) PURE; - STDMETHOD_(MCONTACT, AddContact)(void) PURE; - STDMETHOD_(BOOL, IsDbContact)(MCONTACT contactID) PURE; - STDMETHOD_(LONG, GetContactSize)(void) PURE; - - STDMETHOD_(LONG, GetEventCount)(MCONTACT contactID) PURE; - STDMETHOD_(MEVENT, AddEvent)(MCONTACT contactID, const DBEVENTINFO *dbe) PURE; - STDMETHOD_(BOOL, DeleteEvent)(MEVENT hDbEvent) PURE; - STDMETHOD_(BOOL, EditEvent)(MCONTACT contactID, MEVENT hDbEvent, const DBEVENTINFO *dbe) PURE; - STDMETHOD_(LONG, GetBlobSize)(MEVENT hDbEvent) PURE; - STDMETHOD_(BOOL, GetEvent)(MEVENT hDbEvent, DBEVENTINFO *dbe) PURE; - STDMETHOD_(BOOL, MarkEventRead)(MCONTACT contactID, MEVENT hDbEvent) PURE; - STDMETHOD_(MCONTACT, GetEventContact)(MEVENT hDbEvent) PURE; - STDMETHOD_(MEVENT, FindFirstEvent)(MCONTACT contactID) PURE; - STDMETHOD_(MEVENT, FindFirstUnreadEvent)(MCONTACT contactID) PURE; - STDMETHOD_(MEVENT, FindLastEvent)(MCONTACT contactID) PURE; - STDMETHOD_(MEVENT, FindNextEvent)(MCONTACT contactID, MEVENT hDbEvent) PURE; - STDMETHOD_(MEVENT, FindPrevEvent)(MCONTACT contactID, MEVENT hDbEvent) PURE; - - STDMETHOD_(BOOL, DeleteModule)(MCONTACT contactID, LPCSTR szModule) PURE; - STDMETHOD_(BOOL, EnumModuleNames)(DBMODULEENUMPROC pFunc, void *pParam) PURE; - - STDMETHOD_(BOOL, GetContactSetting)(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) PURE; - STDMETHOD_(BOOL, GetContactSettingStr)(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) PURE; - STDMETHOD_(BOOL, GetContactSettingStatic)(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) PURE; - STDMETHOD_(BOOL, FreeVariant)(DBVARIANT *dbv) PURE; - STDMETHOD_(BOOL, WriteContactSetting)(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws) PURE; - STDMETHOD_(BOOL, DeleteContactSetting)(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting) PURE; - STDMETHOD_(BOOL, EnumContactSettings)(MCONTACT contactID, DBSETTINGENUMPROC pfnEnumProc, const char *szModule, void *param) PURE; - STDMETHOD_(BOOL, SetSettingResident)(BOOL bIsResident, const char *pszSettingName) PURE; - STDMETHOD_(BOOL, EnumResidentSettings)(DBMODULEENUMPROC pFunc, void *pParam) PURE; - STDMETHOD_(BOOL, IsSettingEncrypted)(LPCSTR szModule, LPCSTR szSetting) PURE; - - STDMETHOD_(BOOL, MetaDetouchSub)(DBCachedContact*, int nSub) PURE; - STDMETHOD_(BOOL, MetaSetDefault)(DBCachedContact*) PURE; - STDMETHOD_(BOOL, MetaMergeHistory)(DBCachedContact *ccMeta, DBCachedContact *ccSub) PURE; - STDMETHOD_(BOOL, MetaSplitHistory)(DBCachedContact *ccMeta, DBCachedContact *ccSub) PURE; - STDMETHOD_(BOOL, MetaRemoveSubHistory)(DBCachedContact *ccSub) PURE; - - STDMETHOD_(BOOL, Compact)(void) PURE; - STDMETHOD_(BOOL, Backup)(LPCWSTR) PURE; - STDMETHOD_(BOOL, Flush)(void) PURE; - - STDMETHOD_(MIDatabaseChecker*, GetChecker)(void) PURE; - STDMETHOD_(DATABASELINK*, GetDriver)(void) PURE; - - STDMETHOD_(MEVENT, GetEventById)(LPCSTR szModule, LPCSTR szId) PURE; - - STDMETHOD_(DB::EventCursor*, EventCursor)(MCONTACT hContact, MEVENT hDbEvent) PURE; - STDMETHOD_(DB::EventCursor*, EventCursorRev)(MCONTACT hContact, MEVENT hDbEvent) PURE; -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -#pragma warning(push) -#pragma warning(disable:4275) - -struct MICryptoEngine; -struct CRYPTO_PROVIDER; - -class MIR_APP_EXPORT MDatabaseCommon : public MIDatabase, public MNonCopyable -{ - HANDLE m_hLock = nullptr; - -protected: - bool m_bEncrypted = false, m_bUsesPassword = false; - int m_codePage; - - mir_cs m_csDbAccess; - LIST m_lResidentSettings; - MIDatabaseCache* m_cache; - MICryptoEngine *m_crypto = nullptr; - -protected: - int CheckProto(DBCachedContact *cc, const char *proto); - void FillContactSettings(); - bool LockName(const wchar_t *pwszProfileName); - void UnlockName(); - - STDMETHOD_(BOOL, GetContactSettingWorker)(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv, int isStatic); - STDMETHOD_(BOOL, WriteContactSettingWorker)(MCONTACT contactID, DBCONTACTWRITESETTING &dbcws) PURE; - -public: - MDatabaseCommon(); - virtual ~MDatabaseCommon(); - - __forceinline bool isEncrypted() const { return m_bEncrypted; } - __forceinline MICryptoEngine* getCrypt() const { return m_crypto; } - __forceinline MIDatabaseCache* getCache() const { return m_cache; } - __forceinline bool usesPassword() const { return m_bUsesPassword; } - - void SetPassword(const wchar_t *ptszPassword); - - STDMETHODIMP_(BOOL) DeleteModule(MCONTACT contactID, LPCSTR szModule) override; - - STDMETHODIMP_(MCONTACT) FindFirstContact(const char *szProto = nullptr) override; - STDMETHODIMP_(MCONTACT) FindNextContact(MCONTACT contactID, const char *szProto = nullptr) override; - - STDMETHODIMP_(BOOL) MetaDetouchSub(DBCachedContact *cc, int nSub) override; - STDMETHODIMP_(BOOL) MetaSetDefault(DBCachedContact *cc) override; - STDMETHODIMP_(BOOL) MetaRemoveSubHistory(DBCachedContact *ccSub) override; - - STDMETHODIMP_(BOOL) IsSettingEncrypted(LPCSTR szModule, LPCSTR szSetting) override; - STDMETHODIMP_(BOOL) GetContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) override; - STDMETHODIMP_(BOOL) GetContactSettingStr(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) override; - STDMETHODIMP_(BOOL) GetContactSettingStatic(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) override; - STDMETHODIMP_(BOOL) FreeVariant(DBVARIANT *dbv); - STDMETHODIMP_(BOOL) WriteContactSetting(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws) override; - - STDMETHODIMP_(BOOL) EnumResidentSettings(DBMODULEENUMPROC pFunc, void *pParam) override; - STDMETHODIMP_(BOOL) SetSettingResident(BOOL bIsResident, const char *pszSettingName) override; - - STDMETHODIMP_(BOOL) Compact(void) override; - STDMETHODIMP_(BOOL) Backup(LPCWSTR) override; - STDMETHODIMP_(BOOL) Flush(void) override; - - STDMETHODIMP_(MIDatabaseChecker*) GetChecker(void) override; - - STDMETHODIMP_(DB::EventCursor*) EventCursor(MCONTACT hContact, MEVENT hDbEvent) override; - STDMETHODIMP_(DB::EventCursor*) EventCursorRev(MCONTACT hContact, MEVENT hDbEvent) override; - - //////////////////////////////////////////////////////////////////////////////////////// - // encryption support - - int InitCrypt(); - - CRYPTO_PROVIDER* SelectProvider(); - STDMETHOD_(CRYPTO_PROVIDER*, ReadProvider)() PURE; - STDMETHOD_(BOOL, StoreProvider)(CRYPTO_PROVIDER*) PURE; - - STDMETHOD_(BOOL, ReadCryptoKey)(MBinBuffer&) PURE; - STDMETHOD_(BOOL, StoreCryptoKey)() PURE; - - STDMETHOD_(BOOL, EnableEncryption)(BOOL) PURE; - STDMETHOD_(BOOL, ReadEncryption)() PURE; -}; - -#pragma warning(pop) - -///////////////////////////////////////////////////////////////////////////////////////// -// Read-only database, that cannot add/modify information in a profile - -class MIR_APP_EXPORT MDatabaseReadonly : public MDatabaseCommon -{ -public: - MDatabaseReadonly(); - - STDMETHODIMP_(BOOL) IsRelational(void) override; - - STDMETHODIMP_(void) SetCacheSafetyMode(BOOL) override; - - STDMETHODIMP_(BOOL) EnumModuleNames(DBMODULEENUMPROC, void*) override; - - STDMETHODIMP_(CRYPTO_PROVIDER*) ReadProvider() override; - STDMETHODIMP_(BOOL) StoreProvider(CRYPTO_PROVIDER*) override; - STDMETHODIMP_(BOOL) ReadCryptoKey(MBinBuffer&) override; - STDMETHODIMP_(BOOL) StoreCryptoKey() override; - STDMETHODIMP_(BOOL) EnableEncryption(BOOL) override; - STDMETHODIMP_(BOOL) ReadEncryption() override; - - //////////////////////////////////////////////////////////////////////////////////////// - STDMETHODIMP_(MCONTACT) AddContact(void) override; - STDMETHODIMP_(LONG) DeleteContact(MCONTACT) override; - STDMETHODIMP_(BOOL) IsDbContact(MCONTACT contactID) override; - STDMETHODIMP_(LONG) GetContactSize(void) override; - - //////////////////////////////////////////////////////////////////////////////////////// - STDMETHODIMP_(MEVENT) AddEvent(MCONTACT, const DBEVENTINFO*) override; - STDMETHODIMP_(BOOL) DeleteEvent(MEVENT) override; - STDMETHODIMP_(BOOL) EditEvent(MCONTACT contactID, MEVENT hDbEvent, const DBEVENTINFO *dbe) override; - STDMETHODIMP_(LONG) GetBlobSize(MEVENT) override; - STDMETHODIMP_(BOOL) MarkEventRead(MCONTACT, MEVENT) override; - STDMETHODIMP_(MCONTACT) GetEventContact(MEVENT) override; - STDMETHODIMP_(MEVENT) FindFirstUnreadEvent(MCONTACT) override; - - //////////////////////////////////////////////////////////////////////////////////////// - STDMETHODIMP_(BOOL) GetContactSettingWorker(MCONTACT, LPCSTR, LPCSTR, DBVARIANT*, int) override; - STDMETHODIMP_(BOOL) WriteContactSettingWorker(MCONTACT, DBCONTACTWRITESETTING&) override; - STDMETHODIMP_(BOOL) DeleteContactSetting(MCONTACT, LPCSTR, LPCSTR) override; - STDMETHODIMP_(BOOL) EnumContactSettings(MCONTACT, DBSETTINGENUMPROC, const char*, void*) override; - - //////////////////////////////////////////////////////////////////////////////////////// - STDMETHODIMP_(BOOL) MetaMergeHistory(DBCachedContact*, DBCachedContact*) override; - STDMETHODIMP_(BOOL) MetaSplitHistory(DBCachedContact*, DBCachedContact*) override; - STDMETHODIMP_(BOOL) MetaRemoveSubHistory(DBCachedContact*) override; - - //////////////////////////////////////////////////////////////////////////////////////// - STDMETHODIMP_(MEVENT) GetEventById(LPCSTR szModule, LPCSTR szId) override; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Each database plugin should register itself using this structure - -// Codes for DATABASELINK functions - -// grokHeader() error codes -#define EGROKPRF_NOERROR 0 -#define EGROKPRF_CANTREAD 1 // can't open the profile for reading -#define EGROKPRF_UNKHEADER 2 // header not supported, not a supported profile -#define EGROKPRF_VERNEWER 3 // header correct, version in profile newer than reader/writer -#define EGROKPRF_DAMAGED 4 // header/version fine, other internal data missing, damaged. -#define EGROKPRF_OBSOLETE 5 // obsolete database version detected, requiring conversion - -// makeDatabase() error codes -#define EMKPRF_CREATEFAILED 1 // for some reason CreateFile() didnt like something - -#define MDB_CAPS_CREATE 0x0001 // new database can be created -#define MDB_CAPS_COMPACT 0x0002 // database can be compacted -#define MDB_CAPS_CHECK 0x0004 // database can be checked - - -struct DATABASELINK -{ - int capabilities; - char* szShortName; // uniqie short database name - wchar_t* szFullName; // in English, auto-translated by the core - - /* - profile: pointer to a string which contains full path + name - Affect: The database plugin should create the profile, the filepath will not exist at - the time of this call, profile will be C:\..\.dat - Returns: 0 on success, non zero on failure - error contains extended error information, see EMKPRF_* - */ - int (*makeDatabase)(const wchar_t *profile); - - /* - profile: [in] a null terminated string to file path of selected profile - error: [in/out] pointer to an int to set with error if any - Affect: Ask the database plugin if it supports the given profile, if it does it will - return 0, if it doesnt return 1, with the error set in error -- EGROKPRF_* can be valid error - condition, most common error would be [EGROKPRF_UNKHEADER] - Note: Just because 1 is returned, doesnt mean the profile is not supported, the profile might be damaged - etc. - Returns: 0 on success, non zero on failure - */ - int (*grokHeader)(const wchar_t *profile); - - /* - Affect: Tell the database to create all services/hooks that a 3.xx legacy database might support into link, - which is a PLUGINLINK structure - Returns: 0 on success, nonzero on failure - */ - MDatabaseCommon* (*Load)(const wchar_t *profile, BOOL bReadOnly); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// global database event handles - -EXTERN_C MIR_APP_EXPORT HANDLE - g_hevContactDeleted, // ME_DB_CONTACT_DELETED - g_hevContactAdded, // ME_DB_CONTACT_ADDED - g_hevSettingChanged, // ME_DB_CONTACT_SETTINGCHANGED - g_hevMarkedRead, // ME_DB_EVENT_MARKED_READ - g_hevEventAdded, // ME_DB_EVENT_ADDED - g_hevEventEdited, // ME_DB_EVENT_EDITED - g_hevEventDeleted, // ME_DB_EVENT_DELETED - g_hevEventFiltered; // ME_DB_EVENT_FILTER_ADD - -///////////////////////////////////////////////////////////////////////////////////////// -// cache access function - -EXTERN_C MIR_CORE_DLL(DBCachedContact*) db_get_contact(MCONTACT); - -///////////////////////////////////////////////////////////////////////////////////////// -// database list's functions - -EXTERN_C MIR_CORE_DLL(MDatabaseCommon*) db_get_current(void); -EXTERN_C MIR_CORE_DLL(void) db_setCurrent(MDatabaseCommon *_db); - -// registers a database plugin -EXTERN_C MIR_APP_DLL(void) RegisterDatabasePlugin(DATABASELINK *pDescr); - -// looks for a database plugin by its short name -// returns DATABASELINK* of the required plugin or nullptr on error -EXTERN_C MIR_APP_DLL(DATABASELINK*) GetDatabasePlugin(const char *pszDriverName); - -// looks for a database plugin suitable to open this file -// returns DATABASELINK* of the required plugin or nullptr on error -EXTERN_C MIR_APP_DLL(DATABASELINK*) FindDatabasePlugin(const wchar_t *ptszFileName); - -///////////////////////////////////////////////////////////////////////////////////////// -// database upgrader - -namespace DB -{ - MIR_APP_DLL(MDatabaseCommon *) Upgrade(const wchar_t *profile); -} - -#endif // M_DB_INT_H__ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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 +aint with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef M_DB_INT_H__ +#define M_DB_INT_H__ 1 + +#ifndef M_CORE_H__ + #include +#endif + +/////////////////////////////////////////////////////////////////////////////// +// basic database checker interface + +#define STATUS_MESSAGE 0 +#define STATUS_WARNING 1 +#define STATUS_ERROR 2 +#define STATUS_FATAL 3 +#define STATUS_SUCCESS 4 + +struct DATABASELINK; + +struct DBCHeckCallback +{ + DWORD spaceProcessed, spaceUsed; + + void (*pfnAddLogMessage)(int type, const wchar_t *ptszFormat, ...); +}; + +interface MIDatabaseChecker +{ + STDMETHOD_(BOOL, Start)(DBCHeckCallback *callback) PURE; + STDMETHOD_(BOOL, CheckDb)(int phase) PURE; + STDMETHOD_(void, Destroy)() PURE; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// basic database interface + +struct DBCachedGlobalValue +{ + char *name; + DBVARIANT value; +}; + +struct DBCachedContactValue +{ + char *name; + DBVARIANT value; + DBCachedContactValue *next; +}; + +struct DBCachedContactBase +{ + MCONTACT contactID; + char *szProto; + DBCachedContactValue *first, *last; + + // metacontacts + int nSubs; // == -1 -> not a metacontact + MCONTACT *pSubs; + MCONTACT parentID; // == 0 -> not a subcontact + int nDefault; // default sub number + + __forceinline bool IsMeta() const { return nSubs != -1; } + __forceinline bool IsSub() const { return parentID != 0; } +}; + +#ifndef OWN_CACHED_CONTACT +struct DBCachedContact : public DBCachedContactBase {}; +#else +struct DBCachedContact; +#endif + +interface MIDatabaseCache : public MZeroedObject +{ + STDMETHOD_(DBCachedContact*, AddContactToCache)(MCONTACT contactID) PURE; + STDMETHOD_(DBCachedContact*, GetCachedContact)(MCONTACT contactID) PURE; + STDMETHOD_(DBCachedContact*, GetFirstContact)(void) PURE; + STDMETHOD_(DBCachedContact*, GetNextContact)(MCONTACT contactID) PURE; + STDMETHOD_(void, FreeCachedContact)(MCONTACT contactID) PURE; + + STDMETHOD_(char*, InsertCachedSetting)(const char *szName, size_t) PURE; + STDMETHOD_(char*, GetCachedSetting)(const char *szModuleName, const char *szSettingName, size_t, size_t) PURE; + STDMETHOD_(void, SetCachedVariant)(DBVARIANT *s, DBVARIANT *d) PURE; + STDMETHOD_(DBVARIANT*, GetCachedValuePtr)(MCONTACT contactID, char *szSetting, int bAllocate) PURE; +}; + +interface MIR_APP_EXPORT MIDatabase +{ + STDMETHOD_(BOOL, IsRelational)(void) PURE; + STDMETHOD_(void, SetCacheSafetyMode)(BOOL) PURE; + + STDMETHOD_(int, GetContactCount)(void) PURE; + STDMETHOD_(MCONTACT, FindFirstContact)(const char *szProto = nullptr) PURE; + STDMETHOD_(MCONTACT, FindNextContact)(MCONTACT contactID, const char *szProto = nullptr) PURE; + + STDMETHOD_(int, DeleteContact)(MCONTACT contactID) PURE; + STDMETHOD_(MCONTACT, AddContact)(void) PURE; + STDMETHOD_(BOOL, IsDbContact)(MCONTACT contactID) PURE; + STDMETHOD_(int, GetContactSize)(void) PURE; + + STDMETHOD_(int, GetEventCount)(MCONTACT contactID) PURE; + STDMETHOD_(MEVENT, AddEvent)(MCONTACT contactID, const DBEVENTINFO *dbe) PURE; + STDMETHOD_(BOOL, DeleteEvent)(MEVENT hDbEvent) PURE; + STDMETHOD_(BOOL, EditEvent)(MCONTACT contactID, MEVENT hDbEvent, const DBEVENTINFO *dbe) PURE; + STDMETHOD_(int, GetBlobSize)(MEVENT hDbEvent) PURE; + STDMETHOD_(BOOL, GetEvent)(MEVENT hDbEvent, DBEVENTINFO *dbe) PURE; + STDMETHOD_(BOOL, MarkEventRead)(MCONTACT contactID, MEVENT hDbEvent) PURE; + STDMETHOD_(MCONTACT, GetEventContact)(MEVENT hDbEvent) PURE; + STDMETHOD_(MEVENT, FindFirstEvent)(MCONTACT contactID) PURE; + STDMETHOD_(MEVENT, FindFirstUnreadEvent)(MCONTACT contactID) PURE; + STDMETHOD_(MEVENT, FindLastEvent)(MCONTACT contactID) PURE; + STDMETHOD_(MEVENT, FindNextEvent)(MCONTACT contactID, MEVENT hDbEvent) PURE; + STDMETHOD_(MEVENT, FindPrevEvent)(MCONTACT contactID, MEVENT hDbEvent) PURE; + + STDMETHOD_(BOOL, DeleteModule)(MCONTACT contactID, LPCSTR szModule) PURE; + STDMETHOD_(BOOL, EnumModuleNames)(DBMODULEENUMPROC pFunc, void *pParam) PURE; + + STDMETHOD_(BOOL, GetContactSetting)(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) PURE; + STDMETHOD_(BOOL, GetContactSettingStr)(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) PURE; + STDMETHOD_(BOOL, GetContactSettingStatic)(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) PURE; + STDMETHOD_(BOOL, FreeVariant)(DBVARIANT *dbv) PURE; + STDMETHOD_(BOOL, WriteContactSetting)(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws) PURE; + STDMETHOD_(BOOL, DeleteContactSetting)(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting) PURE; + STDMETHOD_(BOOL, EnumContactSettings)(MCONTACT contactID, DBSETTINGENUMPROC pfnEnumProc, const char *szModule, void *param) PURE; + STDMETHOD_(BOOL, SetSettingResident)(BOOL bIsResident, const char *pszSettingName) PURE; + STDMETHOD_(BOOL, EnumResidentSettings)(DBMODULEENUMPROC pFunc, void *pParam) PURE; + STDMETHOD_(BOOL, IsSettingEncrypted)(LPCSTR szModule, LPCSTR szSetting) PURE; + + STDMETHOD_(BOOL, MetaDetouchSub)(DBCachedContact*, int nSub) PURE; + STDMETHOD_(BOOL, MetaSetDefault)(DBCachedContact*) PURE; + STDMETHOD_(BOOL, MetaMergeHistory)(DBCachedContact *ccMeta, DBCachedContact *ccSub) PURE; + STDMETHOD_(BOOL, MetaSplitHistory)(DBCachedContact *ccMeta, DBCachedContact *ccSub) PURE; + STDMETHOD_(BOOL, MetaRemoveSubHistory)(DBCachedContact *ccSub) PURE; + + STDMETHOD_(BOOL, Compact)(void) PURE; + STDMETHOD_(BOOL, Backup)(LPCWSTR) PURE; + STDMETHOD_(BOOL, Flush)(void) PURE; + + STDMETHOD_(MIDatabaseChecker*, GetChecker)(void) PURE; + STDMETHOD_(DATABASELINK*, GetDriver)(void) PURE; + + STDMETHOD_(MEVENT, GetEventById)(LPCSTR szModule, LPCSTR szId) PURE; + + STDMETHOD_(DB::EventCursor*, EventCursor)(MCONTACT hContact, MEVENT hDbEvent) PURE; + STDMETHOD_(DB::EventCursor*, EventCursorRev)(MCONTACT hContact, MEVENT hDbEvent) PURE; +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +#pragma warning(push) +#pragma warning(disable:4275) + +struct MICryptoEngine; +struct CRYPTO_PROVIDER; + +class MIR_APP_EXPORT MDatabaseCommon : public MIDatabase, public MNonCopyable +{ + HANDLE m_hLock = nullptr; + +protected: + bool m_bEncrypted = false, m_bUsesPassword = false; + int m_codePage; + + mir_cs m_csDbAccess; + LIST m_lResidentSettings; + MIDatabaseCache* m_cache; + MICryptoEngine *m_crypto = nullptr; + +protected: + int CheckProto(DBCachedContact *cc, const char *proto); + void FillContactSettings(); + bool LockName(const wchar_t *pwszProfileName); + void UnlockName(); + + STDMETHOD_(BOOL, GetContactSettingWorker)(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv, int isStatic); + STDMETHOD_(BOOL, WriteContactSettingWorker)(MCONTACT contactID, DBCONTACTWRITESETTING &dbcws) PURE; + +public: + MDatabaseCommon(); + virtual ~MDatabaseCommon(); + + __forceinline bool isEncrypted() const { return m_bEncrypted; } + __forceinline MICryptoEngine* getCrypt() const { return m_crypto; } + __forceinline MIDatabaseCache* getCache() const { return m_cache; } + __forceinline bool usesPassword() const { return m_bUsesPassword; } + + void SetPassword(const wchar_t *ptszPassword); + + STDMETHODIMP_(BOOL) DeleteModule(MCONTACT contactID, LPCSTR szModule) override; + + STDMETHODIMP_(MCONTACT) FindFirstContact(const char *szProto = nullptr) override; + STDMETHODIMP_(MCONTACT) FindNextContact(MCONTACT contactID, const char *szProto = nullptr) override; + + STDMETHODIMP_(BOOL) MetaDetouchSub(DBCachedContact *cc, int nSub) override; + STDMETHODIMP_(BOOL) MetaSetDefault(DBCachedContact *cc) override; + STDMETHODIMP_(BOOL) MetaRemoveSubHistory(DBCachedContact *ccSub) override; + + STDMETHODIMP_(BOOL) IsSettingEncrypted(LPCSTR szModule, LPCSTR szSetting) override; + STDMETHODIMP_(BOOL) GetContactSetting(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) override; + STDMETHODIMP_(BOOL) GetContactSettingStr(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) override; + STDMETHODIMP_(BOOL) GetContactSettingStatic(MCONTACT contactID, LPCSTR szModule, LPCSTR szSetting, DBVARIANT *dbv) override; + STDMETHODIMP_(BOOL) FreeVariant(DBVARIANT *dbv); + STDMETHODIMP_(BOOL) WriteContactSetting(MCONTACT contactID, DBCONTACTWRITESETTING *dbcws) override; + + STDMETHODIMP_(BOOL) EnumResidentSettings(DBMODULEENUMPROC pFunc, void *pParam) override; + STDMETHODIMP_(BOOL) SetSettingResident(BOOL bIsResident, const char *pszSettingName) override; + + STDMETHODIMP_(BOOL) Compact(void) override; + STDMETHODIMP_(BOOL) Backup(LPCWSTR) override; + STDMETHODIMP_(BOOL) Flush(void) override; + + STDMETHODIMP_(MIDatabaseChecker*) GetChecker(void) override; + + STDMETHODIMP_(DB::EventCursor*) EventCursor(MCONTACT hContact, MEVENT hDbEvent) override; + STDMETHODIMP_(DB::EventCursor*) EventCursorRev(MCONTACT hContact, MEVENT hDbEvent) override; + + //////////////////////////////////////////////////////////////////////////////////////// + // encryption support + + int InitCrypt(); + + CRYPTO_PROVIDER* SelectProvider(); + STDMETHOD_(CRYPTO_PROVIDER*, ReadProvider)() PURE; + STDMETHOD_(BOOL, StoreProvider)(CRYPTO_PROVIDER*) PURE; + + STDMETHOD_(BOOL, ReadCryptoKey)(MBinBuffer&) PURE; + STDMETHOD_(BOOL, StoreCryptoKey)() PURE; + + STDMETHOD_(BOOL, EnableEncryption)(BOOL) PURE; + STDMETHOD_(BOOL, ReadEncryption)() PURE; +}; + +#pragma warning(pop) + +///////////////////////////////////////////////////////////////////////////////////////// +// Read-only database, that cannot add/modify information in a profile + +class MIR_APP_EXPORT MDatabaseReadonly : public MDatabaseCommon +{ +public: + MDatabaseReadonly(); + + STDMETHODIMP_(BOOL) IsRelational(void) override; + + STDMETHODIMP_(void) SetCacheSafetyMode(BOOL) override; + + STDMETHODIMP_(BOOL) EnumModuleNames(DBMODULEENUMPROC, void*) override; + + STDMETHODIMP_(CRYPTO_PROVIDER*) ReadProvider() override; + STDMETHODIMP_(BOOL) StoreProvider(CRYPTO_PROVIDER*) override; + STDMETHODIMP_(BOOL) ReadCryptoKey(MBinBuffer&) override; + STDMETHODIMP_(BOOL) StoreCryptoKey() override; + STDMETHODIMP_(BOOL) EnableEncryption(BOOL) override; + STDMETHODIMP_(BOOL) ReadEncryption() override; + + //////////////////////////////////////////////////////////////////////////////////////// + STDMETHODIMP_(MCONTACT) AddContact(void) override; + STDMETHODIMP_(int) DeleteContact(MCONTACT) override; + STDMETHODIMP_(BOOL) IsDbContact(MCONTACT contactID) override; + STDMETHODIMP_(int) GetContactSize(void) override; + + //////////////////////////////////////////////////////////////////////////////////////// + STDMETHODIMP_(MEVENT) AddEvent(MCONTACT, const DBEVENTINFO*) override; + STDMETHODIMP_(BOOL) DeleteEvent(MEVENT) override; + STDMETHODIMP_(BOOL) EditEvent(MCONTACT contactID, MEVENT hDbEvent, const DBEVENTINFO *dbe) override; + STDMETHODIMP_(int) GetBlobSize(MEVENT) override; + STDMETHODIMP_(BOOL) MarkEventRead(MCONTACT, MEVENT) override; + STDMETHODIMP_(MCONTACT) GetEventContact(MEVENT) override; + STDMETHODIMP_(MEVENT) FindFirstUnreadEvent(MCONTACT) override; + + //////////////////////////////////////////////////////////////////////////////////////// + STDMETHODIMP_(BOOL) GetContactSettingWorker(MCONTACT, LPCSTR, LPCSTR, DBVARIANT*, int) override; + STDMETHODIMP_(BOOL) WriteContactSettingWorker(MCONTACT, DBCONTACTWRITESETTING&) override; + STDMETHODIMP_(BOOL) DeleteContactSetting(MCONTACT, LPCSTR, LPCSTR) override; + STDMETHODIMP_(BOOL) EnumContactSettings(MCONTACT, DBSETTINGENUMPROC, const char*, void*) override; + + //////////////////////////////////////////////////////////////////////////////////////// + STDMETHODIMP_(BOOL) MetaMergeHistory(DBCachedContact*, DBCachedContact*) override; + STDMETHODIMP_(BOOL) MetaSplitHistory(DBCachedContact*, DBCachedContact*) override; + STDMETHODIMP_(BOOL) MetaRemoveSubHistory(DBCachedContact*) override; + + //////////////////////////////////////////////////////////////////////////////////////// + STDMETHODIMP_(MEVENT) GetEventById(LPCSTR szModule, LPCSTR szId) override; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Each database plugin should register itself using this structure + +// Codes for DATABASELINK functions + +// grokHeader() error codes +#define EGROKPRF_NOERROR 0 +#define EGROKPRF_CANTREAD 1 // can't open the profile for reading +#define EGROKPRF_UNKHEADER 2 // header not supported, not a supported profile +#define EGROKPRF_VERNEWER 3 // header correct, version in profile newer than reader/writer +#define EGROKPRF_DAMAGED 4 // header/version fine, other internal data missing, damaged. +#define EGROKPRF_OBSOLETE 5 // obsolete database version detected, requiring conversion + +// makeDatabase() error codes +#define EMKPRF_CREATEFAILED 1 // for some reason CreateFile() didnt like something + +#define MDB_CAPS_CREATE 0x0001 // new database can be created +#define MDB_CAPS_COMPACT 0x0002 // database can be compacted +#define MDB_CAPS_CHECK 0x0004 // database can be checked + + +struct DATABASELINK +{ + int capabilities; + char* szShortName; // uniqie short database name + wchar_t* szFullName; // in English, auto-translated by the core + + /* + profile: pointer to a string which contains full path + name + Affect: The database plugin should create the profile, the filepath will not exist at + the time of this call, profile will be C:\..\.dat + Returns: 0 on success, non zero on failure - error contains extended error information, see EMKPRF_* + */ + int (*makeDatabase)(const wchar_t *profile); + + /* + profile: [in] a null terminated string to file path of selected profile + error: [in/out] pointer to an int to set with error if any + Affect: Ask the database plugin if it supports the given profile, if it does it will + return 0, if it doesnt return 1, with the error set in error -- EGROKPRF_* can be valid error + condition, most common error would be [EGROKPRF_UNKHEADER] + Note: Just because 1 is returned, doesnt mean the profile is not supported, the profile might be damaged + etc. + Returns: 0 on success, non zero on failure + */ + int (*grokHeader)(const wchar_t *profile); + + /* + Affect: Tell the database to create all services/hooks that a 3.xx legacy database might support into link, + which is a PLUGINLINK structure + Returns: 0 on success, nonzero on failure + */ + MDatabaseCommon* (*Load)(const wchar_t *profile, BOOL bReadOnly); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// global database event handles + +EXTERN_C MIR_APP_EXPORT HANDLE + g_hevContactDeleted, // ME_DB_CONTACT_DELETED + g_hevContactAdded, // ME_DB_CONTACT_ADDED + g_hevSettingChanged, // ME_DB_CONTACT_SETTINGCHANGED + g_hevMarkedRead, // ME_DB_EVENT_MARKED_READ + g_hevEventAdded, // ME_DB_EVENT_ADDED + g_hevEventEdited, // ME_DB_EVENT_EDITED + g_hevEventDeleted, // ME_DB_EVENT_DELETED + g_hevEventFiltered; // ME_DB_EVENT_FILTER_ADD + +///////////////////////////////////////////////////////////////////////////////////////// +// cache access function + +EXTERN_C MIR_CORE_DLL(DBCachedContact*) db_get_contact(MCONTACT); + +///////////////////////////////////////////////////////////////////////////////////////// +// database list's functions + +EXTERN_C MIR_CORE_DLL(MDatabaseCommon*) db_get_current(void); +EXTERN_C MIR_CORE_DLL(void) db_setCurrent(MDatabaseCommon *_db); + +// registers a database plugin +EXTERN_C MIR_APP_DLL(void) RegisterDatabasePlugin(DATABASELINK *pDescr); + +// looks for a database plugin by its short name +// returns DATABASELINK* of the required plugin or nullptr on error +EXTERN_C MIR_APP_DLL(DATABASELINK*) GetDatabasePlugin(const char *pszDriverName); + +// looks for a database plugin suitable to open this file +// returns DATABASELINK* of the required plugin or nullptr on error +EXTERN_C MIR_APP_DLL(DATABASELINK*) FindDatabasePlugin(const wchar_t *ptszFileName); + +///////////////////////////////////////////////////////////////////////////////////////// +// database upgrader + +namespace DB +{ + MIR_APP_DLL(MDatabaseCommon *) Upgrade(const wchar_t *profile); +} + +#endif // M_DB_INT_H__ diff --git a/include/m_gui.h b/include/m_gui.h index 85fba587a4..5277d7e05d 100644 --- a/include/m_gui.h +++ b/include/m_gui.h @@ -1,1580 +1,1589 @@ -/* - -Jabber Protocol Plugin for Miranda NG - -Copyright (c) 2002-04 Santithorn Bunchua -Copyright (c) 2005-12 George Hazan -Copyright (c) 2007-09 Maxim Mluhov -Copyright (c) 2007-09 Victor Pavlychko -Copyright (C) 2012-21 Miranda NG team - -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. - -*/ - -#pragma once - -#ifndef __M_GUI_H -#define __M_GUI_H - -#include - -#include -#include -#include - -#pragma warning(disable:4355 4251 4481) - -///////////////////////////////////////////////////////////////////////////////////////// -// helpers for the option's visualization - -template -struct CMDBTraits -{ -}; - -template<> -struct CMDBTraits<1> -{ - typedef BYTE DBType; - enum { DBTypeId = DBVT_BYTE }; - static __forceinline DBType Get(const char *szModule, const char *szSetting, DBType value) - { - return db_get_b(0, szModule, szSetting, value); - } - static __forceinline void Set(const char *szModule, const char *szSetting, DBType value) - { - db_set_b(0, szModule, szSetting, value); - } -}; - -template<> -struct CMDBTraits<2> -{ - typedef WORD DBType; - enum { DBTypeId = DBVT_WORD }; - static __forceinline DBType Get(const char *szModule, const char *szSetting, DBType value) - { - return db_get_w(0, szModule, szSetting, value); - } - static __forceinline void Set(const char *szModule, const char *szSetting, DBType value) - { - db_set_w(0, szModule, szSetting, value); - } -}; - -template<> -struct CMDBTraits<4> -{ - typedef DWORD DBType; - enum { DBTypeId = DBVT_DWORD }; - static __forceinline DBType Get(const char *szModule, const char *szSetting, DBType value) - { - return db_get_dw(0, szModule, szSetting, value); - } - static __forceinline void Set(const char *szModule, const char *szSetting, DBType value) - { - db_set_dw(0, szModule, szSetting, value); - } -}; - -template<> -struct CMDBTraits<8> -{ - typedef DWORD DBType; - enum { DBTypeId = DBVT_DWORD }; - static __forceinline DBType Get(const char *szModule, const char *szSetting, DBType value) - { - return db_get_dw(0, szModule, szSetting, value); - } - static __forceinline void Set(const char *szModule, const char *szSetting, DBType value) - { - db_set_dw(0, szModule, szSetting, value); - } -}; - -class CMOptionBase : public MNonCopyable -{ -public: - __forceinline const char* GetDBModuleName() const { return m_szModuleName; } - __forceinline const char* GetDBSettingName() const { return m_szSetting; } - -protected: - __forceinline CMOptionBase(PROTO_INTERFACE *proto, const char *szSetting) : - m_szModuleName(proto->m_szModuleName), m_szSetting(szSetting) - {} - - __forceinline CMOptionBase(const char *module, const char *szSetting) : - m_szModuleName(module), m_szSetting(szSetting) - {} - - const char *m_szModuleName; - const char *m_szSetting; -}; - -template -class CMOption : public CMOptionBase -{ -public: - typedef T Type; - - __forceinline CMOption(PROTO_INTERFACE *proto, const char *szSetting, Type defValue) : - CMOptionBase(proto, szSetting), m_default(defValue) - {} - - __forceinline CMOption(const char *szModule, const char *szSetting, Type defValue) : - CMOptionBase(szModule, szSetting), m_default(defValue) - {} - - __forceinline Type Default() const - { - return m_default; - } - - __forceinline operator Type() - { - return (Type)CMDBTraits::Get(m_szModuleName, m_szSetting, m_default); - } - - __forceinline Type operator= (Type value) - { - CMDBTraits::Set(m_szModuleName, m_szSetting, (CMDBTraits::DBType)value); - return value; - } - -private: - Type m_default; -}; - -template<> -class CMOption : public CMOptionBase -{ -public: - - typedef char Type; - - __forceinline CMOption(PROTO_INTERFACE *proto, const char *szSetting, const Type *defValue = nullptr) : - CMOptionBase(proto, szSetting), m_default(defValue) - {} - - __forceinline CMOption(const char *szModule, const char *szSetting, const Type *defValue = nullptr) : - CMOptionBase(szModule, szSetting), m_default(defValue) - {} - - __forceinline const Type* Default() const - { - return m_default; - } - - __forceinline operator Type*() - { - m_value = db_get_sa(0, m_szModuleName, m_szSetting); - if (!m_value) m_value = mir_strdup(m_default); - return m_value; - } - - __forceinline Type* operator= (Type *value) - { - db_set_s(0, m_szModuleName, m_szSetting, value); - return value; - } - -private: - const Type *m_default; - mir_ptr m_value; -}; - -template<> -class CMOption : public CMOptionBase -{ -public: - - typedef wchar_t Type; - - __forceinline CMOption(PROTO_INTERFACE *proto, const char *szSetting, const Type *defValue = nullptr) : - CMOptionBase(proto, szSetting), m_default(defValue) - {} - - __forceinline CMOption(const char *szModule, const char *szSetting, const Type *defValue = nullptr) : - CMOptionBase(szModule, szSetting), m_default(defValue) - {} - - __forceinline const Type* Default() const - { - return m_default; - } - - __forceinline operator Type*() - { - m_value = db_get_wsa(0, m_szModuleName, m_szSetting); - if (!m_value) m_value = mir_wstrdup(m_default); - return m_value; - } - - __forceinline const Type* operator= (const Type *value) - { - db_set_ws(0, m_szModuleName, m_szSetting, value); - return value; - } - -private: - const Type *m_default; - mir_ptr m_value; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CDbLink - -class MIR_CORE_EXPORT CDataLink -{ -protected: - BYTE m_type; - -public: - __inline CDataLink(BYTE type) : m_type(type) {} - virtual ~CDataLink() {} - - __inline BYTE GetDataType() const { return m_type; } - - virtual DWORD LoadInt() = 0; - virtual void SaveInt(DWORD value) = 0; - - virtual wchar_t* LoadText() = 0; - virtual void SaveText(wchar_t *value) = 0; -}; - -class MIR_CORE_EXPORT CDbLink : public CDataLink -{ - char *m_szModule; - char *m_szSetting; - - DWORD m_iDefault; - wchar_t *m_szDefault; - - DBVARIANT dbv; - -public: - CDbLink(const char *szModule, const char *szSetting, BYTE type, DWORD iValue); - CDbLink(const char *szModule, const char *szSetting, BYTE type, wchar_t *szValue); - ~CDbLink(); - - DWORD LoadInt() override; - void SaveInt(DWORD value) override; - - wchar_t* LoadText() override; - void SaveText(wchar_t *value) override; -}; - -template -class CMOptionLink : public CDataLink -{ -private: - CMOption *m_option; - -public: - __forceinline CMOptionLink(CMOption &option) : - CDataLink(CMDBTraits::DBTypeId), m_option(&option) - {} - - __forceinline DWORD LoadInt() override { return (DWORD)(T)*m_option; } - __forceinline void SaveInt(DWORD value) override { *m_option = (T)value; } - - __forceinline wchar_t* LoadText() override { return nullptr; } - __forceinline void SaveText(wchar_t*) override {} -}; - -template<> -class CMOptionLink : public CDataLink -{ -private: - typedef wchar_t *T; - CMOption *m_option; - -public: - __forceinline CMOptionLink(CMOption &option) : - CDataLink(DBVT_WCHAR), m_option(&option) - {} - - __forceinline DWORD LoadInt() override { return 0; } - __forceinline void SaveInt(DWORD) override { } - - __forceinline wchar_t* LoadText() override { return *m_option; } - __forceinline void SaveText(wchar_t *value) override { *m_option = value; } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CDlgBase - base dialog class - -class MIR_CORE_EXPORT CDlgBase -{ - friend class CTimer; - friend class CCtrlBase; - friend class CCtrlData; - -public: - CDlgBase(class CMPluginBase &pPlug, int idDialog); - virtual ~CDlgBase(); - - // general utilities - void Close(); - void Resize(); - void Create(); - void Show(int nCmdShow = SW_SHOW); - int DoModal(); - void EndModal(INT_PTR nResult); - - CCtrlBase* FindControl(int idCtrl); - CCtrlBase* FindControl(HWND hwnd); - - void SetCaption(const wchar_t *ptszCaption); - void SetDraw(bool bEnable); - void NotifyChange(void); // sends a notification to a parent window - - __forceinline HINSTANCE GetInst() const { return m_pPlugin.getInst(); } - __forceinline HWND GetHwnd() const { return m_hwnd; } - __forceinline void Hide() { Show(SW_HIDE); } - __forceinline bool IsInitialized() const { return m_bInitialized; } - __forceinline void SetMinSize(int x, int y) { m_iMinWidth = x, m_iMinHeight = y; } - __forceinline void SetParent(HWND hwnd) { m_hwndParent = hwnd; } - - __forceinline CCtrlBase* operator[](int iControlId) { return FindControl(iControlId); } - - static CDlgBase* Find(HWND hwnd); - -protected: - HWND m_hwnd = nullptr; // must be the first data item - HWND m_hwndParent = nullptr; - int m_idDialog; - - bool m_isModal = false; - bool m_bInitialized = false; - bool m_forceResizable = false; - bool m_bSucceeded = false; // was IDOK pressed or not - bool m_bExiting = false; // window received WM_CLOSE and gonna die soon - - enum { CLOSE_ON_OK = 0x1, CLOSE_ON_CANCEL = 0x2 }; - BYTE m_autoClose; // automatically close dialog on IDOK/CANCEL commands. default: CLOSE_ON_OK|CLOSE_ON_CANCEL - - CMPluginBase &m_pPlugin; - - // override this handlers to provide custom functionality - // general messages - virtual bool OnInitDialog(); - virtual bool OnApply(); - virtual bool OnClose(); - virtual void OnDestroy(); - - virtual void OnTimer(CTimer*); - - // miranda-related stuff - virtual int Resizer(UTILRESIZECONTROL *urc); - virtual void OnReset(); - virtual void OnChange(); - - // main dialog procedure - virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); - - CCallback m_OnFinishWizard; - - // register controls - void AddControl(CCtrlBase *ctrl); - void RemoveControl(CCtrlBase *ctrl); - - // timers - void AddTimer(CTimer *timer); - void RemoveTimer(UINT_PTR idEvent); - - // options support - void CreateLink(CCtrlData& ctrl, const char *szSetting, BYTE type, DWORD iValue); - void CreateLink(CCtrlData& ctrl, const char *szSetting, wchar_t *szValue); - - template - __inline void CreateLink(CCtrlData& ctrl, CMOption &option) - { - ctrl.CreateDbLink(new CMOptionLink(option)); - } - - // win32 stuff - void ThemeDialogBackground(BOOL tabbed); - -private: - LIST m_timers; - LIST m_controls; - - void NotifyControls(void (CCtrlBase::*fn)()); - bool VerifyControls(bool (CCtrlBase::*fn)()); - - CTimer* FindTimer(int idEvent); - int m_iMinWidth = -1, m_iMinHeight = -1; - - static BOOL CALLBACK GlobalFieldEnum(HWND hwnd, LPARAM lParam); - static INT_PTR CALLBACK GlobalDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - static int GlobalDlgResizer(HWND hwnd, LPARAM lParam, UTILRESIZECONTROL *urc); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CTimer - -class MIR_CORE_EXPORT CTimer -{ - friend class CDlgBase; - -public: - CTimer(CDlgBase* wnd, UINT_PTR idEvent); - ~CTimer(); - - __forceinline UINT_PTR GetEventId() const { return m_idEvent; } - __forceinline HWND GetHwnd() const { return m_wnd->GetHwnd(); } - - virtual BOOL OnTimer(); - - void Start(int elapse); - bool Stop(); // returns true if timer was active - - void StartSafe(int elapse); - void StopSafe(); - - CCallback OnEvent; - -protected: - UINT_PTR m_idEvent; - CDlgBase* m_wnd; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlBase - -struct CContextMenuPos -{ - const CCtrlBase *pCtrl; - POINT pt; - union { - int iCurr; // int for list boxes - HTREEITEM hItem; - }; -}; - -class MIR_CORE_EXPORT CCtrlBase -{ - friend class CDlgBase; - - __forceinline CCtrlBase(const CCtrlBase&) = delete; - __forceinline CCtrlBase& operator=(const CCtrlBase&) = delete; - -public: - CCtrlBase(CDlgBase *wnd, int idCtrl); - virtual ~CCtrlBase(); - - __forceinline HWND GetHwnd() const { return m_hwnd; } - __forceinline int GetCtrlId() const { return m_idCtrl; } - __forceinline CDlgBase *GetParent() const { return m_parentWnd; } - __forceinline bool IsChanged() const { return m_bChanged; } - __forceinline void SetSilent(bool bSilent = true) { m_bSilent = bSilent; } - __forceinline void UseSystemColors() { m_bUseSystemColors = true; } - - void Show(bool bShow = true); - __forceinline void Hide() { Show(false); } - - void Enable(bool bIsEnable = true); - __forceinline void Disable() { Enable(false); } - bool Enabled(void) const; - - void NotifyChange(); - void SetDraw(bool bEnable); - - LRESULT SendMsg(UINT Msg, WPARAM wParam, LPARAM lParam) const; - - void SetText(const wchar_t *text); - void SetTextA(const char *text); - void SetInt(int value); - - wchar_t* GetText() const; - char* GetTextA() const; - char* GetTextU() const; - - wchar_t* GetText(wchar_t *buf, size_t size) const; - char* GetTextA(char *buf, size_t size) const; - char* GetTextU(char *buf, size_t size) const; - - int GetInt() const; - - virtual BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) { return FALSE; } - virtual BOOL OnNotify(int /*idCtrl*/, NMHDR* /*pnmh*/) { return FALSE; } - - virtual BOOL OnMeasureItem(MEASUREITEMSTRUCT*) { return FALSE; } - virtual BOOL OnDrawItem(DRAWITEMSTRUCT*) { return FALSE; } - virtual BOOL OnDeleteItem(DELETEITEMSTRUCT*) { return FALSE; } - - virtual void OnInit(); - virtual void OnDestroy(); - - virtual bool OnApply(); - virtual void OnReset(); - -protected: - HWND m_hwnd = nullptr; // must be the first data item - int m_idCtrl; - CDlgBase* m_parentWnd; - bool m_bChanged = false, m_bSilent = false, m_bUseSystemColors = false, m_bNotifiable = false; - -public: - CCallback OnChange; - CCallback OnBuildMenu; - -protected: - virtual void GetCaretPos(CContextMenuPos&) const; - virtual LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam); - - void Subclass(); - void Unsubclass(); - -private: - static LRESULT CALLBACK GlobalSubclassWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlLabel - -class MIR_CORE_EXPORT CCtrlLabel : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlLabel(CDlgBase *dlg, int ctrlId); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlButton - -class MIR_CORE_EXPORT CCtrlButton : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlButton(CDlgBase *dlg, int ctrlId); - - BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode) override; - - CCallback OnClick; - - void Click(); - bool IsPushed() const; - void Push(bool bPushed); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlMButton - -class MIR_CORE_EXPORT CCtrlMButton : public CCtrlButton -{ - typedef CCtrlButton CSuper; - -public: - CCtrlMButton(CDlgBase *dlg, int ctrlId, HICON hIcon, const char* tooltip); - CCtrlMButton(CDlgBase *dlg, int ctrlId, int iCoreIcon, const char* tooltip); - ~CCtrlMButton(); - - void MakeFlat(); - void MakePush(); - - void OnInit() override; - -protected: - HICON m_hIcon; - const char* m_toolTip; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CSplitter - -class MIR_CORE_EXPORT CSplitter : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CSplitter(CDlgBase *dlg, int ctrlId); - - __forceinline int GetPos() const { return m_iPosition; } - -protected: - LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) override; - void OnInit() override; - - int m_iPosition; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlHyperlink - -class MIR_CORE_EXPORT CCtrlHyperlink : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlHyperlink(CDlgBase *dlg, int ctrlId, const char* url = nullptr); - - BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode) override; - - CCallback OnClick; - - void SetUrl(const char *url); - const char *GetUrl(); - -protected: - const char* m_url; - - void Default_OnClick(CCtrlHyperlink*); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CProgress - -class MIR_CORE_EXPORT CCtrlProgress : public CCtrlBase -{ -public: - CCtrlProgress(CDlgBase *dlg, int ctrlId); - - void SetRange(WORD max, WORD min = 0); - void SetPosition(WORD value); - void SetStep(WORD value); - WORD Move(WORD delta = 0); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlClc - -#if !defined(MGROUP) - typedef int MGROUP; -#endif - -class MIR_CORE_EXPORT CCtrlClc : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlClc(CDlgBase *dlg, int ctrlId); - - void AddContact(MCONTACT hContact); - void AddGroup(HANDLE hGroup); - HANDLE AddInfoItem(CLCINFOITEM *cii); - void AutoRebuild(); - void DeleteItem(HANDLE hItem); - void EditLabel(HANDLE hItem); - void EndEditLabel(bool save); - void EnsureVisible(HANDLE hItem, bool partialOk); - void Expand(HANDLE hItem, DWORD flags); - HANDLE FindContact(MCONTACT hContact); - HANDLE FindGroup(MGROUP hGroup); - COLORREF GetBkColor() const; - bool GetCheck(HANDLE hItem) const; - int GetCount() const; - HWND GetEditControl() const; - DWORD GetExStyle() const; - DWORD GetExpand(HANDLE hItem) const; - int GetExtraColumns() const; - BYTE GetExtraImage(HANDLE hItem, int iColumn) const; - HIMAGELIST GetExtraImageList() const; - HFONT GetFont(int iFontId) const; - bool GetHideOfflineRoot() const; - int GetItemType(HANDLE hItem) const; - HANDLE GetNextItem(HANDLE hItem, DWORD flags) const; - HANDLE GetSelection() const; - HANDLE HitTest(int x, int y, DWORD *hitTest) const; - void SelectItem(HANDLE hItem); - void SetBkColor(COLORREF clBack); - void SetCheck(HANDLE hItem, bool check); - void SetExStyle(DWORD exStyle); - void SetExtraColumns(int iColumns); - void SetExtraImage(HANDLE hItem, int iColumn, int iImage); - void SetExtraImageList(HIMAGELIST hImgList); - void SetFont(int iFontId, HANDLE hFont, bool bRedraw); - void SetItemText(HANDLE hItem, char *szText); - void SetHideEmptyGroups(bool state); - void SetHideOfflineRoot(bool state); - void SetOfflineModes(DWORD modes); - void SetUseGroups(bool state); - - struct TEventInfo - { - CCtrlClc *ctrl; - NMCLISTCONTROL *info; - }; - - CCallback OnExpanded; - CCallback OnListRebuilt; - CCallback OnItemChecked; - CCallback OnDragging; - CCallback OnDropped; - CCallback OnListSizeChange; - CCallback OnOptionsChanged; - CCallback OnDragStop; - CCallback OnNewContact; - CCallback OnContactMoved; - CCallback OnCheckChanged; - CCallback OnClick; - -protected: - BOOL OnNotify(int idCtrl, NMHDR *pnmh) override; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlData - data access controls base class - -class MIR_CORE_EXPORT CCtrlData : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlData(CDlgBase *dlg, int ctrlId); - ~CCtrlData(); - - void CreateDbLink(const char* szModuleName, const char* szSetting, BYTE type, DWORD iValue); - void CreateDbLink(const char* szModuleName, const char* szSetting, wchar_t* szValue); - void CreateDbLink(CDataLink *link) { m_dbLink = link; } - - void OnInit() override; - -protected: - CDataLink *m_dbLink; - - __inline BYTE GetDataType() { return m_dbLink ? m_dbLink->GetDataType() : DBVT_DELETED; } - __inline DWORD LoadInt() { return m_dbLink ? m_dbLink->LoadInt() : 0; } - __inline void SaveInt(DWORD value) { if (m_dbLink) m_dbLink->SaveInt(value); } - __inline const wchar_t *LoadText() { return m_dbLink ? m_dbLink->LoadText() : L""; } - __inline void SaveText(wchar_t *value) { if (m_dbLink) m_dbLink->SaveText(value); } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlCheck - -class MIR_CORE_EXPORT CCtrlCheck : public CCtrlData -{ - typedef CCtrlData CSuper; - -public: - CCtrlCheck(CDlgBase *dlg, int ctrlId); - BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) override; - - bool OnApply() override; - void OnReset() override; - - int GetState() const; - void SetState(int state); - - bool IsChecked(); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlColor - color picker - -class MIR_CORE_EXPORT CCtrlColor : public CCtrlData -{ - typedef CCtrlData CSuper; - -public: - CCtrlColor(CDlgBase *dlg, int ctrlId); - BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) override; - - bool OnApply() override; - void OnReset() override; - - DWORD GetColor(); - void SetColor(DWORD dwValue); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlDate - date & time picker - -class MIR_CORE_EXPORT CCtrlDate : public CCtrlData -{ - typedef CCtrlData CSuper; - - BOOL OnNotify(int, NMHDR*) override; - -public: - CCtrlDate(CDlgBase *dlg, int ctrlId); - - void GetTime(SYSTEMTIME*); - void SetTime(SYSTEMTIME*); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlEdit - -class MIR_CORE_EXPORT CCtrlEdit : public CCtrlData -{ - typedef CCtrlData CSuper; - -public: - CCtrlEdit(CDlgBase *dlg, int ctrlId); - BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD idCode) override; - - bool OnApply() override; - void OnReset() override; - - void SetMaxLength(unsigned int len); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlRichEdit - -class MIR_CORE_EXPORT CCtrlRichEdit : public CCtrlEdit -{ - typedef CCtrlEdit CSuper; - -public: - CCtrlRichEdit(CDlgBase *dlg, int ctrlId); - - // returns text length in bytes if a parameter is omitted or in symbols, if not - int GetRichTextLength(int iCodePage = CP_ACP) const; - - // returns a buffer that should be freed using mir_free() or ptrA/ptrW - char* GetRichTextRtf(bool bText = false, bool bSelection = false) const; // returns text with formatting - wchar_t* GetRichText() const; // returns only text in ucs2 - - // these methods return text length in Unicode chars - int SetRichText(const wchar_t *text); - int SetRichTextRtf(const char *text); - - // enables or disables content editing - void SetReadOnly(bool bReadOnly); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlSlider - -class MIR_CORE_EXPORT CCtrlSlider : public CCtrlData -{ - typedef CCtrlData CSuper; - - int m_wMin, m_wMax; - -protected: - BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode) override; - -public: - CCtrlSlider(CDlgBase *dlg, int ctrlId, int max = 100, int min = 0); - - bool OnApply() override; - void OnReset() override; - - int GetPosition() const; - void SetPosition(int pos); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlSpin - -class MIR_CORE_EXPORT CCtrlSpin : public CCtrlData -{ - typedef CCtrlData CSuper; - - WORD m_wMin, m_wMax, m_wCurr; - - BOOL OnNotify(int, NMHDR*) override; - -public: - CCtrlSpin(CDlgBase *dlg, int ctrlId, WORD max = 100, WORD min = 0); - - bool OnApply() override; - void OnReset() override; - - WORD GetPosition(); - void SetPosition(WORD pos); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlListBox - -class MIR_CORE_EXPORT CCtrlListBox : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlListBox(CDlgBase *dlg, int ctrlId); - - int AddString(const wchar_t *text, LPARAM data=0); - void DeleteString(int index); - int FindString(const wchar_t *str, int index = -1, bool exact = false); - int GetCount() const; - int GetCurSel() const; - LPARAM GetItemData(int index) const; - int GetItemRect(int index, RECT *pResult) const; - wchar_t* GetItemText(int index) const; - wchar_t* GetItemText(int index, wchar_t *buf, int size) const; - bool GetSel(int index) const; - int GetSelCount() const; - int* GetSelItems(int *items, int count) const; - int* GetSelItems() const; - int InsertString(const wchar_t *text, int pos, LPARAM data=0); - void ResetContent(); - int SelectString(const wchar_t *str); - int SetCurSel(int index); - void SetItemData(int index, LPARAM data); - void SetItemHeight(int index, int iHeight); - void SetSel(int index, bool sel = true); - - // Events - CCallback OnDblClick; - CCallback OnSelCancel; - CCallback OnSelChange; - -protected: - BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode) override; - void GetCaretPos(CContextMenuPos&) const override; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlCombo - -class MIR_CORE_EXPORT CCtrlCombo : public CCtrlData -{ - typedef CCtrlData CSuper; - -public: - CCtrlCombo(CDlgBase *dlg, int ctrlId); - - BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD idCode) override; - void OnInit() override; - bool OnApply() override; - void OnReset() override; - - // returns item data associated with the selected item or -1 - LPARAM GetCurData() const; - - // selects line with userdata passed. returns index of this line or -1 - int SelectData(LPARAM data); - - // Control interface - int AddString(const wchar_t *text, LPARAM data = 0); - int AddStringA(const char *text, LPARAM data = 0); - void DeleteString(int index); - int FindString(const wchar_t *str, int index = -1, bool exact = false); - int FindStringA(const char *str, int index = -1, bool exact = false); - int GetCount() const; - int GetCurSel() const; - bool GetDroppedState() const; - LPARAM GetItemData(int index) const; - wchar_t* GetItemText(int index) const; - wchar_t* GetItemText(int index, wchar_t *buf, int size) const; - int InsertString(const wchar_t *text, int pos, LPARAM data=0); - void ResetContent(); - int SelectString(const wchar_t *str); - int SetCurSel(int index); - void SetItemData(int index, LPARAM data); - void ShowDropdown(bool show = true); - - // Events - CCallback OnCloseup; - CCallback OnDropdown; - CCallback OnKillFocus; - CCallback OnSelChanged; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlListView - -class MIR_CORE_EXPORT CCtrlListView : public CCtrlBase -{ - typedef CCtrlBase CSuper; - -public: - CCtrlListView(CDlgBase *dlg, int ctrlId); - - // direction = -1 or 1. returns new item index - int MoveItem(int idx, int direction); - - void SetCurSel(int idx); - - // Classic LV interface - DWORD ApproximateViewRect(int cx, int cy, int iCount); - void Arrange(UINT code); - void CancelEditLabel(); - HIMAGELIST CreateDragImage(int iItem, LPPOINT lpptUpLeft); - void DeleteAllItems(); - void DeleteColumn(int iCol); - void DeleteItem(int iItem); - HWND EditLabel(int iItem); - int EnableGroupView(BOOL fEnable); - BOOL EnsureVisible(int i, BOOL fPartialOK); - int FindItem(int iStart, const LVFINDINFO *plvfi); - COLORREF GetBkColor() const; - void GetBkImage(LPLVBKIMAGE plvbki) const; - UINT GetCallbackMask() const; - BOOL GetCheckState(UINT iIndex) const; - void GetColumn(int iCol, LPLVCOLUMN pcol) const; - void GetColumnOrderArray(int iCount, int *lpiArray) const; - int GetColumnWidth(int iCol) const; - int GetCountPerPage() const; - HWND GetEditControl() const; - DWORD GetExtendedListViewStyle() const; - INT GetFocusedGroup() const; - int GetGroupCount() const; - void GetGroupInfo(int iGroupId, PLVGROUP pgrp) const; - void GetGroupInfoByIndex(int iIndex, PLVGROUP pgrp) const; - void GetGroupMetrics(LVGROUPMETRICS *pGroupMetrics) const; - UINT GetGroupState(UINT dwGroupId, UINT dwMask) const; - HWND GetHeader() const; - HCURSOR GetHotCursor() const; - INT GetHotItem() const; - DWORD GetHoverTime() const; - HIMAGELIST GetImageList(int iImageList) const; - BOOL GetInsertMark(LVINSERTMARK *plvim) const; - COLORREF GetInsertMarkColor() const; - int GetInsertMarkRect(LPRECT prc) const; - BOOL GetISearchString(LPSTR lpsz) const; - bool GetItem(LPLVITEM pitem) const; - int GetItemCount() const; - void GetItemPosition(int i, POINT *ppt) const; - void GetItemRect(int i, RECT *prc, int code) const; - DWORD GetItemSpacing(BOOL fSmall) const; - UINT GetItemState(int i, UINT mask) const; - void GetItemText(int iItem, int iSubItem, LPTSTR pszText, int cchTextMax) const; - int GetNextItem(int iStart, UINT flags) const; - BOOL GetNumberOfWorkAreas(LPUINT lpuWorkAreas) const; - BOOL GetOrigin(LPPOINT lpptOrg) const; - COLORREF GetOutlineColor() const; - UINT GetSelectedColumn() const; - UINT GetSelectedCount() const; - INT GetSelectionMark() const; - int GetStringWidth(LPCSTR psz) const; - BOOL GetSubItemRect(int iItem, int iSubItem, int code, LPRECT lpRect) const; - COLORREF GetTextBkColor() const; - COLORREF GetTextColor() const; - void GetTileInfo(PLVTILEINFO plvtinfo) const; - void GetTileViewInfo(PLVTILEVIEWINFO plvtvinfo) const; - HWND GetToolTips() const; - int GetTopIndex() const; - BOOL GetUnicodeFormat() const; - DWORD GetView() const; - BOOL GetViewRect(RECT *prc) const; - void GetWorkAreas(INT nWorkAreas, LPRECT lprc) const; - BOOL HasGroup(int dwGroupId); - int HitTest(LPLVHITTESTINFO pinfo) const; - int HitTestEx(LPLVHITTESTINFO pinfo); - int InsertColumn(int iCol, const LPLVCOLUMN pcol); - int InsertGroup(int index, PLVGROUP pgrp); - void InsertGroupSorted(PLVINSERTGROUPSORTED structInsert); - int InsertItem(const LPLVITEM pitem); - BOOL InsertMarkHitTest(LPPOINT point, LVINSERTMARK *plvim); - BOOL IsGroupViewEnabled(); - UINT IsItemVisible(UINT index); - UINT MapIDToIndex(UINT id); - UINT MapIndexToID(UINT index); - BOOL RedrawItems(int iFirst, int iLast); - void RemoveAllGroups(); - int RemoveGroup(int iGroupId); - BOOL Scroll(int dx, int dy); - BOOL SetBkColor(COLORREF clrBk); - BOOL SetBkImage(LPLVBKIMAGE plvbki); - BOOL SetCallbackMask(UINT mask); - void SetCheckState(UINT iIndex, BOOL fCheck); - BOOL SetColumn(int iCol, LPLVCOLUMN pcol); - BOOL SetColumnOrderArray(int iCount, int *lpiArray); - BOOL SetColumnWidth(int iCol, int cx); - void SetExtendedListViewStyle(DWORD dwExStyle); - void SetExtendedListViewStyleEx(DWORD dwExMask, DWORD dwExStyle); - int SetGroupInfo(int iGroupId, PLVGROUP pgrp); - void SetGroupMetrics(PLVGROUPMETRICS pGroupMetrics); - void SetGroupState(UINT dwGroupId, UINT dwMask, UINT dwState); - HCURSOR SetHotCursor(HCURSOR hCursor); - INT SetHotItem(INT iIndex); - void SetHoverTime(DWORD dwHoverTime); - DWORD SetIconSpacing(int cx, int cy); - HIMAGELIST SetImageList(HIMAGELIST himl, int iImageList); - BOOL SetInfoTip(PLVSETINFOTIP plvSetInfoTip); - BOOL SetInsertMark(LVINSERTMARK *plvim); - COLORREF SetInsertMarkColor(COLORREF color); - BOOL SetItem(const LPLVITEM pitem); - void SetItemCount(int cItems); - void SetItemCountEx(int cItems, DWORD dwFlags); - BOOL SetItemPosition(int i, int x, int y); - void SetItemPosition32(int iItem, int x, int y); - void SetItemState(int i, UINT state, UINT mask); - void SetItemText(int i, int iSubItem, const wchar_t *pszText); - COLORREF SetOutlineColor(COLORREF color); - void SetSelectedColumn(int iCol); - INT SetSelectionMark(INT iIndex); - BOOL SetTextBkColor(COLORREF clrText); - BOOL SetTextColor(COLORREF clrText); - BOOL SetTileInfo(PLVTILEINFO plvtinfo); - BOOL SetTileViewInfo(PLVTILEVIEWINFO plvtvinfo); - HWND SetToolTips(HWND ToolTip); - BOOL SetUnicodeFormat(BOOL fUnicode); - int SetView(DWORD iView); - void SetWorkAreas(INT nWorkAreas, LPRECT lprc); - int SortGroups(PFNLVGROUPCOMPARE pfnGroupCompare, LPVOID plv); - BOOL SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort); - BOOL SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort); - INT SubItemHitTest(LPLVHITTESTINFO pInfo) const; - INT SubItemHitTestEx(LPLVHITTESTINFO plvhti); - BOOL Update(int iItem); - - // Additional APIs - HIMAGELIST CreateImageList(int iImageList); - void AddColumn(int iSubItem, const wchar_t *name, int cx); - void AddGroup(int iGroupId, const wchar_t *name); - int AddItem(const wchar_t *text, int iIcon, LPARAM lParam = 0, int iGroupId = -1); - void SetItem(int iItem, int iSubItem, const wchar_t *text, int iIcon = -1); - LPARAM GetItemData(int iItem) const; - - // Events - struct TEventInfo { - CCtrlListView *treeviewctrl; - union { - NMHDR *nmhdr; - NMLISTVIEW *nmlv; - NMLVDISPINFO *nmlvdi; - NMLVSCROLL *nmlvscr; - NMLVGETINFOTIP *nmlvit; - NMLVFINDITEM *nmlvfi; - NMITEMACTIVATE *nmlvia; - NMLVKEYDOWN *nmlvkey; - NMLVCUSTOMDRAW *nmcd; - }; - }; - - CCallback OnBeginDrag; - CCallback OnBeginLabelEdit; - CCallback OnBeginRDrag; - CCallback OnBeginScroll; - CCallback OnColumnClick; - CCallback OnCustomDraw; - CCallback OnDeleteAllItems; - CCallback OnDeleteItem; - CCallback OnClick; - CCallback OnDoubleClick; - CCallback OnEndLabelEdit; - CCallback OnEndScroll; - CCallback OnGetDispInfo; - CCallback OnGetInfoTip; - CCallback OnHotTrack; - CCallback OnIncrementalSearch; - CCallback OnInsertItem; - CCallback OnItemActivate; - CCallback OnItemChanged; - CCallback OnItemChanging; - CCallback OnKeyDown; - CCallback OnMarqueeBegin; - CCallback OnSetDispInfo; - -protected: - BOOL OnNotify(int idCtrl, NMHDR *pnmh) override; - void GetCaretPos(CContextMenuPos&) const override; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlTreeView - -#undef GetNextSibling -#undef GetPrevSibling - -#define MTREE_CHECKBOX 0x0001 -#define MTREE_DND 0x0002 -#define MTREE_MULTISELECT 0x0004 - -class MIR_CORE_EXPORT CCtrlTreeView : public CCtrlBase -{ - typedef CCtrlBase CSuper; - - HTREEITEM MoveItemAbove(HTREEITEM hItem, HTREEITEM hInsertAfter, HTREEITEM hParent); - -public: - CCtrlTreeView(CDlgBase *dlg, int ctrlId); - - void SetFlags(uint32_t dwFlags); // MTREE_* combination - - // Classic TV interface - HIMAGELIST CreateDragImage(HTREEITEM hItem); - void DeleteAllItems(); - void DeleteItem(HTREEITEM hItem); - HWND EditLabel(HTREEITEM hItem); - void EndEditLabelNow(BOOL cancel); - void EnsureVisible(HTREEITEM hItem); - void Expand(HTREEITEM hItem, DWORD flag); - COLORREF GetBkColor() const; - DWORD GetCheckState(HTREEITEM hItem) const; - HTREEITEM GetChild(HTREEITEM hItem) const; - int GetCount() const; - HTREEITEM GetDropHilight() const; - HWND GetEditControl() const; - HTREEITEM GetFirstVisible() const; - HIMAGELIST GetImageList(int iImage) const; - int GetIndent() const; - COLORREF GetInsertMarkColor() const; - bool GetItem(TVITEMEX *tvi) const; - int GetItemHeight() const; - void GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect) const; - DWORD GetItemState(HTREEITEM hItem, DWORD stateMask) const; - HTREEITEM GetLastVisible() const; - COLORREF GetLineColor() const; - HTREEITEM GetNextItem(HTREEITEM hItem, DWORD flag) const; - HTREEITEM GetNextSibling(HTREEITEM hItem) const; - HTREEITEM GetNextVisible(HTREEITEM hItem) const; - HTREEITEM GetParent(HTREEITEM hItem) const; - HTREEITEM GetPrevSibling(HTREEITEM hItem) const; - HTREEITEM GetPrevVisible(HTREEITEM hItem) const; - HTREEITEM GetRoot() const; - DWORD GetScrollTime() const; - HTREEITEM GetSelection() const; - COLORREF GetTextColor() const; - HWND GetToolTips() const; - BOOL GetUnicodeFormat() const; - unsigned GetVisibleCount() const; - HTREEITEM HitTest(TVHITTESTINFO *hti) const; - HTREEITEM InsertItem(TVINSERTSTRUCT *tvis); - void Select(HTREEITEM hItem, DWORD flag); - void SelectDropTarget(HTREEITEM hItem); - void SelectItem(HTREEITEM hItem); - void SelectSetFirstVisible(HTREEITEM hItem); - COLORREF SetBkColor(COLORREF clBack); - void SetCheckState(HTREEITEM hItem, DWORD state); - void SetImageList(HIMAGELIST hIml, int iImage); - void SetIndent(int iIndent); - void SetInsertMark(HTREEITEM hItem, BOOL fAfter); - COLORREF SetInsertMarkColor(COLORREF clMark); - void SetItem(TVITEMEX *tvi); - void SetItemHeight(short cyItem); - void SetItemState(HTREEITEM hItem, DWORD state, DWORD stateMask); - COLORREF SetLineColor(COLORREF clLine); - void SetScrollTime(UINT uMaxScrollTime); - COLORREF SetTextColor(COLORREF clText); - HWND SetToolTips(HWND hwndToolTips); - BOOL SetUnicodeFormat(BOOL fUnicode); - void SortChildren(HTREEITEM hItem, BOOL fRecurse); - void SortChildrenCB(TVSORTCB *cb, BOOL fRecurse); - - // Additional stuff - void TranslateItem(HTREEITEM hItem); - void TranslateTree(); - HTREEITEM FindNamedItem(HTREEITEM hItem, const wchar_t *name); - void GetItem(HTREEITEM hItem, TVITEMEX *tvi) const; - void GetItem(HTREEITEM hItem, TVITEMEX *tvi, wchar_t *szText, int iTextLength) const; - void InvertCheck(HTREEITEM hItem); - - bool IsSelected(HTREEITEM hItem); - int GetNumSelected(); - void GetSelected(LIST<_TREEITEM> &selected); - - void Select(HTREEITEM hItem); - void Select(LIST<_TREEITEM> &selected); - void SelectAll(); - void SelectRange(HTREEITEM hStart, HTREEITEM hEnd); - - void Unselect(HTREEITEM hItem); - void UnselectAll(); - - void DropHilite(HTREEITEM hItem); - void DropUnhilite(HTREEITEM hItem); - - // Events - struct TEventInfo { - CCtrlTreeView *treeviewctrl; - union { - NMHDR *nmhdr; - NMTREEVIEW *nmtv; - NMTVKEYDOWN *nmtvkey; - NMTVDISPINFO *nmtvdi; - NMTVGETINFOTIP *nmtvit; - NMTVCUSTOMDRAW *nmcd; - HTREEITEM hItem; // for OnItemChanged - }; - }; - - CCallback OnBeginDrag; - CCallback OnBeginLabelEdit; - CCallback OnBeginRDrag; - CCallback OnCustomDraw; - CCallback OnDeleteItem; - CCallback OnEndLabelEdit; - CCallback OnGetDispInfo; - CCallback OnGetInfoTip; - CCallback OnItemChanged; - CCallback OnItemExpanded; - CCallback OnItemExpanding; - CCallback OnKeyDown; - CCallback OnRightClick; - CCallback OnSelChanged; - CCallback OnSelChanging; - CCallback OnSetDispInfo; - CCallback OnSingleExpand; - -protected: - void OnInit() override; - void OnDestroy() override; - BOOL OnNotify(int idCtrl, NMHDR *pnmh) override; - - void GetCaretPos(CContextMenuPos&) const override; - LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) override; - - union { - uint32_t m_dwFlags; - struct { - bool m_bDndEnabled : 1; - bool m_bDragging : 1; - bool m_bCheckBox : 1; - bool m_bMultiSelect : 1; - }; - }; - HTREEITEM m_hDragItem; // valid if m_bDragging == true -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlTreeOpts - array of options with sections - -class MIR_CORE_EXPORT CCtrlTreeOpts : public CCtrlTreeView -{ - typedef CCtrlTreeView CSuper; - -public: - CCtrlTreeOpts(CDlgBase *dlg, int ctrlId); - ~CCtrlTreeOpts(); - - void AddOption(const wchar_t *pwszSection, const wchar_t *pwszName, CMOption &option); - - BOOL OnNotify(int idCtrl, NMHDR *pnmh) override; - void OnDestroy() override; - void OnInit() override; - bool OnApply() override; - -protected: - struct COptionsItem - { - const wchar_t *m_pwszSection, *m_pwszName; - - CMOption *m_option; - - HTREEITEM m_hItem = nullptr; - - COptionsItem(const wchar_t *pwszSection, const wchar_t *pwszName, CMOption &option) : - m_pwszSection(pwszSection), - m_pwszName(pwszName), - m_option(&option) - { - } - }; - - OBJLIST m_options; - - void ProcessItemClick(HTREEITEM hti); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CCtrlPages - -#define PSN_INFOCHANGED 1 -#define PSN_PARAMCHANGED 2 - -// force-send a PSN_INFOCHANGED to all pages -#define PSM_FORCECHANGED (WM_USER+100) - -class MIR_CORE_EXPORT CCtrlPages : public CCtrlBase -{ - typedef CCtrlBase CSuper; - - HIMAGELIST m_hIml; - CDlgBase *m_pActivePage; - int m_numRows = 1; - - struct TPageInfo; - void InsertPage(TPageInfo *pPage); - void ShowPage(CDlgBase *pDlg); - - void CheckRowCount(); - TPageInfo* GetCurrPage(); - TPageInfo* GetItemPage(int iPage); - LIST m_pages; - -public: - CCtrlPages(CDlgBase *dlg, int ctrlId); - - void AddPage(const wchar_t *ptszName, HICON hIcon, CDlgBase *pDlg); - void ActivatePage(int iPage); - int GetCount(void); - int GetDlgIndex(CDlgBase*); - void RemovePage(int iPage); - void SwapPages(int idx1, int idx2); - - CDlgBase* GetNthPage(int iPage); - - __forceinline CDlgBase* GetActivePage() const - { return m_pActivePage; - } - -protected: - BOOL OnNotify(int idCtrl, NMHDR *pnmh) override; - - void OnInit() override; - void OnDestroy() override; - - bool OnApply() override; - void OnReset() override; - - LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) override; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// CProtoDlgBase - -#define WM_PROTO_REFRESH (WM_USER + 100) -#define WM_PROTO_CHECK_ONLINE (WM_USER + 101) -#define WM_PROTO_ACTIVATE (WM_USER + 102) -#define WM_PROTO_LAST (WM_USER + 200) - -struct PROTO_INTERFACE; - -class MIR_APP_EXPORT CProtoIntDlgBase : public CDlgBase -{ - typedef CDlgBase CSuper; - -public: - CProtoIntDlgBase(PROTO_INTERFACE *proto, int idDialog); - - void CreateLink(CCtrlData &ctrl, const char *szSetting, BYTE type, DWORD iValue); - void CreateLink(CCtrlData &ctrl, const char *szSetting, wchar_t *szValue); - - template - __inline void CreateLink(CCtrlData &ctrl, CMOption &option) - { - ctrl.CreateDbLink(new CMOptionLink(option)); - } - - __inline PROTO_INTERFACE *GetProtoInterface() { return m_proto_interface; } - - void SetStatusText(const wchar_t *statusText); - -protected: - PROTO_INTERFACE *m_proto_interface; - HWND m_hwndStatus = nullptr; - - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override; - - virtual void OnProtoRefresh(WPARAM, LPARAM); - virtual void OnProtoActivate(WPARAM, LPARAM); - virtual void OnProtoCheckOnline(WPARAM, LPARAM); - -private: - void UpdateStatusBar(); -}; - -template -class CProtoDlgBase : public CProtoIntDlgBase -{ - typedef CProtoIntDlgBase CSuper; - -public: - __inline CProtoDlgBase(TProto *proto, int idDialog) : - CProtoIntDlgBase(proto, idDialog), - m_proto(proto) - { - } - - __inline TProto *GetProto() { return m_proto; } - -protected: - TProto* m_proto; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Safe open/close dialogs -#define UI_SAFE_OPEN(dlgClass, dlgPtr) \ - { \ - if (dlgPtr) \ - { \ - SetForegroundWindow((dlgPtr)->GetHwnd()); \ - } else \ - { \ - (dlgPtr) = new dlgClass(this); \ - (dlgPtr)->Show(); \ - } \ - } - -#define UI_SAFE_OPEN_EX(dlgClass, dlgPtr, dlgLocal) \ - if (dlgPtr) \ - { \ - ::SetForegroundWindow((dlgPtr)->GetHwnd()); \ - } else \ - { \ - (dlgPtr) = new dlgClass(this); \ - (dlgPtr)->Show(); \ - } \ - dlgClass *dlgLocal = (dlgClass *)(dlgPtr); - -#define UI_SAFE_CLOSE(dlg) \ - { \ - if (dlg) { \ - (dlg)->Close(); \ - (dlg) = NULL; \ - } \ - } - -#define UI_SAFE_CLOSE_HWND(hwnd) \ - { \ - if (hwnd) { \ - ::SendMessage((hwnd), WM_CLOSE, 0, 0); \ - (hwnd) = NULL; \ - } \ - } - -///////////////////////////////////////////////////////////////////////////////////////// -// NULL-Safe dialog notifications -#define UI_SAFE_NOTIFY(dlg, msg) \ - { \ - if (dlg) \ - ::SendMessage((dlg)->GetHwnd(), msg, 0, 0); \ - } - -#define UI_SAFE_NOTIFY_HWND(hwnd, msg) \ - { \ - if (hwnd) \ - ::SendMessage((hwnd), msg, 0, 0); \ - } - -///////////////////////////////////////////////////////////////////////////////////////// -// Define message maps -#define UI_MESSAGE_MAP(dlgClass, baseDlgClass) \ - typedef baseDlgClass CMessageMapSuperClass; \ - virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) \ - { \ - switch (msg) \ - { \ - case 0: \ - break /* just to handle ";" symbol after macro */ - -#define UI_MESSAGE(msg, proc) \ - case msg: \ - proc(msg, wParam, lParam); \ - break - -#define UI_MESSAGE_EX(msg, func) \ - case msg: \ - return func(msg, wParam, lParam) - -#define UI_POSTPROCESS_MESSAGE(msg, proc) \ - case msg: \ - CMessageMapSuperClass::DlgProc(msg, wParam, lParam); \ - return FALSE - -#define UI_POSTPROCESS_MESSAGE_EX(msg, func) \ - case msg: \ - CMessageMapSuperClass::DlgProc(msg, wParam, lParam); \ - return func(msg, wParam, lParam) - -#define UI_MESSAGE_MAP_END() \ - } \ - return CMessageMapSuperClass::DlgProc(msg, wParam, lParam); \ - } - -#endif // __M_GUI_H +/* + +Jabber Protocol Plugin for Miranda NG + +Copyright (c) 2002-04 Santithorn Bunchua +Copyright (c) 2005-12 George Hazan +Copyright (c) 2007-09 Maxim Mluhov +Copyright (c) 2007-09 Victor Pavlychko +Copyright (C) 2012-21 Miranda NG team + +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. + +*/ + +#pragma once + +#ifndef __M_GUI_H +#define __M_GUI_H + +#ifdef _MSC_VER +#include +#endif // _WINDOWS + +#include +#include +#include + +#pragma warning(disable:4355 4251 4481) + +///////////////////////////////////////////////////////////////////////////////////////// +// helpers for the option's visualization + +template +struct CMDBTraits +{ +}; + +template<> +struct CMDBTraits<1> +{ + typedef BYTE DBType; + enum { DBTypeId = DBVT_BYTE }; + static __forceinline DBType Get(const char *szModule, const char *szSetting, DBType value) + { + return db_get_b(0, szModule, szSetting, value); + } + static __forceinline void Set(const char *szModule, const char *szSetting, DBType value) + { + db_set_b(0, szModule, szSetting, value); + } +}; + +template<> +struct CMDBTraits<2> +{ + typedef WORD DBType; + enum { DBTypeId = DBVT_WORD }; + static __forceinline DBType Get(const char *szModule, const char *szSetting, DBType value) + { + return db_get_w(0, szModule, szSetting, value); + } + static __forceinline void Set(const char *szModule, const char *szSetting, DBType value) + { + db_set_w(0, szModule, szSetting, value); + } +}; + +template<> +struct CMDBTraits<4> +{ + typedef DWORD DBType; + enum { DBTypeId = DBVT_DWORD }; + static __forceinline DBType Get(const char *szModule, const char *szSetting, DBType value) + { + return db_get_dw(0, szModule, szSetting, value); + } + static __forceinline void Set(const char *szModule, const char *szSetting, DBType value) + { + db_set_dw(0, szModule, szSetting, value); + } +}; + +template<> +struct CMDBTraits<8> +{ + typedef DWORD DBType; + enum { DBTypeId = DBVT_DWORD }; + static __forceinline DBType Get(const char *szModule, const char *szSetting, DBType value) + { + return db_get_dw(0, szModule, szSetting, value); + } + static __forceinline void Set(const char *szModule, const char *szSetting, DBType value) + { + db_set_dw(0, szModule, szSetting, value); + } +}; + +class CMOptionBase : public MNonCopyable +{ +public: + __forceinline const char* GetDBModuleName() const { return m_szModuleName; } + __forceinline const char* GetDBSettingName() const { return m_szSetting; } + +protected: + __forceinline CMOptionBase(PROTO_INTERFACE *proto, const char *szSetting) : + m_szModuleName(proto->m_szModuleName), m_szSetting(szSetting) + {} + + __forceinline CMOptionBase(const char *module, const char *szSetting) : + m_szModuleName(module), m_szSetting(szSetting) + {} + + const char *m_szModuleName; + const char *m_szSetting; +}; + +template +class CMOption : public CMOptionBase +{ +public: + typedef T Type; + + __forceinline CMOption(PROTO_INTERFACE *proto, const char *szSetting, Type defValue) : + CMOptionBase(proto, szSetting), m_default(defValue) + {} + + __forceinline CMOption(const char *szModule, const char *szSetting, Type defValue) : + CMOptionBase(szModule, szSetting), m_default(defValue) + {} + + __forceinline Type Default() const + { + return m_default; + } + + __forceinline operator Type() + { + return (Type)CMDBTraits::Get(m_szModuleName, m_szSetting, m_default); + } + + __forceinline Type operator= (Type value) + { + #ifdef _MSC_VER + CMDBTraits::Set(m_szModuleName, m_szSetting, (CMDBTraits::DBType)value); + #else + CMDBTraits::Set(m_szModuleName, m_szSetting, value); + #endif + return value; + } + +private: + Type m_default; +}; + +template<> +class CMOption : public CMOptionBase +{ +public: + + typedef char Type; + + __forceinline CMOption(PROTO_INTERFACE *proto, const char *szSetting, const Type *defValue = nullptr) : + CMOptionBase(proto, szSetting), m_default(defValue) + {} + + __forceinline CMOption(const char *szModule, const char *szSetting, const Type *defValue = nullptr) : + CMOptionBase(szModule, szSetting), m_default(defValue) + {} + + __forceinline const Type* Default() const + { + return m_default; + } + + __forceinline operator Type*() + { + m_value = db_get_sa(0, m_szModuleName, m_szSetting); + if (!m_value) m_value = mir_strdup(m_default); + return m_value; + } + + __forceinline Type* operator= (Type *value) + { + db_set_s(0, m_szModuleName, m_szSetting, value); + return value; + } + +private: + const Type *m_default; + mir_ptr m_value; +}; + +template<> +class CMOption : public CMOptionBase +{ +public: + + typedef wchar_t Type; + + __forceinline CMOption(PROTO_INTERFACE *proto, const char *szSetting, const Type *defValue = nullptr) : + CMOptionBase(proto, szSetting), m_default(defValue) + {} + + __forceinline CMOption(const char *szModule, const char *szSetting, const Type *defValue = nullptr) : + CMOptionBase(szModule, szSetting), m_default(defValue) + {} + + __forceinline const Type* Default() const + { + return m_default; + } + + __forceinline operator Type*() + { + m_value = db_get_wsa(0, m_szModuleName, m_szSetting); + if (!m_value) m_value = mir_wstrdup(m_default); + return m_value; + } + + __forceinline const Type* operator= (const Type *value) + { + db_set_ws(0, m_szModuleName, m_szSetting, value); + return value; + } + +private: + const Type *m_default; + mir_ptr m_value; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CDbLink + +class MIR_CORE_EXPORT CDataLink +{ +protected: + BYTE m_type; + +public: + __inline CDataLink(BYTE type) : m_type(type) {} + virtual ~CDataLink() {} + + __inline BYTE GetDataType() const { return m_type; } + + virtual DWORD LoadInt() = 0; + virtual void SaveInt(DWORD value) = 0; + + virtual wchar_t* LoadText() = 0; + virtual void SaveText(wchar_t *value) = 0; +}; + +class MIR_CORE_EXPORT CDbLink : public CDataLink +{ + char *m_szModule; + char *m_szSetting; + + DWORD m_iDefault; + wchar_t *m_szDefault; + + DBVARIANT dbv; + +public: + CDbLink(const char *szModule, const char *szSetting, BYTE type, DWORD iValue); + CDbLink(const char *szModule, const char *szSetting, BYTE type, wchar_t *szValue); + ~CDbLink(); + + DWORD LoadInt() override; + void SaveInt(DWORD value) override; + + wchar_t* LoadText() override; + void SaveText(wchar_t *value) override; +}; + +template +class CMOptionLink : public CDataLink +{ +private: + CMOption *m_option; + +public: + __forceinline CMOptionLink(CMOption &option) : + CDataLink(CMDBTraits::DBTypeId), m_option(&option) + {} + + __forceinline DWORD LoadInt() override { return (DWORD)(T)*m_option; } + __forceinline void SaveInt(DWORD value) override { *m_option = (T)value; } + + __forceinline wchar_t* LoadText() override { return nullptr; } + __forceinline void SaveText(wchar_t*) override {} +}; + +template<> +class CMOptionLink : public CDataLink +{ +private: + typedef wchar_t *T; + CMOption *m_option; + +public: + __forceinline CMOptionLink(CMOption &option) : + CDataLink(DBVT_WCHAR), m_option(&option) + {} + + __forceinline DWORD LoadInt() override { return 0; } + __forceinline void SaveInt(DWORD) override { } + + __forceinline wchar_t* LoadText() override { return *m_option; } + __forceinline void SaveText(wchar_t *value) override { *m_option = value; } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CDlgBase - base dialog class + +class MIR_CORE_EXPORT CDlgBase +{ + friend class CTimer; + friend class CCtrlBase; + friend class CCtrlData; + +public: + CDlgBase(class CMPluginBase &pPlug, int idDialog); + virtual ~CDlgBase(); + + // general utilities + void Close(); + void Resize(); + void Create(); + void Show(int nCmdShow = SW_SHOW); + int DoModal(); + void EndModal(INT_PTR nResult); + + class CCtrlBase* FindControl(int idCtrl); + class CCtrlBase* FindControl(HWND hwnd); + + void SetCaption(const wchar_t *ptszCaption); + void SetDraw(bool bEnable); + void NotifyChange(void); // sends a notification to a parent window + + __forceinline HINSTANCE GetInst() const { return m_pPlugin.getInst(); } + __forceinline HWND GetHwnd() const { return m_hwnd; } + __forceinline void Hide() { Show(SW_HIDE); } + __forceinline bool IsInitialized() const { return m_bInitialized; } + __forceinline void SetMinSize(int x, int y) { m_iMinWidth = x, m_iMinHeight = y; } + __forceinline void SetParent(HWND hwnd) { m_hwndParent = hwnd; } + + __forceinline CCtrlBase* operator[](int iControlId) { return FindControl(iControlId); } + + static CDlgBase* Find(HWND hwnd); + +protected: + HWND m_hwnd = nullptr; // must be the first data item + HWND m_hwndParent = nullptr; + int m_idDialog; + + bool m_isModal = false; + bool m_bInitialized = false; + bool m_forceResizable = false; + bool m_bSucceeded = false; // was IDOK pressed or not + bool m_bExiting = false; // window received WM_CLOSE and gonna die soon + + enum { CLOSE_ON_OK = 0x1, CLOSE_ON_CANCEL = 0x2 }; + BYTE m_autoClose; // automatically close dialog on IDOK/CANCEL commands. default: CLOSE_ON_OK|CLOSE_ON_CANCEL + + CMPluginBase &m_pPlugin; + + // override this handlers to provide custom functionality + // general messages + virtual bool OnInitDialog(); + virtual bool OnApply(); + virtual bool OnClose(); + virtual void OnDestroy(); + + virtual void OnTimer(class CTimer*); + + // miranda-related stuff + virtual int Resizer(UTILRESIZECONTROL *urc); + virtual void OnReset(); + virtual void OnChange(); + + // main dialog procedure + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam); + + CCallback m_OnFinishWizard; + + // register controls + void AddControl(CCtrlBase *ctrl); + void RemoveControl(CCtrlBase *ctrl); + + // timers + void AddTimer(CTimer *timer); + void RemoveTimer(UINT_PTR idEvent); + + // options support + void CreateLink(class CCtrlData& ctrl, const char *szSetting, BYTE type, DWORD iValue); + void CreateLink(class CCtrlData& ctrl, const char *szSetting, wchar_t *szValue); + + template + __inline void CreateLink(CCtrlData& ctrl, CMOption &option) + { + ctrl.CreateDbLink(new CMOptionLink(option)); + } + + // win32 stuff + void ThemeDialogBackground(BOOL tabbed); + +private: + LIST m_timers; + LIST m_controls; + + void NotifyControls(void (CCtrlBase::*fn)()); + bool VerifyControls(bool (CCtrlBase::*fn)()); + + CTimer* FindTimer(int idEvent); + int m_iMinWidth = -1, m_iMinHeight = -1; + + static BOOL CALLBACK GlobalFieldEnum(HWND hwnd, LPARAM lParam); + static INT_PTR CALLBACK GlobalDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + static int GlobalDlgResizer(HWND hwnd, LPARAM lParam, UTILRESIZECONTROL *urc); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CTimer + +class MIR_CORE_EXPORT CTimer +{ + friend class CDlgBase; + +public: + CTimer(CDlgBase* wnd, UINT_PTR idEvent); + ~CTimer(); + + __forceinline UINT_PTR GetEventId() const { return m_idEvent; } + __forceinline HWND GetHwnd() const { return m_wnd->GetHwnd(); } + + virtual BOOL OnTimer(); + + void Start(int elapse); + bool Stop(); // returns true if timer was active + + void StartSafe(int elapse); + void StopSafe(); + + CCallback OnEvent; + +protected: + UINT_PTR m_idEvent; + CDlgBase* m_wnd; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlBase + +struct CContextMenuPos +{ + const CCtrlBase *pCtrl; + POINT pt; + union { + int iCurr; // int for list boxes + HTREEITEM hItem; + }; +}; + +class MIR_CORE_EXPORT CCtrlBase +{ + friend class CDlgBase; + + __forceinline CCtrlBase(const CCtrlBase&) = delete; + __forceinline CCtrlBase& operator=(const CCtrlBase&) = delete; + +public: + CCtrlBase(CDlgBase *wnd, int idCtrl); + virtual ~CCtrlBase(); + + __forceinline HWND GetHwnd() const { return m_hwnd; } + __forceinline int GetCtrlId() const { return m_idCtrl; } + __forceinline CDlgBase *GetParent() const { return m_parentWnd; } + __forceinline bool IsChanged() const { return m_bChanged; } + __forceinline void SetSilent(bool bSilent = true) { m_bSilent = bSilent; } + __forceinline void UseSystemColors() { m_bUseSystemColors = true; } + + void Show(bool bShow = true); + __forceinline void Hide() { Show(false); } + + void Enable(bool bIsEnable = true); + __forceinline void Disable() { Enable(false); } + bool Enabled(void) const; + + void NotifyChange(); + void SetDraw(bool bEnable); + + INT_PTR SendMsg(UINT Msg, WPARAM wParam, LPARAM lParam) const; + + void SetText(const wchar_t *text); + void SetTextA(const char *text); + void SetInt(int value); + + wchar_t* GetText() const; + char* GetTextA() const; + char* GetTextU() const; + + wchar_t* GetText(wchar_t *buf, size_t size) const; + char* GetTextA(char *buf, size_t size) const; + char* GetTextU(char *buf, size_t size) const; + + int GetInt() const; + + virtual BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) { return FALSE; } + virtual BOOL OnNotify(int /*idCtrl*/, struct NMHDR* /*pnmh*/) { return FALSE; } + + virtual BOOL OnMeasureItem(struct MEASUREITEMSTRUCT*) { return FALSE; } + virtual BOOL OnDrawItem(struct DRAWITEMSTRUCT*) { return FALSE; } + virtual BOOL OnDeleteItem(struct DELETEITEMSTRUCT*) { return FALSE; } + + virtual void OnInit(); + virtual void OnDestroy(); + + virtual bool OnApply(); + virtual void OnReset(); + +protected: + HWND m_hwnd = nullptr; // must be the first data item + int m_idCtrl; + CDlgBase* m_parentWnd; + bool m_bChanged = false, m_bSilent = false, m_bUseSystemColors = false, m_bNotifiable = false; + +public: + CCallback OnChange; + CCallback OnBuildMenu; + +protected: + virtual void GetCaretPos(CContextMenuPos&) const; + virtual INT_PTR CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam); + + void Subclass(); + void Unsubclass(); + +private: + static INT_PTR CALLBACK GlobalSubclassWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlLabel + +class MIR_CORE_EXPORT CCtrlLabel : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlLabel(CDlgBase *dlg, int ctrlId); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlButton + +class MIR_CORE_EXPORT CCtrlButton : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlButton(CDlgBase *dlg, int ctrlId); + + BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode) override; + + CCallback OnClick; + + void Click(); + bool IsPushed() const; + void Push(bool bPushed); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlMButton + +class MIR_CORE_EXPORT CCtrlMButton : public CCtrlButton +{ + typedef CCtrlButton CSuper; + +public: + CCtrlMButton(CDlgBase *dlg, int ctrlId, HICON hIcon, const char* tooltip); + CCtrlMButton(CDlgBase *dlg, int ctrlId, int iCoreIcon, const char* tooltip); + ~CCtrlMButton(); + + void MakeFlat(); + void MakePush(); + + void OnInit() override; + +protected: + HICON m_hIcon; + const char* m_toolTip; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CSplitter + +class MIR_CORE_EXPORT CSplitter : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CSplitter(CDlgBase *dlg, int ctrlId); + + __forceinline int GetPos() const { return m_iPosition; } + +protected: + INT_PTR CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) override; + void OnInit() override; + + int m_iPosition; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlHyperlink + +class MIR_CORE_EXPORT CCtrlHyperlink : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlHyperlink(CDlgBase *dlg, int ctrlId, const char* url = nullptr); + + BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode) override; + + CCallback OnClick; + + void SetUrl(const char *url); + const char *GetUrl(); + +protected: + const char* m_url; + + void Default_OnClick(CCtrlHyperlink*); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CProgress + +class MIR_CORE_EXPORT CCtrlProgress : public CCtrlBase +{ +public: + CCtrlProgress(CDlgBase *dlg, int ctrlId); + + void SetRange(WORD max, WORD min = 0); + void SetPosition(WORD value); + void SetStep(WORD value); + WORD Move(WORD delta = 0); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlClc + +#if !defined(MGROUP) + typedef int MGROUP; +#endif + +class MIR_CORE_EXPORT CCtrlClc : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlClc(CDlgBase *dlg, int ctrlId); + + void AddContact(MCONTACT hContact); + void AddGroup(HANDLE hGroup); + HANDLE AddInfoItem(CLCINFOITEM *cii); + void AutoRebuild(); + void DeleteItem(HANDLE hItem); + void EditLabel(HANDLE hItem); + void EndEditLabel(bool save); + void EnsureVisible(HANDLE hItem, bool partialOk); + void Expand(HANDLE hItem, DWORD flags); + HANDLE FindContact(MCONTACT hContact); + HANDLE FindGroup(MGROUP hGroup); + COLORREF GetBkColor() const; + bool GetCheck(HANDLE hItem) const; + int GetCount() const; + HWND GetEditControl() const; + DWORD GetExStyle() const; + DWORD GetExpand(HANDLE hItem) const; + int GetExtraColumns() const; + BYTE GetExtraImage(HANDLE hItem, int iColumn) const; + HIMAGELIST GetExtraImageList() const; + HFONT GetFont(int iFontId) const; + bool GetHideOfflineRoot() const; + int GetItemType(HANDLE hItem) const; + HANDLE GetNextItem(HANDLE hItem, DWORD flags) const; + HANDLE GetSelection() const; + HANDLE HitTest(int x, int y, DWORD *hitTest) const; + void SelectItem(HANDLE hItem); + void SetBkColor(COLORREF clBack); + void SetCheck(HANDLE hItem, bool check); + void SetExStyle(DWORD exStyle); + void SetExtraColumns(int iColumns); + void SetExtraImage(HANDLE hItem, int iColumn, int iImage); + void SetExtraImageList(HIMAGELIST hImgList); + void SetFont(int iFontId, HANDLE hFont, bool bRedraw); + void SetItemText(HANDLE hItem, char *szText); + void SetHideEmptyGroups(bool state); + void SetHideOfflineRoot(bool state); + void SetOfflineModes(DWORD modes); + void SetUseGroups(bool state); + + struct TEventInfo + { + CCtrlClc *ctrl; + struct NMCLISTCONTROL *info; + }; + + CCallback OnExpanded; + CCallback OnListRebuilt; + CCallback OnItemChecked; + CCallback OnDragging; + CCallback OnDropped; + CCallback OnListSizeChange; + CCallback OnOptionsChanged; + CCallback OnDragStop; + CCallback OnNewContact; + CCallback OnContactMoved; + CCallback OnCheckChanged; + CCallback OnClick; + +protected: + BOOL OnNotify(int idCtrl, NMHDR *pnmh) override; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlData - data access controls base class + +class MIR_CORE_EXPORT CCtrlData : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlData(CDlgBase *dlg, int ctrlId); + ~CCtrlData(); + + void CreateDbLink(const char* szModuleName, const char* szSetting, BYTE type, DWORD iValue); + void CreateDbLink(const char* szModuleName, const char* szSetting, wchar_t* szValue); + void CreateDbLink(CDataLink *link) { m_dbLink = link; } + + void OnInit() override; + +protected: + CDataLink *m_dbLink; + + __inline BYTE GetDataType() { return m_dbLink ? m_dbLink->GetDataType() : DBVT_DELETED; } + __inline DWORD LoadInt() { return m_dbLink ? m_dbLink->LoadInt() : 0; } + __inline void SaveInt(DWORD value) { if (m_dbLink) m_dbLink->SaveInt(value); } + __inline const wchar_t *LoadText() { return m_dbLink ? m_dbLink->LoadText() : L""; } + __inline void SaveText(wchar_t *value) { if (m_dbLink) m_dbLink->SaveText(value); } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCheck + +class MIR_CORE_EXPORT CCtrlCheck : public CCtrlData +{ + typedef CCtrlData CSuper; + +public: + CCtrlCheck(CDlgBase *dlg, int ctrlId); + BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) override; + + bool OnApply() override; + void OnReset() override; + + int GetState() const; + void SetState(int state); + + bool IsChecked(); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlColor - color picker + +class MIR_CORE_EXPORT CCtrlColor : public CCtrlData +{ + typedef CCtrlData CSuper; + +public: + CCtrlColor(CDlgBase *dlg, int ctrlId); + BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD /*idCode*/) override; + + bool OnApply() override; + void OnReset() override; + + DWORD GetColor(); + void SetColor(DWORD dwValue); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlDate - date & time picker + +class MIR_CORE_EXPORT CCtrlDate : public CCtrlData +{ + typedef CCtrlData CSuper; + + BOOL OnNotify(int, NMHDR*) override; + +public: + CCtrlDate(CDlgBase *dlg, int ctrlId); + + void GetTime(struct SYSTEMTIME*); + void SetTime(struct SYSTEMTIME*); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlEdit + +class MIR_CORE_EXPORT CCtrlEdit : public CCtrlData +{ + typedef CCtrlData CSuper; + +public: + CCtrlEdit(CDlgBase *dlg, int ctrlId); + BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD idCode) override; + + bool OnApply() override; + void OnReset() override; + + void SetMaxLength(unsigned int len); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlRichEdit + +class MIR_CORE_EXPORT CCtrlRichEdit : public CCtrlEdit +{ + typedef CCtrlEdit CSuper; + +public: + CCtrlRichEdit(CDlgBase *dlg, int ctrlId); + + // returns text length in bytes if a parameter is omitted or in symbols, if not + int GetRichTextLength(int iCodePage = CP_ACP) const; + + // returns a buffer that should be freed using mir_free() or ptrA/ptrW + char* GetRichTextRtf(bool bText = false, bool bSelection = false) const; // returns text with formatting + wchar_t* GetRichText() const; // returns only text in ucs2 + + // these methods return text length in Unicode chars + int SetRichText(const wchar_t *text); + int SetRichTextRtf(const char *text); + + // enables or disables content editing + void SetReadOnly(bool bReadOnly); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlSlider + +class MIR_CORE_EXPORT CCtrlSlider : public CCtrlData +{ + typedef CCtrlData CSuper; + + int m_wMin, m_wMax; + +protected: + BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode) override; + +public: + CCtrlSlider(CDlgBase *dlg, int ctrlId, int max = 100, int min = 0); + + bool OnApply() override; + void OnReset() override; + + int GetPosition() const; + void SetPosition(int pos); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlSpin + +class MIR_CORE_EXPORT CCtrlSpin : public CCtrlData +{ + typedef CCtrlData CSuper; + + WORD m_wMin, m_wMax, m_wCurr; + + BOOL OnNotify(int, NMHDR*) override; + +public: + CCtrlSpin(CDlgBase *dlg, int ctrlId, WORD max = 100, WORD min = 0); + + bool OnApply() override; + void OnReset() override; + + WORD GetPosition(); + void SetPosition(WORD pos); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlListBox + +class MIR_CORE_EXPORT CCtrlListBox : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlListBox(CDlgBase *dlg, int ctrlId); + + int AddString(const wchar_t *text, LPARAM data=0); + void DeleteString(int index); + int FindString(const wchar_t *str, int index = -1, bool exact = false); + int GetCount() const; + int GetCurSel() const; + LPARAM GetItemData(int index) const; + int GetItemRect(int index, RECT *pResult) const; + wchar_t* GetItemText(int index) const; + wchar_t* GetItemText(int index, wchar_t *buf, int size) const; + bool GetSel(int index) const; + int GetSelCount() const; + int* GetSelItems(int *items, int count) const; + int* GetSelItems() const; + int InsertString(const wchar_t *text, int pos, LPARAM data=0); + void ResetContent(); + int SelectString(const wchar_t *str); + int SetCurSel(int index); + void SetItemData(int index, LPARAM data); + void SetItemHeight(int index, int iHeight); + void SetSel(int index, bool sel = true); + + // Events + CCallback OnDblClick; + CCallback OnSelCancel; + CCallback OnSelChange; + +protected: + BOOL OnCommand(HWND hwndCtrl, WORD idCtrl, WORD idCode) override; + void GetCaretPos(CContextMenuPos&) const override; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlCombo + +class MIR_CORE_EXPORT CCtrlCombo : public CCtrlData +{ + typedef CCtrlData CSuper; + +public: + CCtrlCombo(CDlgBase *dlg, int ctrlId); + + BOOL OnCommand(HWND /*hwndCtrl*/, WORD /*idCtrl*/, WORD idCode) override; + void OnInit() override; + bool OnApply() override; + void OnReset() override; + + // returns item data associated with the selected item or -1 + LPARAM GetCurData() const; + + // selects line with userdata passed. returns index of this line or -1 + int SelectData(LPARAM data); + + // Control interface + int AddString(const wchar_t *text, LPARAM data = 0); + int AddStringA(const char *text, LPARAM data = 0); + void DeleteString(int index); + int FindString(const wchar_t *str, int index = -1, bool exact = false); + int FindStringA(const char *str, int index = -1, bool exact = false); + int GetCount() const; + int GetCurSel() const; + bool GetDroppedState() const; + LPARAM GetItemData(int index) const; + wchar_t* GetItemText(int index) const; + wchar_t* GetItemText(int index, wchar_t *buf, int size) const; + int InsertString(const wchar_t *text, int pos, LPARAM data=0); + void ResetContent(); + int SelectString(const wchar_t *str); + int SetCurSel(int index); + void SetItemData(int index, LPARAM data); + void ShowDropdown(bool show = true); + + // Events + CCallback OnCloseup; + CCallback OnDropdown; + CCallback OnKillFocus; + CCallback OnSelChanged; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlListView + +class MIR_CORE_EXPORT CCtrlListView : public CCtrlBase +{ + typedef CCtrlBase CSuper; + +public: + CCtrlListView(CDlgBase *dlg, int ctrlId); + + // direction = -1 or 1. returns new item index + int MoveItem(int idx, int direction); + + void SetCurSel(int idx); + + // Classic LV interface + DWORD ApproximateViewRect(int cx, int cy, int iCount); + void Arrange(UINT code); + void CancelEditLabel(); + HIMAGELIST CreateDragImage(int iItem, POINT *lpptUpLeft); + void DeleteAllItems(); + void DeleteColumn(int iCol); + void DeleteItem(int iItem); + HWND EditLabel(int iItem); + int EnableGroupView(BOOL fEnable); + BOOL EnsureVisible(int i, BOOL fPartialOK); + int FindItem(int iStart, const struct LVFINDINFO *plvfi); + COLORREF GetBkColor() const; + void GetBkImage(struct LVBKIMAGE *plvbki) const; + UINT GetCallbackMask() const; + BOOL GetCheckState(UINT iIndex) const; + void GetColumn(int iCol, struct LVCOLUMN *pcol) const; + void GetColumnOrderArray(int iCount, int *lpiArray) const; + int GetColumnWidth(int iCol) const; + int GetCountPerPage() const; + HWND GetEditControl() const; + DWORD GetExtendedListViewStyle() const; + int GetFocusedGroup() const; + int GetGroupCount() const; + void GetGroupInfo(int iGroupId, struct LVGROUP *pgrp) const; + void GetGroupInfoByIndex(int iIndex, struct LVGROUP *pgrp) const; + void GetGroupMetrics(struct LVGROUPMETRICS *pGroupMetrics) const; + UINT GetGroupState(UINT dwGroupId, UINT dwMask) const; + HWND GetHeader() const; + HCURSOR GetHotCursor() const; + int GetHotItem() const; + DWORD GetHoverTime() const; + HIMAGELIST GetImageList(int iImageList) const; + BOOL GetInsertMark(struct LVINSERTMARK *plvim) const; + COLORREF GetInsertMarkColor() const; + int GetInsertMarkRect(RECT *prc) const; + BOOL GetISearchString(LPSTR lpsz) const; + bool GetItem(struct LVITEM *pitem) const; + int GetItemCount() const; + void GetItemPosition(int i, POINT *ppt) const; + void GetItemRect(int i, RECT *prc, int code) const; + DWORD GetItemSpacing(BOOL fSmall) const; + UINT GetItemState(int i, UINT mask) const; + void GetItemText(int iItem, int iSubItem, LPTSTR pszText, int cchTextMax) const; + int GetNextItem(int iStart, UINT flags) const; + BOOL GetNumberOfWorkAreas(UINT *lpuWorkAreas) const; + BOOL GetOrigin(POINT *lpptOrg) const; + COLORREF GetOutlineColor() const; + UINT GetSelectedColumn() const; + UINT GetSelectedCount() const; + int GetSelectionMark() const; + int GetStringWidth(LPCSTR psz) const; + BOOL GetSubItemRect(int iItem, int iSubItem, int code, RECT *lpRect) const; + COLORREF GetTextBkColor() const; + COLORREF GetTextColor() const; + void GetTileInfo(struct LVTILEINFO *plvtinfo) const; + void GetTileViewInfo(struct LVTILEVIEWINFO *plvtvinfo) const; + HWND GetToolTips() const; + int GetTopIndex() const; + BOOL GetUnicodeFormat() const; + DWORD GetView() const; + BOOL GetViewRect(RECT *prc) const; + void GetWorkAreas(int nWorkAreas, RECT *lprc) const; + BOOL HasGroup(int dwGroupId); + int HitTest(struct LVHITTESTINFO *pinfo) const; + int HitTestEx(struct LVHITTESTINFO *pinfo); + int InsertColumn(int iCol, const struct LVCOLUMN *pcol); + int InsertGroup(int index, struct LVGROUP *pgrp); + void InsertGroupSorted(struct LVINSERTGROUPSORTED *structInsert); + int InsertItem(const struct LVITEM *pitem); + BOOL InsertMarkHitTest(POINT *point, LVINSERTMARK *plvim); + BOOL IsGroupViewEnabled(); + UINT IsItemVisible(UINT index); + UINT MapIDToIndex(UINT id); + UINT MapIndexToID(UINT index); + BOOL RedrawItems(int iFirst, int iLast); + void RemoveAllGroups(); + int RemoveGroup(int iGroupId); + BOOL Scroll(int dx, int dy); + BOOL SetBkColor(COLORREF clrBk); + BOOL SetBkImage(struct LVBKIMAGE *plvbki); + BOOL SetCallbackMask(UINT mask); + void SetCheckState(UINT iIndex, BOOL fCheck); + BOOL SetColumn(int iCol, struct LVCOLUMN *pcol); + BOOL SetColumnOrderArray(int iCount, int *lpiArray); + BOOL SetColumnWidth(int iCol, int cx); + void SetExtendedListViewStyle(DWORD dwExStyle); + void SetExtendedListViewStyleEx(DWORD dwExMask, DWORD dwExStyle); + int SetGroupInfo(int iGroupId, struct LVGROUP *pgrp); + void SetGroupMetrics(struct LVGROUPMETRICS *pGroupMetrics); + void SetGroupState(UINT dwGroupId, UINT dwMask, UINT dwState); + HCURSOR SetHotCursor(HCURSOR hCursor); + int SetHotItem(int iIndex); + void SetHoverTime(DWORD dwHoverTime); + DWORD SetIconSpacing(int cx, int cy); + HIMAGELIST SetImageList(HIMAGELIST himl, int iImageList); + BOOL SetInfoTip(struct LVSETINFOTIP *plvSetInfoTip); + BOOL SetInsertMark(struct LVINSERTMARK *plvim); + COLORREF SetInsertMarkColor(COLORREF color); + BOOL SetItem(const struct LVITEM *pitem); + void SetItemCount(int cItems); + void SetItemCountEx(int cItems, DWORD dwFlags); + BOOL SetItemPosition(int i, int x, int y); + void SetItemPosition32(int iItem, int x, int y); + void SetItemState(int i, UINT state, UINT mask); + void SetItemText(int i, int iSubItem, const wchar_t *pszText); + COLORREF SetOutlineColor(COLORREF color); + void SetSelectedColumn(int iCol); + int SetSelectionMark(int iIndex); + BOOL SetTextBkColor(COLORREF clrText); + BOOL SetTextColor(COLORREF clrText); + BOOL SetTileInfo(struct LVTILEINFO *plvtinfo); + BOOL SetTileViewInfo(struct LVTILEVIEWINFO *plvtvinfo); + HWND SetToolTips(HWND ToolTip); + BOOL SetUnicodeFormat(BOOL fUnicode); + int SetView(DWORD iView); + void SetWorkAreas(int nWorkAreas, RECT *lprc); + int SubItemHitTest(struct LVHITTESTINFO *pInfo) const; + int SubItemHitTestEx(struct LVHITTESTINFO *plvhti); + BOOL Update(int iItem); + + #ifdef _MSC_VER + int SortGroups(PFNLVGROUPCOMPARE pfnGroupCompare, LPVOID plv); + BOOL SortItems(PFNLVCOMPARE pfnCompare, LPARAM lParamSort); + BOOL SortItemsEx(PFNLVCOMPARE pfnCompare, LPARAM lParamSort); + #endif // _MSC_VER + + // Additional APIs + HIMAGELIST CreateImageList(int iImageList); + void AddColumn(int iSubItem, const wchar_t *name, int cx); + void AddGroup(int iGroupId, const wchar_t *name); + int AddItem(const wchar_t *text, int iIcon, LPARAM lParam = 0, int iGroupId = -1); + void SetItem(int iItem, int iSubItem, const wchar_t *text, int iIcon = -1); + LPARAM GetItemData(int iItem) const; + + // Events + struct TEventInfo { + CCtrlListView *treeviewctrl; + union { + struct NMHDR *nmhdr; + struct NMLISTVIEW *nmlv; + struct NMLVDISPINFO *nmlvdi; + struct NMLVSCROLL *nmlvscr; + struct NMLVGETINFOTIP *nmlvit; + struct NMLVFINDITEM *nmlvfi; + struct NMITEMACTIVATE *nmlvia; + struct NMLVKEYDOWN *nmlvkey; + struct NMLVCUSTOMDRAW *nmcd; + }; + }; + + CCallback OnBeginDrag; + CCallback OnBeginLabelEdit; + CCallback OnBeginRDrag; + CCallback OnBeginScroll; + CCallback OnColumnClick; + CCallback OnCustomDraw; + CCallback OnDeleteAllItems; + CCallback OnDeleteItem; + CCallback OnClick; + CCallback OnDoubleClick; + CCallback OnEndLabelEdit; + CCallback OnEndScroll; + CCallback OnGetDispInfo; + CCallback OnGetInfoTip; + CCallback OnHotTrack; + CCallback OnIncrementalSearch; + CCallback OnInsertItem; + CCallback OnItemActivate; + CCallback OnItemChanged; + CCallback OnItemChanging; + CCallback OnKeyDown; + CCallback OnMarqueeBegin; + CCallback OnSetDispInfo; + +protected: + BOOL OnNotify(int idCtrl, NMHDR *pnmh) override; + void GetCaretPos(CContextMenuPos&) const override; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlTreeView + +#undef GetNextSibling +#undef GetPrevSibling + +#define MTREE_CHECKBOX 0x0001 +#define MTREE_DND 0x0002 +#define MTREE_MULTISELECT 0x0004 + +class MIR_CORE_EXPORT CCtrlTreeView : public CCtrlBase +{ + typedef CCtrlBase CSuper; + + HTREEITEM MoveItemAbove(HTREEITEM hItem, HTREEITEM hInsertAfter, HTREEITEM hParent); + +public: + CCtrlTreeView(CDlgBase *dlg, int ctrlId); + + void SetFlags(uint32_t dwFlags); // MTREE_* combination + + // Classic TV interface + HIMAGELIST CreateDragImage(HTREEITEM hItem); + void DeleteAllItems(); + void DeleteItem(HTREEITEM hItem); + HWND EditLabel(HTREEITEM hItem); + void EndEditLabelNow(BOOL cancel); + void EnsureVisible(HTREEITEM hItem); + void Expand(HTREEITEM hItem, DWORD flag); + COLORREF GetBkColor() const; + DWORD GetCheckState(HTREEITEM hItem) const; + HTREEITEM GetChild(HTREEITEM hItem) const; + int GetCount() const; + HTREEITEM GetDropHilight() const; + HWND GetEditControl() const; + HTREEITEM GetFirstVisible() const; + HIMAGELIST GetImageList(int iImage) const; + int GetIndent() const; + COLORREF GetInsertMarkColor() const; + bool GetItem(struct TVITEMEX *tvi) const; + int GetItemHeight() const; + void GetItemRect(HTREEITEM hItem, RECT *rcItem, BOOL fItemRect) const; + DWORD GetItemState(HTREEITEM hItem, DWORD stateMask) const; + HTREEITEM GetLastVisible() const; + COLORREF GetLineColor() const; + HTREEITEM GetNextItem(HTREEITEM hItem, DWORD flag) const; + HTREEITEM GetNextSibling(HTREEITEM hItem) const; + HTREEITEM GetNextVisible(HTREEITEM hItem) const; + HTREEITEM GetParent(HTREEITEM hItem) const; + HTREEITEM GetPrevSibling(HTREEITEM hItem) const; + HTREEITEM GetPrevVisible(HTREEITEM hItem) const; + HTREEITEM GetRoot() const; + DWORD GetScrollTime() const; + HTREEITEM GetSelection() const; + COLORREF GetTextColor() const; + HWND GetToolTips() const; + BOOL GetUnicodeFormat() const; + unsigned GetVisibleCount() const; + HTREEITEM HitTest(struct TVHITTESTINFO *hti) const; + HTREEITEM InsertItem(struct TVINSERTSTRUCT *tvis); + void Select(HTREEITEM hItem, DWORD flag); + void SelectDropTarget(HTREEITEM hItem); + void SelectItem(HTREEITEM hItem); + void SelectSetFirstVisible(HTREEITEM hItem); + COLORREF SetBkColor(COLORREF clBack); + void SetCheckState(HTREEITEM hItem, DWORD state); + void SetImageList(HIMAGELIST hIml, int iImage); + void SetIndent(int iIndent); + void SetInsertMark(HTREEITEM hItem, BOOL fAfter); + COLORREF SetInsertMarkColor(COLORREF clMark); + void SetItem(TVITEMEX *tvi); + void SetItemHeight(short cyItem); + void SetItemState(HTREEITEM hItem, DWORD state, DWORD stateMask); + COLORREF SetLineColor(COLORREF clLine); + void SetScrollTime(UINT uMaxScrollTime); + COLORREF SetTextColor(COLORREF clText); + HWND SetToolTips(HWND hwndToolTips); + BOOL SetUnicodeFormat(BOOL fUnicode); + void SortChildren(HTREEITEM hItem, BOOL fRecurse); + void SortChildrenCB(struct TVSORTCB *cb, BOOL fRecurse); + + // Additional stuff + void TranslateItem(HTREEITEM hItem); + void TranslateTree(); + HTREEITEM FindNamedItem(HTREEITEM hItem, const wchar_t *name); + void GetItem(HTREEITEM hItem, TVITEMEX *tvi) const; + void GetItem(HTREEITEM hItem, TVITEMEX *tvi, wchar_t *szText, int iTextLength) const; + void InvertCheck(HTREEITEM hItem); + + bool IsSelected(HTREEITEM hItem); + int GetNumSelected(); + void GetSelected(LIST &selected); + + void Select(HTREEITEM hItem); + void Select(LIST<_TREEITEM> &selected); + void SelectAll(); + void SelectRange(HTREEITEM hStart, HTREEITEM hEnd); + + void Unselect(HTREEITEM hItem); + void UnselectAll(); + + void DropHilite(HTREEITEM hItem); + void DropUnhilite(HTREEITEM hItem); + + // Events + struct TEventInfo { + CCtrlTreeView *treeviewctrl; + union { + struct NMHDR *nmhdr; + struct NMTREEVIEW *nmtv; + struct NMTVKEYDOWN *nmtvkey; + struct NMTVDISPINFO *nmtvdi; + struct NMTVGETINFOTIP *nmtvit; + struct NMTVCUSTOMDRAW *nmcd; + HTREEITEM hItem; // for OnItemChanged + }; + }; + + CCallback OnBeginDrag; + CCallback OnBeginLabelEdit; + CCallback OnBeginRDrag; + CCallback OnCustomDraw; + CCallback OnDeleteItem; + CCallback OnEndLabelEdit; + CCallback OnGetDispInfo; + CCallback OnGetInfoTip; + CCallback OnItemChanged; + CCallback OnItemExpanded; + CCallback OnItemExpanding; + CCallback OnKeyDown; + CCallback OnRightClick; + CCallback OnSelChanged; + CCallback OnSelChanging; + CCallback OnSetDispInfo; + CCallback OnSingleExpand; + +protected: + void OnInit() override; + void OnDestroy() override; + BOOL OnNotify(int idCtrl, NMHDR *pnmh) override; + + void GetCaretPos(CContextMenuPos&) const override; + INT_PTR CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) override; + + union { + uint32_t m_dwFlags; + struct { + bool m_bDndEnabled : 1; + bool m_bDragging : 1; + bool m_bCheckBox : 1; + bool m_bMultiSelect : 1; + }; + }; + HTREEITEM m_hDragItem; // valid if m_bDragging == true +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlTreeOpts - array of options with sections + +class MIR_CORE_EXPORT CCtrlTreeOpts : public CCtrlTreeView +{ + typedef CCtrlTreeView CSuper; + +public: + CCtrlTreeOpts(CDlgBase *dlg, int ctrlId); + ~CCtrlTreeOpts(); + + void AddOption(const wchar_t *pwszSection, const wchar_t *pwszName, CMOption &option); + + BOOL OnNotify(int idCtrl, NMHDR *pnmh) override; + void OnDestroy() override; + void OnInit() override; + bool OnApply() override; + +protected: + struct COptionsItem + { + const wchar_t *m_pwszSection, *m_pwszName; + + CMOption *m_option; + + HTREEITEM m_hItem = nullptr; + + COptionsItem(const wchar_t *pwszSection, const wchar_t *pwszName, CMOption &option) : + m_pwszSection(pwszSection), + m_pwszName(pwszName), + m_option(&option) + { + } + }; + + OBJLIST m_options; + + void ProcessItemClick(HTREEITEM hti); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CCtrlPages + +#define PSN_INFOCHANGED 1 +#define PSN_PARAMCHANGED 2 + +// force-send a PSN_INFOCHANGED to all pages +#define PSM_FORCECHANGED (WM_USER+100) + +class MIR_CORE_EXPORT CCtrlPages : public CCtrlBase +{ + typedef CCtrlBase CSuper; + + HIMAGELIST m_hIml; + CDlgBase *m_pActivePage; + int m_numRows = 1; + + struct TPageInfo; + void InsertPage(TPageInfo *pPage); + void ShowPage(CDlgBase *pDlg); + + void CheckRowCount(); + TPageInfo* GetCurrPage(); + TPageInfo* GetItemPage(int iPage); + LIST m_pages; + +public: + CCtrlPages(CDlgBase *dlg, int ctrlId); + + void AddPage(const wchar_t *ptszName, HICON hIcon, CDlgBase *pDlg); + void ActivatePage(int iPage); + int GetCount(void); + int GetDlgIndex(CDlgBase*); + void RemovePage(int iPage); + void SwapPages(int idx1, int idx2); + + CDlgBase* GetNthPage(int iPage); + + __forceinline CDlgBase* GetActivePage() const + { return m_pActivePage; + } + +protected: + BOOL OnNotify(int idCtrl, NMHDR *pnmh) override; + + void OnInit() override; + void OnDestroy() override; + + bool OnApply() override; + void OnReset() override; + + INT_PTR CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) override; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// CProtoDlgBase + +#define WM_PROTO_REFRESH (WM_USER + 100) +#define WM_PROTO_CHECK_ONLINE (WM_USER + 101) +#define WM_PROTO_ACTIVATE (WM_USER + 102) +#define WM_PROTO_LAST (WM_USER + 200) + +struct PROTO_INTERFACE; + +class MIR_APP_EXPORT CProtoIntDlgBase : public CDlgBase +{ + typedef CDlgBase CSuper; + +public: + CProtoIntDlgBase(PROTO_INTERFACE *proto, int idDialog); + + void CreateLink(CCtrlData &ctrl, const char *szSetting, BYTE type, DWORD iValue); + void CreateLink(CCtrlData &ctrl, const char *szSetting, wchar_t *szValue); + + template + __inline void CreateLink(CCtrlData &ctrl, CMOption &option) + { + ctrl.CreateDbLink(new CMOptionLink(option)); + } + + __inline PROTO_INTERFACE *GetProtoInterface() { return m_proto_interface; } + + void SetStatusText(const wchar_t *statusText); + +protected: + PROTO_INTERFACE *m_proto_interface; + HWND m_hwndStatus = nullptr; + + INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override; + + virtual void OnProtoRefresh(WPARAM, LPARAM); + virtual void OnProtoActivate(WPARAM, LPARAM); + virtual void OnProtoCheckOnline(WPARAM, LPARAM); + +private: + void UpdateStatusBar(); +}; + +template +class CProtoDlgBase : public CProtoIntDlgBase +{ + typedef CProtoIntDlgBase CSuper; + +public: + __inline CProtoDlgBase(TProto *proto, int idDialog) : + CProtoIntDlgBase(proto, idDialog), + m_proto(proto) + { + } + + __inline TProto *GetProto() { return m_proto; } + +protected: + TProto* m_proto; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Safe open/close dialogs +#define UI_SAFE_OPEN(dlgClass, dlgPtr) \ + { \ + if (dlgPtr) \ + { \ + SetForegroundWindow((dlgPtr)->GetHwnd()); \ + } else \ + { \ + (dlgPtr) = new dlgClass(this); \ + (dlgPtr)->Show(); \ + } \ + } + +#define UI_SAFE_OPEN_EX(dlgClass, dlgPtr, dlgLocal) \ + if (dlgPtr) \ + { \ + ::SetForegroundWindow((dlgPtr)->GetHwnd()); \ + } else \ + { \ + (dlgPtr) = new dlgClass(this); \ + (dlgPtr)->Show(); \ + } \ + dlgClass *dlgLocal = (dlgClass *)(dlgPtr); + +#define UI_SAFE_CLOSE(dlg) \ + { \ + if (dlg) { \ + (dlg)->Close(); \ + (dlg) = NULL; \ + } \ + } + +#define UI_SAFE_CLOSE_HWND(hwnd) \ + { \ + if (hwnd) { \ + ::SendMessage((hwnd), WM_CLOSE, 0, 0); \ + (hwnd) = NULL; \ + } \ + } + +///////////////////////////////////////////////////////////////////////////////////////// +// NULL-Safe dialog notifications +#define UI_SAFE_NOTIFY(dlg, msg) \ + { \ + if (dlg) \ + ::SendMessage((dlg)->GetHwnd(), msg, 0, 0); \ + } + +#define UI_SAFE_NOTIFY_HWND(hwnd, msg) \ + { \ + if (hwnd) \ + ::SendMessage((hwnd), msg, 0, 0); \ + } + +///////////////////////////////////////////////////////////////////////////////////////// +// Define message maps +#define UI_MESSAGE_MAP(dlgClass, baseDlgClass) \ + typedef baseDlgClass CMessageMapSuperClass; \ + virtual INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) \ + { \ + switch (msg) \ + { \ + case 0: \ + break /* just to handle ";" symbol after macro */ + +#define UI_MESSAGE(msg, proc) \ + case msg: \ + proc(msg, wParam, lParam); \ + break + +#define UI_MESSAGE_EX(msg, func) \ + case msg: \ + return func(msg, wParam, lParam) + +#define UI_POSTPROCESS_MESSAGE(msg, proc) \ + case msg: \ + CMessageMapSuperClass::DlgProc(msg, wParam, lParam); \ + return FALSE + +#define UI_POSTPROCESS_MESSAGE_EX(msg, func) \ + case msg: \ + CMessageMapSuperClass::DlgProc(msg, wParam, lParam); \ + return func(msg, wParam, lParam) + +#define UI_MESSAGE_MAP_END() \ + } \ + return CMessageMapSuperClass::DlgProc(msg, wParam, lParam); \ + } + +#endif // __M_GUI_H diff --git a/include/m_netlib.h b/include/m_netlib.h index b821af977a..8c3e1e1d24 100644 --- a/include/m_netlib.h +++ b/include/m_netlib.h @@ -1,865 +1,865 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) -Copyright (c) 2000-12 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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_NETLIB_H__ -#define M_NETLIB_H__ 1 - -#include "m_utils.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// this module was created in 0.1.2.2 -// All error codes are returned via GetLastError() (or WSAGetLastError(): -// they're the same). -// This module is thread-safe where it is sensible for it to be so. This -// basically means that you can call anything from any thread, but don't try -// to predict what will happen if you try to recv() on the same connection from -// two different threads at the same time. -// Note that because the vast majority of the routines in this module return -// a pointer, I have decided to diverge from the rest of Miranda and go with -// the convention that functions return false on failure and nonzero on success. - -struct NETLIBHTTPREQUEST; -struct NETLIBOPENCONNECTION; - -#define NETLIB_USER_AGENT "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.112 Safari/537.36" - -///////////////////////////////////////////////////////////////////////////////////////// -// Initialises the netlib for a set of connections -// Returns a HNETLIBUSER to be used for future netlib calls, NULL on failure -// NOTE: Netlib is loaded after any plugins, so you need to wait until -// ME_SYSTEM_MODULESLOADED before calling this function -// Netlib settings are stored under the module szSettingsModule -// All netlib settings being with "NL". -// The default settings for registered users that don't have any settings stored -// in the database are the same as those displayed by the page -// of the netlib options page. -// Errors: ERROR_INVALID_PARAMETER, ERROR_OUTOFMEMORY, ERROR_DUP_NAME - -struct NETLIBUSER -{ - char *szSettingsModule; // used for db settings and log - MAllStrings szDescriptiveName; // used in options dialog, already translated - DWORD flags; - int minIncomingPorts; // only if NUF_INCOMING. Will be used for validation of user input. -}; - -#define NUF_INCOMING 0x01 // binds incoming ports -#define NUF_OUTGOING 0x02 // makes outgoing plain connections -#define NUF_NOOPTIONS 0x08 // don't create an options page for this. szDescriptiveName is never used. -#define NUF_HTTPCONNS 0x10 // at least some connections are made for HTTP communication. Enables the HTTP proxy option in options. -#define NUF_NOHTTPSOPTION 0x20 // disable the HTTPS proxy option in options. Use this if all communication is HTTP. -#define NUF_UNICODE 0x40 // if set ptszDescriptiveName points to Unicode, otherwise it points to ANSI string - -EXTERN_C MIR_APP_DLL(HNETLIBUSER) Netlib_RegisterUser(const NETLIBUSER *pDescr); - -///////////////////////////////////////////////////////////////////////////////////////// -// Assign a Netlib user handle a set of dynamic HTTP headers to be used with all -// -// HTTP connections that enable the HTTP-use-sticky headers flag. -// The headers persist until cleared with lParam = NULL. -// -// All memory should be allocated by the caller using malloc() from MS_SYSTEM_GET_MMI -// Once it has passed to Netlib, Netlib is the owner of it, the caller should not refer to the memory -// In any way after this point. -// -// NOTE: The szHeaders parameter should be a NULL terminated string following the HTTP header syntax. -// This string will be injected verbatim, thus the user should be aware of setting strings that are not -// headers. This service is NOT THREAD SAFE, only a single thread is expected to set the headers and a single -// thread reading the pointer internally, stopping race conditions and mutual exclusion don't happen. -// -// Version 0.3.2a+ (2003/10/27) -// - -EXTERN_C MIR_APP_DLL(int) Netlib_SetStickyHeaders(HNETLIBUSER nlu, const char *szHeaders); - -/* Notes on HTTP gateway usage -When a connection is initiated through an HTTP proxy using -MS_NETLIB_OPENCONNECTION, netlib will GET nlu.szHttpGatewayHello and read -the replied headers. Once this succeeds nlu.pfnHttpGatewayInit will be called -with a valid handle to the connection, the NETLIBOPENCONNECTION structure that -MS_NETLIB_OPENCONNECTION was called with, and the replied HTTP headers as its -parameters. This function is responsible for recving and parsing the data then -calling MS_NETLIB_SETHTTPPROXYINFO with the appropriate information. -nlu.pfnHttpGatewayInit should return nonzero on success. If it returns zero -then the entire connection attempt will return signalling failure. If your -function needs to return an error code it can do so via SetLastError(). -If nlu.pfnHttpGatewayInit returns success without having called -MS_NETLIB_SETHTTPPROXYINFO then the connection attempt will fail anyway. -If you need more fine-tuned control over the GET/POST URLs than just appending -sequence numbers you can call MS_NETLIB_SETHTTPPROXYINFO from within your -wrap/unwrap functions (see below). - -Just prior to MS_NETLIB_OPENCONNECTION returning nlu.pfnHttpGatewayBegin is -called with the handle to the connection and the NETLIBOPENCONNECTION structure -as its parameters. This is for gateways that need special non-protocol -initialisation. If you do send any packets in this function, you probably want -to remember to use the MSG_NOHTTPGATEWAYWRAP flag. This function pointer can be -NULL if this functionality isn't needed. This function must return nonzero on -success. If it fails the connect attempt will return failure without changing -LastError. - -Whenever MS_NETLIB_SEND is called on a connection through an HTTP proxy and -the MSG_NOHTTPGATEWAYWRAP flags is not set and nlu.pfnHttpGatewayWrapSend is -not NULL, nlu.pfnHttpGatewayWrapSend will be called *instead* of sending the -data. It is this function's responsibility to wrap the sending data -appropriately for transmission and call pfnNetlibSend to send it again. -The flags parameter to nlu.pfnHttpGatewayWrapSend should be passed straight -through to the pfnNetlibSend call. It has already been ORed with -MSG_NOHTTPGATEWAYWRAP. nlu.pfnHttpGatewayWrapSend should return the a -number of the same type as MS_NETLIB_SEND, ie the number of bytes sent or -SOCKET_ERROR. The number of wrapping bytes should be subtracted so that the -return value appears as if the proxy wasn't there. -pfnNetlibSend() is identical to CallService(MS_NETLIB_SEND, ...) but it's -quicker to call using this pointer than to do the CallService() lookup again. - -Whenever an HTTP reply is received inside MS_NETLIB_RECV the headers and data -are read into memory. If the headers indicate success then the data is passed -to nlu.pfnHttpGatewayUnwrapRecv (if it's non-NULL) for processing. This -function should remove (and do other processing if necessary) all HTTP proxy -specific headers and return a pointer to the buffer whose size is returned in -*outBufLen. If the buffer needs to be resized then NetlibRealloc() should be -used for that purpose, *not* your own CRT's realloc(). NetlibRealloc() behaves -identically to realloc() so it's possible to free the original buffer and -create a new one if that's the most sensible way to write your parser. -If errors are encountered you should SetLastError() and return NULL; -MS_NETLIB_RECV will return SOCKET_ERROR. If the passed buffer unwraps to -contain no actual data you should set *outBufLen to 0 but make sure you return -some non-NULL buffer that can be freed. - -When you call MS_NETLIB_SEND or MS_NETLIB_RECV from any of these functions, you -should use the MSG_DUMPPROXY flag so that the logging is neat. -*/ - -#define PROXYTYPE_SOCKS4 1 -#define PROXYTYPE_SOCKS5 2 -#define PROXYTYPE_HTTP 3 -#define PROXYTYPE_HTTPS 4 -#define PROXYTYPE_IE 5 - -struct NETLIBUSERSETTINGS -{ - int cbSize; // to be filled in before calling - int useProxy; // 1 or 0 - int proxyType; // a PROXYTYPE_ - char *szProxyServer; // can be NULL - int wProxyPort; // host byte order - int useProxyAuth; // 1 or 0. Always 0 for SOCKS4 - char *szProxyAuthUser; // can be NULL, always used by SOCKS4 - char *szProxyAuthPassword; // can be NULL - int useProxyAuthNtlm; // 1 or 0, only used by HTTP, HTTPS - int dnsThroughProxy; // 1 or 0 - int specifyIncomingPorts; // 1 or 0 - char *szIncomingPorts; // can be NULL. Of form "1024-1050, 1060-1070, 2000" - int specifyOutgoingPorts; // 0.3.3a+ - char *szOutgoingPorts; // 0.3.3a+ - int enableUPnP; // 0.6.1+ only for NUF_INCOMING - int validateSSL; -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Gets the user-configured settings for a netlib user -// -// Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib) -// The pointers referred to in the returned struct will remain valid until -// the hUser handle is closed, or until the user changes the settings in the -// options page, so it's best not to rely on them for too long. -// Errors: ERROR_INVALID_PARAMETER - -EXTERN_C MIR_APP_DLL(int) Netlib_GetUserSettings(HNETLIBUSER nlu, NETLIBUSERSETTINGS *result); - -///////////////////////////////////////////////////////////////////////////////////////// -//Gets the user-configured settings for a netlib user idetified by name -// -//Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib) -//This function behaves like Netlib_GetUserSettings but the user is identified -//by the name provided by registration. When the name is not found NETLIBUSERSETTINGS is set to NULL. -//Errors: ERROR_INVALID_PARAMETER - -EXTERN_C MIR_APP_DLL(int) Netlib_GetUserSettingsByName(char * UserSettingsName, NETLIBUSERSETTINGS *result); - -///////////////////////////////////////////////////////////////////////////////////////// -// Changes the user-configurable settings for a netlib user -// -// Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib) -// This function is only really useful for people that specify NUF_NOOPTIONS -// and want to create their own options. -// Even if a setting is not active (eg szProxyAuthPassword when useProxyAuth is -// zero) that settings is still set for use in the options dialog. -// Errors: ERROR_INVALID_PARAMETER - -EXTERN_C MIR_APP_DLL(int) Netlib_SetUserSettings(HNETLIBUSER nlu, const NETLIBUSERSETTINGS *result); - -///////////////////////////////////////////////////////////////////////////////////////// -//Changes the user-configurable settings for a netlib user idetified by name -// -//Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib) -//This function behaves like Netlib_SetUserSettings but the user is identified -//by the name provided by registration. Nothing will be changed when the name is not found. -//Errors: ERROR_INVALID_PARAMETER - -EXTERN_C MIR_APP_DLL(int) Netlib_SetUserSettingsByName(char * UserSettingsName, NETLIBUSERSETTINGS *result); - -///////////////////////////////////////////////////////////////////////////////////////// -// Closes a netlib handle -// -// Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib) -// This function should be called on all handles returned by netlib functions -// once you are done with them. If it's called on a socket-type handle, the -// socket will be closed. -// Errors: ERROR_INVALID_PARAMETER - -EXTERN_C MIR_APP_DLL(int) Netlib_CloseHandle(HANDLE h); - -///////////////////////////////////////////////////////////////////////////////////////// -// Open a port and wait for connections on it -// -// Returns a HANDLE on success, NULL on failure -// hUser should have been returned by MS_NETLIB_REGISTERUSER -// This function does the equivalent of socket(), bind(), getsockname(), -// listen(), accept() -// Internally this function creates a new thread which waits around in accept() -// for new connections. When one is received it calls nlb.pfnNewConnection *from -// this new thread* and then loops back to wait again. -// Close the returned handle to end the thread and close the open port. -// Errors: ERROR_INVALID_PARAMETER, any returned by socket() or bind() or -// listen() or getsockname() -// -// Notes: -// -// During development of 0.3.1a+ (2003/07/04) passing wPort != 0 -// will result in an attempt to bind on the port given in wPort -// if this port is taken then you will get an error, so be sure to check -// for such conditions. -// -// passing wPort != 0 is for people who need to open a set port for -// daemon activities, usually passing wPort == 0 is what you want and -// will result in a free port given by the TCP/IP socket layer and/or -// seeded from the user selected port ranges. -// -// also note that wPort if != 0, will have be converted to network byte order -// -/* pExtra was added during 0.3.4+, prior its just two args, since we use the cdecl convention -it shouldnt matter */ - -typedef void (*NETLIBNEWCONNECTIONPROC)(HNETLIBCONN hNewConnection, DWORD dwRemoteIP, void *pExtra); - -struct NETLIBBIND -{ - NETLIBNEWCONNECTIONPROC pfnNewConnection; - - // function to call when there's a new connection. Params are: the - // new connection, IP of remote machine (host byte order) - DWORD dwInternalIP; // set on return, host byte order - DWORD dwExternalIP; // set on return, host byte order - WORD wPort, wExPort; // set on return, host byte order - void *pExtra; // argument is sent to callback -}; - -EXTERN_C MIR_APP_DLL(HNETLIBBIND) Netlib_BindPort(HNETLIBUSER nlu, NETLIBBIND *nlb); - -///////////////////////////////////////////////////////////////////////////////////////// -// Open a connection -// -// Returns a HNETLIBCONN to the new connection on success, NULL on failure -// hUser must have been returned by MS_NETLIB_REGISTERUSER -// Internally this function is the equivalent of socket(), gethostbyname(), -// connect() -// If NLOCF_HTTP is set and hUser is configured for an HTTP or HTTPS proxy then -// this function will connect() to the proxy server only, without performing any -// initialisation conversation. -// If hUser is configured for an HTTP proxy and does not support HTTP gateways -// and you try to open a connection without specifying NLOCF_HTTP then this -// function will first attempt to open an HTTPS connection, if that fails it -// will try a direct connection, if that fails it will return failure with the -// error from the connect() during the direct connection attempt. -// Errors: ERROR_INVALID_PARAMETER, any returned by socket(), gethostbyname(), -// connect(), MS_NETLIB_SEND, MS_NETLIB_RECV, select() -// ERROR_TIMEOUT (during proxy communication) -// ERROR_BAD_FORMAT (very invalid proxy reply) -// ERROR_ACCESS_DENIED (by proxy) -// ERROR_CONNECTION_UNAVAIL (socks proxy can't connect to identd) -// ERROR_INVALID_ACCESS (proxy refused identd auth) -// ERROR_INVALID_DATA (proxy returned invalid code) -// ERROR_INVALID_ID_AUTHORITY (proxy requires use of auth method that's not supported) -// ERROR_GEN_FAILURE (socks5/https general failure) -// ERROR_CALL_NOT_IMPLEMENTED (socks5 command not supported) -// ERROR_INVALID_ADDRESS (socks5 address type not supported) -// HTTP: anything from nlu.pfnHttpGatewayInit, nlu.pfnHttpGatewayBegin, -// MS_NETLIB_SENDHTTPREQUEST or MS_NETLIB_RECVHTTPHEADERS - -#define NLOCF_HTTP 0x0001 // this connection will be used for HTTP communications. If configured for an HTTP/HTTPS proxy the connection is opened as if there was no proxy. -#define NLOCF_STICKYHEADERS 0x0002 // this connection should send the sticky headers associated with NetLib user apart of any HTTP request -#define NLOCF_V2 0x0004 // this connection understands the newer structure, newer cbSize isnt enough -#define NLOCF_UDP 0x0008 // this connection is UDP -#define NLOCF_SSL 0x0010 // this connection is SSL - -struct NETLIBOPENCONNECTION -{ - const char *szHost; // can contain the string representation of an IP - WORD wPort; // host byte order - DWORD flags; - unsigned int timeout; - /* optional, called in the context of the thread that issued the attempt, if it returns 0 the connection attempt is - stopped, the remaining timeout value can also be adjusted */ - int (*waitcallback) (unsigned int *timeout); -}; - -EXTERN_C MIR_APP_DLL(HNETLIBCONN) Netlib_OpenConnection(HNETLIBUSER nlu, const NETLIBOPENCONNECTION *nloc); - -///////////////////////////////////////////////////////////////////////////////////////// -// Sets the required information for an HTTP proxy connection -// -// Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib) -// This function is designed to be called from within pfnHttpGatewayInit -// See notes below MS_NETLIB_REGISTERUSER. -// Errors: ERROR_INVALID_PARAMETER - -#define NLHPIF_USEGETSEQUENCE 0x0001 // append sequence numbers to GET requests -#define NLHPIF_USEPOSTSEQUENCE 0x0002 // append sequence numbers to POST requests -#define NLHPIF_GETPOSTSAMESEQUENCE 0x0004 // GET and POST use the same sequence -#define NLHPIF_HTTP11 0x0008 // HTTP 1.1 proxy - -struct NETLIBHTTPPROXYINFO -{ - DWORD flags; - int firstGetSequence, firstPostSequence; - int combinePackets; - char *szHttpPostUrl; - char *szHttpGetUrl; -}; - -EXTERN_C MIR_APP_DLL(int) Netlib_SetHttpProxyInfo(HNETLIBCONN hConnection, const NETLIBHTTPPROXYINFO *nlhpi); - -///////////////////////////////////////////////////////////////////////////////////////// -// Gets the SOCKET associated with a netlib handle -// -// Returns the SOCKET on success, INVALID_SOCKET on failure -// hNetlibHandle should have been returned by MS_NETLIB_BINDPORT or -// MS_NETLIB_OPENCONNECTION only. -// Be careful how you use this socket because you might be connected via an -// HTTP proxy in which case calling send() or recv() will totally break things. -// Errors: ERROR_INVALID_PARAMETER - -EXTERN_C MIR_APP_DLL(UINT_PTR) Netlib_GetSocket(HNETLIBCONN hConnection); - -///////////////////////////////////////////////////////////////////////////////////////// - -#define Netlib_GetBase64DecodedBufferSize(cchEncoded) (((cchEncoded)>>2)*3) -#define Netlib_GetBase64EncodedBufferSize(cbDecoded) (((cbDecoded)*4+11)/12*4+1) - -///////////////////////////////////////////////////////////////////////////////////////// -// Gets HNETLIBUSER owner of a connection - -EXTERN_C MIR_APP_DLL(HNETLIBUSER) Netlib_GetConnNlu(HNETLIBCONN hConn); - -///////////////////////////////////////////////////////////////////////////////////////// -// Gets the fake User-Agent header field to make some sites happy - -EXTERN_C MIR_APP_DLL(char*) Netlib_GetUserAgent(); - -///////////////////////////////////////////////////////////////////////////////////////// -// Converts numerical representation of IP in SOCKADDR_INET into string representation with IP and port -// IPv4 will be supplied in formats address:port or address -// IPv6 will be supplied in formats [address]:port or [address] -// Returns pointer to the string or NULL if not successful - -struct sockaddr_in; -EXTERN_C MIR_APP_DLL(char*) Netlib_AddressToString(sockaddr_in *addr); -EXTERN_C MIR_APP_DLL(bool) Netlib_StringToAddress(const char *str, sockaddr_in *addr); - -///////////////////////////////////////////////////////////////////////////////////////// -// Gets connection Information -// IPv4 will be supplied in formats address:port or address -// IPv6 will be supplied in formats [address]:port or [address] -// Returns 0 if successful - -struct NETLIBCONNINFO -{ - char szIpPort[64]; - unsigned dwIpv4; - WORD wPort; -}; - -EXTERN_C MIR_APP_DLL(int) Netlib_GetConnectionInfo(HNETLIBCONN hConnection, NETLIBCONNINFO *connInfo); - -///////////////////////////////////////////////////////////////////////////////////////// -// Gets connection Information -// -// Returns (INT_PTR)(NETLIBIPLIST*) numeric IP address address array -// the last element of the array is all 0s, 0 if not successful - -struct NETLIBIPLIST -{ - unsigned cbNum; - char szIp[1][64]; -}; - -EXTERN_C MIR_APP_DLL(NETLIBIPLIST*) Netlib_GetMyIp(bool bGlobalOnly); - -///////////////////////////////////////////////////////////////////////////////////////// -// Send an HTTP request over a connection -// -// Returns number of bytes sent on success, SOCKET_ERROR on failure -// hConnection must have been returned by MS_NETLIB_OPENCONNECTION -// Note that if you use NLHRF_SMARTAUTHHEADER and NTLM authentication is in use -// then the full NTLM authentication transaction occurs, comprising sending the -// domain, receiving the challenge, then sending the response. -// nlhr.resultCode and nlhr.szResultDescr are ignored by this function. -// Errors: ERROR_INVALID_PARAMETER, anything returned by MS_NETLIB_SEND - -struct NETLIBHTTPHEADER -{ - char *szName; - char *szValue; -}; - -EXTERN_C MIR_APP_DLL(char*) Netlib_GetHeader(const NETLIBHTTPREQUEST *pRec, const char *pszName); - -///////////////////////////////////////////////////////////////////////////////////////// - -#define REQUEST_RESPONSE 0 // used by structure returned by MS_NETLIB_RECVHTTPHEADERS -#define REQUEST_GET 1 -#define REQUEST_POST 2 -#define REQUEST_CONNECT 3 -#define REQUEST_HEAD 4 -#define REQUEST_PUT 5 -#define REQUEST_DELETE 6 -#define REQUEST_PATCH 7 - -#define NLHRF_MANUALHOST 0x00000001 // do not remove any host and/or protocol portion of szUrl before sending it -#define NLHRF_HTTP11 0x00000010 // use HTTP 1.1 -#define NLHRF_PERSISTENT 0x00000020 // preserve connection on exit, open connection provided in the nlc field of the reply - // it should be supplied in nlc field of request for reuse or closed if not needed -#define NLHRF_SSL 0x00000040 // use SSL connection -#define NLHRF_NOPROXY 0x00000080 // do not use proxy server -#define NLHRF_REDIRECT 0x00000100 // handle HTTP redirect requests (response 30x), the resulting url provided in szUrl of the response -#define NLHRF_NODUMP 0x00010000 // never dump this to the log -#define NLHRF_NODUMPHEADERS 0x00020000 // don't dump http headers (only useful for POSTs and MS_NETLIB_HTTPTRANSACTION) -#define NLHRF_DUMPPROXY 0x00040000 // this transaction is a proxy communication. For dump filtering only. -#define NLHRF_DUMPASTEXT 0x00080000 // dump posted and reply data as text. Headers are always dumped as text. -#define NLHRF_NODUMPSEND 0x00100000 // do not dump sent message. - -struct NETLIBHTTPREQUEST -{ - int cbSize; - int requestType; // a REQUEST_ - DWORD flags; - char *szUrl; - NETLIBHTTPHEADER *headers; // If this is a POST request and headers - // doesn't contain a Content-Length it'll be added automatically - int headersCount; - char *pData; // data to be sent in POST request. - int dataLength; // must be 0 for REQUEST_GET/REQUEST_CONNECT - int resultCode; - char *szResultDescr; - HNETLIBCONN nlc; - int timeout; - - __forceinline const char *operator[](const char *pszName) { - return Netlib_GetHeader(this, pszName); - } -}; - -EXTERN_C MIR_APP_DLL(int) Netlib_SendHttpRequest(HNETLIBCONN hConnection, NETLIBHTTPREQUEST *pRec); - -///////////////////////////////////////////////////////////////////////////////////////// -// Receives HTTP headers -// -// Returns a pointer to a NETLIBHTTPREQUEST structure on success, NULL on failure. -// Call Netlib_FreeHttpRequest() to free this. -// hConnection must have been returned by MS_NETLIB_OPENCONNECTION -// nlhr->pData = NULL and nlhr->dataLength = 0 always. The requested data should -// be retrieved using MS_NETLIB_RECV once the header has been parsed. -// If the headers haven't finished within 60 seconds the function returns NULL -// and ERROR_TIMEOUT. -// Errors: ERROR_INVALID_PARAMETER, any from MS_NETLIB_RECV or select() -// ERROR_HANDLE_EOF (connection closed before headers complete) -// ERROR_TIMEOUT (headers still not complete after 60 seconds) -// ERROR_BAD_FORMAT (invalid character or line ending in headers, or first line is blank) -// ERROR_BUFFER_OVERFLOW (each header line must be less than 4096 chars long) -// ERROR_INVALID_DATA (first header line is malformed ("http/[01].[0-9] [0-9]+ .*", or no colon in subsequent line) - -EXTERN_C MIR_APP_DLL(NETLIBHTTPREQUEST*) Netlib_RecvHttpHeaders(HNETLIBCONN hConnection, int flags = 0); - -///////////////////////////////////////////////////////////////////////////////////////// -// Free the memory used by a NETLIBHTTPREQUEST structure -// -// Returns true on success, false on failure (!! this is different to most of the rest of Miranda, but consistent with netlib) -// This should only be called on structures returned by -// MS_NETLIB_RECVHTTPHEADERS or MS_NETLIB_HTTPTRANSACTION. Calling it on an -// arbitrary structure will have disastrous results. -// Errors: ERROR_INVALID_PARAMETER - -EXTERN_C MIR_APP_DLL(bool) Netlib_FreeHttpRequest(NETLIBHTTPREQUEST*); - -///////////////////////////////////////////////////////////////////////////////////////// -// smart pointer for NETLIBHTTPREQUEST via a call of Netlib_FreeHttpRequest() - -#ifdef __cplusplus -class NLHR_PTR -{ -protected: - NETLIBHTTPREQUEST *_p; - -public: - __forceinline explicit NLHR_PTR(NETLIBHTTPREQUEST *p) : _p(p) {} - - __forceinline NETLIBHTTPREQUEST* operator=(INT_PTR i_p) - { - return operator=((NETLIBHTTPREQUEST*)i_p); - } - __forceinline NETLIBHTTPREQUEST* operator=(NETLIBHTTPREQUEST *p) - { - if (_p) - Netlib_FreeHttpRequest(_p); - _p = p; - return _p; - } - __forceinline operator NETLIBHTTPREQUEST*() const { return _p; } - __forceinline NETLIBHTTPREQUEST* operator->() const { return _p; } - __forceinline ~NLHR_PTR() - { - Netlib_FreeHttpRequest(_p); - } -}; - -struct MIR_APP_EXPORT MHttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject -{ - MHttpRequest(); - ~MHttpRequest(); - - CMStringA m_szUrl; - CMStringA m_szParam; - void *pUserInfo = nullptr; - - void AddHeader(const char *szName, const char *szValue); -}; - -template -class MTHttpRequest : public MHttpRequest -{ -public: - __forceinline MTHttpRequest() - {} - - typedef void (T::*MTHttpRequestHandler)(NETLIBHTTPREQUEST*, struct AsyncHttpRequest*); - MTHttpRequestHandler m_pFunc = nullptr; -}; - -MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest*, const INT_PARAM&); -MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest*, const INT64_PARAM&); -MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest*, const CHAR_PARAM&); -MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest*, const WCHAR_PARAM&); - -#endif - -///////////////////////////////////////////////////////////////////////////////////////// -// Do an entire HTTP transaction -// -// Returns a pointer to another NETLIBHTTPREQUEST structure on success, NULL on failure. -// Call Netlib_FreeHttpRequest() to free this. -// hUser must have been returned by MS_NETLIB_REGISTERUSER -// nlhr.szUrl should be a full HTTP URL. If it does not start with http:// , that -// will be assumed (but it's best not to use this fact, for reasons of -// extensibility). -// This function is the equivalent of MS_NETLIB_OPENCONNECTION, -// MS_NETLIB_SENDHTTPREQ, MS_NETLIB_RECVHTTPHEADERS, MS_NETLIB_RECV, -// MS_NETLIB_CLOSEHANDLE -// nlhr.headers will be augmented with the following headers unless they have -// already been set by the caller: -// "Host" (regardless of whether it is requested in nlhr.flags) -// "User-Agent" (of the form "Miranda/0.1.2.2 (alpha)" or "Miranda/0.1.2.2") -// "Content-Length" (for POSTs only. Set to nlhr.dataLength) -// If you do not want to send one of these headers, create a nlhr.headers with -// szValue = NULL. -// In the return value headers, headerCount, pData, dataLength, resultCode and -// szResultDescr are all valid. -// In the return value pData[dataLength] == 0 always, as an extra safeguard -// against programming slips. -// Note that the function can succeed (ie not return NULL) yet result in an HTTP -// error code. You should check that resultCode == 2xx before proceeding. -// Errors: ERROR_INVALID_PARAMETER, ERROR_OUTOFMEMORY, anything from the above -// list of functions - -EXTERN_C MIR_APP_DLL(NETLIBHTTPREQUEST*) Netlib_HttpTransaction(HNETLIBUSER hNlu, NETLIBHTTPREQUEST *pRequest); - -///////////////////////////////////////////////////////////////////////////////////////// -// Send data over a connection -// -// Returns the number of bytes sent on success, SOCKET_ERROR on failure -// Errors: ERROR_INVALID_PARAMETER -// anything from send(), nlu.pfnHttpGatewayWrapSend() -// HTTP proxy: ERROR_GEN_FAILURE (http result code wasn't 2xx) -// anything from socket(), connect(), -// MS_NETLIB_SENDHTTPREQUEST, MS_NETLIB_RECVHTTPHEADERS -// flags: - -#define MSG_NOHTTPGATEWAYWRAP 0x010000 // don't wrap the outgoing packet using nlu.pfnHttpGatewayWrapSend -#define MSG_NODUMP 0x020000 // don't dump this packet to the log -#define MSG_DUMPPROXY 0x040000 // this is proxy communiciation. For dump filtering only. -#define MSG_DUMPASTEXT 0x080000 // this is textual data, don't dump as hex -#define MSG_RAW 0x100000 // send as raw data, bypass any HTTP proxy stuff -#define MSG_DUMPSSL 0x200000 // this is SSL traffic. For dump filtering only. -#define MSG_NOTITLE 0x400000 // skip date, time & protocol from dump - -EXTERN_C MIR_APP_DLL(int) Netlib_Send(HNETLIBCONN hConn, const char *buf, int len, int flags = 0); - -///////////////////////////////////////////////////////////////////////////////////////// -// Receive data over a connection -// -// Returns the number of bytes read on success, SOCKET_ERROR on failure, -// 0 if the connection has been closed -// Flags supported: MSG_PEEK, MSG_NODUMP, MSG_DUMPPROXY, MSG_NOHTTPGATEWAYWRAP, -// MSG_DUMPASTEXT, MSG_RAW -// On using MSG_NOHTTPGATEWAYWRAP: Because packets through an HTTP proxy are -// batched and cached and stuff, using this flag is not a guarantee that it -// will be obeyed, and if it is it may even be propogated to future calls -// even if you don't specify it then. Because of this, the flag should be -// considered an all-or-nothing thing: either use it for the entire duration -// of a connection, or not at all. -// Errors: ERROR_INVALID_PARAMETER, anything from recv() -// HTTP proxy: ERROR_GEN_FAILURE (http result code wasn't 2xx) -// ERROR_INVALID_DATA (no Content-Length header in reply) -// ERROR_NOT_ENOUGH_MEMORY (Content-Length very large) -// ERROR_HANDLE_EOF (connection closed before Content-Length bytes recved) -// anything from select(), MS_NETLIB_RECVHTTPHEADERS, -// nlu.pfnHttpGatewayUnwrapRecv, socket(), connect(), -// MS_NETLIB_SENDHTTPREQUEST - -EXTERN_C MIR_APP_DLL(int) Netlib_Recv(HNETLIBCONN hConn, char *buf, int len, int flags = 0); - -///////////////////////////////////////////////////////////////////////////////////////// -// Determine the status of one or more connections -// Returns the number of ready connections, SOCKET_ERROR on failure, 0 if the timeout expired. -// All handles passed to this function must have been returned by either -// MS_NETLIB_OPENCONNECTION or MS_NETLIB_BINDPORT. -// The last handle in each list must be followed by either NULL or INVALID_HANDLE_VALUE. -// Errors: ERROR_INVALID_HANDLE, ERROR_INVALID_DATA, anything from select() - -struct NETLIBSELECT -{ - DWORD dwTimeout; // in milliseconds, INFINITE is acceptable - HNETLIBCONN hReadConns[FD_SETSIZE + 1]; - HNETLIBCONN hWriteConns[FD_SETSIZE + 1]; - HNETLIBCONN hExceptConns[FD_SETSIZE + 1]; -}; - -EXTERN_C MIR_APP_DLL(int) Netlib_Select(NETLIBSELECT *nls); - -struct NETLIBSELECTEX -{ - DWORD dwTimeout; // in milliseconds, INFINITE is acceptable - HNETLIBCONN hReadConns[FD_SETSIZE + 1]; - HNETLIBCONN hWriteConns[FD_SETSIZE + 1]; - HNETLIBCONN hExceptConns[FD_SETSIZE + 1]; - - BOOL hReadStatus[FD_SETSIZE+1]; /* out, [in, expected to be FALSE] */ - BOOL hWriteStatus[FD_SETSIZE+1]; /* out, [in, expected to be FALSE] */ - BOOL hExceptStatus[FD_SETSIZE+1]; /* out, [in, expected to be FALSE] */ -}; - -EXTERN_C MIR_APP_DLL(int) Netlib_SelectEx(NETLIBSELECTEX *nls); - -///////////////////////////////////////////////////////////////////////////////////////// -// Shutdown connection - -EXTERN_C MIR_APP_DLL(void) Netlib_Shutdown(HNETLIBCONN h); - -///////////////////////////////////////////////////////////////////////////////////////// -// Create a packet receiver -// -// Returns a HANDLE on success, NULL on failure -// The packet receiver implements the common situation where you have variable -// length packets coming in over a connection and you want to split them up -// in order to handle them. -// The major limitation is that the buffer is created in memory, so you can't -// have arbitrarily large packets. -// Errors: ERROR_INVALID_PARAMETER, ERROR_OUTOFMEMORY - -EXTERN_C MIR_APP_DLL(HANDLE) Netlib_CreatePacketReceiver(HNETLIBCONN hConnection, int iMaxSize); - -///////////////////////////////////////////////////////////////////////////////////////// -// Get the next set of packets from a packet receiver -// -// Returns the total number of bytes available in the buffer, 0 if the -// connection was closed, SOCKET_ERROR on error. -// hPacketRecver must have been returned by MS_NETLIB_CREATEPACKETRECVER -// If nlpr.bytesUsed is set to zero and the buffer is already full up to -// maxPacketSize, it is assumed that too large a packet has been received. All -// data in the buffer is discarded and receiving is begun anew. This will -// probably cause alignment problems so if you think this is likely to happen -// then you should deal with it yourself. -// Closing the packet receiver will not close the associated connection, but -// will discard any bytes still in the buffer, so if you intend to carry on -// reading from that connection, make sure you have processed the buffer first. -// This function is the equivalent of a memmove() to remove the first bytesUsed -// from the buffer, select() if dwTimeout is not INFINITE, then MS_NETLIB_RECV. -// Errors: ERROR_INVALID_PARAMETER, ERROR_TIMEOUT, -// anything from select(), MS_NETLIB_RECV - -struct NETLIBPACKETRECVER -{ - DWORD dwTimeout; // fill before calling. In milliseconds. INFINITE is valid - int bytesUsed; // fill before calling. This many bytes are removed from the start of the buffer. Set to 0 on return - int bytesAvailable; // equal to the return value, unless the return value is 0 - int bufferSize; // same as parameter to MS_NETLIB_CREATEPACKETRECVER - BYTE *buffer; // contains the recved data -}; - -EXTERN_C MIR_APP_DLL(int) Netlib_GetMorePackets(HANDLE hReceiver, NETLIBPACKETRECVER *nlprParam); - -///////////////////////////////////////////////////////////////////////////////////////// -// Sets a gateway polling timeout interval -// -// Returns previous timeout value -// Errors: -1 - -EXTERN_C MIR_APP_DLL(int) Netlib_SetPollingTimeout(HNETLIBCONN hConnection, int iTimeout); - -///////////////////////////////////////////////////////////////////////////////////////// -// netlib log funcitons - -EXTERN_C MIR_APP_DLL(int) Netlib_Log(HNETLIBUSER hUser, const char *pszStr); -EXTERN_C MIR_APP_DLL(int) Netlib_LogW(HNETLIBUSER hUser, const wchar_t *pwszStr); - -EXTERN_C MIR_APP_DLL(int) Netlib_Logf(HNETLIBUSER hUser, _Printf_format_string_ const char *fmt, ...); -EXTERN_C MIR_APP_DLL(int) Netlib_LogfW(HNETLIBUSER hUser, _Printf_format_string_ const wchar_t *fmt, ...); - -EXTERN_C MIR_APP_DLL(void) Netlib_Dump(HNETLIBCONN nlc, const void *buf, size_t len, bool bIsSent, int flags); - -// Inits a required security provider. Right now only NTLM is supported -// Returns HANDLE = NULL on error or non-null value on success -// Known providers: Basic, NTLM, Negotiate, Kerberos, GSSAPI - (Kerberos SASL) -EXTERN_C MIR_APP_DLL(HANDLE) Netlib_InitSecurityProvider(const wchar_t *szProviderName, const wchar_t *szPrincipal = nullptr); - -// Destroys a security provider's handle, provided by Netlib_InitSecurityProvider. -// Right now only NTLM is supported -EXTERN_C MIR_APP_DLL(void) Netlib_DestroySecurityProvider(HANDLE hProvider); - -// Returns the NTLM response string. The result value should be freed using mir_free -EXTERN_C MIR_APP_DLL(char*) Netlib_NtlmCreateResponse(HANDLE hProvider, const char *szChallenge, wchar_t *szLogin, wchar_t *szPass, unsigned &complete); - -///////////////////////////////////////////////////////////////////////////////////////// -// SSL/TLS support - -#if !defined(HSSL_DEFINED) -DECLARE_HANDLE(HSSL); -#endif - -// Makes connection SSL -// Returns 0 on failure 1 on success -EXTERN_C MIR_APP_DLL(int) Netlib_StartSsl(HNETLIBCONN hConnection, const char *host); - -// negotiates SSL session, verifies cert, returns NULL if failed -EXTERN_C MIR_APP_DLL(HSSL) Netlib_SslConnect(SOCKET s, const char* host, int verify); - -// return true if there is either unsend or buffered received data (ie. after peek) -EXTERN_C MIR_APP_DLL(BOOL) Netlib_SslPending(HSSL ssl); - -// reads number of bytes, keeps in buffer if peek != 0 -EXTERN_C MIR_APP_DLL(int) Netlib_SslRead(HSSL ssl, char *buf, int num, int peek); - -// writes data to the SSL socket -EXTERN_C MIR_APP_DLL(int) Netlib_SslWrite(HSSL ssl, const char *buf, int num); - -// closes SSL session, but keeps socket open -EXTERN_C MIR_APP_DLL(void) Netlib_SslShutdown(HSSL ssl); - -// frees all data associated with the SSL socket -EXTERN_C MIR_APP_DLL(void) Netlib_SslFree(HSSL ssl); - -// gets TLS channel binging data for a socket -EXTERN_C MIR_APP_DLL(void*) Netlib_GetTlsUnique(HNETLIBCONN nlc, int &cbLen); - -///////////////////////////////////////////////////////////////////////////////////////// -// WebSocket support - -struct WSHeader -{ - WSHeader() - { - memset(this, 0, sizeof(*this)); - } - - bool bIsFinal, bIsMasked; - int opCode, firstByte; - size_t payloadSize, headerSize; -}; - -// connects to a WebSocket server -EXTERN_C MIR_APP_DLL(NETLIBHTTPREQUEST*) WebSocket_Connect(HNETLIBUSER, const char *szHost, NETLIBHTTPHEADER *pHeaders = nullptr); - -// validates that the provided buffer contains full WebSocket datagram -EXTERN_C MIR_APP_DLL(bool) WebSocket_InitHeader(WSHeader &hdr, const void *pData, size_t bufSize); - -// sends a packet to WebSocket -EXTERN_C MIR_APP_DLL(void) WebSocket_SendText(HNETLIBCONN nlc, const char *pData); -EXTERN_C MIR_APP_DLL(void) WebSocket_SendBinary(HNETLIBCONN nlc, const void *pData, size_t strLen); - -///////////////////////////////////////////////////////////////////////////////////////// -// Netlib hooks (0.8+) - -// WARNING: these hooks are being called in the context of the calling thread, without switching -// to the first thread, like all another events do. The hook procedure should be ready for the -// multithreaded mode -// -// Parameters: -// wParam: NETLIBNOTIFY* - points to the data being sent/received -// lParam: NETLIBUSER* - points to the protocol definition - -struct NETLIBNOTIFY -{ - const char *buf; - int len; - int flags; - int result; // amount of bytes really sent/received -}; - -#define ME_NETLIB_FASTRECV "Netlib/OnRecv" // being called on every receive -#define ME_NETLIB_FASTSEND "Netlib/OnSend" // being called on every send -#define ME_NETLIB_FASTDUMP "Netlib/OnDump" // being called on every dump - -struct NETLIBCONNECTIONEVENTINFO -{ - BOOL connected; // 1-opening socket 0-closing socket - BOOL listening; // 1-bind 0-connect - SOCKADDR_IN local; // local IP+port (always used) - SOCKADDR_IN remote; // remote IP+port (only connect (opening + closing only if no proxy)) - SOCKADDR_IN proxy; // proxy IP+port (only connect when used) - char *szSettingsModule; // name of the registered Netlib user that requested the action -}; - -//This event is sent as a new port is bound or a new connection opened. -//It is NOT sent for sigle HTTP(S) requests. -//wParam=(WPARAM)(NETLIBCONNECTIONEVENTINFO*)hInfo -//lParam=(LPARAM)0 (not used) -#define ME_NETLIB_EVENT_CONNECTED "Netlib/Event/Connected" - -//This event is sent if coneection or listening socket is closed. -//It is NOT sent for sigle HTTP(S) requests. -//wParam=(WPARAM)(NETLIBCONNECTIONEVENTINFO*)hInfo -//lParam=(LPARAM)0 (not used) -#define ME_NETLIB_EVENT_DISCONNECTED "Netlib/Event/Disconnected" - -#endif // M_NETLIB_H__ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2000-12 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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_NETLIB_H__ +#define M_NETLIB_H__ 1 + +#include "m_utils.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// this module was created in 0.1.2.2 +// All error codes are returned via GetLastError() (or WSAGetLastError(): +// they're the same). +// This module is thread-safe where it is sensible for it to be so. This +// basically means that you can call anything from any thread, but don't try +// to predict what will happen if you try to recv() on the same connection from +// two different threads at the same time. +// Note that because the vast majority of the routines in this module return +// a pointer, I have decided to diverge from the rest of Miranda and go with +// the convention that functions return false on failure and nonzero on success. + +struct NETLIBHTTPREQUEST; +struct NETLIBOPENCONNECTION; + +#define NETLIB_USER_AGENT "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.112 Safari/537.36" + +///////////////////////////////////////////////////////////////////////////////////////// +// Initialises the netlib for a set of connections +// Returns a HNETLIBUSER to be used for future netlib calls, NULL on failure +// NOTE: Netlib is loaded after any plugins, so you need to wait until +// ME_SYSTEM_MODULESLOADED before calling this function +// Netlib settings are stored under the module szSettingsModule +// All netlib settings being with "NL". +// The default settings for registered users that don't have any settings stored +// in the database are the same as those displayed by the page +// of the netlib options page. +// Errors: ERROR_INVALID_PARAMETER, ERROR_OUTOFMEMORY, ERROR_DUP_NAME + +struct NETLIBUSER +{ + char *szSettingsModule; // used for db settings and log + MAllStrings szDescriptiveName; // used in options dialog, already translated + DWORD flags; + int minIncomingPorts; // only if NUF_INCOMING. Will be used for validation of user input. +}; + +#define NUF_INCOMING 0x01 // binds incoming ports +#define NUF_OUTGOING 0x02 // makes outgoing plain connections +#define NUF_NOOPTIONS 0x08 // don't create an options page for this. szDescriptiveName is never used. +#define NUF_HTTPCONNS 0x10 // at least some connections are made for HTTP communication. Enables the HTTP proxy option in options. +#define NUF_NOHTTPSOPTION 0x20 // disable the HTTPS proxy option in options. Use this if all communication is HTTP. +#define NUF_UNICODE 0x40 // if set ptszDescriptiveName points to Unicode, otherwise it points to ANSI string + +EXTERN_C MIR_APP_DLL(HNETLIBUSER) Netlib_RegisterUser(const NETLIBUSER *pDescr); + +///////////////////////////////////////////////////////////////////////////////////////// +// Assign a Netlib user handle a set of dynamic HTTP headers to be used with all +// +// HTTP connections that enable the HTTP-use-sticky headers flag. +// The headers persist until cleared with lParam = NULL. +// +// All memory should be allocated by the caller using malloc() from MS_SYSTEM_GET_MMI +// Once it has passed to Netlib, Netlib is the owner of it, the caller should not refer to the memory +// In any way after this point. +// +// NOTE: The szHeaders parameter should be a NULL terminated string following the HTTP header syntax. +// This string will be injected verbatim, thus the user should be aware of setting strings that are not +// headers. This service is NOT THREAD SAFE, only a single thread is expected to set the headers and a single +// thread reading the pointer internally, stopping race conditions and mutual exclusion don't happen. +// +// Version 0.3.2a+ (2003/10/27) +// + +EXTERN_C MIR_APP_DLL(int) Netlib_SetStickyHeaders(HNETLIBUSER nlu, const char *szHeaders); + +/* Notes on HTTP gateway usage +When a connection is initiated through an HTTP proxy using +MS_NETLIB_OPENCONNECTION, netlib will GET nlu.szHttpGatewayHello and read +the replied headers. Once this succeeds nlu.pfnHttpGatewayInit will be called +with a valid handle to the connection, the NETLIBOPENCONNECTION structure that +MS_NETLIB_OPENCONNECTION was called with, and the replied HTTP headers as its +parameters. This function is responsible for recving and parsing the data then +calling MS_NETLIB_SETHTTPPROXYINFO with the appropriate information. +nlu.pfnHttpGatewayInit should return nonzero on success. If it returns zero +then the entire connection attempt will return signalling failure. If your +function needs to return an error code it can do so via SetLastError(). +If nlu.pfnHttpGatewayInit returns success without having called +MS_NETLIB_SETHTTPPROXYINFO then the connection attempt will fail anyway. +If you need more fine-tuned control over the GET/POST URLs than just appending +sequence numbers you can call MS_NETLIB_SETHTTPPROXYINFO from within your +wrap/unwrap functions (see below). + +Just prior to MS_NETLIB_OPENCONNECTION returning nlu.pfnHttpGatewayBegin is +called with the handle to the connection and the NETLIBOPENCONNECTION structure +as its parameters. This is for gateways that need special non-protocol +initialisation. If you do send any packets in this function, you probably want +to remember to use the MSG_NOHTTPGATEWAYWRAP flag. This function pointer can be +NULL if this functionality isn't needed. This function must return nonzero on +success. If it fails the connect attempt will return failure without changing +LastError. + +Whenever MS_NETLIB_SEND is called on a connection through an HTTP proxy and +the MSG_NOHTTPGATEWAYWRAP flags is not set and nlu.pfnHttpGatewayWrapSend is +not NULL, nlu.pfnHttpGatewayWrapSend will be called *instead* of sending the +data. It is this function's responsibility to wrap the sending data +appropriately for transmission and call pfnNetlibSend to send it again. +The flags parameter to nlu.pfnHttpGatewayWrapSend should be passed straight +through to the pfnNetlibSend call. It has already been ORed with +MSG_NOHTTPGATEWAYWRAP. nlu.pfnHttpGatewayWrapSend should return the a +number of the same type as MS_NETLIB_SEND, ie the number of bytes sent or +SOCKET_ERROR. The number of wrapping bytes should be subtracted so that the +return value appears as if the proxy wasn't there. +pfnNetlibSend() is identical to CallService(MS_NETLIB_SEND, ...) but it's +quicker to call using this pointer than to do the CallService() lookup again. + +Whenever an HTTP reply is received inside MS_NETLIB_RECV the headers and data +are read into memory. If the headers indicate success then the data is passed +to nlu.pfnHttpGatewayUnwrapRecv (if it's non-NULL) for processing. This +function should remove (and do other processing if necessary) all HTTP proxy +specific headers and return a pointer to the buffer whose size is returned in +*outBufLen. If the buffer needs to be resized then NetlibRealloc() should be +used for that purpose, *not* your own CRT's realloc(). NetlibRealloc() behaves +identically to realloc() so it's possible to free the original buffer and +create a new one if that's the most sensible way to write your parser. +If errors are encountered you should SetLastError() and return NULL; +MS_NETLIB_RECV will return SOCKET_ERROR. If the passed buffer unwraps to +contain no actual data you should set *outBufLen to 0 but make sure you return +some non-NULL buffer that can be freed. + +When you call MS_NETLIB_SEND or MS_NETLIB_RECV from any of these functions, you +should use the MSG_DUMPPROXY flag so that the logging is neat. +*/ + +#define PROXYTYPE_SOCKS4 1 +#define PROXYTYPE_SOCKS5 2 +#define PROXYTYPE_HTTP 3 +#define PROXYTYPE_HTTPS 4 +#define PROXYTYPE_IE 5 + +struct NETLIBUSERSETTINGS +{ + int cbSize; // to be filled in before calling + int useProxy; // 1 or 0 + int proxyType; // a PROXYTYPE_ + char *szProxyServer; // can be NULL + int wProxyPort; // host byte order + int useProxyAuth; // 1 or 0. Always 0 for SOCKS4 + char *szProxyAuthUser; // can be NULL, always used by SOCKS4 + char *szProxyAuthPassword; // can be NULL + int useProxyAuthNtlm; // 1 or 0, only used by HTTP, HTTPS + int dnsThroughProxy; // 1 or 0 + int specifyIncomingPorts; // 1 or 0 + char *szIncomingPorts; // can be NULL. Of form "1024-1050, 1060-1070, 2000" + int specifyOutgoingPorts; // 0.3.3a+ + char *szOutgoingPorts; // 0.3.3a+ + int enableUPnP; // 0.6.1+ only for NUF_INCOMING + int validateSSL; +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Gets the user-configured settings for a netlib user +// +// Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib) +// The pointers referred to in the returned struct will remain valid until +// the hUser handle is closed, or until the user changes the settings in the +// options page, so it's best not to rely on them for too long. +// Errors: ERROR_INVALID_PARAMETER + +EXTERN_C MIR_APP_DLL(int) Netlib_GetUserSettings(HNETLIBUSER nlu, NETLIBUSERSETTINGS *result); + +///////////////////////////////////////////////////////////////////////////////////////// +//Gets the user-configured settings for a netlib user idetified by name +// +//Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib) +//This function behaves like Netlib_GetUserSettings but the user is identified +//by the name provided by registration. When the name is not found NETLIBUSERSETTINGS is set to NULL. +//Errors: ERROR_INVALID_PARAMETER + +EXTERN_C MIR_APP_DLL(int) Netlib_GetUserSettingsByName(char * UserSettingsName, NETLIBUSERSETTINGS *result); + +///////////////////////////////////////////////////////////////////////////////////////// +// Changes the user-configurable settings for a netlib user +// +// Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib) +// This function is only really useful for people that specify NUF_NOOPTIONS +// and want to create their own options. +// Even if a setting is not active (eg szProxyAuthPassword when useProxyAuth is +// zero) that settings is still set for use in the options dialog. +// Errors: ERROR_INVALID_PARAMETER + +EXTERN_C MIR_APP_DLL(int) Netlib_SetUserSettings(HNETLIBUSER nlu, const NETLIBUSERSETTINGS *result); + +///////////////////////////////////////////////////////////////////////////////////////// +//Changes the user-configurable settings for a netlib user idetified by name +// +//Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib) +//This function behaves like Netlib_SetUserSettings but the user is identified +//by the name provided by registration. Nothing will be changed when the name is not found. +//Errors: ERROR_INVALID_PARAMETER + +EXTERN_C MIR_APP_DLL(int) Netlib_SetUserSettingsByName(char * UserSettingsName, NETLIBUSERSETTINGS *result); + +///////////////////////////////////////////////////////////////////////////////////////// +// Closes a netlib handle +// +// Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib) +// This function should be called on all handles returned by netlib functions +// once you are done with them. If it's called on a socket-type handle, the +// socket will be closed. +// Errors: ERROR_INVALID_PARAMETER + +EXTERN_C MIR_APP_DLL(int) Netlib_CloseHandle(HANDLE h); + +///////////////////////////////////////////////////////////////////////////////////////// +// Open a port and wait for connections on it +// +// Returns a HANDLE on success, NULL on failure +// hUser should have been returned by MS_NETLIB_REGISTERUSER +// This function does the equivalent of socket(), bind(), getsockname(), +// listen(), accept() +// Internally this function creates a new thread which waits around in accept() +// for new connections. When one is received it calls nlb.pfnNewConnection *from +// this new thread* and then loops back to wait again. +// Close the returned handle to end the thread and close the open port. +// Errors: ERROR_INVALID_PARAMETER, any returned by socket() or bind() or +// listen() or getsockname() +// +// Notes: +// +// During development of 0.3.1a+ (2003/07/04) passing wPort != 0 +// will result in an attempt to bind on the port given in wPort +// if this port is taken then you will get an error, so be sure to check +// for such conditions. +// +// passing wPort != 0 is for people who need to open a set port for +// daemon activities, usually passing wPort == 0 is what you want and +// will result in a free port given by the TCP/IP socket layer and/or +// seeded from the user selected port ranges. +// +// also note that wPort if != 0, will have be converted to network byte order +// +/* pExtra was added during 0.3.4+, prior its just two args, since we use the cdecl convention +it shouldnt matter */ + +typedef void (*NETLIBNEWCONNECTIONPROC)(HNETLIBCONN hNewConnection, DWORD dwRemoteIP, void *pExtra); + +struct NETLIBBIND +{ + NETLIBNEWCONNECTIONPROC pfnNewConnection; + + // function to call when there's a new connection. Params are: the + // new connection, IP of remote machine (host byte order) + DWORD dwInternalIP; // set on return, host byte order + DWORD dwExternalIP; // set on return, host byte order + WORD wPort, wExPort; // set on return, host byte order + void *pExtra; // argument is sent to callback +}; + +EXTERN_C MIR_APP_DLL(HNETLIBBIND) Netlib_BindPort(HNETLIBUSER nlu, NETLIBBIND *nlb); + +///////////////////////////////////////////////////////////////////////////////////////// +// Open a connection +// +// Returns a HNETLIBCONN to the new connection on success, NULL on failure +// hUser must have been returned by MS_NETLIB_REGISTERUSER +// Internally this function is the equivalent of socket(), gethostbyname(), +// connect() +// If NLOCF_HTTP is set and hUser is configured for an HTTP or HTTPS proxy then +// this function will connect() to the proxy server only, without performing any +// initialisation conversation. +// If hUser is configured for an HTTP proxy and does not support HTTP gateways +// and you try to open a connection without specifying NLOCF_HTTP then this +// function will first attempt to open an HTTPS connection, if that fails it +// will try a direct connection, if that fails it will return failure with the +// error from the connect() during the direct connection attempt. +// Errors: ERROR_INVALID_PARAMETER, any returned by socket(), gethostbyname(), +// connect(), MS_NETLIB_SEND, MS_NETLIB_RECV, select() +// ERROR_TIMEOUT (during proxy communication) +// ERROR_BAD_FORMAT (very invalid proxy reply) +// ERROR_ACCESS_DENIED (by proxy) +// ERROR_CONNECTION_UNAVAIL (socks proxy can't connect to identd) +// ERROR_INVALID_ACCESS (proxy refused identd auth) +// ERROR_INVALID_DATA (proxy returned invalid code) +// ERROR_INVALID_ID_AUTHORITY (proxy requires use of auth method that's not supported) +// ERROR_GEN_FAILURE (socks5/https general failure) +// ERROR_CALL_NOT_IMPLEMENTED (socks5 command not supported) +// ERROR_INVALID_ADDRESS (socks5 address type not supported) +// HTTP: anything from nlu.pfnHttpGatewayInit, nlu.pfnHttpGatewayBegin, +// MS_NETLIB_SENDHTTPREQUEST or MS_NETLIB_RECVHTTPHEADERS + +#define NLOCF_HTTP 0x0001 // this connection will be used for HTTP communications. If configured for an HTTP/HTTPS proxy the connection is opened as if there was no proxy. +#define NLOCF_STICKYHEADERS 0x0002 // this connection should send the sticky headers associated with NetLib user apart of any HTTP request +#define NLOCF_V2 0x0004 // this connection understands the newer structure, newer cbSize isnt enough +#define NLOCF_UDP 0x0008 // this connection is UDP +#define NLOCF_SSL 0x0010 // this connection is SSL + +struct NETLIBOPENCONNECTION +{ + const char *szHost; // can contain the string representation of an IP + WORD wPort; // host byte order + DWORD flags; + unsigned int timeout; + /* optional, called in the context of the thread that issued the attempt, if it returns 0 the connection attempt is + stopped, the remaining timeout value can also be adjusted */ + int (*waitcallback) (unsigned int *timeout); +}; + +EXTERN_C MIR_APP_DLL(HNETLIBCONN) Netlib_OpenConnection(HNETLIBUSER nlu, const NETLIBOPENCONNECTION *nloc); + +///////////////////////////////////////////////////////////////////////////////////////// +// Sets the required information for an HTTP proxy connection +// +// Returns nonzero on success, 0 on failure (!! this is different to most of the rest of Miranda, but consistent with netlib) +// This function is designed to be called from within pfnHttpGatewayInit +// See notes below MS_NETLIB_REGISTERUSER. +// Errors: ERROR_INVALID_PARAMETER + +#define NLHPIF_USEGETSEQUENCE 0x0001 // append sequence numbers to GET requests +#define NLHPIF_USEPOSTSEQUENCE 0x0002 // append sequence numbers to POST requests +#define NLHPIF_GETPOSTSAMESEQUENCE 0x0004 // GET and POST use the same sequence +#define NLHPIF_HTTP11 0x0008 // HTTP 1.1 proxy + +struct NETLIBHTTPPROXYINFO +{ + DWORD flags; + int firstGetSequence, firstPostSequence; + int combinePackets; + char *szHttpPostUrl; + char *szHttpGetUrl; +}; + +EXTERN_C MIR_APP_DLL(int) Netlib_SetHttpProxyInfo(HNETLIBCONN hConnection, const NETLIBHTTPPROXYINFO *nlhpi); + +///////////////////////////////////////////////////////////////////////////////////////// +// Gets the SOCKET associated with a netlib handle +// +// Returns the SOCKET on success, INVALID_SOCKET on failure +// hNetlibHandle should have been returned by MS_NETLIB_BINDPORT or +// MS_NETLIB_OPENCONNECTION only. +// Be careful how you use this socket because you might be connected via an +// HTTP proxy in which case calling send() or recv() will totally break things. +// Errors: ERROR_INVALID_PARAMETER + +EXTERN_C MIR_APP_DLL(UINT_PTR) Netlib_GetSocket(HNETLIBCONN hConnection); + +///////////////////////////////////////////////////////////////////////////////////////// + +#define Netlib_GetBase64DecodedBufferSize(cchEncoded) (((cchEncoded)>>2)*3) +#define Netlib_GetBase64EncodedBufferSize(cbDecoded) (((cbDecoded)*4+11)/12*4+1) + +///////////////////////////////////////////////////////////////////////////////////////// +// Gets HNETLIBUSER owner of a connection + +EXTERN_C MIR_APP_DLL(HNETLIBUSER) Netlib_GetConnNlu(HNETLIBCONN hConn); + +///////////////////////////////////////////////////////////////////////////////////////// +// Gets the fake User-Agent header field to make some sites happy + +EXTERN_C MIR_APP_DLL(char*) Netlib_GetUserAgent(); + +///////////////////////////////////////////////////////////////////////////////////////// +// Converts numerical representation of IP in SOCKADDR_INET into string representation with IP and port +// IPv4 will be supplied in formats address:port or address +// IPv6 will be supplied in formats [address]:port or [address] +// Returns pointer to the string or NULL if not successful + +struct sockaddr_in; +EXTERN_C MIR_APP_DLL(char*) Netlib_AddressToString(sockaddr_in *addr); +EXTERN_C MIR_APP_DLL(bool) Netlib_StringToAddress(const char *str, sockaddr_in *addr); + +///////////////////////////////////////////////////////////////////////////////////////// +// Gets connection Information +// IPv4 will be supplied in formats address:port or address +// IPv6 will be supplied in formats [address]:port or [address] +// Returns 0 if successful + +struct NETLIBCONNINFO +{ + char szIpPort[64]; + unsigned dwIpv4; + WORD wPort; +}; + +EXTERN_C MIR_APP_DLL(int) Netlib_GetConnectionInfo(HNETLIBCONN hConnection, NETLIBCONNINFO *connInfo); + +///////////////////////////////////////////////////////////////////////////////////////// +// Gets connection Information +// +// Returns (INT_PTR)(NETLIBIPLIST*) numeric IP address address array +// the last element of the array is all 0s, 0 if not successful + +struct NETLIBIPLIST +{ + unsigned cbNum; + char szIp[1][64]; +}; + +EXTERN_C MIR_APP_DLL(NETLIBIPLIST*) Netlib_GetMyIp(bool bGlobalOnly); + +///////////////////////////////////////////////////////////////////////////////////////// +// Send an HTTP request over a connection +// +// Returns number of bytes sent on success, SOCKET_ERROR on failure +// hConnection must have been returned by MS_NETLIB_OPENCONNECTION +// Note that if you use NLHRF_SMARTAUTHHEADER and NTLM authentication is in use +// then the full NTLM authentication transaction occurs, comprising sending the +// domain, receiving the challenge, then sending the response. +// nlhr.resultCode and nlhr.szResultDescr are ignored by this function. +// Errors: ERROR_INVALID_PARAMETER, anything returned by MS_NETLIB_SEND + +struct NETLIBHTTPHEADER +{ + char *szName; + char *szValue; +}; + +EXTERN_C MIR_APP_DLL(char*) Netlib_GetHeader(const NETLIBHTTPREQUEST *pRec, const char *pszName); + +///////////////////////////////////////////////////////////////////////////////////////// + +#define REQUEST_RESPONSE 0 // used by structure returned by MS_NETLIB_RECVHTTPHEADERS +#define REQUEST_GET 1 +#define REQUEST_POST 2 +#define REQUEST_CONNECT 3 +#define REQUEST_HEAD 4 +#define REQUEST_PUT 5 +#define REQUEST_DELETE 6 +#define REQUEST_PATCH 7 + +#define NLHRF_MANUALHOST 0x00000001 // do not remove any host and/or protocol portion of szUrl before sending it +#define NLHRF_HTTP11 0x00000010 // use HTTP 1.1 +#define NLHRF_PERSISTENT 0x00000020 // preserve connection on exit, open connection provided in the nlc field of the reply + // it should be supplied in nlc field of request for reuse or closed if not needed +#define NLHRF_SSL 0x00000040 // use SSL connection +#define NLHRF_NOPROXY 0x00000080 // do not use proxy server +#define NLHRF_REDIRECT 0x00000100 // handle HTTP redirect requests (response 30x), the resulting url provided in szUrl of the response +#define NLHRF_NODUMP 0x00010000 // never dump this to the log +#define NLHRF_NODUMPHEADERS 0x00020000 // don't dump http headers (only useful for POSTs and MS_NETLIB_HTTPTRANSACTION) +#define NLHRF_DUMPPROXY 0x00040000 // this transaction is a proxy communication. For dump filtering only. +#define NLHRF_DUMPASTEXT 0x00080000 // dump posted and reply data as text. Headers are always dumped as text. +#define NLHRF_NODUMPSEND 0x00100000 // do not dump sent message. + +struct NETLIBHTTPREQUEST +{ + int cbSize; + int requestType; // a REQUEST_ + DWORD flags; + char *szUrl; + NETLIBHTTPHEADER *headers; // If this is a POST request and headers + // doesn't contain a Content-Length it'll be added automatically + int headersCount; + char *pData; // data to be sent in POST request. + int dataLength; // must be 0 for REQUEST_GET/REQUEST_CONNECT + int resultCode; + char *szResultDescr; + HNETLIBCONN nlc; + int timeout; + + __forceinline const char *operator[](const char *pszName) { + return Netlib_GetHeader(this, pszName); + } +}; + +EXTERN_C MIR_APP_DLL(int) Netlib_SendHttpRequest(HNETLIBCONN hConnection, NETLIBHTTPREQUEST *pRec); + +///////////////////////////////////////////////////////////////////////////////////////// +// Receives HTTP headers +// +// Returns a pointer to a NETLIBHTTPREQUEST structure on success, NULL on failure. +// Call Netlib_FreeHttpRequest() to free this. +// hConnection must have been returned by MS_NETLIB_OPENCONNECTION +// nlhr->pData = NULL and nlhr->dataLength = 0 always. The requested data should +// be retrieved using MS_NETLIB_RECV once the header has been parsed. +// If the headers haven't finished within 60 seconds the function returns NULL +// and ERROR_TIMEOUT. +// Errors: ERROR_INVALID_PARAMETER, any from MS_NETLIB_RECV or select() +// ERROR_HANDLE_EOF (connection closed before headers complete) +// ERROR_TIMEOUT (headers still not complete after 60 seconds) +// ERROR_BAD_FORMAT (invalid character or line ending in headers, or first line is blank) +// ERROR_BUFFER_OVERFLOW (each header line must be less than 4096 chars long) +// ERROR_INVALID_DATA (first header line is malformed ("http/[01].[0-9] [0-9]+ .*", or no colon in subsequent line) + +EXTERN_C MIR_APP_DLL(NETLIBHTTPREQUEST*) Netlib_RecvHttpHeaders(HNETLIBCONN hConnection, int flags = 0); + +///////////////////////////////////////////////////////////////////////////////////////// +// Free the memory used by a NETLIBHTTPREQUEST structure +// +// Returns true on success, false on failure (!! this is different to most of the rest of Miranda, but consistent with netlib) +// This should only be called on structures returned by +// MS_NETLIB_RECVHTTPHEADERS or MS_NETLIB_HTTPTRANSACTION. Calling it on an +// arbitrary structure will have disastrous results. +// Errors: ERROR_INVALID_PARAMETER + +EXTERN_C MIR_APP_DLL(bool) Netlib_FreeHttpRequest(NETLIBHTTPREQUEST*); + +///////////////////////////////////////////////////////////////////////////////////////// +// smart pointer for NETLIBHTTPREQUEST via a call of Netlib_FreeHttpRequest() + +#ifdef __cplusplus +class NLHR_PTR +{ +protected: + NETLIBHTTPREQUEST *_p; + +public: + __forceinline explicit NLHR_PTR(NETLIBHTTPREQUEST *p) : _p(p) {} + + __forceinline NETLIBHTTPREQUEST* operator=(INT_PTR i_p) + { + return operator=((NETLIBHTTPREQUEST*)i_p); + } + __forceinline NETLIBHTTPREQUEST* operator=(NETLIBHTTPREQUEST *p) + { + if (_p) + Netlib_FreeHttpRequest(_p); + _p = p; + return _p; + } + __forceinline operator NETLIBHTTPREQUEST*() const { return _p; } + __forceinline NETLIBHTTPREQUEST* operator->() const { return _p; } + __forceinline ~NLHR_PTR() + { + Netlib_FreeHttpRequest(_p); + } +}; + +struct MIR_APP_EXPORT MHttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject +{ + MHttpRequest(); + ~MHttpRequest(); + + CMStringA m_szUrl; + CMStringA m_szParam; + void *pUserInfo = nullptr; + + void AddHeader(const char *szName, const char *szValue); +}; + +template +class MTHttpRequest : public MHttpRequest +{ +public: + __forceinline MTHttpRequest() + {} + + typedef void (T::*MTHttpRequestHandler)(NETLIBHTTPREQUEST*, struct AsyncHttpRequest*); + MTHttpRequestHandler m_pFunc = nullptr; +}; + +MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest*, const INT_PARAM&); +MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest*, const INT64_PARAM&); +MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest*, const CHAR_PARAM&); +MIR_APP_DLL(MHttpRequest*) operator<<(MHttpRequest*, const WCHAR_PARAM&); + +#endif + +///////////////////////////////////////////////////////////////////////////////////////// +// Do an entire HTTP transaction +// +// Returns a pointer to another NETLIBHTTPREQUEST structure on success, NULL on failure. +// Call Netlib_FreeHttpRequest() to free this. +// hUser must have been returned by MS_NETLIB_REGISTERUSER +// nlhr.szUrl should be a full HTTP URL. If it does not start with http:// , that +// will be assumed (but it's best not to use this fact, for reasons of +// extensibility). +// This function is the equivalent of MS_NETLIB_OPENCONNECTION, +// MS_NETLIB_SENDHTTPREQ, MS_NETLIB_RECVHTTPHEADERS, MS_NETLIB_RECV, +// MS_NETLIB_CLOSEHANDLE +// nlhr.headers will be augmented with the following headers unless they have +// already been set by the caller: +// "Host" (regardless of whether it is requested in nlhr.flags) +// "User-Agent" (of the form "Miranda/0.1.2.2 (alpha)" or "Miranda/0.1.2.2") +// "Content-Length" (for POSTs only. Set to nlhr.dataLength) +// If you do not want to send one of these headers, create a nlhr.headers with +// szValue = NULL. +// In the return value headers, headerCount, pData, dataLength, resultCode and +// szResultDescr are all valid. +// In the return value pData[dataLength] == 0 always, as an extra safeguard +// against programming slips. +// Note that the function can succeed (ie not return NULL) yet result in an HTTP +// error code. You should check that resultCode == 2xx before proceeding. +// Errors: ERROR_INVALID_PARAMETER, ERROR_OUTOFMEMORY, anything from the above +// list of functions + +EXTERN_C MIR_APP_DLL(NETLIBHTTPREQUEST*) Netlib_HttpTransaction(HNETLIBUSER hNlu, NETLIBHTTPREQUEST *pRequest); + +///////////////////////////////////////////////////////////////////////////////////////// +// Send data over a connection +// +// Returns the number of bytes sent on success, SOCKET_ERROR on failure +// Errors: ERROR_INVALID_PARAMETER +// anything from send(), nlu.pfnHttpGatewayWrapSend() +// HTTP proxy: ERROR_GEN_FAILURE (http result code wasn't 2xx) +// anything from socket(), connect(), +// MS_NETLIB_SENDHTTPREQUEST, MS_NETLIB_RECVHTTPHEADERS +// flags: + +#define MSG_NOHTTPGATEWAYWRAP 0x010000 // don't wrap the outgoing packet using nlu.pfnHttpGatewayWrapSend +#define MSG_NODUMP 0x020000 // don't dump this packet to the log +#define MSG_DUMPPROXY 0x040000 // this is proxy communiciation. For dump filtering only. +#define MSG_DUMPASTEXT 0x080000 // this is textual data, don't dump as hex +#define MSG_RAW 0x100000 // send as raw data, bypass any HTTP proxy stuff +#define MSG_DUMPSSL 0x200000 // this is SSL traffic. For dump filtering only. +#define MSG_NOTITLE 0x400000 // skip date, time & protocol from dump + +EXTERN_C MIR_APP_DLL(int) Netlib_Send(HNETLIBCONN hConn, const char *buf, int len, int flags = 0); + +///////////////////////////////////////////////////////////////////////////////////////// +// Receive data over a connection +// +// Returns the number of bytes read on success, SOCKET_ERROR on failure, +// 0 if the connection has been closed +// Flags supported: MSG_PEEK, MSG_NODUMP, MSG_DUMPPROXY, MSG_NOHTTPGATEWAYWRAP, +// MSG_DUMPASTEXT, MSG_RAW +// On using MSG_NOHTTPGATEWAYWRAP: Because packets through an HTTP proxy are +// batched and cached and stuff, using this flag is not a guarantee that it +// will be obeyed, and if it is it may even be propogated to future calls +// even if you don't specify it then. Because of this, the flag should be +// considered an all-or-nothing thing: either use it for the entire duration +// of a connection, or not at all. +// Errors: ERROR_INVALID_PARAMETER, anything from recv() +// HTTP proxy: ERROR_GEN_FAILURE (http result code wasn't 2xx) +// ERROR_INVALID_DATA (no Content-Length header in reply) +// ERROR_NOT_ENOUGH_MEMORY (Content-Length very large) +// ERROR_HANDLE_EOF (connection closed before Content-Length bytes recved) +// anything from select(), MS_NETLIB_RECVHTTPHEADERS, +// nlu.pfnHttpGatewayUnwrapRecv, socket(), connect(), +// MS_NETLIB_SENDHTTPREQUEST + +EXTERN_C MIR_APP_DLL(int) Netlib_Recv(HNETLIBCONN hConn, char *buf, int len, int flags = 0); + +///////////////////////////////////////////////////////////////////////////////////////// +// Determine the status of one or more connections +// Returns the number of ready connections, SOCKET_ERROR on failure, 0 if the timeout expired. +// All handles passed to this function must have been returned by either +// MS_NETLIB_OPENCONNECTION or MS_NETLIB_BINDPORT. +// The last handle in each list must be followed by either NULL or INVALID_HANDLE_VALUE. +// Errors: ERROR_INVALID_HANDLE, ERROR_INVALID_DATA, anything from select() + +struct NETLIBSELECT +{ + DWORD dwTimeout; // in milliseconds, INFINITE is acceptable + HNETLIBCONN hReadConns[FD_SETSIZE + 1]; + HNETLIBCONN hWriteConns[FD_SETSIZE + 1]; + HNETLIBCONN hExceptConns[FD_SETSIZE + 1]; +}; + +EXTERN_C MIR_APP_DLL(int) Netlib_Select(NETLIBSELECT *nls); + +struct NETLIBSELECTEX +{ + DWORD dwTimeout; // in milliseconds, INFINITE is acceptable + HNETLIBCONN hReadConns[FD_SETSIZE + 1]; + HNETLIBCONN hWriteConns[FD_SETSIZE + 1]; + HNETLIBCONN hExceptConns[FD_SETSIZE + 1]; + + BOOL hReadStatus[FD_SETSIZE+1]; /* out, [in, expected to be FALSE] */ + BOOL hWriteStatus[FD_SETSIZE+1]; /* out, [in, expected to be FALSE] */ + BOOL hExceptStatus[FD_SETSIZE+1]; /* out, [in, expected to be FALSE] */ +}; + +EXTERN_C MIR_APP_DLL(int) Netlib_SelectEx(NETLIBSELECTEX *nls); + +///////////////////////////////////////////////////////////////////////////////////////// +// Shutdown connection + +EXTERN_C MIR_APP_DLL(void) Netlib_Shutdown(HNETLIBCONN h); + +///////////////////////////////////////////////////////////////////////////////////////// +// Create a packet receiver +// +// Returns a HANDLE on success, NULL on failure +// The packet receiver implements the common situation where you have variable +// length packets coming in over a connection and you want to split them up +// in order to handle them. +// The major limitation is that the buffer is created in memory, so you can't +// have arbitrarily large packets. +// Errors: ERROR_INVALID_PARAMETER, ERROR_OUTOFMEMORY + +EXTERN_C MIR_APP_DLL(HANDLE) Netlib_CreatePacketReceiver(HNETLIBCONN hConnection, int iMaxSize); + +///////////////////////////////////////////////////////////////////////////////////////// +// Get the next set of packets from a packet receiver +// +// Returns the total number of bytes available in the buffer, 0 if the +// connection was closed, SOCKET_ERROR on error. +// hPacketRecver must have been returned by MS_NETLIB_CREATEPACKETRECVER +// If nlpr.bytesUsed is set to zero and the buffer is already full up to +// maxPacketSize, it is assumed that too large a packet has been received. All +// data in the buffer is discarded and receiving is begun anew. This will +// probably cause alignment problems so if you think this is likely to happen +// then you should deal with it yourself. +// Closing the packet receiver will not close the associated connection, but +// will discard any bytes still in the buffer, so if you intend to carry on +// reading from that connection, make sure you have processed the buffer first. +// This function is the equivalent of a memmove() to remove the first bytesUsed +// from the buffer, select() if dwTimeout is not INFINITE, then MS_NETLIB_RECV. +// Errors: ERROR_INVALID_PARAMETER, ERROR_TIMEOUT, +// anything from select(), MS_NETLIB_RECV + +struct NETLIBPACKETRECVER +{ + DWORD dwTimeout; // fill before calling. In milliseconds. INFINITE is valid + int bytesUsed; // fill before calling. This many bytes are removed from the start of the buffer. Set to 0 on return + int bytesAvailable; // equal to the return value, unless the return value is 0 + int bufferSize; // same as parameter to MS_NETLIB_CREATEPACKETRECVER + BYTE *buffer; // contains the recved data +}; + +EXTERN_C MIR_APP_DLL(int) Netlib_GetMorePackets(HANDLE hReceiver, NETLIBPACKETRECVER *nlprParam); + +///////////////////////////////////////////////////////////////////////////////////////// +// Sets a gateway polling timeout interval +// +// Returns previous timeout value +// Errors: -1 + +EXTERN_C MIR_APP_DLL(int) Netlib_SetPollingTimeout(HNETLIBCONN hConnection, int iTimeout); + +///////////////////////////////////////////////////////////////////////////////////////// +// netlib log funcitons + +EXTERN_C MIR_APP_DLL(int) Netlib_Log(HNETLIBUSER hUser, const char *pszStr); +EXTERN_C MIR_APP_DLL(int) Netlib_LogW(HNETLIBUSER hUser, const wchar_t *pwszStr); + +EXTERN_C MIR_APP_DLL(int) Netlib_Logf(HNETLIBUSER hUser, _Printf_format_string_ const char *fmt, ...); +EXTERN_C MIR_APP_DLL(int) Netlib_LogfW(HNETLIBUSER hUser, _Printf_format_string_ const wchar_t *fmt, ...); + +EXTERN_C MIR_APP_DLL(void) Netlib_Dump(HNETLIBCONN nlc, const void *buf, size_t len, bool bIsSent, int flags); + +// Inits a required security provider. Right now only NTLM is supported +// Returns HANDLE = NULL on error or non-null value on success +// Known providers: Basic, NTLM, Negotiate, Kerberos, GSSAPI - (Kerberos SASL) +EXTERN_C MIR_APP_DLL(HANDLE) Netlib_InitSecurityProvider(const wchar_t *szProviderName, const wchar_t *szPrincipal = nullptr); + +// Destroys a security provider's handle, provided by Netlib_InitSecurityProvider. +// Right now only NTLM is supported +EXTERN_C MIR_APP_DLL(void) Netlib_DestroySecurityProvider(HANDLE hProvider); + +// Returns the NTLM response string. The result value should be freed using mir_free +EXTERN_C MIR_APP_DLL(char*) Netlib_NtlmCreateResponse(HANDLE hProvider, const char *szChallenge, wchar_t *szLogin, wchar_t *szPass, unsigned &complete); + +///////////////////////////////////////////////////////////////////////////////////////// +// SSL/TLS support + +#if !defined(HSSL_DEFINED) +DECLARE_HANDLE(HSSL); +#endif + +// Makes connection SSL +// Returns 0 on failure 1 on success +EXTERN_C MIR_APP_DLL(int) Netlib_StartSsl(HNETLIBCONN hConnection, const char *host); + +// negotiates SSL session, verifies cert, returns NULL if failed +EXTERN_C MIR_APP_DLL(HSSL) Netlib_SslConnect(SOCKET s, const char* host, int verify); + +// return true if there is either unsend or buffered received data (ie. after peek) +EXTERN_C MIR_APP_DLL(BOOL) Netlib_SslPending(HSSL ssl); + +// reads number of bytes, keeps in buffer if peek != 0 +EXTERN_C MIR_APP_DLL(int) Netlib_SslRead(HSSL ssl, char *buf, int num, int peek); + +// writes data to the SSL socket +EXTERN_C MIR_APP_DLL(int) Netlib_SslWrite(HSSL ssl, const char *buf, int num); + +// closes SSL session, but keeps socket open +EXTERN_C MIR_APP_DLL(void) Netlib_SslShutdown(HSSL ssl); + +// frees all data associated with the SSL socket +EXTERN_C MIR_APP_DLL(void) Netlib_SslFree(HSSL ssl); + +// gets TLS channel binging data for a socket +EXTERN_C MIR_APP_DLL(void*) Netlib_GetTlsUnique(HNETLIBCONN nlc, int &cbLen); + +///////////////////////////////////////////////////////////////////////////////////////// +// WebSocket support + +struct WSHeader +{ + WSHeader() + { + memset(this, 0, sizeof(*this)); + } + + bool bIsFinal, bIsMasked; + int opCode, firstByte; + size_t payloadSize, headerSize; +}; + +// connects to a WebSocket server +EXTERN_C MIR_APP_DLL(NETLIBHTTPREQUEST*) WebSocket_Connect(HNETLIBUSER, const char *szHost, NETLIBHTTPHEADER *pHeaders = nullptr); + +// validates that the provided buffer contains full WebSocket datagram +EXTERN_C MIR_APP_DLL(bool) WebSocket_InitHeader(WSHeader &hdr, const void *pData, size_t bufSize); + +// sends a packet to WebSocket +EXTERN_C MIR_APP_DLL(void) WebSocket_SendText(HNETLIBCONN nlc, const char *pData); +EXTERN_C MIR_APP_DLL(void) WebSocket_SendBinary(HNETLIBCONN nlc, const void *pData, size_t strLen); + +///////////////////////////////////////////////////////////////////////////////////////// +// Netlib hooks (0.8+) + +// WARNING: these hooks are being called in the context of the calling thread, without switching +// to the first thread, like all another events do. The hook procedure should be ready for the +// multithreaded mode +// +// Parameters: +// wParam: NETLIBNOTIFY* - points to the data being sent/received +// lParam: NETLIBUSER* - points to the protocol definition + +struct NETLIBNOTIFY +{ + const char *buf; + int len; + int flags; + int result; // amount of bytes really sent/received +}; + +#define ME_NETLIB_FASTRECV "Netlib/OnRecv" // being called on every receive +#define ME_NETLIB_FASTSEND "Netlib/OnSend" // being called on every send +#define ME_NETLIB_FASTDUMP "Netlib/OnDump" // being called on every dump + +struct NETLIBCONNECTIONEVENTINFO +{ + BOOL connected; // 1-opening socket 0-closing socket + BOOL listening; // 1-bind 0-connect + SOCKADDR_IN local; // local IP+port (always used) + SOCKADDR_IN remote; // remote IP+port (only connect (opening + closing only if no proxy)) + SOCKADDR_IN proxy; // proxy IP+port (only connect when used) + char *szSettingsModule; // name of the registered Netlib user that requested the action +}; + +//This event is sent as a new port is bound or a new connection opened. +//It is NOT sent for sigle HTTP(S) requests. +//wParam=(WPARAM)(NETLIBCONNECTIONEVENTINFO*)hInfo +//lParam=(LPARAM)0 (not used) +#define ME_NETLIB_EVENT_CONNECTED "Netlib/Event/Connected" + +//This event is sent if coneection or listening socket is closed. +//It is NOT sent for sigle HTTP(S) requests. +//wParam=(WPARAM)(NETLIBCONNECTIONEVENTINFO*)hInfo +//lParam=(LPARAM)0 (not used) +#define ME_NETLIB_EVENT_DISCONNECTED "Netlib/Event/Disconnected" + +#endif // M_NETLIB_H__ diff --git a/include/m_protoint.h b/include/m_protoint.h index 0f9444c448..90955ad34e 100644 --- a/include/m_protoint.h +++ b/include/m_protoint.h @@ -1,310 +1,310 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) -Copyright (c) 2000-08 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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_PROTOINT_H__ -#define M_PROTOINT_H__ 1 - -#include -#include -#include -#include -#include - -///////////////////////////////////////////////////////////////////////////////////////// -// protocol helpers - -struct PROTO_INTERFACE; - -// Call it in the very beginning of your proto's constructor -EXTERN_C MIR_APP_DLL(void) ProtoConstructor(PROTO_INTERFACE *pThis, const char *pszModuleName, const wchar_t *ptszUserName); - -// Call it in the very end of your proto's destructor -EXTERN_C MIR_APP_DLL(void) ProtoDestructor(PROTO_INTERFACE *pThis); - -#if defined( __cplusplus ) -typedef void (__cdecl PROTO_INTERFACE::*ProtoThreadFunc)(void*); -EXTERN_C MIR_APP_DLL(void) ProtoForkThread(PROTO_INTERFACE *pThis, ProtoThreadFunc, void *param); -EXTERN_C MIR_APP_DLL(HANDLE) ProtoForkThreadEx(PROTO_INTERFACE *pThis, ProtoThreadFunc, void *param, UINT* threadID); -EXTERN_C MIR_APP_DLL(void) ProtoWindowAdd(PROTO_INTERFACE *pThis, HWND hwnd); -EXTERN_C MIR_APP_DLL(void) ProtoWindowRemove(PROTO_INTERFACE *pThis, HWND hwnd); - -typedef int (__cdecl PROTO_INTERFACE::*ProtoEventFunc)(WPARAM, LPARAM); -EXTERN_C MIR_APP_DLL(void) ProtoHookEvent(PROTO_INTERFACE *pThis, const char* szName, ProtoEventFunc pFunc); -EXTERN_C MIR_APP_DLL(HANDLE) ProtoCreateHookableEvent(PROTO_INTERFACE *pThis, const char* szService); - -typedef INT_PTR (__cdecl PROTO_INTERFACE::*ProtoServiceFunc)(WPARAM, LPARAM); -EXTERN_C MIR_APP_DLL(void) ProtoCreateService(PROTO_INTERFACE *pThis, const char* szService, ProtoServiceFunc); - -typedef INT_PTR (__cdecl PROTO_INTERFACE::*ProtoServiceFuncParam)(WPARAM, LPARAM, LPARAM); -EXTERN_C MIR_APP_DLL(void) ProtoCreateServiceParam(PROTO_INTERFACE *pThis, const char* szService, ProtoServiceFuncParam, LPARAM); -#endif - -///////////////////////////////////////////////////////////////////////////////////////// -// interface declaration - -enum ProtoMenuItemType -{ - PROTO_MENU_REQ_AUTH, - PROTO_MENU_GRANT_AUTH, - PROTO_MENU_REVOKE_AUTH, - PROTO_MENU_LOAD_HISTORY -}; - -struct MIR_APP_EXPORT PROTO_INTERFACE : public MZeroedObject -{ - -protected: - MWindowList m_hWindowList = 0; // list of all windows which belong to this protocol's instance - -public: - int m_iStatus; // current protocol status - int m_iDesiredStatus; // status to be set after logging in - int m_iXStatus; // extanded status - int m_iVersion; // version 2 or higher designate support of Unicode services - wchar_t* m_tszUserName; // human readable protocol's name - char* m_szModuleName; // internal protocol name, also its database module name - HANDLE m_hProtoIcon = 0; // icon to be displayed in the account manager - HNETLIBUSER m_hNetlibUser = 0; // network agent - HGENMENU m_hmiMainMenu = 0; // if protocol menus are displayed in the main menu, this is the root - - PROTO_INTERFACE(const char *pszModuleName, const wchar_t *ptszUserName); - ~PROTO_INTERFACE(); - - ////////////////////////////////////////////////////////////////////////////////////// - // Helpers - - __forceinline INT_PTR ProtoBroadcastAck(MCONTACT hContact, int type, int hResult, HANDLE hProcess, LPARAM lParam = 0) { - return ::ProtoBroadcastAck(m_szModuleName, hContact, type, hResult, hProcess, lParam); } - __forceinline void ProtoBroadcastAsync(MCONTACT hContact, int type, int hResult, HANDLE hProcess, LPARAM lParam = 0) { - return ::ProtoBroadcastAsync(m_szModuleName, hContact, type, hResult, hProcess, lParam); } - - __forceinline INT_PTR delSetting(const char *name) { return db_unset(NULL, m_szModuleName, name); } - __forceinline INT_PTR delSetting(MCONTACT hContact, const char *name) { return db_unset(hContact, m_szModuleName, name); } - - __forceinline bool getBool(const char *name, bool defaultValue = false) { - return db_get_b(NULL, m_szModuleName, name, defaultValue) != 0; } - __forceinline bool getBool(MCONTACT hContact, const char *name, bool defaultValue = false) { - return db_get_b(hContact, m_szModuleName, name, defaultValue) != 0; } - - __forceinline bool isChatRoom(MCONTACT hContact) { return getBool(hContact, "ChatRoom", false); } - - __forceinline int getByte(const char *name, BYTE defaultValue = 0) { - return db_get_b(NULL, m_szModuleName, name, defaultValue); } - __forceinline int getByte(MCONTACT hContact, const char *name, BYTE defaultValue = 0) { - return db_get_b(hContact, m_szModuleName, name, defaultValue); } - - __forceinline int getWord(const char *name, WORD defaultValue = 0) { - return db_get_w(NULL, m_szModuleName, name, defaultValue); } - __forceinline int getWord(MCONTACT hContact, const char *name, WORD defaultValue = 0) { - return db_get_w(hContact, m_szModuleName, name, defaultValue); } - - __forceinline DWORD getDword(const char *name, DWORD defaultValue = 0) { - return db_get_dw(NULL, m_szModuleName, name, defaultValue); } - __forceinline DWORD getDword(MCONTACT hContact, const char *name, DWORD defaultValue = 0) { - return db_get_dw(hContact, m_szModuleName, name, defaultValue); } - - __forceinline INT_PTR getString(const char *name, DBVARIANT *result) { - return db_get_s(NULL, m_szModuleName, name, result, DBVT_ASCIIZ); } - __forceinline INT_PTR getString(MCONTACT hContact, const char *name, DBVARIANT *result) { - return db_get_s(hContact, m_szModuleName, name, result, DBVT_ASCIIZ); } - - __forceinline INT_PTR getUString(const char *name, DBVARIANT *result) { - return db_get_s(NULL, m_szModuleName, name, result, DBVT_UTF8); } - __forceinline INT_PTR getUString(MCONTACT hContact, const char *name, DBVARIANT *result) { - return db_get_s(hContact, m_szModuleName, name, result, DBVT_UTF8); } - - __forceinline INT_PTR getWString(const char *name, DBVARIANT *result) { - return db_get_s(NULL, m_szModuleName, name, result, DBVT_WCHAR); } - __forceinline INT_PTR getWString(MCONTACT hContact, const char *name, DBVARIANT *result) { - return db_get_s(hContact, m_szModuleName, name, result, DBVT_WCHAR); } - - __forceinline char* getStringA(const char *name, const char *szValue = nullptr) { - return db_get_sa(NULL, m_szModuleName, name, szValue); } - __forceinline char* getStringA(MCONTACT hContact, const char *name, const char *szValue = nullptr) { - return db_get_sa(hContact, m_szModuleName, name, szValue); } - - __forceinline char* getUStringA(const char *name, const char *szValue = nullptr) { - return db_get_utfa(NULL, m_szModuleName, name, szValue); } - __forceinline char* getUStringA(MCONTACT hContact, const char *name, const char *szValue = nullptr) { - return db_get_utfa(hContact, m_szModuleName, name, szValue); } - - __forceinline wchar_t* getWStringA(const char *name, const wchar_t *szValue = nullptr) { - return db_get_wsa(NULL, m_szModuleName, name, szValue); } - __forceinline wchar_t* getWStringA(MCONTACT hContact, const char *name, const wchar_t *szValue = nullptr) { - return db_get_wsa(hContact, m_szModuleName, name, szValue); } - - __forceinline CMStringA getMStringA(const char *name, const char *szValue = nullptr) { - return db_get_sm(NULL, m_szModuleName, name, szValue); } - __forceinline CMStringA getMStringA(MCONTACT hContact, const char *name, const char *szValue = nullptr) { - return db_get_sm(hContact, m_szModuleName, name, szValue); } - - __forceinline CMStringW getMStringW(const char *name, const wchar_t *szValue = nullptr) { - return db_get_wsm(NULL, m_szModuleName, name, szValue); } - __forceinline CMStringW getMStringW(MCONTACT hContact, const char *name, const wchar_t *szValue = nullptr) { - return db_get_wsm(hContact, m_szModuleName, name, szValue); } - - __forceinline void setByte(const char *name, BYTE value) { db_set_b(NULL, m_szModuleName, name, value); } - __forceinline void setByte(MCONTACT hContact, const char *name, BYTE value) { db_set_b(hContact, m_szModuleName, name, value); } - - __forceinline void setWord(const char *name, WORD value) { db_set_w(NULL, m_szModuleName, name, value); } - __forceinline void setWord(MCONTACT hContact, const char *name, WORD value) { db_set_w(hContact, m_szModuleName, name, value); } - - __forceinline void setDword(const char *name, DWORD value) { db_set_dw(NULL, m_szModuleName, name, value); } - __forceinline void setDword(MCONTACT hContact, const char *name, DWORD value) { db_set_dw(hContact, m_szModuleName, name, value); } - - __forceinline void setString(const char *name, const char* value) { db_set_s(NULL, m_szModuleName, name, value); } - __forceinline void setString(MCONTACT hContact, const char *name, const char* value) { db_set_s(hContact, m_szModuleName, name, value); } - - __forceinline void setUString(const char *name, const char* value) { db_set_utf(NULL, m_szModuleName, name, value); } - __forceinline void setUString(MCONTACT hContact, const char *name, const char* value) { db_set_utf(hContact, m_szModuleName, name, value); } - - __forceinline void setWString(const char *name, const wchar_t* value) { db_set_ws(NULL, m_szModuleName, name, value); } - __forceinline void setWString(MCONTACT hContact, const char *name, const wchar_t* value) { db_set_ws(hContact, m_szModuleName, name, value); } - - __forceinline Contacts AccContacts() const { return Contacts(m_szModuleName); } - - ////////////////////////////////////////////////////////////////////////////////////// - // Service functions - - void debugLogA(const char *szFormat, ...); - void debugLogW(const wchar_t *wszFormat, ...); - - void setAllContactStatuses(int iStatus, bool bSkipChats = true); - - void ReportSelfAvatarChanged(); - - void WindowSubscribe(HWND hwnd); - void WindowUnsubscribe(HWND hwnd); - - HGENMENU GetMenuItem(ProtoMenuItemType); - - ////////////////////////////////////////////////////////////////////////////////////// - // Virtual functions - - virtual MCONTACT AddToList(int flags, PROTOSEARCHRESULT *psr); - virtual MCONTACT AddToListByEvent(int flags, int iContact, MEVENT hDbEvent); - - virtual int Authorize(MEVENT hDbEvent); - virtual int AuthDeny(MEVENT hDbEvent, const wchar_t *szReason); - virtual int AuthRecv(MCONTACT hContact, PROTORECVEVENT *); - virtual int AuthRequest(MCONTACT hContact, const wchar_t *szMessage); - - virtual HANDLE FileAllow(MCONTACT hContact, HANDLE hTransfer, const wchar_t *szPath); - virtual int FileCancel(MCONTACT hContact, HANDLE hTransfer); - virtual int FileDeny(MCONTACT hContact, HANDLE hTransfer, const wchar_t *szReason); - virtual int FileResume(HANDLE hTransfer, int action, const wchar_t *szFilename); - - virtual INT_PTR GetCaps(int type, MCONTACT hContact = NULL); - virtual int GetInfo(MCONTACT hContact, int infoType); - - virtual HANDLE SearchBasic(const wchar_t *id); - virtual HANDLE SearchByEmail(const wchar_t *email); - virtual HANDLE SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName); - virtual HWND SearchAdvanced(HWND owner); - virtual HWND CreateExtendedSearchUI(HWND owner); - - virtual int RecvContacts(MCONTACT hContact, PROTORECVEVENT *); - virtual int RecvFile(MCONTACT hContact, PROTORECVFILE *); - virtual MEVENT RecvMsg(MCONTACT hContact, PROTORECVEVENT *); - - virtual int SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT *hContactsList); - virtual HANDLE SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles); - virtual int SendMsg(MCONTACT hContact, int flags, const char *msg); - - virtual int SetApparentMode(MCONTACT hContact, int mode); - virtual int SetStatus(int iNewStatus); - - virtual HANDLE GetAwayMsg(MCONTACT hContact); - virtual int RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT *evt); - virtual int SetAwayMsg(int iStatus, const wchar_t *msg); - - virtual int UserIsTyping(MCONTACT hContact, int type); - - ////////////////////////////////////////////////////////////////////////////////////// - // events - - // builds the account's protocol menu - virtual void OnBuildProtoMenu(void); - - // called when an account's contact is added - virtual void OnContactAdded(MCONTACT); - - // called when an account's contact is deleted - virtual void OnContactDeleted(MCONTACT); - - // called when an event is altered in database - virtual void OnEventEdited(MCONTACT, MEVENT); - - // called when an account gets physically removed from the database - virtual void OnErase(); - - // the analog of ME_SYSTEM_MODULESLOADED for an account - virtual void OnModulesLoaded(void); - - // same for ME_SYSTEM_SHUTDOWN - virtual void OnShutdown(void); - - // same for ME_SYSTEM_OKTOEXIT - virtual bool IsReadyToExit(void); -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Basic class for all protocols written in C++ - -template struct PROTO : public PROTO_INTERFACE -{ - typedef PROTO_INTERFACE CSuper; - - __forceinline PROTO(const char *szProto, const wchar_t *tszUserName) : - PROTO_INTERFACE(szProto, tszUserName) - {} - - __forceinline HANDLE CreateProtoEvent(const char *name) { - return ::ProtoCreateHookableEvent(this, name); } - - typedef int(__cdecl T::*MyEventFunc)(WPARAM, LPARAM); - __forceinline void HookProtoEvent(const char *name, MyEventFunc pFunc) { - ::ProtoHookEvent(this, name, (ProtoEventFunc)pFunc); } - - typedef void(__cdecl T::*MyThreadFunc)(void*); - __forceinline void ForkThread(MyThreadFunc pFunc, void *param = nullptr) { - ::ProtoForkThread(this, (ProtoThreadFunc)pFunc, param); } - HANDLE __forceinline ForkThreadEx(MyThreadFunc pFunc, void *param, UINT *pThreadId) { - return ::ProtoForkThreadEx(this, (ProtoThreadFunc)pFunc, param, pThreadId); } - - typedef INT_PTR(__cdecl T::*MyServiceFunc)(WPARAM, LPARAM); - __forceinline void CreateProtoService(const char *name, MyServiceFunc pFunc) { - ::ProtoCreateService(this, name, (ProtoServiceFunc)pFunc); } - - typedef INT_PTR(__cdecl T::*MyServiceFuncParam)(WPARAM, LPARAM, LPARAM); - __forceinline void CreateProtoServiceParam(const char *name, MyServiceFuncParam pFunc, LPARAM param) { - ::ProtoCreateServiceParam(this, name, (ProtoServiceFuncParam)pFunc, param); } -}; - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_APP_DLL(PROTO_INTERFACE *) Proto_GetInstance(const char *szModule); -MIR_APP_DLL(PROTO_INTERFACE *) Proto_GetInstance(MCONTACT hContact); - -#endif // M_PROTOINT_H__ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2000-08 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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_PROTOINT_H__ +#define M_PROTOINT_H__ 1 + +#include +#include +#include +#include +#include + +///////////////////////////////////////////////////////////////////////////////////////// +// protocol helpers + +struct PROTO_INTERFACE; + +// Call it in the very beginning of your proto's constructor +EXTERN_C MIR_APP_DLL(void) ProtoConstructor(PROTO_INTERFACE *pThis, const char *pszModuleName, const wchar_t *ptszUserName); + +// Call it in the very end of your proto's destructor +EXTERN_C MIR_APP_DLL(void) ProtoDestructor(PROTO_INTERFACE *pThis); + +#if defined( __cplusplus ) +typedef void (MIR_CDECL PROTO_INTERFACE::*ProtoThreadFunc)(void*); +EXTERN_C MIR_APP_DLL(void) ProtoForkThread(PROTO_INTERFACE *pThis, ProtoThreadFunc, void *param); +EXTERN_C MIR_APP_DLL(HANDLE) ProtoForkThreadEx(PROTO_INTERFACE *pThis, ProtoThreadFunc, void *param, UINT* threadID); +EXTERN_C MIR_APP_DLL(void) ProtoWindowAdd(PROTO_INTERFACE *pThis, HWND hwnd); +EXTERN_C MIR_APP_DLL(void) ProtoWindowRemove(PROTO_INTERFACE *pThis, HWND hwnd); + +typedef int (MIR_CDECL PROTO_INTERFACE::*ProtoEventFunc)(WPARAM, LPARAM); +EXTERN_C MIR_APP_DLL(void) ProtoHookEvent(PROTO_INTERFACE *pThis, const char* szName, ProtoEventFunc pFunc); +EXTERN_C MIR_APP_DLL(HANDLE) ProtoCreateHookableEvent(PROTO_INTERFACE *pThis, const char* szService); + +typedef INT_PTR (MIR_CDECL PROTO_INTERFACE::*ProtoServiceFunc)(WPARAM, LPARAM); +EXTERN_C MIR_APP_DLL(void) ProtoCreateService(PROTO_INTERFACE *pThis, const char* szService, ProtoServiceFunc); + +typedef INT_PTR (MIR_CDECL PROTO_INTERFACE::*ProtoServiceFuncParam)(WPARAM, LPARAM, LPARAM); +EXTERN_C MIR_APP_DLL(void) ProtoCreateServiceParam(PROTO_INTERFACE *pThis, const char* szService, ProtoServiceFuncParam, LPARAM); +#endif + +///////////////////////////////////////////////////////////////////////////////////////// +// interface declaration + +enum ProtoMenuItemType +{ + PROTO_MENU_REQ_AUTH, + PROTO_MENU_GRANT_AUTH, + PROTO_MENU_REVOKE_AUTH, + PROTO_MENU_LOAD_HISTORY +}; + +struct MIR_APP_EXPORT PROTO_INTERFACE : public MZeroedObject +{ + +protected: + MWindowList m_hWindowList = 0; // list of all windows which belong to this protocol's instance + +public: + int m_iStatus; // current protocol status + int m_iDesiredStatus; // status to be set after logging in + int m_iXStatus; // extanded status + int m_iVersion; // version 2 or higher designate support of Unicode services + wchar_t* m_tszUserName; // human readable protocol's name + char* m_szModuleName; // internal protocol name, also its database module name + HANDLE m_hProtoIcon = 0; // icon to be displayed in the account manager + HNETLIBUSER m_hNetlibUser = 0; // network agent + HGENMENU m_hmiMainMenu = 0; // if protocol menus are displayed in the main menu, this is the root + + PROTO_INTERFACE(const char *pszModuleName, const wchar_t *ptszUserName); + ~PROTO_INTERFACE(); + + ////////////////////////////////////////////////////////////////////////////////////// + // Helpers + + __forceinline INT_PTR ProtoBroadcastAck(MCONTACT hContact, int type, int hResult, HANDLE hProcess, LPARAM lParam = 0) { + return ::ProtoBroadcastAck(m_szModuleName, hContact, type, hResult, hProcess, lParam); } + __forceinline void ProtoBroadcastAsync(MCONTACT hContact, int type, int hResult, HANDLE hProcess, LPARAM lParam = 0) { + return ::ProtoBroadcastAsync(m_szModuleName, hContact, type, hResult, hProcess, lParam); } + + __forceinline INT_PTR delSetting(const char *name) { return db_unset(NULL, m_szModuleName, name); } + __forceinline INT_PTR delSetting(MCONTACT hContact, const char *name) { return db_unset(hContact, m_szModuleName, name); } + + __forceinline bool getBool(const char *name, bool defaultValue = false) { + return db_get_b(NULL, m_szModuleName, name, defaultValue) != 0; } + __forceinline bool getBool(MCONTACT hContact, const char *name, bool defaultValue = false) { + return db_get_b(hContact, m_szModuleName, name, defaultValue) != 0; } + + __forceinline bool isChatRoom(MCONTACT hContact) { return getBool(hContact, "ChatRoom", false); } + + __forceinline int getByte(const char *name, BYTE defaultValue = 0) { + return db_get_b(NULL, m_szModuleName, name, defaultValue); } + __forceinline int getByte(MCONTACT hContact, const char *name, BYTE defaultValue = 0) { + return db_get_b(hContact, m_szModuleName, name, defaultValue); } + + __forceinline int getWord(const char *name, WORD defaultValue = 0) { + return db_get_w(NULL, m_szModuleName, name, defaultValue); } + __forceinline int getWord(MCONTACT hContact, const char *name, WORD defaultValue = 0) { + return db_get_w(hContact, m_szModuleName, name, defaultValue); } + + __forceinline DWORD getDword(const char *name, DWORD defaultValue = 0) { + return db_get_dw(NULL, m_szModuleName, name, defaultValue); } + __forceinline DWORD getDword(MCONTACT hContact, const char *name, DWORD defaultValue = 0) { + return db_get_dw(hContact, m_szModuleName, name, defaultValue); } + + __forceinline INT_PTR getString(const char *name, DBVARIANT *result) { + return db_get_s(NULL, m_szModuleName, name, result, DBVT_ASCIIZ); } + __forceinline INT_PTR getString(MCONTACT hContact, const char *name, DBVARIANT *result) { + return db_get_s(hContact, m_szModuleName, name, result, DBVT_ASCIIZ); } + + __forceinline INT_PTR getUString(const char *name, DBVARIANT *result) { + return db_get_s(NULL, m_szModuleName, name, result, DBVT_UTF8); } + __forceinline INT_PTR getUString(MCONTACT hContact, const char *name, DBVARIANT *result) { + return db_get_s(hContact, m_szModuleName, name, result, DBVT_UTF8); } + + __forceinline INT_PTR getWString(const char *name, DBVARIANT *result) { + return db_get_s(NULL, m_szModuleName, name, result, DBVT_WCHAR); } + __forceinline INT_PTR getWString(MCONTACT hContact, const char *name, DBVARIANT *result) { + return db_get_s(hContact, m_szModuleName, name, result, DBVT_WCHAR); } + + __forceinline char* getStringA(const char *name, const char *szValue = nullptr) { + return db_get_sa(NULL, m_szModuleName, name, szValue); } + __forceinline char* getStringA(MCONTACT hContact, const char *name, const char *szValue = nullptr) { + return db_get_sa(hContact, m_szModuleName, name, szValue); } + + __forceinline char* getUStringA(const char *name, const char *szValue = nullptr) { + return db_get_utfa(NULL, m_szModuleName, name, szValue); } + __forceinline char* getUStringA(MCONTACT hContact, const char *name, const char *szValue = nullptr) { + return db_get_utfa(hContact, m_szModuleName, name, szValue); } + + __forceinline wchar_t* getWStringA(const char *name, const wchar_t *szValue = nullptr) { + return db_get_wsa(NULL, m_szModuleName, name, szValue); } + __forceinline wchar_t* getWStringA(MCONTACT hContact, const char *name, const wchar_t *szValue = nullptr) { + return db_get_wsa(hContact, m_szModuleName, name, szValue); } + + __forceinline CMStringA getMStringA(const char *name, const char *szValue = nullptr) { + return db_get_sm(NULL, m_szModuleName, name, szValue); } + __forceinline CMStringA getMStringA(MCONTACT hContact, const char *name, const char *szValue = nullptr) { + return db_get_sm(hContact, m_szModuleName, name, szValue); } + + __forceinline CMStringW getMStringW(const char *name, const wchar_t *szValue = nullptr) { + return db_get_wsm(NULL, m_szModuleName, name, szValue); } + __forceinline CMStringW getMStringW(MCONTACT hContact, const char *name, const wchar_t *szValue = nullptr) { + return db_get_wsm(hContact, m_szModuleName, name, szValue); } + + __forceinline void setByte(const char *name, BYTE value) { db_set_b(NULL, m_szModuleName, name, value); } + __forceinline void setByte(MCONTACT hContact, const char *name, BYTE value) { db_set_b(hContact, m_szModuleName, name, value); } + + __forceinline void setWord(const char *name, WORD value) { db_set_w(NULL, m_szModuleName, name, value); } + __forceinline void setWord(MCONTACT hContact, const char *name, WORD value) { db_set_w(hContact, m_szModuleName, name, value); } + + __forceinline void setDword(const char *name, DWORD value) { db_set_dw(NULL, m_szModuleName, name, value); } + __forceinline void setDword(MCONTACT hContact, const char *name, DWORD value) { db_set_dw(hContact, m_szModuleName, name, value); } + + __forceinline void setString(const char *name, const char* value) { db_set_s(NULL, m_szModuleName, name, value); } + __forceinline void setString(MCONTACT hContact, const char *name, const char* value) { db_set_s(hContact, m_szModuleName, name, value); } + + __forceinline void setUString(const char *name, const char* value) { db_set_utf(NULL, m_szModuleName, name, value); } + __forceinline void setUString(MCONTACT hContact, const char *name, const char* value) { db_set_utf(hContact, m_szModuleName, name, value); } + + __forceinline void setWString(const char *name, const wchar_t* value) { db_set_ws(NULL, m_szModuleName, name, value); } + __forceinline void setWString(MCONTACT hContact, const char *name, const wchar_t* value) { db_set_ws(hContact, m_szModuleName, name, value); } + + __forceinline Contacts AccContacts() const { return Contacts(m_szModuleName); } + + ////////////////////////////////////////////////////////////////////////////////////// + // Service functions + + void debugLogA(const char *szFormat, ...); + void debugLogW(const wchar_t *wszFormat, ...); + + void setAllContactStatuses(int iStatus, bool bSkipChats = true); + + void ReportSelfAvatarChanged(); + + void WindowSubscribe(HWND hwnd); + void WindowUnsubscribe(HWND hwnd); + + HGENMENU GetMenuItem(ProtoMenuItemType); + + ////////////////////////////////////////////////////////////////////////////////////// + // Virtual functions + + virtual MCONTACT AddToList(int flags, PROTOSEARCHRESULT *psr); + virtual MCONTACT AddToListByEvent(int flags, int iContact, MEVENT hDbEvent); + + virtual int Authorize(MEVENT hDbEvent); + virtual int AuthDeny(MEVENT hDbEvent, const wchar_t *szReason); + virtual int AuthRecv(MCONTACT hContact, PROTORECVEVENT *); + virtual int AuthRequest(MCONTACT hContact, const wchar_t *szMessage); + + virtual HANDLE FileAllow(MCONTACT hContact, HANDLE hTransfer, const wchar_t *szPath); + virtual int FileCancel(MCONTACT hContact, HANDLE hTransfer); + virtual int FileDeny(MCONTACT hContact, HANDLE hTransfer, const wchar_t *szReason); + virtual int FileResume(HANDLE hTransfer, int action, const wchar_t *szFilename); + + virtual INT_PTR GetCaps(int type, MCONTACT hContact = NULL); + virtual int GetInfo(MCONTACT hContact, int infoType); + + virtual HANDLE SearchBasic(const wchar_t *id); + virtual HANDLE SearchByEmail(const wchar_t *email); + virtual HANDLE SearchByName(const wchar_t *nick, const wchar_t *firstName, const wchar_t *lastName); + virtual HWND SearchAdvanced(HWND owner); + virtual HWND CreateExtendedSearchUI(HWND owner); + + virtual int RecvContacts(MCONTACT hContact, PROTORECVEVENT *); + virtual int RecvFile(MCONTACT hContact, PROTORECVFILE *); + virtual MEVENT RecvMsg(MCONTACT hContact, PROTORECVEVENT *); + + virtual int SendContacts(MCONTACT hContact, int flags, int nContacts, MCONTACT *hContactsList); + virtual HANDLE SendFile(MCONTACT hContact, const wchar_t *szDescription, wchar_t **ppszFiles); + virtual int SendMsg(MCONTACT hContact, int flags, const char *msg); + + virtual int SetApparentMode(MCONTACT hContact, int mode); + virtual int SetStatus(int iNewStatus); + + virtual HANDLE GetAwayMsg(MCONTACT hContact); + virtual int RecvAwayMsg(MCONTACT hContact, int mode, PROTORECVEVENT *evt); + virtual int SetAwayMsg(int iStatus, const wchar_t *msg); + + virtual int UserIsTyping(MCONTACT hContact, int type); + + ////////////////////////////////////////////////////////////////////////////////////// + // events + + // builds the account's protocol menu + virtual void OnBuildProtoMenu(void); + + // called when an account's contact is added + virtual void OnContactAdded(MCONTACT); + + // called when an account's contact is deleted + virtual void OnContactDeleted(MCONTACT); + + // called when an event is altered in database + virtual void OnEventEdited(MCONTACT, MEVENT); + + // called when an account gets physically removed from the database + virtual void OnErase(); + + // the analog of ME_SYSTEM_MODULESLOADED for an account + virtual void OnModulesLoaded(void); + + // same for ME_SYSTEM_SHUTDOWN + virtual void OnShutdown(void); + + // same for ME_SYSTEM_OKTOEXIT + virtual bool IsReadyToExit(void); +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Basic class for all protocols written in C++ + +template struct PROTO : public PROTO_INTERFACE +{ + typedef PROTO_INTERFACE CSuper; + + __forceinline PROTO(const char *szProto, const wchar_t *tszUserName) : + PROTO_INTERFACE(szProto, tszUserName) + {} + + __forceinline HANDLE CreateProtoEvent(const char *name) { + return ::ProtoCreateHookableEvent(this, name); } + + typedef int(MIR_CDECL T::*MyEventFunc)(WPARAM, LPARAM); + __forceinline void HookProtoEvent(const char *name, MyEventFunc pFunc) { + ::ProtoHookEvent(this, name, (ProtoEventFunc)pFunc); } + + typedef void(MIR_CDECL T::*MyThreadFunc)(void*); + __forceinline void ForkThread(MyThreadFunc pFunc, void *param = nullptr) { + ::ProtoForkThread(this, (ProtoThreadFunc)pFunc, param); } + HANDLE __forceinline ForkThreadEx(MyThreadFunc pFunc, void *param, UINT *pThreadId) { + return ::ProtoForkThreadEx(this, (ProtoThreadFunc)pFunc, param, pThreadId); } + + typedef INT_PTR(MIR_CDECL T::*MyServiceFunc)(WPARAM, LPARAM); + __forceinline void CreateProtoService(const char *name, MyServiceFunc pFunc) { + ::ProtoCreateService(this, name, (ProtoServiceFunc)pFunc); } + + typedef INT_PTR(MIR_CDECL T::*MyServiceFuncParam)(WPARAM, LPARAM, LPARAM); + __forceinline void CreateProtoServiceParam(const char *name, MyServiceFuncParam pFunc, LPARAM param) { + ::ProtoCreateServiceParam(this, name, (ProtoServiceFuncParam)pFunc, param); } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_APP_DLL(PROTO_INTERFACE *) Proto_GetInstance(const char *szModule); +MIR_APP_DLL(PROTO_INTERFACE *) Proto_GetInstance(MCONTACT hContact); + +#endif // M_PROTOINT_H__ diff --git a/include/m_string.h b/include/m_string.h index 21404268cd..9d6244b19b 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -1,958 +1,1040 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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. -*/ - -#pragma once - -#ifndef M_STRING_H__ -#define M_STRING_H__ - -#include -#include -#include -#include - -#include - -#ifdef __MINGW32__ -#include - -__inline size_t strnlen(const char *string, size_t maxlen) -{ - const char *end = (const char *)memchr ((const void *)string, '\0', maxlen); - return end ? (size_t) (end - string) : maxlen; -} -__inline size_t wcsnlen(const wchar_t *string, size_t maxlen) -{ - const wchar_t *end = wmemchr (string, L'\0', maxlen); - return end ? (size_t) (end - string) : maxlen; -} - -/* FIXME: This may be wrong assumption about Langpack_GetDefaultCodePage */ -#define Langpack_GetDefaultCodePage() CP_THREAD_ACP -/* FIXME: This is unsafe */ -#define memcpy_s(dest,size,src,count) memcpy(dest,src,count) -/* FIXME: This is quite silly implementation of _mbsstr */ -#define _mbsstr(str,search) strstr((const char *)str,(const char *)search) -#define __max(x,y) (((x)<(y))?(y):(x)) -#endif /* __MINGW32__ */ - -///////////////////////////////////////////////////////////////////////////////////////// - -struct CMStringData; - -MIR_CORE_DLL(CMStringData*) mirstr_allocate(int nChars, int nCharSize); -MIR_CORE_DLL(void) mirstr_free(CMStringData *pData); -MIR_CORE_DLL(CMStringData*) mirstr_realloc(CMStringData* pData, int nChars, int nCharSize); -MIR_CORE_DLL(CMStringData*) mirstr_getNil(); - -MIR_CORE_DLL(void) mirstr_lock(CMStringData* pThis); -MIR_CORE_DLL(void) mirstr_release(CMStringData* pThis); -MIR_CORE_DLL(void) mirstr_unlock(CMStringData* pThis); - -///////////////////////////////////////////////////////////////////////////////////////// - -enum CMStringDataFormat { FORMAT }; - -struct CMStringData -{ - int nDataLength; // Length of currently used data in XCHARs (not including terminating null) - int nAllocLength; // Length of allocated data in XCHARs (not including terminating null) - long nRefs; // Reference count: negative == locked - - __forceinline void* data() { return (this + 1); } - __forceinline void AddRef() { InterlockedIncrement(&nRefs); } - __forceinline bool IsLocked() const { return nRefs < 0; } - __forceinline bool IsShared() const { return nRefs > 1; } - - __forceinline void Lock() { mirstr_lock(this); } - __forceinline void Release() { mirstr_release(this); } - __forceinline void Unlock() { mirstr_unlock(this); } -}; - -template< typename BaseType = char > -class ChTraitsBase -{ -public: - typedef char XCHAR; - typedef LPSTR PXSTR; - typedef LPCSTR PCXSTR; - typedef wchar_t YCHAR; - typedef LPWSTR PYSTR; - typedef LPCWSTR PCYSTR; -}; - -template<> -class ChTraitsBase< wchar_t > -{ -public: - typedef wchar_t XCHAR; - typedef LPWSTR PXSTR; - typedef LPCWSTR PCXSTR; - typedef char YCHAR; - typedef LPSTR PYSTR; - typedef LPCSTR PCYSTR; -}; - -template< typename BaseType > -class CMSimpleStringT -{ -public: - typedef typename ChTraitsBase< BaseType >::XCHAR XCHAR; - typedef typename ChTraitsBase< BaseType >::PXSTR PXSTR; - typedef typename ChTraitsBase< BaseType >::PCXSTR PCXSTR; - typedef typename ChTraitsBase< BaseType >::YCHAR YCHAR; - typedef typename ChTraitsBase< BaseType >::PYSTR PYSTR; - typedef typename ChTraitsBase< BaseType >::PCYSTR PCYSTR; - -public: - explicit CMSimpleStringT(); - - CMSimpleStringT(const CMSimpleStringT& strSrc); - CMSimpleStringT(PCXSTR pszSrc); - CMSimpleStringT(const XCHAR* pchSrc, int nLength); - ~CMSimpleStringT(); - - __forceinline operator CMSimpleStringT&() - { return *(CMSimpleStringT*)this; - } - - CMSimpleStringT& operator=(const CMSimpleStringT& strSrc); - - __forceinline CMSimpleStringT& operator=(PCXSTR pszSrc) - { SetString(pszSrc); - return *this; - } - - __forceinline CMSimpleStringT& operator+=(const CMSimpleStringT& strSrc) - { Append(strSrc); - return *this; - } - - __forceinline CMSimpleStringT& operator+=(PCXSTR pszSrc) - { Append(pszSrc); - return *this; - } - - __forceinline CMSimpleStringT& operator+=(char ch) - { AppendChar(XCHAR(ch)); - return *this; - } - - __forceinline CMSimpleStringT& operator+=(unsigned char ch) - { AppendChar(XCHAR(ch)); - return *this; - } - - __forceinline CMSimpleStringT& operator+=(wchar_t ch) - { AppendChar(XCHAR(ch)); - return *this; - } - - __forceinline XCHAR operator[](int iChar) const - { return m_pszData[iChar]; - } - - __forceinline operator PCXSTR() const - { return m_pszData; - } - - __forceinline PCXSTR c_str() const - { return m_pszData; - } - - __forceinline int GetAllocLength() const - { return GetData()->nAllocLength; - } - - __forceinline XCHAR GetAt(int iChar) const - { return m_pszData[iChar]; - } - - __forceinline PXSTR GetBuffer(int nMinBufferLength) - { return PrepareWrite(nMinBufferLength); - } - - __forceinline int GetLength() const - { return GetData()->nDataLength; - } - - __forceinline PCXSTR GetString() const - { return m_pszData; - } - - __forceinline PCXSTR GetTail() const - { return m_pszData + GetData()->nDataLength; - } - - __forceinline bool IsEmpty() const - { return GetLength() == 0; - } - - __forceinline void Preallocate(int nLength) - { PrepareWrite(nLength); - } - - __forceinline void ReleaseBufferSetLength(int nNewLength) - { SetLength(nNewLength); - } - - void Append(PCXSTR pszSrc); - void Append(PCXSTR pszSrc, int nLength); - void AppendChar(XCHAR ch); - void Append(const CMSimpleStringT& strSrc); - - void Empty(); - void FreeExtra(); - - PXSTR GetBuffer(); - PXSTR GetBufferSetLength(int nLength); - - PXSTR LockBuffer(); - void UnlockBuffer(); - - void ReleaseBuffer(int nNewLength = -1); - - void Truncate(int nNewLength); - void SetAt(int iChar, XCHAR ch); - void SetString(PCXSTR pszSrc); - void SetString(PCXSTR pszSrc, int nLength); - -public: - friend CMSimpleStringT operator+(const CMSimpleStringT& str1, const CMSimpleStringT& str2); - friend CMSimpleStringT operator+(const CMSimpleStringT& str1, PCXSTR psz2); - friend CMSimpleStringT operator+(PCXSTR psz1, const CMSimpleStringT& str2); - - static void __stdcall CopyChars(XCHAR* pchDest, const XCHAR* pchSrc, int nChars); - static void __stdcall CopyChars(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars); - static void __stdcall CopyCharsOverlapped(XCHAR* pchDest, const XCHAR* pchSrc, int nChars); - static void __stdcall CopyCharsOverlapped(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars); - static int __stdcall StringLength(const char* psz); - static int __stdcall StringLength(const wchar_t* psz); - static int __stdcall StringLengthN(const char* psz, size_t sizeInXChar); - static int __stdcall StringLengthN(const wchar_t* psz, size_t sizeInXChar); - static void __stdcall Concatenate(CMSimpleStringT& strResult, PCXSTR psz1, int nLength1, PCXSTR psz2, int nLength2); - - // Implementation -private: - __forceinline CMStringData* GetData() const - { return (reinterpret_cast(m_pszData)-1); - } - - void Attach(CMStringData* pData); - void Fork(int nLength); - PXSTR PrepareWrite(int nLength); - void PrepareWrite2(int nLength); - void Reallocate(int nLength); - void SetLength(int nLength); - static CMStringData* __stdcall CloneData(CMStringData* pData); - -private: - PXSTR m_pszData; -}; - - -template< typename _CharType = char > -class ChTraitsCRT : public ChTraitsBase < _CharType > -{ -public: - static char* __stdcall CharNext(const char* p) - { - return reinterpret_cast(_mbsinc(reinterpret_cast(p))); - } - - static int __stdcall IsDigit(char ch) - { - return _ismbcdigit(ch); - } - - static int __stdcall IsSpace(char ch) - { - return _ismbcspace(ch); - } - - static int __stdcall StringCompare(LPCSTR pszA, LPCSTR pszB) - { - return _mbscmp(reinterpret_cast(pszA), reinterpret_cast(pszB)); - } - - static int __stdcall StringCompareIgnore(LPCSTR pszA, LPCSTR pszB) - { - return _mbsicmp(reinterpret_cast(pszA), reinterpret_cast(pszB)); - } - - static int __stdcall StringCollate(LPCSTR pszA, LPCSTR pszB) - { - return _mbscoll(reinterpret_cast(pszA), reinterpret_cast(pszB)); - } - - static int __stdcall StringCollateIgnore(LPCSTR pszA, LPCSTR pszB) - { - return _mbsicoll(reinterpret_cast(pszA), reinterpret_cast(pszB)); - } - - static LPCSTR __stdcall StringFindString(LPCSTR pszBlock, LPCSTR pszMatch) - { - return reinterpret_cast(_mbsstr(reinterpret_cast(pszBlock), - reinterpret_cast(pszMatch))); - } - - static LPSTR __stdcall StringFindString(LPSTR pszBlock, LPCSTR pszMatch) - { - return const_cast(StringFindString(const_cast(pszBlock), pszMatch)); - } - - static LPCSTR __stdcall StringFindChar(LPCSTR pszBlock, char chMatch) - { - return reinterpret_cast(_mbschr(reinterpret_cast(pszBlock), (unsigned char)chMatch)); - } - - static LPCSTR __stdcall StringFindCharRev(LPCSTR psz, char ch) - { - return reinterpret_cast(_mbsrchr(reinterpret_cast(psz), (unsigned char)ch)); - } - - static LPCSTR __stdcall StringScanSet(LPCSTR pszBlock, LPCSTR pszMatch) - { - return reinterpret_cast(_mbspbrk(reinterpret_cast(pszBlock), - reinterpret_cast(pszMatch))); - } - - static int __stdcall StringSpanIncluding(LPCSTR pszBlock, LPCSTR pszSet) - { - return (int)_mbsspn(reinterpret_cast(pszBlock), reinterpret_cast(pszSet)); - } - - static int __stdcall StringSpanExcluding(LPCSTR pszBlock, LPCSTR pszSet) - { - return (int)_mbscspn(reinterpret_cast(pszBlock), reinterpret_cast(pszSet)); - } - - static LPSTR __stdcall StringUppercase(LPSTR psz) - { - CharUpperBuffA(psz, (DWORD)strlen(psz)); - return psz; - } - - static LPSTR __stdcall StringLowercase(LPSTR psz) - { - CharLowerBuffA(psz, (DWORD)strlen(psz)); - return psz; - } - - static LPSTR __stdcall StringUppercase(LPSTR psz, size_t size) - { - CharUpperBuffA(psz, (DWORD)size); - return psz; - } - - static LPSTR __stdcall StringLowercase(LPSTR psz, size_t size) - { - CharLowerBuffA(psz, (DWORD)size); - return psz; - } - - static LPSTR __stdcall StringReverse(LPSTR psz) - { - return reinterpret_cast(_mbsrev(reinterpret_cast(psz))); - } - - static int __stdcall GetFormattedLength(_Printf_format_string_ LPCSTR pszFormat, va_list args) - { - return _vscprintf(pszFormat, args); - } - - static int __stdcall Format(LPSTR pszBuffer, size_t nlength, _Printf_format_string_ LPCSTR pszFormat, va_list args) - { - return vsprintf_s(pszBuffer, nlength, pszFormat, args); - } - - static int __stdcall GetBaseTypeLength(LPCSTR pszSrc) - { - // Returns required buffer length in XCHARs - return int(strlen(pszSrc)); - } - - static int __stdcall GetBaseTypeLength(LPCSTR pszSrc, int nLength) - { - (void)pszSrc; - // Returns required buffer length in XCHARs - return nLength; - } - - static int __stdcall GetBaseTypeLength(LPCWSTR pszSource) - { - // Returns required buffer length in XCHARs - return ::WideCharToMultiByte(Langpack_GetDefaultCodePage(), 0, pszSource, -1, NULL, 0, NULL, NULL) - 1; - } - - static int __stdcall GetBaseTypeLength(LPCWSTR pszSource, int nLength) - { - // Returns required buffer length in XCHARs - return ::WideCharToMultiByte(Langpack_GetDefaultCodePage(), 0, pszSource, nLength, NULL, 0, NULL, NULL); - } - - static void __stdcall ConvertToBaseType(LPSTR pszDest, int nDestLength, LPCSTR pszSrc, int nSrcLength = -1) - { - if (nSrcLength == -1) { nSrcLength = 1 + GetBaseTypeLength(pszSrc); } - // nLen is in XCHARs - memcpy_s(pszDest, nDestLength*sizeof(char), pszSrc, nSrcLength*sizeof(char)); - } - - static void __stdcall ConvertToBaseType(LPSTR pszDest, int nDestLength, LPCWSTR pszSrc, int nSrcLength = -1) - { - // nLen is in XCHARs - ::WideCharToMultiByte(Langpack_GetDefaultCodePage(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL); - } - - static void ConvertToOem(_CharType* pstrString) - { - BOOL fSuccess = ::CharToOemA(pstrString, pstrString); - } - - static void ConvertToAnsi(_CharType* pstrString) - { - BOOL fSuccess = ::OemToCharA(pstrString, pstrString); - } - - static void ConvertToOem(_CharType* pstrString, size_t size) - { - DWORD dwSize = static_cast(size); - ::CharToOemBuffA(pstrString, pstrString, dwSize); - } - - static void ConvertToAnsi(_CharType* pstrString, size_t size) - { - DWORD dwSize = static_cast(size); - ::OemToCharBuffA(pstrString, pstrString, dwSize); - } - - static void __stdcall FloodCharacters(char ch, int nLength, char* pch) - { - // nLength is in XCHARs - memset(pch, ch, nLength); - } - - static int __stdcall SafeStringLen(LPCSTR psz) - { - // returns length in bytes - return (psz != NULL) ? int(strlen(psz)) : 0; - } - - static int __stdcall SafeStringLen(LPCWSTR psz) - { - // returns length in wchar_ts - return (psz != NULL) ? int(wcslen(psz)) : 0; - } - - static int __stdcall GetCharLen(const wchar_t* pch) - { - // returns char length - return 1; - } - - static int __stdcall GetCharLen(const char* pch) - { - // returns char length - return int(_mbclen(reinterpret_cast(pch))); - } - - static DWORD __stdcall GetEnvironmentVariable(LPCSTR pszVar, LPSTR pszBuffer, DWORD dwSize) - { - return ::GetEnvironmentVariableA(pszVar, pszBuffer, dwSize); - } - - static char* MirCopy(const char *pstrString, size_t size) - { - return mir_strndup(pstrString, size); - } -}; - -// specialization for wchar_t -template<> -class ChTraitsCRT< wchar_t > : public ChTraitsBase< wchar_t > -{ - static DWORD __stdcall _GetEnvironmentVariableW(LPCWSTR pszName, LPWSTR pszBuffer, DWORD nSize) - { - return ::GetEnvironmentVariableW(pszName, pszBuffer, nSize); - } - -public: - static LPWSTR __stdcall CharNext(LPCWSTR psz) - { - return const_cast< LPWSTR >(psz+1); - } - - static int __stdcall IsDigit(wchar_t ch) - { - return iswdigit(static_cast(ch)); - } - - static int __stdcall IsSpace(wchar_t ch) - { - return iswspace(static_cast(ch)); - } - - static int __stdcall StringCompare(LPCWSTR pszA, LPCWSTR pszB) - { - return wcscmp(pszA, pszB); - } - - static int __stdcall StringCompareIgnore(LPCWSTR pszA, LPCWSTR pszB) - { - return _wcsicmp(pszA, pszB); - } - - static int __stdcall StringCollate(LPCWSTR pszA, LPCWSTR pszB) - { - return wcscoll(pszA, pszB); - } - - static int __stdcall StringCollateIgnore(LPCWSTR pszA, LPCWSTR pszB) - { - return _wcsicoll(pszA, pszB); - } - - static LPCWSTR __stdcall StringFindString(LPCWSTR pszBlock, LPCWSTR pszMatch) - { - return wcsstr(pszBlock, pszMatch); - } - - static LPWSTR __stdcall StringFindString(LPWSTR pszBlock, LPCWSTR pszMatch) - { - return const_cast< LPWSTR >(StringFindString(const_cast< LPCWSTR >(pszBlock), pszMatch)); - } - - static LPCWSTR __stdcall StringFindChar(LPCWSTR pszBlock, wchar_t chMatch) - { - return wcschr(pszBlock, chMatch); - } - - static LPCWSTR __stdcall StringFindCharRev(LPCWSTR psz, wchar_t ch) - { - return wcsrchr(psz, ch); - } - - static LPCWSTR __stdcall StringScanSet(LPCWSTR pszBlock, LPCWSTR pszMatch) - { - return wcspbrk(pszBlock, pszMatch); - } - - static int __stdcall StringSpanIncluding(LPCWSTR pszBlock, LPCWSTR pszSet) - { - return (int)wcsspn(pszBlock, pszSet); - } - - static int __stdcall StringSpanExcluding(LPCWSTR pszBlock, LPCWSTR pszSet) - { - return (int)wcscspn(pszBlock, pszSet); - } - - static LPWSTR __stdcall StringUppercase(LPWSTR psz) - { - CharUpperBuffW(psz, (DWORD)wcslen(psz)); - return psz; - } - - static LPWSTR __stdcall StringLowercase(LPWSTR psz) - { - CharLowerBuffW(psz, (DWORD)wcslen(psz)); - return psz; - } - - static LPWSTR __stdcall StringUppercase(LPWSTR psz, size_t len) - { - CharUpperBuffW(psz, (DWORD)len); - return psz; - } - - static LPWSTR __stdcall StringLowercase(LPWSTR psz, size_t len) - { - CharLowerBuffW(psz, (DWORD)len); - return psz; - } - - static LPWSTR __stdcall StringReverse(LPWSTR psz) - { - return _wcsrev(psz); - } - - static int __stdcall GetFormattedLength(_Printf_format_string_ LPCWSTR pszFormat, va_list args) - { - return _vscwprintf(pszFormat, args); - } - - static int __stdcall Format(LPWSTR pszBuffer, _Printf_format_string_ LPCWSTR pszFormat, va_list args) - { - #pragma warning(push) - #pragma warning(disable : 4996) - return vswprintf(pszBuffer, pszFormat, args); - #pragma warning(pop) - } - - static int __stdcall Format(LPWSTR pszBuffer, size_t nLength, _Printf_format_string_ LPCWSTR pszFormat, va_list args) - { - #pragma warning(push) - #pragma warning(disable : 4996) - return _vsnwprintf(pszBuffer, nLength, pszFormat, args); - #pragma warning(pop) - } - - static int __stdcall GetBaseTypeLength(LPCSTR pszSrc) - { - // Returns required buffer size in wchar_ts - return ::MultiByteToWideChar(CP_ACP, 0, pszSrc, -1, nullptr, 0)-1; - } - - static int __stdcall GetBaseTypeLength(LPCSTR pszSrc, int nLength) - { - // Returns required buffer size in wchar_ts - return ::MultiByteToWideChar(CP_ACP, 0, pszSrc, nLength, nullptr, 0); - } - - static int __stdcall GetBaseTypeLength(LPCWSTR pszSrc) - { - // Returns required buffer size in wchar_ts - return (int)wcslen(pszSrc); - } - - static int __stdcall GetBaseTypeLength(LPCWSTR pszSrc, int nLength) - { - (void)pszSrc; - // Returns required buffer size in wchar_ts - return nLength; - } - - static void __stdcall ConvertToBaseType(LPWSTR pszDest, int nDestLength, LPCSTR pszSrc, int nSrcLength = -1) - { - // nLen is in wchar_ts - ::MultiByteToWideChar(CP_ACP, 0, pszSrc, nSrcLength, pszDest, nDestLength); - } - - static void __stdcall ConvertToBaseType(LPWSTR pszDest, int nDestLength, LPCWSTR pszSrc, int nSrcLength = -1) - { - if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); } - // nLen is in wchar_ts - #if _MSC_VER >= 1400 - wmemcpy_s(pszDest, nDestLength, pszSrc, nSrcLength); - #else - wmemcpy(pszDest, pszSrc, nDestLength); - #endif - } - - static void __stdcall FloodCharacters(wchar_t ch, int nLength, LPWSTR psz) - { - // nLength is in XCHARs - for (int i = 0; i < nLength; i++) - { - psz[i] = ch; - } - } - - static int __stdcall SafeStringLen(LPCSTR psz) - { - // returns length in bytes - return (psz != nullptr) ? (int)strlen(psz) : 0; - } - - static int __stdcall SafeStringLen(LPCWSTR psz) - { - // returns length in wchar_ts - return (psz != nullptr) ? (int)wcslen(psz) : 0; - } - - static int __stdcall GetCharLen(const wchar_t* pch) - { - (void)pch; - // returns char length - return 1; - } - - static int __stdcall GetCharLen(const char* pch) - { - // returns char length - return (int)(_mbclen(reinterpret_cast< const unsigned char* >(pch))); - } - - static DWORD __stdcall GetEnvironmentVariable(LPCWSTR pszVar, LPWSTR pszBuffer, DWORD dwSize) - { - return _GetEnvironmentVariableW(pszVar, pszBuffer, dwSize); - } - - static void __stdcall ConvertToOem(LPWSTR /*psz*/) - { - } - - static void __stdcall ConvertToAnsi(LPWSTR /*psz*/) - { - } - - static void __stdcall ConvertToOem(LPWSTR /*psz*/, size_t) - { - } - - static void __stdcall ConvertToAnsi(LPWSTR /*psz*/, size_t) - { - } - - static LPWSTR MirCopy(LPCWSTR pstrString, size_t size) - { - return mir_wstrndup(pstrString, size); - } -}; - -template< typename BaseType, class StringTraits > -class MIR_CORE_EXPORT CMStringT : public CMSimpleStringT< BaseType > -{ -public: - typedef CMSimpleStringT< BaseType> CThisSimpleString; - typedef typename CThisSimpleString::XCHAR XCHAR; - typedef typename CThisSimpleString::PXSTR PXSTR; - typedef typename CThisSimpleString::PCXSTR PCXSTR; - typedef typename CThisSimpleString::YCHAR YCHAR; - typedef typename CThisSimpleString::PYSTR PYSTR; - typedef typename CThisSimpleString::PCYSTR PCYSTR; - -public: - CMStringT(); - - // Copy constructor - CMStringT(const CMStringT& strSrc); - - CMStringT(const XCHAR* pszSrc); - CMStringT(CMStringDataFormat, _Printf_format_string_ const XCHAR* pszFormat, ...); - - CMStringT(const YCHAR* pszSrc); - CMStringT(const unsigned char* pszSrc); - - CMStringT(char ch, int nLength = 1); - CMStringT(wchar_t ch, int nLength = 1); - - CMStringT(const XCHAR* pch, int nLength); - CMStringT(const YCHAR* pch, int nLength); - - // Destructor - ~CMStringT(); - - // Assignment operators - CMStringT& operator=(const CMStringT& strSrc); - CMStringT& operator=(PCXSTR pszSrc); - CMStringT& operator=(PCYSTR pszSrc); - CMStringT& operator=(const unsigned char* pszSrc); - CMStringT& operator=(char ch); - CMStringT& operator=(wchar_t ch); - - CMStringT& operator+=(const CMStringT& str); - CMStringT& operator+=(const CThisSimpleString& str); - CMStringT& operator+=(PCXSTR pszSrc); - CMStringT& operator+=(PCYSTR pszSrc); - CMStringT& operator+=(char ch); - CMStringT& operator+=(unsigned char ch); - CMStringT& operator+=(wchar_t ch); - - // Comparison - - int Compare(PCXSTR psz) const; - int CompareNoCase(PCXSTR psz) const; - int Collate(PCXSTR psz) const; - int CollateNoCase(PCXSTR psz) const; - - // Advanced manipulation - - // Delete 'nCount' characters, starting at index 'iIndex' - int Delete(int iIndex, int nCount = 1); - - // Insert character 'ch' before index 'iIndex' - int Insert(int iIndex, XCHAR ch); - - // Insert string 'psz' before index 'iIndex' - int Insert(int iIndex, PCXSTR psz); - - // Replace all occurrences of character 'chOld' with character 'chNew' - int Replace(XCHAR chOld, XCHAR chNew); - - // Replace all occurrences of string 'pszOld' with string 'pszNew' - int Replace(PCXSTR pszOld, PCXSTR pszNew); - - // Remove all occurrences of character 'chRemove' - int Remove(XCHAR chRemove); - - CMStringT Tokenize(PCXSTR pszTokens, int& iStart) const; - - // find routines - - // Find the first occurrence of character 'ch', starting at index 'iStart' - int Find(XCHAR ch, int iStart = 0) const; - - // look for a specific sub-string - - // Find the first occurrence of string 'pszSub', starting at index 'iStart' - int Find(PCXSTR pszSub, int iStart = 0) const; - - // Find the first occurrence of any of the characters in string 'pszCharSet' - int FindOneOf(PCXSTR pszCharSet) const; - - // Find the last occurrence of character 'ch' - int ReverseFind(XCHAR ch) const; - - // manipulation - - // Convert the string to uppercase - CMStringT& MakeUpper(); - - // Convert the string to lowercase - CMStringT& MakeLower(); - - // Reverse the string - CMStringT& MakeReverse(); - - // trimming - - // Remove all trailing whitespace - CMStringT& TrimRight(); - - // Remove all leading whitespace - CMStringT& TrimLeft(); - - // Remove all leading and trailing whitespace - CMStringT& Trim(); - - // Remove all leading and trailing occurrences of character 'chTarget' - CMStringT& Trim(XCHAR chTarget); - - // Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets' - CMStringT& Trim(PCXSTR pszTargets); - - // trimming anything (either side) - - // Remove all trailing occurrences of character 'chTarget' - CMStringT& TrimRight(XCHAR chTarget); - - // Remove all trailing occurrences of any of the characters in string 'pszTargets' - CMStringT& TrimRight(PCXSTR pszTargets); - - // Remove all leading occurrences of character 'chTarget' - CMStringT& TrimLeft(XCHAR chTarget); - - // Remove all leading occurrences of any of the characters in string 'pszTargets' - CMStringT& TrimLeft(PCXSTR pszTargets); - - // Convert the string to the OEM character set - void AnsiToOem(); - - // Convert the string to the ANSI character set - void OemToAnsi(); - - // Very simple sub-string extraction - - // Return the substring starting at index 'iFirst' - CMStringT Mid(int iFirst) const; - - // Return the substring starting at index 'iFirst', with length 'nCount' - CMStringT Mid(int iFirst, int nCount) const; - - // Return the substring consisting of the rightmost 'nCount' characters - CMStringT Right(int nCount) const; - - // Return the substring consisting of the leftmost 'nCount' characters - CMStringT Left(int nCount) const; - - // Return the substring consisting of the leftmost characters in the set 'pszCharSet' - CMStringT SpanIncluding(PCXSTR pszCharSet) const; - - // Return the substring consisting of the leftmost characters not in the set 'pszCharSet' - CMStringT SpanExcluding(PCXSTR pszCharSet) const; - - // Format data using format string 'pszFormat' - PCXSTR Format(PCXSTR _Printf_format_string_ pszFormat, ...); - PCXSTR FormatV(PCXSTR _Printf_format_string_ pszFormat, va_list args); - - // Append formatted data using format string 'pszFormat' - PCXSTR AppendFormat(PCXSTR _Printf_format_string_ pszFormat, ...); - void AppendFormatV(PCXSTR _Printf_format_string_ pszFormat, va_list args); - - // return a copy of string to be freed by mir_free() - PXSTR Detach() const; - - // Set the string to the value of environment variable 'pszVar' - BOOL GetEnvironmentVariable(PCXSTR pszVar); - - friend bool __forceinline operator==(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) == 0; } - friend bool __forceinline operator==(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) == 0; } - friend bool __forceinline operator==(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) == 0; } - friend bool __forceinline operator==(const CMStringT& str1, PCYSTR psz2) { return str1 == CMStringT(psz2); } - friend bool __forceinline operator==(PCYSTR psz1, const CMStringT& str2) { return CMStringT(psz1) == str2; } - - friend bool __forceinline operator!=(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) != 0; } - friend bool __forceinline operator!=(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) != 0; } - friend bool __forceinline operator!=(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) != 0; } - friend bool __forceinline operator!=(const CMStringT& str1, PCYSTR psz2) { return str1 != CMStringT(psz2); } - friend bool __forceinline operator!=(PCYSTR psz1, const CMStringT& str2) { return CMStringT(psz1) != str2; } - - friend bool __forceinline operator<(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) < 0; } - friend bool __forceinline operator<(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) < 0; } - friend bool __forceinline operator<(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) > 0; } - - friend bool __forceinline operator>(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) > 0; } - friend bool __forceinline operator>(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) > 0; } - friend bool __forceinline operator>(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) < 0; } - - friend bool __forceinline operator<=(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) <= 0; } - friend bool __forceinline operator<=(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) <= 0; } - friend bool __forceinline operator<=(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) >= 0; } - - friend bool __forceinline operator>=(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) >= 0; } - friend bool __forceinline operator>=(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) >= 0; } - friend bool __forceinline operator>=(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) <= 0; } - - friend bool __forceinline operator==(XCHAR ch1, const CMStringT& str2) { return (str2.GetLength() == 1) && (str2[0] == ch1); } - friend bool __forceinline operator==(const CMStringT& str1, XCHAR ch2) { return (str1.GetLength() == 1) && (str1[0] == ch2); } - - friend bool __forceinline operator!=(XCHAR ch1, const CMStringT& str2) { return (str2.GetLength() != 1) || (str2[0] != ch1); } - friend bool __forceinline operator!=(const CMStringT& str1, XCHAR ch2) { return (str1.GetLength() != 1) || (str1[0] != ch2); } -}; - -template< typename BaseType, class StringTraits > -MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, const CMStringT& str2); - -template< typename BaseType, class StringTraits > -MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, typename CMStringT::PCXSTR psz2); - -template< typename BaseType, class StringTraits > -MIR_CORE_EXPORT CMStringT CALLBACK operator+(typename CMStringT::PCXSTR psz1, const CMStringT& str2); - -template< typename BaseType, class StringTraits > -MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, wchar_t ch2); - -template< typename BaseType, class StringTraits > -MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, char ch2); - -template< typename BaseType, class StringTraits > -MIR_CORE_EXPORT CMStringT CALLBACK operator + (wchar_t ch1, const CMStringT& str2); - -template< typename BaseType, class StringTraits > -MIR_CORE_EXPORT CMStringT CALLBACK operator+(char ch1, const CMStringT& str2); - -typedef CMStringT< wchar_t, ChTraitsCRT< wchar_t > > CMStringW; -typedef CMStringT< char, ChTraitsCRT< char > > CMStringA; - -#endif // M_STRING_H__ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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. +*/ + +#pragma once + +#ifndef M_STRING_H__ +#define M_STRING_H__ + +#include +#include + +#ifdef _WINDOWS +#include +#endif // _WINDOWS +#include + +#include + +#ifdef __MINGW32__ +#include + +__inline size_t strnlen(const char *string, size_t maxlen) +{ + const char *end = (const char *)memchr ((const void *)string, '\0', maxlen); + return end ? (size_t) (end - string) : maxlen; +} +__inline size_t wcsnlen(const wchar_t *string, size_t maxlen) +{ + const wchar_t *end = wmemchr (string, L'\0', maxlen); + return end ? (size_t) (end - string) : maxlen; +} + +/* FIXME: This may be wrong assumption about Langpack_GetDefaultCodePage */ +#define Langpack_GetDefaultCodePage() CP_THREAD_ACP +/* FIXME: This is unsafe */ +#define memcpy_s(dest,size,src,count) memcpy(dest,src,count) +/* FIXME: This is quite silly implementation of _mbsstr */ +#define _mbsstr(str,search) strstr((const char *)str,(const char *)search) +#define __max(x,y) (((x)<(y))?(y):(x)) +#endif /* __MINGW32__ */ + +///////////////////////////////////////////////////////////////////////////////////////// + +struct CMStringData; + +MIR_CORE_DLL(CMStringData*) mirstr_allocate(int nChars, int nCharSize); +MIR_CORE_DLL(void) mirstr_free(CMStringData *pData); +MIR_CORE_DLL(CMStringData*) mirstr_realloc(CMStringData* pData, int nChars, int nCharSize); +MIR_CORE_DLL(CMStringData*) mirstr_getNil(); + +MIR_CORE_DLL(void) mirstr_lock(CMStringData* pThis); +MIR_CORE_DLL(void) mirstr_release(CMStringData* pThis); +MIR_CORE_DLL(void) mirstr_unlock(CMStringData* pThis); + +///////////////////////////////////////////////////////////////////////////////////////// + +enum CMStringDataFormat { FORMAT }; + +struct CMStringData +{ + int nDataLength; // Length of currently used data in XCHARs (not including terminating null) + int nAllocLength; // Length of allocated data in XCHARs (not including terminating null) + long nRefs; // Reference count: negative == locked + + __forceinline void* data() { return (this + 1); } + __forceinline void AddRef() { InterlockedIncrement(&nRefs); } + __forceinline bool IsLocked() const { return nRefs < 0; } + __forceinline bool IsShared() const { return nRefs > 1; } + + __forceinline void Lock() { mirstr_lock(this); } + __forceinline void Release() { mirstr_release(this); } + __forceinline void Unlock() { mirstr_unlock(this); } +}; + +template< typename BaseType = char > +class ChTraitsBase +{ +public: + typedef char XCHAR; + typedef LPSTR PXSTR; + typedef LPCSTR PCXSTR; + typedef wchar_t YCHAR; + typedef LPWSTR PYSTR; + typedef LPCWSTR PCYSTR; +}; + +template<> +class ChTraitsBase< wchar_t > +{ +public: + typedef wchar_t XCHAR; + typedef LPWSTR PXSTR; + typedef LPCWSTR PCXSTR; + typedef char YCHAR; + typedef LPSTR PYSTR; + typedef LPCSTR PCYSTR; +}; + +template< typename BaseType > +class CMSimpleStringT +{ +public: + typedef typename ChTraitsBase< BaseType >::XCHAR XCHAR; + typedef typename ChTraitsBase< BaseType >::PXSTR PXSTR; + typedef typename ChTraitsBase< BaseType >::PCXSTR PCXSTR; + typedef typename ChTraitsBase< BaseType >::YCHAR YCHAR; + typedef typename ChTraitsBase< BaseType >::PYSTR PYSTR; + typedef typename ChTraitsBase< BaseType >::PCYSTR PCYSTR; + +public: + explicit CMSimpleStringT(); + + CMSimpleStringT(const CMSimpleStringT& strSrc); + CMSimpleStringT(PCXSTR pszSrc); + CMSimpleStringT(const XCHAR* pchSrc, int nLength); + ~CMSimpleStringT(); + + __forceinline operator CMSimpleStringT&() + { return *(CMSimpleStringT*)this; + } + + CMSimpleStringT& operator=(const CMSimpleStringT& strSrc); + + __forceinline CMSimpleStringT& operator=(PCXSTR pszSrc) + { SetString(pszSrc); + return *this; + } + + __forceinline CMSimpleStringT& operator+=(const CMSimpleStringT& strSrc) + { Append(strSrc); + return *this; + } + + __forceinline CMSimpleStringT& operator+=(PCXSTR pszSrc) + { Append(pszSrc); + return *this; + } + + __forceinline CMSimpleStringT& operator+=(char ch) + { AppendChar(XCHAR(ch)); + return *this; + } + + __forceinline CMSimpleStringT& operator+=(unsigned char ch) + { AppendChar(XCHAR(ch)); + return *this; + } + + __forceinline CMSimpleStringT& operator+=(wchar_t ch) + { AppendChar(XCHAR(ch)); + return *this; + } + + __forceinline XCHAR operator[](int iChar) const + { return m_pszData[iChar]; + } + + __forceinline operator PCXSTR() const + { return m_pszData; + } + + __forceinline PCXSTR c_str() const + { return m_pszData; + } + + __forceinline int GetAllocLength() const + { return GetData()->nAllocLength; + } + + __forceinline XCHAR GetAt(int iChar) const + { return m_pszData[iChar]; + } + + __forceinline PXSTR GetBuffer(int nMinBufferLength) + { return PrepareWrite(nMinBufferLength); + } + + __forceinline int GetLength() const + { return GetData()->nDataLength; + } + + __forceinline PCXSTR GetString() const + { return m_pszData; + } + + __forceinline PCXSTR GetTail() const + { return m_pszData + GetData()->nDataLength; + } + + __forceinline bool IsEmpty() const + { return GetLength() == 0; + } + + __forceinline void Preallocate(int nLength) + { PrepareWrite(nLength); + } + + __forceinline void ReleaseBufferSetLength(int nNewLength) + { SetLength(nNewLength); + } + + void Append(PCXSTR pszSrc); + void Append(PCXSTR pszSrc, int nLength); + void AppendChar(XCHAR ch); + void Append(const CMSimpleStringT& strSrc); + + void Empty(); + void FreeExtra(); + + PXSTR GetBuffer(); + PXSTR GetBufferSetLength(int nLength); + + PXSTR LockBuffer(); + void UnlockBuffer(); + + void ReleaseBuffer(int nNewLength = -1); + + void Truncate(int nNewLength); + void SetAt(int iChar, XCHAR ch); + void SetString(PCXSTR pszSrc); + void SetString(PCXSTR pszSrc, int nLength); + +public: + friend CMSimpleStringT operator+(const CMSimpleStringT& str1, const CMSimpleStringT& str2); + friend CMSimpleStringT operator+(const CMSimpleStringT& str1, PCXSTR psz2); + friend CMSimpleStringT operator+(PCXSTR psz1, const CMSimpleStringT& str2); + + static void MIR_SYSCALL CopyChars(XCHAR* pchDest, const XCHAR* pchSrc, int nChars); + static void MIR_SYSCALL CopyChars(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars); + static void MIR_SYSCALL CopyCharsOverlapped(XCHAR* pchDest, const XCHAR* pchSrc, int nChars); + static void MIR_SYSCALL CopyCharsOverlapped(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars); + static int MIR_SYSCALL StringLength(const char* psz); + static int MIR_SYSCALL StringLength(const wchar_t* psz); + static int MIR_SYSCALL StringLengthN(const char* psz, size_t sizeInXChar); + static int MIR_SYSCALL StringLengthN(const wchar_t* psz, size_t sizeInXChar); + static void MIR_SYSCALL Concatenate(CMSimpleStringT& strResult, PCXSTR psz1, int nLength1, PCXSTR psz2, int nLength2); + + // Implementation +private: + __forceinline CMStringData* GetData() const + { return (reinterpret_cast(m_pszData)-1); + } + + void Attach(CMStringData* pData); + void Fork(int nLength); + PXSTR PrepareWrite(int nLength); + void PrepareWrite2(int nLength); + void Reallocate(int nLength); + void SetLength(int nLength); + static CMStringData* MIR_SYSCALL CloneData(CMStringData* pData); + +private: + PXSTR m_pszData; +}; + + +template< typename _CharType = char > +class ChTraitsCRT : public ChTraitsBase < _CharType > +{ +public: + static char* MIR_SYSCALL CharNext(const char* p) + { + return reinterpret_cast(_mbsinc(reinterpret_cast(p))); + } + + static int MIR_SYSCALL IsDigit(char ch) + { + return _ismbcdigit(ch); + } + + static int MIR_SYSCALL IsSpace(char ch) + { + return _ismbcspace(ch); + } + + static int MIR_SYSCALL StringCompare(LPCSTR pszA, LPCSTR pszB) + { + return _mbscmp(reinterpret_cast(pszA), reinterpret_cast(pszB)); + } + + static int MIR_SYSCALL StringCompareIgnore(LPCSTR pszA, LPCSTR pszB) + { + return _mbsicmp(reinterpret_cast(pszA), reinterpret_cast(pszB)); + } + + static int MIR_SYSCALL StringCollate(LPCSTR pszA, LPCSTR pszB) + { + return _mbscoll(reinterpret_cast(pszA), reinterpret_cast(pszB)); + } + + static int MIR_SYSCALL StringCollateIgnore(LPCSTR pszA, LPCSTR pszB) + { + return _mbsicoll(reinterpret_cast(pszA), reinterpret_cast(pszB)); + } + + static LPCSTR MIR_SYSCALL StringFindString(LPCSTR pszBlock, LPCSTR pszMatch) + { + return reinterpret_cast(_mbsstr(reinterpret_cast(pszBlock), + reinterpret_cast(pszMatch))); + } + + static LPSTR MIR_SYSCALL StringFindString(LPSTR pszBlock, LPCSTR pszMatch) + { + return const_cast(StringFindString(const_cast(pszBlock), pszMatch)); + } + + static LPCSTR MIR_SYSCALL StringFindChar(LPCSTR pszBlock, char chMatch) + { + return reinterpret_cast(_mbschr(reinterpret_cast(pszBlock), (unsigned char)chMatch)); + } + + static LPCSTR MIR_SYSCALL StringFindCharRev(LPCSTR psz, char ch) + { + return reinterpret_cast(_mbsrchr(reinterpret_cast(psz), (unsigned char)ch)); + } + + static LPCSTR MIR_SYSCALL StringScanSet(LPCSTR pszBlock, LPCSTR pszMatch) + { + return reinterpret_cast(_mbspbrk(reinterpret_cast(pszBlock), + reinterpret_cast(pszMatch))); + } + + static int MIR_SYSCALL StringSpanIncluding(LPCSTR pszBlock, LPCSTR pszSet) + { + return (int)_mbsspn(reinterpret_cast(pszBlock), reinterpret_cast(pszSet)); + } + + static int MIR_SYSCALL StringSpanExcluding(LPCSTR pszBlock, LPCSTR pszSet) + { + return (int)_mbscspn(reinterpret_cast(pszBlock), reinterpret_cast(pszSet)); + } + + static LPSTR MIR_SYSCALL StringUppercase(LPSTR psz) + { + CharUpperBuffA(psz, (DWORD)strlen(psz)); + return psz; + } + + static LPSTR MIR_SYSCALL StringLowercase(LPSTR psz) + { + CharLowerBuffA(psz, (DWORD)strlen(psz)); + return psz; + } + + static LPSTR MIR_SYSCALL StringUppercase(LPSTR psz, size_t size) + { + CharUpperBuffA(psz, (DWORD)size); + return psz; + } + + static LPSTR MIR_SYSCALL StringLowercase(LPSTR psz, size_t size) + { + CharLowerBuffA(psz, (DWORD)size); + return psz; + } + + static LPSTR MIR_SYSCALL StringReverse(LPSTR psz) + { + return reinterpret_cast(_mbsrev(reinterpret_cast(psz))); + } + + static int MIR_SYSCALL GetFormattedLength(_Printf_format_string_ LPCSTR pszFormat, va_list args) + { + return _vscprintf(pszFormat, args); + } + + static int MIR_SYSCALL Format(LPSTR pszBuffer, size_t nlength, _Printf_format_string_ LPCSTR pszFormat, va_list args) + { + return vsprintf_s(pszBuffer, nlength, pszFormat, args); + } + + static int MIR_SYSCALL GetBaseTypeLength(LPCSTR pszSrc) + { + // Returns required buffer length in XCHARs + return int(strlen(pszSrc)); + } + + static int MIR_SYSCALL GetBaseTypeLength(LPCSTR pszSrc, int nLength) + { + (void)pszSrc; + // Returns required buffer length in XCHARs + return nLength; + } + + static int MIR_SYSCALL GetBaseTypeLength(LPCWSTR pszSource) + { + // Returns required buffer length in XCHARs + #ifdef _MSC_VER + return ::WideCharToMultiByte(Langpack_GetDefaultCodePage(), 0, pszSource, -1, NULL, 0, NULL, NULL) - 1; + #else + return 0; + #endif + } + + static int MIR_SYSCALL GetBaseTypeLength(LPCWSTR pszSource, int nLength) + { + // Returns required buffer length in XCHARs + #ifdef _MSC_VER + return ::WideCharToMultiByte(Langpack_GetDefaultCodePage(), 0, pszSource, nLength, NULL, 0, NULL, NULL); + #else + return 0; + #endif + } + + static void MIR_SYSCALL ConvertToBaseType(LPSTR pszDest, int nDestLength, LPCSTR pszSrc, int nSrcLength = -1) + { + if (nSrcLength == -1) { nSrcLength = 1 + GetBaseTypeLength(pszSrc); } + // nLen is in XCHARs + memcpy_s(pszDest, nDestLength*sizeof(char), pszSrc, nSrcLength*sizeof(char)); + } + + static void MIR_SYSCALL ConvertToBaseType(LPSTR pszDest, int nDestLength, LPCWSTR pszSrc, int nSrcLength = -1) + { + // nLen is in XCHARs + #ifdef _MSC_VER + ::WideCharToMultiByte(Langpack_GetDefaultCodePage(), 0, pszSrc, nSrcLength, pszDest, nDestLength, NULL, NULL); + #endif + } + + static void ConvertToOem(_CharType* pstrString) + { + #ifdef _MSC_VER + BOOL fSuccess = ::CharToOemA(pstrString, pstrString); + #endif // _MSC_VER + } + + static void ConvertToAnsi(_CharType* pstrString) + { + #ifdef _MSC_VER + BOOL fSuccess = ::OemToCharA(pstrString, pstrString); + #endif + } + + static void ConvertToOem(_CharType* pstrString, size_t size) + { + #ifdef _MSC_VER + DWORD dwSize = static_cast(size); + ::CharToOemBuffA(pstrString, pstrString, dwSize); + #endif + } + + static void ConvertToAnsi(_CharType* pstrString, size_t size) + { + #ifdef _MSC_VER + DWORD dwSize = static_cast(size); + ::OemToCharBuffA(pstrString, pstrString, dwSize); + #endif + } + + static void MIR_SYSCALL FloodCharacters(char ch, int nLength, char* pch) + { + // nLength is in XCHARs + memset(pch, ch, nLength); + } + + static int MIR_SYSCALL SafeStringLen(LPCSTR psz) + { + // returns length in bytes + return (psz != NULL) ? int(strlen(psz)) : 0; + } + + static int MIR_SYSCALL SafeStringLen(LPCWSTR psz) + { + // returns length in wchar_ts + return (psz != NULL) ? int(wcslen(psz)) : 0; + } + + static int MIR_SYSCALL GetCharLen(const wchar_t* pch) + { + // returns char length + return 1; + } + + static int MIR_SYSCALL GetCharLen(const char* pch) + { + // returns char length + return int(_mbclen(reinterpret_cast(pch))); + } + + static DWORD MIR_SYSCALL GetEnvironmentVariable(LPCSTR pszVar, LPSTR pszBuffer, DWORD dwSize) + { + #ifdef _MSC_VER + return ::GetEnvironmentVariableA(pszVar, pszBuffer, dwSize); + #endif // _MSC_VER + } + + static char* MirCopy(const char *pstrString, size_t size) + { + return mir_strndup(pstrString, size); + } +}; + +// specialization for wchar_t +template<> +class ChTraitsCRT< wchar_t > : public ChTraitsBase< wchar_t > +{ + static DWORD MIR_SYSCALL _GetEnvironmentVariableW(LPCWSTR pszName, LPWSTR pszBuffer, DWORD nSize) + { + #ifdef _MSC_VER + return ::GetEnvironmentVariableW(pszName, pszBuffer, nSize); + #endif // _MSC_VER + } + +public: + static LPWSTR MIR_SYSCALL CharNext(LPCWSTR psz) + { + return const_cast< LPWSTR >(psz+1); + } + + static int MIR_SYSCALL IsDigit(wchar_t ch) + { + #ifdef _MSC_VER + return iswdigit(static_cast(ch)); + #else + return 0; + #endif + } + + static int MIR_SYSCALL IsSpace(wchar_t ch) + { + #ifdef _MSC_VER + return iswspace(static_cast(ch)); + #else + return 0; + #endif + } + + static int MIR_SYSCALL StringCompare(LPCWSTR pszA, LPCWSTR pszB) + { + return wcscmp(pszA, pszB); + } + + static int MIR_SYSCALL StringCompareIgnore(LPCWSTR pszA, LPCWSTR pszB) + { + #ifdef _MSC_VER + return _wcsicmp(pszA, pszB); + #else + return 0; + #endif + } + + static int MIR_SYSCALL StringCollate(LPCWSTR pszA, LPCWSTR pszB) + { + return wcscoll(pszA, pszB); + } + + static int MIR_SYSCALL StringCollateIgnore(LPCWSTR pszA, LPCWSTR pszB) + { + #ifdef _MSC_VER + return _wcsicoll(pszA, pszB); + #else + return 0; + #endif + } + + static LPCWSTR MIR_SYSCALL StringFindString(LPCWSTR pszBlock, LPCWSTR pszMatch) + { + return wcsstr(pszBlock, pszMatch); + } + + static LPWSTR MIR_SYSCALL StringFindString(LPWSTR pszBlock, LPCWSTR pszMatch) + { + return const_cast< LPWSTR >(StringFindString(const_cast< LPCWSTR >(pszBlock), pszMatch)); + } + + static LPCWSTR MIR_SYSCALL StringFindChar(LPCWSTR pszBlock, wchar_t chMatch) + { + return wcschr(pszBlock, chMatch); + } + + static LPCWSTR MIR_SYSCALL StringFindCharRev(LPCWSTR psz, wchar_t ch) + { + return wcsrchr(psz, ch); + } + + static LPCWSTR MIR_SYSCALL StringScanSet(LPCWSTR pszBlock, LPCWSTR pszMatch) + { + return wcspbrk(pszBlock, pszMatch); + } + + static int MIR_SYSCALL StringSpanIncluding(LPCWSTR pszBlock, LPCWSTR pszSet) + { + return (int)wcsspn(pszBlock, pszSet); + } + + static int MIR_SYSCALL StringSpanExcluding(LPCWSTR pszBlock, LPCWSTR pszSet) + { + return (int)wcscspn(pszBlock, pszSet); + } + + static LPWSTR MIR_SYSCALL StringUppercase(LPWSTR psz) + { + #ifdef _MSC_VER + CharUpperBuffW(psz, (DWORD)wcslen(psz)); + #endif + return psz; + } + + static LPWSTR MIR_SYSCALL StringLowercase(LPWSTR psz) + { + #ifdef _MSC_VER + CharLowerBuffW(psz, (DWORD)wcslen(psz)); + #endif + return psz; + } + + static LPWSTR MIR_SYSCALL StringUppercase(LPWSTR psz, size_t len) + { + #ifdef _MSC_VER + CharUpperBuffW(psz, (DWORD)len); + #endif + return psz; + } + + static LPWSTR MIR_SYSCALL StringLowercase(LPWSTR psz, size_t len) + { + #ifdef _MSC_VER + CharLowerBuffW(psz, (DWORD)len); + #endif + return psz; + } + + static LPWSTR MIR_SYSCALL StringReverse(LPWSTR psz) + { + #ifdef _MSC_VER + return _wcsrev(psz); + #else + return psz; + #endif + } + + static int MIR_SYSCALL GetFormattedLength(_Printf_format_string_ LPCWSTR pszFormat, va_list args) + { + #ifdef _MSC_VER + return _vscwprintf(pszFormat, args); + #else + return 0; + #endif + } + + static int MIR_SYSCALL Format(LPWSTR pszBuffer, _Printf_format_string_ LPCWSTR pszFormat, va_list args) + { + #pragma warning(push) + #pragma warning(disable : 4996) + + #ifdef _MSC_VER + return vswprintf(pszBuffer, pszFormat, args); + #else + return 0; + #endif + #pragma warning(pop) + } + + static int MIR_SYSCALL Format(LPWSTR pszBuffer, size_t nLength, _Printf_format_string_ LPCWSTR pszFormat, va_list args) + { + #pragma warning(push) + #pragma warning(disable : 4996) + + #ifdef _MSC_VER + return _vsnwprintf(pszBuffer, nLength, pszFormat, args); + #else + return 0; + #endif + + #pragma warning(pop) + } + + static int MIR_SYSCALL GetBaseTypeLength(LPCSTR pszSrc) + { + // Returns required buffer size in wchar_ts + #ifdef _MSC_VER + return ::MultiByteToWideChar(CP_ACP, 0, pszSrc, -1, nullptr, 0)-1; + #else + return 0; + #endif + } + + static int MIR_SYSCALL GetBaseTypeLength(LPCSTR pszSrc, int nLength) + { + // Returns required buffer size in wchar_ts + #ifdef _MSC_VER + return ::MultiByteToWideChar(CP_ACP, 0, pszSrc, nLength, nullptr, 0); + #else + return 0; + #endif + } + + static int MIR_SYSCALL GetBaseTypeLength(LPCWSTR pszSrc) + { + // Returns required buffer size in wchar_ts + return (int)wcslen(pszSrc); + } + + static int MIR_SYSCALL GetBaseTypeLength(LPCWSTR pszSrc, int nLength) + { + (void)pszSrc; + // Returns required buffer size in wchar_ts + return nLength; + } + + static void MIR_SYSCALL ConvertToBaseType(LPWSTR pszDest, int nDestLength, LPCSTR pszSrc, int nSrcLength = -1) + { + // nLen is in wchar_ts + #ifdef _MSC_VER + ::MultiByteToWideChar(CP_ACP, 0, pszSrc, nSrcLength, pszDest, nDestLength); + #endif + } + + static void MIR_SYSCALL ConvertToBaseType(LPWSTR pszDest, int nDestLength, LPCWSTR pszSrc, int nSrcLength = -1) + { + if (nSrcLength == -1) { nSrcLength=1 + GetBaseTypeLength(pszSrc); } + // nLen is in wchar_ts + #if _MSC_VER >= 1400 + wmemcpy_s(pszDest, nDestLength, pszSrc, nSrcLength); + #else + wmemcpy(pszDest, pszSrc, nDestLength); + #endif + } + + static void MIR_SYSCALL FloodCharacters(wchar_t ch, int nLength, LPWSTR psz) + { + // nLength is in XCHARs + for (int i = 0; i < nLength; i++) + { + psz[i] = ch; + } + } + + static int MIR_SYSCALL SafeStringLen(LPCSTR psz) + { + // returns length in bytes + return (psz != nullptr) ? (int)strlen(psz) : 0; + } + + static int MIR_SYSCALL SafeStringLen(LPCWSTR psz) + { + // returns length in wchar_ts + return (psz != nullptr) ? (int)wcslen(psz) : 0; + } + + static int MIR_SYSCALL GetCharLen(const wchar_t* pch) + { + (void)pch; + // returns char length + return 1; + } + + static int MIR_SYSCALL GetCharLen(const char* pch) + { + // returns char length + #ifdef _MSC_VER + return (int)(_mbclen(reinterpret_cast< const unsigned char* >(pch))); + #else + return mblen(pch, strlen(pch)); + #endif + } + + static DWORD MIR_SYSCALL GetEnvironmentVariable(LPCWSTR pszVar, LPWSTR pszBuffer, DWORD dwSize) + { + return _GetEnvironmentVariableW(pszVar, pszBuffer, dwSize); + } + + static void MIR_SYSCALL ConvertToOem(LPWSTR /*psz*/) + { + } + + static void MIR_SYSCALL ConvertToAnsi(LPWSTR /*psz*/) + { + } + + static void MIR_SYSCALL ConvertToOem(LPWSTR /*psz*/, size_t) + { + } + + static void MIR_SYSCALL ConvertToAnsi(LPWSTR /*psz*/, size_t) + { + } + + static LPWSTR MirCopy(LPCWSTR pstrString, size_t size) + { + return mir_wstrndup(pstrString, size); + } +}; + +template< typename BaseType, class StringTraits > +class MIR_CORE_EXPORT CMStringT : public CMSimpleStringT< BaseType > +{ +public: + typedef CMSimpleStringT< BaseType> CThisSimpleString; + typedef typename CThisSimpleString::XCHAR XCHAR; + typedef typename CThisSimpleString::PXSTR PXSTR; + typedef typename CThisSimpleString::PCXSTR PCXSTR; + typedef typename CThisSimpleString::YCHAR YCHAR; + typedef typename CThisSimpleString::PYSTR PYSTR; + typedef typename CThisSimpleString::PCYSTR PCYSTR; + +public: + CMStringT(); + + // Copy constructor + CMStringT(const CMStringT& strSrc); + + CMStringT(const XCHAR* pszSrc); + CMStringT(CMStringDataFormat, _Printf_format_string_ const XCHAR* pszFormat, ...); + + CMStringT(const YCHAR* pszSrc); + CMStringT(const unsigned char* pszSrc); + + CMStringT(char ch, int nLength = 1); + CMStringT(wchar_t ch, int nLength = 1); + + CMStringT(const XCHAR* pch, int nLength); + CMStringT(const YCHAR* pch, int nLength); + + // Destructor + ~CMStringT(); + + // Assignment operators + CMStringT& operator=(const CMStringT& strSrc); + CMStringT& operator=(PCXSTR pszSrc); + CMStringT& operator=(PCYSTR pszSrc); + CMStringT& operator=(const unsigned char* pszSrc); + CMStringT& operator=(char ch); + CMStringT& operator=(wchar_t ch); + + CMStringT& operator+=(const CMStringT& str); + CMStringT& operator+=(const CThisSimpleString& str); + CMStringT& operator+=(PCXSTR pszSrc); + CMStringT& operator+=(PCYSTR pszSrc); + CMStringT& operator+=(char ch); + CMStringT& operator+=(unsigned char ch); + CMStringT& operator+=(wchar_t ch); + + // Comparison + + int Compare(PCXSTR psz) const; + int CompareNoCase(PCXSTR psz) const; + int Collate(PCXSTR psz) const; + int CollateNoCase(PCXSTR psz) const; + + // Advanced manipulation + + // Delete 'nCount' characters, starting at index 'iIndex' + int Delete(int iIndex, int nCount = 1); + + // Insert character 'ch' before index 'iIndex' + int Insert(int iIndex, XCHAR ch); + + // Insert string 'psz' before index 'iIndex' + int Insert(int iIndex, PCXSTR psz); + + // Replace all occurrences of character 'chOld' with character 'chNew' + int Replace(XCHAR chOld, XCHAR chNew); + + // Replace all occurrences of string 'pszOld' with string 'pszNew' + int Replace(PCXSTR pszOld, PCXSTR pszNew); + + // Remove all occurrences of character 'chRemove' + int Remove(XCHAR chRemove); + + CMStringT Tokenize(PCXSTR pszTokens, int& iStart) const; + + // find routines + + // Find the first occurrence of character 'ch', starting at index 'iStart' + int Find(XCHAR ch, int iStart = 0) const; + + // look for a specific sub-string + + // Find the first occurrence of string 'pszSub', starting at index 'iStart' + int Find(PCXSTR pszSub, int iStart = 0) const; + + // Find the first occurrence of any of the characters in string 'pszCharSet' + int FindOneOf(PCXSTR pszCharSet) const; + + // Find the last occurrence of character 'ch' + int ReverseFind(XCHAR ch) const; + + // manipulation + + // Convert the string to uppercase + CMStringT& MakeUpper(); + + // Convert the string to lowercase + CMStringT& MakeLower(); + + // Reverse the string + CMStringT& MakeReverse(); + + // trimming + + // Remove all trailing whitespace + CMStringT& TrimRight(); + + // Remove all leading whitespace + CMStringT& TrimLeft(); + + // Remove all leading and trailing whitespace + CMStringT& Trim(); + + // Remove all leading and trailing occurrences of character 'chTarget' + CMStringT& Trim(XCHAR chTarget); + + // Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets' + CMStringT& Trim(PCXSTR pszTargets); + + // trimming anything (either side) + + // Remove all trailing occurrences of character 'chTarget' + CMStringT& TrimRight(XCHAR chTarget); + + // Remove all trailing occurrences of any of the characters in string 'pszTargets' + CMStringT& TrimRight(PCXSTR pszTargets); + + // Remove all leading occurrences of character 'chTarget' + CMStringT& TrimLeft(XCHAR chTarget); + + // Remove all leading occurrences of any of the characters in string 'pszTargets' + CMStringT& TrimLeft(PCXSTR pszTargets); + + // Convert the string to the OEM character set + void AnsiToOem(); + + // Convert the string to the ANSI character set + void OemToAnsi(); + + // Very simple sub-string extraction + + // Return the substring starting at index 'iFirst' + CMStringT Mid(int iFirst) const; + + // Return the substring starting at index 'iFirst', with length 'nCount' + CMStringT Mid(int iFirst, int nCount) const; + + // Return the substring consisting of the rightmost 'nCount' characters + CMStringT Right(int nCount) const; + + // Return the substring consisting of the leftmost 'nCount' characters + CMStringT Left(int nCount) const; + + // Return the substring consisting of the leftmost characters in the set 'pszCharSet' + CMStringT SpanIncluding(PCXSTR pszCharSet) const; + + // Return the substring consisting of the leftmost characters not in the set 'pszCharSet' + CMStringT SpanExcluding(PCXSTR pszCharSet) const; + + // Format data using format string 'pszFormat' + PCXSTR Format(PCXSTR _Printf_format_string_ pszFormat, ...); + PCXSTR FormatV(PCXSTR _Printf_format_string_ pszFormat, va_list args); + + // Append formatted data using format string 'pszFormat' + PCXSTR AppendFormat(PCXSTR _Printf_format_string_ pszFormat, ...); + void AppendFormatV(PCXSTR _Printf_format_string_ pszFormat, va_list args); + + // return a copy of string to be freed by mir_free() + PXSTR Detach() const; + + // Set the string to the value of environment variable 'pszVar' + BOOL GetEnvironmentVariable(PCXSTR pszVar); + + friend bool __forceinline operator==(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) == 0; } + friend bool __forceinline operator==(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) == 0; } + friend bool __forceinline operator==(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) == 0; } + friend bool __forceinline operator==(const CMStringT& str1, PCYSTR psz2) { return str1 == CMStringT(psz2); } + friend bool __forceinline operator==(PCYSTR psz1, const CMStringT& str2) { return CMStringT(psz1) == str2; } + + friend bool __forceinline operator!=(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) != 0; } + friend bool __forceinline operator!=(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) != 0; } + friend bool __forceinline operator!=(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) != 0; } + friend bool __forceinline operator!=(const CMStringT& str1, PCYSTR psz2) { return str1 != CMStringT(psz2); } + friend bool __forceinline operator!=(PCYSTR psz1, const CMStringT& str2) { return CMStringT(psz1) != str2; } + + friend bool __forceinline operator<(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) < 0; } + friend bool __forceinline operator<(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) < 0; } + friend bool __forceinline operator<(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) > 0; } + + friend bool __forceinline operator>(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) > 0; } + friend bool __forceinline operator>(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) > 0; } + friend bool __forceinline operator>(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) < 0; } + + friend bool __forceinline operator<=(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) <= 0; } + friend bool __forceinline operator<=(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) <= 0; } + friend bool __forceinline operator<=(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) >= 0; } + + friend bool __forceinline operator>=(const CMStringT& str1, const CMStringT& str2) { return str1.Compare(str2) >= 0; } + friend bool __forceinline operator>=(const CMStringT& str1, PCXSTR psz2) { return str1.Compare(psz2) >= 0; } + friend bool __forceinline operator>=(PCXSTR psz1, const CMStringT& str2) { return str2.Compare(psz1) <= 0; } + + friend bool __forceinline operator==(XCHAR ch1, const CMStringT& str2) { return (str2.GetLength() == 1) && (str2[0] == ch1); } + friend bool __forceinline operator==(const CMStringT& str1, XCHAR ch2) { return (str1.GetLength() == 1) && (str1[0] == ch2); } + + friend bool __forceinline operator!=(XCHAR ch1, const CMStringT& str2) { return (str2.GetLength() != 1) || (str2[0] != ch1); } + friend bool __forceinline operator!=(const CMStringT& str1, XCHAR ch2) { return (str1.GetLength() != 1) || (str1[0] != ch2); } +}; + +template< typename BaseType, class StringTraits > +MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, const CMStringT& str2); + +template< typename BaseType, class StringTraits > +MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, typename CMStringT::PCXSTR psz2); + +template< typename BaseType, class StringTraits > +MIR_CORE_EXPORT CMStringT CALLBACK operator+(typename CMStringT::PCXSTR psz1, const CMStringT& str2); + +template< typename BaseType, class StringTraits > +MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, wchar_t ch2); + +template< typename BaseType, class StringTraits > +MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, char ch2); + +template< typename BaseType, class StringTraits > +MIR_CORE_EXPORT CMStringT CALLBACK operator + (wchar_t ch1, const CMStringT& str2); + +template< typename BaseType, class StringTraits > +MIR_CORE_EXPORT CMStringT CALLBACK operator+(char ch1, const CMStringT& str2); + +typedef CMStringT< wchar_t, ChTraitsCRT< wchar_t > > CMStringW; +typedef CMStringT< char, ChTraitsCRT< char > > CMStringA; + +#endif // M_STRING_H__ diff --git a/include/m_string.inl b/include/m_string.inl index 78c393e19b..6a4ec0f35b 100644 --- a/include/m_string.inl +++ b/include/m_string.inl @@ -1,1466 +1,1466 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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. -*/ - -#pragma once - -#ifndef M_STRING_INL__ - -template -CMSimpleStringT::CMSimpleStringT() -{ - CMStringData* pData = mirstr_getNil(); - Attach(pData); -} - -template -CMSimpleStringT::CMSimpleStringT(const CMSimpleStringT& strSrc) -{ - CMStringData* pSrcData = strSrc.GetData(); - CMStringData* pNewData = CloneData(pSrcData); - Attach(pNewData); -} - -template -CMSimpleStringT::CMSimpleStringT(PCXSTR pszSrc) -{ - int nLength = StringLength(pszSrc); - CMStringData* pData = mirstr_allocate(nLength, sizeof(XCHAR)); - if (pData != nullptr) { - Attach(pData); - SetLength(nLength); - CopyChars(m_pszData, nLength, pszSrc, nLength); - } -} - -template -CMSimpleStringT::CMSimpleStringT(const XCHAR* pchSrc, int nLength) -{ - CMStringData* pData = mirstr_allocate(nLength, sizeof(XCHAR)); - if (pData != nullptr) { - Attach(pData); - SetLength(nLength); - CopyChars(m_pszData, nLength, pchSrc, nLength); - } -} - -template -CMSimpleStringT::~CMSimpleStringT() -{ - CMStringData* pData = GetData(); - pData->Release(); -} - -template -CMSimpleStringT& CMSimpleStringT::operator=(const CMSimpleStringT& strSrc) -{ - CMStringData* pSrcData = strSrc.GetData(); - CMStringData* pOldData = GetData(); - if (pSrcData != pOldData) { - if (pOldData->IsLocked()) - SetString(strSrc.GetString(), strSrc.GetLength()); - else { - CMStringData* pNewData = CloneData(pSrcData); - pOldData->Release(); - Attach(pNewData); - } - } - - return *this; -} - -template -void CMSimpleStringT::Append(PCXSTR pszSrc) -{ - Append(pszSrc, StringLength(pszSrc)); -} - -template -void CMSimpleStringT::Append(PCXSTR pszSrc, int nLength) -{ - // See comment in SetString() about why we do this - UINT_PTR nOffset = UINT_PTR(pszSrc - GetString()); - - int nOldLength = GetLength(); - if (nOldLength < 0) { - // protects from underflow - nOldLength = 0; - } - - //Make sure we don't read pass end of the terminating NULL - int nSrcLength = StringLength(pszSrc); - nLength = nLength > nSrcLength ? nSrcLength : nLength; - - int nNewLength = nOldLength + nLength; - PXSTR pszBuffer = GetBuffer(nNewLength); - if (nOffset <= UINT_PTR(nOldLength)) { - pszSrc = pszBuffer + nOffset; - // No need to call CopyCharsOverlapped, since the destination is - // beyond the end of the original buffer - } - CopyChars(pszBuffer + nOldLength, nLength, pszSrc, nLength); - ReleaseBufferSetLength(nNewLength); -} - -template -void CMSimpleStringT::AppendChar(XCHAR ch) -{ - UINT nOldLength = GetLength(); - int nNewLength = nOldLength + 1; - PXSTR pszBuffer = GetBuffer(nNewLength); - pszBuffer[nOldLength] = ch; - ReleaseBufferSetLength(nNewLength); -} - -template -void CMSimpleStringT::Append(const CMSimpleStringT& strSrc) -{ - Append(strSrc.GetString(), strSrc.GetLength()); -} - -template -void CMSimpleStringT::Empty() -{ - CMStringData* pOldData = GetData(); - if (pOldData->nDataLength == 0) - return; - - if (pOldData->IsLocked()) { - // Don't reallocate a locked buffer that's shrinking - SetLength(0); - } - else { - pOldData->Release(); - CMStringData* pNewData = mirstr_getNil(); - Attach(pNewData); - } -} - -template -void CMSimpleStringT::FreeExtra() -{ - CMStringData* pOldData = GetData(); - int nLength = pOldData->nDataLength; - if (pOldData->nAllocLength == nLength) - return; - - if (!pOldData->IsLocked()) { // Don't reallocate a locked buffer that's shrinking - CMStringData* pNewData = mirstr_allocate(nLength, sizeof(XCHAR)); - if (pNewData == nullptr) { - SetLength(nLength); - return; - } - - CopyChars(PXSTR(pNewData->data()), nLength, PCXSTR(pOldData->data()), nLength); - - pOldData->Release(); - Attach(pNewData); - SetLength(nLength); - } -} - -template -typename CMSimpleStringT::PXSTR CMSimpleStringT::GetBuffer() -{ - CMStringData* pData = GetData(); - if (pData->IsShared()) - Fork(pData->nDataLength); - - return m_pszData; -} - -template -typename CMSimpleStringT::PXSTR CMSimpleStringT::GetBufferSetLength(int nLength) -{ - PXSTR pszBuffer = GetBuffer(nLength); - SetLength(nLength); - - return pszBuffer; -} - -template -typename CMSimpleStringT::PXSTR CMSimpleStringT::LockBuffer() -{ - CMStringData* pData = GetData(); - if (pData->IsShared()) { - Fork(pData->nDataLength); - pData = GetData(); // Do it again, because the fork might have changed it - } - pData->Lock(); - - return m_pszData; -} - -template -void CMSimpleStringT::UnlockBuffer() -{ - CMStringData* pData = GetData(); - pData->Unlock(); -} - -template -void CMSimpleStringT::ReleaseBuffer(int nNewLength) -{ - if (nNewLength == -1) { - int nAlloc = GetData()->nAllocLength; - nNewLength = StringLengthN(m_pszData, nAlloc); - } - SetLength(nNewLength); -} - -template -void CMSimpleStringT::Truncate(int nNewLength) -{ - GetBuffer(nNewLength); - ReleaseBufferSetLength(nNewLength); -} - -template -void CMSimpleStringT::SetAt(int iChar, XCHAR ch) -{ - int nLength = GetLength(); - PXSTR pszBuffer = GetBuffer(); - pszBuffer[iChar] = ch; - ReleaseBufferSetLength(nLength); - -} - -template -void CMSimpleStringT::SetString(PCXSTR pszSrc) -{ - SetString(pszSrc, StringLength(pszSrc)); -} - -template -void CMSimpleStringT::SetString(PCXSTR pszSrc, int nLength) -{ - if (nLength == 0) - Empty(); - else { - UINT nOldLength = GetLength(); - UINT_PTR nOffset = pszSrc - GetString(); - - PXSTR pszBuffer = GetBuffer(nLength); - if (nOffset <= nOldLength) - CopyCharsOverlapped(pszBuffer, GetAllocLength(), pszBuffer + nOffset, nLength); - else - CopyChars(pszBuffer, GetAllocLength(), pszSrc, nLength); - - ReleaseBufferSetLength(nLength); - } -} - -template -typename CMSimpleStringT operator+(const CMSimpleStringT& str1, const CMSimpleStringT& str2) -{ - CMSimpleStringT s; - Concatenate(s, str1, str1.GetLength(), str2, str2.GetLength()); - return s; -} - -template -typename CMSimpleStringT operator+(const CMSimpleStringT& str1, typename CMSimpleStringT::PCXSTR psz2) -{ - CMSimpleStringT s; - Concatenate(s, str1, str1.GetLength(), psz2, StringLength(psz2)); - return s; -} - -template -CMSimpleStringT operator+(typename CMSimpleStringT::PCXSTR psz1, const CMSimpleStringT& str2) -{ - CMSimpleStringT s; - Concatenate(s, psz1, StringLength(psz1), str2, str2.GetLength()); - return s; -} - -template -void __stdcall CMSimpleStringT::CopyChars(XCHAR* pchDest, const XCHAR* pchSrc, int nChars) -{ - #pragma warning (push) - #pragma warning(disable : 4996) - memcpy(pchDest, pchSrc, nChars * sizeof(XCHAR)); - #pragma warning (pop) -} - -template -void __stdcall CMSimpleStringT::CopyChars(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars) -{ - memcpy_s(pchDest, nDestLen * sizeof(XCHAR), pchSrc, nChars * sizeof(XCHAR)); -} - -template -void __stdcall CMSimpleStringT::CopyCharsOverlapped(XCHAR* pchDest, const XCHAR* pchSrc, int nChars) -{ - #pragma warning (push) - #pragma warning(disable : 4996) - memmove(pchDest, pchSrc, nChars * sizeof(XCHAR)); - #pragma warning (pop) -} - -template -void __stdcall CMSimpleStringT::CopyCharsOverlapped(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars) -{ - memmove_s(pchDest, nDestLen * sizeof(XCHAR), pchSrc, nChars * sizeof(XCHAR)); -} - -template -int __stdcall CMSimpleStringT::StringLength(const char* psz) -{ - if (psz == nullptr) - return(0); - - return (int(strlen(psz))); -} - -template -int __stdcall CMSimpleStringT::StringLength(const wchar_t* psz) -{ - if (psz == nullptr) - return 0; - - return int(wcslen(psz)); -} - -template -int __stdcall CMSimpleStringT::StringLengthN(const char* psz, size_t sizeInXChar) -{ - if (psz == nullptr) - return 0; - - return int(strnlen(psz, sizeInXChar)); -} - -template -int __stdcall CMSimpleStringT::StringLengthN(const wchar_t* psz, size_t sizeInXChar) -{ - if (psz == nullptr) - return 0; - - return int(wcsnlen(psz, sizeInXChar)); -} - -template -void __stdcall CMSimpleStringT::Concatenate(CMSimpleStringT& strResult, PCXSTR psz1, int nLength1, PCXSTR psz2, int nLength2) -{ - int nNewLength = nLength1 + nLength2; - PXSTR pszBuffer = strResult.GetBuffer(nNewLength); - CopyChars(pszBuffer, nLength1, psz1, nLength1); - CopyChars(pszBuffer + nLength1, nLength2, psz2, nLength2); - strResult.ReleaseBufferSetLength(nNewLength); -} - -template -void CMSimpleStringT::Attach(CMStringData* pData) -{ - m_pszData = static_cast(pData->data()); -} - -template -void CMSimpleStringT::Fork(int nLength) -{ - CMStringData* pOldData = GetData(); - int nOldLength = pOldData->nDataLength; - CMStringData* pNewData = mirstr_allocate(nLength, sizeof(XCHAR)); - if (pNewData != nullptr) { - int nCharsToCopy = ((nOldLength < nLength) ? nOldLength : nLength) + 1; // Copy '\0' - CopyChars(PXSTR(pNewData->data()), nCharsToCopy, PCXSTR(pOldData->data()), nCharsToCopy); - pNewData->nDataLength = nOldLength; - pOldData->Release(); - Attach(pNewData); - } -} - -template -typename CMSimpleStringT::PXSTR CMSimpleStringT::PrepareWrite(int nLength) -{ - CMStringData* pOldData = GetData(); - int nShared = 1 - pOldData->nRefs; // nShared < 0 means true, >= 0 means false - int nTooShort = pOldData->nAllocLength - nLength; // nTooShort < 0 means true, >= 0 means false - if ((nShared | nTooShort) < 0) // If either sign bit is set (i.e. either is less than zero), we need to copy data - PrepareWrite2(nLength); - - return m_pszData; -} - -template -void CMSimpleStringT::PrepareWrite2(int nLength) -{ - CMStringData* pOldData = GetData(); - if (pOldData->nDataLength > nLength) - nLength = pOldData->nDataLength; - - if (pOldData->IsShared()) { - Fork(nLength); - } - else if (pOldData->nAllocLength < nLength) { - // Grow exponentially, until we hit 1K. - int nNewLength = pOldData->nAllocLength; - if (nNewLength > 1024) - nNewLength += 1024; - else - nNewLength *= 2; - - if (nNewLength < nLength) - nNewLength = nLength; - - Reallocate(nNewLength); - } -} - -template -void CMSimpleStringT::Reallocate(int nLength) -{ - CMStringData* pOldData = GetData(); - if (pOldData->nAllocLength >= nLength || nLength <= 0) - return; - - CMStringData* pNewData = mirstr_realloc(pOldData, nLength, sizeof(XCHAR)); - if (pNewData != nullptr) - Attach(pNewData); -} - -template -void CMSimpleStringT::SetLength(int nLength) -{ - GetData()->nDataLength = nLength; - m_pszData[nLength] = 0; -} - -template -CMStringData* __stdcall CMSimpleStringT::CloneData(CMStringData* pData) -{ - CMStringData* pNewData = nullptr; - - if (!pData->IsLocked()) { - pNewData = pData; - pNewData->AddRef(); - } - - return pNewData; -} - -template< typename BaseType, class StringTraits > -CMStringT::CMStringT() : - CThisSimpleString() -{ -} - -// Copy constructor -template< typename BaseType, class StringTraits > -CMStringT::CMStringT(const CMStringT& strSrc) : - CThisSimpleString(strSrc) -{ -} - -template< typename BaseType, class StringTraits > -CMStringT::CMStringT(const XCHAR* pszSrc) : - CThisSimpleString() -{ - *this = pszSrc; -} - -template< typename BaseType, class StringTraits > -CMStringT::CMStringT(CMStringDataFormat, const XCHAR* pszFormat, ...) : - CThisSimpleString() -{ - va_list args; - va_start(args, pszFormat); - FormatV(pszFormat, args); -} - -template< typename BaseType, class StringTraits > -CMStringT::CMStringT(const YCHAR* pszSrc) : - CThisSimpleString() -{ - *this = pszSrc; -} - -template< typename BaseType, class StringTraits > -CMStringT::CMStringT(const unsigned char* pszSrc) : - CThisSimpleString() -{ - *this = reinterpret_cast(pszSrc); -} - -template< typename BaseType, class StringTraits > -CMStringT::CMStringT(char ch, int nLength) : - CThisSimpleString() -{ - if (nLength > 0) { - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::FloodCharacters(XCHAR(ch), nLength, pszBuffer); - this->ReleaseBufferSetLength(nLength); - } -} - -template< typename BaseType, class StringTraits > -CMStringT::CMStringT(wchar_t ch, int nLength) : - CThisSimpleString() -{ - if (nLength > 0) { - //Convert ch to the BaseType - wchar_t pszCh[2] = { ch, 0 }; - int nBaseTypeCharLen = 1; - - if (ch != L'\0') - nBaseTypeCharLen = StringTraits::GetBaseTypeLength(pszCh); - - XCHAR *buffBaseTypeChar = new XCHAR[nBaseTypeCharLen + 1]; - StringTraits::ConvertToBaseType(buffBaseTypeChar, nBaseTypeCharLen + 1, pszCh, 1); - //allocate enough characters in String and flood (replicate) with the (converted character)*nLength - PXSTR pszBuffer = this->GetBuffer(nLength*nBaseTypeCharLen); - if (nBaseTypeCharLen == 1) //Optimization for a common case - wide char translates to 1 ansi/wide char. - StringTraits::FloodCharacters(buffBaseTypeChar[0], nLength, pszBuffer); - else { - XCHAR* p = pszBuffer; - for (int i = 0; i < nLength; i++) { - for (int j = 0; j < nBaseTypeCharLen; ++j) { - *p = buffBaseTypeChar[j]; - ++p; - } - } - } - this->ReleaseBufferSetLength(nLength*nBaseTypeCharLen); - delete[] buffBaseTypeChar; - } -} - -template< typename BaseType, class StringTraits > -CMStringT::CMStringT(const XCHAR* pch, int nLength) : - CThisSimpleString(pch, nLength) -{ -} - -template< typename BaseType, class StringTraits > -CMStringT::CMStringT(const YCHAR* pch, int nLength) : - CThisSimpleString() -{ - if (nLength > 0) { - int nDestLength = StringTraits::GetBaseTypeLength(pch, nLength); - PXSTR pszBuffer = this->GetBuffer(nDestLength); - StringTraits::ConvertToBaseType(pszBuffer, nDestLength, pch, nLength); - this->ReleaseBufferSetLength(nDestLength); - } -} - -// Destructor -template< typename BaseType, class StringTraits > -CMStringT::~CMStringT() -{ -} - -// Assignment operators -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::operator=(const CMStringT& strSrc) -{ - CThisSimpleString::operator=(strSrc); - return *this; -} - -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::operator=(PCXSTR pszSrc) -{ - CThisSimpleString::operator=(pszSrc); - return *this; -} - -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::operator=(PCYSTR pszSrc) -{ - // nDestLength is in XCHARs - int nDestLength = (pszSrc != nullptr) ? StringTraits::GetBaseTypeLength(pszSrc) : 0; - if (nDestLength > 0) { - PXSTR pszBuffer = this->GetBuffer(nDestLength); - StringTraits::ConvertToBaseType(pszBuffer, nDestLength, pszSrc); - this->ReleaseBufferSetLength(nDestLength); - } - else this->Empty(); - - return *this; -} - -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::operator=(const unsigned char* pszSrc) -{ - return operator=(reinterpret_cast(pszSrc)); -} - -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::operator=(char ch) -{ - char ach[2] = { ch, 0 }; - return operator=(ach); -} - -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::operator=(wchar_t ch) -{ - wchar_t ach[2] = { ch, 0 }; - return operator=(ach); -} - -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::operator+=(const CMStringT& str) -{ - CThisSimpleString::operator+=(str); - return *this; -} - -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::operator+=(const CThisSimpleString& str) -{ - CThisSimpleString::operator+=(str); - return *this; -} - -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::operator+=(PCXSTR pszSrc) -{ - CThisSimpleString::operator+=(pszSrc); - return *this; -} - -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::operator+=(PCYSTR pszSrc) -{ - CMStringT str(pszSrc); - return operator+=(str); -} - -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::operator+=(char ch) -{ - CThisSimpleString::operator+=(ch); - return *this; -} - -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::operator+=(unsigned char ch) -{ - CThisSimpleString::operator+=(ch); - return *this; -} - -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::operator+=(wchar_t ch) -{ - CThisSimpleString::operator+=(ch); - return *this; -} - -// Comparison - -template< typename BaseType, class StringTraits > -int CMStringT::Compare(PCXSTR psz) const -{ - return StringTraits::StringCompare(this->GetString(), psz); -} - -template< typename BaseType, class StringTraits > -int CMStringT::CompareNoCase(PCXSTR psz) const -{ - return StringTraits::StringCompareIgnore(this->GetString(), psz); -} - -template< typename BaseType, class StringTraits > -int CMStringT::Collate(PCXSTR psz) const -{ - return StringTraits::StringCollate(this->GetString(), psz); -} - -template< typename BaseType, class StringTraits > -int CMStringT::CollateNoCase(PCXSTR psz) const -{ - return StringTraits::StringCollateIgnore(this->GetString(), psz); -} - -// Advanced manipulation - -// Delete 'nCount' characters, starting at index 'iIndex' -template< typename BaseType, class StringTraits > -int CMStringT::Delete(int iIndex, int nCount) -{ - if (iIndex < 0) - iIndex = 0; - - if (nCount < 0) - nCount = 0; - - int nLength = this->GetLength(); - if (nCount + iIndex > nLength) - nCount = nLength - iIndex; - - if (nCount > 0) { - int nNewLength = nLength - nCount; - int nXCHARsToCopy = nLength - (iIndex + nCount) + 1; - PXSTR pszBuffer = this->GetBuffer(); -#if _MSC_VER >= 1400 - memmove_s(pszBuffer + iIndex, nXCHARsToCopy*sizeof(XCHAR), pszBuffer + iIndex + nCount, nXCHARsToCopy*sizeof(XCHAR)); -#else - memmove(pszBuffer+iIndex, pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof(XCHAR)); -#endif - this->ReleaseBufferSetLength(nNewLength); - } - - return this->GetLength(); -} - -// Insert character 'ch' before index 'iIndex' -template< typename BaseType, class StringTraits > -int CMStringT::Insert(int iIndex, XCHAR ch) -{ - if (iIndex < 0) - iIndex = 0; - - if (iIndex > this->GetLength()) - iIndex = this->GetLength(); - - int nNewLength = this->GetLength() + 1; - - PXSTR pszBuffer = this->GetBuffer(nNewLength); - - // move existing bytes down -#if _MSC_VER >= 1400 - memmove_s(pszBuffer + iIndex + 1, (nNewLength - iIndex)*sizeof(XCHAR), pszBuffer + iIndex, (nNewLength - iIndex)*sizeof(XCHAR)); -#else - memmove(pszBuffer+iIndex+1, pszBuffer+iIndex, (nNewLength-iIndex)*sizeof(XCHAR)); -#endif - pszBuffer[iIndex] = ch; - - this->ReleaseBufferSetLength(nNewLength); - return nNewLength; -} - -// Insert string 'psz' before index 'iIndex' -template< typename BaseType, class StringTraits > -int CMStringT::Insert(int iIndex, PCXSTR psz) -{ - if (iIndex < 0) - iIndex = 0; - - if (iIndex > this->GetLength()) - iIndex = this->GetLength(); - - // nInsertLength and nNewLength are in XCHARs - int nInsertLength = StringTraits::SafeStringLen(psz); - int nNewLength = this->GetLength(); - if (nInsertLength > 0) { - nNewLength += nInsertLength; - - PXSTR pszBuffer = this->GetBuffer(nNewLength); - // move existing bytes down -#if _MSC_VER >= 1400 - memmove_s(pszBuffer + iIndex + nInsertLength, (nNewLength - iIndex - nInsertLength + 1)*sizeof(XCHAR), pszBuffer + iIndex, (nNewLength - iIndex - nInsertLength + 1)*sizeof(XCHAR)); - memcpy_s(pszBuffer + iIndex, nInsertLength*sizeof(XCHAR), psz, nInsertLength*sizeof(XCHAR)); -#else - memmove(pszBuffer+iIndex+nInsertLength, pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof(XCHAR)); - memcpy(pszBuffer+iIndex, psz, nInsertLength*sizeof(XCHAR)); -#endif - this->ReleaseBufferSetLength(nNewLength); - } - - return nNewLength; -} - -// Replace all occurrences of character 'chOld' with character 'chNew' -template< typename BaseType, class StringTraits > -int CMStringT::Replace(XCHAR chOld, XCHAR chNew) -{ - int nCount = 0; - - // short-circuit the nop case - if (chOld != chNew) { - // otherwise modify each character that matches in the string - bool bCopied = false; - PXSTR pszBuffer = const_cast(this->GetString()); // We don't actually write to pszBuffer until we've called GetBuffer(). - - int nLength = this->GetLength(); - int iChar = 0; - while (iChar < nLength) { - // replace instances of the specified character only - if (pszBuffer[iChar] == chOld) { - if (!bCopied) { - bCopied = true; - pszBuffer = this->GetBuffer(nLength); - } - pszBuffer[iChar] = chNew; - nCount++; - } - iChar = int(StringTraits::CharNext(pszBuffer + iChar) - pszBuffer); - } - - if (bCopied) - this->ReleaseBufferSetLength(nLength); - } - - return nCount; -} - -// Replace all occurrences of string 'pszOld' with string 'pszNew' -template< typename BaseType, class StringTraits > -int CMStringT::Replace(PCXSTR pszOld, PCXSTR pszNew) -{ - // can't have empty or NULL lpszOld - - // nSourceLen is in XCHARs - int nSourceLen = StringTraits::SafeStringLen(pszOld); - if (nSourceLen == 0) - return 0; - // nReplacementLen is in XCHARs - int nReplacementLen = StringTraits::SafeStringLen(pszNew); - - // loop once to figure out the size of the result string - int nCount = 0; - { - PCXSTR pszStart = this->GetString(); - PCXSTR pszEnd = pszStart + this->GetLength(); - while (pszStart < pszEnd) { - PCXSTR pszTarget; - while ((pszTarget = StringTraits::StringFindString(pszStart, pszOld)) != nullptr) { - nCount++; - pszStart = pszTarget + nSourceLen; - } - pszStart += StringTraits::SafeStringLen(pszStart) + 1; - } - } - - // if any changes were made, make them - if (nCount > 0) { - // if the buffer is too small, just - // allocate a new buffer (slow but sure) - int nOldLength = this->GetLength(); - int nNewLength = nOldLength + (nReplacementLen - nSourceLen)*nCount; - - PXSTR pszBuffer = this->GetBuffer(__max(nNewLength, nOldLength)); - - PXSTR pszStart = pszBuffer; - PXSTR pszEnd = pszStart + nOldLength; - - // loop again to actually do the work - while (pszStart < pszEnd) { - PXSTR pszTarget; - while ((pszTarget = StringTraits::StringFindString(pszStart, pszOld)) != nullptr) { - int nBalance = nOldLength - int(pszTarget - pszBuffer + nSourceLen); - memmove_s(pszTarget + nReplacementLen, nBalance*sizeof(XCHAR), - pszTarget + nSourceLen, nBalance*sizeof(XCHAR)); - memcpy_s(pszTarget, nReplacementLen*sizeof(XCHAR), - pszNew, nReplacementLen*sizeof(XCHAR)); - pszStart = pszTarget + nReplacementLen; - pszTarget[nReplacementLen + nBalance] = 0; - nOldLength += (nReplacementLen - nSourceLen); - } - pszStart += StringTraits::SafeStringLen(pszStart) + 1; - } - this->ReleaseBufferSetLength(nNewLength); - } - - return nCount; -} - -// Remove all occurrences of character 'chRemove' -template< typename BaseType, class StringTraits > -int CMStringT::Remove(XCHAR chRemove) -{ - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer(nLength); - - PXSTR pszSource = pszBuffer; - PXSTR pszDest = pszBuffer; - PXSTR pszEnd = pszBuffer + nLength; - - while (pszSource < pszEnd) { - PXSTR pszNewSource = StringTraits::CharNext(pszSource); - if (*pszSource != chRemove) { - // Copy the source to the destination. Remember to copy all bytes of an MBCS character - size_t NewSourceGap = (pszNewSource - pszSource); - PXSTR pszNewDest = pszDest + NewSourceGap; - for (size_t i = 0; pszDest != pszNewDest && i < NewSourceGap; i++) { - *pszDest = *pszSource; - pszSource++; - pszDest++; - } - } - pszSource = pszNewSource; - } - *pszDest = 0; - int nCount = int(pszSource - pszDest); - this->ReleaseBufferSetLength(nLength - nCount); - - return nCount; -} - -template< typename BaseType, class StringTraits > -CMStringT CMStringT::Tokenize(PCXSTR pszTokens, int& iStart) const -{ - if ((pszTokens == nullptr) || (*pszTokens == (XCHAR)0)) { - if (iStart < this->GetLength()) - return CMStringT(this->GetString() + iStart); - } - else { - PCXSTR pszPlace = this->GetString() + iStart; - PCXSTR pszEnd = this->GetString() + this->GetLength(); - if (pszPlace < pszEnd) { - int nIncluding = StringTraits::StringSpanIncluding(pszPlace, pszTokens); - - if ((pszPlace + nIncluding) < pszEnd) { - pszPlace += nIncluding; - int nExcluding = StringTraits::StringSpanExcluding(pszPlace, pszTokens); - - int iFrom = iStart + nIncluding; - int nUntil = nExcluding; - iStart = iFrom + nUntil + 1; - - return Mid(iFrom, nUntil); - } - } - } - - // return empty string, done tokenizing - iStart = -1; - - return CMStringT(); -} - -// find routines - -// Find the first occurrence of character 'ch', starting at index 'iStart' -template< typename BaseType, class StringTraits > -int CMStringT::Find(XCHAR ch, int iStart) const -{ - // nLength is in XCHARs - int nLength = this->GetLength(); - if (iStart < 0 || iStart >= nLength) - return -1; - - // find first single character - PCXSTR psz = StringTraits::StringFindChar(this->GetString() + iStart, ch); - - // return -1 if not found and index otherwise - return (psz == nullptr) ? -1 : int(psz - this->GetString()); -} - -// look for a specific sub-string - -// Find the first occurrence of string 'pszSub', starting at index 'iStart' -template< typename BaseType, class StringTraits > -int CMStringT::Find(PCXSTR pszSub, int iStart) const -{ - // iStart is in XCHARs - if (pszSub == nullptr) - return -1; - - // nLength is in XCHARs - int nLength = this->GetLength(); - if (iStart < 0 || iStart > nLength) - return -1; - - // find first matching substring - PCXSTR psz = StringTraits::StringFindString(this->GetString() + iStart, pszSub); - - // return -1 for not found, distance from beginning otherwise - return (psz == nullptr) ? -1 : int(psz - this->GetString()); -} - -// Find the first occurrence of any of the characters in string 'pszCharSet' -template< typename BaseType, class StringTraits > -int CMStringT::FindOneOf(PCXSTR pszCharSet) const -{ - PCXSTR psz = StringTraits::StringScanSet(this->GetString(), pszCharSet); - return (psz == nullptr) ? -1 : int(psz - this->GetString()); -} - -// Find the last occurrence of character 'ch' -template< typename BaseType, class StringTraits > -int CMStringT::ReverseFind(XCHAR ch) const -{ - // find last single character - PCXSTR psz = StringTraits::StringFindCharRev(this->GetString(), ch); - - // return -1 if not found, distance from beginning otherwise - return (psz == nullptr) ? -1 : int(psz - this->GetString()); -} - -// manipulation - -// Convert the string to uppercase -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::MakeUpper() -{ - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::StringUppercase(pszBuffer, nLength + 1); - this->ReleaseBufferSetLength(nLength); - - return *this; -} - -// Convert the string to lowercase -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::MakeLower() -{ - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::StringLowercase(pszBuffer, nLength + 1); - this->ReleaseBufferSetLength(nLength); - - return *this; -} - -// Reverse the string -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::MakeReverse() -{ - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::StringReverse(pszBuffer); - this->ReleaseBufferSetLength(nLength); - - return *this; -} - -// trimming - -// Remove all trailing whitespace -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::TrimRight() -{ - // find beginning of trailing spaces by starting - // at beginning (DBCS aware) - - PCXSTR psz = this->GetString(); - PCXSTR pszLast = nullptr; - - while (*psz != 0) { - if (StringTraits::IsSpace(*psz)) { - if (pszLast == nullptr) - pszLast = psz; - } - else pszLast = nullptr; - - psz = StringTraits::CharNext(psz); - } - - if (pszLast != nullptr) { - // truncate at trailing space start - int iLast = int(pszLast - this->GetString()); - - this->Truncate(iLast); - } - - return *this; -} - -// Remove all leading whitespace -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::TrimLeft() -{ - // find first non-space character - - PCXSTR psz = this->GetString(); - while (StringTraits::IsSpace(*psz)) - psz = StringTraits::CharNext(psz); - - if (psz != this->GetString()) { - // fix up data and length - int iFirst = int(psz - this->GetString()); - PXSTR pszBuffer = this->GetBuffer(this->GetLength()); - psz = pszBuffer + iFirst; - int nDataLength = this->GetLength() - iFirst; - memmove_s(pszBuffer, (this->GetLength() + 1)*sizeof(XCHAR), - psz, (nDataLength + 1)*sizeof(XCHAR)); - this->ReleaseBufferSetLength(nDataLength); - } - - return *this; -} - -// Remove all leading and trailing whitespace -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::Trim() -{ - return TrimRight().TrimLeft(); -} - -// Remove all leading and trailing occurrences of character 'chTarget' -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::Trim(XCHAR chTarget) -{ - return TrimRight(chTarget).TrimLeft(chTarget); -} - -// Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets' -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::Trim(PCXSTR pszTargets) -{ - return TrimRight(pszTargets).TrimLeft(pszTargets); -} - -// trimming anything (either side) - -// Remove all trailing occurrences of character 'chTarget' -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::TrimRight(XCHAR chTarget) -{ - // find beginning of trailing matches - // by starting at beginning (DBCS aware) - - PCXSTR psz = this->GetString(); - PCXSTR pszLast = nullptr; - - while (*psz != 0) { - if (*psz == chTarget) { - if (pszLast == nullptr) - pszLast = psz; - } - else pszLast = nullptr; - - psz = StringTraits::CharNext(psz); - } - - if (pszLast != nullptr) { - // truncate at left-most matching character - int iLast = int(pszLast - this->GetString()); - this->Truncate(iLast); - } - - return *this; -} - -// Remove all trailing occurrences of any of the characters in string 'pszTargets' -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::TrimRight(PCXSTR pszTargets) -{ - // if we're not trimming anything, we're not doing any work - if ((pszTargets == nullptr) || (*pszTargets == 0)) { - return *this; - } - - // find beginning of trailing matches - // by starting at beginning (DBCS aware) - - PCXSTR psz = this->GetString(); - PCXSTR pszLast = nullptr; - - while (*psz != 0) { - if (StringTraits::StringFindChar(pszTargets, *psz) != nullptr) { - if (pszLast == nullptr) { - pszLast = psz; - } - } - else { - pszLast = nullptr; - } - psz = StringTraits::CharNext(psz); - } - - if (pszLast != nullptr) { - // truncate at left-most matching character - int iLast = int(pszLast - this->GetString()); - this->Truncate(iLast); - } - - return *this; -} - -// Remove all leading occurrences of character 'chTarget' -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::TrimLeft(XCHAR chTarget) -{ - // find first non-matching character - PCXSTR psz = this->GetString(); - - while (chTarget == *psz) { - psz = StringTraits::CharNext(psz); - } - - if (psz != this->GetString()) { - // fix up data and length - int iFirst = int(psz - this->GetString()); - PXSTR pszBuffer = this->GetBuffer(this->GetLength()); - psz = pszBuffer + iFirst; - int nDataLength = this->GetLength() - iFirst; - memmove_s(pszBuffer, (this->GetLength() + 1)*sizeof(XCHAR), - psz, (nDataLength + 1)*sizeof(XCHAR)); - this->ReleaseBufferSetLength(nDataLength); - } - - return *this; -} - -// Remove all leading occurrences of any of the characters in string 'pszTargets' -template< typename BaseType, class StringTraits > -CMStringT& CMStringT::TrimLeft(PCXSTR pszTargets) -{ - // if we're not trimming anything, we're not doing any work - if ((pszTargets == nullptr) || (*pszTargets == 0)) { - return *this; - } - - PCXSTR psz = this->GetString(); - while ((*psz != 0) && (StringTraits::StringFindChar(pszTargets, *psz) != nullptr)) { - psz = StringTraits::CharNext(psz); - } - - if (psz != this->GetString()) { - // fix up data and length - int iFirst = int(psz - this->GetString()); - PXSTR pszBuffer = this->GetBuffer(this->GetLength()); - psz = pszBuffer + iFirst; - int nDataLength = this->GetLength() - iFirst; - memmove_s(pszBuffer, (this->GetLength() + 1)*sizeof(XCHAR), - psz, (nDataLength + 1)*sizeof(XCHAR)); - this->ReleaseBufferSetLength(nDataLength); - } - - return *this; -} - -// Convert the string to the OEM character set -template< typename BaseType, class StringTraits > -void CMStringT::AnsiToOem() -{ - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::ConvertToOem(pszBuffer, nLength + 1); - this->ReleaseBufferSetLength(nLength); -} - -// Convert the string to the ANSI character set -template< typename BaseType, class StringTraits > -void CMStringT::OemToAnsi() -{ - int nLength = this->GetLength(); - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::ConvertToAnsi(pszBuffer, nLength + 1); - this->ReleaseBufferSetLength(nLength); -} - -// Very simple sub-string extraction - -// Return the substring starting at index 'iFirst' -template< typename BaseType, class StringTraits > -CMStringT CMStringT::Mid(int iFirst) const -{ - return Mid(iFirst, this->GetLength() - iFirst); -} - -// Return the substring starting at index 'iFirst', with length 'nCount' -template< typename BaseType, class StringTraits > -CMStringT CMStringT::Mid(int iFirst, int nCount) const -{ - // nCount is in XCHARs - - // out-of-bounds requests return sensible things - if (iFirst < 0) - iFirst = 0; - if (nCount < 0) - nCount = 0; - - if ((iFirst + nCount) > this->GetLength()) - nCount = this->GetLength() - iFirst; - - if (iFirst > this->GetLength()) - nCount = 0; - - // optimize case of returning entire string - if ((iFirst == 0) && ((iFirst + nCount) == this->GetLength())) - return *this; - - return CMStringT(this->GetString() + iFirst, nCount); -} - -// Return the substring consisting of the rightmost 'nCount' characters -template< typename BaseType, class StringTraits > -CMStringT CMStringT::Right(int nCount) const -{ - // nCount is in XCHARs - if (nCount < 0) - nCount = 0; - - int nLength = this->GetLength(); - if (nCount >= nLength) - return *this; - - return CMStringT(this->GetString() + nLength - nCount, nCount); -} - -// Return the substring consisting of the leftmost 'nCount' characters -template< typename BaseType, class StringTraits > -CMStringT CMStringT::Left(int nCount) const -{ - // nCount is in XCHARs - if (nCount < 0) - nCount = 0; - - int nLength = this->GetLength(); - if (nCount >= nLength) - return *this; - - return CMStringT(this->GetString(), nCount); -} - -// Return the substring consisting of the leftmost characters in the set 'pszCharSet' -template< typename BaseType, class StringTraits > -CMStringT CMStringT::SpanIncluding(PCXSTR pszCharSet) const -{ - return Left(StringTraits::StringSpanIncluding(this->GetString(), pszCharSet)); -} - -// Return the substring consisting of the leftmost characters not in the set 'pszCharSet' -template< typename BaseType, class StringTraits > -CMStringT CMStringT::SpanExcluding(PCXSTR pszCharSet) const -{ - return Left(StringTraits::StringSpanExcluding(this->GetString(), pszCharSet)); -} - -// Format data using format string 'pszFormat' -template< typename BaseType, class StringTraits > -typename CMStringT::PCXSTR CMStringT::Format(PCXSTR pszFormat, ...) -{ - va_list argList; - va_start(argList, pszFormat); - FormatV(pszFormat, argList); - va_end(argList); - return GetString(); -} - -// Append formatted data using format string 'pszFormat' -template< typename BaseType, class StringTraits > -typename CMStringT::PCXSTR CMStringT::AppendFormat(PCXSTR pszFormat, ...) -{ - va_list argList; - va_start(argList, pszFormat); - AppendFormatV(pszFormat, argList); - va_end(argList); - return GetString(); -} - -template< typename BaseType, class StringTraits > -void CMStringT::AppendFormatV(PCXSTR pszFormat, va_list args) -{ - int nCurrentLength = this->GetLength(); - int nAppendLength = StringTraits::GetFormattedLength(pszFormat, args); - PXSTR pszBuffer = this->GetBuffer(nCurrentLength + nAppendLength); - StringTraits::Format(pszBuffer + nCurrentLength, nAppendLength + 1, pszFormat, args); - this->ReleaseBufferSetLength(nCurrentLength + nAppendLength); -} - -template< typename BaseType, class StringTraits > -typename CMStringT::PCXSTR CMStringT::FormatV(PCXSTR pszFormat, va_list args) -{ - int nLength = StringTraits::GetFormattedLength(pszFormat, args); - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::Format(pszBuffer, nLength + 1, pszFormat, args); - this->ReleaseBufferSetLength(nLength); - return GetString(); -} - -// Set the string to the value of environment variable 'pszVar' -template< typename BaseType, class StringTraits > -BOOL CMStringT::GetEnvironmentVariable(PCXSTR pszVar) -{ - ULONG nLength = StringTraits::GetEnvironmentVariable(pszVar, nullptr, 0); - BOOL bRetVal = FALSE; - - if (nLength == 0) - this->Empty(); - else { - PXSTR pszBuffer = this->GetBuffer(nLength); - StringTraits::GetEnvironmentVariable(pszVar, pszBuffer, nLength); - this->ReleaseBuffer(); - bRetVal = TRUE; - } - - return bRetVal; -} - -// Set the string to the value of environment variable 'pszVar' -template< typename BaseType, class StringTraits > -typename CMStringT::PXSTR CMStringT::Detach() const -{ - return StringTraits::MirCopy(CMStringT::GetString(), GetLength()); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -template< typename BaseType, class StringTraits > -MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, const CMStringT& str2) -{ - CMStringT strResult; - CMStringT::Concatenate(strResult, str1, str1.GetLength(), str2, str2.GetLength()); - return strResult; -} - -template< typename BaseType, class StringTraits > -MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, typename CMStringT::PCXSTR psz2) -{ - CMStringT strResult; - CMStringT::Concatenate(strResult, str1, str1.GetLength(), psz2, CMStringT::StringLength(psz2)); - return strResult; -} - -template< typename BaseType, class StringTraits > -MIR_CORE_EXPORT CMStringT CALLBACK operator+(typename CMStringT::PCXSTR psz1, const CMStringT& str2) -{ - CMStringT strResult; - CMStringT::Concatenate(strResult, psz1, CMStringT::StringLength(psz1), str2, str2.GetLength()); - return strResult; -} - -template< typename BaseType, class StringTraits > -MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, wchar_t ch2) -{ - CMStringT strResult; - typename CMStringT::XCHAR chTemp = typename CMStringT::XCHAR(ch2); - CMStringT::Concatenate(strResult, str1, str1.GetLength(), &chTemp, 1); - return strResult; -} - -template< typename BaseType, class StringTraits > -MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, char ch2) -{ - CMStringT strResult; - typename CMStringT::XCHAR chTemp = typename CMStringT::XCHAR(ch2); - CMStringT::Concatenate(strResult, str1, str1.GetLength(), &chTemp, 1); - return strResult; -} - -template< typename BaseType, class StringTraits > -MIR_CORE_EXPORT CMStringT CALLBACK operator+(wchar_t ch1, const CMStringT& str2) -{ - CMStringT strResult; - typename CMStringT::XCHAR chTemp = typename CMStringT::XCHAR(ch1); - CMStringT::Concatenate(strResult, &chTemp, 1, str2, str2.GetLength()); - return strResult; -} - -template< typename BaseType, class StringTraits > -MIR_CORE_EXPORT CMStringT CALLBACK operator+(char ch1, const CMStringT& str2) -{ - CMStringT strResult; - typename CMStringT::XCHAR chTemp = typename CMStringT::XCHAR(ch1); - CMStringT::Concatenate(strResult, &chTemp, 1, str2, str2.GetLength()); - return strResult; -} - -#endif // M_STRING_INL__ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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. +*/ + +#pragma once + +#ifndef M_STRING_INL__ + +template +CMSimpleStringT::CMSimpleStringT() +{ + CMStringData* pData = mirstr_getNil(); + Attach(pData); +} + +template +CMSimpleStringT::CMSimpleStringT(const CMSimpleStringT& strSrc) +{ + CMStringData* pSrcData = strSrc.GetData(); + CMStringData* pNewData = CloneData(pSrcData); + Attach(pNewData); +} + +template +CMSimpleStringT::CMSimpleStringT(PCXSTR pszSrc) +{ + int nLength = StringLength(pszSrc); + CMStringData* pData = mirstr_allocate(nLength, sizeof(XCHAR)); + if (pData != nullptr) { + Attach(pData); + SetLength(nLength); + CopyChars(m_pszData, nLength, pszSrc, nLength); + } +} + +template +CMSimpleStringT::CMSimpleStringT(const XCHAR* pchSrc, int nLength) +{ + CMStringData* pData = mirstr_allocate(nLength, sizeof(XCHAR)); + if (pData != nullptr) { + Attach(pData); + SetLength(nLength); + CopyChars(m_pszData, nLength, pchSrc, nLength); + } +} + +template +CMSimpleStringT::~CMSimpleStringT() +{ + CMStringData* pData = GetData(); + pData->Release(); +} + +template +CMSimpleStringT& CMSimpleStringT::operator=(const CMSimpleStringT& strSrc) +{ + CMStringData* pSrcData = strSrc.GetData(); + CMStringData* pOldData = GetData(); + if (pSrcData != pOldData) { + if (pOldData->IsLocked()) + SetString(strSrc.GetString(), strSrc.GetLength()); + else { + CMStringData* pNewData = CloneData(pSrcData); + pOldData->Release(); + Attach(pNewData); + } + } + + return *this; +} + +template +void CMSimpleStringT::Append(PCXSTR pszSrc) +{ + Append(pszSrc, StringLength(pszSrc)); +} + +template +void CMSimpleStringT::Append(PCXSTR pszSrc, int nLength) +{ + // See comment in SetString() about why we do this + UINT_PTR nOffset = UINT_PTR(pszSrc - GetString()); + + int nOldLength = GetLength(); + if (nOldLength < 0) { + // protects from underflow + nOldLength = 0; + } + + //Make sure we don't read pass end of the terminating NULL + int nSrcLength = StringLength(pszSrc); + nLength = nLength > nSrcLength ? nSrcLength : nLength; + + int nNewLength = nOldLength + nLength; + PXSTR pszBuffer = GetBuffer(nNewLength); + if (nOffset <= UINT_PTR(nOldLength)) { + pszSrc = pszBuffer + nOffset; + // No need to call CopyCharsOverlapped, since the destination is + // beyond the end of the original buffer + } + CopyChars(pszBuffer + nOldLength, nLength, pszSrc, nLength); + ReleaseBufferSetLength(nNewLength); +} + +template +void CMSimpleStringT::AppendChar(XCHAR ch) +{ + UINT nOldLength = GetLength(); + int nNewLength = nOldLength + 1; + PXSTR pszBuffer = GetBuffer(nNewLength); + pszBuffer[nOldLength] = ch; + ReleaseBufferSetLength(nNewLength); +} + +template +void CMSimpleStringT::Append(const CMSimpleStringT& strSrc) +{ + Append(strSrc.GetString(), strSrc.GetLength()); +} + +template +void CMSimpleStringT::Empty() +{ + CMStringData* pOldData = GetData(); + if (pOldData->nDataLength == 0) + return; + + if (pOldData->IsLocked()) { + // Don't reallocate a locked buffer that's shrinking + SetLength(0); + } + else { + pOldData->Release(); + CMStringData* pNewData = mirstr_getNil(); + Attach(pNewData); + } +} + +template +void CMSimpleStringT::FreeExtra() +{ + CMStringData* pOldData = GetData(); + int nLength = pOldData->nDataLength; + if (pOldData->nAllocLength == nLength) + return; + + if (!pOldData->IsLocked()) { // Don't reallocate a locked buffer that's shrinking + CMStringData* pNewData = mirstr_allocate(nLength, sizeof(XCHAR)); + if (pNewData == nullptr) { + SetLength(nLength); + return; + } + + CopyChars(PXSTR(pNewData->data()), nLength, PCXSTR(pOldData->data()), nLength); + + pOldData->Release(); + Attach(pNewData); + SetLength(nLength); + } +} + +template +typename CMSimpleStringT::PXSTR CMSimpleStringT::GetBuffer() +{ + CMStringData* pData = GetData(); + if (pData->IsShared()) + Fork(pData->nDataLength); + + return m_pszData; +} + +template +typename CMSimpleStringT::PXSTR CMSimpleStringT::GetBufferSetLength(int nLength) +{ + PXSTR pszBuffer = GetBuffer(nLength); + SetLength(nLength); + + return pszBuffer; +} + +template +typename CMSimpleStringT::PXSTR CMSimpleStringT::LockBuffer() +{ + CMStringData* pData = GetData(); + if (pData->IsShared()) { + Fork(pData->nDataLength); + pData = GetData(); // Do it again, because the fork might have changed it + } + pData->Lock(); + + return m_pszData; +} + +template +void CMSimpleStringT::UnlockBuffer() +{ + CMStringData* pData = GetData(); + pData->Unlock(); +} + +template +void CMSimpleStringT::ReleaseBuffer(int nNewLength) +{ + if (nNewLength == -1) { + int nAlloc = GetData()->nAllocLength; + nNewLength = StringLengthN(m_pszData, nAlloc); + } + SetLength(nNewLength); +} + +template +void CMSimpleStringT::Truncate(int nNewLength) +{ + GetBuffer(nNewLength); + ReleaseBufferSetLength(nNewLength); +} + +template +void CMSimpleStringT::SetAt(int iChar, XCHAR ch) +{ + int nLength = GetLength(); + PXSTR pszBuffer = GetBuffer(); + pszBuffer[iChar] = ch; + ReleaseBufferSetLength(nLength); + +} + +template +void CMSimpleStringT::SetString(PCXSTR pszSrc) +{ + SetString(pszSrc, StringLength(pszSrc)); +} + +template +void CMSimpleStringT::SetString(PCXSTR pszSrc, int nLength) +{ + if (nLength == 0) + Empty(); + else { + UINT nOldLength = GetLength(); + UINT_PTR nOffset = pszSrc - GetString(); + + PXSTR pszBuffer = GetBuffer(nLength); + if (nOffset <= nOldLength) + CopyCharsOverlapped(pszBuffer, GetAllocLength(), pszBuffer + nOffset, nLength); + else + CopyChars(pszBuffer, GetAllocLength(), pszSrc, nLength); + + ReleaseBufferSetLength(nLength); + } +} + +template +class CMSimpleStringT operator+(const CMSimpleStringT& str1, const CMSimpleStringT& str2) +{ + CMSimpleStringT s; + Concatenate(s, str1, str1.GetLength(), str2, str2.GetLength()); + return s; +} + +template +class CMSimpleStringT operator+(const CMSimpleStringT& str1, typename CMSimpleStringT::PCXSTR psz2) +{ + CMSimpleStringT s; + Concatenate(s, str1, str1.GetLength(), psz2, StringLength(psz2)); + return s; +} + +template +CMSimpleStringT operator+(typename CMSimpleStringT::PCXSTR psz1, const CMSimpleStringT& str2) +{ + CMSimpleStringT s; + Concatenate(s, psz1, StringLength(psz1), str2, str2.GetLength()); + return s; +} + +template +void MIR_SYSCALL CMSimpleStringT::CopyChars(XCHAR* pchDest, const XCHAR* pchSrc, int nChars) +{ + #pragma warning (push) + #pragma warning(disable : 4996) + memcpy(pchDest, pchSrc, nChars * sizeof(XCHAR)); + #pragma warning (pop) +} + +template +void MIR_SYSCALL CMSimpleStringT::CopyChars(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars) +{ + memcpy_s(pchDest, nDestLen * sizeof(XCHAR), pchSrc, nChars * sizeof(XCHAR)); +} + +template +void MIR_SYSCALL CMSimpleStringT::CopyCharsOverlapped(XCHAR* pchDest, const XCHAR* pchSrc, int nChars) +{ + #pragma warning (push) + #pragma warning(disable : 4996) + memmove(pchDest, pchSrc, nChars * sizeof(XCHAR)); + #pragma warning (pop) +} + +template +void MIR_SYSCALL CMSimpleStringT::CopyCharsOverlapped(XCHAR* pchDest, size_t nDestLen, const XCHAR* pchSrc, int nChars) +{ + memmove_s(pchDest, nDestLen * sizeof(XCHAR), pchSrc, nChars * sizeof(XCHAR)); +} + +template +int MIR_SYSCALL CMSimpleStringT::StringLength(const char* psz) +{ + if (psz == nullptr) + return(0); + + return (int(strlen(psz))); +} + +template +int MIR_SYSCALL CMSimpleStringT::StringLength(const wchar_t* psz) +{ + if (psz == nullptr) + return 0; + + return int(wcslen(psz)); +} + +template +int MIR_SYSCALL CMSimpleStringT::StringLengthN(const char* psz, size_t sizeInXChar) +{ + if (psz == nullptr) + return 0; + + return int(strnlen(psz, sizeInXChar)); +} + +template +int MIR_SYSCALL CMSimpleStringT::StringLengthN(const wchar_t* psz, size_t sizeInXChar) +{ + if (psz == nullptr) + return 0; + + return int(wcsnlen(psz, sizeInXChar)); +} + +template +void MIR_SYSCALL CMSimpleStringT::Concatenate(CMSimpleStringT& strResult, PCXSTR psz1, int nLength1, PCXSTR psz2, int nLength2) +{ + int nNewLength = nLength1 + nLength2; + PXSTR pszBuffer = strResult.GetBuffer(nNewLength); + CopyChars(pszBuffer, nLength1, psz1, nLength1); + CopyChars(pszBuffer + nLength1, nLength2, psz2, nLength2); + strResult.ReleaseBufferSetLength(nNewLength); +} + +template +void CMSimpleStringT::Attach(CMStringData* pData) +{ + m_pszData = static_cast(pData->data()); +} + +template +void CMSimpleStringT::Fork(int nLength) +{ + CMStringData* pOldData = GetData(); + int nOldLength = pOldData->nDataLength; + CMStringData* pNewData = mirstr_allocate(nLength, sizeof(XCHAR)); + if (pNewData != nullptr) { + int nCharsToCopy = ((nOldLength < nLength) ? nOldLength : nLength) + 1; // Copy '\0' + CopyChars(PXSTR(pNewData->data()), nCharsToCopy, PCXSTR(pOldData->data()), nCharsToCopy); + pNewData->nDataLength = nOldLength; + pOldData->Release(); + Attach(pNewData); + } +} + +template +typename CMSimpleStringT::PXSTR CMSimpleStringT::PrepareWrite(int nLength) +{ + CMStringData* pOldData = GetData(); + int nShared = 1 - pOldData->nRefs; // nShared < 0 means true, >= 0 means false + int nTooShort = pOldData->nAllocLength - nLength; // nTooShort < 0 means true, >= 0 means false + if ((nShared | nTooShort) < 0) // If either sign bit is set (i.e. either is less than zero), we need to copy data + PrepareWrite2(nLength); + + return m_pszData; +} + +template +void CMSimpleStringT::PrepareWrite2(int nLength) +{ + CMStringData* pOldData = GetData(); + if (pOldData->nDataLength > nLength) + nLength = pOldData->nDataLength; + + if (pOldData->IsShared()) { + Fork(nLength); + } + else if (pOldData->nAllocLength < nLength) { + // Grow exponentially, until we hit 1K. + int nNewLength = pOldData->nAllocLength; + if (nNewLength > 1024) + nNewLength += 1024; + else + nNewLength *= 2; + + if (nNewLength < nLength) + nNewLength = nLength; + + Reallocate(nNewLength); + } +} + +template +void CMSimpleStringT::Reallocate(int nLength) +{ + CMStringData* pOldData = GetData(); + if (pOldData->nAllocLength >= nLength || nLength <= 0) + return; + + CMStringData* pNewData = mirstr_realloc(pOldData, nLength, sizeof(XCHAR)); + if (pNewData != nullptr) + Attach(pNewData); +} + +template +void CMSimpleStringT::SetLength(int nLength) +{ + GetData()->nDataLength = nLength; + m_pszData[nLength] = 0; +} + +template +CMStringData* MIR_SYSCALL CMSimpleStringT::CloneData(CMStringData* pData) +{ + CMStringData* pNewData = nullptr; + + if (!pData->IsLocked()) { + pNewData = pData; + pNewData->AddRef(); + } + + return pNewData; +} + +template< typename BaseType, class StringTraits > +CMStringT::CMStringT() : + CThisSimpleString() +{ +} + +// Copy constructor +template< typename BaseType, class StringTraits > +CMStringT::CMStringT(const CMStringT& strSrc) : + CThisSimpleString(strSrc) +{ +} + +template< typename BaseType, class StringTraits > +CMStringT::CMStringT(const XCHAR* pszSrc) : + CThisSimpleString() +{ + *this = pszSrc; +} + +template< typename BaseType, class StringTraits > +CMStringT::CMStringT(CMStringDataFormat, const XCHAR* pszFormat, ...) : + CThisSimpleString() +{ + va_list args; + va_start(args, pszFormat); + FormatV(pszFormat, args); +} + +template< typename BaseType, class StringTraits > +CMStringT::CMStringT(const YCHAR* pszSrc) : + CThisSimpleString() +{ + *this = pszSrc; +} + +template< typename BaseType, class StringTraits > +CMStringT::CMStringT(const unsigned char* pszSrc) : + CThisSimpleString() +{ + *this = reinterpret_cast(pszSrc); +} + +template< typename BaseType, class StringTraits > +CMStringT::CMStringT(char ch, int nLength) : + CThisSimpleString() +{ + if (nLength > 0) { + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::FloodCharacters(XCHAR(ch), nLength, pszBuffer); + this->ReleaseBufferSetLength(nLength); + } +} + +template< typename BaseType, class StringTraits > +CMStringT::CMStringT(wchar_t ch, int nLength) : + CThisSimpleString() +{ + if (nLength > 0) { + //Convert ch to the BaseType + wchar_t pszCh[2] = { ch, 0 }; + int nBaseTypeCharLen = 1; + + if (ch != L'\0') + nBaseTypeCharLen = StringTraits::GetBaseTypeLength(pszCh); + + XCHAR *buffBaseTypeChar = new XCHAR[nBaseTypeCharLen + 1]; + StringTraits::ConvertToBaseType(buffBaseTypeChar, nBaseTypeCharLen + 1, pszCh, 1); + //allocate enough characters in String and flood (replicate) with the (converted character)*nLength + PXSTR pszBuffer = this->GetBuffer(nLength*nBaseTypeCharLen); + if (nBaseTypeCharLen == 1) //Optimization for a common case - wide char translates to 1 ansi/wide char. + StringTraits::FloodCharacters(buffBaseTypeChar[0], nLength, pszBuffer); + else { + XCHAR* p = pszBuffer; + for (int i = 0; i < nLength; i++) { + for (int j = 0; j < nBaseTypeCharLen; ++j) { + *p = buffBaseTypeChar[j]; + ++p; + } + } + } + this->ReleaseBufferSetLength(nLength*nBaseTypeCharLen); + delete[] buffBaseTypeChar; + } +} + +template< typename BaseType, class StringTraits > +CMStringT::CMStringT(const XCHAR* pch, int nLength) : + CThisSimpleString(pch, nLength) +{ +} + +template< typename BaseType, class StringTraits > +CMStringT::CMStringT(const YCHAR* pch, int nLength) : + CThisSimpleString() +{ + if (nLength > 0) { + int nDestLength = StringTraits::GetBaseTypeLength(pch, nLength); + PXSTR pszBuffer = this->GetBuffer(nDestLength); + StringTraits::ConvertToBaseType(pszBuffer, nDestLength, pch, nLength); + this->ReleaseBufferSetLength(nDestLength); + } +} + +// Destructor +template< typename BaseType, class StringTraits > +CMStringT::~CMStringT() +{ +} + +// Assignment operators +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::operator=(const CMStringT& strSrc) +{ + CThisSimpleString::operator=(strSrc); + return *this; +} + +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::operator=(PCXSTR pszSrc) +{ + CThisSimpleString::operator=(pszSrc); + return *this; +} + +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::operator=(PCYSTR pszSrc) +{ + // nDestLength is in XCHARs + int nDestLength = (pszSrc != nullptr) ? StringTraits::GetBaseTypeLength(pszSrc) : 0; + if (nDestLength > 0) { + PXSTR pszBuffer = this->GetBuffer(nDestLength); + StringTraits::ConvertToBaseType(pszBuffer, nDestLength, pszSrc); + this->ReleaseBufferSetLength(nDestLength); + } + else this->Empty(); + + return *this; +} + +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::operator=(const unsigned char* pszSrc) +{ + return operator=(reinterpret_cast(pszSrc)); +} + +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::operator=(char ch) +{ + char ach[2] = { ch, 0 }; + return operator=(ach); +} + +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::operator=(wchar_t ch) +{ + wchar_t ach[2] = { ch, 0 }; + return operator=(ach); +} + +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::operator+=(const CMStringT& str) +{ + CThisSimpleString::operator+=(str); + return *this; +} + +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::operator+=(const CThisSimpleString& str) +{ + CThisSimpleString::operator+=(str); + return *this; +} + +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::operator+=(PCXSTR pszSrc) +{ + CThisSimpleString::operator+=(pszSrc); + return *this; +} + +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::operator+=(PCYSTR pszSrc) +{ + CMStringT str(pszSrc); + return operator+=(str); +} + +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::operator+=(char ch) +{ + CThisSimpleString::operator+=(ch); + return *this; +} + +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::operator+=(unsigned char ch) +{ + CThisSimpleString::operator+=(ch); + return *this; +} + +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::operator+=(wchar_t ch) +{ + CThisSimpleString::operator+=(ch); + return *this; +} + +// Comparison + +template< typename BaseType, class StringTraits > +int CMStringT::Compare(PCXSTR psz) const +{ + return StringTraits::StringCompare(this->GetString(), psz); +} + +template< typename BaseType, class StringTraits > +int CMStringT::CompareNoCase(PCXSTR psz) const +{ + return StringTraits::StringCompareIgnore(this->GetString(), psz); +} + +template< typename BaseType, class StringTraits > +int CMStringT::Collate(PCXSTR psz) const +{ + return StringTraits::StringCollate(this->GetString(), psz); +} + +template< typename BaseType, class StringTraits > +int CMStringT::CollateNoCase(PCXSTR psz) const +{ + return StringTraits::StringCollateIgnore(this->GetString(), psz); +} + +// Advanced manipulation + +// Delete 'nCount' characters, starting at index 'iIndex' +template< typename BaseType, class StringTraits > +int CMStringT::Delete(int iIndex, int nCount) +{ + if (iIndex < 0) + iIndex = 0; + + if (nCount < 0) + nCount = 0; + + int nLength = this->GetLength(); + if (nCount + iIndex > nLength) + nCount = nLength - iIndex; + + if (nCount > 0) { + int nNewLength = nLength - nCount; + int nXCHARsToCopy = nLength - (iIndex + nCount) + 1; + PXSTR pszBuffer = this->GetBuffer(); +#if _MSC_VER >= 1400 + memmove_s(pszBuffer + iIndex, nXCHARsToCopy*sizeof(XCHAR), pszBuffer + iIndex + nCount, nXCHARsToCopy*sizeof(XCHAR)); +#else + memmove(pszBuffer+iIndex, pszBuffer+iIndex+nCount, nXCHARsToCopy*sizeof(XCHAR)); +#endif + this->ReleaseBufferSetLength(nNewLength); + } + + return this->GetLength(); +} + +// Insert character 'ch' before index 'iIndex' +template< typename BaseType, class StringTraits > +int CMStringT::Insert(int iIndex, XCHAR ch) +{ + if (iIndex < 0) + iIndex = 0; + + if (iIndex > this->GetLength()) + iIndex = this->GetLength(); + + int nNewLength = this->GetLength() + 1; + + PXSTR pszBuffer = this->GetBuffer(nNewLength); + + // move existing bytes down +#if _MSC_VER >= 1400 + memmove_s(pszBuffer + iIndex + 1, (nNewLength - iIndex)*sizeof(XCHAR), pszBuffer + iIndex, (nNewLength - iIndex)*sizeof(XCHAR)); +#else + memmove(pszBuffer+iIndex+1, pszBuffer+iIndex, (nNewLength-iIndex)*sizeof(XCHAR)); +#endif + pszBuffer[iIndex] = ch; + + this->ReleaseBufferSetLength(nNewLength); + return nNewLength; +} + +// Insert string 'psz' before index 'iIndex' +template< typename BaseType, class StringTraits > +int CMStringT::Insert(int iIndex, PCXSTR psz) +{ + if (iIndex < 0) + iIndex = 0; + + if (iIndex > this->GetLength()) + iIndex = this->GetLength(); + + // nInsertLength and nNewLength are in XCHARs + int nInsertLength = StringTraits::SafeStringLen(psz); + int nNewLength = this->GetLength(); + if (nInsertLength > 0) { + nNewLength += nInsertLength; + + PXSTR pszBuffer = this->GetBuffer(nNewLength); + // move existing bytes down +#if _MSC_VER >= 1400 + memmove_s(pszBuffer + iIndex + nInsertLength, (nNewLength - iIndex - nInsertLength + 1)*sizeof(XCHAR), pszBuffer + iIndex, (nNewLength - iIndex - nInsertLength + 1)*sizeof(XCHAR)); + memcpy_s(pszBuffer + iIndex, nInsertLength*sizeof(XCHAR), psz, nInsertLength*sizeof(XCHAR)); +#else + memmove(pszBuffer+iIndex+nInsertLength, pszBuffer+iIndex, (nNewLength-iIndex-nInsertLength+1)*sizeof(XCHAR)); + memcpy(pszBuffer+iIndex, psz, nInsertLength*sizeof(XCHAR)); +#endif + this->ReleaseBufferSetLength(nNewLength); + } + + return nNewLength; +} + +// Replace all occurrences of character 'chOld' with character 'chNew' +template< typename BaseType, class StringTraits > +int CMStringT::Replace(XCHAR chOld, XCHAR chNew) +{ + int nCount = 0; + + // short-circuit the nop case + if (chOld != chNew) { + // otherwise modify each character that matches in the string + bool bCopied = false; + PXSTR pszBuffer = const_cast(this->GetString()); // We don't actually write to pszBuffer until we've called GetBuffer(). + + int nLength = this->GetLength(); + int iChar = 0; + while (iChar < nLength) { + // replace instances of the specified character only + if (pszBuffer[iChar] == chOld) { + if (!bCopied) { + bCopied = true; + pszBuffer = this->GetBuffer(nLength); + } + pszBuffer[iChar] = chNew; + nCount++; + } + iChar = int(StringTraits::CharNext(pszBuffer + iChar) - pszBuffer); + } + + if (bCopied) + this->ReleaseBufferSetLength(nLength); + } + + return nCount; +} + +// Replace all occurrences of string 'pszOld' with string 'pszNew' +template< typename BaseType, class StringTraits > +int CMStringT::Replace(PCXSTR pszOld, PCXSTR pszNew) +{ + // can't have empty or NULL lpszOld + + // nSourceLen is in XCHARs + int nSourceLen = StringTraits::SafeStringLen(pszOld); + if (nSourceLen == 0) + return 0; + // nReplacementLen is in XCHARs + int nReplacementLen = StringTraits::SafeStringLen(pszNew); + + // loop once to figure out the size of the result string + int nCount = 0; + { + PCXSTR pszStart = this->GetString(); + PCXSTR pszEnd = pszStart + this->GetLength(); + while (pszStart < pszEnd) { + PCXSTR pszTarget; + while ((pszTarget = StringTraits::StringFindString(pszStart, pszOld)) != nullptr) { + nCount++; + pszStart = pszTarget + nSourceLen; + } + pszStart += StringTraits::SafeStringLen(pszStart) + 1; + } + } + + // if any changes were made, make them + if (nCount > 0) { + // if the buffer is too small, just + // allocate a new buffer (slow but sure) + int nOldLength = this->GetLength(); + int nNewLength = nOldLength + (nReplacementLen - nSourceLen)*nCount; + + PXSTR pszBuffer = this->GetBuffer(__max(nNewLength, nOldLength)); + + PXSTR pszStart = pszBuffer; + PXSTR pszEnd = pszStart + nOldLength; + + // loop again to actually do the work + while (pszStart < pszEnd) { + PXSTR pszTarget; + while ((pszTarget = StringTraits::StringFindString(pszStart, pszOld)) != nullptr) { + int nBalance = nOldLength - int(pszTarget - pszBuffer + nSourceLen); + memmove_s(pszTarget + nReplacementLen, nBalance*sizeof(XCHAR), + pszTarget + nSourceLen, nBalance*sizeof(XCHAR)); + memcpy_s(pszTarget, nReplacementLen*sizeof(XCHAR), + pszNew, nReplacementLen*sizeof(XCHAR)); + pszStart = pszTarget + nReplacementLen; + pszTarget[nReplacementLen + nBalance] = 0; + nOldLength += (nReplacementLen - nSourceLen); + } + pszStart += StringTraits::SafeStringLen(pszStart) + 1; + } + this->ReleaseBufferSetLength(nNewLength); + } + + return nCount; +} + +// Remove all occurrences of character 'chRemove' +template< typename BaseType, class StringTraits > +int CMStringT::Remove(XCHAR chRemove) +{ + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer(nLength); + + PXSTR pszSource = pszBuffer; + PXSTR pszDest = pszBuffer; + PXSTR pszEnd = pszBuffer + nLength; + + while (pszSource < pszEnd) { + PXSTR pszNewSource = StringTraits::CharNext(pszSource); + if (*pszSource != chRemove) { + // Copy the source to the destination. Remember to copy all bytes of an MBCS character + size_t NewSourceGap = (pszNewSource - pszSource); + PXSTR pszNewDest = pszDest + NewSourceGap; + for (size_t i = 0; pszDest != pszNewDest && i < NewSourceGap; i++) { + *pszDest = *pszSource; + pszSource++; + pszDest++; + } + } + pszSource = pszNewSource; + } + *pszDest = 0; + int nCount = int(pszSource - pszDest); + this->ReleaseBufferSetLength(nLength - nCount); + + return nCount; +} + +template< typename BaseType, class StringTraits > +CMStringT CMStringT::Tokenize(PCXSTR pszTokens, int& iStart) const +{ + if ((pszTokens == nullptr) || (*pszTokens == (XCHAR)0)) { + if (iStart < this->GetLength()) + return CMStringT(this->GetString() + iStart); + } + else { + PCXSTR pszPlace = this->GetString() + iStart; + PCXSTR pszEnd = this->GetString() + this->GetLength(); + if (pszPlace < pszEnd) { + int nIncluding = StringTraits::StringSpanIncluding(pszPlace, pszTokens); + + if ((pszPlace + nIncluding) < pszEnd) { + pszPlace += nIncluding; + int nExcluding = StringTraits::StringSpanExcluding(pszPlace, pszTokens); + + int iFrom = iStart + nIncluding; + int nUntil = nExcluding; + iStart = iFrom + nUntil + 1; + + return Mid(iFrom, nUntil); + } + } + } + + // return empty string, done tokenizing + iStart = -1; + + return CMStringT(); +} + +// find routines + +// Find the first occurrence of character 'ch', starting at index 'iStart' +template< typename BaseType, class StringTraits > +int CMStringT::Find(XCHAR ch, int iStart) const +{ + // nLength is in XCHARs + int nLength = this->GetLength(); + if (iStart < 0 || iStart >= nLength) + return -1; + + // find first single character + PCXSTR psz = StringTraits::StringFindChar(this->GetString() + iStart, ch); + + // return -1 if not found and index otherwise + return (psz == nullptr) ? -1 : int(psz - this->GetString()); +} + +// look for a specific sub-string + +// Find the first occurrence of string 'pszSub', starting at index 'iStart' +template< typename BaseType, class StringTraits > +int CMStringT::Find(PCXSTR pszSub, int iStart) const +{ + // iStart is in XCHARs + if (pszSub == nullptr) + return -1; + + // nLength is in XCHARs + int nLength = this->GetLength(); + if (iStart < 0 || iStart > nLength) + return -1; + + // find first matching substring + PCXSTR psz = StringTraits::StringFindString(this->GetString() + iStart, pszSub); + + // return -1 for not found, distance from beginning otherwise + return (psz == nullptr) ? -1 : int(psz - this->GetString()); +} + +// Find the first occurrence of any of the characters in string 'pszCharSet' +template< typename BaseType, class StringTraits > +int CMStringT::FindOneOf(PCXSTR pszCharSet) const +{ + PCXSTR psz = StringTraits::StringScanSet(this->GetString(), pszCharSet); + return (psz == nullptr) ? -1 : int(psz - this->GetString()); +} + +// Find the last occurrence of character 'ch' +template< typename BaseType, class StringTraits > +int CMStringT::ReverseFind(XCHAR ch) const +{ + // find last single character + PCXSTR psz = StringTraits::StringFindCharRev(this->GetString(), ch); + + // return -1 if not found, distance from beginning otherwise + return (psz == nullptr) ? -1 : int(psz - this->GetString()); +} + +// manipulation + +// Convert the string to uppercase +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::MakeUpper() +{ + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::StringUppercase(pszBuffer, nLength + 1); + this->ReleaseBufferSetLength(nLength); + + return *this; +} + +// Convert the string to lowercase +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::MakeLower() +{ + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::StringLowercase(pszBuffer, nLength + 1); + this->ReleaseBufferSetLength(nLength); + + return *this; +} + +// Reverse the string +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::MakeReverse() +{ + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::StringReverse(pszBuffer); + this->ReleaseBufferSetLength(nLength); + + return *this; +} + +// trimming + +// Remove all trailing whitespace +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::TrimRight() +{ + // find beginning of trailing spaces by starting + // at beginning (DBCS aware) + + PCXSTR psz = this->GetString(); + PCXSTR pszLast = nullptr; + + while (*psz != 0) { + if (StringTraits::IsSpace(*psz)) { + if (pszLast == nullptr) + pszLast = psz; + } + else pszLast = nullptr; + + psz = StringTraits::CharNext(psz); + } + + if (pszLast != nullptr) { + // truncate at trailing space start + int iLast = int(pszLast - this->GetString()); + + this->Truncate(iLast); + } + + return *this; +} + +// Remove all leading whitespace +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::TrimLeft() +{ + // find first non-space character + + PCXSTR psz = this->GetString(); + while (StringTraits::IsSpace(*psz)) + psz = StringTraits::CharNext(psz); + + if (psz != this->GetString()) { + // fix up data and length + int iFirst = int(psz - this->GetString()); + PXSTR pszBuffer = this->GetBuffer(this->GetLength()); + psz = pszBuffer + iFirst; + int nDataLength = this->GetLength() - iFirst; + memmove_s(pszBuffer, (this->GetLength() + 1)*sizeof(XCHAR), + psz, (nDataLength + 1)*sizeof(XCHAR)); + this->ReleaseBufferSetLength(nDataLength); + } + + return *this; +} + +// Remove all leading and trailing whitespace +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::Trim() +{ + return TrimRight().TrimLeft(); +} + +// Remove all leading and trailing occurrences of character 'chTarget' +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::Trim(XCHAR chTarget) +{ + return TrimRight(chTarget).TrimLeft(chTarget); +} + +// Remove all leading and trailing occurrences of any of the characters in the string 'pszTargets' +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::Trim(PCXSTR pszTargets) +{ + return TrimRight(pszTargets).TrimLeft(pszTargets); +} + +// trimming anything (either side) + +// Remove all trailing occurrences of character 'chTarget' +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::TrimRight(XCHAR chTarget) +{ + // find beginning of trailing matches + // by starting at beginning (DBCS aware) + + PCXSTR psz = this->GetString(); + PCXSTR pszLast = nullptr; + + while (*psz != 0) { + if (*psz == chTarget) { + if (pszLast == nullptr) + pszLast = psz; + } + else pszLast = nullptr; + + psz = StringTraits::CharNext(psz); + } + + if (pszLast != nullptr) { + // truncate at left-most matching character + int iLast = int(pszLast - this->GetString()); + this->Truncate(iLast); + } + + return *this; +} + +// Remove all trailing occurrences of any of the characters in string 'pszTargets' +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::TrimRight(PCXSTR pszTargets) +{ + // if we're not trimming anything, we're not doing any work + if ((pszTargets == nullptr) || (*pszTargets == 0)) { + return *this; + } + + // find beginning of trailing matches + // by starting at beginning (DBCS aware) + + PCXSTR psz = this->GetString(); + PCXSTR pszLast = nullptr; + + while (*psz != 0) { + if (StringTraits::StringFindChar(pszTargets, *psz) != nullptr) { + if (pszLast == nullptr) { + pszLast = psz; + } + } + else { + pszLast = nullptr; + } + psz = StringTraits::CharNext(psz); + } + + if (pszLast != nullptr) { + // truncate at left-most matching character + int iLast = int(pszLast - this->GetString()); + this->Truncate(iLast); + } + + return *this; +} + +// Remove all leading occurrences of character 'chTarget' +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::TrimLeft(XCHAR chTarget) +{ + // find first non-matching character + PCXSTR psz = this->GetString(); + + while (chTarget == *psz) { + psz = StringTraits::CharNext(psz); + } + + if (psz != this->GetString()) { + // fix up data and length + int iFirst = int(psz - this->GetString()); + PXSTR pszBuffer = this->GetBuffer(this->GetLength()); + psz = pszBuffer + iFirst; + int nDataLength = this->GetLength() - iFirst; + memmove_s(pszBuffer, (this->GetLength() + 1)*sizeof(XCHAR), + psz, (nDataLength + 1)*sizeof(XCHAR)); + this->ReleaseBufferSetLength(nDataLength); + } + + return *this; +} + +// Remove all leading occurrences of any of the characters in string 'pszTargets' +template< typename BaseType, class StringTraits > +CMStringT& CMStringT::TrimLeft(PCXSTR pszTargets) +{ + // if we're not trimming anything, we're not doing any work + if ((pszTargets == nullptr) || (*pszTargets == 0)) { + return *this; + } + + PCXSTR psz = this->GetString(); + while ((*psz != 0) && (StringTraits::StringFindChar(pszTargets, *psz) != nullptr)) { + psz = StringTraits::CharNext(psz); + } + + if (psz != this->GetString()) { + // fix up data and length + int iFirst = int(psz - this->GetString()); + PXSTR pszBuffer = this->GetBuffer(this->GetLength()); + psz = pszBuffer + iFirst; + int nDataLength = this->GetLength() - iFirst; + memmove_s(pszBuffer, (this->GetLength() + 1)*sizeof(XCHAR), + psz, (nDataLength + 1)*sizeof(XCHAR)); + this->ReleaseBufferSetLength(nDataLength); + } + + return *this; +} + +// Convert the string to the OEM character set +template< typename BaseType, class StringTraits > +void CMStringT::AnsiToOem() +{ + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::ConvertToOem(pszBuffer, nLength + 1); + this->ReleaseBufferSetLength(nLength); +} + +// Convert the string to the ANSI character set +template< typename BaseType, class StringTraits > +void CMStringT::OemToAnsi() +{ + int nLength = this->GetLength(); + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::ConvertToAnsi(pszBuffer, nLength + 1); + this->ReleaseBufferSetLength(nLength); +} + +// Very simple sub-string extraction + +// Return the substring starting at index 'iFirst' +template< typename BaseType, class StringTraits > +CMStringT CMStringT::Mid(int iFirst) const +{ + return Mid(iFirst, this->GetLength() - iFirst); +} + +// Return the substring starting at index 'iFirst', with length 'nCount' +template< typename BaseType, class StringTraits > +CMStringT CMStringT::Mid(int iFirst, int nCount) const +{ + // nCount is in XCHARs + + // out-of-bounds requests return sensible things + if (iFirst < 0) + iFirst = 0; + if (nCount < 0) + nCount = 0; + + if ((iFirst + nCount) > this->GetLength()) + nCount = this->GetLength() - iFirst; + + if (iFirst > this->GetLength()) + nCount = 0; + + // optimize case of returning entire string + if ((iFirst == 0) && ((iFirst + nCount) == this->GetLength())) + return *this; + + return CMStringT(this->GetString() + iFirst, nCount); +} + +// Return the substring consisting of the rightmost 'nCount' characters +template< typename BaseType, class StringTraits > +CMStringT CMStringT::Right(int nCount) const +{ + // nCount is in XCHARs + if (nCount < 0) + nCount = 0; + + int nLength = this->GetLength(); + if (nCount >= nLength) + return *this; + + return CMStringT(this->GetString() + nLength - nCount, nCount); +} + +// Return the substring consisting of the leftmost 'nCount' characters +template< typename BaseType, class StringTraits > +CMStringT CMStringT::Left(int nCount) const +{ + // nCount is in XCHARs + if (nCount < 0) + nCount = 0; + + int nLength = this->GetLength(); + if (nCount >= nLength) + return *this; + + return CMStringT(this->GetString(), nCount); +} + +// Return the substring consisting of the leftmost characters in the set 'pszCharSet' +template< typename BaseType, class StringTraits > +CMStringT CMStringT::SpanIncluding(PCXSTR pszCharSet) const +{ + return Left(StringTraits::StringSpanIncluding(this->GetString(), pszCharSet)); +} + +// Return the substring consisting of the leftmost characters not in the set 'pszCharSet' +template< typename BaseType, class StringTraits > +CMStringT CMStringT::SpanExcluding(PCXSTR pszCharSet) const +{ + return Left(StringTraits::StringSpanExcluding(this->GetString(), pszCharSet)); +} + +// Format data using format string 'pszFormat' +template< typename BaseType, class StringTraits > +typename CMStringT::PCXSTR CMStringT::Format(PCXSTR pszFormat, ...) +{ + va_list argList; + va_start(argList, pszFormat); + FormatV(pszFormat, argList); + va_end(argList); + return GetString(); +} + +// Append formatted data using format string 'pszFormat' +template< typename BaseType, class StringTraits > +typename CMStringT::PCXSTR CMStringT::AppendFormat(PCXSTR pszFormat, ...) +{ + va_list argList; + va_start(argList, pszFormat); + AppendFormatV(pszFormat, argList); + va_end(argList); + return GetString(); +} + +template< typename BaseType, class StringTraits > +void CMStringT::AppendFormatV(PCXSTR pszFormat, va_list args) +{ + int nCurrentLength = this->GetLength(); + int nAppendLength = StringTraits::GetFormattedLength(pszFormat, args); + PXSTR pszBuffer = this->GetBuffer(nCurrentLength + nAppendLength); + StringTraits::Format(pszBuffer + nCurrentLength, nAppendLength + 1, pszFormat, args); + this->ReleaseBufferSetLength(nCurrentLength + nAppendLength); +} + +template< typename BaseType, class StringTraits > +typename CMStringT::PCXSTR CMStringT::FormatV(PCXSTR pszFormat, va_list args) +{ + int nLength = StringTraits::GetFormattedLength(pszFormat, args); + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::Format(pszBuffer, nLength + 1, pszFormat, args); + this->ReleaseBufferSetLength(nLength); + return GetString(); +} + +// Set the string to the value of environment variable 'pszVar' +template< typename BaseType, class StringTraits > +BOOL CMStringT::GetEnvironmentVariable(PCXSTR pszVar) +{ + int nLength = StringTraits::GetEnvironmentVariable(pszVar, nullptr, 0); + BOOL bRetVal = FALSE; + + if (nLength == 0) + this->Empty(); + else { + PXSTR pszBuffer = this->GetBuffer(nLength); + StringTraits::GetEnvironmentVariable(pszVar, pszBuffer, nLength); + this->ReleaseBuffer(); + bRetVal = TRUE; + } + + return bRetVal; +} + +// Set the string to the value of environment variable 'pszVar' +template< typename BaseType, class StringTraits > +typename CMStringT::PXSTR CMStringT::Detach() const +{ + return StringTraits::MirCopy(CMStringT::GetString(), GetLength()); +} + +///////////////////////////////////////////////////////////////////////////////////////// + +template< typename BaseType, class StringTraits > +MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, const CMStringT& str2) +{ + CMStringT strResult; + CMStringT::Concatenate(strResult, str1, str1.GetLength(), str2, str2.GetLength()); + return strResult; +} + +template< typename BaseType, class StringTraits > +MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, typename CMStringT::PCXSTR psz2) +{ + CMStringT strResult; + CMStringT::Concatenate(strResult, str1, str1.GetLength(), psz2, CMStringT::StringLength(psz2)); + return strResult; +} + +template< typename BaseType, class StringTraits > +MIR_CORE_EXPORT CMStringT CALLBACK operator+(typename CMStringT::PCXSTR psz1, const CMStringT& str2) +{ + CMStringT strResult; + CMStringT::Concatenate(strResult, psz1, CMStringT::StringLength(psz1), str2, str2.GetLength()); + return strResult; +} + +template< typename BaseType, class StringTraits > +MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, wchar_t ch2) +{ + CMStringT strResult; + typename CMStringT::XCHAR chTemp = typename CMStringT::XCHAR(ch2); + CMStringT::Concatenate(strResult, str1, str1.GetLength(), &chTemp, 1); + return strResult; +} + +template< typename BaseType, class StringTraits > +MIR_CORE_EXPORT CMStringT CALLBACK operator+(const CMStringT& str1, char ch2) +{ + CMStringT strResult; + typename CMStringT::XCHAR chTemp = typename CMStringT::XCHAR(ch2); + CMStringT::Concatenate(strResult, str1, str1.GetLength(), &chTemp, 1); + return strResult; +} + +template< typename BaseType, class StringTraits > +MIR_CORE_EXPORT CMStringT CALLBACK operator+(wchar_t ch1, const CMStringT& str2) +{ + CMStringT strResult; + typename CMStringT::XCHAR chTemp = typename CMStringT::XCHAR(ch1); + CMStringT::Concatenate(strResult, &chTemp, 1, str2, str2.GetLength()); + return strResult; +} + +template< typename BaseType, class StringTraits > +MIR_CORE_EXPORT CMStringT CALLBACK operator+(char ch1, const CMStringT& str2) +{ + CMStringT strResult; + typename CMStringT::XCHAR chTemp = typename CMStringT::XCHAR(ch1); + CMStringT::Concatenate(strResult, &chTemp, 1, str2, str2.GetLength()); + return strResult; +} + +#endif // M_STRING_INL__ diff --git a/include/m_system.h b/include/m_system.h index 5226961d0f..9994da7c67 100644 --- a/include/m_system.h +++ b/include/m_system.h @@ -1,652 +1,654 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) -Copyright (c) 2000-08 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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. -*/ - -#pragma once - -#ifndef M_SYSTEM_H__ -#define M_SYSTEM_H__ 1 - -#ifndef MIRANDANAME - #define MIRANDANAME "Miranda NG" -#endif -#ifndef MIRANDACLASS - #define MIRANDACLASS "Miranda" -#endif - -// set the default compatibility lever for Miranda 0.4.x -#ifndef MIRANDA_VER - #define MIRANDA_VER 0x0A00 -#endif - -#ifndef _MSC_VER - #define __forceinline inline __attribute__ ((always_inline)) -#else - #pragma warning(disable:4244 4245) -#endif - -#define NEWSTR_ALLOCA(A) (A == NULL)?NULL:strcpy((char*)alloca(strlen(A)+1), A) -#define NEWWSTR_ALLOCA(A) ((A==NULL)?NULL:wcscpy((wchar_t*)alloca(sizeof(wchar_t)*(wcslen(A)+1)),A)) - -#include - -// miranda/system/modulesloaded -// called after all modules have been successfully initialised -// wParam = lParam = 0 -// used to resolve double-dependencies in the module load order -#define ME_SYSTEM_MODULESLOADED "Miranda/System/ModulesLoaded" - -// miranda/system/shutdown event -// called just before the application terminates -// the database is still guaranteed to be running during this hook. -// wParam = lParam = 0 -#define ME_SYSTEM_SHUTDOWN "Miranda/System/Shutdown" - -// restarts miranda (0.8+) -// wParam = 0 or 1. 1 - restart with current profile, 0 - restart in default profile or profile manager -// lParam = (wchar_t*)path to a new miranda32.exe binary or NULL to use current -#define MS_SYSTEM_RESTART "Miranda/System/Restart" - -// miranda/system/oktoexit event -// called before the app goes into shutdown routine to make sure everyone is -// happy to exit -// wParam = lParam = 0 -// return nonzero to stop the exit cycle -#define ME_SYSTEM_OKTOEXIT "Miranda/System/OkToExitEvent" - -// gets the version number of Miranda encoded as a DWORD -// returns the version number, encoded as one version per byte, therefore -// version 1.2.3.10 is 0x0102030a -EXTERN_C MIR_APP_DLL(DWORD) Miranda_GetVersion(void); - -// gets the version number of Miranda encoded as four WORDs v0.92.2+ -// returns the version number, encoded as one version per word, therefore -// version 1.2.3.3210 is 0x0001, 0x0002, 0x0003, 0x0C8a -typedef WORD MFileVersion[4]; -EXTERN_C MIR_APP_DLL(void) Miranda_GetFileVersion(MFileVersion*); - -// gets the version of Miranda encoded as text -// cch is the size of the buffer pointed to by pszVersion, in bytes -// may return a build qualifier, such as "0.1.0.1 alpha" -// returns 0 on success, nonzero on failure -EXTERN_C MIR_APP_DLL(void) Miranda_GetVersionText(char *pDest, size_t cbSize); - -// returns a system window that can handle global timers -// a usual practice is to use a unique pointer as a timer id -EXTERN_C MIR_APP_DLL(class CDlgBase *) Miranda_GetSystemWindow(); - -// Adds an event to the list to be checked in the main message loop -// when a handle gets triggered, an appopriate stub gets called -typedef void (CALLBACK *MWaitableStub)(void); -typedef void (CALLBACK *MWaitableStubEx)(void*); - -EXTERN_C MIR_APP_DLL(void) Miranda_WaitOnHandle(MWaitableStub pFunc, HANDLE hEvent = nullptr); -EXTERN_C MIR_APP_DLL(void) Miranda_WaitOnHandleEx(MWaitableStubEx pFunc, void *pInfo); - -// wParam = 0 (ignored) -// lParam = 0 (ignored) -// -// This hook is fired just before the thread unwind stack is used, -// it allows MT plugins to shutdown threads if they have any special -// processing to do, etc. -#define ME_SYSTEM_PRESHUTDOWN "Miranda/System/PShutdown" - -// Returns true when Miranda has got WM_QUIT and is in the process of shutting down -EXTERN_C MIR_APP_DLL(bool) Miranda_IsTerminated(void); - -// Check if everyone is happy to exit -// if everyone acknowleges OK to exit then returns true, otherwise false -EXTERN_C MIR_APP_DLL(bool) Miranda_OkToExit(void); - -// Used by contact lists inside CloseAction -// Waits for a permission to exit and destroys contact list -EXTERN_C MIR_APP_DLL(void) Miranda_Close(void); - -// Sets up a function pointer to be called after main loop iterations, suitable for idle processing -EXTERN_C MIR_APP_DLL(void) Miranda_SetIdleCallback(void(__cdecl *pfnCallback)(void)); - -// returns the last window tick where a monitored event was seen, currently WM_CHAR/WM_MOUSEMOVE -EXTERN_C MIR_APP_DLL(DWORD) Miranda_GetIdle(void); - -/////////////////////////////////////////////////////////////////////////////// - -#if defined(__cplusplus) - -#ifndef M_STRING_H__ - #include -#endif - -/////////////////////////////////////////////////////////////////////////////// -// general lists' templates - -struct MIR_CORE_EXPORT MNonCopyable -{ - __inline MNonCopyable() {} - - MNonCopyable(const MNonCopyable &) = delete; - MNonCopyable &operator=(const MNonCopyable &) = delete; -}; - -/////////////////////////////////////////////////////////////////////////////// -// mir_ptr - automatic pointer for buffers, allocated using mir_alloc/mir_calloc - -template class mir_ptr -{ -protected: - T *data; - -public: - __inline explicit mir_ptr() : data(nullptr) {} - __inline explicit mir_ptr(T *_p) : data(_p) {} - __inline ~mir_ptr() { mir_free(data); } - __inline T *get() const { return data; } - __inline T *operator=(T *_p) { if (data) mir_free(data); data = _p; return data; } - __inline T *operator->() const { return data; } - __inline operator T *() const { return data; } - __inline operator INT_PTR() const { return (INT_PTR)data; } - __inline T *detach() { T *res = data; data = nullptr; return res; } -}; - -typedef mir_ptr ptrA; -typedef mir_ptr ptrW; - -/////////////////////////////////////////////////////////////////////////////// -// mir_cs - simple wrapper for the critical sections - -class MIR_CORE_EXPORT mir_cs : public MNonCopyable -{ - CRITICAL_SECTION m_cs; - -public: - mir_cs(); - ~mir_cs(); - - void Lock(); - void Unlock(); -}; - -/////////////////////////////////////////////////////////////////////////////// -// mir_cslock - simple locker for the critical sections - -class mir_cslock : public MNonCopyable -{ - mir_cs &cs; - -public: - __inline mir_cslock(mir_cs &_cs) : cs(_cs) { cs.Lock(); } - __inline ~mir_cslock() { cs.Unlock(); } -}; - -class mir_cslockfull : public MNonCopyable -{ - mir_cs &cs; - bool bIsLocked = false; - -public: - __inline void lock() { bIsLocked = true; cs.Lock(); } - __inline void unlock() { bIsLocked = false; cs.Unlock(); } - - __inline mir_cslockfull(mir_cs &_cs) : cs(_cs) { lock(); } - __inline ~mir_cslockfull() { if (bIsLocked) unlock(); } -}; - -////////////////////////////////////////////////////////////////////////////// -//pass_ptrA, pass_ptrW and pass_ptrT - automatic pointer for passwords - -class pass_ptrA : public mir_ptr -{ -public: - __inline explicit pass_ptrA() : mir_ptr() {} - __inline explicit pass_ptrA(char *_p) : mir_ptr(_p) {} - __inline ~pass_ptrA() { zero(); } - __inline char *operator=(char *_p) { zero(); return mir_ptr::operator=(_p); } - __inline void zero() - { - if (data) SecureZeroMemory(data, mir_strlen(data)); - } -}; - -class pass_ptrW : public mir_ptr -{ -public: - __inline explicit pass_ptrW() : mir_ptr() {} - __inline explicit pass_ptrW(wchar_t *_p) : mir_ptr(_p) {} - __inline ~pass_ptrW() { zero(); } - __inline wchar_t *operator=(wchar_t *_p) { zero(); return mir_ptr::operator=(_p); } - __inline void zero() - { - if (data) SecureZeroMemory(data, mir_wstrlen(data) * sizeof(wchar_t)); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// basic class for classes that should be cleared inside new() - -class MZeroedObject -{ -public: - __inline void *operator new(size_t size) - { - return calloc(1, size); - } - - __inline void operator delete(void *p) - { - free(p); - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// general lists' templates - -#define NumericKeySortT -1 -#define HandleKeySortT -2 -#define PtrKeySortT -3 - -template struct LIST -{ - typedef int (*FTSortFunc)(const T *p1, const T *p2); - - __inline LIST(int aincr, FTSortFunc afunc = nullptr) - { - memset(this, 0, sizeof(*this)); - increment = aincr; - sortFunc = afunc; - } - - __inline LIST(int aincr, INT_PTR id) - { - memset(this, 0, sizeof(*this)); - increment = aincr; - sortFunc = FTSortFunc(id); - } - - __inline LIST(const LIST &x) - { - items = nullptr; - List_Copy((SortedList *)&x, (SortedList *)this, sizeof(T)); - } - - __inline LIST &operator = (const LIST &x) - { - destroy(); - List_Copy((SortedList *)&x, (SortedList *)this, sizeof(T)); - return *this; - } - - __inline ~LIST() - { - destroy(); - } - - __inline T *operator[](int idx) const { return (idx >= 0 && idx < count) ? items[idx] : nullptr; } - __inline int getCount(void) const { return count; } - __inline T **getArray(void) const { return items; } - - __inline int getIndex(T *p) const - { - int idx; - return (!List_GetIndex((SortedList *)this, p, &idx)) ? -1 : idx; - } - - class reverse_iterator - { - int index; - T **base; - - public: - reverse_iterator(const LIST &_lst) : - index(_lst.getCount() - 1), - base(_lst.getArray()) - { - } - - class iterator - { - T **ptr; - - public: - iterator(T **_p) : ptr(_p) {} - iterator operator++() { --ptr; return *this; } - bool operator!=(const iterator &p) { return ptr != p.ptr; } - operator T **() const { return ptr; } - }; - - __inline iterator begin() const { return iterator(base + index); } - __inline iterator end() const { return iterator(base - 1); } - __inline int indexOf(T **p) const { return int(p - base); } - }; - - __inline void destroy(void) { List_Destroy((SortedList *)this); } - __inline T* find(T *p) const { return (T *)List_Find((SortedList *)this, p); } - __inline int indexOf(T *p) const { return List_IndexOf((SortedList *)this, p); } - __inline int insert(T *p, int idx) { return List_Insert((SortedList *)this, p, idx); } - __inline int remove(int idx) { return List_Remove((SortedList *)this, idx); } - - __inline int insert(T *p) { return List_InsertPtr((SortedList *)this, p); } - __inline int remove(T *p) { return List_RemovePtr((SortedList *)this, p); } - - __inline int indexOf(T **p) const { return int(p - items); } - - __inline T* removeItem(T **p) - { - T *savePtr = *p; - List_Remove((SortedList *)this, int(p - items)); - return savePtr; - } - - __inline void put(int idx, T *p) { items[idx] = p; } - - __inline T **begin() const { return items; } - __inline T **end() const { return items + count; } - - __inline reverse_iterator rev_iter() const { return reverse_iterator(*this); } - -protected: - T **items; - int count, limit, increment; - FTSortFunc sortFunc; -}; - -template struct OBJLIST : public LIST -{ - typedef int (*FTSortFunc)(const T *p1, const T *p2); - - __inline OBJLIST(int aincr, FTSortFunc afunc = nullptr) : - LIST(aincr, afunc) - { - } - - __inline OBJLIST(int aincr, INT_PTR id) : - LIST(aincr, (FTSortFunc)id) - { - } - - __inline OBJLIST(const OBJLIST &x) : - LIST(x.increment, x.sortFunc) - { - this->items = nullptr; - List_ObjCopy((SortedList *)&x, (SortedList *)this, sizeof(T)); - } - - __inline OBJLIST &operator = (const OBJLIST &x) - { - destroy(); - List_ObjCopy((SortedList *)&x, (SortedList *)this, sizeof(T)); - return *this; - } - - ~OBJLIST() - { - destroy(); - } - - __inline void destroy(void) - { - for (int i = 0; i < this->count; i++) - delete this->items[i]; - - List_Destroy((SortedList *)this); - } - - __inline int remove(int idx) - { - delete this->items[idx]; - return List_Remove((SortedList *)this, idx); - } - - __inline int remove(T *p) - { - int i = this->getIndex(p); - if (i != -1) { - remove(i); - return 1; - } - return 0; - } - - __inline T &operator[](int idx) const { return *this->items[idx]; } -}; - -#define __A2W(s) L ## s -#define _A2W(s) __A2W(s) - -class _A2T : public ptrW -{ -public: - __inline _A2T(const char *s) : ptrW(mir_a2u(s)) {} - __inline _A2T(const char *s, int cp) : ptrW(mir_a2u_cp(s, cp)) {} -}; - -class _T2A : public ptrA -{ -public: - __forceinline _T2A(const wchar_t *s) : ptrA(mir_u2a(s)) {} - __forceinline _T2A(const wchar_t *s, int cp) : ptrA(mir_u2a_cp(s, cp)) {} -}; - -class T2Utf : public ptrA -{ -public: - __forceinline T2Utf(const wchar_t *str) : ptrA(mir_utf8encodeW(str)) {} - __forceinline operator BYTE *() const { return (BYTE *)data; } -#ifdef _XSTRING_ - std::string str() const { return std::string(data); } -#endif -}; - -class Utf2T : public ptrW -{ -public: - __forceinline Utf2T(const char *str) : ptrW(mir_utf8decodeW(str)) {} - __forceinline operator wchar_t *() const { return data; } -#ifdef _XSTRING_ - std::wstring str() const { return std::wstring(data); } -#endif -}; - -/////////////////////////////////////////////////////////////////////////////// -// basic class for classes that should be cleared inside new() - -class MIR_CORE_EXPORT MBinBuffer -{ - char *m_buf; - size_t m_len; - -public: - MBinBuffer(); - ~MBinBuffer(); - - __forceinline char *data() const { return m_buf; } - __forceinline bool isEmpty() const { return m_len == 0; } - __forceinline size_t length() const { return m_len; } - - // adds a buffer to the end - void append(const void *pBuf, size_t bufLen); - - // adds a buffer to the beginning - void appendBefore(const void *pBuf, size_t bufLen); - - // replaces buffer contents - void assign(const void *pBuf, size_t bufLen); - - // drops a part of buffer - void remove(size_t sz); -}; - -/////////////////////////////////////////////////////////////////////////////// -// thread handle controller - -class MThreadLock -{ - HANDLE &m_pHandle; - -public: - __forceinline MThreadLock(HANDLE &pHandle) : - m_pHandle(pHandle) - { - } - - __forceinline ~MThreadLock() - { - m_pHandle = nullptr; - } -}; - -/////////////////////////////////////////////////////////////////////////////// -// parameter classes for XML, JSON & HTTP requests - -struct PARAM -{ - const char *szName; - __forceinline PARAM(const char *_name) : szName(_name) - { - } -}; - -struct BOOL_PARAM : public PARAM -{ - bool bValue; - __forceinline BOOL_PARAM(const char *_name, bool _value) : - PARAM(_name), bValue(_value) - { - } -}; - -struct INT_PARAM : public PARAM -{ - int32_t iValue; - __forceinline INT_PARAM(const char *_name, int32_t _value) : - PARAM(_name), iValue(_value) - { - } -}; - -struct INT64_PARAM : public PARAM -{ - int64_t iValue; - __forceinline INT64_PARAM(const char *_name, int64_t _value) : - PARAM(_name), iValue(_value) - { - } -}; - -struct SINT64_PARAM : public PARAM -{ - int64_t iValue; - __forceinline SINT64_PARAM(const char *_name, int64_t _value) : - PARAM(_name), iValue(_value) - { - } -}; - -struct CHAR_PARAM : public PARAM -{ - const char *szValue; - __forceinline CHAR_PARAM(const char *_name, const char *_value) : - PARAM(_name), szValue(_value) - { - } -}; - -struct WCHAR_PARAM : public PARAM -{ - const wchar_t *wszValue; - __forceinline WCHAR_PARAM(const char *_name, const wchar_t *_value) : - PARAM(_name), wszValue(_value) - { - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Callbacks - -class CCallbackImp -{ - struct CDummy - { - int foo; - }; - - typedef void (CDummy:: *TFnCallback)(void *argument); - - CDummy *m_object; - TFnCallback m_func; - -protected: - template - __inline CCallbackImp(TClass *object, void (TClass:: *func)(TArgument *argument)) : - m_object((CDummy *)object), - m_func((TFnCallback)func) - { - } - - __inline void Invoke(void *argument) const { if (m_func && m_object) (m_object->*m_func)(argument); } - -public: - __inline CCallbackImp() : m_object(nullptr), m_func(nullptr) {} - - __inline CCallbackImp(const CCallbackImp &other) : m_object(other.m_object), m_func(other.m_func) {} - __inline CCallbackImp &operator=(const CCallbackImp &other) { m_object = other.m_object; m_func = other.m_func; return *this; } - - __inline bool operator==(const CCallbackImp &other) const { return (m_object == other.m_object) && (m_func == other.m_func); } - __inline bool operator!=(const CCallbackImp &other) const { return (m_object != other.m_object) || (m_func != other.m_func); } - - __inline operator bool() const { return m_object && m_func; } -}; - -template -struct CCallback : public CCallbackImp -{ - typedef CCallbackImp CSuper; - -public: - __inline CCallback() {} - - template - __inline CCallback(TClass *object, void (TClass:: *func)(TArgument *argument)) : CCallbackImp(object, func) {} - - __inline CCallback &operator=(const CCallbackImp &x) { CSuper::operator =(x); return *this; } - - __inline void operator()(TArgument *argument) const { Invoke((void *)argument); } -}; - -template -__inline CCallback Callback(TClass *object, void (TClass:: *func)(TArgument *argument)) -{ - return CCallback(object, func); -} - -/////////////////////////////////////////////////////////////////////////////// -// http support - -// works inline, in the same buffer, thus destroying its contents -// returns the address of buffer passed - -MIR_CORE_DLL(char *) mir_urlDecode(char *szUrl); - -MIR_CORE_DLL(CMStringA) mir_urlEncode(const char *szUrl); - -#endif // __cpluscplus - -#endif // M_SYSTEM_H +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2000-08 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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. +*/ + +#pragma once + +#ifndef M_SYSTEM_H__ +#define M_SYSTEM_H__ 1 + +#ifndef MIRANDANAME + #define MIRANDANAME "Miranda NG" +#endif +#ifndef MIRANDACLASS + #define MIRANDACLASS "Miranda" +#endif + +// set the default compatibility lever for Miranda 0.4.x +#ifndef MIRANDA_VER + #define MIRANDA_VER 0x0A00 +#endif + +#ifndef _MSC_VER + #define __forceinline inline __attribute__ ((always_inline)) +#else + #pragma warning(disable:4244 4245) +#endif + +#define NEWSTR_ALLOCA(A) (A == NULL)?NULL:strcpy((char*)alloca(strlen(A)+1), A) +#define NEWWSTR_ALLOCA(A) ((A==NULL)?NULL:wcscpy((wchar_t*)alloca(sizeof(wchar_t)*(wcslen(A)+1)),A)) + +#include + +// miranda/system/modulesloaded +// called after all modules have been successfully initialised +// wParam = lParam = 0 +// used to resolve double-dependencies in the module load order +#define ME_SYSTEM_MODULESLOADED "Miranda/System/ModulesLoaded" + +// miranda/system/shutdown event +// called just before the application terminates +// the database is still guaranteed to be running during this hook. +// wParam = lParam = 0 +#define ME_SYSTEM_SHUTDOWN "Miranda/System/Shutdown" + +// restarts miranda (0.8+) +// wParam = 0 or 1. 1 - restart with current profile, 0 - restart in default profile or profile manager +// lParam = (wchar_t*)path to a new miranda32.exe binary or NULL to use current +#define MS_SYSTEM_RESTART "Miranda/System/Restart" + +// miranda/system/oktoexit event +// called before the app goes into shutdown routine to make sure everyone is +// happy to exit +// wParam = lParam = 0 +// return nonzero to stop the exit cycle +#define ME_SYSTEM_OKTOEXIT "Miranda/System/OkToExitEvent" + +// gets the version number of Miranda encoded as a DWORD +// returns the version number, encoded as one version per byte, therefore +// version 1.2.3.10 is 0x0102030a +EXTERN_C MIR_APP_DLL(DWORD) Miranda_GetVersion(void); + +// gets the version number of Miranda encoded as four WORDs v0.92.2+ +// returns the version number, encoded as one version per word, therefore +// version 1.2.3.3210 is 0x0001, 0x0002, 0x0003, 0x0C8a +typedef uint16_t MFileVersion[4]; +EXTERN_C MIR_APP_DLL(void) Miranda_GetFileVersion(MFileVersion*); + +// gets the version of Miranda encoded as text +// cch is the size of the buffer pointed to by pszVersion, in bytes +// may return a build qualifier, such as "0.1.0.1 alpha" +// returns 0 on success, nonzero on failure +EXTERN_C MIR_APP_DLL(void) Miranda_GetVersionText(char *pDest, size_t cbSize); + +// returns a system window that can handle global timers +// a usual practice is to use a unique pointer as a timer id +EXTERN_C MIR_APP_DLL(class CDlgBase *) Miranda_GetSystemWindow(); + +// Adds an event to the list to be checked in the main message loop +// when a handle gets triggered, an appopriate stub gets called +typedef void (CALLBACK *MWaitableStub)(void); +typedef void (CALLBACK *MWaitableStubEx)(void*); + +EXTERN_C MIR_APP_DLL(void) Miranda_WaitOnHandle(MWaitableStub pFunc, HANDLE hEvent = nullptr); +EXTERN_C MIR_APP_DLL(void) Miranda_WaitOnHandleEx(MWaitableStubEx pFunc, void *pInfo); + +// wParam = 0 (ignored) +// lParam = 0 (ignored) +// +// This hook is fired just before the thread unwind stack is used, +// it allows MT plugins to shutdown threads if they have any special +// processing to do, etc. +#define ME_SYSTEM_PRESHUTDOWN "Miranda/System/PShutdown" + +// Returns true when Miranda has got WM_QUIT and is in the process of shutting down +EXTERN_C MIR_APP_DLL(bool) Miranda_IsTerminated(void); + +// Check if everyone is happy to exit +// if everyone acknowleges OK to exit then returns true, otherwise false +EXTERN_C MIR_APP_DLL(bool) Miranda_OkToExit(void); + +// Used by contact lists inside CloseAction +// Waits for a permission to exit and destroys contact list +EXTERN_C MIR_APP_DLL(void) Miranda_Close(void); + +// Sets up a function pointer to be called after main loop iterations, suitable for idle processing +EXTERN_C MIR_APP_DLL(void) Miranda_SetIdleCallback(void(MIR_CDECL *pfnCallback)(void)); + +// returns the last window tick where a monitored event was seen, currently WM_CHAR/WM_MOUSEMOVE +EXTERN_C MIR_APP_DLL(DWORD) Miranda_GetIdle(void); + +/////////////////////////////////////////////////////////////////////////////// + +#if defined(__cplusplus) + +#ifndef M_STRING_H__ + #include +#endif + +/////////////////////////////////////////////////////////////////////////////// +// general lists' templates + +struct MIR_CORE_EXPORT MNonCopyable +{ + __inline MNonCopyable() {} + + MNonCopyable(const MNonCopyable &) = delete; + MNonCopyable &operator=(const MNonCopyable &) = delete; +}; + +/////////////////////////////////////////////////////////////////////////////// +// mir_ptr - automatic pointer for buffers, allocated using mir_alloc/mir_calloc + +template class mir_ptr +{ +protected: + T *data; + +public: + __inline explicit mir_ptr() : data(nullptr) {} + __inline explicit mir_ptr(T *_p) : data(_p) {} + __inline ~mir_ptr() { mir_free(data); } + __inline T *get() const { return data; } + __inline T *operator=(T *_p) { if (data) mir_free(data); data = _p; return data; } + __inline T *operator->() const { return data; } + __inline operator T *() const { return data; } + __inline operator INT_PTR() const { return (INT_PTR)data; } + __inline T *detach() { T *res = data; data = nullptr; return res; } +}; + +typedef mir_ptr ptrA; +typedef mir_ptr ptrW; + +/////////////////////////////////////////////////////////////////////////////// +// mir_cs - simple wrapper for the critical sections + +class MIR_CORE_EXPORT mir_cs : public MNonCopyable +{ + #ifdef _MSC_VER + CRITICAL_SECTION m_cs; + #endif + +public: + mir_cs(); + ~mir_cs(); + + void Lock(); + void Unlock(); +}; + +/////////////////////////////////////////////////////////////////////////////// +// mir_cslock - simple locker for the critical sections + +class mir_cslock : public MNonCopyable +{ + mir_cs &cs; + +public: + __inline mir_cslock(mir_cs &_cs) : cs(_cs) { cs.Lock(); } + __inline ~mir_cslock() { cs.Unlock(); } +}; + +class mir_cslockfull : public MNonCopyable +{ + mir_cs &cs; + bool bIsLocked = false; + +public: + __inline void lock() { bIsLocked = true; cs.Lock(); } + __inline void unlock() { bIsLocked = false; cs.Unlock(); } + + __inline mir_cslockfull(mir_cs &_cs) : cs(_cs) { lock(); } + __inline ~mir_cslockfull() { if (bIsLocked) unlock(); } +}; + +////////////////////////////////////////////////////////////////////////////// +//pass_ptrA, pass_ptrW and pass_ptrT - automatic pointer for passwords + +class pass_ptrA : public mir_ptr +{ +public: + __inline explicit pass_ptrA() : mir_ptr() {} + __inline explicit pass_ptrA(char *_p) : mir_ptr(_p) {} + __inline ~pass_ptrA() { zero(); } + __inline char *operator=(char *_p) { zero(); return mir_ptr::operator=(_p); } + __inline void zero() + { + if (data) SecureZeroMemory(data, mir_strlen(data)); + } +}; + +class pass_ptrW : public mir_ptr +{ +public: + __inline explicit pass_ptrW() : mir_ptr() {} + __inline explicit pass_ptrW(wchar_t *_p) : mir_ptr(_p) {} + __inline ~pass_ptrW() { zero(); } + __inline wchar_t *operator=(wchar_t *_p) { zero(); return mir_ptr::operator=(_p); } + __inline void zero() + { + if (data) SecureZeroMemory(data, mir_wstrlen(data) * sizeof(wchar_t)); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// basic class for classes that should be cleared inside new() + +class MZeroedObject +{ +public: + __inline void *operator new(size_t size) + { + return calloc(1, size); + } + + __inline void operator delete(void *p) + { + free(p); + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// general lists' templates + +#define NumericKeySortT -1 +#define HandleKeySortT -2 +#define PtrKeySortT -3 + +template struct LIST +{ + typedef int (*FTSortFunc)(const T *p1, const T *p2); + + __inline LIST(int aincr, FTSortFunc afunc = nullptr) + { + memset(this, 0, sizeof(*this)); + increment = aincr; + sortFunc = afunc; + } + + __inline LIST(int aincr, INT_PTR id) + { + memset(this, 0, sizeof(*this)); + increment = aincr; + sortFunc = FTSortFunc(id); + } + + __inline LIST(const LIST &x) + { + items = nullptr; + List_Copy((SortedList *)&x, (SortedList *)this, sizeof(T)); + } + + __inline LIST &operator = (const LIST &x) + { + destroy(); + List_Copy((SortedList *)&x, (SortedList *)this, sizeof(T)); + return *this; + } + + __inline ~LIST() + { + destroy(); + } + + __inline T *operator[](int idx) const { return (idx >= 0 && idx < count) ? items[idx] : nullptr; } + __inline int getCount(void) const { return count; } + __inline T **getArray(void) const { return items; } + + __inline int getIndex(T *p) const + { + int idx; + return (!List_GetIndex((SortedList *)this, p, &idx)) ? -1 : idx; + } + + class reverse_iterator + { + int index; + T **base; + + public: + reverse_iterator(const LIST &_lst) : + index(_lst.getCount() - 1), + base(_lst.getArray()) + { + } + + class iterator + { + T **ptr; + + public: + iterator(T **_p) : ptr(_p) {} + iterator operator++() { --ptr; return *this; } + bool operator!=(const iterator &p) { return ptr != p.ptr; } + operator T **() const { return ptr; } + }; + + __inline iterator begin() const { return iterator(base + index); } + __inline iterator end() const { return iterator(base - 1); } + __inline int indexOf(T **p) const { return int(p - base); } + }; + + __inline void destroy(void) { List_Destroy((SortedList *)this); } + __inline T* find(T *p) const { return (T *)List_Find((SortedList *)this, p); } + __inline int indexOf(T *p) const { return List_IndexOf((SortedList *)this, p); } + __inline int insert(T *p, int idx) { return List_Insert((SortedList *)this, p, idx); } + __inline int remove(int idx) { return List_Remove((SortedList *)this, idx); } + + __inline int insert(T *p) { return List_InsertPtr((SortedList *)this, p); } + __inline int remove(T *p) { return List_RemovePtr((SortedList *)this, p); } + + __inline int indexOf(T **p) const { return int(p - items); } + + __inline T* removeItem(T **p) + { + T *savePtr = *p; + List_Remove((SortedList *)this, int(p - items)); + return savePtr; + } + + __inline void put(int idx, T *p) { items[idx] = p; } + + __inline T **begin() const { return items; } + __inline T **end() const { return items + count; } + + __inline reverse_iterator rev_iter() const { return reverse_iterator(*this); } + +protected: + T **items; + int count, limit, increment; + FTSortFunc sortFunc; +}; + +template struct OBJLIST : public LIST +{ + typedef int (*FTSortFunc)(const T *p1, const T *p2); + + __inline OBJLIST(int aincr, FTSortFunc afunc = nullptr) : + LIST(aincr, afunc) + { + } + + __inline OBJLIST(int aincr, INT_PTR id) : + LIST(aincr, (FTSortFunc)id) + { + } + + __inline OBJLIST(const OBJLIST &x) : + LIST(x.increment, x.sortFunc) + { + this->items = nullptr; + List_ObjCopy((SortedList *)&x, (SortedList *)this, sizeof(T)); + } + + __inline OBJLIST &operator = (const OBJLIST &x) + { + destroy(); + List_ObjCopy((SortedList *)&x, (SortedList *)this, sizeof(T)); + return *this; + } + + ~OBJLIST() + { + destroy(); + } + + __inline void destroy(void) + { + for (int i = 0; i < this->count; i++) + delete this->items[i]; + + List_Destroy((SortedList *)this); + } + + __inline int remove(int idx) + { + delete this->items[idx]; + return List_Remove((SortedList *)this, idx); + } + + __inline int remove(T *p) + { + int i = this->getIndex(p); + if (i != -1) { + remove(i); + return 1; + } + return 0; + } + + __inline T &operator[](int idx) const { return *this->items[idx]; } +}; + +#define __A2W(s) L ## s +#define _A2W(s) __A2W(s) + +class _A2T : public ptrW +{ +public: + __inline _A2T(const char *s) : ptrW(mir_a2u(s)) {} + __inline _A2T(const char *s, int cp) : ptrW(mir_a2u_cp(s, cp)) {} +}; + +class _T2A : public ptrA +{ +public: + __forceinline _T2A(const wchar_t *s) : ptrA(mir_u2a(s)) {} + __forceinline _T2A(const wchar_t *s, int cp) : ptrA(mir_u2a_cp(s, cp)) {} +}; + +class T2Utf : public ptrA +{ +public: + __forceinline T2Utf(const wchar_t *str) : ptrA(mir_utf8encodeW(str)) {} + __forceinline operator BYTE *() const { return (BYTE *)data; } +#ifdef _XSTRING_ + std::string str() const { return std::string(data); } +#endif +}; + +class Utf2T : public ptrW +{ +public: + __forceinline Utf2T(const char *str) : ptrW(mir_utf8decodeW(str)) {} + __forceinline operator wchar_t *() const { return data; } +#ifdef _XSTRING_ + std::wstring str() const { return std::wstring(data); } +#endif +}; + +/////////////////////////////////////////////////////////////////////////////// +// basic class for classes that should be cleared inside new() + +class MIR_CORE_EXPORT MBinBuffer +{ + char *m_buf; + size_t m_len; + +public: + MBinBuffer(); + ~MBinBuffer(); + + __forceinline char *data() const { return m_buf; } + __forceinline bool isEmpty() const { return m_len == 0; } + __forceinline size_t length() const { return m_len; } + + // adds a buffer to the end + void append(const void *pBuf, size_t bufLen); + + // adds a buffer to the beginning + void appendBefore(const void *pBuf, size_t bufLen); + + // replaces buffer contents + void assign(const void *pBuf, size_t bufLen); + + // drops a part of buffer + void remove(size_t sz); +}; + +/////////////////////////////////////////////////////////////////////////////// +// thread handle controller + +class MThreadLock +{ + HANDLE &m_pHandle; + +public: + __forceinline MThreadLock(HANDLE &pHandle) : + m_pHandle(pHandle) + { + } + + __forceinline ~MThreadLock() + { + m_pHandle = nullptr; + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// parameter classes for XML, JSON & HTTP requests + +struct PARAM +{ + const char *szName; + __forceinline PARAM(const char *_name) : szName(_name) + { + } +}; + +struct BOOL_PARAM : public PARAM +{ + bool bValue; + __forceinline BOOL_PARAM(const char *_name, bool _value) : + PARAM(_name), bValue(_value) + { + } +}; + +struct INT_PARAM : public PARAM +{ + int32_t iValue; + __forceinline INT_PARAM(const char *_name, int32_t _value) : + PARAM(_name), iValue(_value) + { + } +}; + +struct INT64_PARAM : public PARAM +{ + int64_t iValue; + __forceinline INT64_PARAM(const char *_name, int64_t _value) : + PARAM(_name), iValue(_value) + { + } +}; + +struct SINT64_PARAM : public PARAM +{ + int64_t iValue; + __forceinline SINT64_PARAM(const char *_name, int64_t _value) : + PARAM(_name), iValue(_value) + { + } +}; + +struct CHAR_PARAM : public PARAM +{ + const char *szValue; + __forceinline CHAR_PARAM(const char *_name, const char *_value) : + PARAM(_name), szValue(_value) + { + } +}; + +struct WCHAR_PARAM : public PARAM +{ + const wchar_t *wszValue; + __forceinline WCHAR_PARAM(const char *_name, const wchar_t *_value) : + PARAM(_name), wszValue(_value) + { + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Callbacks + +class CCallbackImp +{ + struct CDummy + { + int foo; + }; + + typedef void (CDummy:: *TFnCallback)(void *argument); + + CDummy *m_object; + TFnCallback m_func; + +protected: + template + __inline CCallbackImp(TClass *object, void (TClass:: *func)(TArgument *argument)) : + m_object((CDummy *)object), + m_func((TFnCallback)func) + { + } + + __inline void Invoke(void *argument) const { if (m_func && m_object) (m_object->*m_func)(argument); } + +public: + __inline CCallbackImp() : m_object(nullptr), m_func(nullptr) {} + + __inline CCallbackImp(const CCallbackImp &other) : m_object(other.m_object), m_func(other.m_func) {} + __inline CCallbackImp &operator=(const CCallbackImp &other) { m_object = other.m_object; m_func = other.m_func; return *this; } + + __inline bool operator==(const CCallbackImp &other) const { return (m_object == other.m_object) && (m_func == other.m_func); } + __inline bool operator!=(const CCallbackImp &other) const { return (m_object != other.m_object) || (m_func != other.m_func); } + + __inline operator bool() const { return m_object && m_func; } +}; + +template +struct CCallback : public CCallbackImp +{ + typedef CCallbackImp CSuper; + +public: + __inline CCallback() {} + + template + __inline CCallback(TClass *object, void (TClass:: *func)(TArgument *argument)) : CCallbackImp(object, func) {} + + __inline CCallback &operator=(const CCallbackImp &x) { CSuper::operator =(x); return *this; } + + __inline void operator()(TArgument *argument) const { Invoke((void *)argument); } +}; + +template +__inline CCallback Callback(TClass *object, void (TClass:: *func)(TArgument *argument)) +{ + return CCallback(object, func); +} + +/////////////////////////////////////////////////////////////////////////////// +// http support + +// works inline, in the same buffer, thus destroying its contents +// returns the address of buffer passed + +MIR_CORE_DLL(char *) mir_urlDecode(char *szUrl); + +MIR_CORE_DLL(CMStringA) mir_urlEncode(const char *szUrl); + +#endif // __cpluscplus + +#endif // M_SYSTEM_H diff --git a/include/m_timezones.h b/include/m_timezones.h index ef85448a90..920712a865 100644 --- a/include/m_timezones.h +++ b/include/m_timezones.h @@ -1,134 +1,139 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) -Copyright (c) 2000-10 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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_TIMEZONES_H -#define __M_TIMEZONES_H - -#ifndef M_CORE_H__ -#include -#endif - -#define MIM_TZ_NAMELEN 64 - -#define TZF_PLF_CB 1 // UI element is assumed to be a combo box -#define TZF_PLF_LB 2 // UI element is assumed to be a list box -#define TZF_DIFONLY 4 -#define TZF_KNOWNONLY 8 - -#define LOCAL_TIME_HANDLE NULL -#define UTC_TIME_HANDLE ((void*)-1) - -typedef INT_PTR mir_time; - -EXTERN_C MIR_CORE_DLL(HANDLE) TimeZone_CreateByName(LPCTSTR tszName, DWORD dwFlags); -EXTERN_C MIR_CORE_DLL(HANDLE) TimeZone_CreateByContact(MCONTACT hContact, LPCSTR szModule, DWORD dwFlags); - -EXTERN_C MIR_CORE_DLL(void) TimeZone_StoreByContact(MCONTACT hContact, LPCSTR szModule, HANDLE hTZ); -EXTERN_C MIR_CORE_DLL(void) TimeZone_StoreListResult(MCONTACT hContact, LPCSTR szModule, HWND hWnd, DWORD dwFlags); - -EXTERN_C MIR_CORE_DLL(int) TimeZone_PrintDateTime(HANDLE hTZ, LPCTSTR szFormat, LPTSTR szDest, size_t cbDest, DWORD dwFlags); -EXTERN_C MIR_CORE_DLL(int) TimeZone_PrintTimeStamp(HANDLE hTZ, mir_time ts, LPCTSTR szFormat, LPTSTR szDest, size_t cbDest, DWORD dwFlags); - -EXTERN_C MIR_CORE_DLL(int) TimeZone_PrepareList(MCONTACT hContact, LPCSTR szModule, HWND hWnd, DWORD dwFlags); -EXTERN_C MIR_CORE_DLL(int) TimeZone_SelectListItem(MCONTACT hContact, LPCSTR szModule, HWND hWnd, DWORD dwFlags); - -EXTERN_C MIR_CORE_DLL(int) TimeZone_GetTimeZoneTime(HANDLE hTZ, SYSTEMTIME *st); -EXTERN_C MIR_CORE_DLL(int) TimeZone_GetSystemTime(HANDLE hTZ, mir_time src, SYSTEMTIME *dest, DWORD dwFlags); -EXTERN_C MIR_CORE_DLL(mir_time) TimeZone_UtcToLocal(HANDLE hTZ, mir_time ts); - -EXTERN_C MIR_CORE_DLL(LPTIME_ZONE_INFORMATION) TimeZone_GetInfo(HANDLE hTZ); -EXTERN_C MIR_CORE_DLL(LPCTSTR) TimeZone_GetName(HANDLE hTZ); -EXTERN_C MIR_CORE_DLL(LPCTSTR) TimeZone_GetDescription(LPCTSTR TZname); - -#ifdef __cplusplus - -__forceinline int printDateTimeByContact (MCONTACT hContact, LPCTSTR szFormat, LPTSTR szDest, int cbDest, DWORD dwFlags) -{ - return TimeZone_PrintDateTime(TimeZone_CreateByContact(hContact, nullptr, dwFlags), szFormat, szDest, cbDest, dwFlags); -} - -__forceinline int printTimeStampByContact(MCONTACT hContact, mir_time ts, LPCTSTR szFormat, LPTSTR szDest, int cbDest, DWORD dwFlags) -{ - return TimeZone_PrintTimeStamp(TimeZone_CreateByContact(hContact, nullptr, dwFlags), ts, szFormat, szDest, cbDest, dwFlags); -} - -__forceinline LPTIME_ZONE_INFORMATION getTziByContact(MCONTACT hContact) -{ - return TimeZone_GetInfo(TimeZone_CreateByContact(hContact, nullptr, 0)); -} - -__forceinline int getTimeZoneTimeByContact(MCONTACT hContact, SYSTEMTIME *st) -{ - return TimeZone_GetTimeZoneTime(TimeZone_CreateByContact(hContact, nullptr, 0), st); -} - -__forceinline mir_time timeStampToTimeZoneTimeStampByContact(MCONTACT hContact, mir_time ts) -{ - return TimeZone_UtcToLocal(TimeZone_CreateByContact(hContact, nullptr, 0), ts); -} - -#endif - -///////////////////////////////////////////////////////////////////////////////////////// -// Time services -// -// Converts a GMT timestamp into local time -// Returns the converted value -// -// Timestamps have zero at midnight 1/1/1970 GMT, this service converts such a -// value to be based at midnight 1/1/1970 local time. -// This service does not use a simple conversion based on the current offset -// between GMT and local. Rather, it figures out whether daylight savings time -// would have been in place at the time of the stamp and gives the local time as -// it would have been at the time and date the stamp contains. -// This service isn't nearly as useful as db/time/TimestampToString below and I -// recommend avoiding its use when possible so that you don't get your timezones -// mixed up (like I did. Living at GMT makes things easier for me, but has certain -// disadvantages :-)). - -EXTERN_C MIR_CORE_DLL(DWORD) TimeZone_ToLocal(DWORD); - -///////////////////////////////////////////////////////////////////////////////////////// -// Converts a GMT timestamp into a customisable local time string -// Returns the destination buffer -// -// Uses db/time/timestamptolocal for the conversion so read that description to -// see what's going on. -// The string is formatted according to the current user's locale, language and -// preferences. -// szFormat can have the following special characters: -// t Time without seconds, eg hh:mm -// s Time with seconds, eg hh:mm:ss -// m Time without minutes, eg hh -// d Short date, eg dd/mm/yyyy -// D Long date, eg d mmmm yyyy -// I ISO 8061 Time yyyy-mm-ddThh:mm:ssZ -// All other characters are copied across to szDest as-is - -EXTERN_C MIR_CORE_DLL(char*) TimeZone_ToString(mir_time timeVal, const char *szFormat, char *szDest, size_t cchDest); -EXTERN_C MIR_CORE_DLL(wchar_t*) TimeZone_ToStringW(mir_time timeVal, const wchar_t *wszFormat, wchar_t *wszDest, size_t cchDest); - -#define TimeZone_ToStringT TimeZone_ToStringW - -#endif /* __M_TIMEZONES_H */ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2000-10 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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_TIMEZONES_H +#define __M_TIMEZONES_H + +#ifndef M_CORE_H__ +#include +#endif + +#define MIM_TZ_NAMELEN 64 + +#define TZF_PLF_CB 1 // UI element is assumed to be a combo box +#define TZF_PLF_LB 2 // UI element is assumed to be a list box +#define TZF_DIFONLY 4 +#define TZF_KNOWNONLY 8 + +#define LOCAL_TIME_HANDLE NULL +#define UTC_TIME_HANDLE ((void*)-1) + +typedef INT_PTR mir_time; + +EXTERN_C MIR_CORE_DLL(HANDLE) TimeZone_CreateByName(LPCTSTR tszName, DWORD dwFlags); +EXTERN_C MIR_CORE_DLL(HANDLE) TimeZone_CreateByContact(MCONTACT hContact, LPCSTR szModule, DWORD dwFlags); + +EXTERN_C MIR_CORE_DLL(void) TimeZone_StoreByContact(MCONTACT hContact, LPCSTR szModule, HANDLE hTZ); +EXTERN_C MIR_CORE_DLL(void) TimeZone_StoreListResult(MCONTACT hContact, LPCSTR szModule, HWND hWnd, DWORD dwFlags); + +EXTERN_C MIR_CORE_DLL(int) TimeZone_PrintDateTime(HANDLE hTZ, LPCTSTR szFormat, LPTSTR szDest, size_t cbDest, DWORD dwFlags); +EXTERN_C MIR_CORE_DLL(int) TimeZone_PrintTimeStamp(HANDLE hTZ, mir_time ts, LPCTSTR szFormat, LPTSTR szDest, size_t cbDest, DWORD dwFlags); + +EXTERN_C MIR_CORE_DLL(int) TimeZone_PrepareList(MCONTACT hContact, LPCSTR szModule, HWND hWnd, DWORD dwFlags); +EXTERN_C MIR_CORE_DLL(int) TimeZone_SelectListItem(MCONTACT hContact, LPCSTR szModule, HWND hWnd, DWORD dwFlags); + +#ifdef _MSC_VER +EXTERN_C MIR_CORE_DLL(int) TimeZone_GetTimeZoneTime(HANDLE hTZ, SYSTEMTIME *st); +EXTERN_C MIR_CORE_DLL(int) TimeZone_GetSystemTime(HANDLE hTZ, mir_time src, SYSTEMTIME *dest, DWORD dwFlags); + +EXTERN_C MIR_CORE_DLL(LPTIME_ZONE_INFORMATION) TimeZone_GetInfo(HANDLE hTZ); +#endif +EXTERN_C MIR_CORE_DLL(mir_time) TimeZone_UtcToLocal(HANDLE hTZ, mir_time ts); + +EXTERN_C MIR_CORE_DLL(LPCTSTR) TimeZone_GetName(HANDLE hTZ); +EXTERN_C MIR_CORE_DLL(LPCTSTR) TimeZone_GetDescription(LPCTSTR TZname); + +#ifdef __cplusplus + +__forceinline int printDateTimeByContact (MCONTACT hContact, LPCTSTR szFormat, LPTSTR szDest, int cbDest, DWORD dwFlags) +{ + return TimeZone_PrintDateTime(TimeZone_CreateByContact(hContact, nullptr, dwFlags), szFormat, szDest, cbDest, dwFlags); +} + +__forceinline int printTimeStampByContact(MCONTACT hContact, mir_time ts, LPCTSTR szFormat, LPTSTR szDest, int cbDest, DWORD dwFlags) +{ + return TimeZone_PrintTimeStamp(TimeZone_CreateByContact(hContact, nullptr, dwFlags), ts, szFormat, szDest, cbDest, dwFlags); +} + +#ifdef _MSC_VER +__forceinline LPTIME_ZONE_INFORMATION getTziByContact(MCONTACT hContact) +{ + return TimeZone_GetInfo(TimeZone_CreateByContact(hContact, nullptr, 0)); +} + +__forceinline int getTimeZoneTimeByContact(MCONTACT hContact, SYSTEMTIME *st) +{ + return TimeZone_GetTimeZoneTime(TimeZone_CreateByContact(hContact, nullptr, 0), st); +} +#endif + +__forceinline mir_time timeStampToTimeZoneTimeStampByContact(MCONTACT hContact, mir_time ts) +{ + return TimeZone_UtcToLocal(TimeZone_CreateByContact(hContact, nullptr, 0), ts); +} + +#endif + +///////////////////////////////////////////////////////////////////////////////////////// +// Time services +// +// Converts a GMT timestamp into local time +// Returns the converted value +// +// Timestamps have zero at midnight 1/1/1970 GMT, this service converts such a +// value to be based at midnight 1/1/1970 local time. +// This service does not use a simple conversion based on the current offset +// between GMT and local. Rather, it figures out whether daylight savings time +// would have been in place at the time of the stamp and gives the local time as +// it would have been at the time and date the stamp contains. +// This service isn't nearly as useful as db/time/TimestampToString below and I +// recommend avoiding its use when possible so that you don't get your timezones +// mixed up (like I did. Living at GMT makes things easier for me, but has certain +// disadvantages :-)). + +EXTERN_C MIR_CORE_DLL(DWORD) TimeZone_ToLocal(DWORD); + +///////////////////////////////////////////////////////////////////////////////////////// +// Converts a GMT timestamp into a customisable local time string +// Returns the destination buffer +// +// Uses db/time/timestamptolocal for the conversion so read that description to +// see what's going on. +// The string is formatted according to the current user's locale, language and +// preferences. +// szFormat can have the following special characters: +// t Time without seconds, eg hh:mm +// s Time with seconds, eg hh:mm:ss +// m Time without minutes, eg hh +// d Short date, eg dd/mm/yyyy +// D Long date, eg d mmmm yyyy +// I ISO 8061 Time yyyy-mm-ddThh:mm:ssZ +// All other characters are copied across to szDest as-is + +EXTERN_C MIR_CORE_DLL(char*) TimeZone_ToString(mir_time timeVal, const char *szFormat, char *szDest, size_t cchDest); +EXTERN_C MIR_CORE_DLL(wchar_t*) TimeZone_ToStringW(mir_time timeVal, const wchar_t *wszFormat, wchar_t *wszDest, size_t cchDest); + +#define TimeZone_ToStringT TimeZone_ToStringW + +#endif /* __M_TIMEZONES_H */ diff --git a/include/m_types.h b/include/m_types.h index 005d289b24..236adfbb1f 100644 --- a/include/m_types.h +++ b/include/m_types.h @@ -1,44 +1,126 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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_TYPES_H__ -#define M_TYPES_H__ 1 - -#ifdef Q_OS_WIN - -#define FALSE 0 -#define TRUE 1 - -typedef void *HANDLE, *HINSTANCE, *HICON, *HBITMAP, *HWND, *HGENMENU; -typedef int BOOL; -typedef unsigned char BYTE; -typedef unsigned int DWORD; -typedef intptr_t WPARAM, LPARAM, INT_PTR; -typedef char *LPSTR; -typedef const char *LPCSTR; -typedef wchar_t *LPWSTR, *LPTSTR; -typedef const wchar_t *LPCWSTR, *LPCTSTR; - -#endif - -#endif // M_TYPES_H__ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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_TYPES_H__ +#define M_TYPES_H__ 1 + +/////////////////////////////////////////////////////////////////////////////// +// Linux + +#include +#include + +#ifndef _MSC_VER + +#define CALLBACK +#define EXTERN_C extern "C" + +#define PURE = 0 +#define STDMETHOD(method) virtual HRESULT method +#define STDMETHOD_(ret, method) virtual ret method +#define STDMETHODIMP_(ret) ret + +#define FALSE 0 +#define TRUE 1 +#define CP_ACP 0 +#define SW_HIDE 0 +#define SW_SHOW 5 +#define MAX_PATH 260 +#define _TRUNCATE size_t(-1) +#define INVALID_HANDLE_VALUE HANDLE(-1) + +typedef void *HANDLE; +typedef int BOOL, SOCKET; +typedef uint8_t BYTE; +typedef uint16_t WORD; +typedef uint32_t DWORD, UINT, COLORREF; +typedef intptr_t WPARAM, LPARAM, INT_PTR; +typedef uintptr_t UINT_PTR; +typedef char *LPSTR; +typedef const char *LPCSTR; +typedef wchar_t *LPWSTR, *LPTSTR; +typedef const wchar_t *LPCWSTR, *LPCTSTR; +typedef sockaddr_in SOCKADDR_IN; + +struct RECT { int left, top, right, bottom; }; +struct POINT { int x, y; }; +struct SIZE { int width, height; }; + +#define MIR_EXPORT __attribute__((__visibility__("default"))) +#define MIR_IMPORT +#define MIR_SYSCALL +#define MIR_CDECL +#define UNREFERENCED_PARAMETER(x) + +#define __try try +#define __except catch +#define EXCEPTION_EXECUTE_HANDLER ... + +#define _In_z_ +#define _Pre_notnull_ +#define _Always_(x) +#define _Printf_format_string_ + +#define InterlockedIncrement(x) __sync_fetch_and_add(x, 1) +#define InterlockedDecrement(x) __sync_fetch_and_add(x, -1) + +#define SecureZeroMemory(x, y) memset(x, 0, y) +#define interface struct +#define memcpy_s(a,b,c,d) memcpy(a,c,(b)<(d)?(b):(d)) +#define memmove_s(a,b,c,d) memmove(a,c,(b)<(d)?(b):(d)) + +#define stricmp strcasecmp +#define strnicmp strncasecmp +#define wcsicmp wcscasecmp +#define wcsnicmp wcsncasecmp + +#define _vsnprintf vsnprintf +#define _vsnwprintf vswprintf + +#define DECLARE_HANDLE(name) struct _##name { int unused; }; typedef struct _##name *name +DECLARE_HANDLE(HWND); +DECLARE_HANDLE(HFONT); +DECLARE_HANDLE(HICON); +DECLARE_HANDLE(HMENU); +DECLARE_HANDLE(HBRUSH); +DECLARE_HANDLE(HBITMAP); +DECLARE_HANDLE(HCURSOR); +DECLARE_HANDLE(HTREEITEM); +DECLARE_HANDLE(HINSTANCE); + +struct EXCEPTION_POINTERS { int unused; }; +struct LOGFONT { int unused; }; + +#else +/////////////////////////////////////////////////////////////////////////////// +// Windows + +#define MIR_EXPORT __declspec(dllexport) +#define MIR_IMPORT __declspec(dllimport) + +#define MIR_SYSCALL __stdcall +#define MIR_CDECL __cdecl + +#endif + +#endif // M_TYPES_H__ diff --git a/include/m_xml.h b/include/m_xml.h index 491c4a016c..d09b289cf3 100644 --- a/include/m_xml.h +++ b/include/m_xml.h @@ -1,195 +1,194 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) -Copyright (c) 2000-08 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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_XML_H__ -#define M_XML_H__ - -#include -#include - -///////////////////////////////////////////////////////////////////////////////////////// -// new API to replace the old one - -#ifdef MIR_CORE_EXPORTS -#define TINYXML2_EXPORT 1 -#else -#define TINYXML2_IMPORT 1 -#endif - -#include "../src/mir_core/src/tinyxml2.h" - -typedef tinyxml2::XMLNode TiXmlNode; -typedef tinyxml2::XMLText TiXmlText; -typedef tinyxml2::XMLElement TiXmlElement; -typedef tinyxml2::XMLDocument TiXmlDocument; - -typedef tinyxml2::XMLHandle TiXmlHandle; -typedef tinyxml2::XMLConstHandle TiXmlConst; - -///////////////////////////////////////////////////////////////////////////////////////// -// safe wrappers - -EXTERN_C MIR_CORE_DLL(int) XmlGetChildCount(const TiXmlElement*); - -EXTERN_C MIR_CORE_DLL(TiXmlElement*) XmlAddChild(TiXmlElement*, const char *pszName); -EXTERN_C MIR_CORE_DLL(TiXmlElement*) XmlAddChildA(TiXmlElement*, const char *pszName, const char *ptszValue); -EXTERN_C MIR_CORE_DLL(TiXmlElement*) XmlAddChildI(TiXmlElement*, const char *pszName, int iValue); - -EXTERN_C MIR_CORE_DLL(int) XmlGetChildInt(const TiXmlElement *hXml, const char *key); -EXTERN_C MIR_CORE_DLL(const char*) XmlGetChildText(const TiXmlElement *hXml, const char *key); -EXTERN_C MIR_CORE_DLL(const TiXmlElement*) XmlGetChildByTag(const TiXmlElement *hXml, const char *key, const char *attrName, const char *attrValue); -EXTERN_C MIR_CORE_DLL(const TiXmlElement*) XmlFirstChild(const TiXmlElement *hXml, const char *key = nullptr); - -EXTERN_C MIR_CORE_DLL(void) XmlAddAttr(TiXmlElement*, const char *pszName, const char *ptszValue); -EXTERN_C MIR_CORE_DLL(const char*) XmlGetAttr(const TiXmlElement*, const char *pszName); - -///////////////////////////////////////////////////////////////////////////////////////// -// simple element iterator -// -// allows traversing subnodes in a cycle like -// for (auto *pNode : TiXmlEnum(pRoot)) { - -class TiXmlIterator -{ - const TiXmlElement *m_pCurr; - -public: - TiXmlIterator(const TiXmlElement *pNode) : - m_pCurr(pNode) - { - } - - TiXmlIterator& operator=(const TiXmlElement *pNode) - { - m_pCurr = pNode; - return *this; - } - - // Prefix ++ overload - TiXmlIterator& operator++() - { - if (m_pCurr) - m_pCurr = m_pCurr->NextSiblingElement(); - return *this; - } - - const TiXmlElement* operator*() - { - return m_pCurr; - } - - bool operator!=(const TiXmlIterator &iterator) - { - return m_pCurr != iterator.m_pCurr; - } -}; - -class TiXmlEnum -{ - const TiXmlElement *m_pFirst; - -public: - TiXmlEnum(const TiXmlNode *pNode) - { - m_pFirst = (pNode) ? pNode->FirstChildElement() : nullptr; - } - - TiXmlIterator begin() - { - return TiXmlIterator(m_pFirst); - } - - TiXmlIterator end() - { - return TiXmlIterator(nullptr); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// filtered element iterator -// -// allows traversing subnodes of the specified name in a cycle like -// for (auto *pNode : TiXmlFilter(pRoot, "element")) { - -class TiXmlFilterIterator -{ - const TiXmlElement *m_pCurr; - const char *m_pszFilter; - -public: - TiXmlFilterIterator(const TiXmlElement *pNode, const char *pszNodeName) : - m_pszFilter(pszNodeName), - m_pCurr(pNode) - { - } - - TiXmlFilterIterator& operator=(const TiXmlElement *pNode) - { - m_pCurr = pNode; - return *this; - } - - // Prefix ++ overload - TiXmlFilterIterator& operator++() - { - if (m_pCurr) - m_pCurr = m_pCurr->NextSiblingElement(m_pszFilter); - return *this; - } - - const TiXmlElement* operator*() - { - return m_pCurr; - } - - bool operator!=(const TiXmlFilterIterator &iterator) - { - return m_pCurr != iterator.m_pCurr; - } -}; - -class TiXmlFilter -{ - const TiXmlElement *m_pFirst; - const char *m_pszFilter; - -public: - TiXmlFilter(const TiXmlNode *pNode, const char *pszNodeName) : - m_pszFilter(pszNodeName) - { - m_pFirst = (pNode) ? pNode->FirstChildElement(pszNodeName) : nullptr; - } - - TiXmlFilterIterator begin() - { - return TiXmlFilterIterator(m_pFirst, m_pszFilter); - } - - TiXmlFilterIterator end() - { - return TiXmlFilterIterator(nullptr, nullptr); - } -}; - -#endif // M_XML_H__ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2000-08 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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_XML_H__ +#define M_XML_H__ + +#include + +///////////////////////////////////////////////////////////////////////////////////////// +// new API to replace the old one + +#ifdef MIR_CORE_EXPORTS +#define TINYXML2_EXPORT 1 +#else +#define TINYXML2_IMPORT 1 +#endif + +#include "../src/mir_core/src/tinyxml2.h" + +typedef tinyxml2::XMLNode TiXmlNode; +typedef tinyxml2::XMLText TiXmlText; +typedef tinyxml2::XMLElement TiXmlElement; +typedef tinyxml2::XMLDocument TiXmlDocument; + +typedef tinyxml2::XMLHandle TiXmlHandle; +typedef tinyxml2::XMLConstHandle TiXmlConst; + +///////////////////////////////////////////////////////////////////////////////////////// +// safe wrappers + +EXTERN_C MIR_CORE_DLL(int) XmlGetChildCount(const TiXmlElement*); + +EXTERN_C MIR_CORE_DLL(TiXmlElement*) XmlAddChild(TiXmlElement*, const char *pszName); +EXTERN_C MIR_CORE_DLL(TiXmlElement*) XmlAddChildA(TiXmlElement*, const char *pszName, const char *ptszValue); +EXTERN_C MIR_CORE_DLL(TiXmlElement*) XmlAddChildI(TiXmlElement*, const char *pszName, int iValue); + +EXTERN_C MIR_CORE_DLL(int) XmlGetChildInt(const TiXmlElement *hXml, const char *key); +EXTERN_C MIR_CORE_DLL(const char*) XmlGetChildText(const TiXmlElement *hXml, const char *key); +EXTERN_C MIR_CORE_DLL(const TiXmlElement*) XmlGetChildByTag(const TiXmlElement *hXml, const char *key, const char *attrName, const char *attrValue); +EXTERN_C MIR_CORE_DLL(const TiXmlElement*) XmlFirstChild(const TiXmlElement *hXml, const char *key = nullptr); + +EXTERN_C MIR_CORE_DLL(void) XmlAddAttr(TiXmlElement*, const char *pszName, const char *ptszValue); +EXTERN_C MIR_CORE_DLL(const char*) XmlGetAttr(const TiXmlElement*, const char *pszName); + +///////////////////////////////////////////////////////////////////////////////////////// +// simple element iterator +// +// allows traversing subnodes in a cycle like +// for (auto *pNode : TiXmlEnum(pRoot)) { + +class TiXmlIterator +{ + const TiXmlElement *m_pCurr; + +public: + TiXmlIterator(const TiXmlElement *pNode) : + m_pCurr(pNode) + { + } + + TiXmlIterator& operator=(const TiXmlElement *pNode) + { + m_pCurr = pNode; + return *this; + } + + // Prefix ++ overload + TiXmlIterator& operator++() + { + if (m_pCurr) + m_pCurr = m_pCurr->NextSiblingElement(); + return *this; + } + + const TiXmlElement* operator*() + { + return m_pCurr; + } + + bool operator!=(const TiXmlIterator &iterator) + { + return m_pCurr != iterator.m_pCurr; + } +}; + +class TiXmlEnum +{ + const TiXmlElement *m_pFirst; + +public: + TiXmlEnum(const TiXmlNode *pNode) + { + m_pFirst = (pNode) ? pNode->FirstChildElement() : nullptr; + } + + TiXmlIterator begin() + { + return TiXmlIterator(m_pFirst); + } + + TiXmlIterator end() + { + return TiXmlIterator(nullptr); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// filtered element iterator +// +// allows traversing subnodes of the specified name in a cycle like +// for (auto *pNode : TiXmlFilter(pRoot, "element")) { + +class TiXmlFilterIterator +{ + const TiXmlElement *m_pCurr; + const char *m_pszFilter; + +public: + TiXmlFilterIterator(const TiXmlElement *pNode, const char *pszNodeName) : + m_pszFilter(pszNodeName), + m_pCurr(pNode) + { + } + + TiXmlFilterIterator& operator=(const TiXmlElement *pNode) + { + m_pCurr = pNode; + return *this; + } + + // Prefix ++ overload + TiXmlFilterIterator& operator++() + { + if (m_pCurr) + m_pCurr = m_pCurr->NextSiblingElement(m_pszFilter); + return *this; + } + + const TiXmlElement* operator*() + { + return m_pCurr; + } + + bool operator!=(const TiXmlFilterIterator &iterator) + { + return m_pCurr != iterator.m_pCurr; + } +}; + +class TiXmlFilter +{ + const TiXmlElement *m_pFirst; + const char *m_pszFilter; + +public: + TiXmlFilter(const TiXmlNode *pNode, const char *pszNodeName) : + m_pszFilter(pszNodeName) + { + m_pFirst = (pNode) ? pNode->FirstChildElement(pszNodeName) : nullptr; + } + + TiXmlFilterIterator begin() + { + return TiXmlFilterIterator(m_pFirst, m_pszFilter); + } + + TiXmlFilterIterator end() + { + return TiXmlFilterIterator(nullptr, nullptr); + } +}; + +#endif // M_XML_H__ diff --git a/include/newpluginapi.h b/include/newpluginapi.h index 21ec09fd54..33394bbfa3 100644 --- a/include/newpluginapi.h +++ b/include/newpluginapi.h @@ -1,517 +1,498 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) -Copyright (c) 2000-08 Miranda ICQ/IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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_NEWPLUGINAPI_H__ -#define M_NEWPLUGINAPI_H__ - -#if !defined(HIMAGELIST) -typedef struct _IMAGELIST* HIMAGELIST; -#endif - -#include -#include - -#define PLUGIN_MAKE_VERSION(a, b, c, d) (((((DWORD)(a))&0xFF)<<24)|((((DWORD)(b))&0xFF)<<16)|((((DWORD)(c))&0xFF)<<8)|(((DWORD)(d))&0xFF)) -#define MAXMODULELABELLENGTH 64 - -#define UNICODE_AWARE 0x0001 -#define STATIC_PLUGIN 0x0002 - -///////////////////////////////////////////////////////////////////////////////////////// -// The UUID structure below is used to for plugin UUID's and module type definitions - -struct MUUID -{ - unsigned long a; - unsigned short b; - unsigned short c; - unsigned char d[8]; -}; - -__forceinline bool operator==(const MUUID &p1, const MUUID &p2) -{ - return memcmp(&p1, &p2, sizeof(MUUID)) == 0; -} -__forceinline bool operator!=(const MUUID &p1, const MUUID &p2) -{ - return memcmp(&p1, &p2, sizeof(MUUID)) != 0; -} - -MIR_APP_DLL(int) GetPluginLangId(const MUUID &uuid, int langId); -MIR_APP_DLL(int) IsPluginLoaded(const MUUID &uuid); -MIR_APP_DLL(int) SetServiceModePlugin(const char *szPluginName, WPARAM = 0, LPARAM = 0); - -// manually get/set flag specified at Options - Plugins - Enabled -MIR_APP_DLL(bool) IsPluginOnWhiteList(const char *szPluginName); -MIR_APP_DLL(void) SetPluginOnWhiteList(const char *szPluginName, bool bAllow); - -///////////////////////////////////////////////////////////////////////////////////////// -// Used to define the end of the MirandaPluginInterface list - -#define MIID_LAST {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}} - -///////////////////////////////////////////////////////////////////////////////////////// -// Replaceable internal modules interface ids - -#define MIID_HISTORY {0x5ca0cbc1, 0x999a, 0x4ea2, {0x8b, 0x44, 0xf8, 0xf6, 0x7d, 0x7f, 0x8e, 0xbe}} -#define MIID_UIUSERINFO {0x570b931c, 0x9af8, 0x48f1, {0xad, 0x9f, 0xc4, 0x49, 0x8c, 0x61, 0x8a, 0x77}} -#define MIID_SRAWAY {0x5ab54c76, 0x1b4c, 0x4a00, {0xb4, 0x04, 0x48, 0xcb, 0xea, 0x5f, 0xef, 0xe7}} -#define MIID_SREMAIL {0xd005b5a6, 0x1b66, 0x445a, {0xb6, 0x03, 0x74, 0xd4, 0xd4, 0x55, 0x2d, 0xe2}} -#define MIID_SRFILE {0x989d104d, 0xacb7, 0x4ee0, {0xb9, 0x6d, 0x67, 0xce, 0x46, 0x53, 0xb6, 0x95}} -#define MIID_UIHISTORY {0x7f7e3d98, 0xce1f, 0x4962, {0x82, 0x84, 0x96, 0x85, 0x50, 0xf1, 0xd3, 0xd9}} -#define MIID_AUTOAWAY {0x9c87f7dc, 0x3bd7, 0x4983, {0xb7, 0xfb, 0xb8, 0x48, 0xfd, 0xbc, 0x91, 0xf0}} -#define MIID_USERONLINE {0x130829e0, 0x2463, 0x4ff8, {0xbb, 0xc8, 0xce, 0x73, 0xc0, 0x18, 0x84, 0x42}} -#define MIID_CRYPTO {0x415ca6e1, 0x895f, 0x40e6, {0x87, 0xbd, 0x9b, 0x39, 0x60, 0x16, 0xd0, 0xe5}} -#define MIID_POPUP {0xb275f4a4, 0xe347, 0x4515, {0xaf, 0x71, 0x77, 0xd0, 0x1e, 0xef, 0x54, 0x41}} - -///////////////////////////////////////////////////////////////////////////////////////// -// Common plugin interfaces (core plugins) - -#define MIID_DATABASE {0xae77fd33, 0xe484, 0x4dc7, {0x8c, 0xbc, 0x09, 0x9f, 0xed, 0xcc, 0xcf, 0xdd}} -#define MIID_CLIST {0x9d8da8bf, 0x665b, 0x4908, {0x9e, 0x61, 0x9f, 0x75, 0x98, 0xae, 0x33, 0x0e}} -#define MIID_SRMM {0x58c7eea6, 0xf9db, 0x4dd9, {0x80, 0x36, 0xae, 0x80, 0x2b, 0xc0, 0x41, 0x4c}} -#define MIID_TESTPLUGIN {0x53b974f4, 0x3c74, 0x4dba, {0x8f, 0xc2, 0x6f, 0x92, 0xfe, 0x01, 0x3b, 0x8c}} - -///////////////////////////////////////////////////////////////////////////////////////// -// Special exception interface for protocols. -// This interface allows more than one plugin to implement it at the same time - -#define MIID_PROTOCOL {0x2a3c815e, 0xa7d9, 0x424b, {0xba, 0x30, 0x2, 0xd0, 0x83, 0x22, 0x90, 0x85}} - -#define MIID_SERVICEMODE {0x8a92c026, 0x953a, 0x4f5f, { 0x99, 0x21, 0xf2, 0xc2, 0xdc, 0x19, 0x5e, 0xc5}} - -///////////////////////////////////////////////////////////////////////////////////////// -// Each service mode plugin must implement MS_SERVICEMODE_LAUNCH -// This service might return one of the following values: -// SERVICE_CONTINUE - load Miranda normally, like there's no service plugins at all -// SERVICE_ONLYDB - load database and then execute service plugin only -// SERVICE_MONOPOLY - execute only service plugin, even without database -// SERVICE_FAILED - terminate Miranda execution - -#define SERVICE_CONTINUE 0 -#define SERVICE_ONLYDB 1 -#define SERVICE_MONOPOLY 2 -#define SERVICE_FAILED (-1) - -#define MS_SERVICEMODE_LAUNCH "ServiceMode/Launch" - -struct PLUGININFOEX -{ - int cbSize; - char *shortName; - DWORD version; - char *description; - char *author; - char *copyright; - char *homepage; - BYTE flags; // right now the only flag, UNICODE_AWARE, is recognized here - MUUID uuid; // plugin's unique identifier -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Miranda/System/LoadModule event -// called when a plugin is being loaded dynamically -// wParam = CMPluginBase* -// lParam = HINSTANCE of the loaded plugin - -#define ME_SYSTEM_MODULELOAD "Miranda/System/LoadModule" - -///////////////////////////////////////////////////////////////////////////////////////// -// Miranda/System/UnloadModule event -// called when a plugin is being unloaded dynamically -// wParam = CMPluginBase* -// lParam = HINSTANCE of the plugin to be unloaded - -#define ME_SYSTEM_MODULEUNLOAD "Miranda/System/UnloadModule" - -///////////////////////////////////////////////////////////////////////////////////////// -// plugin's class - -// initializes an empty account -typedef struct PROTO_INTERFACE* (*pfnInitProto)(const char* szModuleName, const wchar_t* szUserName); - -// deallocates an account instance -typedef int(*pfnUninitProto)(PROTO_INTERFACE*); - -#pragma warning(push) -#pragma warning(disable:4275) - -struct IcolibItem; - -class MIR_APP_EXPORT CMPluginBase : public MNonCopyable -{ - void tryOpenLog(); - -protected: - HINSTANCE m_hInst; - const char *m_szModuleName; - const PLUGININFOEX &m_pInfo; - HANDLE m_hLogger = nullptr; - LIST m_arIcons; - - CMPluginBase(const char *moduleName, const PLUGININFOEX &pInfo); - ~CMPluginBase(); - - // pass one of PROTOTYPE_* constants as type - void RegisterProtocol(int type, pfnInitProto = nullptr, pfnUninitProto = nullptr); - void SetUniqueId(const char *pszUniqueId); - -public: - void debugLogA(LPCSTR szFormat, ...); - void debugLogW(LPCWSTR wszFormat, ...); - - __forceinline void addIcolib(HANDLE hIcolib) { m_arIcons.insert((IcolibItem*)hIcolib); } - int addImgListIcon(HIMAGELIST himl, int iconId); - HICON getIcon(int iconId, bool big = false); - HANDLE getIconHandle(int iconId); - void releaseIcon(int iconId, bool big = false); - - __forceinline const PLUGININFOEX& getInfo() const { return m_pInfo; } - __forceinline const char* getModule() const { return m_szModuleName; } - - __forceinline HINSTANCE getInst() const { return m_hInst; } - __forceinline void setInst(HINSTANCE hInst) { m_hInst = hInst; } - - virtual int Load(); - virtual int Unload(); - - //////////////////////////////////////////////////////////////////////////////////////// - // registering module's resources - - template - __forceinline void registerIcon(const char *szSection, IconItem(&pIcons)[_Size], const char *prefix = nullptr) - { - Icon_Register(m_hInst, szSection, pIcons, _Size, prefix, this); - } - - template - __forceinline void registerIconW(const wchar_t *szSection, IconItemT(&pIcons)[_Size], const char *prefix = nullptr) - { - Icon_RegisterT(m_hInst, szSection, pIcons, _Size, prefix, this); - } - - int addOptions(WPARAM wParam, struct OPTIONSDIALOGPAGE *odp); - void openOptions(const wchar_t *pszGroup, const wchar_t *pszPage = 0, const wchar_t *pszTab = 0); - void openOptionsPage(const wchar_t *pszGroup, const wchar_t *pszPage = 0, const wchar_t *pszTab = 0); - - HANDLE addIcon(const struct SKINICONDESC*); - HANDLE addTTB(const struct TTBButton*); - - HGENMENU addRootMenu(int hMenuObject, LPCWSTR ptszName, int position, HANDLE hIcoLib = nullptr); - - int addFont(struct FontID *pFont); - int addFont(struct FontIDW *pFont); - - int addColor(struct ColourID *pColor); - int addColor(struct ColourIDW *pColor); - - int addEffect(struct EffectID *pEffect); - int addEffect(struct EffectIDW *pEffect); - - int addFrame(const struct CLISTFrame*); - int addHotkey(const struct HOTKEYDESC*); - int addSound(const char *name, const wchar_t *section, const wchar_t *description, const wchar_t *defaultFile = nullptr); - int addUserInfo(WPARAM wParam, struct OPTIONSDIALOGPAGE *odp); - - //////////////////////////////////////////////////////////////////////////////////////// - - __forceinline INT_PTR delSetting(const char *name) - { - return db_unset(0, m_szModuleName, name); - } - __forceinline INT_PTR delSetting(MCONTACT hContact, const char *name) - { - return db_unset(hContact, m_szModuleName, name); - } - - __forceinline bool getBool(const char *name, bool defaultValue = false) - { - return db_get_b(0, m_szModuleName, name, defaultValue) != 0; - } - __forceinline bool getBool(MCONTACT hContact, const char *name, bool defaultValue = false) - { - return db_get_b(hContact, m_szModuleName, name, defaultValue) != 0; - } - - __forceinline int getByte(const char *name, int defaultValue = 0) - { - return db_get_b(0, m_szModuleName, name, defaultValue); - } - __forceinline int getByte(MCONTACT hContact, const char *name, int defaultValue = 0) - { - return db_get_b(hContact, m_szModuleName, name, defaultValue); - } - - __forceinline int getWord(const char *name, int defaultValue = 0) - { - return db_get_w(0, m_szModuleName, name, defaultValue); - } - __forceinline int getWord(MCONTACT hContact, const char *name, int defaultValue = 0) - { - return db_get_w(hContact, m_szModuleName, name, defaultValue); - } - - __forceinline DWORD getDword(const char *name, int defaultValue = 0) - { - return db_get_dw(0, m_szModuleName, name, defaultValue); - } - __forceinline DWORD getDword(MCONTACT hContact, const char *name, int defaultValue = 0) - { - return db_get_dw(hContact, m_szModuleName, name, defaultValue); - } - - __forceinline INT_PTR getString(const char *name, DBVARIANT *result) - { - return db_get_s(0, m_szModuleName, name, result); - } - __forceinline INT_PTR getString(MCONTACT hContact, const char *name, DBVARIANT *result) - { - return db_get_s(hContact, m_szModuleName, name, result); - } - - __forceinline INT_PTR getUString(const char *name, DBVARIANT *result) - { - return db_get_utf(0, m_szModuleName, name, result); - } - __forceinline INT_PTR getUString(MCONTACT hContact, const char *name, DBVARIANT *result) - { - return db_get_utf(hContact, m_szModuleName, name, result); - } - - __forceinline INT_PTR getWString(const char *name, DBVARIANT *result) - { - return db_get_ws(0, m_szModuleName, name, result); - } - __forceinline INT_PTR getWString(MCONTACT hContact, const char *name, DBVARIANT *result) - { - return db_get_ws(hContact, m_szModuleName, name, result); - } - - __forceinline CMStringA getMStringA(const char *name, const char *szValue = nullptr) - { - return db_get_sm(0, m_szModuleName, name, szValue); - } - __forceinline CMStringA getMStringA(MCONTACT hContact, const char *name, const char *szValue = nullptr) - { - return db_get_sm(hContact, m_szModuleName, name, szValue); - } - - __forceinline char* getStringA(const char *name, const char *szValue = nullptr) - { - return db_get_sa(0, m_szModuleName, name, szValue); - } - __forceinline char* getStringA(MCONTACT hContact, const char *name, const char *szValue = nullptr) - { - return db_get_sa(hContact, m_szModuleName, name, szValue); - } - - __forceinline char* getUStringA(const char *name, const char *szValue = nullptr) - { - return db_get_utfa(0, m_szModuleName, name, szValue); - } - __forceinline char* getUStringA(MCONTACT hContact, const char *name, const char *szValue = nullptr) - { - return db_get_utfa(hContact, m_szModuleName, name, szValue); - } - - __forceinline wchar_t* getWStringA(const char *name, const wchar_t *szValue = nullptr) - { - return db_get_wsa(0, m_szModuleName, name, szValue); - } - __forceinline wchar_t* getWStringA(MCONTACT hContact, const char *name, const wchar_t *szValue = nullptr) - { - return db_get_wsa(hContact, m_szModuleName, name, szValue); - } - - __forceinline CMStringW getMStringW(const char *name, const wchar_t *szValue = nullptr) - { - return db_get_wsm(0, m_szModuleName, name, szValue); - } - __forceinline CMStringW getMStringW(MCONTACT hContact, const char *name, const wchar_t *szValue = nullptr) - { - return db_get_wsm(hContact, m_szModuleName, name, szValue); - } - - __forceinline void setByte(const char *name, BYTE value) - { - db_set_b(0, m_szModuleName, name, value); - } - __forceinline void setByte(MCONTACT hContact, const char *name, BYTE value) - { - db_set_b(hContact, m_szModuleName, name, value); - } - - __forceinline void setWord(const char *name, WORD value) - { - db_set_w(0, m_szModuleName, name, value); - } - __forceinline void setWord(MCONTACT hContact, const char *name, WORD value) - { - db_set_w(hContact, m_szModuleName, name, value); - } - - __forceinline void setDword(const char *name, DWORD value) - { - db_set_dw(0, m_szModuleName, name, value); - } - __forceinline void setDword(MCONTACT hContact, const char *name, DWORD value) - { - db_set_dw(hContact, m_szModuleName, name, value); - } - - __forceinline void setString(const char *name, const char* value) - { - db_set_s(0, m_szModuleName, name, value); - } - __forceinline void setString(MCONTACT hContact, const char *name, const char* value) - { - db_set_s(hContact, m_szModuleName, name, value); - } - - __forceinline void setUString(const char *name, const char* value) - { - db_set_utf(0, m_szModuleName, name, value); - } - __forceinline void setUString(MCONTACT hContact, const char *name, const char* value) - { - db_set_utf(hContact, m_szModuleName, name, value); - } - - __forceinline void setWString(const char *name, const wchar_t* value) - { - db_set_ws(0, m_szModuleName, name, value); - } - __forceinline void setWString(MCONTACT hContact, const char *name, const wchar_t* value) - { - db_set_ws(hContact, m_szModuleName, name, value); - } -}; - -#pragma warning(pop) - -extern struct CMPlugin g_plugin; - -///////////////////////////////////////////////////////////////////////////////////////// -// Basic class for plugins (not protocols) written in C++ - -typedef BOOL(WINAPI * const _pfnCrtInit)(HINSTANCE, DWORD, LPVOID); - -template class PLUGIN : public CMPluginBase -{ - typedef CMPluginBase CSuper; - -protected: - __forceinline PLUGIN(const char *moduleName, const PLUGININFOEX &pInfo) - : CSuper(moduleName, pInfo) - {} - - __forceinline HANDLE CreatePluginEvent(const char *name) - { - CMStringA str(FORMAT, "%s\\%s", m_szModuleName, name); - return CreateHookableEvent(str); - } - - typedef int(__cdecl T::*MyEventFunc)(WPARAM, LPARAM); - __forceinline void HookPluginEvent(const char *name, MyEventFunc pFunc) - { - HookEventObj(name, (MIRANDAHOOKOBJ)*(void**)&pFunc, this); - } - - typedef INT_PTR(__cdecl T::*MyServiceFunc)(WPARAM, LPARAM); - __forceinline void CreatePluginService(const char *name, MyServiceFunc pFunc) - { - CMStringA str(FORMAT, "%s\\%s", m_szModuleName, name); - CreateServiceFunctionObj(str, (MIRANDASERVICEOBJ)*(void**)&pFunc, this); - } - - typedef INT_PTR(__cdecl T::*MyServiceFuncParam)(WPARAM, LPARAM, LPARAM); - __forceinline void CreatePluginServiceParam(const char *name, MyServiceFuncParam pFunc, LPARAM param) - { - CMStringA str(FORMAT, "%s\\%s", m_szModuleName, name); - CreateServiceFunctionObjParam(str, (MIRANDASERVICEOBJPARAM)*(void**)&pFunc, this, param); - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Basic class for protocols with accounts - -struct CMPlugin; - -template class ACCPROTOPLUGIN : public PLUGIN -{ - typedef PLUGIN CSuper; - -protected: - ACCPROTOPLUGIN(const char *moduleName, const PLUGININFOEX &pInfo) : - CSuper(moduleName, pInfo) - { - CMPluginBase::RegisterProtocol(1002, &fnInit, &fnUninit); - } - - static PROTO_INTERFACE* fnInit(const char *szModuleName, const wchar_t *wszAccountName) - { - P *ppro = new P(szModuleName, wszAccountName); - g_arInstances.insert(ppro); - return ppro; - } - - static int fnUninit(PROTO_INTERFACE *ppro) - { - g_arInstances.remove((P*)ppro); - return 0; - } - -public: - static OBJLIST

g_arInstances; - - static P* getInstance(const char *szProto) - { - for (auto &it : g_arInstances) - if (mir_strcmp(szProto, it->m_szModuleName) == 0) - return it; - - return nullptr; - } - - static P* getInstance(MCONTACT hContact) - { - return getInstance(::Proto_GetBaseAccountName(hContact)); - } -}; - -template -OBJLIST

ACCPROTOPLUGIN

::g_arInstances(1, PtrKeySortT); - -#ifndef __NO_CMPLUGIN_NEEDED -#ifdef _DEBUG -#pragma comment(lib, "cmstubd.lib") -#else -#pragma comment(lib, "cmstub.lib") -#endif -#endif - -EXTERN_C MIR_APP_DLL(HINSTANCE) GetInstByAddress(void* codePtr); -EXTERN_C MIR_APP_DLL(CMPluginBase&) GetPluginByInstance(HINSTANCE hInst); - -#endif // M_NEWPLUGINAPI_H__ +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org) +Copyright (c) 2000-08 Miranda ICQ/IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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_NEWPLUGINAPI_H__ +#define M_NEWPLUGINAPI_H__ + +#if !defined(HIMAGELIST) +typedef struct _IMAGELIST* HIMAGELIST; +#endif + +#include +#include +#include + +#define PLUGIN_MAKE_VERSION(a, b, c, d) (((((DWORD)(a))&0xFF)<<24)|((((DWORD)(b))&0xFF)<<16)|((((DWORD)(c))&0xFF)<<8)|(((DWORD)(d))&0xFF)) +#define MAXMODULELABELLENGTH 64 + +#define UNICODE_AWARE 0x0001 +#define STATIC_PLUGIN 0x0002 + +MIR_APP_DLL(int) GetPluginLangId(const MUUID &uuid, int langId); +MIR_APP_DLL(int) IsPluginLoaded(const MUUID &uuid); +MIR_APP_DLL(int) SetServiceModePlugin(const char *szPluginName, WPARAM = 0, LPARAM = 0); + +// manually get/set flag specified at Options - Plugins - Enabled +MIR_APP_DLL(bool) IsPluginOnWhiteList(const char *szPluginName); +MIR_APP_DLL(void) SetPluginOnWhiteList(const char *szPluginName, bool bAllow); + +///////////////////////////////////////////////////////////////////////////////////////// +// Used to define the end of the MirandaPluginInterface list + +#define MIID_LAST {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}} + +///////////////////////////////////////////////////////////////////////////////////////// +// Replaceable internal modules interface ids + +#define MIID_HISTORY {0x5ca0cbc1, 0x999a, 0x4ea2, {0x8b, 0x44, 0xf8, 0xf6, 0x7d, 0x7f, 0x8e, 0xbe}} +#define MIID_UIUSERINFO {0x570b931c, 0x9af8, 0x48f1, {0xad, 0x9f, 0xc4, 0x49, 0x8c, 0x61, 0x8a, 0x77}} +#define MIID_SRAWAY {0x5ab54c76, 0x1b4c, 0x4a00, {0xb4, 0x04, 0x48, 0xcb, 0xea, 0x5f, 0xef, 0xe7}} +#define MIID_SREMAIL {0xd005b5a6, 0x1b66, 0x445a, {0xb6, 0x03, 0x74, 0xd4, 0xd4, 0x55, 0x2d, 0xe2}} +#define MIID_SRFILE {0x989d104d, 0xacb7, 0x4ee0, {0xb9, 0x6d, 0x67, 0xce, 0x46, 0x53, 0xb6, 0x95}} +#define MIID_UIHISTORY {0x7f7e3d98, 0xce1f, 0x4962, {0x82, 0x84, 0x96, 0x85, 0x50, 0xf1, 0xd3, 0xd9}} +#define MIID_AUTOAWAY {0x9c87f7dc, 0x3bd7, 0x4983, {0xb7, 0xfb, 0xb8, 0x48, 0xfd, 0xbc, 0x91, 0xf0}} +#define MIID_USERONLINE {0x130829e0, 0x2463, 0x4ff8, {0xbb, 0xc8, 0xce, 0x73, 0xc0, 0x18, 0x84, 0x42}} +#define MIID_CRYPTO {0x415ca6e1, 0x895f, 0x40e6, {0x87, 0xbd, 0x9b, 0x39, 0x60, 0x16, 0xd0, 0xe5}} +#define MIID_POPUP {0xb275f4a4, 0xe347, 0x4515, {0xaf, 0x71, 0x77, 0xd0, 0x1e, 0xef, 0x54, 0x41}} + +///////////////////////////////////////////////////////////////////////////////////////// +// Common plugin interfaces (core plugins) + +#define MIID_DATABASE {0xae77fd33, 0xe484, 0x4dc7, {0x8c, 0xbc, 0x09, 0x9f, 0xed, 0xcc, 0xcf, 0xdd}} +#define MIID_CLIST {0x9d8da8bf, 0x665b, 0x4908, {0x9e, 0x61, 0x9f, 0x75, 0x98, 0xae, 0x33, 0x0e}} +#define MIID_SRMM {0x58c7eea6, 0xf9db, 0x4dd9, {0x80, 0x36, 0xae, 0x80, 0x2b, 0xc0, 0x41, 0x4c}} +#define MIID_TESTPLUGIN {0x53b974f4, 0x3c74, 0x4dba, {0x8f, 0xc2, 0x6f, 0x92, 0xfe, 0x01, 0x3b, 0x8c}} + +///////////////////////////////////////////////////////////////////////////////////////// +// Special exception interface for protocols. +// This interface allows more than one plugin to implement it at the same time + +#define MIID_PROTOCOL {0x2a3c815e, 0xa7d9, 0x424b, {0xba, 0x30, 0x2, 0xd0, 0x83, 0x22, 0x90, 0x85}} + +#define MIID_SERVICEMODE {0x8a92c026, 0x953a, 0x4f5f, { 0x99, 0x21, 0xf2, 0xc2, 0xdc, 0x19, 0x5e, 0xc5}} + +///////////////////////////////////////////////////////////////////////////////////////// +// Each service mode plugin must implement MS_SERVICEMODE_LAUNCH +// This service might return one of the following values: +// SERVICE_CONTINUE - load Miranda normally, like there's no service plugins at all +// SERVICE_ONLYDB - load database and then execute service plugin only +// SERVICE_MONOPOLY - execute only service plugin, even without database +// SERVICE_FAILED - terminate Miranda execution + +#define SERVICE_CONTINUE 0 +#define SERVICE_ONLYDB 1 +#define SERVICE_MONOPOLY 2 +#define SERVICE_FAILED (-1) + +#define MS_SERVICEMODE_LAUNCH "ServiceMode/Launch" + +struct PLUGININFOEX +{ + int cbSize; + char *shortName; + DWORD version; + char *description; + char *author; + char *copyright; + char *homepage; + BYTE flags; // right now the only flag, UNICODE_AWARE, is recognized here + MUUID uuid; // plugin's unique identifier +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Miranda/System/LoadModule event +// called when a plugin is being loaded dynamically +// wParam = CMPluginBase* +// lParam = HINSTANCE of the loaded plugin + +#define ME_SYSTEM_MODULELOAD "Miranda/System/LoadModule" + +///////////////////////////////////////////////////////////////////////////////////////// +// Miranda/System/UnloadModule event +// called when a plugin is being unloaded dynamically +// wParam = CMPluginBase* +// lParam = HINSTANCE of the plugin to be unloaded + +#define ME_SYSTEM_MODULEUNLOAD "Miranda/System/UnloadModule" + +///////////////////////////////////////////////////////////////////////////////////////// +// plugin's class + +// initializes an empty account +typedef struct PROTO_INTERFACE* (*pfnInitProto)(const char* szModuleName, const wchar_t* szUserName); + +// deallocates an account instance +typedef int(*pfnUninitProto)(PROTO_INTERFACE*); + +#pragma warning(push) +#pragma warning(disable:4275) + +struct IcolibItem; + +class MIR_APP_EXPORT CMPluginBase : public MNonCopyable +{ + void tryOpenLog(); + +protected: + HINSTANCE m_hInst; + const char *m_szModuleName; + const PLUGININFOEX &m_pInfo; + HANDLE m_hLogger = nullptr; + LIST m_arIcons; + + CMPluginBase(const char *moduleName, const PLUGININFOEX &pInfo); + ~CMPluginBase(); + + // pass one of PROTOTYPE_* constants as type + void RegisterProtocol(int type, pfnInitProto = nullptr, pfnUninitProto = nullptr); + void SetUniqueId(const char *pszUniqueId); + +public: + void debugLogA(LPCSTR szFormat, ...); + void debugLogW(LPCWSTR wszFormat, ...); + + __forceinline void addIcolib(HANDLE hIcolib) { m_arIcons.insert((IcolibItem*)hIcolib); } + int addImgListIcon(HIMAGELIST himl, int iconId); + HICON getIcon(int iconId, bool big = false); + HANDLE getIconHandle(int iconId); + void releaseIcon(int iconId, bool big = false); + + __forceinline const PLUGININFOEX& getInfo() const { return m_pInfo; } + __forceinline const char* getModule() const { return m_szModuleName; } + + __forceinline HINSTANCE getInst() const { return m_hInst; } + __forceinline void setInst(HINSTANCE hInst) { m_hInst = hInst; } + + virtual int Load(); + virtual int Unload(); + + //////////////////////////////////////////////////////////////////////////////////////// + // registering module's resources + + template + __forceinline void registerIcon(const char *szSection, IconItem(&pIcons)[_Size], const char *prefix = nullptr) + { + Icon_Register(m_hInst, szSection, pIcons, _Size, prefix, this); + } + + template + __forceinline void registerIconW(const wchar_t *szSection, IconItemT(&pIcons)[_Size], const char *prefix = nullptr) + { + Icon_RegisterT(m_hInst, szSection, pIcons, _Size, prefix, this); + } + + int addOptions(WPARAM wParam, struct OPTIONSDIALOGPAGE *odp); + void openOptions(const wchar_t *pszGroup, const wchar_t *pszPage = 0, const wchar_t *pszTab = 0); + void openOptionsPage(const wchar_t *pszGroup, const wchar_t *pszPage = 0, const wchar_t *pszTab = 0); + + HANDLE addIcon(const struct SKINICONDESC*); + HANDLE addTTB(const struct TTBButton*); + + HGENMENU addRootMenu(int hMenuObject, LPCWSTR ptszName, int position, HANDLE hIcoLib = nullptr); + + int addFont(struct FontID *pFont); + int addFont(struct FontIDW *pFont); + + int addColor(struct ColourID *pColor); + int addColor(struct ColourIDW *pColor); + + int addEffect(struct EffectID *pEffect); + int addEffect(struct EffectIDW *pEffect); + + int addFrame(const struct CLISTFrame*); + int addHotkey(const struct HOTKEYDESC*); + int addSound(const char *name, const wchar_t *section, const wchar_t *description, const wchar_t *defaultFile = nullptr); + int addUserInfo(WPARAM wParam, struct OPTIONSDIALOGPAGE *odp); + + //////////////////////////////////////////////////////////////////////////////////////// + + __forceinline INT_PTR delSetting(const char *name) + { + return db_unset(0, m_szModuleName, name); + } + __forceinline INT_PTR delSetting(MCONTACT hContact, const char *name) + { + return db_unset(hContact, m_szModuleName, name); + } + + __forceinline bool getBool(const char *name, bool defaultValue = false) + { + return db_get_b(0, m_szModuleName, name, defaultValue) != 0; + } + __forceinline bool getBool(MCONTACT hContact, const char *name, bool defaultValue = false) + { + return db_get_b(hContact, m_szModuleName, name, defaultValue) != 0; + } + + __forceinline int getByte(const char *name, int defaultValue = 0) + { + return db_get_b(0, m_szModuleName, name, defaultValue); + } + __forceinline int getByte(MCONTACT hContact, const char *name, int defaultValue = 0) + { + return db_get_b(hContact, m_szModuleName, name, defaultValue); + } + + __forceinline int getWord(const char *name, int defaultValue = 0) + { + return db_get_w(0, m_szModuleName, name, defaultValue); + } + __forceinline int getWord(MCONTACT hContact, const char *name, int defaultValue = 0) + { + return db_get_w(hContact, m_szModuleName, name, defaultValue); + } + + __forceinline DWORD getDword(const char *name, int defaultValue = 0) + { + return db_get_dw(0, m_szModuleName, name, defaultValue); + } + __forceinline DWORD getDword(MCONTACT hContact, const char *name, int defaultValue = 0) + { + return db_get_dw(hContact, m_szModuleName, name, defaultValue); + } + + __forceinline INT_PTR getString(const char *name, DBVARIANT *result) + { + return db_get_s(0, m_szModuleName, name, result); + } + __forceinline INT_PTR getString(MCONTACT hContact, const char *name, DBVARIANT *result) + { + return db_get_s(hContact, m_szModuleName, name, result); + } + + __forceinline INT_PTR getUString(const char *name, DBVARIANT *result) + { + return db_get_utf(0, m_szModuleName, name, result); + } + __forceinline INT_PTR getUString(MCONTACT hContact, const char *name, DBVARIANT *result) + { + return db_get_utf(hContact, m_szModuleName, name, result); + } + + __forceinline INT_PTR getWString(const char *name, DBVARIANT *result) + { + return db_get_ws(0, m_szModuleName, name, result); + } + __forceinline INT_PTR getWString(MCONTACT hContact, const char *name, DBVARIANT *result) + { + return db_get_ws(hContact, m_szModuleName, name, result); + } + + __forceinline CMStringA getMStringA(const char *name, const char *szValue = nullptr) + { + return db_get_sm(0, m_szModuleName, name, szValue); + } + __forceinline CMStringA getMStringA(MCONTACT hContact, const char *name, const char *szValue = nullptr) + { + return db_get_sm(hContact, m_szModuleName, name, szValue); + } + + __forceinline char* getStringA(const char *name, const char *szValue = nullptr) + { + return db_get_sa(0, m_szModuleName, name, szValue); + } + __forceinline char* getStringA(MCONTACT hContact, const char *name, const char *szValue = nullptr) + { + return db_get_sa(hContact, m_szModuleName, name, szValue); + } + + __forceinline char* getUStringA(const char *name, const char *szValue = nullptr) + { + return db_get_utfa(0, m_szModuleName, name, szValue); + } + __forceinline char* getUStringA(MCONTACT hContact, const char *name, const char *szValue = nullptr) + { + return db_get_utfa(hContact, m_szModuleName, name, szValue); + } + + __forceinline wchar_t* getWStringA(const char *name, const wchar_t *szValue = nullptr) + { + return db_get_wsa(0, m_szModuleName, name, szValue); + } + __forceinline wchar_t* getWStringA(MCONTACT hContact, const char *name, const wchar_t *szValue = nullptr) + { + return db_get_wsa(hContact, m_szModuleName, name, szValue); + } + + __forceinline CMStringW getMStringW(const char *name, const wchar_t *szValue = nullptr) + { + return db_get_wsm(0, m_szModuleName, name, szValue); + } + __forceinline CMStringW getMStringW(MCONTACT hContact, const char *name, const wchar_t *szValue = nullptr) + { + return db_get_wsm(hContact, m_szModuleName, name, szValue); + } + + __forceinline void setByte(const char *name, BYTE value) + { + db_set_b(0, m_szModuleName, name, value); + } + __forceinline void setByte(MCONTACT hContact, const char *name, BYTE value) + { + db_set_b(hContact, m_szModuleName, name, value); + } + + __forceinline void setWord(const char *name, WORD value) + { + db_set_w(0, m_szModuleName, name, value); + } + __forceinline void setWord(MCONTACT hContact, const char *name, WORD value) + { + db_set_w(hContact, m_szModuleName, name, value); + } + + __forceinline void setDword(const char *name, DWORD value) + { + db_set_dw(0, m_szModuleName, name, value); + } + __forceinline void setDword(MCONTACT hContact, const char *name, DWORD value) + { + db_set_dw(hContact, m_szModuleName, name, value); + } + + __forceinline void setString(const char *name, const char* value) + { + db_set_s(0, m_szModuleName, name, value); + } + __forceinline void setString(MCONTACT hContact, const char *name, const char* value) + { + db_set_s(hContact, m_szModuleName, name, value); + } + + __forceinline void setUString(const char *name, const char* value) + { + db_set_utf(0, m_szModuleName, name, value); + } + __forceinline void setUString(MCONTACT hContact, const char *name, const char* value) + { + db_set_utf(hContact, m_szModuleName, name, value); + } + + __forceinline void setWString(const char *name, const wchar_t* value) + { + db_set_ws(0, m_szModuleName, name, value); + } + __forceinline void setWString(MCONTACT hContact, const char *name, const wchar_t* value) + { + db_set_ws(hContact, m_szModuleName, name, value); + } +}; + +#pragma warning(pop) + +extern struct CMPlugin g_plugin; + +///////////////////////////////////////////////////////////////////////////////////////// +// Basic class for plugins (not protocols) written in C++ + +typedef BOOL(MIR_SYSCALL* const _pfnCrtInit)(HINSTANCE, DWORD, void*); + +template class PLUGIN : public CMPluginBase +{ + typedef CMPluginBase CSuper; + +protected: + __forceinline PLUGIN(const char *moduleName, const PLUGININFOEX &pInfo) + : CSuper(moduleName, pInfo) + {} + + __forceinline HANDLE CreatePluginEvent(const char *name) + { + CMStringA str(FORMAT, "%s\\%s", m_szModuleName, name); + return CreateHookableEvent(str); + } + + typedef int(MIR_CDECL T::*MyEventFunc)(WPARAM, LPARAM); + __forceinline void HookPluginEvent(const char *name, MyEventFunc pFunc) + { + HookEventObj(name, (MIRANDAHOOKOBJ)*(void**)&pFunc, this); + } + + typedef INT_PTR(MIR_CDECL T::*MyServiceFunc)(WPARAM, LPARAM); + __forceinline void CreatePluginService(const char *name, MyServiceFunc pFunc) + { + CMStringA str(FORMAT, "%s\\%s", m_szModuleName, name); + CreateServiceFunctionObj(str, (MIRANDASERVICEOBJ)*(void**)&pFunc, this); + } + + typedef INT_PTR(MIR_CDECL T::*MyServiceFuncParam)(WPARAM, LPARAM, LPARAM); + __forceinline void CreatePluginServiceParam(const char *name, MyServiceFuncParam pFunc, LPARAM param) + { + CMStringA str(FORMAT, "%s\\%s", m_szModuleName, name); + CreateServiceFunctionObjParam(str, (MIRANDASERVICEOBJPARAM)*(void**)&pFunc, this, param); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Basic class for protocols with accounts + +struct CMPlugin; + +template class ACCPROTOPLUGIN : public PLUGIN +{ + typedef PLUGIN CSuper; + +protected: + ACCPROTOPLUGIN(const char *moduleName, const PLUGININFOEX &pInfo) : + CSuper(moduleName, pInfo) + { + CMPluginBase::RegisterProtocol(1002, &fnInit, &fnUninit); + } + + static PROTO_INTERFACE* fnInit(const char *szModuleName, const wchar_t *wszAccountName) + { + P *ppro = new P(szModuleName, wszAccountName); + g_arInstances.insert(ppro); + return ppro; + } + + static int fnUninit(PROTO_INTERFACE *ppro) + { + g_arInstances.remove((P*)ppro); + return 0; + } + +public: + static OBJLIST

g_arInstances; + + static P* getInstance(const char *szProto) + { + for (auto &it : g_arInstances) + if (mir_strcmp(szProto, it->m_szModuleName) == 0) + return it; + + return nullptr; + } + + static P* getInstance(MCONTACT hContact) + { + return getInstance(::Proto_GetBaseAccountName(hContact)); + } +}; + +template +OBJLIST

ACCPROTOPLUGIN

::g_arInstances(1, PtrKeySortT); + +#ifndef __NO_CMPLUGIN_NEEDED +#ifdef _DEBUG +#pragma comment(lib, "cmstubd.lib") +#else +#pragma comment(lib, "cmstub.lib") +#endif +#endif + +EXTERN_C MIR_APP_DLL(HINSTANCE) GetInstByAddress(void* codePtr); +EXTERN_C MIR_APP_DLL(CMPluginBase&) GetPluginByInstance(HINSTANCE hInst); + +#endif // M_NEWPLUGINAPI_H__ diff --git a/libs/Pcre16/pcre16.cbp b/libs/Pcre16/pcre16.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/libs/Pcre16/pcre16.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/libs/Pcre16/pcre16.layout b/libs/Pcre16/pcre16.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/libs/Pcre16/pcre16.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/libs/freeimage/freeimage.cbp b/libs/freeimage/freeimage.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/libs/freeimage/freeimage.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/libs/freeimage/freeimage.layout b/libs/freeimage/freeimage.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/libs/freeimage/freeimage.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/libs/libjson/libjson.cbp b/libs/libjson/libjson.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/libs/libjson/libjson.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/libs/libjson/libjson.layout b/libs/libjson/libjson.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/libs/libjson/libjson.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/libs/libsignal/libsignal.cbp b/libs/libsignal/libsignal.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/libs/libsignal/libsignal.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/libs/libsignal/libsignal.layout b/libs/libsignal/libsignal.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/libs/libsignal/libsignal.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/libs/sqlite3/sqlite3.cbp b/libs/sqlite3/sqlite3.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/libs/sqlite3/sqlite3.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/libs/sqlite3/sqlite3.layout b/libs/sqlite3/sqlite3.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/libs/sqlite3/sqlite3.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/libs/zlib/zlib.cbp b/libs/zlib/zlib.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/libs/zlib/zlib.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/libs/zlib/zlib.layout b/libs/zlib/zlib.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/libs/zlib/zlib.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/AVS/avs.cbp b/plugins/AVS/avs.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/plugins/AVS/avs.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/plugins/AVS/avs.layout b/plugins/AVS/avs.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/plugins/AVS/avs.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/Clist_modern/clist_modern.cbp b/plugins/Clist_modern/clist_modern.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/plugins/Clist_modern/clist_modern.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/plugins/Clist_modern/clist_modern.layout b/plugins/Clist_modern/clist_modern.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/plugins/Clist_modern/clist_modern.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/Clist_modern/icons_pack/Toolbar_icons.cbp b/plugins/Clist_modern/icons_pack/Toolbar_icons.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/plugins/Clist_modern/icons_pack/Toolbar_icons.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/plugins/Clist_modern/icons_pack/Toolbar_icons.layout b/plugins/Clist_modern/icons_pack/Toolbar_icons.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/plugins/Clist_modern/icons_pack/Toolbar_icons.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/Cln_skinedit/skinedit.cbp b/plugins/Cln_skinedit/skinedit.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/plugins/Cln_skinedit/skinedit.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/plugins/Cln_skinedit/skinedit.layout b/plugins/Cln_skinedit/skinedit.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/plugins/Cln_skinedit/skinedit.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/DbChecker/dbchecker.cbp b/plugins/DbChecker/dbchecker.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/plugins/DbChecker/dbchecker.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/plugins/DbChecker/dbchecker.layout b/plugins/DbChecker/dbchecker.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/plugins/DbChecker/dbchecker.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/Dbx_sqlite/dbx_sqlite.cbp b/plugins/Dbx_sqlite/dbx_sqlite.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/plugins/Dbx_sqlite/dbx_sqlite.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/plugins/Dbx_sqlite/dbx_sqlite.layout b/plugins/Dbx_sqlite/dbx_sqlite.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/plugins/Dbx_sqlite/dbx_sqlite.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/Import/import.cbp b/plugins/Import/import.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/plugins/Import/import.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/plugins/Import/import.layout b/plugins/Import/import.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/plugins/Import/import.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/PluginUpdater/PluginUpdater.cbp b/plugins/PluginUpdater/PluginUpdater.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/plugins/PluginUpdater/PluginUpdater.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/plugins/PluginUpdater/PluginUpdater.layout b/plugins/PluginUpdater/PluginUpdater.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/plugins/PluginUpdater/PluginUpdater.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/TabSRMM/TabSRMM_icons/NOVA/ICONS_NOVA_16.cbp b/plugins/TabSRMM/TabSRMM_icons/NOVA/ICONS_NOVA_16.cbp new file mode 100644 index 0000000000..daed7cf466 --- /dev/null +++ b/plugins/TabSRMM/TabSRMM_icons/NOVA/ICONS_NOVA_16.cbp @@ -0,0 +1,138 @@ + + + + + + diff --git a/plugins/TabSRMM/TabSRMM_icons/NOVA/ICONS_NOVA_16.layout b/plugins/TabSRMM/TabSRMM_icons/NOVA/ICONS_NOVA_16.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/plugins/TabSRMM/TabSRMM_icons/NOVA/ICONS_NOVA_16.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/TabSRMM/tabsrmm.cbp b/plugins/TabSRMM/tabsrmm.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/plugins/TabSRMM/tabsrmm.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/plugins/TabSRMM/tabsrmm.layout b/plugins/TabSRMM/tabsrmm.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/plugins/TabSRMM/tabsrmm.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/plugins/TopToolBar/TopToolBar.cbp b/plugins/TopToolBar/TopToolBar.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/plugins/TopToolBar/TopToolBar.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/plugins/TopToolBar/TopToolBar.layout b/plugins/TopToolBar/TopToolBar.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/plugins/TopToolBar/TopToolBar.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/protocols/Facebook/facebook.cbp b/protocols/Facebook/facebook.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/protocols/Facebook/facebook.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/protocols/Facebook/facebook.layout b/protocols/Facebook/facebook.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/protocols/Facebook/facebook.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/protocols/Facebook/proto_facebook/Proto_Facebook.cbp b/protocols/Facebook/proto_facebook/Proto_Facebook.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/protocols/Facebook/proto_facebook/Proto_Facebook.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/protocols/Facebook/proto_facebook/Proto_Facebook.layout b/protocols/Facebook/proto_facebook/Proto_Facebook.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/protocols/Facebook/proto_facebook/Proto_Facebook.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/protocols/Gadu-Gadu/gadugadu.cbp b/protocols/Gadu-Gadu/gadugadu.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/protocols/Gadu-Gadu/gadugadu.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/protocols/Gadu-Gadu/gadugadu.layout b/protocols/Gadu-Gadu/gadugadu.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/protocols/Gadu-Gadu/gadugadu.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/protocols/Gadu-Gadu/proto_gg/Proto_GG.cbp b/protocols/Gadu-Gadu/proto_gg/Proto_GG.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/protocols/Gadu-Gadu/proto_gg/Proto_GG.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/protocols/Gadu-Gadu/proto_gg/Proto_GG.layout b/protocols/Gadu-Gadu/proto_gg/Proto_GG.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/protocols/Gadu-Gadu/proto_gg/Proto_GG.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/protocols/ICQ-WIM/ICQ-WIM.cbp b/protocols/ICQ-WIM/ICQ-WIM.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/protocols/ICQ-WIM/ICQ-WIM.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/protocols/ICQ-WIM/ICQ-WIM.layout b/protocols/ICQ-WIM/ICQ-WIM.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/protocols/ICQ-WIM/ICQ-WIM.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/protocols/ICQ-WIM/proto_icq/Proto_ICQ.cbp b/protocols/ICQ-WIM/proto_icq/Proto_ICQ.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/protocols/ICQ-WIM/proto_icq/Proto_ICQ.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/protocols/ICQ-WIM/proto_icq/Proto_ICQ.layout b/protocols/ICQ-WIM/proto_icq/Proto_ICQ.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/protocols/ICQ-WIM/proto_icq/Proto_ICQ.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/protocols/IRCG/IRC.cbp b/protocols/IRCG/IRC.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/protocols/IRCG/IRC.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/protocols/IRCG/IRC.layout b/protocols/IRCG/IRC.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/protocols/IRCG/IRC.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/protocols/IRCG/proto_irc/Proto_IRC.cbp b/protocols/IRCG/proto_irc/Proto_IRC.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/protocols/IRCG/proto_irc/Proto_IRC.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/protocols/IRCG/proto_irc/Proto_IRC.layout b/protocols/IRCG/proto_irc/Proto_IRC.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/protocols/IRCG/proto_irc/Proto_IRC.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/protocols/JabberG/jabber.cbp b/protocols/JabberG/jabber.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/protocols/JabberG/jabber.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/protocols/JabberG/jabber.layout b/protocols/JabberG/jabber.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/protocols/JabberG/jabber.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/protocols/JabberG/jabber_xstatus/xStatus_Jabber.cbp b/protocols/JabberG/jabber_xstatus/xStatus_Jabber.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/protocols/JabberG/jabber_xstatus/xStatus_Jabber.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/protocols/JabberG/jabber_xstatus/xStatus_Jabber.layout b/protocols/JabberG/jabber_xstatus/xStatus_Jabber.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/protocols/JabberG/jabber_xstatus/xStatus_Jabber.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/protocols/JabberG/proto_jabber/Proto_Jabber.cbp b/protocols/JabberG/proto_jabber/Proto_Jabber.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/protocols/JabberG/proto_jabber/Proto_Jabber.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/protocols/JabberG/proto_jabber/Proto_Jabber.layout b/protocols/JabberG/proto_jabber/Proto_Jabber.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/protocols/JabberG/proto_jabber/Proto_Jabber.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/src/core/stdautoaway/stdautoaway.cbp b/src/core/stdautoaway/stdautoaway.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/src/core/stdautoaway/stdautoaway.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/core/stdautoaway/stdautoaway.layout b/src/core/stdautoaway/stdautoaway.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/src/core/stdautoaway/stdautoaway.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/src/core/stdaway/stdaway.cbp b/src/core/stdaway/stdaway.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/src/core/stdaway/stdaway.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/core/stdaway/stdaway.layout b/src/core/stdaway/stdaway.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/src/core/stdaway/stdaway.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/src/core/stdclist/stdclist.cbp b/src/core/stdclist/stdclist.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/src/core/stdclist/stdclist.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/core/stdclist/stdclist.layout b/src/core/stdclist/stdclist.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/src/core/stdclist/stdclist.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/src/core/stdcrypt/stdcrypt.cbp b/src/core/stdcrypt/stdcrypt.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/src/core/stdcrypt/stdcrypt.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/core/stdcrypt/stdcrypt.layout b/src/core/stdcrypt/stdcrypt.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/src/core/stdcrypt/stdcrypt.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/src/core/stdemail/stdemail.cbp b/src/core/stdemail/stdemail.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/src/core/stdemail/stdemail.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/core/stdemail/stdemail.layout b/src/core/stdemail/stdemail.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/src/core/stdemail/stdemail.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/src/core/stdfile/stdfile.cbp b/src/core/stdfile/stdfile.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/src/core/stdfile/stdfile.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/core/stdfile/stdfile.layout b/src/core/stdfile/stdfile.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/src/core/stdfile/stdfile.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/src/core/stdmsg/stdmsg.cbp b/src/core/stdmsg/stdmsg.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/src/core/stdmsg/stdmsg.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/core/stdmsg/stdmsg.layout b/src/core/stdmsg/stdmsg.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/src/core/stdmsg/stdmsg.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/src/core/stdpopup/stdpopup.cbp b/src/core/stdpopup/stdpopup.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/src/core/stdpopup/stdpopup.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/core/stdpopup/stdpopup.layout b/src/core/stdpopup/stdpopup.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/src/core/stdpopup/stdpopup.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/src/core/stduihist/stduihist.cbp b/src/core/stduihist/stduihist.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/src/core/stduihist/stduihist.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/core/stduihist/stduihist.layout b/src/core/stduihist/stduihist.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/src/core/stduihist/stduihist.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/src/core/stduserinfo/stduserinfo.cbp b/src/core/stduserinfo/stduserinfo.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/src/core/stduserinfo/stduserinfo.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/core/stduserinfo/stduserinfo.layout b/src/core/stduserinfo/stduserinfo.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/src/core/stduserinfo/stduserinfo.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/src/core/stduseronline/stduseronline.cbp b/src/core/stduseronline/stduseronline.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/src/core/stduseronline/stduseronline.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/core/stduseronline/stduseronline.layout b/src/core/stduseronline/stduseronline.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/src/core/stduseronline/stduseronline.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/src/icons/proto_metacontacts/Proto_MetaContacts.cbp b/src/icons/proto_metacontacts/Proto_MetaContacts.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/src/icons/proto_metacontacts/Proto_MetaContacts.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/icons/proto_metacontacts/Proto_MetaContacts.layout b/src/icons/proto_metacontacts/Proto_MetaContacts.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/src/icons/proto_metacontacts/Proto_MetaContacts.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/src/mir_app/mir_app.cbp b/src/mir_app/mir_app.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/src/mir_app/mir_app.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/mir_app/mir_app.layout b/src/mir_app/mir_app.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/src/mir_app/mir_app.layout @@ -0,0 +1,5 @@ + + + + + diff --git a/src/mir_core/main.cpp b/src/mir_core/main.cpp new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/src/mir_core/main.cpp @@ -0,0 +1 @@ + diff --git a/src/mir_core/mir_core.cbp b/src/mir_core/mir_core.cbp new file mode 100644 index 0000000000..b24f650bb3 --- /dev/null +++ b/src/mir_core/mir_core.cbp @@ -0,0 +1,75 @@ + + + + + + diff --git a/src/mir_core/mir_core.depend b/src/mir_core/mir_core.depend new file mode 100644 index 0000000000..bd3a5c7130 --- /dev/null +++ b/src/mir_core/mir_core.depend @@ -0,0 +1,231 @@ +# depslib dependency file v1.0 +1634479263 source:/var/www/miranda-ng/src/mir_core/src/binbuffer.cpp + "stdafx.h" + +1636290589 /var/www/miranda-ng/src/mir_core/src/stdafx.h + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "miranda.h" + + + +1636282921 /var/www/miranda-ng/include/m_system.h + + + +1636291943 /var/www/miranda-ng/include/m_core.h + + + + + +1636292217 /var/www/miranda-ng/include/m_types.h + + + +1636282895 /var/www/miranda-ng/include/m_string.h + + + + + + + +1636283401 /var/www/miranda-ng/include/m_database.h + "m_system.h" + "m_utils.h" + +1634479262 /var/www/miranda-ng/include/m_utils.h + + + + "m_system.h" + +1636283723 /var/www/miranda-ng/include/m_db_int.h + + +1636284034 /var/www/miranda-ng/include/newpluginapi.h + + + + +1634479262 /var/www/miranda-ng/include/m_protocols.h + "statusmodes.h" + + + + +1634479262 /var/www/miranda-ng/include/statusmodes.h + +1634479262 /var/www/miranda-ng/include/m_genmenu.h + + + +1634479262 /var/www/miranda-ng/include/m_langpack.h + + +1634479262 /var/www/miranda-ng/include/m_metacontacts.h + + +1634479262 /var/www/miranda-ng/include/m_skin.h + + +1634479262 /var/www/miranda-ng/include/m_icolib.h + + +1636284288 /var/www/miranda-ng/include/m_netlib.h + "m_utils.h" + +1636284672 /var/www/miranda-ng/include/m_timezones.h + + +1634479262 /var/www/miranda-ng/include/m_button.h + +1636286799 /var/www/miranda-ng/include/m_gui.h + + + + + +1636284756 /var/www/miranda-ng/include/m_protoint.h + + + + + + +1634479262 /var/www/miranda-ng/include/m_protosvc.h + "m_protocols.h" + +1636284822 /var/www/miranda-ng/include/m_clc.h + +1634479262 /var/www/miranda-ng/include/m_chat_int.h + + + + + + + +1634479262 /var/www/miranda-ng/include/m_chat.h + +1636286911 /var/www/miranda-ng/src/mir_core/src/miranda.h + +1636278170 /var/www/miranda-ng/include/m_xml.h + + "../src/mir_core/src/tinyxml2.h" + +1634479263 /var/www/miranda-ng/src/mir_core/src/tinyxml2.h + + + + + + + + + + + + + + + +1636290281 /var/www/miranda-ng/include/m_string.inl + +1634479263 source:/var/www/miranda-ng/src/mir_core/src/lists.cpp + "stdafx.h" + +1634479263 source:/var/www/miranda-ng/src/mir_core/src/sha1.cpp + "stdafx.h" + +1634479263 source:/var/www/miranda-ng/src/mir_core/src/stdafx.cxx + "stdafx.h" + +1634479263 source:/var/www/miranda-ng/src/mir_core/src/tinyxml2.cpp + "stdafx.h" + + + + + + +1636289969 source:/var/www/miranda-ng/src/mir_core/src/Linux/fileutil.cpp + "../stdafx.h" + +1634479263 source:/var/www/miranda-ng/src/mir_core/src/http.cpp + "stdafx.h" + +1636289767 source:/var/www/miranda-ng/src/mir_core/src/logger.cpp + "stdafx.h" + +1636290658 source:/var/www/miranda-ng/src/mir_core/src/md5.cpp + "stdafx.h" + +1636290256 source:/var/www/miranda-ng/src/mir_core/src/db.cpp + "stdafx.h" + +1636290951 source:/var/www/miranda-ng/src/mir_core/src/mstring.cpp + "stdafx.h" + +1636290966 source:/var/www/miranda-ng/src/mir_core/src/sha256.cpp + "stdafx.h" + +1636290782 source:/var/www/miranda-ng/src/mir_core/src/bitmaps.cpp + "stdafx.h" + + +1634479262 /var/www/miranda-ng/include/m_imgsrvc.h + "../libs/freeimage/src/FreeImage.h" + + +1634479262 /var/www/miranda-ng/libs/freeimage/src/FreeImage.h + + + +1636291741 source:/var/www/miranda-ng/src/mir_core/src/memory.cpp + "stdafx.h" + +1634479263 source:/var/www/miranda-ng/src/mir_core/src/tinyxml2_utils.cpp + "stdafx.h" + +1636291998 source:/var/www/miranda-ng/src/mir_core/src/utf.cpp + "stdafx.h" + +1636292418 source:/var/www/miranda-ng/src/mir_core/src/utils.cpp + "stdafx.h" + diff --git a/src/mir_core/mir_core.layout b/src/mir_core/mir_core.layout new file mode 100644 index 0000000000..5ca32c1036 --- /dev/null +++ b/src/mir_core/mir_core.layout @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/mir_core/src/Linux/fileutil.cpp b/src/mir_core/src/Linux/fileutil.cpp new file mode 100644 index 0000000000..e246219f46 --- /dev/null +++ b/src/mir_core/src/Linux/fileutil.cpp @@ -0,0 +1,23 @@ +/* +Copyright (C) 2012-21 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 . +*/ + +#include "../stdafx.h" + +MIR_CORE_DLL(FILE*) _wfopen(const wchar_t *pwszFileName, const wchar_t *pwszMode) +{ + return fopen(T2Utf(pwszFileName), T2Utf(pwszMode)); +} diff --git a/src/mir_core/src/db.cpp b/src/mir_core/src/db.cpp index 9f00db4387..11d28cf84a 100644 --- a/src/mir_core/src/db.cpp +++ b/src/mir_core/src/db.cpp @@ -1,533 +1,538 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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. -*/ - -#include "stdafx.h" - -MIR_CORE_EXPORT MDatabaseCommon* g_pCurrDb = nullptr; - -///////////////////////////////////////////////////////////////////////////////////////// -// database functions - -MIR_CORE_DLL(void) db_set_safety_mode(BOOL bNewMode) -{ - if (g_pCurrDb) - g_pCurrDb->SetCacheSafetyMode(bNewMode != 0); -} - -MIR_CORE_DLL(int) db_get_contact_count(void) -{ - return (g_pCurrDb) ? g_pCurrDb->GetContactCount() : 0; -} - -MIR_CORE_DLL(MDatabaseCommon*) db_get_current() -{ - return g_pCurrDb; -} - -MIR_CORE_DLL(int) db_delete_module(MCONTACT hContact, const char *szModuleName) -{ - return (g_pCurrDb) ? g_pCurrDb->DeleteModule(hContact, szModuleName) : 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// contact functions - -MIR_CORE_DLL(MCONTACT) db_add_contact(void) -{ - MCONTACT hNew = (g_pCurrDb) ? g_pCurrDb->AddContact() : 0; - Netlib_Logf(nullptr, "New contact created: %d", hNew); - return hNew; -} - -MIR_CORE_DLL(int) db_delete_contact(MCONTACT hContact) -{ - ptrW wszPhoto(db_get_wsa(hContact, "ContactPhoto", "File")); - if (wszPhoto != NULL) - DeleteFile(wszPhoto); - - Netlib_Logf(nullptr, "Contact deleted: %d", hContact); - return (g_pCurrDb) ? g_pCurrDb->DeleteContact(hContact) : 0; -} - -MIR_CORE_DLL(int) db_is_contact(MCONTACT hContact) -{ - return (g_pCurrDb) ? g_pCurrDb->IsDbContact(hContact) : 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// enumerators - -MIR_CORE_DLL(int) db_enum_modules(DBMODULEENUMPROC pFunc, void *param) -{ - return (g_pCurrDb) ? g_pCurrDb->EnumModuleNames(pFunc, param) : 0; -} - -MIR_CORE_DLL(int) db_enum_residents(DBMODULEENUMPROC pFunc, void *param) -{ - return (g_pCurrDb) ? g_pCurrDb->EnumResidentSettings(pFunc, param) : 0; -} - -EXTERN_C MIR_CORE_DLL(int) db_enum_settings(MCONTACT hContact, DBSETTINGENUMPROC pFunc, const char *szModule, void *param) -{ - return (g_pCurrDb) ? g_pCurrDb->EnumContactSettings(hContact, pFunc, szModule, param) : 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// getting data - -MIR_CORE_DLL(int) db_get_b(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue) -{ - if (g_pCurrDb != nullptr) { - DBVARIANT dbv; - if (!g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) - { - switch(dbv.type) { - case DBVT_BYTE: return dbv.bVal; - case DBVT_WORD: return BYTE(dbv.wVal); - case DBVT_DWORD: return BYTE(dbv.dVal); - } - g_pCurrDb->FreeVariant(&dbv); - } - } - return errorValue; -} - -MIR_CORE_DLL(int) db_get_w(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue) -{ - if (g_pCurrDb != nullptr) { - DBVARIANT dbv; - if (!g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) { - switch(dbv.type) { - case DBVT_BYTE: return dbv.bVal; - case DBVT_WORD: return dbv.wVal; - case DBVT_DWORD: return WORD(dbv.dVal); - } - g_pCurrDb->FreeVariant(&dbv); - } - } - return errorValue; -} - -MIR_CORE_DLL(DWORD) db_get_dw(MCONTACT hContact, const char *szModule, const char *szSetting, DWORD errorValue) -{ - if (g_pCurrDb != nullptr) { - DBVARIANT dbv; - if (!g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) { - switch(dbv.type) { - case DBVT_BYTE: return dbv.bVal; - case DBVT_WORD: return dbv.wVal; - case DBVT_DWORD: return dbv.dVal; - } - g_pCurrDb->FreeVariant(&dbv); - } - } - - return errorValue; -} - -MIR_CORE_DLL(INT_PTR) db_get(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) -{ - if (g_pCurrDb == nullptr) - return 1; - - return g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, dbv); -} - -MIR_CORE_DLL(INT_PTR) db_get_s(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv, const int nType) -{ - if (g_pCurrDb == nullptr) - return 1; - - dbv->type = (BYTE)nType; - return g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, dbv); -} - -MIR_CORE_DLL(char*) db_get_sa(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue) -{ - if (g_pCurrDb) { - DBVARIANT dbv = { DBVT_ASCIIZ }; - if (!g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) - return dbv.pszVal; - } - - return (szValue == nullptr) ? nullptr : mir_strdup(szValue); -} - -MIR_CORE_DLL(char*) db_get_utfa(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue) -{ - if (g_pCurrDb) { - DBVARIANT dbv = { DBVT_UTF8 }; - if (!g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) - return dbv.pszVal; - } - - return (szValue == nullptr) ? nullptr : mir_strdup(szValue); -} - -MIR_CORE_DLL(wchar_t*) db_get_wsa(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *szValue) -{ - if (g_pCurrDb) { - DBVARIANT dbv = { DBVT_WCHAR }; - if (!g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) - return dbv.pwszVal; - } - - return (szValue == nullptr) ? nullptr : mir_wstrdup(szValue); -} - -MIR_CORE_DLL(CMStringA) db_get_sm(MCONTACT hContact, LPCSTR szModule, LPCSTR szSetting, const char *szValue) -{ - if (g_pCurrDb == nullptr) - return (szValue == nullptr) ? CMStringA() : CMStringA(szValue); - - DBVARIANT dbv = { DBVT_ASCIIZ }; - if (g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) - return (szValue == nullptr) ? CMStringA() : CMStringA(szValue); - - return CMStringA(ptrA(dbv.pszVal)); -} - -MIR_CORE_DLL(CMStringW) db_get_wsm(MCONTACT hContact, LPCSTR szModule, LPCSTR szSetting, const wchar_t *szValue) -{ - if (g_pCurrDb == nullptr) - return (szValue == nullptr) ? CMStringW() : CMStringW(szValue); - - DBVARIANT dbv = { DBVT_WCHAR }; - if (g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) - return (szValue == nullptr) ? CMStringW() : CMStringW(szValue); - - return CMStringW(ptrW(dbv.pwszVal)); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// getting static data - -MIR_CORE_DLL(int) db_get_static(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest) -{ - if (g_pCurrDb == nullptr) - return 1; - - DBVARIANT dbv; - dbv.type = DBVT_ASCIIZ; - dbv.pszVal = pDest; - dbv.cchVal = cbDest; - return g_pCurrDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); -} - -MIR_CORE_DLL(int) db_get_static_utf(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest) -{ - if (g_pCurrDb == nullptr) - return 1; - - DBVARIANT dbv; - dbv.type = DBVT_UTF8; - dbv.pszVal = pDest; - dbv.cchVal = cbDest; - return g_pCurrDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); -} - -MIR_CORE_DLL(int) db_get_wstatic(MCONTACT hContact, const char *szModule, const char *szSetting, wchar_t *pDest, int cbDest) -{ - if (g_pCurrDb == nullptr) - return 1; - - DBVARIANT dbv; - dbv.type = DBVT_WCHAR; - dbv.pwszVal = pDest; - dbv.cchVal = cbDest; - return g_pCurrDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// setting data - -MIR_CORE_DLL(INT_PTR) db_set(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) -{ - if (g_pCurrDb == nullptr) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value = *dbv; - return g_pCurrDb->WriteContactSetting(hContact, &cws); -} - -MIR_CORE_DLL(INT_PTR) db_set_b(MCONTACT hContact, const char *szModule, const char *szSetting, BYTE val) -{ - if (g_pCurrDb == nullptr) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value.type = DBVT_BYTE; - cws.value.bVal = val; - return g_pCurrDb->WriteContactSetting(hContact, &cws); -} - -MIR_CORE_DLL(INT_PTR) db_set_w(MCONTACT hContact, const char *szModule, const char *szSetting, WORD val) -{ - if (g_pCurrDb == nullptr) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value.type = DBVT_WORD; - cws.value.wVal = val; - return g_pCurrDb->WriteContactSetting(hContact, &cws); -} - -MIR_CORE_DLL(INT_PTR) db_set_dw(MCONTACT hContact, const char *szModule, const char *szSetting, DWORD val) -{ - if (g_pCurrDb == nullptr) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value.type = DBVT_DWORD; - cws.value.dVal = val; - return g_pCurrDb->WriteContactSetting(hContact, &cws); -} - -MIR_CORE_DLL(INT_PTR) db_set_s(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val) -{ - if (g_pCurrDb == nullptr) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value.type = DBVT_ASCIIZ; - cws.value.pszVal = (char*)(val == nullptr ? "" : val); - return g_pCurrDb->WriteContactSetting(hContact, &cws); -} - -MIR_CORE_DLL(INT_PTR) db_set_ws(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *val) -{ - if (g_pCurrDb == nullptr) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value.type = DBVT_WCHAR; - cws.value.pwszVal = (wchar_t*)(val == nullptr ? L"" : val); - return g_pCurrDb->WriteContactSetting(hContact, &cws); -} - -MIR_CORE_DLL(INT_PTR) db_set_utf(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val) -{ - if (g_pCurrDb == nullptr) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value.type = DBVT_UTF8; - cws.value.pszVal = (char*)(val == nullptr ? "" : val); - return g_pCurrDb->WriteContactSetting(hContact, &cws); -} - -MIR_CORE_DLL(INT_PTR) db_set_blob(MCONTACT hContact, const char *szModule, const char *szSetting, void *val, unsigned len) -{ - if (g_pCurrDb == nullptr) return 1; - - DBCONTACTWRITESETTING cws; - cws.szModule = szModule; - cws.szSetting = szSetting; - cws.value.type = DBVT_BLOB; - cws.value.cpbVal = (WORD)len; - cws.value.pbVal = (unsigned char*)val; - return g_pCurrDb->WriteContactSetting(hContact, &cws); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// events - -MIR_CORE_DLL(MEVENT) db_event_add(MCONTACT hContact, const DBEVENTINFO *dbei) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->AddEvent(hContact, dbei); -} - -MIR_CORE_DLL(int) db_event_count(MCONTACT hContact) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetEventCount(hContact); -} - -MIR_CORE_DLL(int) db_event_delete(MEVENT hDbEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->DeleteEvent(hDbEvent); -} - -MIR_CORE_DLL(int) db_event_edit(MCONTACT hContact, MEVENT hDbEvent, const DBEVENTINFO *dbei) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->EditEvent(hContact, hDbEvent, dbei); -} - -MIR_CORE_DLL(MEVENT) db_event_first(MCONTACT hContact) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindFirstEvent(hContact); -} - -MIR_CORE_DLL(MEVENT) db_event_firstUnread(MCONTACT hContact) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindFirstUnreadEvent(hContact); -} - -MIR_CORE_DLL(int) db_event_get(MEVENT hDbEvent, DBEVENTINFO *dbei) -{ - return (g_pCurrDb == nullptr) ? 1 : g_pCurrDb->GetEvent(hDbEvent, dbei); -} - -MIR_CORE_DLL(int) db_event_getBlobSize(MEVENT hDbEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetBlobSize(hDbEvent); -} - -MIR_CORE_DLL(MCONTACT) db_event_getContact(MEVENT hDbEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetEventContact(hDbEvent); -} - -MIR_CORE_DLL(MEVENT) db_event_last(MCONTACT hContact) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindLastEvent(hContact); -} - -MIR_CORE_DLL(int) db_event_markRead(MCONTACT hContact, MEVENT hDbEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->MarkEventRead(hContact, hDbEvent); -} - -MIR_CORE_DLL(MEVENT) db_event_next(MCONTACT hContact, MEVENT hDbEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindNextEvent(hContact, hDbEvent); -} - -MIR_CORE_DLL(MEVENT) db_event_prev(MCONTACT hContact, MEVENT hDbEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindPrevEvent(hContact, hDbEvent); -} - -MIR_CORE_DLL(MEVENT) db_event_getById(const char *szModule, const char *szId) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetEventById(szModule, szId); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// event cursors - -DB::EventCursor::~EventCursor() -{ -} - -MIR_CORE_DLL(DB::EventCursor*) DB::Events(MCONTACT hContact, MEVENT iStartEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->EventCursor(hContact, iStartEvent); -} - -MIR_CORE_DLL(DB::EventCursor*) DB::EventsRev(MCONTACT hContact, MEVENT iStartEvent) -{ - return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->EventCursorRev(hContact, iStartEvent); -} - -DB::ECPTR::ECPTR(EventCursor *_pCursor) : - m_cursor(_pCursor), - m_prevFetched(-1), - m_currEvent(0) -{ -} - -DB::ECPTR::~ECPTR() -{ - delete m_cursor; -} - -void DB::ECPTR::DeleteEvent() -{ - m_prevFetched = m_cursor->FetchNext(); - db_event_delete(m_currEvent); -} - -MEVENT DB::ECPTR::FetchNext() -{ - if (m_prevFetched != -1) { - m_currEvent = m_prevFetched; - m_prevFetched = -1; - } - else m_currEvent = m_cursor->FetchNext(); - - return m_currEvent; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// misc functions - -MIR_CORE_DLL(INT_PTR) db_free(DBVARIANT *dbv) -{ - return (g_pCurrDb == nullptr) ? 1 : g_pCurrDb->FreeVariant(dbv); -} - -MIR_CORE_DLL(INT_PTR) db_unset(MCONTACT hContact, const char *szModule, const char *szSetting) -{ - if (g_pCurrDb == nullptr) - return 1; - - return g_pCurrDb->DeleteContactSetting(hContact, szModule, szSetting); -} - -MIR_CORE_DLL(DBCachedContact*) db_get_contact(MCONTACT hContact) -{ - return (g_pCurrDb == nullptr) ? nullptr : g_pCurrDb->getCache()->GetCachedContact(hContact); -} - -MIR_CORE_DLL(MCONTACT) db_find_first(const char *szProto) -{ - return (g_pCurrDb == nullptr) ? NULL : g_pCurrDb->FindFirstContact(szProto); -} - -MIR_CORE_DLL(MCONTACT) db_find_next(MCONTACT hContact, const char *szProto) -{ - return (g_pCurrDb == nullptr) ? NULL : g_pCurrDb->FindNextContact(hContact, szProto); -} - -MIR_CORE_DLL(void) db_setCurrent(MDatabaseCommon *_db) -{ - g_pCurrDb = _db; - if (g_pCurrDb == nullptr) - return; - - // try to get the langpack's name from a profile - ptrW langpack(db_get_wsa(0, "Langpack", "Current")); - if (langpack && langpack[0] != '\0') - LoadLangPack(langpack); - else - GetDefaultLang(); -} - -MIR_CORE_DLL(BOOL) db_set_resident(const char *szModule, const char *szService, BOOL bEnable) -{ - if (g_pCurrDb == nullptr || szModule == nullptr || szService == nullptr) - return FALSE; - - char str[MAXMODULELABELLENGTH * 2]; - mir_snprintf(str, "%s/%s", szModule, szService); - return g_pCurrDb->SetSettingResident(bEnable, str); -} +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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. +*/ + +#include "stdafx.h" + +MIR_CORE_EXPORT MDatabaseCommon* g_pCurrDb = nullptr; + +///////////////////////////////////////////////////////////////////////////////////////// +// database functions + +MIR_CORE_DLL(void) db_set_safety_mode(BOOL bNewMode) +{ + if (g_pCurrDb) + g_pCurrDb->SetCacheSafetyMode(bNewMode != 0); +} + +MIR_CORE_DLL(int) db_get_contact_count(void) +{ + return (g_pCurrDb) ? g_pCurrDb->GetContactCount() : 0; +} + +MIR_CORE_DLL(MDatabaseCommon*) db_get_current() +{ + return g_pCurrDb; +} + +MIR_CORE_DLL(int) db_delete_module(MCONTACT hContact, const char *szModuleName) +{ + return (g_pCurrDb) ? g_pCurrDb->DeleteModule(hContact, szModuleName) : 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// contact functions + +MIR_CORE_DLL(MCONTACT) db_add_contact(void) +{ + MCONTACT hNew = (g_pCurrDb) ? g_pCurrDb->AddContact() : 0; + Netlib_Logf(nullptr, "New contact created: %d", hNew); + return hNew; +} + +MIR_CORE_DLL(int) db_delete_contact(MCONTACT hContact) +{ + ptrW wszPhoto(db_get_wsa(hContact, "ContactPhoto", "File")); + if (wszPhoto != NULL) { + #ifdef _MSC_VER + DeleteFileW(wszPhoto); + #else + remove(T2Utf(wszPhoto)); + #endif + } + + Netlib_Logf(nullptr, "Contact deleted: %d", hContact); + return (g_pCurrDb) ? g_pCurrDb->DeleteContact(hContact) : 0; +} + +MIR_CORE_DLL(int) db_is_contact(MCONTACT hContact) +{ + return (g_pCurrDb) ? g_pCurrDb->IsDbContact(hContact) : 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// enumerators + +MIR_CORE_DLL(int) db_enum_modules(DBMODULEENUMPROC pFunc, void *param) +{ + return (g_pCurrDb) ? g_pCurrDb->EnumModuleNames(pFunc, param) : 0; +} + +MIR_CORE_DLL(int) db_enum_residents(DBMODULEENUMPROC pFunc, void *param) +{ + return (g_pCurrDb) ? g_pCurrDb->EnumResidentSettings(pFunc, param) : 0; +} + +EXTERN_C MIR_CORE_DLL(int) db_enum_settings(MCONTACT hContact, DBSETTINGENUMPROC pFunc, const char *szModule, void *param) +{ + return (g_pCurrDb) ? g_pCurrDb->EnumContactSettings(hContact, pFunc, szModule, param) : 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// getting data + +MIR_CORE_DLL(int) db_get_b(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue) +{ + if (g_pCurrDb != nullptr) { + DBVARIANT dbv; + if (!g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) + { + switch(dbv.type) { + case DBVT_BYTE: return dbv.bVal; + case DBVT_WORD: return BYTE(dbv.wVal); + case DBVT_DWORD: return BYTE(dbv.dVal); + } + g_pCurrDb->FreeVariant(&dbv); + } + } + return errorValue; +} + +MIR_CORE_DLL(int) db_get_w(MCONTACT hContact, const char *szModule, const char *szSetting, int errorValue) +{ + if (g_pCurrDb != nullptr) { + DBVARIANT dbv; + if (!g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) { + switch(dbv.type) { + case DBVT_BYTE: return dbv.bVal; + case DBVT_WORD: return dbv.wVal; + case DBVT_DWORD: return WORD(dbv.dVal); + } + g_pCurrDb->FreeVariant(&dbv); + } + } + return errorValue; +} + +MIR_CORE_DLL(DWORD) db_get_dw(MCONTACT hContact, const char *szModule, const char *szSetting, DWORD errorValue) +{ + if (g_pCurrDb != nullptr) { + DBVARIANT dbv; + if (!g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, &dbv)) { + switch(dbv.type) { + case DBVT_BYTE: return dbv.bVal; + case DBVT_WORD: return dbv.wVal; + case DBVT_DWORD: return dbv.dVal; + } + g_pCurrDb->FreeVariant(&dbv); + } + } + + return errorValue; +} + +MIR_CORE_DLL(INT_PTR) db_get(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) +{ + if (g_pCurrDb == nullptr) + return 1; + + return g_pCurrDb->GetContactSetting(hContact, szModule, szSetting, dbv); +} + +MIR_CORE_DLL(INT_PTR) db_get_s(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv, const int nType) +{ + if (g_pCurrDb == nullptr) + return 1; + + dbv->type = (BYTE)nType; + return g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, dbv); +} + +MIR_CORE_DLL(char*) db_get_sa(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue) +{ + if (g_pCurrDb) { + DBVARIANT dbv = { DBVT_ASCIIZ }; + if (!g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) + return dbv.pszVal; + } + + return (szValue == nullptr) ? nullptr : mir_strdup(szValue); +} + +MIR_CORE_DLL(char*) db_get_utfa(MCONTACT hContact, const char *szModule, const char *szSetting, const char *szValue) +{ + if (g_pCurrDb) { + DBVARIANT dbv = { DBVT_UTF8 }; + if (!g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) + return dbv.pszVal; + } + + return (szValue == nullptr) ? nullptr : mir_strdup(szValue); +} + +MIR_CORE_DLL(wchar_t*) db_get_wsa(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *szValue) +{ + if (g_pCurrDb) { + DBVARIANT dbv = { DBVT_WCHAR }; + if (!g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) + return dbv.pwszVal; + } + + return (szValue == nullptr) ? nullptr : mir_wstrdup(szValue); +} + +MIR_CORE_DLL(CMStringA) db_get_sm(MCONTACT hContact, LPCSTR szModule, LPCSTR szSetting, const char *szValue) +{ + if (g_pCurrDb == nullptr) + return (szValue == nullptr) ? CMStringA() : CMStringA(szValue); + + DBVARIANT dbv = { DBVT_ASCIIZ }; + if (g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) + return (szValue == nullptr) ? CMStringA() : CMStringA(szValue); + + return CMStringA(ptrA(dbv.pszVal).get()); +} + +MIR_CORE_DLL(CMStringW) db_get_wsm(MCONTACT hContact, LPCSTR szModule, LPCSTR szSetting, const wchar_t *szValue) +{ + if (g_pCurrDb == nullptr) + return (szValue == nullptr) ? CMStringW() : CMStringW(szValue); + + DBVARIANT dbv = { DBVT_WCHAR }; + if (g_pCurrDb->GetContactSettingStr(hContact, szModule, szSetting, &dbv)) + return (szValue == nullptr) ? CMStringW() : CMStringW(szValue); + + return CMStringW(ptrW(dbv.pwszVal).get()); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// getting static data + +MIR_CORE_DLL(int) db_get_static(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest) +{ + if (g_pCurrDb == nullptr) + return 1; + + DBVARIANT dbv; + dbv.type = DBVT_ASCIIZ; + dbv.pszVal = pDest; + dbv.cchVal = cbDest; + return g_pCurrDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); +} + +MIR_CORE_DLL(int) db_get_static_utf(MCONTACT hContact, const char *szModule, const char *szSetting, char *pDest, int cbDest) +{ + if (g_pCurrDb == nullptr) + return 1; + + DBVARIANT dbv; + dbv.type = DBVT_UTF8; + dbv.pszVal = pDest; + dbv.cchVal = cbDest; + return g_pCurrDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); +} + +MIR_CORE_DLL(int) db_get_wstatic(MCONTACT hContact, const char *szModule, const char *szSetting, wchar_t *pDest, int cbDest) +{ + if (g_pCurrDb == nullptr) + return 1; + + DBVARIANT dbv; + dbv.type = DBVT_WCHAR; + dbv.pwszVal = pDest; + dbv.cchVal = cbDest; + return g_pCurrDb->GetContactSettingStatic(hContact, szModule, szSetting, &dbv); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// setting data + +MIR_CORE_DLL(INT_PTR) db_set(MCONTACT hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv) +{ + if (g_pCurrDb == nullptr) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value = *dbv; + return g_pCurrDb->WriteContactSetting(hContact, &cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_b(MCONTACT hContact, const char *szModule, const char *szSetting, BYTE val) +{ + if (g_pCurrDb == nullptr) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_BYTE; + cws.value.bVal = val; + return g_pCurrDb->WriteContactSetting(hContact, &cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_w(MCONTACT hContact, const char *szModule, const char *szSetting, WORD val) +{ + if (g_pCurrDb == nullptr) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_WORD; + cws.value.wVal = val; + return g_pCurrDb->WriteContactSetting(hContact, &cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_dw(MCONTACT hContact, const char *szModule, const char *szSetting, DWORD val) +{ + if (g_pCurrDb == nullptr) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_DWORD; + cws.value.dVal = val; + return g_pCurrDb->WriteContactSetting(hContact, &cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_s(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val) +{ + if (g_pCurrDb == nullptr) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_ASCIIZ; + cws.value.pszVal = (char*)(val == nullptr ? "" : val); + return g_pCurrDb->WriteContactSetting(hContact, &cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_ws(MCONTACT hContact, const char *szModule, const char *szSetting, const wchar_t *val) +{ + if (g_pCurrDb == nullptr) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_WCHAR; + cws.value.pwszVal = (wchar_t*)(val == nullptr ? L"" : val); + return g_pCurrDb->WriteContactSetting(hContact, &cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_utf(MCONTACT hContact, const char *szModule, const char *szSetting, const char *val) +{ + if (g_pCurrDb == nullptr) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_UTF8; + cws.value.pszVal = (char*)(val == nullptr ? "" : val); + return g_pCurrDb->WriteContactSetting(hContact, &cws); +} + +MIR_CORE_DLL(INT_PTR) db_set_blob(MCONTACT hContact, const char *szModule, const char *szSetting, void *val, unsigned len) +{ + if (g_pCurrDb == nullptr) return 1; + + DBCONTACTWRITESETTING cws; + cws.szModule = szModule; + cws.szSetting = szSetting; + cws.value.type = DBVT_BLOB; + cws.value.cpbVal = (WORD)len; + cws.value.pbVal = (unsigned char*)val; + return g_pCurrDb->WriteContactSetting(hContact, &cws); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// events + +MIR_CORE_DLL(MEVENT) db_event_add(MCONTACT hContact, const DBEVENTINFO *dbei) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->AddEvent(hContact, dbei); +} + +MIR_CORE_DLL(int) db_event_count(MCONTACT hContact) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetEventCount(hContact); +} + +MIR_CORE_DLL(int) db_event_delete(MEVENT hDbEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->DeleteEvent(hDbEvent); +} + +MIR_CORE_DLL(int) db_event_edit(MCONTACT hContact, MEVENT hDbEvent, const DBEVENTINFO *dbei) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->EditEvent(hContact, hDbEvent, dbei); +} + +MIR_CORE_DLL(MEVENT) db_event_first(MCONTACT hContact) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindFirstEvent(hContact); +} + +MIR_CORE_DLL(MEVENT) db_event_firstUnread(MCONTACT hContact) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindFirstUnreadEvent(hContact); +} + +MIR_CORE_DLL(int) db_event_get(MEVENT hDbEvent, DBEVENTINFO *dbei) +{ + return (g_pCurrDb == nullptr) ? 1 : g_pCurrDb->GetEvent(hDbEvent, dbei); +} + +MIR_CORE_DLL(int) db_event_getBlobSize(MEVENT hDbEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetBlobSize(hDbEvent); +} + +MIR_CORE_DLL(MCONTACT) db_event_getContact(MEVENT hDbEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetEventContact(hDbEvent); +} + +MIR_CORE_DLL(MEVENT) db_event_last(MCONTACT hContact) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindLastEvent(hContact); +} + +MIR_CORE_DLL(int) db_event_markRead(MCONTACT hContact, MEVENT hDbEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->MarkEventRead(hContact, hDbEvent); +} + +MIR_CORE_DLL(MEVENT) db_event_next(MCONTACT hContact, MEVENT hDbEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindNextEvent(hContact, hDbEvent); +} + +MIR_CORE_DLL(MEVENT) db_event_prev(MCONTACT hContact, MEVENT hDbEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->FindPrevEvent(hContact, hDbEvent); +} + +MIR_CORE_DLL(MEVENT) db_event_getById(const char *szModule, const char *szId) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->GetEventById(szModule, szId); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// event cursors + +DB::EventCursor::~EventCursor() +{ +} + +MIR_CORE_DLL(DB::EventCursor*) DB::Events(MCONTACT hContact, MEVENT iStartEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->EventCursor(hContact, iStartEvent); +} + +MIR_CORE_DLL(DB::EventCursor*) DB::EventsRev(MCONTACT hContact, MEVENT iStartEvent) +{ + return (g_pCurrDb == nullptr) ? 0 : g_pCurrDb->EventCursorRev(hContact, iStartEvent); +} + +DB::ECPTR::ECPTR(EventCursor *_pCursor) : + m_cursor(_pCursor), + m_prevFetched(-1), + m_currEvent(0) +{ +} + +DB::ECPTR::~ECPTR() +{ + delete m_cursor; +} + +void DB::ECPTR::DeleteEvent() +{ + m_prevFetched = m_cursor->FetchNext(); + db_event_delete(m_currEvent); +} + +MEVENT DB::ECPTR::FetchNext() +{ + if (m_prevFetched != -1) { + m_currEvent = m_prevFetched; + m_prevFetched = -1; + } + else m_currEvent = m_cursor->FetchNext(); + + return m_currEvent; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// misc functions + +MIR_CORE_DLL(INT_PTR) db_free(DBVARIANT *dbv) +{ + return (g_pCurrDb == nullptr) ? 1 : g_pCurrDb->FreeVariant(dbv); +} + +MIR_CORE_DLL(INT_PTR) db_unset(MCONTACT hContact, const char *szModule, const char *szSetting) +{ + if (g_pCurrDb == nullptr) + return 1; + + return g_pCurrDb->DeleteContactSetting(hContact, szModule, szSetting); +} + +MIR_CORE_DLL(DBCachedContact*) db_get_contact(MCONTACT hContact) +{ + return (g_pCurrDb == nullptr) ? nullptr : g_pCurrDb->getCache()->GetCachedContact(hContact); +} + +MIR_CORE_DLL(MCONTACT) db_find_first(const char *szProto) +{ + return (g_pCurrDb == nullptr) ? NULL : g_pCurrDb->FindFirstContact(szProto); +} + +MIR_CORE_DLL(MCONTACT) db_find_next(MCONTACT hContact, const char *szProto) +{ + return (g_pCurrDb == nullptr) ? NULL : g_pCurrDb->FindNextContact(hContact, szProto); +} + +MIR_CORE_DLL(void) db_setCurrent(MDatabaseCommon *_db) +{ + g_pCurrDb = _db; + if (g_pCurrDb == nullptr) + return; + + // try to get the langpack's name from a profile + ptrW langpack(db_get_wsa(0, "Langpack", "Current")); + if (langpack && langpack[0] != '\0') + LoadLangPack(langpack); + else + GetDefaultLang(); +} + +MIR_CORE_DLL(BOOL) db_set_resident(const char *szModule, const char *szService, BOOL bEnable) +{ + if (g_pCurrDb == nullptr || szModule == nullptr || szService == nullptr) + return FALSE; + + char str[MAXMODULELABELLENGTH * 2]; + mir_snprintf(str, "%s/%s", szModule, szService); + return g_pCurrDb->SetSettingResident(bEnable, str); +} diff --git a/src/mir_core/src/logger.cpp b/src/mir_core/src/logger.cpp index c6a1681139..30244e45e4 100644 --- a/src/mir_core/src/logger.cpp +++ b/src/mir_core/src/logger.cpp @@ -1,222 +1,202 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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. -*/ - -#include "stdafx.h" - -#define SECRET_SIGNATURE 0x87654321 - -struct Logger -{ - Logger(const char* pszName, const wchar_t *ptszDescr, const wchar_t *ptszFilename, unsigned options) : - m_name(mir_strdup(pszName)), - m_descr(mir_wstrdup(ptszDescr)), - m_fileName(mir_wstrdup(ptszFilename)), - m_options(options), - m_signature(SECRET_SIGNATURE), - m_out(nullptr), - m_lastwrite(0) - { - } - - ~Logger() - { - if (m_out) - fclose(m_out); - } - - int m_signature; - ptrA m_name; - ptrW m_fileName, m_descr; - FILE *m_out; - __int64 m_lastwrite; - unsigned m_options; - mir_cs m_cs; -}; - -static int CompareLoggers(const Logger *p1, const Logger *p2) -{ return strcmp(p1->m_name, p2->m_name); -} - -static OBJLIST arLoggers(1, CompareLoggers); - -static __int64 llIdlePeriod; - -void InitLogs() -{ - LARGE_INTEGER li; - QueryPerformanceFrequency(&li); - llIdlePeriod = li.QuadPart; -} - -void UninitLogs() -{ - arLoggers.destroy(); -} - -void CheckLogs() -{ - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - - for (auto &p : arLoggers) { - mir_cslock lck(p->m_cs); - if (p->m_out && li.QuadPart - p->m_lastwrite > llIdlePeriod) { - fclose(p->m_out); - p->m_out = nullptr; - } - else fflush(p->m_out); - } -} - -//////////////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(HANDLE) mir_createLog(const char* pszName, const wchar_t *ptszDescr, const wchar_t *ptszFile, unsigned options) -{ - if (ptszFile == nullptr) - return nullptr; - - Logger *result = new Logger(pszName, ptszDescr, ptszFile, options); - if (result == nullptr) - return nullptr; - - int idx = arLoggers.getIndex(result); - if (idx != -1) { - delete result; - return &arLoggers[idx]; - } - - FILE *fp = _wfopen(ptszFile, L"ab"); - if (fp == nullptr) - CreatePathToFileW(ptszFile); - else - fclose(fp); - - DeleteFile(ptszFile); - arLoggers.insert(result); - return result; -} - -//////////////////////////////////////////////////////////////////////////////////////////////// - -static Logger* prepareLogger(HANDLE hLogger) -{ - if (hLogger == nullptr) - return nullptr; - - Logger *p = (Logger*)hLogger; - return (p->m_signature == SECRET_SIGNATURE) ? p : nullptr; -} - -MIR_CORE_DLL(void) mir_closeLog(HANDLE hLogger) -{ - Logger *p = prepareLogger(hLogger); - if (p != nullptr) - arLoggers.remove(p); -} - -//////////////////////////////////////////////////////////////////////////////////////////////// - -MIR_C_CORE_DLL(int) mir_writeLogA(HANDLE hLogger, const char *format, ...) -{ - Logger *p = prepareLogger(hLogger); - if (p == nullptr) - return 1; - - mir_cslock lck(p->m_cs); - if (p->m_out == nullptr) - if ((p->m_out = _wfopen(p->m_fileName, L"ab")) == nullptr) - return 2; - - va_list args; - va_start(args, format); - vfprintf(p->m_out, format, args); - va_end(args); - - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - p->m_lastwrite = li.QuadPart; - return 0; -} - -MIR_C_CORE_DLL(int) mir_writeLogW(HANDLE hLogger, const wchar_t *format, ...) -{ - Logger *p = prepareLogger(hLogger); - if (p == nullptr) - return 1; - - mir_cslock lck(p->m_cs); - if (p->m_out == nullptr) - if ((p->m_out = _wfopen(p->m_fileName, L"ab")) == nullptr) - return 2; - - va_list args; - va_start(args, format); - vfwprintf(p->m_out, format, args); - va_end(args); - - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - p->m_lastwrite = li.QuadPart; - return 0; -} - -//////////////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(int) mir_writeLogVA(HANDLE hLogger, const char *format, va_list args) -{ - Logger *p = prepareLogger(hLogger); - if (p == nullptr) - return 1; - - mir_cslock lck(p->m_cs); - if (p->m_out == nullptr) - if ((p->m_out = _wfopen(p->m_fileName, L"ab")) == nullptr) - return 2; - - vfprintf(p->m_out, format, args); - - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - p->m_lastwrite = li.QuadPart; - return 0; -} - -MIR_CORE_DLL(int) mir_writeLogVW(HANDLE hLogger, const wchar_t *format, va_list args) -{ - Logger *p = prepareLogger(hLogger); - if (p == nullptr) - return 1; - - mir_cslock lck(p->m_cs); - if (p->m_out == nullptr) - if ((p->m_out = _wfopen(p->m_fileName, L"ab")) == nullptr) - return 2; - - vfwprintf(p->m_out, format, args); - - LARGE_INTEGER li; - QueryPerformanceCounter(&li); - p->m_lastwrite = li.QuadPart; - return 0; -} +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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. +*/ + +#include "stdafx.h" + +#define SECRET_SIGNATURE 0x87654321 + +struct Logger +{ + Logger(const char* pszName, const wchar_t *ptszDescr, const wchar_t *ptszFilename, unsigned options) : + m_name(mir_strdup(pszName)), + m_descr(mir_wstrdup(ptszDescr)), + m_fileName(mir_wstrdup(ptszFilename)), + m_options(options), + m_signature(SECRET_SIGNATURE), + m_out(nullptr), + m_lastwrite(0) + { + } + + ~Logger() + { + if (m_out) + fclose(m_out); + } + + int m_signature; + ptrA m_name; + ptrW m_fileName, m_descr; + FILE *m_out; + __int64_t m_lastwrite; + unsigned m_options; + mir_cs m_cs; +}; + +static int CompareLoggers(const Logger *p1, const Logger *p2) +{ return strcmp(p1->m_name, p2->m_name); +} + +static OBJLIST arLoggers(1, CompareLoggers); + +void InitLogs() +{ +} + +void UninitLogs() +{ + arLoggers.destroy(); +} + +void CheckLogs() +{ + time_t tm = time(0); + + for (auto &p : arLoggers) { + mir_cslock lck(p->m_cs); + if (p->m_out && tm - p->m_lastwrite > 5) { + fclose(p->m_out); + p->m_out = nullptr; + } + else fflush(p->m_out); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(HANDLE) mir_createLog(const char* pszName, const wchar_t *ptszDescr, const wchar_t *ptszFile, unsigned options) +{ + if (ptszFile == nullptr) + return nullptr; + + Logger *result = new Logger(pszName, ptszDescr, ptszFile, options); + if (result == nullptr) + return nullptr; + + int idx = arLoggers.getIndex(result); + if (idx != -1) { + delete result; + return &arLoggers[idx]; + } + + CreatePathToFileW(ptszFile); + arLoggers.insert(result); + return result; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +static Logger* prepareLogger(HANDLE hLogger) +{ + if (hLogger == nullptr) + return nullptr; + + Logger *p = (Logger*)hLogger; + return (p->m_signature == SECRET_SIGNATURE) ? p : nullptr; +} + +MIR_CORE_DLL(void) mir_closeLog(HANDLE hLogger) +{ + Logger *p = prepareLogger(hLogger); + if (p != nullptr) + arLoggers.remove(p); +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +MIR_C_CORE_DLL(int) mir_writeLogA(HANDLE hLogger, const char *format, ...) +{ + Logger *p = prepareLogger(hLogger); + if (p == nullptr) + return 1; + + mir_cslock lck(p->m_cs); + if (p->m_out == nullptr) + if ((p->m_out = _wfopen(p->m_fileName, L"ab")) == nullptr) + return 2; + + va_list args; + va_start(args, format); + vfprintf(p->m_out, format, args); + va_end(args); + + p->m_lastwrite = time(0); + return 0; +} + +MIR_C_CORE_DLL(int) mir_writeLogW(HANDLE hLogger, const wchar_t *format, ...) +{ + Logger *p = prepareLogger(hLogger); + if (p == nullptr) + return 1; + + mir_cslock lck(p->m_cs); + if (p->m_out == nullptr) + if ((p->m_out = _wfopen(p->m_fileName, L"ab")) == nullptr) + return 2; + + va_list args; + va_start(args, format); + vfwprintf(p->m_out, format, args); + va_end(args); + + p->m_lastwrite = time(0); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(int) mir_writeLogVA(HANDLE hLogger, const char *format, va_list args) +{ + Logger *p = prepareLogger(hLogger); + if (p == nullptr) + return 1; + + mir_cslock lck(p->m_cs); + if (p->m_out == nullptr) + if ((p->m_out = _wfopen(p->m_fileName, L"ab")) == nullptr) + return 2; + + vfprintf(p->m_out, format, args); + + p->m_lastwrite = time(0); + return 0; +} + +MIR_CORE_DLL(int) mir_writeLogVW(HANDLE hLogger, const wchar_t *format, va_list args) +{ + Logger *p = prepareLogger(hLogger); + if (p == nullptr) + return 1; + + mir_cslock lck(p->m_cs); + if (p->m_out == nullptr) + if ((p->m_out = _wfopen(p->m_fileName, L"ab")) == nullptr) + return 2; + + vfwprintf(p->m_out, format, args); + + p->m_lastwrite = time(0); + return 0; +} diff --git a/src/mir_core/src/md5.cpp b/src/mir_core/src/md5.cpp index 6cb8419249..8b7b37020f 100644 --- a/src/mir_core/src/md5.cpp +++ b/src/mir_core/src/md5.cpp @@ -1,358 +1,358 @@ -/* - Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.c 2874 2006-05-16 21:38:00Z ghazan $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.c is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -// (C) 2005 Joe @ Whale - changed to compile with Miranda - -#include "stdafx.h" - -#define T_MASK ((UINT32)~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - -//gfd* -static void md5_process(mir_md5_state_t *pms, const BYTE *data /*[64]*/) -{ - UINT32 - a = pms->abcd[0], b = pms->abcd[1], - c = pms->abcd[2], d = pms->abcd[3]; - UINT32 t; - /* Define storage for little-endian or both types of CPUs. */ - UINT32 xbuf[16]; - const UINT32 *X; - - { - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const BYTE *)&w)) /* dynamic little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if ( !((data - (const BYTE *)nullptr) & 3)) { - /* data are properly aligned */ - X = (const UINT32 *)data; - } else { - /* not aligned */ - memcpy(xbuf, data, 64); - X = xbuf; - } - } - else /* dynamic big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const BYTE *xp = data; - int i; - - X = xbuf; /* (dynamic only) */ - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - - /* Round 1. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + F(b, c, d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET1(a, b, c, d, k, s, Ti)\ - t = a + F(b, c, d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET1(a, b, c, d, 0, 7, T1); - SET1(d, a, b, c, 1, 12, T2); - SET1(c, d, a, b, 2, 17, T3); - SET1(b, c, d, a, 3, 22, T4); - SET1(a, b, c, d, 4, 7, T5); - SET1(d, a, b, c, 5, 12, T6); - SET1(c, d, a, b, 6, 17, T7); - SET1(b, c, d, a, 7, 22, T8); - SET1(a, b, c, d, 8, 7, T9); - SET1(d, a, b, c, 9, 12, T10); - SET1(c, d, a, b, 10, 17, T11); - SET1(b, c, d, a, 11, 22, T12); - SET1(a, b, c, d, 12, 7, T13); - SET1(d, a, b, c, 13, 12, T14); - SET1(c, d, a, b, 14, 17, T15); - SET1(b, c, d, a, 15, 22, T16); - - /* Round 2. */ - /* Let [abcd k s i] denote the operation - a = b + ((a + G(b, c, d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET2(a, b, c, d, k, s, Ti)\ - t = a + G(b, c, d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET2(a, b, c, d, 1, 5, T17); - SET2(d, a, b, c, 6, 9, T18); - SET2(c, d, a, b, 11, 14, T19); - SET2(b, c, d, a, 0, 20, T20); - SET2(a, b, c, d, 5, 5, T21); - SET2(d, a, b, c, 10, 9, T22); - SET2(c, d, a, b, 15, 14, T23); - SET2(b, c, d, a, 4, 20, T24); - SET2(a, b, c, d, 9, 5, T25); - SET2(d, a, b, c, 14, 9, T26); - SET2(c, d, a, b, 3, 14, T27); - SET2(b, c, d, a, 8, 20, T28); - SET2(a, b, c, d, 13, 5, T29); - SET2(d, a, b, c, 2, 9, T30); - SET2(c, d, a, b, 7, 14, T31); - SET2(b, c, d, a, 12, 20, T32); - - /* Round 3. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + H(b, c, d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET3(a, b, c, d, k, s, Ti)\ - t = a + H(b, c, d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET3(a, b, c, d, 5, 4, T33); - SET3(d, a, b, c, 8, 11, T34); - SET3(c, d, a, b, 11, 16, T35); - SET3(b, c, d, a, 14, 23, T36); - SET3(a, b, c, d, 1, 4, T37); - SET3(d, a, b, c, 4, 11, T38); - SET3(c, d, a, b, 7, 16, T39); - SET3(b, c, d, a, 10, 23, T40); - SET3(a, b, c, d, 13, 4, T41); - SET3(d, a, b, c, 0, 11, T42); - SET3(c, d, a, b, 3, 16, T43); - SET3(b, c, d, a, 6, 23, T44); - SET3(a, b, c, d, 9, 4, T45); - SET3(d, a, b, c, 12, 11, T46); - SET3(c, d, a, b, 15, 16, T47); - SET3(b, c, d, a, 2, 23, T48); - - /* Round 4. */ - /* Let [abcd k s t] denote the operation - a = b + ((a + I(b, c, d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET4(a, b, c, d, k, s, Ti)\ - t = a + I(b, c, d) + X[k] + Ti;\ - a = ROTATE_LEFT(t, s) + b - /* Do the following 16 operations. */ - SET4(a, b, c, d, 0, 6, T49); - SET4(d, a, b, c, 7, 10, T50); - SET4(c, d, a, b, 14, 15, T51); - SET4(b, c, d, a, 5, 21, T52); - SET4(a, b, c, d, 12, 6, T53); - SET4(d, a, b, c, 3, 10, T54); - SET4(c, d, a, b, 10, 15, T55); - SET4(b, c, d, a, 1, 21, T56); - SET4(a, b, c, d, 8, 6, T57); - SET4(d, a, b, c, 15, 10, T58); - SET4(c, d, a, b, 6, 15, T59); - SET4(b, c, d, a, 13, 21, T60); - SET4(a, b, c, d, 4, 6, T61); - SET4(d, a, b, c, 11, 10, T62); - SET4(c, d, a, b, 2, 15, T63); - SET4(b, c, d, a, 9, 21, T64); - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - pms->abcd[0] += a; - pms->abcd[1] += b; - pms->abcd[2] += c; - pms->abcd[3] += d; -} - -MIR_CORE_DLL(void) mir_md5_init(mir_md5_state_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -MIR_CORE_DLL(void) mir_md5_append(mir_md5_state_t *pms, const BYTE *data, size_t nBytes) -{ - const BYTE *p = data; - size_t left = nBytes; - size_t offset = (pms->count[0] >> 3) & 63; - UINT32 nbits = (UINT32)(nBytes << 3); - - if (nBytes == 0) - return; - - /* Update the message length. */ - pms->count[1] += (UINT32)nBytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - size_t copy = (offset + nBytes > 64 ? 64 - offset : nBytes); - memcpy(pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - - p += copy; - left -= copy; - md5_process(pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - md5_process(pms, p); - - /* Process a final partial block. */ - if (left) - memcpy(pms->buf, p, left); -} - -MIR_CORE_DLL(void) mir_md5_finish(mir_md5_state_t *pms, BYTE digest[16]) -{ - static const BYTE pad[64] = { - 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - BYTE data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (BYTE)(pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - mir_md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - mir_md5_append(pms, data, 8); - for (i = 0; i < 16; ++i) - digest[i] = (BYTE)(pms->abcd[i >> 2] >> ((i & 3) << 3)); -} - -MIR_CORE_DLL(void) mir_md5_hash(const BYTE *data, size_t len, BYTE digest[16]) -{ - mir_md5_state_t state; - mir_md5_init(&state); - mir_md5_append(&state, data, len); - mir_md5_finish(&state, digest); -} +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5.c 2874 2006-05-16 21:38:00Z ghazan $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +// (C) 2005 Joe @ Whale - changed to compile with Miranda + +#include "stdafx.h" + +#define T_MASK ((uint32_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + +//gfd* +static void md5_process(mir_md5_state_t *pms, const BYTE *data /*[64]*/) +{ + uint32_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + uint32_t t; + /* Define storage for little-endian or both types of CPUs. */ + uint32_t xbuf[16]; + const uint32_t *X; + + { + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const BYTE *)&w)) /* dynamic little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if ( !((data - (const BYTE *)nullptr) & 3)) { + /* data are properly aligned */ + X = (const uint32_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } + else /* dynamic big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const BYTE *xp = data; + int i; + + X = xbuf; /* (dynamic only) */ + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b, c, d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET1(a, b, c, d, k, s, Ti)\ + t = a + F(b, c, d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET1(a, b, c, d, 0, 7, T1); + SET1(d, a, b, c, 1, 12, T2); + SET1(c, d, a, b, 2, 17, T3); + SET1(b, c, d, a, 3, 22, T4); + SET1(a, b, c, d, 4, 7, T5); + SET1(d, a, b, c, 5, 12, T6); + SET1(c, d, a, b, 6, 17, T7); + SET1(b, c, d, a, 7, 22, T8); + SET1(a, b, c, d, 8, 7, T9); + SET1(d, a, b, c, 9, 12, T10); + SET1(c, d, a, b, 10, 17, T11); + SET1(b, c, d, a, 11, 22, T12); + SET1(a, b, c, d, 12, 7, T13); + SET1(d, a, b, c, 13, 12, T14); + SET1(c, d, a, b, 14, 17, T15); + SET1(b, c, d, a, 15, 22, T16); + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b, c, d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET2(a, b, c, d, k, s, Ti)\ + t = a + G(b, c, d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET2(a, b, c, d, 1, 5, T17); + SET2(d, a, b, c, 6, 9, T18); + SET2(c, d, a, b, 11, 14, T19); + SET2(b, c, d, a, 0, 20, T20); + SET2(a, b, c, d, 5, 5, T21); + SET2(d, a, b, c, 10, 9, T22); + SET2(c, d, a, b, 15, 14, T23); + SET2(b, c, d, a, 4, 20, T24); + SET2(a, b, c, d, 9, 5, T25); + SET2(d, a, b, c, 14, 9, T26); + SET2(c, d, a, b, 3, 14, T27); + SET2(b, c, d, a, 8, 20, T28); + SET2(a, b, c, d, 13, 5, T29); + SET2(d, a, b, c, 2, 9, T30); + SET2(c, d, a, b, 7, 14, T31); + SET2(b, c, d, a, 12, 20, T32); + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b, c, d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET3(a, b, c, d, k, s, Ti)\ + t = a + H(b, c, d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET3(a, b, c, d, 5, 4, T33); + SET3(d, a, b, c, 8, 11, T34); + SET3(c, d, a, b, 11, 16, T35); + SET3(b, c, d, a, 14, 23, T36); + SET3(a, b, c, d, 1, 4, T37); + SET3(d, a, b, c, 4, 11, T38); + SET3(c, d, a, b, 7, 16, T39); + SET3(b, c, d, a, 10, 23, T40); + SET3(a, b, c, d, 13, 4, T41); + SET3(d, a, b, c, 0, 11, T42); + SET3(c, d, a, b, 3, 16, T43); + SET3(b, c, d, a, 6, 23, T44); + SET3(a, b, c, d, 9, 4, T45); + SET3(d, a, b, c, 12, 11, T46); + SET3(c, d, a, b, 15, 16, T47); + SET3(b, c, d, a, 2, 23, T48); + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b, c, d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET4(a, b, c, d, k, s, Ti)\ + t = a + I(b, c, d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET4(a, b, c, d, 0, 6, T49); + SET4(d, a, b, c, 7, 10, T50); + SET4(c, d, a, b, 14, 15, T51); + SET4(b, c, d, a, 5, 21, T52); + SET4(a, b, c, d, 12, 6, T53); + SET4(d, a, b, c, 3, 10, T54); + SET4(c, d, a, b, 10, 15, T55); + SET4(b, c, d, a, 1, 21, T56); + SET4(a, b, c, d, 8, 6, T57); + SET4(d, a, b, c, 15, 10, T58); + SET4(c, d, a, b, 6, 15, T59); + SET4(b, c, d, a, 13, 21, T60); + SET4(a, b, c, d, 4, 6, T61); + SET4(d, a, b, c, 11, 10, T62); + SET4(c, d, a, b, 2, 15, T63); + SET4(b, c, d, a, 9, 21, T64); + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +MIR_CORE_DLL(void) mir_md5_init(mir_md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +MIR_CORE_DLL(void) mir_md5_append(mir_md5_state_t *pms, const BYTE *data, size_t nBytes) +{ + const BYTE *p = data; + size_t left = nBytes; + size_t offset = (pms->count[0] >> 3) & 63; + uint32_t nbits = (uint32_t)(nBytes << 3); + + if (nBytes == 0) + return; + + /* Update the message length. */ + pms->count[1] += (uint32_t)nBytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + size_t copy = (offset + nBytes > 64 ? 64 - offset : nBytes); + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +MIR_CORE_DLL(void) mir_md5_finish(mir_md5_state_t *pms, BYTE digest[16]) +{ + static const BYTE pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + BYTE data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (BYTE)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + mir_md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + mir_md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (BYTE)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} + +MIR_CORE_DLL(void) mir_md5_hash(const BYTE *data, size_t len, BYTE digest[16]) +{ + mir_md5_state_t state; + mir_md5_init(&state); + mir_md5_append(&state, data, len); + mir_md5_finish(&state, digest); +} diff --git a/src/mir_core/src/memory.cpp b/src/mir_core/src/memory.cpp index 849e42564a..3e3d7be69d 100644 --- a/src/mir_core/src/memory.cpp +++ b/src/mir_core/src/memory.cpp @@ -1,285 +1,295 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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. -*/ - -#include "stdafx.h" - -#define BLOCK_ALLOCED 0xABBABABA -#define BLOCK_FREED 0xDEADBEEF - -static int CheckBlock(void* blk) -{ - int result = FALSE; - char* p = (char*)blk - sizeof(DWORD)*2; - DWORD size, *b, *e; - - __try - { - size = *(DWORD*)p; - b = (DWORD*)&p[ sizeof(DWORD) ]; - e = (DWORD*)&p[ sizeof(DWORD)*2 + size ]; - - if (*b != BLOCK_ALLOCED || *e != BLOCK_ALLOCED) - { - if (*b == BLOCK_FREED && *e == BLOCK_FREED) - OutputDebugStringA("memory block is already deleted\n"); - else - OutputDebugStringA("memory block is corrupted\n"); - #if defined(_DEBUG) - DebugBreak(); - #endif - } - else result = TRUE; - } - __except(EXCEPTION_EXECUTE_HANDLER) - { - OutputDebugStringA("access violation during checking memory block\n"); - #if defined(_DEBUG) - DebugBreak(); - #endif - } - - return result; -} - -/******************************************************************************/ - -MIR_C_CORE_DLL(void*) mir_alloc(size_t size) -{ - if (size == 0) - return nullptr; - - char *p = (char*)malloc(size + sizeof(DWORD)* 3); - if (p == nullptr) { - OutputDebugStringA("memory overflow\n"); - #if defined(_DEBUG) - DebugBreak(); - #endif - return nullptr; - } - - *(DWORD*)p = (DWORD)size; - *(DWORD*)&p[sizeof(DWORD)] = BLOCK_ALLOCED; - *(DWORD*)&p[size + sizeof(DWORD)*2] = BLOCK_ALLOCED; - return p + sizeof(DWORD)* 2; -} - -/******************************************************************************/ - -MIR_C_CORE_DLL(void*) mir_calloc(size_t size) -{ - void* p = mir_alloc(size); - if (p != nullptr) - memset(p, 0, size); - return p; -} - -/******************************************************************************/ - -MIR_C_CORE_DLL(void*) mir_realloc(void* ptr, size_t size) -{ - char *p; - - if (ptr != nullptr) { - if (!CheckBlock(ptr)) - return nullptr; - p = (char*)ptr - sizeof(DWORD)*2; - } - else p = nullptr; - - p = (char*)realloc(p, size + sizeof(DWORD)*3); - if (p == nullptr) { - OutputDebugStringA("memory overflow\n"); - #if defined(_DEBUG) - DebugBreak(); - #endif - return nullptr; - } - - *(DWORD*)p = (DWORD)size; - *(DWORD*)&p[sizeof(DWORD)] = BLOCK_ALLOCED; - *(DWORD*)&p[size + sizeof(DWORD)*2] = BLOCK_ALLOCED; - return p + sizeof(DWORD)*2; -} - -/******************************************************************************/ - -MIR_C_CORE_DLL(void) mir_free(void* ptr) -{ - char* p; - DWORD size; - - if (ptr == nullptr) - return; - if (!CheckBlock(ptr)) - return; - - p = (char*)ptr - sizeof(DWORD)*2; - size = *(DWORD*)p; - - *(DWORD*)&p[sizeof(DWORD)] = BLOCK_FREED; - *(DWORD*)&p[size + sizeof(DWORD)*2] = BLOCK_FREED; - free(p); -} - -/******************************************************************************/ - -MIR_CORE_DLL(char*) mir_strdup(const char *str) -{ - if (str == nullptr) - return nullptr; - - char *p = (char*)mir_alloc(strlen(str)+1); - if (p) - strcpy(p, str); - return p; -} - -MIR_CORE_DLL(wchar_t*) mir_wstrdup(const wchar_t *str) -{ - if (str == nullptr) - return nullptr; - - wchar_t *p = (wchar_t*)mir_alloc(sizeof(wchar_t)*(wcslen(str)+1)); - if (p) - wcscpy(p, str); - return p; -} - -/******************************************************************************/ - -MIR_CORE_DLL(char*) mir_strndup(const char *str, size_t len) -{ - if (str == nullptr || len == 0) - return nullptr; - - char *p = (char*)mir_alloc(len+1); - if (p) { - memcpy(p, str, len); - p[len] = 0; - } - return p; -} - -MIR_CORE_DLL(wchar_t*) mir_wstrndup(const wchar_t *str, size_t len) -{ - if (str == nullptr || len == 0) - return nullptr; - - wchar_t *p = (wchar_t*)mir_alloc(sizeof(wchar_t)*(len+1)); - if (p) { - memcpy(p, str, sizeof(wchar_t)*len); - p[len] = 0; - } - return p; -} - -/******************************************************************************/ - -MIR_CORE_DLL(int) mir_snprintf(char *buffer, size_t count, const char* fmt, ...) -{ - va_list va; - va_start(va, fmt); - int len = _vsnprintf(buffer, count-1, fmt, va); - va_end(va); - buffer[count-1] = 0; - return len; -} - -/******************************************************************************/ - -MIR_CORE_DLL(int) mir_snwprintf(wchar_t *buffer, size_t count, const wchar_t* fmt, ...) -{ - va_list va; - va_start(va, fmt); - int len = _vsnwprintf(buffer, count-1, fmt, va); - va_end(va); - buffer[count-1] = 0; - return len; -} - -/******************************************************************************/ - -MIR_CORE_DLL(int) mir_vsnprintf(char *buffer, size_t count, const char* fmt, va_list va) -{ - int len = _vsnprintf(buffer, count-1, fmt, va); - buffer[count-1] = 0; - return len; -} - -/******************************************************************************/ - -MIR_CORE_DLL(int) mir_vsnwprintf(wchar_t *buffer, size_t count, const wchar_t* fmt, va_list va) -{ - int len = _vsnwprintf(buffer, count-1, fmt, va); - buffer[count-1] = 0; - return len; -} - -/******************************************************************************/ - -MIR_CORE_DLL(wchar_t*) mir_a2u_cp(const char* src, int codepage) -{ - if (src == nullptr) - return nullptr; - - int cbLen = MultiByteToWideChar(codepage, 0, src, -1, nullptr, 0); - wchar_t* result = (wchar_t*)mir_alloc(sizeof(wchar_t)*(cbLen+1)); - if (result == nullptr) - return nullptr; - - MultiByteToWideChar(codepage, 0, src, -1, result, cbLen); - result[cbLen] = 0; - return result; -} - -/******************************************************************************/ - -MIR_CORE_DLL(wchar_t*) mir_a2u(const char* src) -{ - return mir_a2u_cp(src, Langpack_GetDefaultCodePage()); -} - -/******************************************************************************/ - -MIR_CORE_DLL(char*) mir_u2a_cp(const wchar_t* src, int codepage) -{ - if (src == nullptr) - return nullptr; - - int cbLen = WideCharToMultiByte(codepage, 0, src, -1, nullptr, 0, nullptr, nullptr); - char* result = (char*)mir_alloc(cbLen+1); - if (result == nullptr) - return nullptr; - - WideCharToMultiByte(codepage, 0, src, -1, result, cbLen, nullptr, nullptr); - result[cbLen] = 0; - return result; -} - -/******************************************************************************/ - -MIR_CORE_DLL(char*) mir_u2a(const wchar_t* src) -{ - return mir_u2a_cp(src, Langpack_GetDefaultCodePage()); -} +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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. +*/ + +#include "stdafx.h" + +#define BLOCK_ALLOCED 0xABBABABA +#define BLOCK_FREED 0xDEADBEEF + +static int CheckBlock(void* blk) +{ + int result = FALSE; + char* p = (char*)blk - sizeof(DWORD)*2; + DWORD size, *b, *e; + + __try + { + size = *(DWORD*)p; + b = (DWORD*)&p[ sizeof(DWORD) ]; + e = (DWORD*)&p[ sizeof(DWORD)*2 + size ]; + + if (*b != BLOCK_ALLOCED || *e != BLOCK_ALLOCED) + { + #ifdef _MSC_VER + if (*b == BLOCK_FREED && *e == BLOCK_FREED) + OutputDebugStringA("memory block is already deleted\n"); + else + OutputDebugStringA("memory block is corrupted\n"); + #if defined(_DEBUG) + DebugBreak(); + #endif + #endif + } + else result = TRUE; + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + #ifdef _MSC_VER + OutputDebugStringA("access violation during checking memory block\n"); + #if defined(_DEBUG) + DebugBreak(); + #endif + #endif + } + + return result; +} + +/******************************************************************************/ + +MIR_C_CORE_DLL(void*) mir_alloc(size_t size) +{ + if (size == 0) + return nullptr; + + char *p = (char*)malloc(size + sizeof(DWORD)* 3); + if (p == nullptr) { + #ifdef _MSC_VER + OutputDebugStringA("memory overflow\n"); + #if defined(_DEBUG) + DebugBreak(); + #endif + #endif + return nullptr; + } + + *(DWORD*)p = (DWORD)size; + *(DWORD*)&p[sizeof(DWORD)] = BLOCK_ALLOCED; + *(DWORD*)&p[size + sizeof(DWORD)*2] = BLOCK_ALLOCED; + return p + sizeof(DWORD)* 2; +} + +/******************************************************************************/ + +MIR_C_CORE_DLL(void*) mir_calloc(size_t size) +{ + void* p = mir_alloc(size); + if (p != nullptr) + memset(p, 0, size); + return p; +} + +/******************************************************************************/ + +MIR_C_CORE_DLL(void*) mir_realloc(void* ptr, size_t size) +{ + char *p; + + if (ptr != nullptr) { + if (!CheckBlock(ptr)) + return nullptr; + p = (char*)ptr - sizeof(DWORD)*2; + } + else p = nullptr; + + p = (char*)realloc(p, size + sizeof(DWORD)*3); + if (p == nullptr) { + #ifdef _MSC_VER + OutputDebugStringA("memory overflow\n"); + #if defined(_DEBUG) + DebugBreak(); + #endif + #endif + return nullptr; + } + + *(DWORD*)p = (DWORD)size; + *(DWORD*)&p[sizeof(DWORD)] = BLOCK_ALLOCED; + *(DWORD*)&p[size + sizeof(DWORD)*2] = BLOCK_ALLOCED; + return p + sizeof(DWORD)*2; +} + +/******************************************************************************/ + +MIR_C_CORE_DLL(void) mir_free(void* ptr) +{ + char* p; + DWORD size; + + if (ptr == nullptr) + return; + if (!CheckBlock(ptr)) + return; + + p = (char*)ptr - sizeof(DWORD)*2; + size = *(DWORD*)p; + + *(DWORD*)&p[sizeof(DWORD)] = BLOCK_FREED; + *(DWORD*)&p[size + sizeof(DWORD)*2] = BLOCK_FREED; + free(p); +} + +/******************************************************************************/ + +MIR_CORE_DLL(char*) mir_strdup(const char *str) +{ + if (str == nullptr) + return nullptr; + + char *p = (char*)mir_alloc(strlen(str)+1); + if (p) + strcpy(p, str); + return p; +} + +MIR_CORE_DLL(wchar_t*) mir_wstrdup(const wchar_t *str) +{ + if (str == nullptr) + return nullptr; + + wchar_t *p = (wchar_t*)mir_alloc(sizeof(wchar_t)*(wcslen(str)+1)); + if (p) + wcscpy(p, str); + return p; +} + +/******************************************************************************/ + +MIR_CORE_DLL(char*) mir_strndup(const char *str, size_t len) +{ + if (str == nullptr || len == 0) + return nullptr; + + char *p = (char*)mir_alloc(len+1); + if (p) { + memcpy(p, str, len); + p[len] = 0; + } + return p; +} + +MIR_CORE_DLL(wchar_t*) mir_wstrndup(const wchar_t *str, size_t len) +{ + if (str == nullptr || len == 0) + return nullptr; + + wchar_t *p = (wchar_t*)mir_alloc(sizeof(wchar_t)*(len+1)); + if (p) { + memcpy(p, str, sizeof(wchar_t)*len); + p[len] = 0; + } + return p; +} + +/******************************************************************************/ + +MIR_CORE_DLL(int) mir_snprintf(char *buffer, size_t count, const char* fmt, ...) +{ + va_list va; + va_start(va, fmt); + int len = _vsnprintf(buffer, count-1, fmt, va); + va_end(va); + buffer[count-1] = 0; + return len; +} + +/******************************************************************************/ + +MIR_CORE_DLL(int) mir_snwprintf(wchar_t *buffer, size_t count, const wchar_t* fmt, ...) +{ + va_list va; + va_start(va, fmt); + int len = _vsnwprintf(buffer, count-1, fmt, va); + va_end(va); + buffer[count-1] = 0; + return len; +} + +/******************************************************************************/ + +MIR_CORE_DLL(int) mir_vsnprintf(char *buffer, size_t count, const char* fmt, va_list va) +{ + int len = _vsnprintf(buffer, count-1, fmt, va); + buffer[count-1] = 0; + return len; +} + +/******************************************************************************/ + +MIR_CORE_DLL(int) mir_vsnwprintf(wchar_t *buffer, size_t count, const wchar_t* fmt, va_list va) +{ + int len = _vsnwprintf(buffer, count-1, fmt, va); + buffer[count-1] = 0; + return len; +} + +/******************************************************************************/ + +#ifdef _MSC_VER +MIR_CORE_DLL(wchar_t*) mir_a2u_cp(const char* src, int codepage) +{ + if (src == nullptr) + return nullptr; + + int cbLen = MultiByteToWideChar(codepage, 0, src, -1, nullptr, 0); + wchar_t* result = (wchar_t*)mir_alloc(sizeof(wchar_t)*(cbLen+1)); + if (result == nullptr) + return nullptr; + + MultiByteToWideChar(codepage, 0, src, -1, result, cbLen); + result[cbLen] = 0; + return result; +} + +/******************************************************************************/ + +MIR_CORE_DLL(wchar_t*) mir_a2u(const char* src) +{ + return mir_a2u_cp(src, Langpack_GetDefaultCodePage()); +} + +/******************************************************************************/ + +MIR_CORE_DLL(char*) mir_u2a_cp(const wchar_t* src, int codepage) +{ + if (src == nullptr) + return nullptr; + + int cbLen = WideCharToMultiByte(codepage, 0, src, -1, nullptr, 0, nullptr, nullptr); + char* result = (char*)mir_alloc(cbLen+1); + if (result == nullptr) + return nullptr; + + WideCharToMultiByte(codepage, 0, src, -1, result, cbLen, nullptr, nullptr); + result[cbLen] = 0; + return result; +} + +/******************************************************************************/ + +MIR_CORE_DLL(char*) mir_u2a(const wchar_t* src) +{ + return mir_u2a_cp(src, Langpack_GetDefaultCodePage()); +} +#endif diff --git a/src/mir_core/src/miranda.h b/src/mir_core/src/miranda.h index 4805798fdd..32ea470e58 100644 --- a/src/mir_core/src/miranda.h +++ b/src/mir_core/src/miranda.h @@ -1,93 +1,93 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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. -*/ - -#pragma once - -void UnloadLangPackModule(void); - -int InitialiseModularEngine(void); -void DestroyModularEngine(void); - -int InitPathUtils(void); - -extern HINSTANCE g_hInst; -extern HWND hAPCWindow; -extern HANDLE hThreadQueueEmpty; -extern HCURSOR g_hCursorNS, g_hCursorWE; - -///////////////////////////////////////////////////////////////////////////////////////// -// modules.cpp - -struct THookSubscriber -{ - HINSTANCE hOwner; - int type; - union { - struct { - union { - MIRANDAHOOK pfnHook; - MIRANDAHOOKPARAM pfnHookParam; - MIRANDAHOOKOBJ pfnHookObj; - MIRANDAHOOKOBJPARAM pfnHookObjParam; - }; - void* object; - LPARAM lParam; - }; - struct { - HWND hwnd; - UINT message; - }; - }; -}; - -#define HOOK_SECRET_SIGNATURE 0xDEADBABA - -struct THook : public MZeroedObject -{ - char name[ MAXMODULELABELLENGTH ]; - int id; - int subscriberCount; - THookSubscriber* subscriber; - MIRANDAHOOK pfnHook; - DWORD secretSignature = HOOK_SECRET_SIGNATURE; - mir_cs csHook; -}; - -extern LIST pluginListAddr; - -///////////////////////////////////////////////////////////////////////////////////////// -// langpack.cpp - -char* LangPackTranslateString(const MUUID *pUuid, const char *szEnglish, const int W); - -///////////////////////////////////////////////////////////////////////////////////////// -// threads.cpp - -extern DWORD mir_tls; - -///////////////////////////////////////////////////////////////////////////////////////// -// utils.cpp - -typedef BOOL(APIENTRY *PGENRANDOM)(PVOID, ULONG); -extern PGENRANDOM pfnRtlGenRandom; +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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. +*/ + +#pragma once + +void UnloadLangPackModule(void); + +int InitialiseModularEngine(void); +void DestroyModularEngine(void); + +int InitPathUtils(void); + +extern HINSTANCE g_hInst; +extern HWND hAPCWindow; +extern HANDLE hThreadQueueEmpty; +extern HCURSOR g_hCursorNS, g_hCursorWE; + +///////////////////////////////////////////////////////////////////////////////////////// +// modules.cpp + +struct THookSubscriber +{ + HINSTANCE hOwner; + int type; + union { + struct { + union { + MIRANDAHOOK pfnHook; + MIRANDAHOOKPARAM pfnHookParam; + MIRANDAHOOKOBJ pfnHookObj; + MIRANDAHOOKOBJPARAM pfnHookObjParam; + }; + void* object; + LPARAM lParam; + }; + struct { + HWND hwnd; + UINT message; + }; + }; +}; + +#define HOOK_SECRET_SIGNATURE 0xDEADBABA + +struct THook : public MZeroedObject +{ + char name[ MAXMODULELABELLENGTH ]; + int id; + int subscriberCount; + THookSubscriber* subscriber; + MIRANDAHOOK pfnHook; + DWORD secretSignature = HOOK_SECRET_SIGNATURE; + mir_cs csHook; +}; + +extern LIST pluginListAddr; + +///////////////////////////////////////////////////////////////////////////////////////// +// langpack.cpp + +char* LangPackTranslateString(const MUUID *pUuid, const char *szEnglish, const int W); + +///////////////////////////////////////////////////////////////////////////////////////// +// threads.cpp + +extern DWORD mir_tls; + +///////////////////////////////////////////////////////////////////////////////////////// +// utils.cpp + +typedef BOOL(MIR_SYSCALL *PGENRANDOM)(void*, DWORD); +extern PGENRANDOM pfnRtlGenRandom; diff --git a/src/mir_core/src/mstring.cpp b/src/mir_core/src/mstring.cpp index 2779c93978..3982fc8d61 100644 --- a/src/mir_core/src/mstring.cpp +++ b/src/mir_core/src/mstring.cpp @@ -1,142 +1,140 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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. -*/ - -#include "stdafx.h" - -///////////////////////////////////////////////////////////////////////////////////////// -// CMBaseString - -class CNilMStringData : public CMStringData -{ -public: - CNilMStringData(); - -public: - wchar_t achNil[2]; -}; - -CNilMStringData::CNilMStringData() -{ - nRefs = 2; // Never gets freed - nDataLength = 0; - nAllocLength = 0; - achNil[0] = 0; - achNil[1] = 0; -} - -static CNilMStringData *m_nil = nullptr; - -///////////////////////////////////////////////////////////////////////////////////////// -// CMBaseString - -MIR_CORE_DLL(CMStringData*) mirstr_allocate(int nChars, int nCharSize) -{ - nChars++; // nil char - size_t nDataBytes = nCharSize * nChars; - size_t nTotalSize = nDataBytes + sizeof(CMStringData); - - CMStringData *pData = static_cast(malloc(nTotalSize)); - if (pData == nullptr) - return nullptr; - - pData->nRefs = 1; - pData->nAllocLength = nChars - 1; - pData->nDataLength = 0; - return pData; -} - -MIR_CORE_DLL(void) mirstr_free(CMStringData *pData) -{ - free(pData); -} - -MIR_CORE_DLL(CMStringData*) mirstr_realloc(CMStringData* pData, int nChars, int nCharSize) -{ - nChars++; // nil char - ULONG nDataBytes = nCharSize * nChars; - ULONG nTotalSize = nDataBytes + sizeof(CMStringData); - - CMStringData *pNewData = static_cast(realloc(pData, nTotalSize)); - if (pNewData == nullptr) - return nullptr; - - pNewData->nAllocLength = nChars - 1; - return pNewData; -} - -MIR_CORE_DLL(CMStringData*) mirstr_getNil() -{ - if (m_nil == nullptr) - m_nil = new CNilMStringData(); - m_nil->AddRef(); - return m_nil; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// CMStringData - -MIR_CORE_DLL(void) mirstr_lock(CMStringData* pThis) -{ - pThis->nRefs--; // Locked buffers can't be shared, so no interlocked operation necessary - if (pThis->nRefs == 0) - pThis->nRefs = -1; -} - -MIR_CORE_DLL(void) mirstr_release(CMStringData* pThis) -{ - if (InterlockedDecrement(&pThis->nRefs) <= 0) - mirstr_free(pThis); -} - -MIR_CORE_DLL(void) mirstr_unlock(CMStringData* pThis) -{ - if (pThis->IsLocked()) - { - pThis->nRefs++; // Locked buffers can't be shared, so no interlocked operation necessary - if (pThis->nRefs == 0) - pThis->nRefs = 1; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// -// don't remove it -// this code just instantiates templates for CMStringW[A/W] - -template CMStringW; -template MIR_CORE_EXPORT CMStringW CALLBACK operator + (const CMStringW& str1, const CMStringW& str2); -template MIR_CORE_EXPORT CMStringW CALLBACK operator+(const CMStringW& str1, const wchar_t *psz2); -template MIR_CORE_EXPORT CMStringW CALLBACK operator+(const wchar_t *psz1, const CMStringW& str2); -template MIR_CORE_EXPORT CMStringW CALLBACK operator+(const CMStringW& str1, wchar_t ch2); -template MIR_CORE_EXPORT CMStringW CALLBACK operator+(const CMStringW& str1, char ch2); -template MIR_CORE_EXPORT CMStringW CALLBACK operator+(wchar_t ch1, const CMStringW& str2); -template MIR_CORE_EXPORT CMStringW CALLBACK operator+(char ch1, const CMStringW& str2); - -template CMStringA; -template MIR_CORE_EXPORT CMStringA CALLBACK operator+(const CMStringA& str1, const CMStringA& str2); -template MIR_CORE_EXPORT CMStringA CALLBACK operator+(const CMStringA& str1, const char *psz2); -template MIR_CORE_EXPORT CMStringA CALLBACK operator+(const char *psz1, const CMStringA& str2); -template MIR_CORE_EXPORT CMStringA CALLBACK operator+(const CMStringA& str1, wchar_t ch2); -template MIR_CORE_EXPORT CMStringA CALLBACK operator+(const CMStringA& str1, char ch2); -template MIR_CORE_EXPORT CMStringA CALLBACK operator+(wchar_t ch1, const CMStringA& str2); -template MIR_CORE_EXPORT CMStringA CALLBACK operator+(char ch1, const CMStringA& str2); +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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. +*/ + +#include "stdafx.h" + +///////////////////////////////////////////////////////////////////////////////////////// +// CMBaseString + +class CNilMStringData : public CMStringData +{ +public: + CNilMStringData(); + +public: + wchar_t achNil[2]; +}; + +CNilMStringData::CNilMStringData() +{ + nRefs = 2; // Never gets freed + nDataLength = 0; + nAllocLength = 0; + achNil[0] = 0; + achNil[1] = 0; +} + +static CNilMStringData *m_nil = nullptr; + +///////////////////////////////////////////////////////////////////////////////////////// +// CMBaseString + +MIR_CORE_DLL(CMStringData*) mirstr_allocate(int nChars, int nCharSize) +{ + nChars++; // nil char + size_t nDataBytes = nCharSize * nChars; + size_t nTotalSize = nDataBytes + sizeof(CMStringData); + + CMStringData *pData = static_cast(malloc(nTotalSize)); + if (pData == nullptr) + return nullptr; + + pData->nRefs = 1; + pData->nAllocLength = nChars - 1; + pData->nDataLength = 0; + return pData; +} + +MIR_CORE_DLL(void) mirstr_free(CMStringData *pData) +{ + free(pData); +} + +MIR_CORE_DLL(CMStringData*) mirstr_realloc(CMStringData* pData, int nChars, int nCharSize) +{ + nChars++; // nil char + uint32_t nDataBytes = nCharSize * nChars; + uint32_t nTotalSize = nDataBytes + sizeof(CMStringData); + + CMStringData *pNewData = static_cast(realloc(pData, nTotalSize)); + if (pNewData == nullptr) + return nullptr; + + pNewData->nAllocLength = nChars - 1; + return pNewData; +} + +MIR_CORE_DLL(CMStringData*) mirstr_getNil() +{ + if (m_nil == nullptr) + m_nil = new CNilMStringData(); + m_nil->AddRef(); + return m_nil; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// CMStringData + +MIR_CORE_DLL(void) mirstr_lock(CMStringData* pThis) +{ + pThis->nRefs--; // Locked buffers can't be shared, so no interlocked operation necessary + if (pThis->nRefs == 0) + pThis->nRefs = -1; +} + +MIR_CORE_DLL(void) mirstr_release(CMStringData* pThis) +{ + if (InterlockedDecrement(&pThis->nRefs) <= 0) + mirstr_free(pThis); +} + +MIR_CORE_DLL(void) mirstr_unlock(CMStringData* pThis) +{ + if (pThis->IsLocked()) + { + pThis->nRefs++; // Locked buffers can't be shared, so no interlocked operation necessary + if (pThis->nRefs == 0) + pThis->nRefs = 1; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// don't remove it +// this code just instantiates templates for CMStringW[A/W] + +template MIR_CORE_EXPORT CMStringW CALLBACK operator+(const CMStringW& str1, const CMStringW& str2); +template MIR_CORE_EXPORT CMStringW CALLBACK operator+(const CMStringW& str1, const wchar_t *psz2); +template MIR_CORE_EXPORT CMStringW CALLBACK operator+(const wchar_t *psz1, const CMStringW& str2); +template MIR_CORE_EXPORT CMStringW CALLBACK operator+(const CMStringW& str1, wchar_t ch2); +template MIR_CORE_EXPORT CMStringW CALLBACK operator+(const CMStringW& str1, char ch2); +template MIR_CORE_EXPORT CMStringW CALLBACK operator+(wchar_t ch1, const CMStringW& str2); +template MIR_CORE_EXPORT CMStringW CALLBACK operator+(char ch1, const CMStringW& str2); + +template MIR_CORE_EXPORT CMStringA CALLBACK operator+(const CMStringA& str1, const CMStringA& str2); +template MIR_CORE_EXPORT CMStringA CALLBACK operator+(const CMStringA& str1, const char *psz2); +template MIR_CORE_EXPORT CMStringA CALLBACK operator+(const char *psz1, const CMStringA& str2); +template MIR_CORE_EXPORT CMStringA CALLBACK operator+(const CMStringA& str1, wchar_t ch2); +template MIR_CORE_EXPORT CMStringA CALLBACK operator+(const CMStringA& str1, char ch2); +template MIR_CORE_EXPORT CMStringA CALLBACK operator+(wchar_t ch1, const CMStringA& str2); +template MIR_CORE_EXPORT CMStringA CALLBACK operator+(char ch1, const CMStringA& str2); diff --git a/src/mir_core/src/sha256.cpp b/src/mir_core/src/sha256.cpp index e3e5991f5f..63fd940a62 100644 --- a/src/mir_core/src/sha256.cpp +++ b/src/mir_core/src/sha256.cpp @@ -1,289 +1,289 @@ - -#include "stdafx.h" - -MIR_CORE_DLL(void) mir_sha256_init(SHA256_CONTEXT *hd) -{ - hd->h0 = 0x6a09e667; - hd->h1 = 0xbb67ae85; - hd->h2 = 0x3c6ef372; - hd->h3 = 0xa54ff53a; - hd->h4 = 0x510e527f; - hd->h5 = 0x9b05688c; - hd->h6 = 0x1f83d9ab; - hd->h7 = 0x5be0cd19; - - hd->nblocks = 0; - hd->count = 0; -} - -/* -Transform the message X which consists of 16 32-bit-words. See FIPS -180-2 for details. */ -#define ror(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) ) -#define S0(x) (ror ((x), 7) ^ ror ((x), 18) ^ ((x) >> 3)) /* (4.6) */ -#define S1(x) (ror ((x), 17) ^ ror ((x), 19) ^ ((x) >> 10)) /* (4.7) */ -#define R(a,b,c,d,e,f,g,h,k,w) do \ -{ \ - t1 = (h)+Sum1((e)) + Cho((e), (f), (g)) + (k)+(w); \ - t2 = Sum0((a)) + Maj((a), (b), (c)); \ - h = g; \ - g = f; \ - f = e; \ - e = d + t1; \ - d = c; \ - c = b; \ - b = a; \ - a = t1 + t2; \ -} while (0) - -/* (4.2) same as SHA-1's F1. */ -static inline UINT32 -Cho(UINT32 x, UINT32 y, UINT32 z) -{ - return (z ^ (x & (y ^ z))); -} - -/* (4.3) same as SHA-1's F3 */ -static inline UINT32 -Maj(UINT32 x, UINT32 y, UINT32 z) -{ - return ((x & y) | (z & (x | y))); -} - -/* (4.4) */ -static inline UINT32 Sum0(UINT32 x) -{ - return (ror(x, 2) ^ ror(x, 13) ^ ror(x, 22)); -} - -/* (4.5) */ -static inline UINT32 -Sum1(UINT32 x) -{ - return (ror(x, 6) ^ ror(x, 11) ^ ror(x, 25)); -} - - -static void transform(SHA256_CONTEXT *hd, const unsigned char *data) -{ - static const UINT32 K[64] = { - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, - 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, - 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, - 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, - 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, - 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, - 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, - 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, - 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 - }; - - UINT32 a, b, c, d, e, f, g, h, t1, t2; - UINT32 x[16]; - UINT32 w[64]; - int i; - - a = hd->h0; - b = hd->h1; - c = hd->h2; - d = hd->h3; - e = hd->h4; - f = hd->h5; - g = hd->h6; - h = hd->h7; - -#ifdef WORDS_BIGENDIAN - memcpy(x, data, 64); -#else - { - BYTE *p2; - - for (i = 0, p2 = (BYTE*)x; i < 16; i++, p2 += 4) { - p2[3] = *data++; - p2[2] = *data++; - p2[1] = *data++; - p2[0] = *data++; - } - } -#endif - - for (i = 0; i < 16; i++) - w[i] = x[i]; - for (; i < 64; i++) - w[i] = S1(w[i - 2]) + w[i - 7] + S0(w[i - 15]) + w[i - 16]; - - for (i = 0; i < 64;) { -#if 0 - R(a, b, c, d, e, f, g, h, K[i], w[i]); - i++; -#else - t1 = h + Sum1(e) + Cho(e, f, g) + K[i] + w[i]; - t2 = Sum0(a) + Maj(a, b, c); - d += t1; - h = t1 + t2; - - t1 = g + Sum1(d) + Cho(d, e, f) + K[i + 1] + w[i + 1]; - t2 = Sum0(h) + Maj(h, a, b); - c += t1; - g = t1 + t2; - - t1 = f + Sum1(c) + Cho(c, d, e) + K[i + 2] + w[i + 2]; - t2 = Sum0(g) + Maj(g, h, a); - b += t1; - f = t1 + t2; - - t1 = e + Sum1(b) + Cho(b, c, d) + K[i + 3] + w[i + 3]; - t2 = Sum0(f) + Maj(f, g, h); - a += t1; - e = t1 + t2; - - t1 = d + Sum1(a) + Cho(a, b, c) + K[i + 4] + w[i + 4]; - t2 = Sum0(e) + Maj(e, f, g); - h += t1; - d = t1 + t2; - - t1 = c + Sum1(h) + Cho(h, a, b) + K[i + 5] + w[i + 5]; - t2 = Sum0(d) + Maj(d, e, f); - g += t1; - c = t1 + t2; - - t1 = b + Sum1(g) + Cho(g, h, a) + K[i + 6] + w[i + 6]; - t2 = Sum0(c) + Maj(c, d, e); - f += t1; - b = t1 + t2; - - t1 = a + Sum1(f) + Cho(f, g, h) + K[i + 7] + w[i + 7]; - t2 = Sum0(b) + Maj(b, c, d); - e += t1; - a = t1 + t2; - - i += 8; -#endif - } - - hd->h0 += a; - hd->h1 += b; - hd->h2 += c; - hd->h3 += d; - hd->h4 += e; - hd->h5 += f; - hd->h6 += g; - hd->h7 += h; -} -#undef S0 -#undef S1 -#undef R - - -/* Update the message digest with the contents of INBUF with length INLEN. */ -MIR_CORE_DLL(void) mir_sha256_write(SHA256_CONTEXT *hd, const void *inbuf_arg, size_t inlen) -{ - const unsigned char *inbuf = (const unsigned char *)inbuf_arg; - - if (hd->count == 64) { /* flush the buffer */ - transform(hd, hd->buf); - hd->count = 0; - hd->nblocks++; - } - if (!inbuf) - return; - if (hd->count) { - for (; inlen && hd->count < 64; inlen--) - hd->buf[hd->count++] = *inbuf++; - mir_sha256_write(hd, nullptr, 0); - if (!inlen) - return; - } - - while (inlen >= 64) { - transform(hd, inbuf); - hd->count = 0; - hd->nblocks++; - inlen -= 64; - inbuf += 64; - } - for (; inlen && hd->count < 64; inlen--) - hd->buf[hd->count++] = *inbuf++; -} - -/* -The routine finally terminates the computation and returns the -digest. The handle is prepared for a new cycle, but adding bytes -to the handle will the destroy the returned buffer. Returns: 32 -bytes with the message the digest. */ - -MIR_CORE_DLL(void) mir_sha256_final(SHA256_CONTEXT *hd, BYTE hashout[MIR_SHA256_HASH_SIZE]) -{ - UINT32 t, msb, lsb; - - mir_sha256_write(hd, nullptr, 0); /* flush */; - - t = hd->nblocks; - /* multiply by 64 to make a BYTE count */ - lsb = t << 6; - msb = t >> 26; - /* add the count */ - t = lsb; - if ((lsb += hd->count) < t) - msb++; - /* multiply by 8 to make a bit count */ - t = lsb; - lsb <<= 3; - msb <<= 3; - msb |= t >> 29; - - if (hd->count < 56) { /* enough room */ - hd->buf[hd->count++] = 0x80; /* pad */ - while (hd->count < 56) - hd->buf[hd->count++] = 0; /* pad */ - } - else { /* need one extra block */ - hd->buf[hd->count++] = 0x80; /* pad character */ - while (hd->count < 64) - hd->buf[hd->count++] = 0; - mir_sha256_write(hd, nullptr, 0); /* flush */; - memset(hd->buf, 0, 56); /* fill next block with zeroes */ - } - /* append the 64 bit count */ - hd->buf[56] = msb >> 24; - hd->buf[57] = msb >> 16; - hd->buf[58] = msb >> 8; - hd->buf[59] = msb; - hd->buf[60] = lsb >> 24; - hd->buf[61] = lsb >> 16; - hd->buf[62] = lsb >> 8; - hd->buf[63] = lsb; - transform(hd, hd->buf); - - BYTE *p = hashout; -#ifdef WORDS_BIGENDIAN -#define X(a) do { *(UINT32*)p = hd->h##a ; p += 4; } while(0) -#else /* little endian */ -#define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ - *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while (0) -#endif - X(0); - X(1); - X(2); - X(3); - X(4); - X(5); - X(6); - X(7); -#undef X -} - -MIR_CORE_DLL(void) mir_sha256_hash(const void *dataIn, size_t len, BYTE hashout[MIR_SHA256_HASH_SIZE]) -{ - SHA256_CONTEXT tmp; - mir_sha256_init(&tmp); - mir_sha256_write(&tmp, dataIn, len); - mir_sha256_final(&tmp, hashout); -} + +#include "stdafx.h" + +MIR_CORE_DLL(void) mir_sha256_init(SHA256_CONTEXT *hd) +{ + hd->h0 = 0x6a09e667; + hd->h1 = 0xbb67ae85; + hd->h2 = 0x3c6ef372; + hd->h3 = 0xa54ff53a; + hd->h4 = 0x510e527f; + hd->h5 = 0x9b05688c; + hd->h6 = 0x1f83d9ab; + hd->h7 = 0x5be0cd19; + + hd->nblocks = 0; + hd->count = 0; +} + +/* +Transform the message X which consists of 16 32-bit-words. See FIPS +180-2 for details. */ +#define ror(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) ) +#define S0(x) (ror ((x), 7) ^ ror ((x), 18) ^ ((x) >> 3)) /* (4.6) */ +#define S1(x) (ror ((x), 17) ^ ror ((x), 19) ^ ((x) >> 10)) /* (4.7) */ +#define R(a,b,c,d,e,f,g,h,k,w) do \ +{ \ + t1 = (h)+Sum1((e)) + Cho((e), (f), (g)) + (k)+(w); \ + t2 = Sum0((a)) + Maj((a), (b), (c)); \ + h = g; \ + g = f; \ + f = e; \ + e = d + t1; \ + d = c; \ + c = b; \ + b = a; \ + a = t1 + t2; \ +} while (0) + +/* (4.2) same as SHA-1's F1. */ +static inline uint32_t +Cho(uint32_t x, uint32_t y, uint32_t z) +{ + return (z ^ (x & (y ^ z))); +} + +/* (4.3) same as SHA-1's F3 */ +static inline uint32_t +Maj(uint32_t x, uint32_t y, uint32_t z) +{ + return ((x & y) | (z & (x | y))); +} + +/* (4.4) */ +static inline uint32_t Sum0(uint32_t x) +{ + return (ror(x, 2) ^ ror(x, 13) ^ ror(x, 22)); +} + +/* (4.5) */ +static inline uint32_t +Sum1(uint32_t x) +{ + return (ror(x, 6) ^ ror(x, 11) ^ ror(x, 25)); +} + + +static void transform(SHA256_CONTEXT *hd, const unsigned char *data) +{ + static const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + uint32_t a, b, c, d, e, f, g, h, t1, t2; + uint32_t x[16]; + uint32_t w[64]; + int i; + + a = hd->h0; + b = hd->h1; + c = hd->h2; + d = hd->h3; + e = hd->h4; + f = hd->h5; + g = hd->h6; + h = hd->h7; + +#ifdef WORDS_BIGENDIAN + memcpy(x, data, 64); +#else + { + BYTE *p2; + + for (i = 0, p2 = (BYTE*)x; i < 16; i++, p2 += 4) { + p2[3] = *data++; + p2[2] = *data++; + p2[1] = *data++; + p2[0] = *data++; + } + } +#endif + + for (i = 0; i < 16; i++) + w[i] = x[i]; + for (; i < 64; i++) + w[i] = S1(w[i - 2]) + w[i - 7] + S0(w[i - 15]) + w[i - 16]; + + for (i = 0; i < 64;) { +#if 0 + R(a, b, c, d, e, f, g, h, K[i], w[i]); + i++; +#else + t1 = h + Sum1(e) + Cho(e, f, g) + K[i] + w[i]; + t2 = Sum0(a) + Maj(a, b, c); + d += t1; + h = t1 + t2; + + t1 = g + Sum1(d) + Cho(d, e, f) + K[i + 1] + w[i + 1]; + t2 = Sum0(h) + Maj(h, a, b); + c += t1; + g = t1 + t2; + + t1 = f + Sum1(c) + Cho(c, d, e) + K[i + 2] + w[i + 2]; + t2 = Sum0(g) + Maj(g, h, a); + b += t1; + f = t1 + t2; + + t1 = e + Sum1(b) + Cho(b, c, d) + K[i + 3] + w[i + 3]; + t2 = Sum0(f) + Maj(f, g, h); + a += t1; + e = t1 + t2; + + t1 = d + Sum1(a) + Cho(a, b, c) + K[i + 4] + w[i + 4]; + t2 = Sum0(e) + Maj(e, f, g); + h += t1; + d = t1 + t2; + + t1 = c + Sum1(h) + Cho(h, a, b) + K[i + 5] + w[i + 5]; + t2 = Sum0(d) + Maj(d, e, f); + g += t1; + c = t1 + t2; + + t1 = b + Sum1(g) + Cho(g, h, a) + K[i + 6] + w[i + 6]; + t2 = Sum0(c) + Maj(c, d, e); + f += t1; + b = t1 + t2; + + t1 = a + Sum1(f) + Cho(f, g, h) + K[i + 7] + w[i + 7]; + t2 = Sum0(b) + Maj(b, c, d); + e += t1; + a = t1 + t2; + + i += 8; +#endif + } + + hd->h0 += a; + hd->h1 += b; + hd->h2 += c; + hd->h3 += d; + hd->h4 += e; + hd->h5 += f; + hd->h6 += g; + hd->h7 += h; +} +#undef S0 +#undef S1 +#undef R + + +/* Update the message digest with the contents of INBUF with length INLEN. */ +MIR_CORE_DLL(void) mir_sha256_write(SHA256_CONTEXT *hd, const void *inbuf_arg, size_t inlen) +{ + const unsigned char *inbuf = (const unsigned char *)inbuf_arg; + + if (hd->count == 64) { /* flush the buffer */ + transform(hd, hd->buf); + hd->count = 0; + hd->nblocks++; + } + if (!inbuf) + return; + if (hd->count) { + for (; inlen && hd->count < 64; inlen--) + hd->buf[hd->count++] = *inbuf++; + mir_sha256_write(hd, nullptr, 0); + if (!inlen) + return; + } + + while (inlen >= 64) { + transform(hd, inbuf); + hd->count = 0; + hd->nblocks++; + inlen -= 64; + inbuf += 64; + } + for (; inlen && hd->count < 64; inlen--) + hd->buf[hd->count++] = *inbuf++; +} + +/* +The routine finally terminates the computation and returns the +digest. The handle is prepared for a new cycle, but adding bytes +to the handle will the destroy the returned buffer. Returns: 32 +bytes with the message the digest. */ + +MIR_CORE_DLL(void) mir_sha256_final(SHA256_CONTEXT *hd, BYTE hashout[MIR_SHA256_HASH_SIZE]) +{ + uint32_t t, msb, lsb; + + mir_sha256_write(hd, nullptr, 0); /* flush */; + + t = hd->nblocks; + /* multiply by 64 to make a BYTE count */ + lsb = t << 6; + msb = t >> 26; + /* add the count */ + t = lsb; + if ((lsb += hd->count) < t) + msb++; + /* multiply by 8 to make a bit count */ + t = lsb; + lsb <<= 3; + msb <<= 3; + msb |= t >> 29; + + if (hd->count < 56) { /* enough room */ + hd->buf[hd->count++] = 0x80; /* pad */ + while (hd->count < 56) + hd->buf[hd->count++] = 0; /* pad */ + } + else { /* need one extra block */ + hd->buf[hd->count++] = 0x80; /* pad character */ + while (hd->count < 64) + hd->buf[hd->count++] = 0; + mir_sha256_write(hd, nullptr, 0); /* flush */; + memset(hd->buf, 0, 56); /* fill next block with zeroes */ + } + /* append the 64 bit count */ + hd->buf[56] = msb >> 24; + hd->buf[57] = msb >> 16; + hd->buf[58] = msb >> 8; + hd->buf[59] = msb; + hd->buf[60] = lsb >> 24; + hd->buf[61] = lsb >> 16; + hd->buf[62] = lsb >> 8; + hd->buf[63] = lsb; + transform(hd, hd->buf); + + BYTE *p = hashout; +#ifdef WORDS_BIGENDIAN +#define X(a) do { *(uint32_t*)p = hd->h##a ; p += 4; } while(0) +#else /* little endian */ +#define X(a) do { *p++ = hd->h##a >> 24; *p++ = hd->h##a >> 16; \ + *p++ = hd->h##a >> 8; *p++ = hd->h##a; } while (0) +#endif + X(0); + X(1); + X(2); + X(3); + X(4); + X(5); + X(6); + X(7); +#undef X +} + +MIR_CORE_DLL(void) mir_sha256_hash(const void *dataIn, size_t len, BYTE hashout[MIR_SHA256_HASH_SIZE]) +{ + SHA256_CONTEXT tmp; + mir_sha256_init(&tmp); + mir_sha256_write(&tmp, dataIn, len); + mir_sha256_final(&tmp, hashout); +} diff --git a/src/mir_core/src/stdafx.h b/src/mir_core/src/stdafx.h index 9b9d913bfc..cbc7f7af48 100644 --- a/src/mir_core/src/stdafx.h +++ b/src/mir_core/src/stdafx.h @@ -1,74 +1,78 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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. -*/ - -#pragma once - -#define INCL_WINSOCK_API_TYPEDEFS 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define __NO_CMPLUGIN_NEEDED -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "miranda.h" - -#include - -#include - -void GetDefaultLang(); \ No newline at end of file +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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. +*/ + +#pragma once + +#define INCL_WINSOCK_API_TYPEDEFS 1 + +#ifdef _MSC_VER +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#endif // _WINDOWS + +#include +#include +#include +#include +#include +#include +#include +#include + +#define __NO_CMPLUGIN_NEEDED +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "miranda.h" + +#include + +#include + +void GetDefaultLang(); diff --git a/src/mir_core/src/utf.cpp b/src/mir_core/src/utf.cpp index 4af4d97fee..b5bd37717f 100644 --- a/src/mir_core/src/utf.cpp +++ b/src/mir_core/src/utf.cpp @@ -1,437 +1,441 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - - Copyright 2000 Alexandre Julliard of Wine project - (UTF-8 conversion routines) - -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. -*/ - -#include "stdafx.h" - -/* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */ -static const char utf8_length[128] = -{ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9f */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xaf */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0-0xbf */ - 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xc0-0xcf */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xd0-0xdf */ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xe0-0xef */ - 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0-0xff */ -}; - -/* first byte mask depending on UTF-8 sequence length */ -static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 }; - -/* minimum Unicode value depending on UTF-8 sequence length */ -static const unsigned int utf8_minval[4] = { 0x0, 0x80, 0x800, 0x10000 }; - -/* get the next char value taking surrogates into account */ -static unsigned int getSurrogateValue(const wchar_t *src, unsigned int srclen) -{ - if (src[0] >= 0xd800 && src[0] <= 0xdfff) { /* surrogate pair */ - if (src[0] > 0xdbff || /* invalid high surrogate */ - srclen <= 1 || /* missing low surrogate */ - src[1] < 0xdc00 || src[1] > 0xdfff) /* invalid low surrogate */ - return 0; - return 0x10000 + ((src[0] & 0x3ff) << 10) + (src[1] & 0x3ff); - } - return src[0]; -} - -/* query necessary dst length for src string */ -static int mir_utf8len(const wchar_t *src, unsigned int srclen) -{ - int len; - unsigned int val; - - for (len = 0; srclen; srclen--, src++) { - if (*src < 0x80) { /* 0x00-0x7f: 1 byte */ - len++; - continue; - } - if (*src < 0x800) { /* 0x80-0x7ff: 2 bytes */ - len += 2; - continue; - } - if (!(val = getSurrogateValue(src, srclen))) - return -2; - - if (val < 0x10000) /* 0x800-0xffff: 3 bytes */ - len += 3; - else { /* 0x10000-0x10ffff: 4 bytes */ - len += 4; - src++; - srclen--; - } - } - return len; -} - -MIR_CORE_DLL(int) mir_utf8lenW(const wchar_t *src) -{ - if (src == nullptr) - return 0; - - return mir_utf8len(src, (int)wcslen(src)); -} - -/* wide char to UTF-8 string conversion */ -/* return -1 on dst buffer overflow, -2 on invalid input char */ -int Ucs2toUtf8(const wchar_t *src, int srclen, char *dst, int dstlen) -{ - int len; - - for (len = dstlen; srclen; srclen--, src++) { - wchar_t ch = *src; - unsigned int val; - - if (ch < 0x80) { /* 0x00-0x7f: 1 byte */ - if (!len--) return -1; /* overflow */ - *dst++ = ch; - continue; - } - - if (ch < 0x800) { /* 0x80-0x7ff: 2 bytes */ - if ((len -= 2) < 0) return -1; /* overflow */ - dst[1] = 0x80 | (ch & 0x3f); - ch >>= 6; - dst[0] = 0xc0 | ch; - dst += 2; - continue; - } - - if (!(val = getSurrogateValue(src, srclen))) - return -2; - - if (val < 0x10000) { /* 0x800-0xffff: 3 bytes */ - if ((len -= 3) < 0) return -1; /* overflow */ - dst[2] = 0x80 | (val & 0x3f); - val >>= 6; - dst[1] = 0x80 | (val & 0x3f); - val >>= 6; - dst[0] = 0xe0 | val; - dst += 3; - } - else { /* 0x10000-0x10ffff: 4 bytes */ - if ((len -= 4) < 0) return -1; /* overflow */ - dst[3] = 0x80 | (val & 0x3f); - val >>= 6; - dst[2] = 0x80 | (val & 0x3f); - val >>= 6; - dst[1] = 0x80 | (val & 0x3f); - val >>= 6; - dst[0] = 0xf0 | val; - dst += 4; - src++; - srclen--; - } - } - return dstlen - len; -} - -/* helper for the various utf8 mbstowcs functions */ -static unsigned int decodeUtf8Char(unsigned char ch, const char **str, const char *strend) -{ - unsigned int len = utf8_length[ch - 0x80]; - unsigned int res = ch & utf8_mask[len]; - const char *end = *str + len; - - if (end > strend) return ~0; - switch (len) { - case 3: - if ((ch = end[-3] ^ 0x80) >= 0x40) break; - res = (res << 6) | ch; - (*str)++; - - case 2: - if ((ch = end[-2] ^ 0x80) >= 0x40) break; - res = (res << 6) | ch; - (*str)++; - - case 1: - if ((ch = end[-1] ^ 0x80) >= 0x40) break; - res = (res << 6) | ch; - (*str)++; - if (res < utf8_minval[len]) break; - return res; - } - return ~0; -} - -/* query necessary dst length for src string */ -static int Utf8toUcs2Len(const char *src, size_t srclen) -{ - int ret = 0; - unsigned int res; - const char *srcend = src + srclen; - - while (src < srcend) { - unsigned char ch = *src++; - if (ch < 0x80) { /* special fast case for 7-bit ASCII */ - ret++; - continue; - } - if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0x10ffff) { - if (res > 0xffff) ret++; - ret++; - } - else return -2; /* bad char */ - /* otherwise ignore it */ - } - return ret; -} - -/* UTF-8 to wide char string conversion */ -/* return -1 on dst buffer overflow, -2 on invalid input char */ -MIR_CORE_DLL(int) Utf8toUcs2(const char *src, size_t srclen, wchar_t *dst, size_t dstlen) -{ - unsigned int res; - const char *srcend = src + srclen; // including trailing zero - wchar_t *dstend = dst + dstlen; - - while ((dst < dstend) && (src < srcend)) { - unsigned char ch = *src++; - if (ch < 0x80) { /* special fast case for 7-bit ASCII */ - *dst++ = ch; - continue; - } - - if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0xffff) - *dst++ = res; - else if (res <= 0x10ffff) { /* we need surrogates */ - if (dst == dstend - 1) - return -1; /* overflow */ - res -= 0x10000; - *dst++ = 0xd800 | (res >> 10); - *dst++ = 0xdc00 | (res & 0x3ff); - } - else return -2; /* bad char */ - } - - if (src < srcend) - return -1; /* overflow */ - - return (int)(dstlen - (dstend - dst)); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// mir_utf8decode - converts UTF8-encoded string to the UCS2/MBCS format - -MIR_CORE_DLL(char*) mir_utf8decodecp(char *str, int codepage, wchar_t **ucs2) -{ - bool needs_free = false; - wchar_t* tempBuf = nullptr; - if (ucs2) - *ucs2 = nullptr; - - if (str == nullptr) - return nullptr; - - size_t len = strlen(str); - if (len < 2) { - if (ucs2 != nullptr) { - *ucs2 = tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t)); - MultiByteToWideChar(codepage, 0, str, (int)len, tempBuf, (int)len); - tempBuf[len] = 0; - } - return str; - } - - int destlen = Utf8toUcs2Len(str, len); - if (destlen < 0) - return nullptr; - - if (ucs2 == nullptr) { - __try { - tempBuf = (wchar_t*)alloca((destlen + 1) * sizeof(wchar_t)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - tempBuf = nullptr; - needs_free = true; - } - } - - if (tempBuf == nullptr) { - tempBuf = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t)); - if (tempBuf == nullptr) - return nullptr; - } - - Utf8toUcs2(str, len, tempBuf, destlen); - tempBuf[destlen] = 0; - WideCharToMultiByte(codepage, 0, tempBuf, -1, str, (int)len + 1, "?", nullptr); - - if (ucs2) - *ucs2 = tempBuf; - else if (needs_free) - mir_free(tempBuf); - - return str; -} - -MIR_CORE_DLL(char*) mir_utf8decode(char *str, wchar_t **ucs2) -{ - return mir_utf8decodecp(str, Langpack_GetDefaultCodePage(), ucs2); -} - -MIR_CORE_DLL(wchar_t*) mir_utf8decodeW(const char *str) -{ - if (str == nullptr) - return nullptr; - - size_t len = strlen(str); - - int destlen = Utf8toUcs2Len(str, len); - if (destlen < 0) - return nullptr; - - wchar_t* ucs2 = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t)); - if (ucs2 == nullptr) - return nullptr; - - if (Utf8toUcs2(str, len, ucs2, destlen) >= 0) { - ucs2[destlen] = 0; - return ucs2; - } - - mir_free(ucs2); - - return nullptr; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// mir_utf8encode - converts MBCS string to the UTF8-encoded format - -MIR_CORE_DLL(char*) mir_utf8encodecp(const char* src, int codepage) -{ - int len; - bool needs_free = false; - char* result = nullptr; - wchar_t* tempBuf; - - if (src == nullptr) - return nullptr; - - len = (int)strlen(src); - - __try { - tempBuf = (wchar_t*)alloca((len + 1) * sizeof(wchar_t)); - } - __except (EXCEPTION_EXECUTE_HANDLER) - { - tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t)); - if (tempBuf == nullptr) return nullptr; - needs_free = true; - } - - len = MultiByteToWideChar(codepage, 0, src, -1, tempBuf, len + 1); - - int destlen = mir_utf8len(tempBuf, len); - if (destlen >= 0) { - result = (char*)mir_alloc(destlen + 1); - if (result) { - Ucs2toUtf8(tempBuf, len, result, destlen); - result[destlen] = 0; - } - } - - if (needs_free) - mir_free(tempBuf); - - return result; -} - -MIR_CORE_DLL(char*) mir_utf8encode(const char* src) -{ - return mir_utf8encodecp(src, Langpack_GetDefaultCodePage()); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// mir_utf8encode - converts UCS2 string to the UTF8-encoded format - -MIR_CORE_DLL(char*) mir_utf8encodeW(const wchar_t* src) -{ - if (src == nullptr) - return nullptr; - - int len = (int)wcslen(src); - - int destlen = mir_utf8len(src, len); - if (destlen < 0) return nullptr; - - char* result = (char*)mir_alloc(destlen + 1); - if (result == nullptr) - return nullptr; - - Ucs2toUtf8(src, len, result, destlen); - result[destlen] = 0; - - return result; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Utf8CheckString - checks if a string is a valid utf8-encoded string - -MIR_CORE_DLL(BOOL) Utf8CheckString(const char *str) -{ - int expect_bytes = 0, utf_found = 0; - - if (!str) return 0; - - while (*str) { - if ((*str & 0x80) == 0) { - /* Looks like an ASCII character */ - if (expect_bytes) - /* byte of UTF-8 character expected */ - return 0; - } - else { - /* Looks like byte of an UTF-8 character */ - if (expect_bytes) { - /* expect_bytes already set: first byte of UTF-8 char already seen */ - if ((*str & 0xC0) != 0x80) { - /* again first byte ?!?! */ - return 0; - } - } - else { - /* First byte of the UTF-8 character */ - /* count initial one bits and set expect_bytes to 1 less */ - char ch = *str; - while (ch & 0x80) { - expect_bytes++; - ch = (ch & 0x7f) << 1; - } - } - /* OK, next byte of UTF-8 character */ - /* Decrement number of expected bytes */ - if (--expect_bytes == 0) - utf_found = 1; - } - str++; - } - - return (utf_found && expect_bytes == 0); -} +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + + Copyright 2000 Alexandre Julliard of Wine project + (UTF-8 conversion routines) + +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. +*/ + +#include "stdafx.h" + +/* number of following bytes in sequence based on first byte value (for bytes above 0x7f) */ +static const char utf8_length[128] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9f */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xaf */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0-0xbf */ + 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xc0-0xcf */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0xd0-0xdf */ + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* 0xe0-0xef */ + 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xf0-0xff */ +}; + +/* first byte mask depending on UTF-8 sequence length */ +static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 }; + +/* minimum Unicode value depending on UTF-8 sequence length */ +static const unsigned int utf8_minval[4] = { 0x0, 0x80, 0x800, 0x10000 }; + +/* get the next char value taking surrogates into account */ +static unsigned int getSurrogateValue(const wchar_t *src, unsigned int srclen) +{ + if (src[0] >= 0xd800 && src[0] <= 0xdfff) { /* surrogate pair */ + if (src[0] > 0xdbff || /* invalid high surrogate */ + srclen <= 1 || /* missing low surrogate */ + src[1] < 0xdc00 || src[1] > 0xdfff) /* invalid low surrogate */ + return 0; + return 0x10000 + ((src[0] & 0x3ff) << 10) + (src[1] & 0x3ff); + } + return src[0]; +} + +/* query necessary dst length for src string */ +static int mir_utf8len(const wchar_t *src, unsigned int srclen) +{ + int len; + unsigned int val; + + for (len = 0; srclen; srclen--, src++) { + if (*src < 0x80) { /* 0x00-0x7f: 1 byte */ + len++; + continue; + } + if (*src < 0x800) { /* 0x80-0x7ff: 2 bytes */ + len += 2; + continue; + } + if (!(val = getSurrogateValue(src, srclen))) + return -2; + + if (val < 0x10000) /* 0x800-0xffff: 3 bytes */ + len += 3; + else { /* 0x10000-0x10ffff: 4 bytes */ + len += 4; + src++; + srclen--; + } + } + return len; +} + +MIR_CORE_DLL(int) mir_utf8lenW(const wchar_t *src) +{ + if (src == nullptr) + return 0; + + return mir_utf8len(src, (int)wcslen(src)); +} + +/* wide char to UTF-8 string conversion */ +/* return -1 on dst buffer overflow, -2 on invalid input char */ +int Ucs2toUtf8(const wchar_t *src, int srclen, char *dst, int dstlen) +{ + int len; + + for (len = dstlen; srclen; srclen--, src++) { + wchar_t ch = *src; + unsigned int val; + + if (ch < 0x80) { /* 0x00-0x7f: 1 byte */ + if (!len--) return -1; /* overflow */ + *dst++ = ch; + continue; + } + + if (ch < 0x800) { /* 0x80-0x7ff: 2 bytes */ + if ((len -= 2) < 0) return -1; /* overflow */ + dst[1] = 0x80 | (ch & 0x3f); + ch >>= 6; + dst[0] = 0xc0 | ch; + dst += 2; + continue; + } + + if (!(val = getSurrogateValue(src, srclen))) + return -2; + + if (val < 0x10000) { /* 0x800-0xffff: 3 bytes */ + if ((len -= 3) < 0) return -1; /* overflow */ + dst[2] = 0x80 | (val & 0x3f); + val >>= 6; + dst[1] = 0x80 | (val & 0x3f); + val >>= 6; + dst[0] = 0xe0 | val; + dst += 3; + } + else { /* 0x10000-0x10ffff: 4 bytes */ + if ((len -= 4) < 0) return -1; /* overflow */ + dst[3] = 0x80 | (val & 0x3f); + val >>= 6; + dst[2] = 0x80 | (val & 0x3f); + val >>= 6; + dst[1] = 0x80 | (val & 0x3f); + val >>= 6; + dst[0] = 0xf0 | val; + dst += 4; + src++; + srclen--; + } + } + return dstlen - len; +} + +/* helper for the various utf8 mbstowcs functions */ +static unsigned int decodeUtf8Char(unsigned char ch, const char **str, const char *strend) +{ + unsigned int len = utf8_length[ch - 0x80]; + unsigned int res = ch & utf8_mask[len]; + const char *end = *str + len; + + if (end > strend) return ~0; + switch (len) { + case 3: + if ((ch = end[-3] ^ 0x80) >= 0x40) break; + res = (res << 6) | ch; + (*str)++; + + case 2: + if ((ch = end[-2] ^ 0x80) >= 0x40) break; + res = (res << 6) | ch; + (*str)++; + + case 1: + if ((ch = end[-1] ^ 0x80) >= 0x40) break; + res = (res << 6) | ch; + (*str)++; + if (res < utf8_minval[len]) break; + return res; + } + return ~0; +} + +/* query necessary dst length for src string */ +static int Utf8toUcs2Len(const char *src, size_t srclen) +{ + int ret = 0; + unsigned int res; + const char *srcend = src + srclen; + + while (src < srcend) { + unsigned char ch = *src++; + if (ch < 0x80) { /* special fast case for 7-bit ASCII */ + ret++; + continue; + } + if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0x10ffff) { + if (res > 0xffff) ret++; + ret++; + } + else return -2; /* bad char */ + /* otherwise ignore it */ + } + return ret; +} + +/* UTF-8 to wide char string conversion */ +/* return -1 on dst buffer overflow, -2 on invalid input char */ +MIR_CORE_DLL(int) Utf8toUcs2(const char *src, size_t srclen, wchar_t *dst, size_t dstlen) +{ + unsigned int res; + const char *srcend = src + srclen; // including trailing zero + wchar_t *dstend = dst + dstlen; + + while ((dst < dstend) && (src < srcend)) { + unsigned char ch = *src++; + if (ch < 0x80) { /* special fast case for 7-bit ASCII */ + *dst++ = ch; + continue; + } + + if ((res = decodeUtf8Char(ch, &src, srcend)) <= 0xffff) + *dst++ = res; + else if (res <= 0x10ffff) { /* we need surrogates */ + if (dst == dstend - 1) + return -1; /* overflow */ + res -= 0x10000; + *dst++ = 0xd800 | (res >> 10); + *dst++ = 0xdc00 | (res & 0x3ff); + } + else return -2; /* bad char */ + } + + if (src < srcend) + return -1; /* overflow */ + + return (int)(dstlen - (dstend - dst)); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// mir_utf8decode - converts UTF8-encoded string to the UCS2/MBCS format + +#ifdef _MSC_VER +MIR_CORE_DLL(char*) mir_utf8decodecp(char *str, int codepage, wchar_t **ucs2) +{ + bool needs_free = false; + wchar_t* tempBuf = nullptr; + if (ucs2) + *ucs2 = nullptr; + + if (str == nullptr) + return nullptr; + + size_t len = strlen(str); + if (len < 2) { + if (ucs2 != nullptr) { + *ucs2 = tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t)); + MultiByteToWideChar(codepage, 0, str, (int)len, tempBuf, (int)len); + tempBuf[len] = 0; + } + return str; + } + + int destlen = Utf8toUcs2Len(str, len); + if (destlen < 0) + return nullptr; + + if (ucs2 == nullptr) { + __try { + tempBuf = (wchar_t*)alloca((destlen + 1) * sizeof(wchar_t)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + tempBuf = nullptr; + needs_free = true; + } + } + + if (tempBuf == nullptr) { + tempBuf = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t)); + if (tempBuf == nullptr) + return nullptr; + } + + Utf8toUcs2(str, len, tempBuf, destlen); + tempBuf[destlen] = 0; + WideCharToMultiByte(codepage, 0, tempBuf, -1, str, (int)len + 1, "?", nullptr); + + if (ucs2) + *ucs2 = tempBuf; + else if (needs_free) + mir_free(tempBuf); + + return str; +} + +MIR_CORE_DLL(char*) mir_utf8decode(char *str, wchar_t **ucs2) +{ + return mir_utf8decodecp(str, Langpack_GetDefaultCodePage(), ucs2); +} +#endif + +MIR_CORE_DLL(wchar_t*) mir_utf8decodeW(const char *str) +{ + if (str == nullptr) + return nullptr; + + size_t len = strlen(str); + + int destlen = Utf8toUcs2Len(str, len); + if (destlen < 0) + return nullptr; + + wchar_t* ucs2 = (wchar_t*)mir_alloc((destlen + 1) * sizeof(wchar_t)); + if (ucs2 == nullptr) + return nullptr; + + if (Utf8toUcs2(str, len, ucs2, destlen) >= 0) { + ucs2[destlen] = 0; + return ucs2; + } + + mir_free(ucs2); + + return nullptr; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// mir_utf8encode - converts MBCS string to the UTF8-encoded format + +#ifdef _MSC_VER +MIR_CORE_DLL(char*) mir_utf8encodecp(const char* src, int codepage) +{ + int len; + bool needs_free = false; + char* result = nullptr; + wchar_t* tempBuf; + + if (src == nullptr) + return nullptr; + + len = (int)strlen(src); + + __try { + tempBuf = (wchar_t*)alloca((len + 1) * sizeof(wchar_t)); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + tempBuf = (wchar_t*)mir_alloc((len + 1) * sizeof(wchar_t)); + if (tempBuf == nullptr) return nullptr; + needs_free = true; + } + + len = MultiByteToWideChar(codepage, 0, src, -1, tempBuf, len + 1); + + int destlen = mir_utf8len(tempBuf, len); + if (destlen >= 0) { + result = (char*)mir_alloc(destlen + 1); + if (result) { + Ucs2toUtf8(tempBuf, len, result, destlen); + result[destlen] = 0; + } + } + + if (needs_free) + mir_free(tempBuf); + + return result; +} + +MIR_CORE_DLL(char*) mir_utf8encode(const char* src) +{ + return mir_utf8encodecp(src, Langpack_GetDefaultCodePage()); +} +#endif + +///////////////////////////////////////////////////////////////////////////////////////// +// mir_utf8encode - converts UCS2 string to the UTF8-encoded format + +MIR_CORE_DLL(char*) mir_utf8encodeW(const wchar_t* src) +{ + if (src == nullptr) + return nullptr; + + int len = (int)wcslen(src); + + int destlen = mir_utf8len(src, len); + if (destlen < 0) return nullptr; + + char* result = (char*)mir_alloc(destlen + 1); + if (result == nullptr) + return nullptr; + + Ucs2toUtf8(src, len, result, destlen); + result[destlen] = 0; + + return result; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Utf8CheckString - checks if a string is a valid utf8-encoded string + +MIR_CORE_DLL(BOOL) Utf8CheckString(const char *str) +{ + int expect_bytes = 0, utf_found = 0; + + if (!str) return 0; + + while (*str) { + if ((*str & 0x80) == 0) { + /* Looks like an ASCII character */ + if (expect_bytes) + /* byte of UTF-8 character expected */ + return 0; + } + else { + /* Looks like byte of an UTF-8 character */ + if (expect_bytes) { + /* expect_bytes already set: first byte of UTF-8 char already seen */ + if ((*str & 0xC0) != 0x80) { + /* again first byte ?!?! */ + return 0; + } + } + else { + /* First byte of the UTF-8 character */ + /* count initial one bits and set expect_bytes to 1 less */ + char ch = *str; + while (ch & 0x80) { + expect_bytes++; + ch = (ch & 0x7f) << 1; + } + } + /* OK, next byte of UTF-8 character */ + /* Decrement number of expected bytes */ + if (--expect_bytes == 0) + utf_found = 1; + } + str++; + } + + return (utf_found && expect_bytes == 0); +} diff --git a/src/mir_core/src/utils.cpp b/src/mir_core/src/utils.cpp index ccd89aabcc..26f6c2970b 100644 --- a/src/mir_core/src/utils.cpp +++ b/src/mir_core/src/utils.cpp @@ -1,561 +1,565 @@ -/* - -Miranda NG: the free IM client for Microsoft* Windows* - -Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), -Copyright (c) 2000-12 Miranda IM project, -all portions of this codebase are copyrighted to the people -listed in contributors.txt. - -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. -*/ - -#include "stdafx.h" - -MIR_CORE_DLL(char*) replaceStr(char* &dest, const char *src) -{ - if (dest != nullptr) - mir_free(dest); - - return dest = (src != nullptr) ? mir_strdup(src) : nullptr; -} - -MIR_CORE_DLL(wchar_t*) replaceStrW(wchar_t* &dest, const wchar_t *src) -{ - if (dest != nullptr) - mir_free(dest); - - return dest = (src != nullptr) ? mir_wstrdup(src) : nullptr; -} - -MIR_CORE_DLL(char*) rtrim(char *str) -{ - if (str == nullptr) - return nullptr; - - char* p = strchr(str, 0); - while (--p >= str) { - switch (*p) { - case ' ': case '\t': case '\n': case '\r': - *p = 0; break; - default: - return str; - } - } - return str; -} - -MIR_CORE_DLL(wchar_t*) rtrimw(wchar_t *str) -{ - if (str == nullptr) - return nullptr; - - wchar_t *p = wcschr(str, 0); - while (--p >= str) { - switch (*p) { - case ' ': case '\t': case '\n': case '\r': - *p = 0; break; - default: - return str; - } - } - return str; -} - -MIR_CORE_DLL(char*) ltrim(char *str) -{ - if (str == nullptr) - return nullptr; - - char* p = str; - for (;;) { - switch (*p) { - case ' ': case '\t': case '\n': case '\r': - ++p; break; - default: - memmove(str, p, strlen(p) + 1); - return str; - } - } -} - -MIR_CORE_DLL(wchar_t*) ltrimw(wchar_t *str) -{ - if (str == nullptr) - return nullptr; - - wchar_t *p = str; - for (;;) { - switch (*p) { - case ' ': case '\t': case '\n': case '\r': - ++p; break; - default: - memmove(str, p, sizeof(wchar_t)*(wcslen(p) + 1)); - return str; - } - } -} - -MIR_CORE_DLL(char*) ltrimp(char *str) -{ - if (str == nullptr) - return nullptr; - - char *p = str; - for (;;) { - switch (*p) { - case ' ': case '\t': case '\n': case '\r': - ++p; break; - default: - return p; - } - } -} - -MIR_CORE_DLL(wchar_t*) ltrimpw(wchar_t *str) -{ - if (str == nullptr) - return nullptr; - - wchar_t *p = str; - for (;;) { - switch (*p) { - case ' ': case '\t': case '\n': case '\r': - ++p; break; - default: - return p; - } - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(char*) strdel(char *str, size_t len) -{ - char* p; - for (p = str + len; *p != 0; p++) - *(p - len) = *p; - - *(p - len) = '\0'; - return str; -} - -MIR_CORE_DLL(wchar_t*) strdelw(wchar_t *str, size_t len) -{ - wchar_t* p; - for (p = str + len; *p != 0; p++) - *(p - len) = *p; - - *(p - len) = '\0'; - return str; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -MIR_CORE_DLL(int) wildcmp(const char *name, const char *mask) -{ - if (name == nullptr || mask == nullptr) - return false; - - const char *last = nullptr; - for (;; mask++, name++) { - if (*mask != '?' && *mask != *name) break; - if (*name == '\0') return ((BOOL)!*mask); - } - if (*mask != '*') return FALSE; - for (;; mask++, name++) { - while (*mask == '*') { - last = mask++; - if (*mask == '\0') return ((BOOL)!*mask); /* true */ - } - if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ - if (*mask != '?' && *mask != *name) name -= (size_t)(mask - last) - 1, mask = last; - } -} - -MIR_CORE_DLL(int) wildcmpw(const wchar_t *name, const wchar_t *mask) -{ - if (name == nullptr || mask == nullptr) - return false; - - const wchar_t* last = nullptr; - for (;; mask++, name++) { - if (*mask != '?' && *mask != *name) break; - if (*name == '\0') return ((BOOL)!*mask); - } - if (*mask != '*') return FALSE; - for (;; mask++, name++) { - while (*mask == '*') { - last = mask++; - if (*mask == '\0') return ((BOOL)!*mask); /* true */ - } - if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ - if (*mask != '?' && *mask != *name) name -= (size_t)(mask - last) - 1, mask = last; - } -} - -#define _qtoupper(_c) (((_c) >= 'a' && (_c) <= 'z')?((_c)-'a'+'A'):(_c)) - -MIR_CORE_DLL(int) wildcmpi(const char *name, const char *mask) -{ - if (name == nullptr || mask == nullptr) - return false; - - const char *last = nullptr; - for (;; mask++, name++) { - if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) break; - if (*name == '\0') return ((BOOL)!*mask); - } - if (*mask != '*') return FALSE; - for (;; mask++, name++) { - while (*mask == '*') { - last = mask++; - if (*mask == '\0') return ((BOOL)!*mask); /* true */ - } - if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ - if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) name -= (size_t)(mask - last) - 1, mask = last; - } -} - -MIR_CORE_DLL(int) wildcmpiw(const wchar_t *name, const wchar_t *mask) -{ - if (name == nullptr || mask == nullptr) - return false; - - const wchar_t* last = nullptr; - for (;; mask++, name++) { - if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) break; - if (*name == '\0') return ((BOOL)!*mask); - } - if (*mask != '*') return FALSE; - for (;; mask++, name++) { - while (*mask == '*') { - last = mask++; - if (*mask == '\0') return ((BOOL)!*mask); /* true */ - } - if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ - if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) name -= (size_t)(mask - last) - 1, mask = last; - } -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static char szHexTable[] = "0123456789abcdef"; - -MIR_CORE_DLL(char*) bin2hex(const void *pData, size_t len, char *dest) -{ - const BYTE *p = (const BYTE*)pData; - char *d = dest; - - for (size_t i = 0; i < len; i++, p++) { - *d++ = szHexTable[*p >> 4]; - *d++ = szHexTable[*p & 0x0F]; - } - *d = 0; - - return dest; -} - -MIR_CORE_DLL(wchar_t*) bin2hexW(const void *pData, size_t len, wchar_t *dest) -{ - const BYTE *p = (const BYTE*)pData; - wchar_t *d = dest; - - for (size_t i = 0; i < len; i++, p++) { - *d++ = szHexTable[*p >> 4]; - *d++ = szHexTable[*p & 0x0F]; - } - *d = 0; - - return dest; -} - -static int hex2dec(int iHex) -{ - if (iHex >= '0' && iHex <= '9') - return iHex - '0'; - if (iHex >= 'a' && iHex <= 'f') - return iHex - 'a' + 10; - if (iHex >= 'A' && iHex <= 'F') - return iHex - 'A' + 10; - return 0; -} - -MIR_CORE_DLL(bool) hex2bin(const char *pSrc, void *pData, size_t len) -{ - if (pSrc == nullptr || pData == nullptr || len == 0) - return false; - - size_t bufLen = strlen(pSrc)/2; - if (pSrc[bufLen*2] != 0 || bufLen > len) - return false; - - BYTE *pDest = (BYTE*)pData; - const char *p = (const char *)pSrc; - for (size_t i = 0; i < bufLen; i++, p += 2) - pDest[i] = hex2dec(p[0]) * 16 + hex2dec(p[1]); - - if (bufLen < len) - memset(pDest + bufLen, 0, len - bufLen); - return true; -} - -MIR_CORE_DLL(bool) hex2binW(const wchar_t *pSrc, void *pData, size_t len) -{ - if (pSrc == nullptr || pData == nullptr || len == 0) - return false; - - size_t bufLen = wcslen(pSrc)/2; - if (pSrc[bufLen * 2] != 0 || bufLen > len) - return false; - - BYTE *pDest = (BYTE*)pData; - const wchar_t *p = (const wchar_t *)pSrc; - for (size_t i = 0; i < bufLen; i++, p += 2) - pDest[i] = hex2dec(p[0]) * 16 + hex2dec(p[1]); - - if (bufLen < len) - memset(pDest+bufLen, 0, len - bufLen); - return true; -} - - -///////////////////////////////////////////////////////////////////////////////////////// - -#pragma intrinsic(strlen, strcpy, strcat, strcmp, wcslen, wcscpy, wcscat, wcscmp) - -MIR_CORE_DLL(size_t) mir_strlen(const char *p) -{ - return (p) ? strlen(p) : 0; -} - -MIR_CORE_DLL(size_t) mir_wstrlen(const wchar_t *p) -{ - return (p) ? wcslen(p) : 0; -} - -MIR_CORE_DLL(char*) mir_strcpy(char *dest, const char *src) -{ - if (dest == nullptr) - return nullptr; - - if (src == nullptr) { - *dest = 0; - return dest; - } - - return strcpy(dest, src); -} - -MIR_CORE_DLL(wchar_t*) mir_wstrcpy(wchar_t *dest, const wchar_t *src) -{ - if (dest == nullptr) - return nullptr; - - if (src == nullptr) { - *dest = 0; - return dest; - } - - return wcscpy(dest, src); -} - -MIR_CORE_DLL(char*) mir_strncpy(char *dest, const char *src, size_t len) -{ - if (dest == nullptr) - return nullptr; - - if (src == nullptr) - *dest = 0; - else - strncpy_s(dest, len, src, _TRUNCATE); - return dest; -} - -MIR_CORE_DLL(wchar_t*) mir_wstrncpy(wchar_t *dest, const wchar_t *src, size_t len) -{ - if (dest == nullptr) - return nullptr; - - if (src == nullptr) - *dest = 0; - else - wcsncpy_s(dest, len, src, _TRUNCATE); - return dest; -} - -MIR_CORE_DLL(char*) mir_strcat(char *dest, const char *src) -{ - if (dest == nullptr) - return nullptr; - - if (src == nullptr) { - *dest = 0; - return dest; - } - - return strcat(dest, src); -} - -MIR_CORE_DLL(wchar_t*) mir_wstrcat(wchar_t *dest, const wchar_t *src) -{ - if (dest == nullptr) - return nullptr; - - if (src == nullptr) { - *dest = 0; - return dest; - } - - return wcscat(dest, src); -} - -MIR_CORE_DLL(char*) mir_strncat(char *dest, const char *src, size_t len) -{ - if (dest == nullptr) - return nullptr; - - if (src == nullptr) - *dest = 0; - else - strncat_s(dest, len, src, _TRUNCATE); - return dest; -} - -MIR_CORE_DLL(wchar_t*) mir_wstrncat(wchar_t *dest, const wchar_t *src, size_t len) -{ - if (dest == nullptr) - return nullptr; - - if (src == nullptr) - *dest = 0; - else - wcsncat_s(dest, len, src, _TRUNCATE); - return dest; -} - -MIR_CORE_DLL(int) mir_strcmp(const char *p1, const char *p2) -{ - if (p1 == nullptr) - return (p2 == nullptr) ? 0 : -1; - if (p2 == nullptr) - return 1; - return strcmp(p1, p2); -} - -MIR_CORE_DLL(int) mir_wstrcmp(const wchar_t *p1, const wchar_t *p2) -{ - if (p1 == nullptr) - return (p2 == nullptr) ? 0 : -1; - if (p2 == nullptr) - return 1; - return wcscmp(p1, p2); -} - -MIR_CORE_DLL(int) mir_strcmpi(const char *p1, const char *p2) -{ - if (p1 == nullptr) - return (p2 == nullptr) ? 0 : -1; - if (p2 == nullptr) - return 1; - return stricmp(p1, p2); -} - -MIR_CORE_DLL(int) mir_wstrcmpi(const wchar_t *p1, const wchar_t *p2) -{ - if (p1 == nullptr) - return (p2 == nullptr) ? 0 : -1; - if (p2 == nullptr) - return 1; - return wcsicmp(p1, p2); -} - -MIR_CORE_DLL(int) mir_strncmp(const char *p1, const char *p2, size_t n) -{ - if (p1 == nullptr) - return (p2 == nullptr) ? 0 : -1; - if (p2 == nullptr) - return 1; - return strncmp(p1, p2, n); -} - -MIR_CORE_DLL(int) mir_wstrncmp(const wchar_t *p1, const wchar_t *p2, size_t n) -{ - if (p1 == nullptr) - return (p2 == nullptr) ? 0 : -1; - if (p2 == nullptr) - return 1; - return wcsncmp(p1, p2, n); -} - -MIR_CORE_DLL(int) mir_strncmpi(const char *p1, const char *p2, size_t n) -{ - if (p1 == nullptr) - return (p2 == nullptr) ? 0 : -1; - if (p2 == nullptr) - return 1; - return strnicmp(p1, p2, n); -} - -MIR_CORE_DLL(int) mir_wstrncmpi(const wchar_t *p1, const wchar_t *p2, size_t n) -{ - if (p1 == nullptr) - return (p2 == nullptr) ? 0 : -1; - if (p2 == nullptr) - return 1; - return wcsnicmp(p1, p2, n); -} - -MIR_CORE_DLL(const wchar_t*) mir_wstrstri(const wchar_t *s1, const wchar_t *s2) -{ - for (int i = 0; s1[i]; i++) - for (int j = i, k = 0; towlower(s1[j]) == towlower(s2[k]); j++, k++) - if (!s2[k + 1]) - return s1 + i; - - return nullptr; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -PGENRANDOM pfnRtlGenRandom; - -MIR_CORE_DLL(void) Utils_GetRandom(void *pszDest, size_t cbLen) -{ - if (pszDest == nullptr || cbLen == 0) - return; - - if (pfnRtlGenRandom != nullptr) - pfnRtlGenRandom(pszDest, (ULONG)cbLen); - else { - srand(time(0)); - BYTE *p = (BYTE*)pszDest; - for (size_t i = 0; i < cbLen; i++) - p[i] = rand() & 0xFF; - } -} - -MIR_CORE_DLL(bool) Utils_IsRtl(const wchar_t *pszwText) -{ - size_t iLen = mir_wstrlen(pszwText); - mir_ptr infoTypeC2((WORD*)mir_calloc(sizeof(WORD) * (iLen + 2))); - GetStringTypeW(CT_CTYPE2, pszwText, (int)iLen, infoTypeC2); - - for (size_t i = 0; i < iLen; i++) - if (infoTypeC2[i] == C2_RIGHTTOLEFT) - return true; - - return false; -} +/* + +Miranda NG: the free IM client for Microsoft* Windows* + +Copyright (C) 2012-21 Miranda NG team (https://miranda-ng.org), +Copyright (c) 2000-12 Miranda IM project, +all portions of this codebase are copyrighted to the people +listed in contributors.txt. + +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. +*/ + +#include "stdafx.h" + +MIR_CORE_DLL(char*) replaceStr(char* &dest, const char *src) +{ + if (dest != nullptr) + mir_free(dest); + + return dest = (src != nullptr) ? mir_strdup(src) : nullptr; +} + +MIR_CORE_DLL(wchar_t*) replaceStrW(wchar_t* &dest, const wchar_t *src) +{ + if (dest != nullptr) + mir_free(dest); + + return dest = (src != nullptr) ? mir_wstrdup(src) : nullptr; +} + +MIR_CORE_DLL(char*) rtrim(char *str) +{ + if (str == nullptr) + return nullptr; + + char* p = strchr(str, 0); + while (--p >= str) { + switch (*p) { + case ' ': case '\t': case '\n': case '\r': + *p = 0; break; + default: + return str; + } + } + return str; +} + +MIR_CORE_DLL(wchar_t*) rtrimw(wchar_t *str) +{ + if (str == nullptr) + return nullptr; + + wchar_t *p = wcschr(str, 0); + while (--p >= str) { + switch (*p) { + case ' ': case '\t': case '\n': case '\r': + *p = 0; break; + default: + return str; + } + } + return str; +} + +MIR_CORE_DLL(char*) ltrim(char *str) +{ + if (str == nullptr) + return nullptr; + + char* p = str; + for (;;) { + switch (*p) { + case ' ': case '\t': case '\n': case '\r': + ++p; break; + default: + memmove(str, p, strlen(p) + 1); + return str; + } + } +} + +MIR_CORE_DLL(wchar_t*) ltrimw(wchar_t *str) +{ + if (str == nullptr) + return nullptr; + + wchar_t *p = str; + for (;;) { + switch (*p) { + case ' ': case '\t': case '\n': case '\r': + ++p; break; + default: + memmove(str, p, sizeof(wchar_t)*(wcslen(p) + 1)); + return str; + } + } +} + +MIR_CORE_DLL(char*) ltrimp(char *str) +{ + if (str == nullptr) + return nullptr; + + char *p = str; + for (;;) { + switch (*p) { + case ' ': case '\t': case '\n': case '\r': + ++p; break; + default: + return p; + } + } +} + +MIR_CORE_DLL(wchar_t*) ltrimpw(wchar_t *str) +{ + if (str == nullptr) + return nullptr; + + wchar_t *p = str; + for (;;) { + switch (*p) { + case ' ': case '\t': case '\n': case '\r': + ++p; break; + default: + return p; + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(char*) strdel(char *str, size_t len) +{ + char* p; + for (p = str + len; *p != 0; p++) + *(p - len) = *p; + + *(p - len) = '\0'; + return str; +} + +MIR_CORE_DLL(wchar_t*) strdelw(wchar_t *str, size_t len) +{ + wchar_t* p; + for (p = str + len; *p != 0; p++) + *(p - len) = *p; + + *(p - len) = '\0'; + return str; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +MIR_CORE_DLL(int) wildcmp(const char *name, const char *mask) +{ + if (name == nullptr || mask == nullptr) + return false; + + const char *last = nullptr; + for (;; mask++, name++) { + if (*mask != '?' && *mask != *name) break; + if (*name == '\0') return ((BOOL)!*mask); + } + if (*mask != '*') return FALSE; + for (;; mask++, name++) { + while (*mask == '*') { + last = mask++; + if (*mask == '\0') return ((BOOL)!*mask); /* true */ + } + if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ + if (*mask != '?' && *mask != *name) name -= (size_t)(mask - last) - 1, mask = last; + } +} + +MIR_CORE_DLL(int) wildcmpw(const wchar_t *name, const wchar_t *mask) +{ + if (name == nullptr || mask == nullptr) + return false; + + const wchar_t* last = nullptr; + for (;; mask++, name++) { + if (*mask != '?' && *mask != *name) break; + if (*name == '\0') return ((BOOL)!*mask); + } + if (*mask != '*') return FALSE; + for (;; mask++, name++) { + while (*mask == '*') { + last = mask++; + if (*mask == '\0') return ((BOOL)!*mask); /* true */ + } + if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ + if (*mask != '?' && *mask != *name) name -= (size_t)(mask - last) - 1, mask = last; + } +} + +#define _qtoupper(_c) (((_c) >= 'a' && (_c) <= 'z')?((_c)-'a'+'A'):(_c)) + +MIR_CORE_DLL(int) wildcmpi(const char *name, const char *mask) +{ + if (name == nullptr || mask == nullptr) + return false; + + const char *last = nullptr; + for (;; mask++, name++) { + if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) break; + if (*name == '\0') return ((BOOL)!*mask); + } + if (*mask != '*') return FALSE; + for (;; mask++, name++) { + while (*mask == '*') { + last = mask++; + if (*mask == '\0') return ((BOOL)!*mask); /* true */ + } + if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ + if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) name -= (size_t)(mask - last) - 1, mask = last; + } +} + +MIR_CORE_DLL(int) wildcmpiw(const wchar_t *name, const wchar_t *mask) +{ + if (name == nullptr || mask == nullptr) + return false; + + const wchar_t* last = nullptr; + for (;; mask++, name++) { + if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) break; + if (*name == '\0') return ((BOOL)!*mask); + } + if (*mask != '*') return FALSE; + for (;; mask++, name++) { + while (*mask == '*') { + last = mask++; + if (*mask == '\0') return ((BOOL)!*mask); /* true */ + } + if (*name == '\0') return ((BOOL)!*mask); /* *mask == EOS */ + if (*mask != '?' && _qtoupper(*mask) != _qtoupper(*name)) name -= (size_t)(mask - last) - 1, mask = last; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static char szHexTable[] = "0123456789abcdef"; + +MIR_CORE_DLL(char*) bin2hex(const void *pData, size_t len, char *dest) +{ + const BYTE *p = (const BYTE*)pData; + char *d = dest; + + for (size_t i = 0; i < len; i++, p++) { + *d++ = szHexTable[*p >> 4]; + *d++ = szHexTable[*p & 0x0F]; + } + *d = 0; + + return dest; +} + +MIR_CORE_DLL(wchar_t*) bin2hexW(const void *pData, size_t len, wchar_t *dest) +{ + const BYTE *p = (const BYTE*)pData; + wchar_t *d = dest; + + for (size_t i = 0; i < len; i++, p++) { + *d++ = szHexTable[*p >> 4]; + *d++ = szHexTable[*p & 0x0F]; + } + *d = 0; + + return dest; +} + +static int hex2dec(int iHex) +{ + if (iHex >= '0' && iHex <= '9') + return iHex - '0'; + if (iHex >= 'a' && iHex <= 'f') + return iHex - 'a' + 10; + if (iHex >= 'A' && iHex <= 'F') + return iHex - 'A' + 10; + return 0; +} + +MIR_CORE_DLL(bool) hex2bin(const char *pSrc, void *pData, size_t len) +{ + if (pSrc == nullptr || pData == nullptr || len == 0) + return false; + + size_t bufLen = strlen(pSrc)/2; + if (pSrc[bufLen*2] != 0 || bufLen > len) + return false; + + BYTE *pDest = (BYTE*)pData; + const char *p = (const char *)pSrc; + for (size_t i = 0; i < bufLen; i++, p += 2) + pDest[i] = hex2dec(p[0]) * 16 + hex2dec(p[1]); + + if (bufLen < len) + memset(pDest + bufLen, 0, len - bufLen); + return true; +} + +MIR_CORE_DLL(bool) hex2binW(const wchar_t *pSrc, void *pData, size_t len) +{ + if (pSrc == nullptr || pData == nullptr || len == 0) + return false; + + size_t bufLen = wcslen(pSrc)/2; + if (pSrc[bufLen * 2] != 0 || bufLen > len) + return false; + + BYTE *pDest = (BYTE*)pData; + const wchar_t *p = (const wchar_t *)pSrc; + for (size_t i = 0; i < bufLen; i++, p += 2) + pDest[i] = hex2dec(p[0]) * 16 + hex2dec(p[1]); + + if (bufLen < len) + memset(pDest+bufLen, 0, len - bufLen); + return true; +} + + +///////////////////////////////////////////////////////////////////////////////////////// + +#pragma intrinsic(strlen, strcpy, strcat, strcmp, wcslen, wcscpy, wcscat, wcscmp) + +MIR_CORE_DLL(size_t) mir_strlen(const char *p) +{ + return (p) ? strlen(p) : 0; +} + +MIR_CORE_DLL(size_t) mir_wstrlen(const wchar_t *p) +{ + return (p) ? wcslen(p) : 0; +} + +MIR_CORE_DLL(char*) mir_strcpy(char *dest, const char *src) +{ + if (dest == nullptr) + return nullptr; + + if (src == nullptr) { + *dest = 0; + return dest; + } + + return strcpy(dest, src); +} + +MIR_CORE_DLL(wchar_t*) mir_wstrcpy(wchar_t *dest, const wchar_t *src) +{ + if (dest == nullptr) + return nullptr; + + if (src == nullptr) { + *dest = 0; + return dest; + } + + return wcscpy(dest, src); +} + +MIR_CORE_DLL(char*) mir_strncpy(char *dest, const char *src, size_t len) +{ + if (dest == nullptr) + return nullptr; + + if (src == nullptr) + *dest = 0; + else + strncpy_s(dest, len, src, _TRUNCATE); + return dest; +} + +MIR_CORE_DLL(wchar_t*) mir_wstrncpy(wchar_t *dest, const wchar_t *src, size_t len) +{ + if (dest == nullptr) + return nullptr; + + if (src == nullptr) + *dest = 0; + else + wcsncpy_s(dest, len, src, _TRUNCATE); + return dest; +} + +MIR_CORE_DLL(char*) mir_strcat(char *dest, const char *src) +{ + if (dest == nullptr) + return nullptr; + + if (src == nullptr) { + *dest = 0; + return dest; + } + + return strcat(dest, src); +} + +MIR_CORE_DLL(wchar_t*) mir_wstrcat(wchar_t *dest, const wchar_t *src) +{ + if (dest == nullptr) + return nullptr; + + if (src == nullptr) { + *dest = 0; + return dest; + } + + return wcscat(dest, src); +} + +MIR_CORE_DLL(char*) mir_strncat(char *dest, const char *src, size_t len) +{ + if (dest == nullptr) + return nullptr; + + if (src == nullptr) + *dest = 0; + else + strncat_s(dest, len, src, _TRUNCATE); + return dest; +} + +MIR_CORE_DLL(wchar_t*) mir_wstrncat(wchar_t *dest, const wchar_t *src, size_t len) +{ + if (dest == nullptr) + return nullptr; + + if (src == nullptr) + *dest = 0; + else + wcsncat_s(dest, len, src, _TRUNCATE); + return dest; +} + +MIR_CORE_DLL(int) mir_strcmp(const char *p1, const char *p2) +{ + if (p1 == nullptr) + return (p2 == nullptr) ? 0 : -1; + if (p2 == nullptr) + return 1; + return strcmp(p1, p2); +} + +MIR_CORE_DLL(int) mir_wstrcmp(const wchar_t *p1, const wchar_t *p2) +{ + if (p1 == nullptr) + return (p2 == nullptr) ? 0 : -1; + if (p2 == nullptr) + return 1; + return wcscmp(p1, p2); +} + +MIR_CORE_DLL(int) mir_strcmpi(const char *p1, const char *p2) +{ + if (p1 == nullptr) + return (p2 == nullptr) ? 0 : -1; + if (p2 == nullptr) + return 1; + return stricmp(p1, p2); +} + +MIR_CORE_DLL(int) mir_wstrcmpi(const wchar_t *p1, const wchar_t *p2) +{ + if (p1 == nullptr) + return (p2 == nullptr) ? 0 : -1; + if (p2 == nullptr) + return 1; + return wcsicmp(p1, p2); +} + +MIR_CORE_DLL(int) mir_strncmp(const char *p1, const char *p2, size_t n) +{ + if (p1 == nullptr) + return (p2 == nullptr) ? 0 : -1; + if (p2 == nullptr) + return 1; + return strncmp(p1, p2, n); +} + +MIR_CORE_DLL(int) mir_wstrncmp(const wchar_t *p1, const wchar_t *p2, size_t n) +{ + if (p1 == nullptr) + return (p2 == nullptr) ? 0 : -1; + if (p2 == nullptr) + return 1; + return wcsncmp(p1, p2, n); +} + +MIR_CORE_DLL(int) mir_strncmpi(const char *p1, const char *p2, size_t n) +{ + if (p1 == nullptr) + return (p2 == nullptr) ? 0 : -1; + if (p2 == nullptr) + return 1; + return strnicmp(p1, p2, n); +} + +MIR_CORE_DLL(int) mir_wstrncmpi(const wchar_t *p1, const wchar_t *p2, size_t n) +{ + if (p1 == nullptr) + return (p2 == nullptr) ? 0 : -1; + if (p2 == nullptr) + return 1; + return wcsnicmp(p1, p2, n); +} + +#ifdef _MSC_VER +MIR_CORE_DLL(const wchar_t*) mir_wstrstri(const wchar_t *s1, const wchar_t *s2) +{ + for (int i = 0; s1[i]; i++) + for (int j = i, k = 0; towlower(s1[j]) == towlower(s2[k]); j++, k++) + if (!s2[k + 1]) + return s1 + i; + + return nullptr; +} +#endif + +///////////////////////////////////////////////////////////////////////////////////////// + +PGENRANDOM pfnRtlGenRandom; + +MIR_CORE_DLL(void) Utils_GetRandom(void *pszDest, size_t cbLen) +{ + if (pszDest == nullptr || cbLen == 0) + return; + + if (pfnRtlGenRandom != nullptr) + pfnRtlGenRandom(pszDest, (uint32_t)cbLen); + else { + srand(time(0)); + BYTE *p = (BYTE*)pszDest; + for (size_t i = 0; i < cbLen; i++) + p[i] = rand() & 0xFF; + } +} + +MIR_CORE_DLL(bool) Utils_IsRtl(const wchar_t *pszwText) +{ + #ifdef _MSC_VER + size_t iLen = mir_wstrlen(pszwText); + mir_ptr infoTypeC2((WORD*)mir_calloc(sizeof(WORD) * (iLen + 2))); + GetStringTypeW(CT_CTYPE2, pszwText, (int)iLen, infoTypeC2); + + for (size_t i = 0; i < iLen; i++) + if (infoTypeC2[i] == C2_RIGHTTOLEFT) + return true; + #endif + + return false; +} diff --git a/src/miranda32/miranda32.cbp b/src/miranda32/miranda32.cbp new file mode 100644 index 0000000000..27040ad943 --- /dev/null +++ b/src/miranda32/miranda32.cbp @@ -0,0 +1,11 @@ + + + + + + diff --git a/src/miranda32/miranda32.layout b/src/miranda32/miranda32.layout new file mode 100644 index 0000000000..00cf04d503 --- /dev/null +++ b/src/miranda32/miranda32.layout @@ -0,0 +1,5 @@ + + + + + -- cgit v1.2.3