summaryrefslogtreecommitdiff
path: root/plugins/NewAwaySysMod
diff options
context:
space:
mode:
authorKirill Volinsky <mataes2007@gmail.com>2012-05-19 17:13:01 +0000
committerKirill Volinsky <mataes2007@gmail.com>2012-05-19 17:13:01 +0000
commitdd61627f93d5f40f530fa71b827716afa3c7c79e (patch)
tree1e5c9c71a15b7d19888fb440af715da66e7d88ca /plugins/NewAwaySysMod
parent0bad57730850a9f6625c12e4605f2e3ffc6242cf (diff)
added NewAwaySysMod (not compiled yet)
git-svn-id: http://svn.miranda-ng.org/main/trunk@81 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/NewAwaySysMod')
-rw-r--r--plugins/NewAwaySysMod/AggressiveOptimize.h169
-rw-r--r--plugins/NewAwaySysMod/AwayOpt.cpp1960
-rw-r--r--plugins/NewAwaySysMod/AwaySys.cpp1123
-rw-r--r--plugins/NewAwaySysMod/Client.cpp232
-rw-r--r--plugins/NewAwaySysMod/Common.h413
-rw-r--r--plugins/NewAwaySysMod/CommonLibs/CString.cpp380
-rw-r--r--plugins/NewAwaySysMod/CommonLibs/CString.h347
-rw-r--r--plugins/NewAwaySysMod/CommonLibs/GroupCheckbox.cpp407
-rw-r--r--plugins/NewAwaySysMod/CommonLibs/GroupCheckbox.h26
-rw-r--r--plugins/NewAwaySysMod/CommonLibs/Options.cpp984
-rw-r--r--plugins/NewAwaySysMod/CommonLibs/Options.h490
-rw-r--r--plugins/NewAwaySysMod/CommonLibs/TMyArray.h353
-rw-r--r--plugins/NewAwaySysMod/CommonLibs/ThemedImageCheckbox.cpp381
-rw-r--r--plugins/NewAwaySysMod/CommonLibs/ThemedImageCheckbox.h26
-rw-r--r--plugins/NewAwaySysMod/CommonLibs/Themes.cpp51
-rw-r--r--plugins/NewAwaySysMod/CommonLibs/Themes.h51
-rw-r--r--plugins/NewAwaySysMod/CommonLibs/pcre.cpp295
-rw-r--r--plugins/NewAwaySysMod/CommonLibs/pcre.h30
-rw-r--r--plugins/NewAwaySysMod/CommonLibs/pcre_main.h298
-rw-r--r--plugins/NewAwaySysMod/ContactList.cpp905
-rw-r--r--plugins/NewAwaySysMod/ContactList.h142
-rw-r--r--plugins/NewAwaySysMod/Images/Delete.icobin0 -> 2038 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/DisableNotify.icobin0 -> 2038 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/Dot.icobin0 -> 2550 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/EnableNotify.icobin0 -> 2038 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/Ignore.icobin0 -> 2550 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/Indefinite.icobin0 -> 2550 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/MsgIcon.icobin0 -> 1150 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/NewCat.icobin0 -> 2550 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/NewMessage.icobin0 -> 2550 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/SaveAsNew.icobin0 -> 2038 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/SaveMsg.icobin0 -> 1150 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/Settings.icobin0 -> 2550 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/Status_Other.icobin0 -> 1406 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/Variables.icobin0 -> 2550 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/off.bmpbin0 -> 1336 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/off.icobin0 -> 1150 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/on.bmpbin0 -> 1016 bytes
-rw-r--r--plugins/NewAwaySysMod/Images/on.icobin0 -> 1150 bytes
-rw-r--r--plugins/NewAwaySysMod/MsgEventAdded.cpp322
-rw-r--r--plugins/NewAwaySysMod/MsgTree.cpp790
-rw-r--r--plugins/NewAwaySysMod/MsgTree.h95
-rw-r--r--plugins/NewAwaySysMod/NewAwaySys.rc701
-rw-r--r--plugins/NewAwaySysMod/NewAwaySys.sln24
-rw-r--r--plugins/NewAwaySysMod/NewAwaySys.vcxproj363
-rw-r--r--plugins/NewAwaySysMod/NewAwaySys.vcxproj.filters220
-rw-r--r--plugins/NewAwaySysMod/Notification.cpp289
-rw-r--r--plugins/NewAwaySysMod/Path.h43
-rw-r--r--plugins/NewAwaySysMod/Properties.cpp447
-rw-r--r--plugins/NewAwaySysMod/Properties.h605
-rw-r--r--plugins/NewAwaySysMod/ReadAwayMsg.cpp161
-rw-r--r--plugins/NewAwaySysMod/Services.cpp254
-rw-r--r--plugins/NewAwaySysMod/Services.h27
-rw-r--r--plugins/NewAwaySysMod/SetAwayMsg.cpp1706
-rw-r--r--plugins/NewAwaySysMod/VersionNo.h5
-rw-r--r--plugins/NewAwaySysMod/copying.txt340
-rw-r--r--plugins/NewAwaySysMod/nas_readme.txt281
-rw-r--r--plugins/NewAwaySysMod/nas_translation.txt238
-rw-r--r--plugins/NewAwaySysMod/resource.h261
-rw-r--r--plugins/NewAwaySysMod/resources.rc6
-rw-r--r--plugins/NewAwaySysMod/version.rc59
61 files changed, 16300 insertions, 0 deletions
diff --git a/plugins/NewAwaySysMod/AggressiveOptimize.h b/plugins/NewAwaySysMod/AggressiveOptimize.h
new file mode 100644
index 0000000000..65cfa5b010
--- /dev/null
+++ b/plugins/NewAwaySysMod/AggressiveOptimize.h
@@ -0,0 +1,169 @@
+
+//////////////////////////////
+// Version 1.40
+// October 22nd, 2002 - .NET (VC7, _MSC_VER=1300) support!
+// Version 1.30
+// Nov 24th, 2000
+// Version 1.20
+// Jun 9th, 2000
+// Version 1.10
+// Jan 23rd, 2000
+// Version 1.00
+// May 20th, 1999
+// Todd C. Wilson, Fresh Ground Software
+// (todd@nopcode.com)
+// This header file will kick in settings for Visual C++ 5 and 6 that will (usually)
+// result in smaller exe's.
+// The "trick" is to tell the compiler to not pad out the function calls; this is done
+// by not using the /O1 or /O2 option - if you do, you implicitly use /Gy, which pads
+// out each and every function call. In one single 500k dll, I managed to cut out 120k
+// by this alone!
+// The other two "tricks" are telling the Linker to merge all data-type segments together
+// in the exe file. The relocation, read-only (constants) data, and code section (.text)
+// sections can almost always be merged. Each section merged can save 4k in exe space,
+// since each section is padded out to 4k chunks. This is very noticeable with smaller
+// exes, since you could have only 700 bytes of data, 300 bytes of code, 94 bytes of
+// strings - padded out, this could be 12k of runtime, for 1094 bytes of stuff! For larger
+// programs, this is less overall, but can save at least 4k.
+// Note that if you're using MFC static or some other 3rd party libs, you may get poor
+// results with merging the readonly (.rdata) section - the exe may grow larger.
+// To use this feature, define _MERGE_DATA_ in your project or before this header is used.
+// With Visual C++ 5, the program uses a file alignment of 512 bytes, which results
+// in a small exe. Under VC6, the program instead uses 4k, which is the same as the
+// section size. The reason (from what I understand) is that 4k is the chunk size of
+// the virtual memory manager, and that WinAlign (an end-user tuning tool for Win98)
+// will re-align the programs on this boundary. The problem with this is that all of
+// Microsoft's system exes and dlls are *NOT* tuned like this, and using 4k causes serious
+// exe bloat. This is very noticeable for smaller programs.
+// The "trick" for this is to use the undocumented FILEALIGN linker parm to change the
+// padding from 4k to 1/2k, which results in a much smaller exe - anywhere from 20%-75%
+// depending on the size. Note that this is the same as using /OPT:NOWIN98, which *is*
+// a previously documented switch, but was left out of the docs for some reason in VC6 and
+// all of the current MSDN's - see KB:Q235956 for more information.
+// Microsoft does say that using the 4k alignment will "speed up process loading",
+// but I've been unable to notice a difference, even on my P180, with a very large (4meg) exe.
+// Please note, however, that this will probably not change the size of the COMPRESSED
+// file (either in a .zip file or in an install archive), since this 4k is all zeroes and
+// gets compressed away.
+// Also, the /ALIGN:4096 switch will "magically" do the same thing, even though this is the
+// default setting for this switch. Apparently this sets the same values as the above two
+// switches do. We do not use this in this header, since it smacks of a bug and not a feature.
+// Thanks to Michael Geary <Mike@Geary.com> for some additional tips!
+//
+// Notes about using this header in .NET
+// First off, VC7 does not allow a lot of the linker command options in pragma's. There is no
+// honest or good reason why Microsoft decided to make this change, it just doesn't.
+// So that is why there are a lot of <1300 #if's in the header.
+// If you want to take full advantage of the VC7 linker options, you will need to do it on a
+// PER PROJECT BASIS; you can no longer use a global header file like this to make it better.
+// Items I strongly suggest putting in all your VC7 project linker options command line settings:
+// /ignore:4078 /RELEASE
+// Compiler options:
+// /GL (Whole Program Optimization)
+// If you're making an .EXE and not a .DLL, consider adding in:
+// /GA (Optimize for Windows Application)
+// Some items to consider using in your VC7 projects (not VC6):
+// Link-time Code Generation - whole code optimization. Put this in your exe/dll project link settings.
+// /LTCG:NOSTATUS
+// The classic no-padding and no-bloat compiler C/C++ switch:
+// /opt:nowin98
+//
+// (C++ command line options: /GL /opt:nowin98 and /GA for .exe files)
+// (Link command line options: /ignore:4078 /RELEASE /LTCG:NOSTATUS)
+//
+// Now, notes on using these options in VC7 vs VC6.
+// VC6 consistently, for me, produces smaller code from C++ the exact same sources,
+// with or without this header. On average, VC6 produces 5% smaller binaries compared
+// to VC7 compiling the exact same project, *without* this header. With this header, VC6
+// will make a 13k file, while VC7 will make a 64k one. VC7 is just bloaty, pure and
+// simple - all that managed/unmanaged C++ runtimes, and the CLR stuff must be getting
+// in the way of code generation. However, template support is better, so there.
+// Both VC6 and VC7 show the same end kind of end result savings - larger binary output
+// will shave about 2% off, where as smaller projects (support DLL's, cpl's,
+// activex controls, ATL libs, etc) get the best result, since the padding is usually
+// more than the actual usable code. But again, VC7 does not compile down as small as VC6.
+//
+// The argument can be made that doing this is a waste of time, since the "zero bytes"
+// will be compressed out in a zip file or install archive. Not really - it doesn't matter
+// if the data is a string of zeroes or ones or 85858585 - it will still take room (20 bytes
+// in a zip file, 29 bytes if only *4* of them 4k bytes are not the same) and time to
+// compress that data and decompress it. Also, 20k of zeros is NOT 20k on disk - it's the
+// size of the cluster slop- for Fat32 systems, 20k can be 32k, NTFS could make it 24k if you're
+// just 1 byte over (round up). Most end users do not have the dual P4 Xeon systems with
+// two gigs of RDram and a Raid 0+1 of Western Digital 120meg Special Editions that all
+// worthy developers have (all six of us), so they will need any space and LOADING TIME
+// savings they will need; taking an extra 32k or more out of your end user's 64megs of
+// ram on Windows 98 is Not a Good Thing.
+//
+// Now, as a ADDED BONUS at NO EXTRA COST TO YOU! Under VC6, using the /merge:.text=.data
+// pragma will cause the output file to be un-disassembleable! (is that a word?) At least,
+// with the normal tools - WinDisam, DumpBin, and the like will not work. Try it - use the
+// header, compile release, and then use DUMPBIN /DISASM filename.exe - no code!
+// Thanks to Gëzim Pani <gpani@siu.edu> for discovering this gem - for a full writeup on
+// this issue and the ramifactions of it, visit www.nopcode.com for the Aggressive Optimize
+// article.
+
+#ifndef _AGGRESSIVEOPTIMIZE_H_
+#define _AGGRESSIVEOPTIMIZE_H_
+
+#pragma warning(disable:4711)
+
+#ifdef NDEBUG
+// /Og (global optimizations), /Os (favor small code), /Oy (no frame pointers)
+#pragma optimize("gsy",on)
+
+#if (_MSC_VER<1300)
+ #pragma comment(linker,"/RELEASE")
+#endif
+
+// Note that merging the .rdata section will result in LARGER exe's if you using
+// MFC (esp. static link). If this is desirable, define _MERGE_RDATA_ in your project.
+/* DEP prevents the plugin from running when section merging is used. Had to disable it. */
+/*
+#ifdef _MERGE_RDATA_
+#pragma comment(linker,"/merge:.rdata=.data")
+#endif // _MERGE_RDATA_
+
+#pragma comment(linker,"/merge:.text=.data")
+#if (_MSC_VER<1300)
+ // In VC7, this causes problems with the relocation and data tables, so best to not merge them
+ #pragma comment(linker,"/merge:.reloc=.data")
+#endif
+*/
+
+// Merging sections with different attributes causes a linker warning, so
+// turn off the warning. From Michael Geary. Undocumented, as usual!
+#if (_MSC_VER<1300)
+ // In VC7, you will need to put this in your project settings
+ #pragma comment(linker,"/ignore:4078")
+#endif
+
+// With Visual C++ 5, you already get the 512-byte alignment, so you will only need
+// it for VC6, and maybe later.
+#if _MSC_VER >= 1000
+
+// Option #1: use /filealign
+// Totally undocumented! And if you set it lower than 512 bytes, the program crashes.
+// Either leave at 0x200 or 0x1000
+//#pragma comment(linker,"/FILEALIGN:0x200")
+
+// Option #2: use /opt:nowin98
+// See KB:Q235956 or the READMEVC.htm in your VC directory for info on this one.
+// This is our currently preferred option, since it is fully documented and unlikely
+// to break in service packs and updates.
+#if (_MSC_VER<1300)
+ // In VC7, you will need to put this in your project settings
+ #pragma comment(linker,"/opt:nowin98")
+#else
+
+// Option #3: use /align:4096
+// A side effect of using the default align value is that it turns on the above switch.
+// Does nothing under Vc7 that /opt:nowin98 doesn't already give you
+// #pragma comment(linker,"/ALIGN:512")
+#endif
+
+#endif // _MSC_VER >= 1000
+
+#endif // NDEBUG
+
+#endif // _AGGRESSIVEOPTIMIZE_H_
diff --git a/plugins/NewAwaySysMod/AwayOpt.cpp b/plugins/NewAwaySysMod/AwayOpt.cpp
new file mode 100644
index 0000000000..82e6c06a4d
--- /dev/null
+++ b/plugins/NewAwaySysMod/AwayOpt.cpp
@@ -0,0 +1,1960 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (C) 2005-2007 Chervov Dmitry
+
+ 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 "Common.h"
+#include "MsgTree.h"
+#include "Properties.h"
+#include "Path.h"
+#include "m_button.h"
+#include "m_clc.h"
+#include "..\CommonLibs\Themes.h"
+#include "..\CommonLibs\GroupCheckbox.h"
+#include "..\CommonLibs\ThemedImageCheckbox.h"
+
+//NightFox
+#include <m_modernopt.h>
+
+int g_Messages_RecentRootID, g_Messages_PredefinedRootID;
+CIconList g_IconList;
+
+
+void MySetPos(HWND hwndParent)
+// Set window size and center its controls
+{
+ HWND hWndTab = FindWindowEx(GetParent(hwndParent), NULL, _T("SysTabControl32"), _T(""));
+ if (!hWndTab)
+ {
+ _ASSERT(0);
+ return;
+ }
+ RECT rcDlg;
+ GetClientRect(hWndTab, &rcDlg);
+ TabCtrl_AdjustRect(hWndTab, false, &rcDlg);
+ rcDlg.right -= rcDlg.left - 2;
+ rcDlg.bottom -= rcDlg.top;
+ rcDlg.top += 2;
+ if (hwndParent)
+ {
+ RECT OldSize;
+ GetClientRect(hwndParent, &OldSize);
+ MoveWindow(hwndParent, rcDlg.left, rcDlg.top, rcDlg.right, rcDlg.bottom, true);
+ int dx = (rcDlg.right - OldSize.right) >> 1;
+ int dy = (rcDlg.bottom - OldSize.bottom) >> 1;
+ HWND hCurWnd = GetWindow(hwndParent, GW_CHILD);
+ while (hCurWnd)
+ {
+ RECT CWOldPos;
+ GetWindowRect(hCurWnd, &CWOldPos);
+ POINT pt;
+ pt.x = CWOldPos.left;
+ pt.y = CWOldPos.top;
+ ScreenToClient(hwndParent, &pt);
+ SetWindowPos(hCurWnd, NULL, pt.x + dx, pt.y + dy, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+ hCurWnd = GetNextWindow(hCurWnd, GW_HWNDNEXT);
+ }
+ }
+}
+
+
+// ================================================ Popup options ================================================
+/*
+COptPage g_PopupOptPage(MOD_NAME, NULL);
+
+
+void EnablePopupOptDlgControls()
+{
+ int I;
+ g_PopupOptPage.PageToMem();
+ int UsePopups = g_PopupOptPage.GetValue(IDC_POPUPOPTDLG_USEPOPUPS);
+ for (I = 0; I < g_PopupOptPage.Items.GetSize(); I++)
+ {
+ switch (g_PopupOptPage.Items[I]->GetParam())
+ {
+ case IDC_POPUPOPTDLG_USEPOPUPS:
+ {
+ g_PopupOptPage.Items[I]->Enable(UsePopups);
+ } break;
+ case IDC_POPUPOPTDLG_DEFBGCOLOUR:
+ {
+ g_PopupOptPage.Items[I]->Enable(UsePopups && !g_PopupOptPage.GetValue(IDC_POPUPOPTDLG_DEFBGCOLOUR));
+ } break;
+ case IDC_POPUPOPTDLG_DEFTEXTCOLOUR:
+ {
+ g_PopupOptPage.Items[I]->Enable(UsePopups && !g_PopupOptPage.GetValue(IDC_POPUPOPTDLG_DEFTEXTCOLOUR));
+ } break;
+ }
+ }
+ if (!ServiceExists(MS_VARS_FORMATSTRING))
+ {
+ g_PopupOptPage.Find(IDC_POPUPOPTDLG_POPUPFORMAT)->Enable(false);
+ }
+ if (!ServiceExists(MS_LOGSERVICE_LOG))
+ {
+ g_PopupOptPage.Find(IDC_POPUPOPTDLG_LOGONLYWITHPOPUP)->Enable(false);
+ }
+ g_PopupOptPage.MemToPage(true);
+ InvalidateRect(GetDlgItem(g_PopupOptPage.GetWnd(), IDC_POPUPOPTDLG_POPUPDELAY_SPIN), NULL, false); // update spin control
+}
+
+
+int CALLBACK PopupOptDlg(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int ChangeLock = 0;
+ static struct {
+ int DlgItem, Status, IconIndex;
+ } StatusButtons[] = {
+ IDC_POPUPOPTDLG_ONLNOTIFY, ID_STATUS_ONLINE, ILI_PROTO_ONL,
+ IDC_POPUPOPTDLG_AWAYNOTIFY, ID_STATUS_AWAY, ILI_PROTO_AWAY,
+ IDC_POPUPOPTDLG_NANOTIFY, ID_STATUS_NA, ILI_PROTO_NA,
+ IDC_POPUPOPTDLG_OCCNOTIFY, ID_STATUS_OCCUPIED, ILI_PROTO_OCC,
+ IDC_POPUPOPTDLG_DNDNOTIFY, ID_STATUS_DND, ILI_PROTO_DND,
+ IDC_POPUPOPTDLG_FFCNOTIFY, ID_STATUS_FREECHAT, ILI_PROTO_FFC
+ };
+ static struct {
+ int DlgItem, IconIndex;
+ TCHAR* Text;
+ } Buttons[] = {
+ IDC_POPUPOPTDLG_VARS, ILI_NOICON, LPGENT("Open Variables help dialog"),
+ IDC_POPUPOPTDLG_OTHERNOTIFY, ILI_STATUS_OTHER, LPGENT("Other (XStatus)")
+ };
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ ChangeLock++;
+ g_PopupOptPage.SetWnd(hwndDlg);
+ SendDlgItemMessage(hwndDlg, IDC_POPUPOPTDLG_POPUPFORMAT, EM_LIMITTEXT, AWAY_MSGDATA_MAX, 0);
+ SendDlgItemMessage(hwndDlg, IDC_POPUPOPTDLG_POPUPDELAY, EM_LIMITTEXT, 4, 0);
+ SendDlgItemMessage(hwndDlg, IDC_POPUPOPTDLG_POPUPDELAY_SPIN, UDM_SETRANGE32, -1, 9999);
+
+ HWND hLCombo = GetDlgItem(hwndDlg, IDC_POPUPOPTDLG_LCLICK_ACTION);
+ HWND hRCombo = GetDlgItem(hwndDlg, IDC_POPUPOPTDLG_RCLICK_ACTION);
+ static struct {
+ TCHAR *Text;
+ int Action;
+ } PopupActions[] = {
+ LPGENT("Open message window"), PCA_OPENMESSAGEWND,
+ LPGENT("Close popup"), PCA_CLOSEPOPUP,
+ LPGENT("Open contact details window"), PCA_OPENDETAILS,
+ LPGENT("Open contact menu"), PCA_OPENMENU,
+ LPGENT("Open contact history"), PCA_OPENHISTORY,
+ LPGENT("Open log file"), PCA_OPENLOG,
+ LPGENT("Do nothing"), PCA_DONOTHING
+ };
+ int I;
+ for (I = 0; I < lengthof(PopupActions); I++)
+ {
+ SendMessage(hLCombo, CB_SETITEMDATA, SendMessage(hLCombo, CB_ADDSTRING, 0, (LPARAM)TranslateTS(PopupActions[I].Text)), PopupActions[I].Action);
+ SendMessage(hRCombo, CB_SETITEMDATA, SendMessage(hRCombo, CB_ADDSTRING, 0, (LPARAM)TranslateTS(PopupActions[I].Text)), PopupActions[I].Action);
+ }
+ for (I = 0; I < lengthof(StatusButtons); I++)
+ {
+ HWND hButton = GetDlgItem(hwndDlg, StatusButtons[I].DlgItem);
+ SendMessage(hButton, BUTTONADDTOOLTIP, CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, StatusButtons[I].Status, GCMDF_TCHAR), BATF_TCHAR);
+ SendMessage(hButton, BUTTONSETASPUSHBTN, 0, 0);
+ SendMessage(hButton, BUTTONSETASFLATBTN, 0, 0);
+ }
+ for (I = 0; I < lengthof(Buttons); I++)
+ {
+ HWND hButton = GetDlgItem(hwndDlg, Buttons[I].DlgItem);
+ SendMessage(hButton, BUTTONADDTOOLTIP, (WPARAM)TranslateTS(Buttons[I].Text), BATF_TCHAR);
+ SendMessage(hButton, BUTTONSETASFLATBTN, 0, 0);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_POPUPOPTDLG_OTHERNOTIFY, BUTTONSETASPUSHBTN, 0, 0);
+ SendMessage(hwndDlg, UM_ICONSCHANGED, 0, 0);
+ g_PopupOptPage.DBToMemToPage();
+ EnablePopupOptDlgControls();
+ ChangeLock--;
+ MakeGroupCheckbox(GetDlgItem(hwndDlg, IDC_POPUPOPTDLG_USEPOPUPS));
+ return true;
+ } break;
+ case UM_ICONSCHANGED:
+ {
+ int I;
+ for (I = 0; I < lengthof(StatusButtons); I++)
+ {
+ SendDlgItemMessage(hwndDlg, StatusButtons[I].DlgItem, BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_IconList[StatusButtons[I].IconIndex]);
+ }
+ for (I = 0; I < lengthof(Buttons); I++)
+ {
+ if (Buttons[I].IconIndex != ILI_NOICON)
+ {
+ SendDlgItemMessage(hwndDlg, Buttons[I].DlgItem, BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_IconList[Buttons[I].IconIndex]);
+ }
+ }
+ my_variables_skin_helpbutton(hwndDlg, IDC_POPUPOPTDLG_VARS);
+ } break;
+ case WM_NOTIFY:
+ {
+ switch (((NMHDR*)lParam)->code)
+ {
+ case PSN_APPLY:
+ {
+ g_PopupOptPage.PageToMemToDB();
+ return true;
+ } break;
+ }
+ } break;
+ case WM_COMMAND:
+ {
+ switch (HIWORD(wParam))
+ {
+ case BN_CLICKED:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_POPUPOPTDLG_USEPOPUPS:
+ case IDC_POPUPOPTDLG_DEFBGCOLOUR:
+ case IDC_POPUPOPTDLG_DEFTEXTCOLOUR:
+ {
+ EnablePopupOptDlgControls();
+ }; // go through
+ case IDC_POPUPOPTDLG_ONLNOTIFY:
+ case IDC_POPUPOPTDLG_AWAYNOTIFY:
+ case IDC_POPUPOPTDLG_NANOTIFY:
+ case IDC_POPUPOPTDLG_OCCNOTIFY:
+ case IDC_POPUPOPTDLG_DNDNOTIFY:
+ case IDC_POPUPOPTDLG_FFCNOTIFY:
+ case IDC_POPUPOPTDLG_OTHERNOTIFY:
+ case IDC_POPUPOPTDLG_LOGONLYWITHPOPUP:
+ {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ return 0;
+ } break;
+ case IDC_POPUPOPTDLG_VARS:
+ {
+ my_variables_showhelp(hwndDlg, IDC_POPUPOPTDLG_POPUPFORMAT);
+ } break;
+ case IDC_POPUPOPTDLG_POPUPPREVIEW:
+ {
+ COptPage PreviewPopupData(g_PopupOptPage);
+ PreviewPopupData.PageToMem();
+ GetDynamicStatMsg(NULL, "ICQ", DBGetContactSettingDword(NULL, "ICQ", "UIN", 0)); ShowPopupNotification(PreviewPopupData, NULL, g_ProtoStates[(char*)NULL].Status);
+// SkinPlaySound(AWAYSYS_STATUSMSGREQUEST_SOUND);
+ } break;
+ }
+ } break;
+ case EN_CHANGE:
+ {
+ if ((LOWORD(wParam) == IDC_POPUPOPTDLG_POPUPFORMAT) || (LOWORD(wParam) == IDC_POPUPOPTDLG_POPUPDELAY))
+ {
+ if (!ChangeLock && g_PopupOptPage.GetWnd())
+ {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ }
+ }
+ } break;
+ case CBN_SELCHANGE:
+// case CPN_COLOURCHANGED:
+ {
+ if ((LOWORD(wParam) == IDC_POPUPOPTDLG_LCLICK_ACTION) || (LOWORD(wParam) == IDC_POPUPOPTDLG_RCLICK_ACTION) || (LOWORD(wParam) == IDC_POPUPOPTDLG_BGCOLOUR) || (LOWORD(wParam) == IDC_POPUPOPTDLG_TEXTCOLOUR))
+ {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ }
+ } break;
+ }
+ } break;
+ case WM_DESTROY:
+ {
+ g_PopupOptPage.SetWnd(NULL);
+ return 0;
+ } break;
+ }
+ return 0;
+}
+*/
+
+// ================================================ Message options ================================================
+
+
+COptPage g_MessagesOptPage(MOD_NAME, NULL);
+
+
+void EnableMessagesOptDlgControls(CMsgTree* MsgTree)
+{
+ int I;
+ int IsNotGroup = false;
+ int Selected = false;
+ CBaseTreeItem* TreeItem = MsgTree->GetSelection();
+ if (TreeItem && !(TreeItem->Flags & TIF_ROOTITEM))
+ {
+ IsNotGroup = !(TreeItem->Flags & TIF_GROUP);
+ Selected = true;
+ }
+ g_MessagesOptPage.Enable(IDC_MESSAGEDLG_DEL, Selected);
+ g_MessagesOptPage.Enable(IDC_MESSAGEDLG_MSGTITLE, Selected);
+ for (I = 0; I < g_MessagesOptPage.Items.GetSize(); I++)
+ {
+ if (g_MessagesOptPage.Items[I]->GetParam() == IDC_MESSAGEDLG_MSGTREE)
+ {
+ g_MessagesOptPage.Items[I]->Enable(IsNotGroup);
+ }
+ }
+ SendDlgItemMessage(g_MessagesOptPage.GetWnd(), IDC_MESSAGEDLG_MSGDATA, EM_SETREADONLY, !IsNotGroup, 0);
+ g_MessagesOptPage.MemToPage(true);
+}
+
+static WNDPROC g_OrigDefStatusButtonMsgProc;
+
+static LRESULT CALLBACK DefStatusButtonSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ if (Msg == WM_LBUTTONUP && IsDlgButtonChecked(GetParent(hWnd), GetDlgCtrlID(hWnd)))
+ {
+ return 0;
+ }
+ return CallWindowProc(g_OrigDefStatusButtonMsgProc, hWnd, Msg, wParam, lParam);
+}
+
+
+int CALLBACK MessagesOptDlg(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int ChangeLock = 0;
+ static CMsgTree* MsgTree = NULL;
+ static struct {
+ int DlgItem, Status, IconIndex;
+ } DefMsgDlgItems[] = {
+ IDC_MESSAGEDLG_DEF_ONL, ID_STATUS_ONLINE, ILI_PROTO_ONL,
+ IDC_MESSAGEDLG_DEF_AWAY, ID_STATUS_AWAY, ILI_PROTO_AWAY,
+ IDC_MESSAGEDLG_DEF_NA, ID_STATUS_NA, ILI_PROTO_NA,
+ IDC_MESSAGEDLG_DEF_OCC, ID_STATUS_OCCUPIED, ILI_PROTO_OCC,
+ IDC_MESSAGEDLG_DEF_DND, ID_STATUS_DND, ILI_PROTO_DND,
+ IDC_MESSAGEDLG_DEF_FFC, ID_STATUS_FREECHAT, ILI_PROTO_FFC,
+ IDC_MESSAGEDLG_DEF_INV, ID_STATUS_INVISIBLE, ILI_PROTO_INV,
+ IDC_MESSAGEDLG_DEF_OTP, ID_STATUS_ONTHEPHONE, ILI_PROTO_OTP,
+ IDC_MESSAGEDLG_DEF_OTL, ID_STATUS_OUTTOLUNCH, ILI_PROTO_OTL
+ };
+ static struct {
+ int DlgItem, IconIndex;
+ TCHAR* Text;
+ } Buttons[] = {
+ IDC_MESSAGEDLG_NEWMSG, ILI_NEWMESSAGE, LPGENT("Create new message"),
+ IDC_MESSAGEDLG_NEWCAT, ILI_NEWCATEGORY, LPGENT("Create new category"),
+ IDC_MESSAGEDLG_DEL, ILI_DELETE, LPGENT("Delete"),
+ IDC_MESSAGEDLG_VARS, ILI_NOICON, LPGENT("Open Variables help dialog"),
+ };
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ MySetPos(hwndDlg);
+ ChangeLock++;
+ g_MessagesOptPage.SetWnd(hwndDlg);
+ SendMessage(GetDlgItem(hwndDlg, IDC_MESSAGEDLG_MSGTITLE), EM_LIMITTEXT, TREEITEMTITLE_MAXLEN, 0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_MESSAGEDLG_MSGDATA), EM_LIMITTEXT, AWAY_MSGDATA_MAX, 0);
+ // init image buttons
+ int I;
+ for (I = 0; I < lengthof(Buttons); I++)
+ {
+ HWND hButton = GetDlgItem(hwndDlg, Buttons[I].DlgItem);
+ SendMessage(hButton, BUTTONADDTOOLTIP, (WPARAM)TranslateTS(Buttons[I].Text), BATF_TCHAR);
+ SendMessage(hButton, BUTTONSETASFLATBTN, 0, 0);
+ }
+ // now default status message buttons
+ for (I = 0; I < lengthof(DefMsgDlgItems); I++)
+ {
+ HWND hButton = GetDlgItem(hwndDlg, DefMsgDlgItems[I].DlgItem);
+ SendMessage(hButton, BUTTONADDTOOLTIP, CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, DefMsgDlgItems[I].Status, GCMDF_TCHAR), BATF_TCHAR);
+ SendMessage(hButton, BUTTONSETASPUSHBTN, 0, 0);
+ SendMessage(hButton, BUTTONSETASFLATBTN, 0, 0);
+ g_OrigDefStatusButtonMsgProc = (WNDPROC)SetWindowLongPtr(hButton, GWLP_WNDPROC, (LONG_PTR)DefStatusButtonSubclassProc);
+ }
+ SendMessage(hwndDlg, UM_ICONSCHANGED, 0, 0);
+ g_MessagesOptPage.DBToMemToPage();
+ _ASSERT(!MsgTree);
+ MsgTree = new CMsgTree(GetDlgItem(hwndDlg, IDC_MESSAGEDLG_MSGTREE));
+ if (!MsgTree->SetSelection(MsgTree->GetDefMsg(ID_STATUS_AWAY), MTSS_BYID))
+ {
+ MsgTree->SetSelection(g_Messages_PredefinedRootID, MTSS_BYID);
+ }
+ ChangeLock--;
+ return true;
+ } break;
+ case UM_ICONSCHANGED:
+ {
+ int I;
+ for (I = 0; I < lengthof(DefMsgDlgItems); I++)
+ {
+ SendDlgItemMessage(hwndDlg, DefMsgDlgItems[I].DlgItem, BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_IconList[DefMsgDlgItems[I].IconIndex]);
+ }
+ for (I = 0; I < lengthof(Buttons); I++)
+ {
+ if (Buttons[I].IconIndex != ILI_NOICON)
+ {
+ SendDlgItemMessage(hwndDlg, Buttons[I].DlgItem, BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_IconList[Buttons[I].IconIndex]);
+ }
+ }
+ my_variables_skin_helpbutton(hwndDlg, IDC_MESSAGEDLG_VARS);
+ } break;
+ case WM_NOTIFY:
+ {
+ switch (((NMHDR*)lParam)->code)
+ {
+ case PSN_APPLY:
+ {
+ HWND hTreeView = GetDlgItem(hwndDlg, IDC_MESSAGEDLG_MSGTREE);
+ HTREEITEM hSelectedItem = TreeView_GetSelection(hTreeView);
+ ChangeLock++;
+ TreeView_SelectItem(hTreeView, NULL);
+ TreeView_SelectItem(hTreeView, hSelectedItem);
+ ChangeLock--;
+ MsgTree->Save();
+ return true;
+ } break;
+ }
+ if (((LPNMHDR)lParam)->idFrom == IDC_MESSAGEDLG_MSGTREE)
+ {
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case MTN_SELCHANGED:
+ {
+ PNMMSGTREE pnm = (PNMMSGTREE)lParam;
+ int I;
+ if (pnm->ItemOld && !(pnm->ItemOld->Flags & (TIF_ROOTITEM | TIF_GROUP)))
+ {
+ TCString Msg;
+ GetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGDATA, Msg.GetBuffer(AWAY_MSGDATA_MAX), AWAY_MSGDATA_MAX);
+ Msg.ReleaseBuffer();
+ if (((CTreeItem*)pnm->ItemOld)->User_Str1 != (const TCHAR*)Msg)
+ {
+ ((CTreeItem*)pnm->ItemOld)->User_Str1 = Msg;
+ MsgTree->SetModified(true);
+ }
+ }
+ if (pnm->ItemNew)
+ {
+ ChangeLock++;
+ if (!(pnm->ItemNew->Flags & TIF_ROOTITEM))
+ {
+ SetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGTITLE, pnm->ItemNew->Title);
+ SetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGDATA, (pnm->ItemNew->Flags & TIF_GROUP) ? _T("") : ((CTreeItem*)pnm->ItemNew)->User_Str1);
+ } else
+ {
+ SetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGTITLE, _T(""));
+ if (pnm->ItemNew->ID == g_Messages_RecentRootID)
+ {
+ SetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGDATA, TranslateT("Your most recent status messages are placed in this category. It's not recommended to put your messages manually here, as they'll be replaced by your recent messages."));
+ } else
+ {
+ _ASSERT(pnm->ItemNew->ID == g_Messages_PredefinedRootID);
+ SetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGDATA, TranslateT("You can put your frequently used and favorite messages in this category."));
+ }
+ }
+ for (I = 0; I < lengthof(DefMsgDlgItems); I++)
+ {
+ COptItem_Checkbox *Checkbox = (COptItem_Checkbox*)g_MessagesOptPage.Find(DefMsgDlgItems[I].DlgItem);
+ Checkbox->SetWndValue(g_MessagesOptPage.GetWnd(), MsgTree->GetDefMsg(DefMsgDlgItems[I].Status) == pnm->ItemNew->ID);
+ }
+ ChangeLock--;
+ }
+ EnableMessagesOptDlgControls(MsgTree);
+ return 0;
+ } break;
+ case MTN_DEFMSGCHANGED:
+ {
+ PNMMSGTREE pnm = (PNMMSGTREE)lParam;
+ if (!ChangeLock)
+ {
+ CBaseTreeItem* SelectedItem = MsgTree->GetSelection();
+ _ASSERT(SelectedItem);
+ if ((pnm->ItemOld && pnm->ItemOld->ID == SelectedItem->ID) || (pnm->ItemNew && pnm->ItemNew->ID == SelectedItem->ID))
+ { // SelectedItem contains the same info as one of ItemOld or ItemNew - so we'll just use SelectedItem and won't bother with identifying which of ItemOld or ItemNew is currently selected
+ int I;
+ for (I = 0; I < lengthof(DefMsgDlgItems); I++)
+ {
+ COptItem_Checkbox *Checkbox = (COptItem_Checkbox*)g_MessagesOptPage.Find(DefMsgDlgItems[I].DlgItem);
+ Checkbox->SetWndValue(g_MessagesOptPage.GetWnd(), MsgTree->GetDefMsg(DefMsgDlgItems[I].Status) == SelectedItem->ID);
+ }
+ }
+ }
+ if (!ChangeLock)
+ {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ }
+ return 0;
+ } break;
+ case MTN_ITEMRENAMED:
+ {
+ PNMMSGTREE pnm = (PNMMSGTREE)lParam;
+ CBaseTreeItem* SelectedItem = MsgTree->GetSelection();
+ _ASSERT(SelectedItem);
+ if (pnm->ItemNew->ID == SelectedItem->ID && !ChangeLock)
+ {
+ ChangeLock++;
+ SetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGTITLE, pnm->ItemNew->Title);
+ ChangeLock--;
+ }
+ } // go through
+ case MTN_ENDDRAG:
+ case MTN_NEWCATEGORY:
+ case MTN_NEWMESSAGE:
+ case MTN_DELETEITEM:
+ case TVN_ITEMEXPANDED:
+ {
+ if (!ChangeLock)
+ {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ }
+ return 0;
+ } break;
+ }
+ }
+ } break;
+ case WM_COMMAND:
+ {
+ switch (HIWORD(wParam))
+ {
+ case BN_CLICKED:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_MESSAGEDLG_DEF_ONL:
+ case IDC_MESSAGEDLG_DEF_AWAY:
+ case IDC_MESSAGEDLG_DEF_NA:
+ case IDC_MESSAGEDLG_DEF_OCC:
+ case IDC_MESSAGEDLG_DEF_DND:
+ case IDC_MESSAGEDLG_DEF_FFC:
+ case IDC_MESSAGEDLG_DEF_INV:
+ case IDC_MESSAGEDLG_DEF_OTP:
+ case IDC_MESSAGEDLG_DEF_OTL:
+ {
+ int I;
+ for (I = 0; I < lengthof(DefMsgDlgItems); I++)
+ {
+ if (LOWORD(wParam) == DefMsgDlgItems[I].DlgItem)
+ {
+ MsgTree->SetDefMsg(DefMsgDlgItems[I].Status, MsgTree->GetSelection()->ID); // PSM_CHANGED is sent here through MTN_DEFMSGCHANGED, so we don't need to send it once more
+ break;
+ }
+ }
+ } break;
+ case IDC_MESSAGEDLG_VARS:
+ {
+ my_variables_showhelp(hwndDlg, IDC_MESSAGEDLG_MSGDATA);
+ } break;
+ case IDC_MESSAGEDLG_DEL:
+ {
+ MsgTree->EnsureVisible(MsgTree->GetSelection()->hItem);
+ MsgTree->DeleteSelectedItem();
+ } break;
+ case IDC_MESSAGEDLG_NEWCAT:
+ {
+ MsgTree->AddCategory();
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGEDLG_MSGTITLE));
+ } break;
+ case IDC_MESSAGEDLG_NEWMSG:
+ {
+ MsgTree->AddMessage();
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGEDLG_MSGTITLE));
+ } break;
+ }
+ } break;
+ case EN_CHANGE:
+ {
+ if (LOWORD(wParam) == IDC_MESSAGEDLG_MSGDATA || LOWORD(wParam) == IDC_MESSAGEDLG_MSGTITLE)
+ {
+ if (!ChangeLock)
+ {
+ if (LOWORD(wParam) == IDC_MESSAGEDLG_MSGTITLE)
+ {
+ CBaseTreeItem* TreeItem = MsgTree->GetSelection();
+ if (TreeItem && !(TreeItem->Flags & TIF_ROOTITEM))
+ {
+ GetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGTITLE, TreeItem->Title.GetBuffer(TREEITEMTITLE_MAXLEN), TREEITEMTITLE_MAXLEN);
+ TreeItem->Title.ReleaseBuffer();
+ ChangeLock++;
+ MsgTree->UpdateItem(TreeItem->ID);
+ ChangeLock--;
+ }
+ }
+ MsgTree->SetModified(true);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ }
+ }
+ } break;
+ }
+ } break;
+ case WM_DESTROY:
+ {
+ delete MsgTree;
+ MsgTree = NULL;
+ g_MessagesOptPage.SetWnd(NULL);
+ } break;
+ }
+ return 0;
+}
+
+// ================================================ Main options ================================================
+
+
+COptPage g_MoreOptPage(MOD_NAME, NULL);
+
+
+void EnableMoreOptDlgControls()
+{
+ g_MoreOptPage.Enable(IDC_MOREOPTDLG_PERSTATUSPERSONAL, g_MoreOptPage.GetWndValue(IDC_MOREOPTDLG_SAVEPERSONALMSGS));
+ int Enabled = g_MoreOptPage.GetWndValue(IDC_MOREOPTDLG_RECENTMSGSCOUNT);
+ g_MoreOptPage.Enable(IDC_MOREOPTDLG_PERSTATUSMRM, Enabled);
+ g_MoreOptPage.Enable(IDC_MOREOPTDLG_USELASTMSG, Enabled);
+ g_MoreOptPage.Enable(IDC_MOREOPTDLG_USEDEFMSG, Enabled);
+ g_MoreOptPage.Enable(IDC_MOREOPTDLG_PERSTATUSPERSONAL, g_MoreOptPage.GetWndValue(IDC_MOREOPTDLG_SAVEPERSONALMSGS));
+ g_MoreOptPage.Enable(IDC_MOREOPTDLG_UPDATEMSGSPERIOD, g_MoreOptPage.GetWndValue(IDC_MOREOPTDLG_UPDATEMSGS));
+ InvalidateRect(GetDlgItem(g_MoreOptPage.GetWnd(), IDC_MOREOPTDLG_UPDATEMSGSPERIOD_SPIN), NULL, false); // update spin control
+ g_MoreOptPage.MemToPage(true);
+}
+
+
+int CALLBACK MoreOptDlg(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int ChangeLock = 0;
+ static struct {
+ int DlgItem, Status, IconIndex;
+ } StatusButtons[] = {
+ IDC_MOREOPTDLG_DONTPOPDLG_ONL, ID_STATUS_ONLINE, ILI_PROTO_ONL,
+ IDC_MOREOPTDLG_DONTPOPDLG_AWAY, ID_STATUS_AWAY, ILI_PROTO_AWAY,
+ IDC_MOREOPTDLG_DONTPOPDLG_NA, ID_STATUS_NA, ILI_PROTO_NA,
+ IDC_MOREOPTDLG_DONTPOPDLG_OCC, ID_STATUS_OCCUPIED, ILI_PROTO_OCC,
+ IDC_MOREOPTDLG_DONTPOPDLG_DND, ID_STATUS_DND, ILI_PROTO_DND,
+ IDC_MOREOPTDLG_DONTPOPDLG_FFC, ID_STATUS_FREECHAT, ILI_PROTO_FFC,
+ IDC_MOREOPTDLG_DONTPOPDLG_INV, ID_STATUS_INVISIBLE, ILI_PROTO_INV,
+ IDC_MOREOPTDLG_DONTPOPDLG_OTP, ID_STATUS_ONTHEPHONE, ILI_PROTO_OTP,
+ IDC_MOREOPTDLG_DONTPOPDLG_OTL, ID_STATUS_OUTTOLUNCH, ILI_PROTO_OTL
+ };
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ MySetPos(hwndDlg);
+ ChangeLock++;
+ g_MoreOptPage.SetWnd(hwndDlg);
+ SendDlgItemMessage(hwndDlg, IDC_MOREOPTDLG_WAITFORMSG, EM_LIMITTEXT, 4, 0);
+ SendDlgItemMessage(hwndDlg, IDC_MOREOPTDLG_RECENTMSGSCOUNT, EM_LIMITTEXT, 2, 0);
+ SendDlgItemMessage(hwndDlg, IDC_MOREOPTDLG_WAITFORMSG_SPIN, UDM_SETRANGE32, -1, 9999);
+ SendDlgItemMessage(hwndDlg, IDC_MOREOPTDLG_RECENTMSGSCOUNT_SPIN, UDM_SETRANGE32, 0, 99);
+ SendDlgItemMessage(hwndDlg, IDC_MOREOPTDLG_UPDATEMSGSPERIOD_SPIN, UDM_SETRANGE32, 30, 99999);
+ int I;
+ for (I = 0; I < lengthof(StatusButtons); I++)
+ {
+ HWND hButton = GetDlgItem(hwndDlg, StatusButtons[I].DlgItem);
+ SendMessage(hButton, BUTTONADDTOOLTIP, CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, StatusButtons[I].Status, GCMDF_TCHAR), BATF_TCHAR);
+ SendMessage(hButton, BUTTONSETASPUSHBTN, 0, 0);
+ SendMessage(hButton, BUTTONSETASFLATBTN, 0, 0);
+ }
+ SendMessage(hwndDlg, UM_ICONSCHANGED, 0, 0);
+ g_MoreOptPage.DBToMemToPage();
+ EnableMoreOptDlgControls();
+ ChangeLock--;
+ return true;
+ } break;
+ case UM_ICONSCHANGED:
+ {
+ int I;
+ for (I = 0; I < lengthof(StatusButtons); I++)
+ {
+ SendDlgItemMessage(hwndDlg, StatusButtons[I].DlgItem, BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_IconList[StatusButtons[I].IconIndex]);
+ }
+ } break;
+ case WM_NOTIFY:
+ {
+ switch (((NMHDR*)lParam)->code)
+ {
+ case PSN_APPLY:
+ {
+ g_MoreOptPage.PageToMemToDB();
+ InitUpdateMsgs();
+ return true;
+ } break;
+ }
+ } break;
+ case WM_COMMAND:
+ {
+ switch (HIWORD(wParam))
+ {
+ case BN_CLICKED:
+ {
+ switch (LOWORD(wParam))
+ {
+
+ case IDC_MOREOPTDLG_RESETPROTOMSGS:
+ case IDC_MOREOPTDLG_SAVEPERSONALMSGS:
+ case IDC_MOREOPTDLG_UPDATEMSGS:
+ {
+ EnableMoreOptDlgControls();
+ } // go through
+ case IDC_MOREOPTDLG_PERSTATUSMRM:
+ case IDC_MOREOPTDLG_PERSTATUSPROTOMSGS:
+ case IDC_MOREOPTDLG_PERSTATUSPROTOSETTINGS:
+ case IDC_MOREOPTDLG_PERSTATUSPERSONAL:
+ case IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS:
+ case IDC_MOREOPTDLG_USEMENUITEM:
+ case IDC_MOREOPTDLG_MYNICKPERPROTO:
+ case IDC_MOREOPTDLG_USEDEFMSG:
+ case IDC_MOREOPTDLG_USELASTMSG:
+ case IDC_MOREOPTDLG_DONTPOPDLG_ONL:
+ case IDC_MOREOPTDLG_DONTPOPDLG_AWAY:
+ case IDC_MOREOPTDLG_DONTPOPDLG_NA:
+ case IDC_MOREOPTDLG_DONTPOPDLG_OCC:
+ case IDC_MOREOPTDLG_DONTPOPDLG_DND:
+ case IDC_MOREOPTDLG_DONTPOPDLG_FFC:
+ case IDC_MOREOPTDLG_DONTPOPDLG_INV:
+ case IDC_MOREOPTDLG_DONTPOPDLG_OTP:
+ case IDC_MOREOPTDLG_DONTPOPDLG_OTL:
+ {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ return 0;
+ } break;
+ }
+ } break;
+ case EN_CHANGE:
+ {
+ if (!ChangeLock && g_MoreOptPage.GetWnd())
+ {
+ if (LOWORD(wParam) == IDC_MOREOPTDLG_RECENTMSGSCOUNT)
+ {
+ EnableMoreOptDlgControls();
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ }
+ } break;
+ }
+ } break;
+ case WM_DESTROY:
+ {
+ g_MoreOptPage.SetWnd(NULL);
+ } break;
+ }
+ return 0;
+}
+
+
+// ================================================ Autoreply options ================================================
+
+
+COptPage g_AutoreplyOptPage(MOD_NAME, NULL);
+
+
+void EnableAutoreplyOptDlgControls()
+{
+ int I;
+ g_AutoreplyOptPage.PageToMem();
+ int Autoreply = g_AutoreplyOptPage.GetValue(IDC_REPLYDLG_ENABLEREPLY);
+ int OnlyIdleReply = g_AutoreplyOptPage.GetValue(IDC_REPLYDLG_ONLYIDLEREPLY);
+ for (I = 0; I < g_AutoreplyOptPage.Items.GetSize(); I++)
+ {
+ switch (g_AutoreplyOptPage.Items[I]->GetParam())
+ {
+ case IDC_REPLYDLG_ENABLEREPLY:
+ {
+ g_AutoreplyOptPage.Items[I]->Enable(Autoreply);
+ } break;
+ case IDC_REPLYDLG_SENDCOUNT:
+ {
+ g_AutoreplyOptPage.Items[I]->Enable(Autoreply && g_AutoreplyOptPage.GetValue(IDC_REPLYDLG_SENDCOUNT) > 0);
+ } break;
+ }
+ }
+ g_AutoreplyOptPage.MemToPage(true);
+ InvalidateRect(GetDlgItem(g_AutoreplyOptPage.GetWnd(), IDC_REPLYDLG_SENDCOUNT_SPIN), NULL, 0); // update spin control
+}
+
+int CALLBACK AutoreplyOptDlg(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int ChangeLock = 0;
+ static HWND hWndTooltips;
+ static HFONT s_hDrawFont;
+ static struct {
+ int DlgItem, Status, IconIndex;
+ } StatusButtons[] = {
+ IDC_REPLYDLG_DISABLE_ONL, ID_STATUS_ONLINE, ILI_PROTO_ONL,
+ IDC_REPLYDLG_DISABLE_AWAY, ID_STATUS_AWAY, ILI_PROTO_AWAY,
+ IDC_REPLYDLG_DISABLE_NA, ID_STATUS_NA, ILI_PROTO_NA,
+ IDC_REPLYDLG_DISABLE_OCC, ID_STATUS_OCCUPIED, ILI_PROTO_OCC,
+ IDC_REPLYDLG_DISABLE_DND, ID_STATUS_DND, ILI_PROTO_DND,
+ IDC_REPLYDLG_DISABLE_FFC, ID_STATUS_FREECHAT, ILI_PROTO_FFC,
+ IDC_REPLYDLG_DISABLE_INV, ID_STATUS_INVISIBLE, ILI_PROTO_INV,
+ IDC_REPLYDLG_DISABLE_OTP, ID_STATUS_ONTHEPHONE, ILI_PROTO_OTP,
+ IDC_REPLYDLG_DISABLE_OTL, ID_STATUS_OUTTOLUNCH, ILI_PROTO_OTL
+ };
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ ChangeLock++;
+ TranslateDialogDefault(hwndDlg);
+ MySetPos(hwndDlg);
+ g_AutoreplyOptPage.SetWnd(hwndDlg);
+
+ LOGFONT logFont;
+ HFONT hFont = (HFONT)SendDlgItemMessage(hwndDlg, IDC_REPLYDLG_STATIC_DISABLEWHENSTATUS, WM_GETFONT, 0, 0); // try getting the font used by the control
+ if (!hFont)
+ {
+ hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+ }
+ GetObject(hFont, sizeof(logFont), &logFont);
+ logFont.lfWeight = FW_BOLD;
+ s_hDrawFont = CreateFontIndirect(&logFont); // recreate the font
+ SendDlgItemMessage(hwndDlg, IDC_REPLYDLG_STATIC_DISABLEWHENSTATUS, WM_SETFONT, (WPARAM)s_hDrawFont, true);
+ SendDlgItemMessage(hwndDlg, IDC_REPLYDLG_STATIC_FORMAT, WM_SETFONT, (WPARAM)s_hDrawFont, true);
+
+ SendDlgItemMessage(hwndDlg, IDC_REPLYDLG_SENDCOUNT, EM_LIMITTEXT, 3, 0);
+ SendDlgItemMessage(hwndDlg, IDC_REPLYDLG_SENDCOUNT_SPIN, UDM_SETRANGE32, -1, 999);
+
+ HWND hCombo = GetDlgItem(hwndDlg, IDC_REPLYDLG_ONLYIDLEREPLY_COMBO);
+ static struct {
+ TCHAR *Text;
+ int Meaning;
+ } IdleComboValues[] = {
+ LPGENT("Windows"), AUTOREPLY_IDLE_WINDOWS,
+ LPGENT("Miranda"), AUTOREPLY_IDLE_MIRANDA
+ };
+ int I;
+ for (I = 0; I < lengthof(IdleComboValues); I++)
+ {
+ SendMessage(hCombo, CB_SETITEMDATA, SendMessage(hCombo, CB_ADDSTRING, 0, (LPARAM)TranslateTS(IdleComboValues[I].Text)), IdleComboValues[I].Meaning);
+ }
+
+ for (I = 0; I < lengthof(StatusButtons); I++)
+ {
+ HWND hButton = GetDlgItem(hwndDlg, StatusButtons[I].DlgItem);
+ SendMessage(hButton, BUTTONADDTOOLTIP, CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, StatusButtons[I].Status, GCMDF_TCHAR), BATF_TCHAR);
+ SendMessage(hButton, BUTTONSETASPUSHBTN, 0, 0);
+ SendMessage(hButton, BUTTONSETASFLATBTN, 0, 0);
+ }
+ HWND hButton = GetDlgItem(hwndDlg, IDC_REPLYDLG_VARS);
+ SendMessage(hButton, BUTTONADDTOOLTIP, (WPARAM)TranslateT("Open Variables help dialog"), BATF_TCHAR);
+ SendMessage(hButton, BUTTONSETASFLATBTN, 0, 0);
+ MakeThemedImageCheckbox(GetDlgItem(hwndDlg, IDC_MOREOPTDLG_EVNTMSG));
+ MakeThemedImageCheckbox(GetDlgItem(hwndDlg, IDC_MOREOPTDLG_EVNTURL));
+ MakeThemedImageCheckbox(GetDlgItem(hwndDlg, IDC_MOREOPTDLG_EVNTFILE));
+ SendMessage(hwndDlg, UM_ICONSCHANGED, 0, 0);
+
+ // init tooltips
+ struct {
+ int DlgItemID;
+ TCHAR* Text;
+ } Tooltips[] = {
+ IDC_REPLYDLG_RESETCOUNTERWHENSAMEICON, LPGENT("When this checkbox is ticked, NewAwaySys counts \"send times\" starting from the last status message change, even if status mode didn't change.\nWhen the checkbox isn't ticked, \"send times\" are counted from last status mode change (i.e. disabled state is more restrictive)."),
+ IDC_MOREOPTDLG_EVNTMSG, LPGENT("Message"),
+ IDC_MOREOPTDLG_EVNTURL, LPGENT("URL"),
+ IDC_MOREOPTDLG_EVNTFILE, LPGENT("File")
+ };
+ TOOLINFO ti = {0};
+ hWndTooltips = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), WS_POPUP | TTS_NOPREFIX, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
+ ti.hwnd = hwndDlg;
+ for (I = 0; I < lengthof(Tooltips); I++)
+ {
+ ti.uId = (UINT)GetDlgItem(hwndDlg, Tooltips[I].DlgItemID);
+ ti.lpszText = TranslateTS(Tooltips[I].Text);
+ SendMessage(hWndTooltips, TTM_ADDTOOL, 0, (LPARAM)&ti);
+ }
+ SendMessage(hWndTooltips, TTM_SETMAXTIPWIDTH, 0, 500);
+ SendMessage(hWndTooltips, TTM_SETDELAYTIME, TTDT_AUTOPOP, 32767); // tooltip hide time; looks like 32 seconds is the maximum
+
+ g_AutoreplyOptPage.DBToMemToPage();
+ EnableAutoreplyOptDlgControls();
+ ChangeLock--;
+ MakeGroupCheckbox(GetDlgItem(hwndDlg, IDC_REPLYDLG_ENABLEREPLY));
+ return true;
+ } break;
+ case UM_ICONSCHANGED:
+ {
+ int I;
+ for (I = 0; I < lengthof(StatusButtons); I++)
+ {
+ SendDlgItemMessage(hwndDlg, StatusButtons[I].DlgItem, BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_IconList[StatusButtons[I].IconIndex]);
+ }
+ my_variables_skin_helpbutton(hwndDlg, IDC_REPLYDLG_VARS);
+ SendDlgItemMessage(hwndDlg, IDC_MOREOPTDLG_EVNTMSG, BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_IconList[ILI_EVENT_MESSAGE]);
+ SendDlgItemMessage(hwndDlg, IDC_MOREOPTDLG_EVNTURL, BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_IconList[ILI_EVENT_URL]);
+ SendDlgItemMessage(hwndDlg, IDC_MOREOPTDLG_EVNTFILE, BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_IconList[ILI_EVENT_FILE]);
+ } break;
+ case WM_NOTIFY:
+ {
+ switch (((NMHDR*)lParam)->code)
+ {
+ case PSN_APPLY:
+ {
+ g_AutoreplyOptPage.PageToMemToDB();
+ //UpdateSOEButtons();
+ return true;
+ } break;
+ }
+ } break;
+ case WM_COMMAND:
+ {
+ switch (HIWORD(wParam))
+ {
+ case BN_CLICKED:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_REPLYDLG_ENABLEREPLY:
+ {
+ EnableAutoreplyOptDlgControls();
+ } // go through
+ case IDC_REPLYDLG_DONTSENDTOICQ:
+ case IDC_REPLYDLG_DONTREPLYINVISIBLE:
+ case IDC_REPLYDLG_ONLYCLOSEDDLGREPLY:
+ case IDC_REPLYDLG_ONLYIDLEREPLY:
+ case IDC_REPLYDLG_RESETCOUNTERWHENSAMEICON:
+ case IDC_REPLYDLG_EVENTMSG:
+ case IDC_REPLYDLG_EVENTURL:
+ case IDC_REPLYDLG_EVENTFILE:
+ case IDC_REPLYDLG_LOGREPLY:
+ case IDC_REPLYDLG_DISABLE_ONL:
+ case IDC_REPLYDLG_DISABLE_AWAY:
+ case IDC_REPLYDLG_DISABLE_NA:
+ case IDC_REPLYDLG_DISABLE_OCC:
+ case IDC_REPLYDLG_DISABLE_DND:
+ case IDC_REPLYDLG_DISABLE_FFC:
+ case IDC_REPLYDLG_DISABLE_INV:
+ case IDC_REPLYDLG_DISABLE_OTP:
+ case IDC_REPLYDLG_DISABLE_OTL:
+ {
+ if (!ChangeLock)
+ {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ }
+ } break;
+ case IDC_REPLYDLG_VARS:
+ {
+ my_variables_showhelp(hwndDlg, IDC_REPLYDLG_PREFIX);
+ } break;
+ }
+ } break;
+ case EN_CHANGE:
+ {
+ if ((LOWORD(wParam) == IDC_REPLYDLG_SENDCOUNT) || (LOWORD(wParam) == IDC_REPLYDLG_PREFIX))
+ {
+ if (!ChangeLock && g_AutoreplyOptPage.GetWnd())
+ {
+ if (LOWORD(wParam) == IDC_REPLYDLG_SENDCOUNT)
+ {
+ EnableAutoreplyOptDlgControls();
+ }
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ }
+ }
+ } break;
+ case CBN_SELCHANGE:
+ {
+ if (LOWORD(wParam) == IDC_REPLYDLG_ONLYIDLEREPLY_COMBO)
+ {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ }
+ } break;
+ }
+ } break;
+ case WM_DESTROY:
+ {
+ g_AutoreplyOptPage.SetWnd(NULL);
+ if (s_hDrawFont)
+ {
+ DeleteObject(s_hDrawFont);
+ }
+ DestroyWindow(hWndTooltips);
+ } break;
+ }
+ return 0;
+}
+// ================================================ Modern options ==============================================
+
+int CALLBACK MessagesModernOptDlg(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static int ChangeLock = 0;
+ static CMsgTree* MsgTree = NULL;
+ static struct {
+ int DlgItem, Status, IconIndex;
+ } DefMsgDlgItems[] = {
+ IDC_MESSAGEDLG_DEF_ONL, ID_STATUS_ONLINE, ILI_PROTO_ONL,
+ IDC_MESSAGEDLG_DEF_AWAY, ID_STATUS_AWAY, ILI_PROTO_AWAY,
+ IDC_MESSAGEDLG_DEF_NA, ID_STATUS_NA, ILI_PROTO_NA,
+ IDC_MESSAGEDLG_DEF_OCC, ID_STATUS_OCCUPIED, ILI_PROTO_OCC,
+ IDC_MESSAGEDLG_DEF_DND, ID_STATUS_DND, ILI_PROTO_DND,
+ IDC_MESSAGEDLG_DEF_FFC, ID_STATUS_FREECHAT, ILI_PROTO_FFC,
+ IDC_MESSAGEDLG_DEF_INV, ID_STATUS_INVISIBLE, ILI_PROTO_INV,
+ IDC_MESSAGEDLG_DEF_OTP, ID_STATUS_ONTHEPHONE, ILI_PROTO_OTP,
+ IDC_MESSAGEDLG_DEF_OTL, ID_STATUS_OUTTOLUNCH, ILI_PROTO_OTL
+ };
+ static struct {
+ int DlgItem, IconIndex;
+ TCHAR* Text;
+ } Buttons[] = {
+ IDC_MESSAGEDLG_NEWMSG, ILI_NEWMESSAGE, LPGENT("Create new message"),
+ IDC_MESSAGEDLG_NEWCAT, ILI_NEWCATEGORY, LPGENT("Create new category"),
+ IDC_MESSAGEDLG_DEL, ILI_DELETE, LPGENT("Delete"),
+ IDC_MESSAGEDLG_VARS, ILI_NOICON, LPGENT("Open Variables help dialog"),
+ };
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ MySetPos(hwndDlg);
+ ChangeLock++;
+ g_MessagesOptPage.SetWnd(hwndDlg);
+ SendMessage(GetDlgItem(hwndDlg, IDC_MESSAGEDLG_MSGTITLE), EM_LIMITTEXT, TREEITEMTITLE_MAXLEN, 0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_MESSAGEDLG_MSGDATA), EM_LIMITTEXT, AWAY_MSGDATA_MAX, 0);
+ // init image buttons
+ int I;
+ for (I = 0; I < lengthof(Buttons); I++)
+ {
+ HWND hButton = GetDlgItem(hwndDlg, Buttons[I].DlgItem);
+ SendMessage(hButton, BUTTONADDTOOLTIP, (WPARAM)TranslateTS(Buttons[I].Text), BATF_TCHAR);
+ SendMessage(hButton, BUTTONSETASFLATBTN, 0, 0);
+ }
+ // now default status message buttons
+ for (I = 0; I < lengthof(DefMsgDlgItems); I++)
+ {
+ HWND hButton = GetDlgItem(hwndDlg, DefMsgDlgItems[I].DlgItem);
+ SendMessage(hButton, BUTTONADDTOOLTIP, CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, DefMsgDlgItems[I].Status, GCMDF_TCHAR), BATF_TCHAR);
+ SendMessage(hButton, BUTTONSETASPUSHBTN, 0, 0);
+ SendMessage(hButton, BUTTONSETASFLATBTN, 0, 0);
+ g_OrigDefStatusButtonMsgProc = (WNDPROC)SetWindowLongPtr(hButton, GWLP_WNDPROC, (LONG_PTR)DefStatusButtonSubclassProc);
+ }
+ SendMessage(hwndDlg, UM_ICONSCHANGED, 0, 0);
+ g_MessagesOptPage.DBToMemToPage();
+ _ASSERT(!MsgTree);
+ MsgTree = new CMsgTree(GetDlgItem(hwndDlg, IDC_MESSAGEDLG_MSGTREE));
+ if (!MsgTree->SetSelection(MsgTree->GetDefMsg(ID_STATUS_AWAY), MTSS_BYID))
+ {
+ MsgTree->SetSelection(g_Messages_PredefinedRootID, MTSS_BYID);
+ }
+ ChangeLock--;
+ //MakeGroupCheckbox(GetDlgItem(hwndDlg, IDC_REPLYDLG_ENABLEREPLY));
+ return true;
+ } break;
+ case UM_ICONSCHANGED:
+ {
+ int I;
+ for (I = 0; I < lengthof(DefMsgDlgItems); I++)
+ {
+ SendDlgItemMessage(hwndDlg, DefMsgDlgItems[I].DlgItem, BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_IconList[DefMsgDlgItems[I].IconIndex]);
+ }
+ for (I = 0; I < lengthof(Buttons); I++)
+ {
+ if (Buttons[I].IconIndex != ILI_NOICON)
+ {
+ SendDlgItemMessage(hwndDlg, Buttons[I].DlgItem, BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_IconList[Buttons[I].IconIndex]);
+ }
+ }
+ my_variables_skin_helpbutton(hwndDlg, IDC_MESSAGEDLG_VARS);
+ } break;
+ case WM_NOTIFY:
+ {
+ switch (((NMHDR*)lParam)->code)
+ {
+ case PSN_APPLY:
+ {
+ HWND hTreeView = GetDlgItem(hwndDlg, IDC_MESSAGEDLG_MSGTREE);
+ HTREEITEM hSelectedItem = TreeView_GetSelection(hTreeView);
+ ChangeLock++;
+ TreeView_SelectItem(hTreeView, NULL);
+ TreeView_SelectItem(hTreeView, hSelectedItem);
+ ChangeLock--;
+ MsgTree->Save();
+ return true;
+ } break;
+ }
+ if (((LPNMHDR)lParam)->idFrom == IDC_MESSAGEDLG_MSGTREE)
+ {
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case MTN_SELCHANGED:
+ {
+ PNMMSGTREE pnm = (PNMMSGTREE)lParam;
+ int I;
+ if (pnm->ItemOld && !(pnm->ItemOld->Flags & (TIF_ROOTITEM | TIF_GROUP)))
+ {
+ TCString Msg;
+ GetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGDATA, Msg.GetBuffer(AWAY_MSGDATA_MAX), AWAY_MSGDATA_MAX);
+ Msg.ReleaseBuffer();
+ if (((CTreeItem*)pnm->ItemOld)->User_Str1 != (const TCHAR*)Msg)
+ {
+ ((CTreeItem*)pnm->ItemOld)->User_Str1 = Msg;
+ MsgTree->SetModified(true);
+ }
+ }
+ if (pnm->ItemNew)
+ {
+ ChangeLock++;
+ if (!(pnm->ItemNew->Flags & TIF_ROOTITEM))
+ {
+ SetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGTITLE, pnm->ItemNew->Title);
+ SetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGDATA, (pnm->ItemNew->Flags & TIF_GROUP) ? _T("") : ((CTreeItem*)pnm->ItemNew)->User_Str1);
+ } else
+ {
+ SetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGTITLE, _T(""));
+ if (pnm->ItemNew->ID == g_Messages_RecentRootID)
+ {
+ SetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGDATA, TranslateT("Your most recent status messages are placed in this category. It's not recommended to put your messages manually here, as they'll be replaced by your recent messages."));
+ } else
+ {
+ _ASSERT(pnm->ItemNew->ID == g_Messages_PredefinedRootID);
+ SetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGDATA, TranslateT("You can put your frequently used and favorite messages in this category."));
+ }
+ }
+ for (I = 0; I < lengthof(DefMsgDlgItems); I++)
+ {
+ COptItem_Checkbox *Checkbox = (COptItem_Checkbox*)g_MessagesOptPage.Find(DefMsgDlgItems[I].DlgItem);
+ Checkbox->SetWndValue(g_MessagesOptPage.GetWnd(), MsgTree->GetDefMsg(DefMsgDlgItems[I].Status) == pnm->ItemNew->ID);
+ }
+ ChangeLock--;
+ }
+ EnableMessagesOptDlgControls(MsgTree);
+ return 0;
+ } break;
+ case MTN_DEFMSGCHANGED:
+ {
+ PNMMSGTREE pnm = (PNMMSGTREE)lParam;
+ if (!ChangeLock)
+ {
+ CBaseTreeItem* SelectedItem = MsgTree->GetSelection();
+ _ASSERT(SelectedItem);
+ if ((pnm->ItemOld && pnm->ItemOld->ID == SelectedItem->ID) || (pnm->ItemNew && pnm->ItemNew->ID == SelectedItem->ID))
+ { // SelectedItem contains the same info as one of ItemOld or ItemNew - so we'll just use SelectedItem and won't bother with identifying which of ItemOld or ItemNew is currently selected
+ int I;
+ for (I = 0; I < lengthof(DefMsgDlgItems); I++)
+ {
+ COptItem_Checkbox *Checkbox = (COptItem_Checkbox*)g_MessagesOptPage.Find(DefMsgDlgItems[I].DlgItem);
+ Checkbox->SetWndValue(g_MessagesOptPage.GetWnd(), MsgTree->GetDefMsg(DefMsgDlgItems[I].Status) == SelectedItem->ID);
+ }
+ }
+ }
+ if (!ChangeLock)
+ {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ }
+ return 0;
+ } break;
+ case MTN_ITEMRENAMED:
+ {
+ PNMMSGTREE pnm = (PNMMSGTREE)lParam;
+ CBaseTreeItem* SelectedItem = MsgTree->GetSelection();
+ _ASSERT(SelectedItem);
+ if (pnm->ItemNew->ID == SelectedItem->ID && !ChangeLock)
+ {
+ ChangeLock++;
+ SetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGTITLE, pnm->ItemNew->Title);
+ ChangeLock--;
+ }
+ } // go through
+ case MTN_ENDDRAG:
+ case MTN_NEWCATEGORY:
+ case MTN_NEWMESSAGE:
+ case MTN_DELETEITEM:
+ case TVN_ITEMEXPANDED:
+ {
+ if (!ChangeLock)
+ {
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ }
+ return 0;
+ } break;
+ }
+ }
+ } break;
+ case WM_COMMAND:
+ {
+ switch (HIWORD(wParam))
+ {
+ case BN_CLICKED:
+ {
+
+
+ switch (LOWORD(wParam))
+ {
+
+ case IDC_MESSAGEDLG_DEF_ONL:
+ case IDC_MESSAGEDLG_DEF_AWAY:
+ case IDC_MESSAGEDLG_DEF_NA:
+ case IDC_MESSAGEDLG_DEF_OCC:
+ case IDC_MESSAGEDLG_DEF_DND:
+ case IDC_MESSAGEDLG_DEF_FFC:
+ case IDC_MESSAGEDLG_DEF_INV:
+ case IDC_MESSAGEDLG_DEF_OTP:
+ case IDC_MESSAGEDLG_DEF_OTL:
+ {
+ int I;
+ for (I = 0; I < lengthof(DefMsgDlgItems); I++)
+ {
+ if (LOWORD(wParam) == DefMsgDlgItems[I].DlgItem)
+ {
+ MsgTree->SetDefMsg(DefMsgDlgItems[I].Status, MsgTree->GetSelection()->ID); // PSM_CHANGED is sent here through MTN_DEFMSGCHANGED, so we don't need to send it once more
+ break;
+ }
+ }
+ } break;
+ case IDC_MESSAGEDLG_VARS:
+ {
+ my_variables_showhelp(hwndDlg, IDC_MESSAGEDLG_MSGDATA);
+ } break;
+ case IDC_MESSAGEDLG_DEL:
+ {
+ MsgTree->EnsureVisible(MsgTree->GetSelection()->hItem);
+ MsgTree->DeleteSelectedItem();
+ } break;
+ case IDC_MESSAGEDLG_NEWCAT:
+ {
+ MsgTree->AddCategory();
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGEDLG_MSGTITLE));
+ } break;
+ case IDC_MESSAGEDLG_NEWMSG:
+ {
+ MsgTree->AddMessage();
+ SetFocus(GetDlgItem(hwndDlg, IDC_MESSAGEDLG_MSGTITLE));
+ } break;
+
+ //NightFox:
+ case IDC_LNK_AUTOAWAY:
+ {
+ OPENOPTIONSDIALOG ood = {0};
+ ood.cbSize = sizeof(ood);
+ ood.pszPage = "Status";
+ ood.pszTab = "Autoreply";
+ //CallService( MS_OPT_OPENOPTIONS, 0, (LPARAM)&ood );
+ CallService( MS_OPT_OPENOPTIONSPAGE, 0, (LPARAM)&ood );
+ break;
+ }
+
+ }
+
+
+ } break;
+ case EN_CHANGE:
+ {
+ if (LOWORD(wParam) == IDC_MESSAGEDLG_MSGDATA || LOWORD(wParam) == IDC_MESSAGEDLG_MSGTITLE)
+ {
+ if (!ChangeLock)
+ {
+ if (LOWORD(wParam) == IDC_MESSAGEDLG_MSGTITLE)
+ {
+ CBaseTreeItem* TreeItem = MsgTree->GetSelection();
+ if (TreeItem && !(TreeItem->Flags & TIF_ROOTITEM))
+ {
+ GetDlgItemText(hwndDlg, IDC_MESSAGEDLG_MSGTITLE, TreeItem->Title.GetBuffer(TREEITEMTITLE_MAXLEN), TREEITEMTITLE_MAXLEN);
+ TreeItem->Title.ReleaseBuffer();
+ ChangeLock++;
+ MsgTree->UpdateItem(TreeItem->ID);
+ ChangeLock--;
+ }
+ }
+ MsgTree->SetModified(true);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, (WPARAM)hwndDlg, 0);
+ }
+ }
+ } break;
+ }
+ } break;
+ case WM_DESTROY:
+ {
+ delete MsgTree;
+ MsgTree = NULL;
+ g_MessagesOptPage.SetWnd(NULL);
+ } break;
+ }
+ return 0;
+}
+
+
+
+// ================================================ Contact list ================================================
+// Based on the code from built-in Miranda ignore module
+
+#define UM_CONTACTSDLG_RESETLISTOPTIONS (WM_USER + 20)
+
+#define EXTRACOLUMNSCOUNT 3
+#define IGNORECOLUMN 2
+#define AUTOREPLYCOLUMN 1
+#define NOTIFYCOLUMN 0
+
+#define EXTRAICON_DOT 0
+#define EXTRAICON_IGNORE 1
+#define EXTRAICON_AUTOREPLYON 2
+#define EXTRAICON_AUTOREPLYOFF 3
+//#define EXTRAICON_ENABLENOTIFY 4
+//#define EXTRAICON_DISABLENOTIFY 5
+//#define EXTRAICON_INDEFINITE 6
+#define EXTRAICON_INDEFINITE 4
+
+#define VAL_INDEFINITE (-2)
+
+static WNDPROC g_OrigContactsProc;
+
+__inline int DBValueToIgnoreIcon(int Value)
+{
+ switch (Value)
+ {
+ case VAL_INDEFINITE: return EXTRAICON_INDEFINITE;
+ case 0: return EXTRAICON_DOT;
+ default: return EXTRAICON_IGNORE;
+ }
+}
+
+__inline int IgnoreIconToDBValue(int Value)
+{
+ switch (Value)
+ {
+ case EXTRAICON_DOT: return 0;
+ case EXTRAICON_IGNORE: return 1;
+ default: return VAL_INDEFINITE; // EXTRAICON_INDEFINITE and 0xFF
+ }
+}
+
+__inline int DBValueToOptReplyIcon(int Value)
+{
+ switch (Value)
+ {
+ case VAL_INDEFINITE: return EXTRAICON_INDEFINITE;
+ case VAL_USEDEFAULT: return EXTRAICON_DOT;
+ case 0: return EXTRAICON_AUTOREPLYOFF;
+ default: return EXTRAICON_AUTOREPLYON;
+ }
+}
+
+__inline int ReplyIconToDBValue(int Value)
+{
+ switch (Value)
+ {
+ case EXTRAICON_DOT: return VAL_USEDEFAULT;
+ case EXTRAICON_AUTOREPLYOFF: return 0;
+ case EXTRAICON_AUTOREPLYON: return 1;
+ default: return VAL_INDEFINITE; // EXTRAICON_INDEFINITE and 0xFF
+ }
+}
+/*
+__inline int DBValueToNotifyIcon(int Value)
+{
+ switch (Value)
+ {
+ case VAL_INDEFINITE: return EXTRAICON_INDEFINITE;
+ case VAL_USEDEFAULT: return EXTRAICON_DOT;
+ case 0: return EXTRAICON_DISABLENOTIFY;
+ default: return EXTRAICON_ENABLENOTIFY;
+ }
+}
+
+__inline int NotifyIconToDBValue(int Value)
+{
+ switch (Value)
+ {
+ case EXTRAICON_DOT: return VAL_USEDEFAULT;
+ case EXTRAICON_DISABLENOTIFY: return 0;
+ case EXTRAICON_ENABLENOTIFY: return 1;
+ default: return VAL_INDEFINITE; // EXTRAICON_INDEFINITE and 0xFF
+ }
+}*/
+
+static void SetListGroupIcons(HWND hwndList, HANDLE hFirstItem, HANDLE hParentItem)
+{
+ int Icons[EXTRACOLUMNSCOUNT] = {0xFF, 0xFF, 0xFF};
+ int I;
+ HANDLE hItem;
+ int FirstItemType = SendMessage(hwndList, CLM_GETITEMTYPE, (WPARAM)hFirstItem, 0);
+ hItem = (FirstItemType == CLCIT_GROUP) ? hFirstItem : (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hFirstItem);
+ while (hItem)
+ {
+ HANDLE hChildItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
+ if (hChildItem)
+ {
+ SetListGroupIcons(hwndList, hChildItem, hItem);
+ }
+ for (I = 0; I < lengthof(Icons); I++)
+ {
+ int Icon = SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(I, 0));
+ if (Icons[I] == 0xFF)
+ {
+ Icons[I] = Icon;
+ } else if (Icon != 0xFF && Icons[I] != Icon)
+ {
+ Icons[I] = EXTRAICON_INDEFINITE;
+ }
+ }
+ hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hItem);
+ }
+ hItem = (FirstItemType == CLCIT_CONTACT) ? hFirstItem : (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hFirstItem);
+ while (hItem)
+ {
+ for (I = 0; I < lengthof(Icons); I++)
+ {
+ int Icon = SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(I, 0));
+ if (Icons[I] == 0xFF)
+ {
+ Icons[I] = Icon;
+ } else if (Icon != 0xFF && Icons[I] != Icon)
+ {
+ Icons[I] = EXTRAICON_INDEFINITE;
+ }
+ }
+ hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hItem);
+ }
+// set icons
+ for (I = 0; I < lengthof(Icons); I++)
+ {
+ SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hParentItem, MAKELPARAM(I, Icons[I]));
+ }
+}
+
+static void SetAllChildIcons(HWND hwndList, HANDLE hFirstItem, int iColumn, int iImage)
+{
+ int typeOfFirst, iOldIcon;
+ HANDLE hItem, hChildItem;
+ typeOfFirst = SendMessage(hwndList, CLM_GETITEMTYPE, (WPARAM)hFirstItem, 0);
+ //check groups
+ if (typeOfFirst == CLCIT_GROUP)
+ {
+ hItem = hFirstItem;
+ } else
+ {
+ hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hFirstItem);
+ }
+ while (hItem)
+ {
+ hChildItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
+ if (hChildItem)
+ {
+ SetAllChildIcons(hwndList, hChildItem, iColumn, iImage);
+ }
+ hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hItem);
+ }
+ //check contacts
+ if (typeOfFirst == CLCIT_CONTACT)
+ {
+ hItem = hFirstItem;
+ } else
+ {
+ hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hFirstItem);
+ }
+ while (hItem)
+ {
+ iOldIcon = SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, iColumn);
+ if (iOldIcon != 0xFF && iOldIcon != iImage)
+ {
+ SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage));
+ }
+ hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hItem);
+ }
+}
+
+static void SetIconsForColumn(HWND hwndList, HANDLE hItem, HANDLE hItemAll, int iColumn, int iImage)
+{
+ int itemType = SendMessage(hwndList, CLM_GETITEMTYPE, (WPARAM)hItem, 0);
+ switch (itemType)
+ {
+ case CLCIT_CONTACT:
+ {
+ int oldiImage = SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, iColumn);
+ if (oldiImage != 0xFF && oldiImage != iImage)
+ {
+ SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage));
+ }
+ } break;
+ case CLCIT_INFO:
+ {
+ if (hItem == hItemAll)
+ {
+ SetAllChildIcons(hwndList, hItem, iColumn, iImage);
+ } else
+ {
+// _ASSERT(hItem == hItemUnknown);
+ SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage));
+ }
+ } break;
+ case CLCIT_GROUP:
+ {
+ hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem);
+ if (hItem)
+ {
+ SetAllChildIcons(hwndList, hItem, iColumn, iImage);
+ }
+ } break;
+ }
+}
+
+static void SaveItemState(HWND hwndList, HANDLE hContact, HANDLE hItem)
+{ // hContact == INVALID_HANDLE_VALUE means that hItem is hItemUnknown
+ int Ignore = IgnoreIconToDBValue(SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(IGNORECOLUMN, 0)));
+ int Reply = ReplyIconToDBValue(SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(AUTOREPLYCOLUMN, 0)));
+// int Notify = NotifyIconToDBValue(SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(NOTIFYCOLUMN, 0)));
+ if (Ignore != VAL_INDEFINITE)
+ {
+ CContactSettings(ID_STATUS_ONLINE, hContact).Ignore = Ignore;
+ }
+ if (Reply != VAL_INDEFINITE)
+ {
+ CContactSettings(ID_STATUS_ONLINE, hContact).Autoreply = Reply;
+ }
+/* if (Notify != VAL_INDEFINITE)
+ {
+ CContactSettings(ID_STATUS_ONLINE, hContact).PopupNotify = Notify;
+ }*/
+ if (hContact != INVALID_HANDLE_VALUE && g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS))
+ {
+ int iMode;
+ for (iMode = ID_STATUS_AWAY; iMode < ID_STATUS_OUTTOLUNCH; iMode++)
+ {
+ if (Ignore != VAL_INDEFINITE)
+ {
+ CContactSettings(iMode, hContact).Ignore = Ignore;
+ }
+ if (Reply != VAL_INDEFINITE)
+ {
+ CContactSettings(iMode, hContact).Autoreply = Reply;
+ } // Notify is not per-status, so we're not setting it here
+ }
+ }
+}
+
+static void SetAllContactIcons(HWND hwndList, HANDLE hItemUnknown)
+{
+ HANDLE hContact, hItem;
+ char *szProto;
+// set values for hItemUnknown first
+ SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItemUnknown, MAKELPARAM(IGNORECOLUMN, DBValueToIgnoreIcon(CContactSettings(ID_STATUS_ONLINE, INVALID_HANDLE_VALUE).Ignore)));
+ SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItemUnknown, MAKELPARAM(AUTOREPLYCOLUMN, DBValueToOptReplyIcon(CContactSettings(ID_STATUS_ONLINE, INVALID_HANDLE_VALUE).Autoreply)));
+// SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItemUnknown, MAKELPARAM(NOTIFYCOLUMN, DBValueToNotifyIcon(CContactSettings(ID_STATUS_ONLINE, INVALID_HANDLE_VALUE).PopupNotify)));
+
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ do
+ {
+ hItem = (HANDLE)SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0);
+ if (hItem)// && SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(IGNOREEVENT_MAX, 0)) == 0xFF)
+ {
+ szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ int Ignore = CContactSettings(ID_STATUS_ONLINE, hContact).Ignore;
+ int Reply = CContactSettings(ID_STATUS_ONLINE, hContact).Autoreply;
+// int Notify = CContactSettings(ID_STATUS_ONLINE, hContact).PopupNotify;
+ if (g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS))
+ {
+ int iMode;
+ for (iMode = ID_STATUS_AWAY; iMode < ID_STATUS_OUTTOLUNCH; iMode++)
+ {
+ if (CContactSettings(iMode, hContact).Ignore != Ignore)
+ {
+ Ignore = VAL_INDEFINITE;
+ }
+ if (CContactSettings(iMode, hContact).Autoreply != Reply)
+ {
+ Reply = VAL_INDEFINITE;
+ } // Notify is not per-status, so we're not checking it here
+ }
+ }
+ SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(IGNORECOLUMN, DBValueToIgnoreIcon(Ignore)));
+ SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(AUTOREPLYCOLUMN, DBValueToOptReplyIcon(Reply)));
+// SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(NOTIFYCOLUMN, (szProto && IsAnICQProto(szProto)) ? DBValueToNotifyIcon(Notify) : 0xFF));
+ }
+ } while (hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0));
+}
+
+static LRESULT CALLBACK ContactsSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (Msg)
+ {
+ case WM_LBUTTONDBLCLK:
+ {
+ DWORD hitFlags;
+ HANDLE hItem = (HANDLE)SendMessage(hWnd, CLM_HITTEST, (WPARAM)&hitFlags, lParam);
+ if (hItem && (hitFlags & CLCHT_ONITEMEXTRA))
+ {
+ Msg = WM_LBUTTONDOWN; // may be considered as a hack, but it's needed to make clicking on extra icons more convenient
+ }
+ } break;
+ }
+ return CallWindowProc(g_OrigContactsProc, hWnd, Msg, wParam, lParam);
+}
+
+int CALLBACK ContactsOptDlg(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HANDLE hItemAll, hItemUnknown;
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ MySetPos(hwndDlg);
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_CONTACTSDLG_LIST);
+ HIMAGELIST hIml;
+ hIml = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), (IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR8) | ILC_MASK, 5, 2);
+ ImageList_AddIcon(hIml, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_DOT)));
+ ImageList_AddIcon(hIml, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_IGNORE)));
+ ImageList_AddIcon(hIml, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SOE_ENABLED)));
+ ImageList_AddIcon(hIml, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SOE_DISABLED)));
+ //ImageList_AddIcon(hIml, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ENABLENOTIFY)));
+ //ImageList_AddIcon(hIml, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_DISABLENOTIFY)));
+ ImageList_AddIcon(hIml, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_INDEFINITE)));
+ SendMessage(hwndList, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hIml);
+ SendMessage(hwndDlg, UM_CONTACTSDLG_RESETLISTOPTIONS, 0, 0);
+ SendMessage(hwndList, CLM_SETEXTRACOLUMNS, EXTRACOLUMNSCOUNT, 0);
+ CLCINFOITEM cii={0};
+ cii.cbSize = sizeof(cii);
+ cii.flags = CLCIIF_GROUPFONT;
+ cii.pszText = TranslateT("** All contacts **");
+ hItemAll = (HANDLE)SendMessage(hwndList, CLM_ADDINFOITEM, 0, (LPARAM)&cii);
+ cii.pszText = TranslateT("** Not-on-list contacts **"); // == Unknown contacts
+ hItemUnknown = (HANDLE)SendMessage(hwndList, CLM_ADDINFOITEM, 0, (LPARAM)&cii);
+ HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ do
+ {
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (szProto)
+ {
+ int Flag1 = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+ if ((Flag1 & PF1_IM) != PF1_IM && !(Flag1 & PF1_INDIVMODEMSG))
+ { // does contact's protocol supports message sending/receiving or individual status messages?
+ SendMessage(hwndList, CLM_DELETEITEM, SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0), 0);
+ }
+ }
+ } while (hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0));
+ SetAllContactIcons(hwndList, hItemUnknown);
+ SetListGroupIcons(hwndList, (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll);
+ g_OrigContactsProc = (WNDPROC)SetWindowLongPtr(hwndList, GWLP_WNDPROC, (LONG_PTR)ContactsSubclassProc);
+ } break;
+ case UM_CONTACTSDLG_RESETLISTOPTIONS:
+ {
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_CONTACTSDLG_LIST);
+ SendMessage(hwndList, CLM_SETBKBITMAP, 0, NULL);
+ SendMessage(hwndList, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0);
+ SendMessage(hwndList, CLM_SETGREYOUTFLAGS, 0, 0);
+ SendMessage(hwndList, CLM_SETLEFTMARGIN, 4, 0);
+ SendMessage(hwndList, CLM_SETINDENT, 10, 0);
+ SendMessage(hwndList, CLM_SETHIDEEMPTYGROUPS, 1, 0);
+ int I;
+ for (I = 0; I <= FONTID_MAX; I++)
+ {
+ SendMessage(hwndList, CLM_SETTEXTCOLOR, I, GetSysColor(COLOR_WINDOWTEXT));
+ }
+ } break;
+ case WM_SETFOCUS:
+ {
+ SetFocus(GetDlgItem(hwndDlg, IDC_CONTACTSDLG_LIST));
+ } break;
+ case WM_NOTIFY:
+ {
+ switch (((LPNMHDR)lParam)->idFrom)
+ {
+ case IDC_CONTACTSDLG_LIST:
+ {
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case CLN_NEWCONTACT:
+ case CLN_LISTREBUILT:
+ {
+ SetAllContactIcons(GetDlgItem(hwndDlg, IDC_CONTACTSDLG_LIST), hItemUnknown);
+ } // fall through
+ case CLN_CONTACTMOVED:
+ {
+ SetListGroupIcons(GetDlgItem(hwndDlg, IDC_CONTACTSDLG_LIST), (HANDLE)SendDlgItemMessage(hwndDlg, IDC_CONTACTSDLG_LIST, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll);
+ } break;
+ case CLN_OPTIONSCHANGED:
+ {
+ SendMessage(hwndDlg, UM_CONTACTSDLG_RESETLISTOPTIONS, 0, 0);
+ } break;
+ case NM_CLICK:
+ case NM_DBLCLK:
+ {
+ NMCLISTCONTROL *nm = (NMCLISTCONTROL*)lParam;
+ HWND hwndList = GetDlgItem(hwndDlg, IDC_CONTACTSDLG_LIST);
+ HANDLE hItem;
+ DWORD hitFlags;
+ if (nm->iColumn == -1)
+ {
+ break;
+ }
+ hItem = (HANDLE)SendMessage(hwndList, CLM_HITTEST, (WPARAM)&hitFlags, MAKELPARAM(nm->pt.x, nm->pt.y));
+ if (!hItem || !(hitFlags & CLCHT_ONITEMEXTRA))
+ {
+ break;
+ }
+ int iImage = SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn, 0));
+ switch (nm->iColumn)
+ {
+ case AUTOREPLYCOLUMN:
+ {
+ switch (iImage)
+ {
+ case EXTRAICON_DOT: iImage = EXTRAICON_AUTOREPLYOFF; break;
+ case EXTRAICON_AUTOREPLYOFF: iImage = EXTRAICON_AUTOREPLYON; break;
+ default: iImage = EXTRAICON_DOT; // EXTRAICON_AUTOREPLYON and EXTRAICON_INDEFINITE
+ }
+ } break;
+ case IGNORECOLUMN:
+ {
+ iImage = (iImage == EXTRAICON_DOT) ? EXTRAICON_IGNORE : EXTRAICON_DOT;
+ } break;
+ /*case NOTIFYCOLUMN:
+ {
+ switch (iImage)
+ {
+ case EXTRAICON_DOT: iImage = EXTRAICON_DISABLENOTIFY; break;
+ case EXTRAICON_DISABLENOTIFY: iImage = EXTRAICON_ENABLENOTIFY; break;
+ default: iImage = EXTRAICON_DOT; // EXTRAICON_ENABLENOTIFY and EXTRAICON_INDEFINITE
+ }
+ }*/ break;
+ }
+ SetIconsForColumn(hwndList, hItem, hItemAll, nm->iColumn, iImage);
+ SetListGroupIcons(hwndList, (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ } break;
+ }
+ } break;
+ case 0:
+ {
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case PSN_APPLY:
+ {
+ HANDLE hContact, hItem;
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ do
+ {
+ hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_CONTACTSDLG_LIST, CLM_FINDCONTACT, (WPARAM)hContact, 0);
+ if (hItem)
+ {
+ SaveItemState(GetDlgItem(hwndDlg, IDC_CONTACTSDLG_LIST), hContact, hItem);
+ }
+ } while (hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0));
+// SaveItemMask(GetDlgItem(hwndDlg, IDC_CONTACTSDLG_LIST), NULL, hItemAll, "Default1"); // TODO: store All Contacts setting here too, - change global Notify and Autoreply settings? (& set the All Contacts icons to "?" initially if the global setting doesn't coincide with the setting calculated in the _current_ way); and also make sure that these settings will be refreshed in the other windows too
+ SaveItemState(GetDlgItem(hwndDlg, IDC_CONTACTSDLG_LIST), INVALID_HANDLE_VALUE, hItemUnknown);
+ return true;
+ } break;
+ }
+ } break;
+ }
+ } break;
+ case WM_DESTROY:
+ {
+ HIMAGELIST hIml = (HIMAGELIST)SendDlgItemMessage(hwndDlg, IDC_CONTACTSDLG_LIST, CLM_GETEXTRAIMAGELIST, 0, 0);
+ _ASSERT(hIml);
+ ImageList_Destroy(hIml);
+ } break;
+ }
+ return 0;
+}
+
+
+int OptsDlgInit(WPARAM wParam, LPARAM lParam)
+{
+ OPTIONSDIALOGPAGE optDi = {0};
+ optDi.cbSize = sizeof(optDi);
+ optDi.position = 920000000;
+ optDi.hInstance = g_hInstance;
+ optDi.flags = ODPF_BOLDGROUPS | ODPF_TCHAR;
+/*
+ optDi.ptszTitle = OPT_TITLE;
+ optDi.pfnDlgProc = PopupOptDlg;
+ optDi.pszTemplate = MAKEINTRESOURCEA(IDD_POPUPOPTDLG);
+ optDi.ptszGroup = OPT_POPUPGROUP;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&optDi);
+*/
+// optDi.ptszTitle = OPT_TITLE;
+ optDi.ptszTitle = OPT_MAINGROUP;
+// optDi.ptszGroup = OPT_MAINGROUP;
+
+ optDi.pfnDlgProc = MessagesOptDlg;
+ optDi.pszTemplate = MAKEINTRESOURCEA(IDD_MESSAGES);
+ optDi.ptszTab = LPGENT("Statuses messages");
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&optDi);
+
+ optDi.pfnDlgProc = MoreOptDlg;
+ optDi.pszTemplate = MAKEINTRESOURCEA(IDD_MOREOPTDIALOG);
+ optDi.ptszTab = LPGENT("Main options");
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&optDi);
+
+ optDi.pfnDlgProc = AutoreplyOptDlg;
+ optDi.pszTemplate = MAKEINTRESOURCEA(IDD_AUTOREPLY);
+ optDi.ptszTab = LPGENT("Autoreply");
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&optDi);
+
+ optDi.pfnDlgProc = ContactsOptDlg;
+ optDi.pszTemplate = MAKEINTRESOURCEA(IDD_CONTACTSOPTDLG);
+ optDi.ptszTab = LPGENT("Contacts");
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&optDi);
+ return 0;
+}
+
+
+COptPage g_SetAwayMsgPage(MOD_NAME, NULL);
+COptPage g_MsgTreePage(MOD_NAME, NULL);
+
+void InitOptions()
+{
+ InitThemes();
+ /*g_PopupOptPage.Items.AddElem(new COptItem_Checkbox(IDC_POPUPOPTDLG_USEPOPUPS, DB_POPUPNOTIFY, DBVT_BYTE, POPUP_DEF_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Edit(IDC_POPUPOPTDLG_POPUPFORMAT, "PopupsFormat", AWAY_MSGDATA_MAX, POPUP_DEF_POPUP_FORMAT, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Generic(IDC_POPUPOPTDLG_POPUPPREVIEW, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Generic(IDC_POPUPOPTDLG_VARS, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Generic(IDC_POPUPOPTDLG_STATIC_EXTRATEXT, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Combobox(IDC_POPUPOPTDLG_LCLICK_ACTION, "PopupLClickAction", DBVT_BYTE, POPUP_DEF_LCLICKACTION, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Combobox(IDC_POPUPOPTDLG_RCLICK_ACTION, "PopupRClickAction", DBVT_BYTE, POPUP_DEF_RCLICKACTION, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Generic(IDC_POPUPOPTDLG_STATIC_LCLICK, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Generic(IDC_POPUPOPTDLG_STATIC_RCLICK, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Colourpicker(IDC_POPUPOPTDLG_BGCOLOUR, "PopupBGColour", POPUP_DEF_POPUP_BGCOLOUR, IDC_POPUPOPTDLG_DEFBGCOLOUR));
+ g_PopupOptPage.Items.AddElem(new COptItem_Colourpicker(IDC_POPUPOPTDLG_TEXTCOLOUR, "PopupTextColour", POPUP_DEF_POPUP_TEXTCOLOUR, IDC_POPUPOPTDLG_DEFTEXTCOLOUR));
+ g_PopupOptPage.Items.AddElem(new COptItem_Checkbox(IDC_POPUPOPTDLG_DEFBGCOLOUR, "UseDefBGColour", DBVT_BYTE, POPUP_DEF_USEDEFBGCOLOUR, 0, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Checkbox(IDC_POPUPOPTDLG_DEFTEXTCOLOUR, "UseDefTextColour", DBVT_BYTE, POPUP_DEF_USEDEFTEXTCOLOUR, 0, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Generic(IDC_POPUPOPTDLG_STATIC_BGCOLOUR, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Generic(IDC_POPUPOPTDLG_STATIC_TEXTCOLOUR, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Checkbox(IDC_POPUPOPTDLG_ONLNOTIFY, "PopupNotify", DBVT_DWORD, POPUP_DEF_POPUPNOTIFYFLAGS, SF_ONL, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Checkbox(IDC_POPUPOPTDLG_AWAYNOTIFY, "PopupNotify", DBVT_DWORD, POPUP_DEF_POPUPNOTIFYFLAGS, SF_AWAY, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Checkbox(IDC_POPUPOPTDLG_NANOTIFY, "PopupNotify", DBVT_DWORD, POPUP_DEF_POPUPNOTIFYFLAGS, SF_NA, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Checkbox(IDC_POPUPOPTDLG_OCCNOTIFY, "PopupNotify", DBVT_DWORD, POPUP_DEF_POPUPNOTIFYFLAGS, SF_OCC, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Checkbox(IDC_POPUPOPTDLG_DNDNOTIFY, "PopupNotify", DBVT_DWORD, POPUP_DEF_POPUPNOTIFYFLAGS, SF_DND, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Checkbox(IDC_POPUPOPTDLG_FFCNOTIFY, "PopupNotify", DBVT_DWORD, POPUP_DEF_POPUPNOTIFYFLAGS, SF_FFC, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Checkbox(IDC_POPUPOPTDLG_OTHERNOTIFY, "PopupNotify", DBVT_DWORD, POPUP_DEF_POPUPNOTIFYFLAGS, SF_OTHER, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_IntEdit(IDC_POPUPOPTDLG_POPUPDELAY, "PopupDelay", DBVT_WORD, true, POPUP_DEF_POPUPDELAY, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Generic(IDC_POPUPOPTDLG_STATIC_SEC, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Generic(IDC_POPUPOPTDLG_STATIC_DEFAULT, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Generic(IDC_POPUPOPTDLG_STATIC_INFINITE, IDC_POPUPOPTDLG_USEPOPUPS));
+ g_PopupOptPage.Items.AddElem(new COptItem_Checkbox(IDC_POPUPOPTDLG_LOGONLYWITHPOPUP, "LogOnlyWithPopup", DBVT_BYTE, 0));*/
+
+ g_MessagesOptPage.Items.AddElem(new COptItem_Generic(IDC_MESSAGEDLG_VARS, IDC_MESSAGEDLG_MSGTREE));
+ g_MessagesOptPage.Items.AddElem(new COptItem_Generic(IDC_MESSAGEDLG_DEL));
+ g_MessagesOptPage.Items.AddElem(new COptItem_Generic(IDC_MESSAGEDLG_MSGTITLE));
+ g_MessagesOptPage.Items.AddElem(new COptItem_Generic(IDC_MESSAGEDLG_MSGDATA));
+ g_MessagesOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MESSAGEDLG_DEF_ONL, NULL, DBVT_BYTE, 0, 0, IDC_MESSAGEDLG_MSGTREE));
+ g_MessagesOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MESSAGEDLG_DEF_AWAY, NULL, DBVT_BYTE, 0, 0, IDC_MESSAGEDLG_MSGTREE));
+ g_MessagesOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MESSAGEDLG_DEF_NA, NULL, DBVT_BYTE, 0, 0, IDC_MESSAGEDLG_MSGTREE));
+ g_MessagesOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MESSAGEDLG_DEF_OCC, NULL, DBVT_BYTE, 0, 0, IDC_MESSAGEDLG_MSGTREE));
+ g_MessagesOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MESSAGEDLG_DEF_DND, NULL, DBVT_BYTE, 0, 0, IDC_MESSAGEDLG_MSGTREE));
+ g_MessagesOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MESSAGEDLG_DEF_FFC, NULL, DBVT_BYTE, 0, 0, IDC_MESSAGEDLG_MSGTREE));
+ g_MessagesOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MESSAGEDLG_DEF_INV, NULL, DBVT_BYTE, 0, 0, IDC_MESSAGEDLG_MSGTREE));
+ g_MessagesOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MESSAGEDLG_DEF_OTP, NULL, DBVT_BYTE, 0, 0, IDC_MESSAGEDLG_MSGTREE));
+ g_MessagesOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MESSAGEDLG_DEF_OTL, NULL, DBVT_BYTE, 0, 0, IDC_MESSAGEDLG_MSGTREE));
+ TreeItemArray DefMsgTree;
+ int ParentID1;
+ int ID = 0;
+ TreeRootItemArray RootItems;
+ RootItems.AddElem(CTreeRootItem(TranslateT("Predefined messages"), g_Messages_PredefinedRootID = ID++, TIF_EXPANDED));
+ RootItems.AddElem(CTreeRootItem(TranslateT("Recent messages"), g_Messages_RecentRootID = ID++, TIF_EXPANDED));
+ DefMsgTree.AddElem(CTreeItem(TranslateT("Gone fragging"), g_Messages_PredefinedRootID, ID++, 0, TranslateTS(_T("Been fragging since %") _T(VAR_AWAYSINCE_TIME) _T("%, I'll msg you later when the adrenaline wears off."))));
+ DefMsgTree.AddElem(CTreeItem(TranslateT("Creepy"), g_Messages_PredefinedRootID, ID++, 0, TranslateT("Your master, %nas_mynick%, has been %nas_statdesc% since the day that is only known as ?nas_awaysince_date(dddd)... When he gets back, I'll tell him you dropped by...")));
+ DefMsgTree.AddElem(CTreeItem(TranslateT("Default messages"), g_Messages_PredefinedRootID, ParentID1 = ID++, TIF_GROUP | TIF_EXPANDED));
+ g_MsgTreePage.Items.AddElem(new COptItem_IntDBSetting(IDS_MESSAGEDLG_DEF_ONL, StatusToDBSetting(ID_STATUS_ONLINE, MESSAGES_DB_MSGTREEDEF), DBVT_WORD, false, ID));
+ DefMsgTree.AddElem(CTreeItem(TranslateT("Online"), ParentID1, ID++, 0, TranslateT("Yep, I'm here.")));
+ g_MsgTreePage.Items.AddElem(new COptItem_IntDBSetting(IDS_MESSAGEDLG_DEF_AWAY, StatusToDBSetting(ID_STATUS_AWAY, MESSAGES_DB_MSGTREEDEF), DBVT_WORD, false, ID));
+ DefMsgTree.AddElem(CTreeItem(TranslateT("Away"), ParentID1, ID++, 0, TranslateT("Been gone since %nas_awaysince_time%, will be back later.")));
+ g_MsgTreePage.Items.AddElem(new COptItem_IntDBSetting(IDS_MESSAGEDLG_DEF_NA, StatusToDBSetting(ID_STATUS_NA, MESSAGES_DB_MSGTREEDEF), DBVT_WORD, false, ID));
+ DefMsgTree.AddElem(CTreeItem(TranslateT("NA"), ParentID1, ID++, 0, TranslateT("Give it up, I'm not in!")));
+ g_MsgTreePage.Items.AddElem(new COptItem_IntDBSetting(IDS_MESSAGEDLG_DEF_OCC, StatusToDBSetting(ID_STATUS_OCCUPIED, MESSAGES_DB_MSGTREEDEF), DBVT_WORD, false, ID));
+ DefMsgTree.AddElem(CTreeItem(TranslateT("Occupied"), ParentID1, ID++, 0, TranslateT("Not right now.")));
+ g_MsgTreePage.Items.AddElem(new COptItem_IntDBSetting(IDS_MESSAGEDLG_DEF_DND, StatusToDBSetting(ID_STATUS_DND, MESSAGES_DB_MSGTREEDEF), DBVT_WORD, false, ID));
+ DefMsgTree.AddElem(CTreeItem(TranslateT("DND"), ParentID1, ID++, 0, TranslateT("Give a guy some peace, would ya?")));
+ g_MsgTreePage.Items.AddElem(new COptItem_IntDBSetting(IDS_MESSAGEDLG_DEF_FFC, StatusToDBSetting(ID_STATUS_FREECHAT, MESSAGES_DB_MSGTREEDEF), DBVT_WORD, false, ID));
+ DefMsgTree.AddElem(CTreeItem(TranslateT("Free for chat"), ParentID1, ID++, 0, TranslateT("I'm a chatbot!")));
+ g_MsgTreePage.Items.AddElem(new COptItem_IntDBSetting(IDS_MESSAGEDLG_DEF_INV, StatusToDBSetting(ID_STATUS_INVISIBLE, MESSAGES_DB_MSGTREEDEF), DBVT_WORD, false, ID));
+ DefMsgTree.AddElem(CTreeItem(TranslateT("Invisible"), ParentID1, ID++, 0, TranslateT("I'm hiding from the mafia.")));
+ g_MsgTreePage.Items.AddElem(new COptItem_IntDBSetting(IDS_MESSAGEDLG_DEF_OTP, StatusToDBSetting(ID_STATUS_ONTHEPHONE, MESSAGES_DB_MSGTREEDEF), DBVT_WORD, false, ID));
+ DefMsgTree.AddElem(CTreeItem(TranslateT("On the phone"), ParentID1, ID++, 0, TranslateT("I've been on the phone since %nas_awaysince_time%, give me a sec!")));
+ g_MsgTreePage.Items.AddElem(new COptItem_IntDBSetting(IDS_MESSAGEDLG_DEF_OTL, StatusToDBSetting(ID_STATUS_OUTTOLUNCH, MESSAGES_DB_MSGTREEDEF), DBVT_WORD, false, ID));
+ DefMsgTree.AddElem(CTreeItem(TranslateT("Out to lunch"), ParentID1, ID++, 0, TranslateT("Been having ?ifgreater(?ctime(H),2,?ifgreater(?ctime(H),10,?ifgreater(?ctime(H),16,supper,dinner),breakfast),supper) since %nas_awaysince_time%.")));
+ g_MsgTreePage.Items.AddElem(new COptItem_TreeCtrl(IDV_MSGTREE, "MsgTree", DefMsgTree, RootItems, 0, "Text"));
+
+ g_SetAwayMsgPage.Items.AddElem(new COptItem_BitDBSetting(IDS_SAWAYMSG_SHOWMSGTREE, "SAMDlgFlags", DBVT_BYTE, DF_SAM_DEFDLGFLAGS, DF_SAM_SHOWMSGTREE));
+ g_SetAwayMsgPage.Items.AddElem(new COptItem_BitDBSetting(IDS_SAWAYMSG_SHOWCONTACTTREE, "SAMDlgFlags", DBVT_BYTE, DF_SAM_DEFDLGFLAGS, DF_SAM_SHOWCONTACTTREE));
+ g_SetAwayMsgPage.Items.AddElem(new COptItem_BitDBSetting(IDS_SAWAYMSG_AUTOSAVEDLGSETTINGS, "AutoSaveDlgSettings", DBVT_BYTE, 1));
+ g_SetAwayMsgPage.Items.AddElem(new COptItem_BitDBSetting(IDS_SAWAYMSG_DISABLEVARIABLES, "DisableVariables", DBVT_BYTE, 0));
+
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_PERSTATUSMRM, "PerStatusMRM", DBVT_BYTE, 0));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_RESETPROTOMSGS, "ResetProtoMsgs", DBVT_BYTE, 1));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_PERSTATUSPROTOMSGS, "PerStatusProtoMsgs", DBVT_BYTE, 0));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_PERSTATUSPROTOSETTINGS, "PerStatusProtoSettings", DBVT_BYTE, 0));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_SAVEPERSONALMSGS, "SavePersonalMsgs", DBVT_BYTE, 1));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_PERSTATUSPERSONAL, "PerStatusPersonal", DBVT_BYTE, 0));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS, "PerStatusPersonalSettings", DBVT_BYTE, 0));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_USEMENUITEM, "UseMenuItem", DBVT_BYTE, 0));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_MYNICKPERPROTO, "MyNickPerProto", DBVT_BYTE, 1));
+ g_MoreOptPage.Items.AddElem(new COptItem_IntEdit(IDC_MOREOPTDLG_WAITFORMSG, "WaitForMsg", DBVT_WORD, TRUE, 5));
+ g_MoreOptPage.Items.AddElem(new COptItem_IntEdit(IDC_MOREOPTDLG_RECENTMSGSCOUNT, "MRMCount", DBVT_WORD, TRUE, 5));
+ g_MoreOptPage.Items.AddElem(new COptItem_Radiobutton(IDC_MOREOPTDLG_USEDEFMSG, "UseByDefault", DBVT_BYTE, MOREOPTDLG_DEF_USEBYDEFAULT, 0));
+ g_MoreOptPage.Items.AddElem(new COptItem_Radiobutton(IDC_MOREOPTDLG_USELASTMSG, "UseByDefault", DBVT_BYTE, MOREOPTDLG_DEF_USEBYDEFAULT, 1));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_UPDATEMSGS, "UpdateMsgs", DBVT_BYTE, 0));
+ g_MoreOptPage.Items.AddElem(new COptItem_IntEdit(IDC_MOREOPTDLG_UPDATEMSGSPERIOD, "UpdateMsgsPeriod", DBVT_WORD, FALSE, 300));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_DONTPOPDLG_ONL, "DontPopDlg", DBVT_WORD, MOREOPTDLG_DEF_DONTPOPDLG, SF_ONL));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_DONTPOPDLG_AWAY, "DontPopDlg", DBVT_WORD, MOREOPTDLG_DEF_DONTPOPDLG, SF_AWAY));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_DONTPOPDLG_NA, "DontPopDlg", DBVT_WORD, MOREOPTDLG_DEF_DONTPOPDLG, SF_NA));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_DONTPOPDLG_OCC, "DontPopDlg", DBVT_WORD, MOREOPTDLG_DEF_DONTPOPDLG, SF_OCC));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_DONTPOPDLG_DND, "DontPopDlg", DBVT_WORD, MOREOPTDLG_DEF_DONTPOPDLG, SF_DND));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_DONTPOPDLG_FFC, "DontPopDlg", DBVT_WORD, MOREOPTDLG_DEF_DONTPOPDLG, SF_FFC));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_DONTPOPDLG_INV, "DontPopDlg", DBVT_WORD, MOREOPTDLG_DEF_DONTPOPDLG, SF_INV));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_DONTPOPDLG_OTP, "DontPopDlg", DBVT_WORD, MOREOPTDLG_DEF_DONTPOPDLG, SF_OTP));
+ g_MoreOptPage.Items.AddElem(new COptItem_Checkbox(IDC_MOREOPTDLG_DONTPOPDLG_OTL, "DontPopDlg", DBVT_WORD, MOREOPTDLG_DEF_DONTPOPDLG, SF_OTL));
+
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_ENABLEREPLY, DB_ENABLEREPLY, DBVT_BYTE, AUTOREPLY_DEF_REPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Generic(IDC_REPLYDLG_STATIC_ONEVENT, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_EVENTMSG, "ReplyOnEvent", DBVT_BYTE, AUTOREPLY_DEF_REPLYONEVENT, EF_MSG, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_EVENTURL, "ReplyOnEvent", DBVT_BYTE, AUTOREPLY_DEF_REPLYONEVENT, EF_URL, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_EVENTFILE, "ReplyOnEvent", DBVT_BYTE, AUTOREPLY_DEF_REPLYONEVENT, EF_FILE, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_DONTSENDTOICQ, "DontSendToICQ", DBVT_BYTE, 0, 0, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_DONTREPLYINVISIBLE, "DontReplyInvisible", DBVT_BYTE, 1, 0, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_LOGREPLY, "LogReply", DBVT_BYTE, 1, 0, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_ONLYIDLEREPLY, "OnlyIdleReply", DBVT_BYTE, 0, 0, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_ONLYCLOSEDDLGREPLY, "OnlyClosedDlgReply", DBVT_BYTE, 1, 0, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Generic(IDC_REPLYDLG_STATIC_SEND, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_IntEdit(IDC_REPLYDLG_SENDCOUNT, "ReplyCount", DBVT_WORD, TRUE, -1, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Generic(IDC_REPLYDLG_STATIC_TIMES, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_RESETCOUNTERWHENSAMEICON, "ResetReplyCounterWhenSameIcon", DBVT_BYTE, 1, 0, IDC_REPLYDLG_SENDCOUNT));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Generic(IDC_REPLYDLG_STATIC_DISABLEWHENSTATUS, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_DISABLE_ONL, "DisableReply", DBVT_WORD, AUTOREPLY_DEF_DISABLEREPLY, SF_ONL, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_DISABLE_AWAY, "DisableReply", DBVT_WORD, AUTOREPLY_DEF_DISABLEREPLY, SF_AWAY, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_DISABLE_NA, "DisableReply", DBVT_WORD, AUTOREPLY_DEF_DISABLEREPLY, SF_NA, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_DISABLE_OCC, "DisableReply", DBVT_WORD, AUTOREPLY_DEF_DISABLEREPLY, SF_OCC, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_DISABLE_DND, "DisableReply", DBVT_WORD, AUTOREPLY_DEF_DISABLEREPLY, SF_DND, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_DISABLE_FFC, "DisableReply", DBVT_WORD, AUTOREPLY_DEF_DISABLEREPLY, SF_FFC, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_DISABLE_INV, "DisableReply", DBVT_WORD, AUTOREPLY_DEF_DISABLEREPLY, SF_INV, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_DISABLE_OTP, "DisableReply", DBVT_WORD, AUTOREPLY_DEF_DISABLEREPLY, SF_OTP, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Checkbox(IDC_REPLYDLG_DISABLE_OTL, "DisableReply", DBVT_WORD, AUTOREPLY_DEF_DISABLEREPLY, SF_OTL, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Generic(IDC_REPLYDLG_STATIC_FORMAT, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Edit(IDC_REPLYDLG_PREFIX, "ReplyPrefix", AWAY_MSGDATA_MAX, AUTOREPLY_DEF_PREFIX, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Generic(IDC_REPLYDLG_VARS, IDC_REPLYDLG_ENABLEREPLY));
+ g_AutoreplyOptPage.Items.AddElem(new COptItem_Generic(IDC_REPLYDLG_STATIC_EXTRATEXT, IDC_REPLYDLG_ENABLEREPLY));
+}
+
+//NightFox
+int ModernOptInitialise(WPARAM wParam, LPARAM lParam)
+{
+ static int iBoldControls[] =
+ {
+ IDC_TXT_TITLE1,
+ IDC_TXT_TITLE2,
+ IDC_TXT_TITLE3,
+ MODERNOPT_CTRL_LAST
+ };
+
+ MODERNOPTOBJECT obj = {0};
+
+ obj.cbSize = sizeof(obj);
+ obj.dwFlags = MODEROPT_FLG_TCHAR|MODEROPT_FLG_NORESIZE;
+ obj.hInstance = g_hInstance;
+ obj.iSection = MODERNOPT_PAGE_STATUS;
+ obj.iType = MODERNOPT_TYPE_SECTIONPAGE;
+ obj.iBoldControls = iBoldControls;
+// obj.lpzClassicGroup = NULL;
+ obj.lpzClassicPage = "Status";
+ obj.lpzClassicTab = "Main options";
+// obj.lpzHelpUrl = "http://wiki.miranda-im.org/";
+
+ obj.lpzTemplate = MAKEINTRESOURCEA(IDD_MODERNOPT_MESSAGES);
+ obj.pfnDlgProc = MessagesModernOptDlg;
+ CallService(MS_MODERNOPT_ADDOBJECT, wParam, (LPARAM)&obj);
+ return 0;
+} \ No newline at end of file
diff --git a/plugins/NewAwaySysMod/AwaySys.cpp b/plugins/NewAwaySysMod/AwaySys.cpp
new file mode 100644
index 0000000000..c335ee1dac
--- /dev/null
+++ b/plugins/NewAwaySysMod/AwaySys.cpp
@@ -0,0 +1,1123 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (c) 2005-2007 Chervov Dmitry
+ Copyright (c) 2004-2005 Iksaif Entertainment
+ Copyright (c) 2002-2003 Goblineye Entertainment
+
+ 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
+*/
+
+/*
+ Thanx to Faith Healer for icons and help, Unregistered for his plugins (variables, AAA :p),
+ mistag for GamerStatus, BigMuscle for his code to use AAA
+ Thanx to Tornado, orignal developer of AwaySys.
+ Please note that some code from the Miranda's original away module (SRAway) is used around
+ AwaySys. I tried to mention it wherever possible, but I might have forgotten a few. Kudos to Miranda's authors.
+ The Read-Away-Msg part was practically copied from Miranda, not proud of it, but since I really can't see how can I make it better, there
+ was no point in rewriting it all.
+*/
+
+#define _DECL_DLLMAIN
+#include <process.h> // needed for MSVC 7 msvcr7*.dll patch
+#include "Common.h"
+#include "m_genmenu.h"
+#include "m_idle.h"
+#include "m_statusplugins.h"
+#include "m_updater.h"
+#include "..\CommonLibs\m_NewAwaySys.h"
+#include "..\CommonLibs\m_ContactSettings.h"
+#include "MsgTree.h"
+#include "ContactList.h"
+#include "Properties.h"
+#include "Path.h"
+#include "Services.h"
+#include "VersionNo.h"
+
+//NightFox
+#include <m_modernopt.h>
+
+HINSTANCE g_hInstance;
+PLUGINLINK *pluginLink;
+TMyArray<HANDLE> hHooks, hServices;
+HANDLE g_hContactMenuItem = NULL, g_hReadStatMenuItem = NULL, /*g_hTopToolbarbutton = NULL, */g_hToggleSOEMenuItem = NULL, g_hToggleSOEContactMenuItem = NULL, g_hAutoreplyOnContactMenuItem = NULL, g_hAutoreplyOffContactMenuItem = NULL, g_hAutoreplyUseDefaultContactMenuItem = NULL;
+bool g_fNoProcessing = false; // tells the status change proc not to do anything
+int g_bIsIdle = false;
+HANDLE hMainThread;
+int g_CSProtoCount = 0; // CommonStatus - StartupStatus and AdvancedAutoAway
+VAR_PARSE_DATA VarParseData;
+int (*g_OldCallService)(const char *, WPARAM, LPARAM) = NULL;
+
+static struct
+{
+ int Status, DisableReplyCtlID, DontShowDialogCtlID;
+} StatusModeList[] = {
+ ID_STATUS_ONLINE, IDC_REPLYDLG_DISABLE_ONL, IDC_MOREOPTDLG_DONTPOPDLG_ONL,
+ ID_STATUS_AWAY, IDC_REPLYDLG_DISABLE_AWAY, IDC_MOREOPTDLG_DONTPOPDLG_AWAY,
+ ID_STATUS_NA, IDC_REPLYDLG_DISABLE_NA, IDC_MOREOPTDLG_DONTPOPDLG_NA,
+ ID_STATUS_OCCUPIED, IDC_REPLYDLG_DISABLE_OCC, IDC_MOREOPTDLG_DONTPOPDLG_OCC,
+ ID_STATUS_DND, IDC_REPLYDLG_DISABLE_DND, IDC_MOREOPTDLG_DONTPOPDLG_DND,
+ ID_STATUS_FREECHAT, IDC_REPLYDLG_DISABLE_FFC, IDC_MOREOPTDLG_DONTPOPDLG_FFC,
+ ID_STATUS_INVISIBLE, IDC_REPLYDLG_DISABLE_INV, IDC_MOREOPTDLG_DONTPOPDLG_INV,
+ ID_STATUS_ONTHEPHONE, IDC_REPLYDLG_DISABLE_OTP, IDC_MOREOPTDLG_DONTPOPDLG_OTP,
+ ID_STATUS_OUTTOLUNCH, IDC_REPLYDLG_DISABLE_OTL, IDC_MOREOPTDLG_DONTPOPDLG_OTL
+};
+
+// took this nice idea from MetaContacts plugin ;)
+// my_make_version is required to break up #define PRODUCTVER from VersionNo.h
+DWORD my_make_version(const int a, const int b, const int c, const int d)
+{
+ return PLUGIN_MAKE_VERSION(a, b, c, d);
+}
+
+PLUGININFOEX pluginInfo = {
+ sizeof(PLUGININFOEX),
+ "New Away System Mod ("
+#ifdef _DEBUG
+ "DEBUG "
+#endif
+#ifdef _UNICODE
+ "Unicode"
+#else
+ "ANSI"
+#endif
+ ")",
+ 0, // see VersionNo.h
+ "New Away System Mod plugin for Miranda IM. Build #"STRSPECIALBUILD" [ "__DATE__" "__TIME__
+#ifdef _DEBUG
+ " DEBUG"
+#endif
+#ifdef _UNICODE
+ " Unicode"
+#else
+ " ANSI"
+#endif
+ " ]",
+ "NightFox; Deathdemon; XF007; Goblineye Entertainment",
+ "NightFox@myied.org",
+ "© 2010 NightFox; © 2005-2007 Chervov Dmitry; © 2004-2005 Iksaif; © 2002-2003 Goblineye Entertainment",
+ "http://MyiEd.org/packs",
+ UNICODE_AWARE,
+ DEFMOD_SRAWAY, // mwawawawa.
+#ifdef _UNICODE
+// {0x75cc4fef, 0xb038, 0x4224, {0xb3, 0x75, 0x7, 0x21, 0xf9, 0x76, 0x18, 0x13}}
+// {75CC4FEF-B038-4224-B375-0721F9761813}
+ {0xb2dd9270, 0xce5e, 0x11df, {0xbd, 0x3d, 0x8, 0x0, 0x20, 0xc, 0x9a, 0x66}}
+// {b2dd9270-ce5d-11df-bd3b-0800200c9a66}
+#else
+// {0x313e808f, 0x7162, 0x4319, {0xae, 0xe, 0xcc, 0xad, 0x4d, 0xe5, 0xeb, 0x71}}
+// {313E808F-7162-4319-AE0E-CCAD4DE5EB71}
+ {0x14254a00, 0xce5e, 0x11df, {0xbd, 0x3d, 0x8, 0x0, 0x20, 0xc, 0x9a, 0x66}}
+// {14254a00-ce5e-11df-bd3b-0800200c9a66}
+
+#endif
+};
+
+PLUGININFO oldPluginInfo = {
+ sizeof(PLUGININFO),
+ pluginInfo.shortName,
+ pluginInfo.version,
+ pluginInfo.description,
+ pluginInfo.author,
+ pluginInfo.authorEmail,
+ pluginInfo.copyright,
+ pluginInfo.homepage,
+ pluginInfo.flags,
+ pluginInfo.replacesDefaultModule
+};
+
+BOOL WINAPI MyDllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ g_hInstance = hinstDLL;
+// have to call _CRT_INIT here, and redefine DLL entry point to MyDllMain because of
+// msvcr71.dll's __CppXcptFilter function dependency, which is not present in msvcrt.dll
+ return _CRT_INIT(hinstDLL, fdwReason, lpvReserved);
+}
+
+static const MUUID interfaces[] = {MIID_SRAWAY, MIID_LAST}; // TODO: add MIID_WHOISREADING here if there'll be any some time in future..
+extern "C" __declspec(dllexport) const MUUID *MirandaPluginInterfaces(void)
+{
+ return interfaces;
+}
+
+extern "C" __declspec(dllexport) PLUGININFOEX *MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ pluginInfo.version = my_make_version(PRODUCTVER);
+ return &pluginInfo;
+}
+
+extern "C" __declspec(dllexport) PLUGININFO *MirandaPluginInfo(DWORD mirandaVersion)
+{
+ oldPluginInfo.version = my_make_version(PRODUCTVER);
+ return &oldPluginInfo;
+}
+
+//NightFox
+int ModernOptInitialise(WPARAM wParam,LPARAM lParam);
+
+TCString GetDynamicStatMsg(HANDLE hContact, char *szProto, DWORD UIN, int iStatus)
+{
+// hContact is the contact that requests the status message
+ if (hContact != INVALID_HANDLE_VALUE)
+ {
+ VarParseData.Message = CContactSettings(iStatus, hContact).GetMsgFormat(GMF_ANYCURRENT, NULL, szProto);
+ } else
+ { // contact is unknown
+ VarParseData.Message = CProtoSettings(szProto, iStatus).GetMsgFormat(iStatus ? GMF_LASTORDEFAULT : GMF_ANYCURRENT);
+ }
+ TCString sTime;
+ VarParseData.szProto = szProto ? szProto : ((hContact && hContact != INVALID_HANDLE_VALUE) ? (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0) : NULL);
+ VarParseData.UIN = UIN;
+ VarParseData.Flags = 0;
+ if (ServiceExists(MS_VARS_FORMATSTRING) && !g_SetAwayMsgPage.GetDBValueCopy(IDS_SAWAYMSG_DISABLEVARIABLES))
+ {
+ FORMATINFO fi = {0};
+ fi.cbSize = sizeof(fi);
+ fi.tszFormat = VarParseData.Message;
+ fi.hContact = hContact;
+ fi.flags = FIF_TCHAR;
+ TCHAR *szResult = (TCHAR*)CallService(MS_VARS_FORMATSTRING, (WPARAM)&fi, 0);
+ if (szResult)
+ {
+ VarParseData.Message = szResult;
+ CallService(MS_VARS_FREEMEMORY, (WPARAM)szResult, 0);
+ }
+ }
+ return VarParseData.Message = VarParseData.Message.Left(AWAY_MSGDATA_MAX);
+}
+
+
+int StatusMsgReq(WPARAM wParam, LPARAM lParam, CString &szProto)
+{
+ _ASSERT(szProto != NULL);
+ LogMessage("ME_ICQ_STATUSMSGREQ called. szProto=%s, Status=%d, UIN=%d", (char*)szProto, wParam, lParam);
+// find the contact
+ char *szFoundProto;
+ HANDLE hFoundContact = NULL; // if we'll find the contact only on some other protocol, but not on szProto, then we'll use that hContact.
+ HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact)
+ {
+ char *szCurProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (DBGetContactSettingDword(hContact, szCurProto, "UIN", 0) == lParam)
+ {
+ szFoundProto = szCurProto;
+ hFoundContact = hContact;
+ if (!strcmp(szCurProto, szProto))
+ {
+ break;
+ }
+ }
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
+ }
+ int iMode = ICQStatusToGeneralStatus(wParam);
+ if (!hFoundContact)
+ {
+ hFoundContact = INVALID_HANDLE_VALUE;
+ } else if (iMode >= ID_STATUS_ONLINE && iMode <= ID_STATUS_OUTTOLUNCH)
+ { // don't count xstatus requests
+ DBWriteContactSettingWord(hFoundContact, MOD_NAME, DB_REQUESTCOUNT, DBGetContactSettingWord(hFoundContact, MOD_NAME, DB_REQUESTCOUNT, 0) + 1);
+ }
+ HANDLE hContactForSettings = hFoundContact; // used to take into account not-on-list contacts when getting contact settings, but at the same time allows to get correct contact info for contacts that are in the DB
+ if (hContactForSettings != INVALID_HANDLE_VALUE && DBGetContactSettingByte(hContactForSettings, "CList", "NotOnList", 0))
+ {
+ hContactForSettings = INVALID_HANDLE_VALUE; // INVALID_HANDLE_VALUE means the contact is not-on-list
+ }
+ if (g_SetAwayMsgPage.GetWnd())
+ {
+ CallAllowedPS_SETAWAYMSG(szProto, iMode, NULL); // we can set status messages to NULL here, as they'll be changed again when the SAM dialog closes.
+ return 0;
+ }
+ if (CContactSettings(iMode, hContactForSettings).Ignore)
+ {
+ CallAllowedPS_SETAWAYMSG(szProto, iMode, ""); // currently NULL makes ICQ to ignore _any_ further status message requests until the next PS_SETAWAYMSG, so I can't use it here..
+ return 0; // move along, sir
+ }
+
+ if (iMode)
+ { // if it's not an xstatus message request
+ CallAllowedPS_SETAWAYMSG(szProto, iMode, (char*)TCHAR2ANSI(GetDynamicStatMsg(hFoundContact, szProto, lParam)));
+ }
+// COptPage PopupNotifyData(g_PopupOptPage);
+// PopupNotifyData.DBToMem();
+ VarParseData.szProto = szProto;
+ VarParseData.UIN = lParam;
+ VarParseData.Flags = 0;
+ if (!iMode)
+ {
+ VarParseData.Flags |= VPF_XSTATUS;
+ }
+/*
+ int ShowPopup = ((iMode == ID_STATUS_ONLINE && PopupNotifyData.GetValue(IDC_POPUPOPTDLG_ONLNOTIFY)) ||
+ (iMode == ID_STATUS_AWAY && PopupNotifyData.GetValue(IDC_POPUPOPTDLG_AWAYNOTIFY)) ||
+ (iMode == ID_STATUS_DND && PopupNotifyData.GetValue(IDC_POPUPOPTDLG_DNDNOTIFY)) ||
+ (iMode == ID_STATUS_NA && PopupNotifyData.GetValue(IDC_POPUPOPTDLG_NANOTIFY)) ||
+ (iMode == ID_STATUS_OCCUPIED && PopupNotifyData.GetValue(IDC_POPUPOPTDLG_OCCNOTIFY)) ||
+ (iMode == ID_STATUS_FREECHAT && PopupNotifyData.GetValue(IDC_POPUPOPTDLG_FFCNOTIFY)) ||
+ (!iMode && PopupNotifyData.GetValue(IDC_POPUPOPTDLG_OTHERNOTIFY))) &&
+ CContactSettings(iMode, hContactForSettings).PopupNotify.IncludingParents();
+
+// Show popup and play a sound
+ if (ShowPopup)
+ {
+ ShowPopup = ShowPopupNotification(PopupNotifyData, hFoundContact, iMode); // we need ShowPopup also to determine whether to log to file or not
+ }
+*/
+// Log status message request to a file
+// if (!PopupNotifyData.GetValue(IDC_POPUPOPTDLG_LOGONLYWITHPOPUP) || ShowPopup)
+// {
+ TCString LogMsg;
+ if (!iMode)
+ { // if it's an xstatus message request
+ LogMsg = DBGetContactSettingString(NULL, szProto, "XStatusName", _T(""));
+ TCString XMsg(DBGetContactSettingString(NULL, szProto, "XStatusMsg", _T("")));
+ if (XMsg.GetLen())
+ {
+ if (LogMsg.GetLen())
+ {
+ LogMsg += _T("\r\n");
+ }
+ LogMsg += XMsg;
+ }
+ } else
+ {
+ LogMsg = VarParseData.Message;
+ }
+ if (ServiceExists(MS_VARS_FORMATSTRING))
+ {
+ logservice_log(LOG_ID, hFoundContact, LogMsg);
+ } else
+ {
+ TCString szUIN;
+ _ultot(lParam, szUIN.GetBuffer(16), 10);
+ szUIN.ReleaseBuffer();
+ TCHAR *szStatDesc = iMode ? (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, iMode, 0) : STR_XSTATUSDESC;
+ if (!szStatDesc)
+ {
+ _ASSERT(0);
+ szStatDesc = _T("");
+ }
+ logservice_log(LOG_ID, hFoundContact, TCString((TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hFoundContact, GCDNF_TCHAR)) + _T(" (") + szUIN + TranslateT(") read your ") + szStatDesc + TranslateT(" message:\r\n") + LogMsg);
+ }
+// }
+ return 0;
+}
+
+// Here is an ugly workaround to support multiple ICQ accounts
+// hope 5 icq accounts will be sufficient for everyone ;)
+#define MAXICQACCOUNTS 5
+CString ICQProtoList[MAXICQACCOUNTS];
+#define StatusMsgReqN(N) int StatusMsgReq##N(WPARAM wParam, LPARAM lParam) {return StatusMsgReq(wParam, lParam, ICQProtoList[N - 1]);}
+StatusMsgReqN(1) StatusMsgReqN(2) StatusMsgReqN(3) StatusMsgReqN(4) StatusMsgReqN(5)
+MIRANDAHOOK StatusMsgReqHooks[] = {StatusMsgReq1, StatusMsgReq2, StatusMsgReq3, StatusMsgReq4, StatusMsgReq5};
+
+int IsAnICQProto(char *szProto)
+{
+ int I;
+ for (I = 0; I < MAXICQACCOUNTS; I++)
+ {
+ if (ICQProtoList[I] == (const char*)szProto)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+int StatusChanged(WPARAM wParam, LPARAM lParam)
+{
+// wParam = iMode
+// lParam = (char*)szProto
+ LogMessage("MS_CLIST_SETSTATUSMODE called. szProto=%s, Status=%d", lParam ? (char*)lParam : "NULL", wParam);
+ g_ProtoStates[(char*)lParam].Status = wParam;
+// let's check if we handle this thingy
+ if (g_fNoProcessing) // we're told not to do anything
+ {
+ g_fNoProcessing = false; // take it off
+ return 0;
+ }
+ DWORD Flag1 = 0;
+ DWORD Flag3 = 0;
+ if (lParam)
+ {
+ Flag1 = CallProtoService((char*)lParam, PS_GETCAPS, PFLAGNUM_1, 0);
+ Flag3 = CallProtoService((char*)lParam, PS_GETCAPS, PFLAGNUM_3, 0);
+ } else
+ {
+ PROTOCOLDESCRIPTOR **proto;
+ int iProtoCount = 0;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&iProtoCount, (LPARAM)&proto);
+ int I;
+ for (I = 0; I < iProtoCount; I++)
+ {
+ if (proto[I]->type == PROTOTYPE_PROTOCOL)
+ {
+ Flag1 |= CallProtoService(proto[I]->szName, PS_GETCAPS, PFLAGNUM_1, 0);
+ Flag3 |= CallProtoService(proto[I]->szName, PS_GETCAPS, PFLAGNUM_3, 0);
+ }
+ }
+ }
+ if (!(Flag1 & PF1_MODEMSGSEND || Flag3 & Proto_Status2Flag(wParam) || (Flag1 & PF1_IM) == PF1_IM))
+ {
+ return 0; // there are no protocols with changed status that support autoreply or away messages for this status
+ }
+ if (g_SetAwayMsgPage.GetWnd())
+ {
+ SetForegroundWindow(g_SetAwayMsgPage.GetWnd());
+ return 0;
+ }
+ int I;
+ for (I = lengthof(StatusModeList) - 1; I >= 0; I--)
+ {
+ if (wParam == StatusModeList[I].Status)
+ {
+ break;
+ }
+ }
+ if (I < 0)
+ {
+ return 0;
+ }
+ BOOL bScreenSaverRunning;
+ SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &bScreenSaverRunning, 0);
+ if (bScreenSaverRunning || g_MoreOptPage.GetDBValueCopy(StatusModeList[I].DontShowDialogCtlID))
+ {
+ CProtoSettings((char*)lParam).SetMsgFormat(SMF_PERSONAL, CProtoSettings((char*)lParam).GetMsgFormat(GMF_LASTORDEFAULT));
+ ChangeProtoMessages((char*)lParam, wParam, TCString());
+ } else
+ {
+ SetAwayMsgData *dat = new SetAwayMsgData;
+ ZeroMemory(dat, sizeof(SetAwayMsgData));
+ dat->szProtocol = (char*)lParam;
+ dat->IsModeless = false;
+ DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_SETAWAYMSG), NULL, SetAwayMsgDlgProc, (LPARAM)dat);
+ }
+ return 0;
+}
+
+
+#define ID_STATUS_LAST 40081 // yes, 40081 means internal CommonStatus' ID_STATUS_LAST here, not ID_STATUS_IDLE :-S
+#define ID_STATUS_CURRENT 40082
+#define ID_STATUS_DISABLED 41083
+int CSStatusChange(WPARAM wParam, LPARAM lParam) // CommonStatus plugins (StartupStatus and AdvancedAutoAway)
+{
+// wParam = PROTOCOLSETTINGEX** protoSettings
+ PROTOCOLSETTINGEX** ps = *(PROTOCOLSETTINGEX***)wParam;
+ if (!ps)
+ {
+ return -1;
+ }
+ LogMessage("ME_CS_STATUSCHANGEEX event:");
+ int I;
+ for (I = 0; I < g_CSProtoCount; I++)
+ {
+ LogMessage("%d: cbSize=%d, szProto=%s, status=%d, lastStatus=%d, szMsg:", I + 1, ps[I]->cbSize, ps[I]->szName ? (char*)ps[I]->szName : "NULL", ps[I]->status, ps[I]->lastStatus, ps[I]->szMsg ? ps[I]->szMsg : "NULL");
+ if (ps[I]->status != ID_STATUS_DISABLED)
+ {
+ if (ps[I]->status != ID_STATUS_CURRENT)
+ {
+ g_ProtoStates[ps[I]->szName].Status = (ps[I]->status == ID_STATUS_LAST) ? ps[I]->lastStatus : ps[I]->status;
+ }
+ CProtoSettings(ps[I]->szName).SetMsgFormat(SMF_TEMPORARY, ps[I]->szMsg ? ANSI2TCHAR(ps[I]->szMsg) : CProtoSettings(ps[I]->szName).GetMsgFormat(GMF_LASTORDEFAULT));
+ }
+ }
+ return 0;
+}
+
+
+static int IdleChangeEvent(WPARAM wParam, LPARAM lParam)
+{
+ LogMessage("ME_IDLE_CHANGED event. lParam=0x%x", lParam); // yes, we don't do anything with status message changes on idle.. there seems to be no any good solution for the wrong status message issue :(
+ g_bIsIdle = lParam & IDF_ISIDLE;
+ return 0;
+}
+
+
+int CSModuleLoaded(WPARAM wParam, LPARAM lParam) // StartupStatus and AdvancedAutoAway
+{
+// wParam = ProtoCount
+ g_CSProtoCount = wParam;
+ return 0;
+}
+
+
+int PreBuildContactMenu(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)wParam;
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ CLISTMENUITEM miSetMsg = {0};
+ miSetMsg.cbSize = sizeof(miSetMsg);
+ miSetMsg.flags = CMIM_FLAGS | CMIF_TCHAR | CMIF_HIDDEN;
+ CLISTMENUITEM miReadMsg = {0};
+ miReadMsg.cbSize = sizeof(miReadMsg);
+ miReadMsg.flags = CMIM_FLAGS | CMIF_TCHAR | CMIF_HIDDEN;
+ int iMode = szProto ? CallProtoService(szProto, PS_GETSTATUS, 0, 0) : 0;
+ int Flag1 = szProto ? CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) : 0;
+ int iContactMode = DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE);
+ TCHAR szSetStr[256], szReadStr[256];
+ if (szProto)
+ {
+ int I;
+ for (I = lengthof(StatusModeList) - 1; I >= 0; I--)
+ {
+ if (iMode == StatusModeList[I].Status)
+ {
+ break;
+ }
+ }
+ if ((Flag1 & PF1_MODEMSGSEND && CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_3, 0) & Proto_Status2Flag(iMode)) || ((Flag1 & PF1_IM) == PF1_IM && (I < 0 || !g_AutoreplyOptPage.GetDBValueCopy(StatusModeList[I].DisableReplyCtlID))))
+ { // the protocol supports status message sending for current status, or autoreplying
+ _stprintf(szSetStr, TranslateT("Set %s message for the contact"), CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, iMode, GCMDF_TCHAR), CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR));
+ miSetMsg.ptszName = szSetStr;
+ miSetMsg.flags = CMIM_FLAGS | CMIF_TCHAR | CMIM_NAME;
+ }
+ if (Flag1 & PF1_MODEMSGRECV && CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_3, 0) & Proto_Status2Flag(iContactMode))
+ { // the protocol supports status message reading for contact's status
+ _stprintf(szReadStr, TranslateT("Re&ad %s Message"), CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, iContactMode, GCMDF_TCHAR));
+ miReadMsg.ptszName = szReadStr;
+ miReadMsg.flags = CMIM_FLAGS | CMIF_TCHAR | CMIM_NAME | CMIM_ICON;
+ miReadMsg.hIcon = LoadSkinnedProtoIcon(szProto, iContactMode);
+ }
+ }
+ if (g_hContactMenuItem)
+ {
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)g_hContactMenuItem, (LPARAM)&miSetMsg);
+
+ if ((Flag1 & PF1_IM) == PF1_IM)
+ { // if this contact supports sending/receiving messages
+ int iAutoreply = CContactSettings(g_ProtoStates[szProto].Status, hContact).Autoreply;
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_ICON | CMIM_FLAGS | CMIF_TCHAR;
+ switch (iAutoreply)
+ {
+ case VAL_USEDEFAULT: mi.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_DOT)); break;
+ case 0: mi.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SOE_DISABLED)); break;
+ default: iAutoreply = 1; mi.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SOE_ENABLED)); break;
+ }
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)g_hToggleSOEContactMenuItem, (LPARAM)&mi);
+ mi.flags = CMIM_FLAGS | CMIF_TCHAR | (iAutoreply == 1 ? CMIF_CHECKED : 0);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)g_hAutoreplyOnContactMenuItem, (LPARAM)&mi);
+ mi.flags = CMIM_FLAGS | CMIF_TCHAR | (iAutoreply == 0 ? CMIF_CHECKED : 0);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)g_hAutoreplyOffContactMenuItem, (LPARAM)&mi);
+ mi.flags = CMIM_FLAGS | CMIF_TCHAR | (iAutoreply == VAL_USEDEFAULT ? CMIF_CHECKED : 0);
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)g_hAutoreplyUseDefaultContactMenuItem, (LPARAM)&mi);
+ } else
+ { // hide the Autoreply menu item
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIM_FLAGS | CMIF_TCHAR | CMIF_HIDDEN;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)g_hToggleSOEContactMenuItem, (LPARAM)&mi);
+ }
+ }
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)g_hReadStatMenuItem, (LPARAM)&miReadMsg);
+ return 0;
+}
+
+
+static int SetContactStatMsg(WPARAM wParam, LPARAM lParam)
+{
+ if (g_SetAwayMsgPage.GetWnd()) // already setting something
+ {
+ SetForegroundWindow(g_SetAwayMsgPage.GetWnd());
+ return 0;
+ }
+ SetAwayMsgData *dat = new SetAwayMsgData;
+ ZeroMemory(dat, sizeof(SetAwayMsgData));
+ dat->hInitContact = (HANDLE)wParam;
+ dat->szProtocol = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0);
+ dat->IsModeless = false;
+ DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_SETAWAYMSG), NULL, SetAwayMsgDlgProc, (LPARAM)dat);
+ return 0;
+}
+
+/* //NightFox: deleted used-to-be support
+void UpdateSOEButtons(HANDLE hContact)
+{
+ if (!hContact)
+ {
+ int SendOnEvent = CContactSettings(g_ProtoStates[(char*)NULL].Status).Autoreply;
+ CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)g_hTopToolbarbutton, SendOnEvent ? TTBST_PUSHED : TTBST_RELEASED);
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.position = 1000020000;
+ mi.flags = CMIF_TCHAR | CMIM_NAME | CMIM_ICON; // strange, but CMIF_TCHAR is still necessary even without CMIM_FLAGS
+ mi.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(SendOnEvent ? IDI_SOE_ENABLED : IDI_SOE_DISABLED));
+ mi.ptszName = SendOnEvent ? DISABLE_SOE_COMMAND : ENABLE_SOE_COMMAND;
+ CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)g_hToggleSOEMenuItem, (LPARAM)&mi);
+ }
+ if (g_SetAwayMsgPage.GetWnd())
+ {
+ SendMessage(g_SetAwayMsgPage.GetWnd(), UM_SAM_REPLYSETTINGCHANGED, (WPARAM)hContact, 0);
+ }
+}
+*/
+
+int ToggleSendOnEvent(WPARAM wParam, LPARAM lParam)
+{ // used only for the global setting
+ HANDLE hContact = (HANDLE)wParam;
+ CContactSettings(g_ProtoStates[hContact ? (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0) : (char*)NULL].Status, hContact).Autoreply.Toggle();
+ //UpdateSOEButtons();
+ return 0;
+}
+
+
+int srvAutoreplyOn(WPARAM wParam, LPARAM lParam)
+{ // wParam = hContact
+ HANDLE hContact = (HANDLE)wParam;
+ CContactSettings(g_ProtoStates[(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0)].Status, hContact).Autoreply = 1;
+ //UpdateSOEButtons(hContact);
+ return 0;
+}
+
+
+int srvAutoreplyOff(WPARAM wParam, LPARAM lParam)
+{ // wParam = hContact
+ HANDLE hContact = (HANDLE)wParam;
+ CContactSettings(g_ProtoStates[(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0)].Status, hContact).Autoreply = 0;
+ //UpdateSOEButtons(hContact);
+ return 0;
+}
+
+
+int srvAutoreplyUseDefault(WPARAM wParam, LPARAM lParam)
+{ // wParam = hContact
+ HANDLE hContact = (HANDLE)wParam;
+ CContactSettings(g_ProtoStates[(char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0)].Status, hContact).Autoreply = VAL_USEDEFAULT;
+ //UpdateSOEButtons(hContact);
+ return 0;
+}
+
+/* //NightFox: deleted used-to-be support
+int Create_TopToolbar(WPARAM wParam, LPARAM lParam)
+{
+ int SendOnEvent = CContactSettings(g_ProtoStates[(char*)NULL].Status).Autoreply;
+ if (ServiceExists(MS_TTB_ADDBUTTON))
+ {
+ TTBButton ttbb = {0};
+ ttbb.cbSize = sizeof(ttbb);
+ ttbb.hbBitmapUp = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_SOE_DISABLED));
+ ttbb.hbBitmapDown = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_SOE_ENABLED));
+ ttbb.pszServiceUp = MS_AWAYSYS_AUTOREPLY_TOGGLE;
+ ttbb.pszServiceDown = MS_AWAYSYS_AUTOREPLY_TOGGLE;
+ ttbb.dwFlags = TTBBF_VISIBLE | TTBBF_SHOWTOOLTIP;
+ ttbb.name = Translate("Toggle autoreply on/off");
+ g_hTopToolbarbutton = (HANDLE)CallService(MS_TTB_ADDBUTTON, (WPARAM)&ttbb, 0);
+ CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)g_hTopToolbarbutton, SendOnEvent ? TTBST_PUSHED : TTBST_RELEASED);
+ }
+ return 0;
+}
+*/
+
+static int IconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ g_IconList.ReloadIcons();
+ if (g_MessagesOptPage.GetWnd())
+ {
+ SendMessage(g_MessagesOptPage.GetWnd(), UM_ICONSCHANGED, 0, 0);
+ }
+ if (g_MoreOptPage.GetWnd())
+ {
+ SendMessage(g_MoreOptPage.GetWnd(), UM_ICONSCHANGED, 0, 0);
+ }
+ if (g_AutoreplyOptPage.GetWnd())
+ {
+ SendMessage(g_AutoreplyOptPage.GetWnd(), UM_ICONSCHANGED, 0, 0);
+ }
+/* if (g_PopupOptPage.GetWnd())
+ {
+ SendMessage(g_PopupOptPage.GetWnd(), UM_ICONSCHANGED, 0, 0);
+ }*/
+ return 0;
+}
+
+
+static int ContactSettingsInit(WPARAM wParam, LPARAM lParam)
+{
+ CONTACTSETTINGSINIT *csi = (CONTACTSETTINGSINIT*)wParam;
+ char *szProto = (csi->Type == CSIT_CONTACT) ? (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)csi->hContact, 0) : NULL;
+ if ((csi->Type == CSIT_GROUP) || szProto)
+ {
+ int Flag1 = (csi->Type == CSIT_CONTACT) ? CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) : PF1_IM; // we assume that there can be some contacts in the group with PF1_IM capability
+ if ((Flag1 & PF1_IM) == PF1_IM || Flag1 & PF1_INDIVMODEMSG)
+ { // does contact's protocol supports message sending/receiving or individual status messages?
+ CONTACTSETTINGSCONTROL csc = {0};
+ csc.cbSize = sizeof(csc);
+ csc.cbStateSize = sizeof(CSCONTROLSTATE);
+ csc.Position = CSPOS_SORTBYALPHABET;
+ csc.ControlType = CSCT_CHECKBOX;
+ csc.szModule = MOD_NAME;
+ csc.StateNum = 3;
+ csc.DefState = 2; // these settings are used for all controls below
+
+ /*if ((csi->Type == CSIT_GROUP) || IsAnICQProto(szProto))
+ {
+ csc.Flags = CSCF_TCHAR;
+ csc.ptszTitle = LPGENT("New Away System: Status message request notifications");
+ csc.ptszGroup = CSGROUP_NOTIFICATIONS;
+ csc.ptszTooltip = NULL;
+ csc.szSetting = DB_POPUPNOTIFY;
+ CallService(MS_CONTACTSETTINGS_ADDCONTROL, wParam, (LPARAM)&csc);
+ }*/
+ int StatusMode = 0;
+ if (csi->Type == CSIT_CONTACT)
+ {
+ CContactSettings CSettings(0, csi->hContact);
+ StatusMode = CSettings.Status;
+ } else
+ {
+ _ASSERT(csi->Type == CSIT_GROUP);
+ StatusMode = g_ProtoStates[(char*)NULL].Status;
+ }
+ if (StatusMode == ID_STATUS_OFFLINE)
+ {
+ StatusMode = ID_STATUS_AWAY;
+ }
+ CString Setting;
+ TCHAR Title[128];
+ csc.Flags = CSCF_TCHAR | CSCF_DONT_TRANSLATE_STRINGS; // these Flags and ptszGroup are used for both controls below
+ csc.ptszGroup = TranslateT("New Away System");
+
+ if (g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS))
+ {
+ _stprintf(Title, TranslateT("Enable autoreply when you are %s"), (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, StatusMode, GCMDF_TCHAR));
+ csc.ptszTitle = Title;
+ csc.ptszTooltip = TranslateT("\"Store contact autoreply/ignore settings for each status separately\" is enabled, so this setting is per-contact AND per-status.");
+ } else
+ {
+ csc.ptszTitle = TranslateT("Enable autoreply");
+ csc.ptszTooltip = NULL;
+ }
+ Setting = StatusToDBSetting(StatusMode, DB_ENABLEREPLY, IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS);
+ csc.szSetting = Setting;
+ CallService(MS_CONTACTSETTINGS_ADDCONTROL, wParam, (LPARAM)&csc);
+
+ if (g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS))
+ {
+ _stprintf(Title, TranslateT("Don't send status message when you are %s"), (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, StatusMode, GCMDF_TCHAR));
+ csc.ptszTitle = Title;
+ csc.ptszTooltip = TranslateT("Ignore status message requests from this contact and don't send an autoreply.\r\n\"Store contact autoreply/ignore settings for each status separately\" is enabled, so this setting is per-contact AND per-status.");
+ } else
+ {
+ csc.ptszTitle = TranslateT("Don't send status message");
+ csc.ptszTooltip = TranslateT("Ignore status message requests from this contact and don't send an autoreply");
+ }
+ Setting = StatusToDBSetting(StatusMode, DB_IGNOREREQUESTS, IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS);
+ csc.szSetting = Setting;
+ CallService(MS_CONTACTSETTINGS_ADDCONTROL, wParam, (LPARAM)&csc);
+ }
+ }
+ return 0;
+}
+
+
+int srvVariablesHandler(WPARAM wParam, LPARAM lParam)
+{
+ ARGUMENTSINFO *ai = (ARGUMENTSINFO*)lParam;
+ ai->flags = AIF_DONTPARSE;
+ TCString Result;
+ if (!lstrcmp(ai->targv[0], _T(VAR_AWAYSINCE_TIME)))
+ {
+ GetTimeFormat(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), 0, g_ProtoStates[VarParseData.szProto].AwaySince, (ai->argc > 1 && *ai->targv[1]) ? ai->targv[1] : _T("H:mm"), Result.GetBuffer(256), 256);
+ Result.ReleaseBuffer();
+ } else if (!lstrcmp(ai->targv[0], _T(VAR_AWAYSINCE_DATE)))
+ {
+ GetDateFormat(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), 0, g_ProtoStates[VarParseData.szProto].AwaySince, (ai->argc > 1 && *ai->targv[1]) ? ai->targv[1] : NULL, Result.GetBuffer(256), 256);
+ Result.ReleaseBuffer();
+ } else if (!lstrcmp(ai->targv[0], _T(VAR_STATDESC)))
+ {
+ Result = (VarParseData.Flags & VPF_XSTATUS) ? STR_XSTATUSDESC : (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, g_ProtoStates[VarParseData.szProto].Status, GCMDF_TCHAR);
+ } else if (!lstrcmp(ai->targv[0], _T(VAR_MYNICK)))
+ {
+ if (g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_MYNICKPERPROTO) && VarParseData.szProto)
+ {
+ Result = DBGetContactSettingString(NULL, VarParseData.szProto, "Nick", (TCHAR*)NULL);
+ }
+ if (Result == NULL)
+ {
+ Result = (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, NULL, GCDNF_TCHAR);
+ }
+ if (Result == NULL)
+ {
+ Result = TranslateT("Stranger");
+ }
+ } else if (!lstrcmp(ai->targv[0], _T(VAR_REQUESTCOUNT)))
+ {
+ _stprintf(Result.GetBuffer(16), _T("%d"), DBGetContactSettingWord(ai->fi->hContact, MOD_NAME, DB_REQUESTCOUNT, 0));
+ Result.ReleaseBuffer();
+ } else if (!lstrcmp(ai->targv[0], _T(VAR_MESSAGENUM)))
+ {
+ _stprintf(Result.GetBuffer(16), _T("%d"), DBGetContactSettingWord(ai->fi->hContact, MOD_NAME, DB_MESSAGECOUNT, 0));
+ Result.ReleaseBuffer();
+ } else if (!lstrcmp(ai->targv[0], _T(VAR_TIMEPASSED)))
+ {
+ ULARGE_INTEGER ul_AwaySince, ul_Now;
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ SystemTimeToFileTime(&st, (LPFILETIME)&ul_Now);
+ SystemTimeToFileTime(g_ProtoStates[VarParseData.szProto].AwaySince, (LPFILETIME)&ul_AwaySince);
+ ul_Now.QuadPart -= ul_AwaySince.QuadPart;
+ ul_Now.QuadPart /= 10000000; // now it's in seconds
+ Result.GetBuffer(256);
+ if (ul_Now.LowPart >= 7200) // more than 2 hours
+ {
+ _stprintf(Result, TranslateT("%d hours"), ul_Now.LowPart / 3600);
+ } else if (ul_Now.LowPart >= 120) // more than 2 minutes
+ {
+ _stprintf(Result, TranslateT("%d minutes"), ul_Now.LowPart / 60);
+ } else
+ {
+ _stprintf(Result, TranslateT("%d seconds"), ul_Now.LowPart);
+ }
+ Result.ReleaseBuffer();
+ } else if (!lstrcmp(ai->targv[0], _T(VAR_PREDEFINEDMESSAGE)))
+ {
+ ai->flags = 0; // reset AIF_DONTPARSE flag
+ if (ai->argc != 2)
+ {
+ return NULL;
+ }
+ COptPage MsgTreeData(g_MsgTreePage);
+ COptItem_TreeCtrl *TreeCtrl = (COptItem_TreeCtrl*)MsgTreeData.Find(IDV_MSGTREE);
+ TreeCtrl->DBToMem(CString(MOD_NAME));
+ int I;
+ for (I = 0; I < TreeCtrl->Value.GetSize(); I++)
+ {
+ if (!(TreeCtrl->Value[I].Flags & TIF_GROUP) && !_tcsicmp(TreeCtrl->Value[I].Title, ai->targv[1]))
+ {
+ Result = TreeCtrl->Value[I].User_Str1;
+ break;
+ }
+ }
+ if (Result == NULL)
+ { // if we didn't find a message with specified title
+ return NULL; // return it now, as later we change NULL to ""
+ }
+ } else if (!lstrcmp(ai->targv[0], _T(VAR_PROTOCOL)))
+ {
+ if (VarParseData.szProto)
+ {
+ CString AnsiResult;
+ CallProtoService(VarParseData.szProto, PS_GETNAME, 256, (LPARAM)AnsiResult.GetBuffer(256));
+ AnsiResult.ReleaseBuffer();
+ Result = ANSI2TCHAR(AnsiResult);
+ }
+ if (Result == NULL)
+ { // if we didn't find a message with specified title
+ return NULL; // return it now, as later we change NULL to ""
+ }
+ }
+ TCHAR *szResult;
+ if (!(szResult = (TCHAR*)malloc((Result.GetLen() + 1) * sizeof(TCHAR))))
+ {
+ return NULL;
+ }
+ _tcscpy(szResult, (Result != NULL) ? Result : _T(""));
+ return (int)szResult;
+}
+
+
+int srvFreeVarMem(WPARAM wParam, LPARAM lParam)
+{
+ if (!lParam)
+ {
+ return -1;
+ }
+ free((void*)lParam);
+ return 0;
+}
+
+
+static int MyCallService(const char *name, WPARAM wParam, LPARAM lParam)
+{
+ if (name && wParam <= ID_STATUS_OUTTOLUNCH && wParam >= ID_STATUS_OFFLINE) // wParam conditions here are distinctive "features" of PS_SETSTATUS and PS_SETAWAYMSG services, so if wParam does not suit them, we'll pass the control to the old CallService function as soon as possible
+ {
+ char *pProtoNameEnd = strrchr(name, '/');
+ if (pProtoNameEnd)
+ {
+ if (!lstrcmpA(pProtoNameEnd, PS_SETSTATUS))
+ {
+ // it's PS_SETSTATUS service; wParam = status; lParam = 0
+ // returns 0 on success, nonzero on failure
+ CString Proto("");
+ Proto.DiffCat(name, pProtoNameEnd);
+ if (wParam != g_ProtoStates[Proto].Status)
+ {
+ g_ProtoStates[Proto].Status = wParam;
+ TCString Msg(CProtoSettings(Proto).GetMsgFormat(GMF_LASTORDEFAULT));
+ LogMessage("Detected a PS_SETSTATUS call with Status different from the one known to NAS. szProto=%s, NewStatus=%d, NewMsg:\n%s", (char*)Proto, wParam, (Msg != NULL) ? TCHAR2ANSI(Msg) : "NULL");
+ CProtoSettings(Proto).SetMsgFormat(SMF_TEMPORARY, Msg);
+ }
+ } else if (!lstrcmpA(pProtoNameEnd, PS_SETAWAYMSG))
+ {
+ // PS_SETAWAYMSG service; wParam = status; lParam = (const char*)szMessage
+ // returns 0 on success, nonzero on failure
+ CString Proto("");
+ Proto.DiffCat(name, pProtoNameEnd);
+ LogMessage("Someone else than NAS called PS_SETAWAYMSG. szProto=%s, Status=%d, Msg:\n%s", (char*)Proto, wParam, lParam ? (char*)lParam : "NULL");
+ CProtoSettings(Proto).SetMsgFormat(SMF_TEMPORARY, lParam ? ((ServiceExists(MS_VARS_FORMATSTRING) && !g_SetAwayMsgPage.GetDBValueCopy(IDS_SAWAYMSG_DISABLEVARIABLES)) ? VariablesEscape(ANSI2TCHAR((char*)lParam)) : ANSI2TCHAR((char*)lParam)) : TCString(_T("")));
+ ChangeProtoMessages(Proto, wParam, TCString());
+ return 0;
+ }
+ }
+ }
+ return g_OldCallService(name, wParam, lParam);
+}
+
+
+int MirandaLoaded(WPARAM wParam, LPARAM lParam)
+{
+ LoadMsgTreeModule();
+ LoadCListModule();
+ InitUpdateMsgs();
+ g_IconList.ReloadIcons();
+
+ PROTOCOLDESCRIPTOR **proto;
+ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hMainThread, THREAD_SET_CONTEXT, false, 0);
+ int iProtoCount = 0;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&iProtoCount, (LPARAM)&proto);
+ int I;
+ int CurProtoIndex;
+ for (I = 0, CurProtoIndex = 0; I < iProtoCount && CurProtoIndex < MAXICQACCOUNTS; I++)
+ {
+ if (proto[I]->type == PROTOTYPE_PROTOCOL)
+ {
+ HANDLE hHook = HookEvent(CString(proto[I]->szName) + ME_ICQ_STATUSMSGREQ, StatusMsgReqHooks[CurProtoIndex]);
+ if (hHook)
+ {
+ hHooks.AddElem(hHook);
+ ICQProtoList[CurProtoIndex] = proto[I]->szName;
+ CurProtoIndex++;
+ }
+ }
+ }
+ hServices.AddElem(CreateServiceFunction(MS_AWAYSYS_SETCONTACTSTATMSG, SetContactStatMsg));
+ hServices.AddElem(CreateServiceFunction(MS_AWAYSYS_AUTOREPLY_TOGGLE, ToggleSendOnEvent));
+ hServices.AddElem(CreateServiceFunction(MS_AWAYSYS_AUTOREPLY_ON, srvAutoreplyOn));
+ hServices.AddElem(CreateServiceFunction(MS_AWAYSYS_AUTOREPLY_OFF, srvAutoreplyOff));
+ hServices.AddElem(CreateServiceFunction(MS_AWAYSYS_AUTOREPLY_USEDEFAULT, srvAutoreplyUseDefault));
+ hServices.AddElem(CreateServiceFunction(MS_NAS_GETSTATEA, GetStateA));
+ hServices.AddElem(CreateServiceFunction(MS_NAS_SETSTATEA, SetStateA));
+ hServices.AddElem(CreateServiceFunction(MS_NAS_GETSTATEW, GetStateW));
+ hServices.AddElem(CreateServiceFunction(MS_NAS_SETSTATEW, SetStateW));
+ hServices.AddElem(CreateServiceFunction(MS_NAS_INVOKESTATUSWINDOW, InvokeStatusWindow));
+ hServices.AddElem(CreateServiceFunction(MS_AWAYMSG_GETSTATUSMSG, GetStatusMsg));
+// and old AwaySysMod service, for compatibility reasons
+ hServices.AddElem(CreateServiceFunction(MS_AWAYSYS_SETSTATUSMODE, SetStatusMode));
+//NightFox: none;
+// hHooks.AddElem(HookEvent(ME_TTB_MODULELOADED, Create_TopToolbar));
+ hHooks.AddElem(HookEvent(ME_OPT_INITIALISE, OptsDlgInit));
+ hHooks.AddElem(HookEvent(ME_CLIST_STATUSMODECHANGE, StatusChanged));
+ hHooks.AddElem(HookEvent(ME_CS_STATUSCHANGEEX, CSStatusChange)); // for compatibility with StartupStatus and AdvancedAutoAway
+ hHooks.AddElem(HookEvent(ME_DB_EVENT_FILTER_ADD, MsgEventAdded));
+ hHooks.AddElem(HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PreBuildContactMenu));
+ hHooks.AddElem(HookEvent(ME_SKIN_ICONSCHANGED, IconsChanged));
+ hHooks.AddElem(HookEvent(ME_IDLE_CHANGED, IdleChangeEvent));
+ hHooks.AddElem(HookEvent(ME_CONTACTSETTINGS_INITIALISE, ContactSettingsInit));
+ g_hReadWndList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0);
+ int SendOnEvent = CContactSettings(g_ProtoStates[(char*)NULL].Status).Autoreply;
+ CLISTMENUITEM mi = {0};
+ mi.cbSize = sizeof(mi);
+ mi.position = 1000020000;
+ mi.flags = CMIF_TCHAR | CMIF_NOTOFFLINE;
+ mi.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(SendOnEvent ? IDI_SOE_ENABLED : IDI_SOE_DISABLED));
+ mi.ptszName = SendOnEvent ? DISABLE_SOE_COMMAND : ENABLE_SOE_COMMAND;
+ mi.pszService = MS_AWAYSYS_AUTOREPLY_TOGGLE;
+ g_hToggleSOEMenuItem = (HANDLE)CallService(MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&mi);
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.position = -2000005000;
+ mi.flags = CMIF_TCHAR | CMIF_NOTOFFLINE | CMIF_HIDDEN;
+ mi.hIcon = NULL;
+ mi.pszContactOwner = NULL;
+ mi.ptszName = LPGENT("Read status message"); // never seen...
+ mi.pszService = MS_AWAYMSG_SHOWAWAYMSG;
+ g_hReadStatMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+ if (g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_USEMENUITEM))
+ {
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIF_TCHAR | CMIF_HIDDEN;
+ mi.ptszName = LPGENT("Set status message"); // will never be shown
+ mi.position = 1000020000;
+ mi.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MSGICON));
+ mi.pszService = MS_AWAYSYS_SETCONTACTSTATMSG;
+ g_hContactMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.flags = CMIF_TCHAR | CMIF_ROOTPOPUP;
+ mi.hIcon = NULL;
+ mi.pszPopupName = (char*)-1;
+ mi.position = 1000020000;
+ mi.ptszName = LPGENT("Autoreply");
+ g_hToggleSOEContactMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+
+ mi.flags = CMIF_TCHAR | CMIF_CHILDPOPUP;
+ mi.pszPopupName = (char*)g_hToggleSOEContactMenuItem;
+ mi.popupPosition = 1000020000;
+ mi.position = 1000020000;
+
+ mi.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SOE_ENABLED));
+ mi.ptszName = LPGENT("On");
+ mi.pszService = MS_AWAYSYS_AUTOREPLY_ON;
+ g_hAutoreplyOnContactMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+ mi.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SOE_DISABLED));
+ mi.ptszName = LPGENT("Off");
+ mi.pszService = MS_AWAYSYS_AUTOREPLY_OFF;
+ g_hAutoreplyOffContactMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+ mi.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_DOT));
+ mi.ptszName = LPGENT("Use the default setting");
+ mi.pszService = MS_AWAYSYS_AUTOREPLY_USEDEFAULT;
+ g_hAutoreplyUseDefaultContactMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM)&mi);
+ }
+ // add that funky thingy (just tweaked a bit, was spotted in Miranda's src code)
+ // we have to read the status message from contacts too... err
+ hServices.AddElem(CreateServiceFunction(MS_AWAYMSG_SHOWAWAYMSG, GetContactStatMsg));
+
+ SkinAddNewSound(AWAYSYS_STATUSMSGREQUEST_SOUND, Translate("NewAwaySys: Incoming status message request"), "");
+ if (ServiceExists(MS_VARS_REGISTERTOKEN))
+ {
+ struct
+ {
+ TCHAR *Name;
+ char *Descr;
+ int Flags;
+ } Variables[] = {
+ _T(VAR_AWAYSINCE_TIME), LPGEN("New Away System\t(x)\tAway since time in default format; ?nas_awaysince_time(x) in format x"), TRF_FIELD | TRF_FUNCTION,
+ _T(VAR_AWAYSINCE_DATE), LPGEN("New Away System\t(x)\tAway since date in default format; ?nas_awaysince_date(x) in format x"), TRF_FIELD | TRF_FUNCTION,
+ _T(VAR_STATDESC), LPGEN("New Away System\tStatus description"), TRF_FIELD | TRF_FUNCTION,
+ _T(VAR_MYNICK), LPGEN("New Away System\tYour nick for current protocol"), TRF_FIELD | TRF_FUNCTION,
+ _T(VAR_REQUESTCOUNT), LPGEN("New Away System\tNumber of status message requests from the contact"), TRF_FIELD | TRF_FUNCTION,
+ _T(VAR_MESSAGENUM), LPGEN("New Away System\tNumber of messages from the contact"), TRF_FIELD | TRF_FUNCTION,
+ _T(VAR_TIMEPASSED), LPGEN("New Away System\tTime passed until request"), TRF_FIELD | TRF_FUNCTION,
+ _T(VAR_PREDEFINEDMESSAGE), LPGEN("New Away System\t(x)\tReturns one of your predefined messages by its title: ?nas_predefinedmessage(creepy)"), TRF_FUNCTION,
+ _T(VAR_PROTOCOL), LPGEN("New Away System\tCurrent protocol name"), TRF_FIELD | TRF_FUNCTION
+ };
+ hServices.AddElem(CreateServiceFunction(MS_AWAYSYS_FREEVARMEM, srvFreeVarMem));
+ hServices.AddElem(CreateServiceFunction(MS_AWAYSYS_VARIABLESHANDLER, srvVariablesHandler));
+ TOKENREGISTER tr = {0};
+ tr.cbSize = sizeof(TOKENREGISTER);
+ tr.szService = MS_AWAYSYS_VARIABLESHANDLER;
+ tr.szCleanupService = MS_AWAYSYS_FREEVARMEM;
+ tr.memType = TR_MEM_OWNER;
+ int I;
+ for (I = 0; I < lengthof(Variables); I++)
+ {
+ tr.flags = Variables[I].Flags | TRF_CALLSVC | TRF_TCHAR;
+ tr.tszTokenString = Variables[I].Name;
+ tr.szHelpText = Variables[I].Descr;
+ CallService(MS_VARS_REGISTERTOKEN, 0, (LPARAM)&tr);
+ }
+ }
+// updater plugin support
+ Update update = {0};
+ char szVersion[16];
+ update.cbSize = sizeof(Update);
+ update.szComponentName = pluginInfo.shortName;
+ update.pbVersion = (BYTE*)CreateVersionString(my_make_version(PRODUCTVER), szVersion);
+ update.cpbVersion = strlen((char*)update.pbVersion);
+ update.szUpdateURL = "http://myied.org/packs/NAS"
+#ifdef _UNICODE
+ "W"
+#endif
+ ".zip";
+ update.szVersionURL = "http://myied.org/packs/NAS/updaterinfo.php";
+ update.pbVersionPrefix = (BYTE*)"New Away System Mod"
+#ifdef _UNICODE
+ " Unicode"
+#endif
+ " version ";
+ update.cpbVersionPrefix = strlen((char*)update.pbVersionPrefix);
+ CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update);
+
+ //NightFox
+ HookEvent(ME_MODERNOPT_INITIALIZE, ModernOptInitialise);
+
+
+ return 0;
+}
+
+
+extern "C" int __declspec(dllexport) Load(PLUGINLINK *link)
+{
+ pluginLink = link;
+ if (CallService(MS_SYSTEM_GETVERSION, 0, 0) < 0x060000)
+ {
+ MessageBox(NULL, TranslateT("New Away System plugin requires Miranda version 0.6.0.0 or above."), TranslateT("New Away System"), MB_OK);
+ return 1;
+ }
+ hHooks.AddElem(HookEvent(ME_SYSTEM_MODULESLOADED, MirandaLoaded));
+// hHooks.AddElem(HookEvent(ME_CS_CSMODULELOADED, CSModuleLoaded)); // compatibility with StartupStatus and AdvancedAutoAway
+ if (DBGetContactSettingString(NULL, "KnownModules", "New Away System", (char*)NULL) == NULL)
+ {
+ DBWriteContactSettingString(NULL, "KnownModules", "New Away System", MOD_NAME);
+ }
+
+ InitCommonControls();
+ InitOptions(); // must be called before we hook CallService
+ g_OldCallService = pluginLink->CallService; // looks like this hack is currently the only way to handle all calls to PS_SETSTATUS and PS_SETAWAYMSG properly. I must know when someone calls it, and there's no any "standard" way to know the real value passed as wParam to it (protocol module often replaces it by another, _supported_ status; for example, Jabber replaces Occupied by DND), so we're intercepting the service here
+// and we need to know the real wParam value just to set proper status message (an example: changing the global status to Out to lunch makes Jabber go Away. I guess, the user wants Jabber status message to be "I've been having lunch..." too, like for other protocols, rather than the default Away message "Gone since...")
+ pluginLink->CallService = MyCallService;
+
+ logservice_register(LOG_ID, LPGENT("New Away System"), _T("NewAwaySys?puts(p,?dbsetting(%subject%,Protocol,p))?if2(_?dbsetting(,?get(p),?pinfo(?get(p),uidsetting)),).log"), TranslateTS(_T("`[`!cdate()-!ctime()`]` ?cinfo(%subject%,display) (?cinfo(%subject%,id)) read your %") _T(VAR_STATDESC) _T("% message:\r\n%extratext%\r\n\r\n")));
+
+ if (DBGetContactSettingByte(NULL, MOD_NAME, DB_SETTINGSVER, 0) < 1)
+ { // change all %nas_message% variables to %extratext% if it wasn't done before
+ TCString Str;
+ Str = DBGetContactSettingString(NULL, MOD_NAME, "PopupsFormat", _T(""));
+ if (Str.GetLen())
+ {
+ DBWriteContactSettingTString(NULL, MOD_NAME, "PopupsFormat", Str.Replace(_T("nas_message"), _T("extratext")));
+ }
+ Str = DBGetContactSettingString(NULL, MOD_NAME, "ReplyPrefix", _T(""));
+ if (Str.GetLen())
+ {
+ DBWriteContactSettingTString(NULL, MOD_NAME, "ReplyPrefix", Str.Replace(_T("nas_message"), _T("extratext")));
+ }
+ }
+ if (DBGetContactSettingByte(NULL, MOD_NAME, DB_SETTINGSVER, 0) < 2)
+ { // disable autoreply for not-on-list contacts, as such contact may be a spam bot
+ DBWriteContactSettingByte(NULL, MOD_NAME, ContactStatusToDBSetting(0, DB_ENABLEREPLY, 0, INVALID_HANDLE_VALUE), 0);
+ DBWriteContactSettingByte(NULL, MOD_NAME, DB_SETTINGSVER, 2);
+ }
+ return 0;
+}
+
+
+extern "C" int __declspec(dllexport) Unload()
+{
+ _ASSERT(pluginLink->CallService == MyCallService);
+ if (pluginLink->CallService == MyCallService)
+ {
+ pluginLink->CallService = g_OldCallService;
+ }
+ CloseHandle(hMainThread);
+ int I;
+ for (I = 0; I < hHooks.GetSize(); I++)
+ {
+ if (hHooks[I])
+ {
+ UnhookEvent(hHooks[I]);
+ }
+ }
+ for (I = 0; I < hServices.GetSize(); I++)
+ {
+ if (hServices[I])
+ {
+ DestroyServiceFunction(hServices[I]);
+ }
+ }
+ return 0;
+}
diff --git a/plugins/NewAwaySysMod/Client.cpp b/plugins/NewAwaySysMod/Client.cpp
new file mode 100644
index 0000000000..e37d3eeb62
--- /dev/null
+++ b/plugins/NewAwaySysMod/Client.cpp
@@ -0,0 +1,232 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (c) 2005-2007 Chervov Dmitry
+ Copyright (c) 2004-2005 Iksaif Entertainment
+ Copyright (c) 2002-2003 Goblineye Entertainment
+
+ 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 "Common.h"
+#include "MsgTree.h"
+#include "Properties.h"
+
+#define PARSE_INTERVAL 10000
+
+HANDLE g_hTerminateUpdateMsgsThread = NULL;
+HANDLE g_hUpdateMsgsThread = NULL;
+
+void __cdecl UpdateMsgsThreadProc(void *)
+{
+ int ProtoCount;
+ PROTOCOLDESCRIPTOR **proto;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&ProtoCount, (LPARAM)&proto);
+ int I;
+ while (WaitForSingleObject(g_hTerminateUpdateMsgsThread, 0) == WAIT_TIMEOUT && !Miranda_Terminated())
+ {
+ DWORD MinUpdateTimeDifference = g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_UPDATEMSGSPERIOD) * 1000; // in milliseconds
+ for (I = 0; I < ProtoCount; I++)
+ {
+ if (proto[I]->type == PROTOTYPE_PROTOCOL && CallProtoService(proto[I]->szName, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGSEND && !IsAnICQProto(proto[I]->szName))
+ {
+ int Status = CallProtoService(proto[I]->szName, PS_GETSTATUS, 0, 0);
+ if (Status < ID_STATUS_OFFLINE || Status > ID_STATUS_OUTTOLUNCH)
+ {
+ Status = g_ProtoStates[proto[I]->szName].Status;
+ }
+ if (CallProtoService(proto[I]->szName, PS_GETCAPS, PFLAGNUM_3, 0) & Proto_Status2Flag(Status) && g_ProtoStates[proto[I]->szName].CurStatusMsg.GetUpdateTimeDifference() >= MinUpdateTimeDifference)
+ {
+ TCString CurMsg(GetDynamicStatMsg(INVALID_HANDLE_VALUE, proto[I]->szName));
+ if ((TCString)g_ProtoStates[proto[I]->szName].CurStatusMsg != (const TCHAR*)CurMsg) // if the message has changed
+ {
+ g_ProtoStates[proto[I]->szName].CurStatusMsg = CurMsg;
+ CallAllowedPS_SETAWAYMSG(proto[I]->szName, Status, (char*)TCHAR2ANSI(CurMsg));
+ }
+ }
+ }
+ }
+ SleepEx(PARSE_INTERVAL, true);
+ }
+}
+
+
+static void __stdcall DummyAPCFunc(DWORD)
+{
+ return;
+}
+
+
+void InitUpdateMsgs()
+{
+ int UpdateMsgs = g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_UPDATEMSGS);
+ if (g_hUpdateMsgsThread && !UpdateMsgs)
+ {
+ _ASSERT(WaitForSingleObject(g_hUpdateMsgsThread, 0) == WAIT_TIMEOUT);
+ SetEvent(g_hTerminateUpdateMsgsThread);
+ QueueUserAPC(DummyAPCFunc, g_hUpdateMsgsThread, 0); // wake up the thread, as it's most probably in SleepEx() now
+ WaitForSingleObject(g_hUpdateMsgsThread, INFINITE);
+ g_hUpdateMsgsThread = NULL;
+ CloseHandle(g_hTerminateUpdateMsgsThread);
+ } else if (!g_hUpdateMsgsThread && UpdateMsgs)
+ {
+ g_hTerminateUpdateMsgsThread = CreateEvent(NULL, TRUE, FALSE, NULL);
+ g_hUpdateMsgsThread = (HANDLE)mir_forkthread(UpdateMsgsThreadProc, NULL);
+ }
+}
+
+
+void ChangeProtoMessages(char* szProto, int iMode, TCString &Msg)
+{
+ TCString CurMsg(Msg);
+ if (szProto)
+ {
+ if (Msg == NULL)
+ {
+ CurMsg = GetDynamicStatMsg(INVALID_HANDLE_VALUE, szProto);
+ }
+ CallAllowedPS_SETAWAYMSG(szProto, iMode, (char*)TCHAR2ANSI(CurMsg));
+ g_ProtoStates[szProto].CurStatusMsg = CurMsg;
+ } else // change message of all protocols
+ {
+ int ProtoCount;
+ PROTOCOLDESCRIPTOR **proto;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&ProtoCount, (LPARAM)&proto);
+ int I;
+ for (I = 0; I < ProtoCount; I++)
+ {
+ if (proto[I]->type == PROTOTYPE_PROTOCOL && !DBGetContactSettingByte(NULL, proto[I]->szName, "LockMainStatus", 0))
+ {
+ if (Msg == NULL)
+ {
+ CurMsg = GetDynamicStatMsg(INVALID_HANDLE_VALUE, proto[I]->szName);
+ }
+ CallAllowedPS_SETAWAYMSG(proto[I]->szName, iMode, (char*)TCHAR2ANSI(CurMsg));
+ g_ProtoStates[proto[I]->szName].CurStatusMsg = CurMsg;
+ }
+ }
+ }
+ static struct
+ {
+ int Status;
+ char *Setting;
+ } StatusSettings[] = {
+ ID_STATUS_OFFLINE, "Off",
+ ID_STATUS_ONLINE, "On",
+ ID_STATUS_AWAY, "Away",
+ ID_STATUS_NA, "Na",
+ ID_STATUS_DND, "Dnd",
+ ID_STATUS_OCCUPIED, "Occupied",
+ ID_STATUS_FREECHAT, "FreeChat",
+ ID_STATUS_INVISIBLE, "Inv",
+ ID_STATUS_ONTHEPHONE, "Otp",
+ ID_STATUS_OUTTOLUNCH, "Otl",
+ ID_STATUS_IDLE, "Idl"
+ };
+ int I;
+ for (I = 0; I < lengthof(StatusSettings); I++)
+ {
+ if (iMode == StatusSettings[I].Status)
+ {
+ DBWriteContactSettingTString(NULL, "SRAway", CString(StatusSettings[I].Setting) + "Msg", CurMsg);
+ DBWriteContactSettingTString(NULL, "SRAway", CString(StatusSettings[I].Setting) + "Default", CurMsg); // TODO: make it more accurate, and change not only here, but when changing status messages through UpdateMsgsTimerFunc too; and when changing messages through AutoAway() ?
+ break;
+ }
+ }
+// InitUpdateMsgs();
+}
+
+
+int GetRecentGroupID(int iMode)
+{ // returns an ID of a group where recent messages are stored, accordingly to current settings and status mode.
+ // -1 if the group is not found
+// COptPage MoreOptData(g_MoreOptPage);
+ COptPage MsgTreeData(g_MsgTreePage);
+ COptItem_TreeCtrl *TreeCtrl = (COptItem_TreeCtrl*)MsgTreeData.Find(IDV_MSGTREE);
+ TreeCtrl->DBToMem(CString(MOD_NAME));
+ int Order;
+ if (g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_PERSTATUSMRM))
+ {
+ for (Order = 0; Order < TreeCtrl->Value.GetSize(); Order++) // find a group named accordingly to the current status
+ {
+ if (TreeCtrl->Value[Order].ParentID == g_Messages_RecentRootID && TreeCtrl->Value[Order].Flags & TIF_GROUP && !_tcsicmp(TreeCtrl->Value[Order].Title, iMode ? (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, iMode, GCMDF_TCHAR) : MSGTREE_RECENT_OTHERGROUP))
+ {
+ return TreeCtrl->Value[Order].ID;
+ }
+ }
+ } else // simply use Recent Messages category
+ {
+ return g_Messages_RecentRootID;
+ }
+ return -1;
+}
+
+
+int ICQStatusToGeneralStatus(int bICQStat)
+{
+ switch (bICQStat)
+ {
+ case MTYPE_AUTOONLINE: return ID_STATUS_ONLINE;
+ case MTYPE_AUTOAWAY: return ID_STATUS_AWAY;
+ case MTYPE_AUTONA: return ID_STATUS_NA;
+ case MTYPE_AUTODND: return ID_STATUS_DND;
+ case MTYPE_AUTOBUSY: return ID_STATUS_OCCUPIED;
+ case MTYPE_AUTOFFC: return ID_STATUS_FREECHAT;
+ default: return 0;
+ }
+}
+
+
+TCString VariablesEscape(TCString Str)
+{
+ if (!Str.GetLen())
+ {
+ return _T("");
+ }
+ enum eState
+ {
+ ST_TEXT, ST_QUOTE
+ };
+ eState State = ST_QUOTE;
+ TCString Result(_T("`"));
+ const TCHAR *p = Str;
+ while (*p)
+ {
+ if (*p == '`')
+ {
+ if (State == ST_TEXT)
+ {
+ Result += _T("````");
+ State = ST_QUOTE;
+ } else
+ {
+ Result += _T("``");
+ }
+ } else
+ {
+ Result += *p;
+ State = ST_TEXT;
+ }
+ p++;
+ }
+ if (State == ST_QUOTE)
+ {
+ Result.GetBuffer()[Result.GetLen() - 1] = '\0';
+ Result.ReleaseBuffer();
+ } else
+ {
+ Result += '`';
+ }
+ return Result;
+}
diff --git a/plugins/NewAwaySysMod/Common.h b/plugins/NewAwaySysMod/Common.h
new file mode 100644
index 0000000000..0cec979cd0
--- /dev/null
+++ b/plugins/NewAwaySysMod/Common.h
@@ -0,0 +1,413 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (c) 2005-2007 Chervov Dmitry
+ Copyright (c) 2004-2005 Iksaif Entertainment
+ Copyright (c) 2002-2003 Goblineye Entertainment
+
+ 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 WIN32_LEAN_AND_MEAN
+#define _WIN32_WINNT 0x0400
+
+#define MIRANDA_VER 0x0600
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <commdlg.h>
+#include <time.h>
+#include <shellapi.h>
+#include <crtdbg.h>
+#include <tchar.h>
+#include <stdarg.h>
+#include "AggressiveOptimize.h"
+#include "resource.h"
+#include "newpluginapi.h"
+#include "m_clist.h"
+#include "m_system.h"
+#include "m_database.h"
+#include "m_clui.h"
+#include "m_langpack.h"
+#include "m_protosvc.h"
+#include "m_options.h"
+#include "..\..\protocols\IcqOscarJ\icq_constants.h"
+#include "m_skin.h"
+#include "m_plugins.h"
+#include "m_awaymsg.h"
+#include "m_utils.h"
+#include "m_history.h"
+#include "m_message.h"
+#include "m_userinfo.h"
+#include "m_icq.h"
+#define THEMEAPI // we don't need no uxtheme defines :-/ they break everything when trying to include tmschema.h later
+#include "win2k.h"
+#undef THEMEAPI
+
+#include "m_variables.h"
+//#include "m_toptoolbar.h"
+#include "m_popup.h"
+//#include "m_popupw.h"
+#include "m_metacontacts.h"
+#include "..\CommonLibs\m_LogService.h"
+#include "..\CommonLibs\CString.h"
+#include "..\CommonLibs\Options.h"
+
+
+#pragma comment(lib,"comctl32.lib")
+
+#define VAR_AWAYSINCE_TIME "nas_awaysince_time"
+#define VAR_AWAYSINCE_DATE "nas_awaysince_date"
+#define VAR_STATDESC "nas_statdesc"
+#define VAR_MYNICK "nas_mynick"
+#define VAR_REQUESTCOUNT "nas_requestcount"
+#define VAR_MESSAGENUM "nas_messagecount"
+#define VAR_TIMEPASSED "nas_timepassed"
+#define VAR_PREDEFINEDMESSAGE "nas_predefinedmessage"
+#define VAR_PROTOCOL "nas_protocol"
+
+#define SENDSMSG_EVENT_MSG 0x1
+#define SENDSMSG_EVENT_URL 0x2
+#define SENDSMSG_EVENT_FILE 0x4
+
+#define AWAY_MSGDATA_MAX 8000
+
+// Flags for status database settings
+#define SF_OFF 0x1
+#define SF_ONL 0x2
+#define SF_AWAY 0x4
+#define SF_NA 0x8
+#define SF_OCC 0x10
+#define SF_DND 0x20
+#define SF_FFC 0x40
+#define SF_INV 0x80
+#define SF_OTP 0x100
+#define SF_OTL 0x200
+#define SF_OTHER 0x80000000
+/*
+// Actions on popup click
+#define PCA_OPENMESSAGEWND 0 // open message window
+#define PCA_CLOSEPOPUP 1 // close popup
+#define PCA_OPENDETAILS 2 // open contact details window
+#define PCA_OPENMENU 3 // open contact menu
+#define PCA_OPENHISTORY 4 // open contact history
+#define PCA_OPENLOG 5 // open log file
+#define PCA_DONOTHING 6 // do nothing
+
+// Notification options defaults
+#define POPUP_DEF_POPUP_FORMAT TranslateT("?cinfo(%subject%,display) (?cinfo(%subject%,id)) is reading your %nas_statdesc% message:\r\n%extratext%")
+#define POPUP_DEF_USEPOPUPS 0
+#define POPUP_DEF_LCLICKACTION PCA_OPENMESSAGEWND
+#define POPUP_DEF_RCLICKACTION PCA_CLOSEPOPUP
+#define POPUP_DEF_POPUP_BGCOLOUR 0xFFB5BC
+#define POPUP_DEF_POPUP_TEXTCOLOUR 0
+#define POPUP_DEF_USEDEFBGCOLOUR 0
+#define POPUP_DEF_USEDEFTEXTCOLOUR 0
+#define POPUP_DEF_POPUPNOTIFYFLAGS (SF_ONL | SF_AWAY | SF_NA | SF_OCC | SF_DND | SF_FFC | SF_INV | SF_OTP | SF_OTL)
+#define POPUP_DEF_POPUPDELAY 0
+
+#define POPUP_MAXPOPUPDELAY 9999
+*/
+#define MOREOPTDLG_DEF_DONTPOPDLG (SF_ONL | SF_INV)
+#define MOREOPTDLG_DEF_USEBYDEFAULT 0
+
+// Event flags (used for "reply on event" options)
+#define EF_MSG 1
+#define EF_URL 2
+#define EF_FILE 4
+
+#define AUTOREPLY_DEF_REPLY 0
+#define AUTOREPLY_DEF_REPLYONEVENT (EF_MSG | EF_URL | EF_FILE)
+#define AUTOREPLY_DEF_PREFIX TranslateT("Miranda IM autoreply >\r\n%extratext%")
+#define AUTOREPLY_DEF_DISABLEREPLY (SF_ONL | SF_INV)
+
+#define AUTOREPLY_IDLE_WINDOWS 0
+#define AUTOREPLY_IDLE_MIRANDA 1
+#define AUTOREPLY_DEF_IDLEREPLYVALUE AUTOREPLY_IDLE_WINDOWS
+
+#define AUTOREPLY_MAXPREFIXLEN 8000
+
+#define VAL_USEDEFAULT 2 // undefined value for ignore/autoreply/notification settings in the db; must be 2 for proper ContactSettings support
+
+// Set Away Message dialog flags
+#define DF_SAM_SHOWMSGTREE 1
+#define DF_SAM_SHOWCONTACTTREE 2
+#define DF_SAM_DEFDLGFLAGS DF_SAM_SHOWMSGTREE
+
+// WriteAwayMsgInDB option flags:
+#define WRITE_LMSG 1
+#define WRITE_RMSG 2
+#define WRITE_INTERPRET 4
+#define WRITE_CMSG 8
+
+#define TOGGLE_SOE_COMMAND LPGENT("Toggle autoreply on/off")
+#define DISABLE_SOE_COMMAND LPGENT("Toggle autoreply off")
+#define ENABLE_SOE_COMMAND LPGENT("Toggle autoreply on")
+
+#define STR_XSTATUSDESC TranslateT("extended status")
+
+#define MOD_NAME "NewAwaySys"
+#define LOG_ID MOD_NAME // LogService log ID
+#define LOG_PREFIX MOD_NAME ": " // netlib.log prefix for all NAS' messages
+
+#define DB_SETTINGSVER "SettingsVer"
+
+#ifndef lengthof
+#define lengthof(s) (sizeof(s) / sizeof(*s))
+#endif
+
+#define MS_NETLIB_LOG "Netlib/Log"
+
+#define UM_ICONSCHANGED (WM_USER + 121)
+
+// IDD_READAWAYMSG user-defined message constants
+#define UM_RAM_AWAYMSGACK (WM_USER + 10)
+
+// IDD_SETAWAYMSG user-defined message constants
+#define UM_SAM_SPLITTERMOVED (WM_USER + 1)
+#define UM_SAM_SAVEDLGSETTINGS (WM_USER + 2)
+#define UM_SAM_APPLYANDCLOSE (WM_USER + 3)
+#define UM_SAM_KILLTIMER (WM_USER + 4)
+#define UM_SAM_REPLYSETTINGCHANGED (WM_USER + 5)
+#define UM_SAM_PROTOSTATUSCHANGED (WM_USER + 6) // wParam = (char*)szProto
+
+#define UM_CLICK (WM_USER + 100)
+
+#define SAM_DB_DLGPOSX "SAMDlgPosX"
+#define SAM_DB_DLGPOSY "SAMDlgPosY"
+#define SAM_DB_DLGSIZEX "SAMDlgSizeX"
+#define SAM_DB_DLGSIZEY "SAMDlgSizeY"
+#define SAM_DB_MSGSPLITTERPOS "SAMMsgSplitterPos"
+#define SAM_DB_CONTACTSPLITTERPOS "SAMContactSplitterPos"
+
+#define DB_MESSAGECOUNT "MessageCount"
+#define DB_REQUESTCOUNT "RequestCount"
+#define DB_SENDCOUNT "SendCount"
+#define MESSAGES_DB_MSGTREEDEF "MsgTreeDef"
+
+#define MSGTREE_RECENT_OTHERGROUP _T("Other")
+
+// GetMsgFormat flags
+#define GMF_PERSONAL 1 // is also used to get global status message, when hContact = NULL (szProto = NULL)
+#define GMF_PROTOORGLOBAL 2
+#define GMF_LASTORDEFAULT 4 // this flag doesn't require hContact or szProto
+#define GMF_TEMPORARY 8 // doesn't require status
+#define GMF_ANYCURRENT (GMF_TEMPORARY | GMF_PERSONAL | GMF_PROTOORGLOBAL)
+
+// SetMsgFormat flags
+#define SMF_PERSONAL 1 // is also used to set global status message, when hContact = NULL (szProto = NULL)
+#define SMF_LAST 2
+#define SMF_TEMPORARY 4 // doesn't require status
+
+// VAR_PARSE_DATA flags
+#define VPF_XSTATUS 1 // use "extended status" instead of the usual status description in %nas_statdesc%, and XStatus message in %nas_message%
+
+// options dialog
+#define OPT_TITLE LPGENT("Away System")
+#define OPT_MAINGROUP LPGENT("Status")
+#define OPT_POPUPGROUP LPGENT("PopUps")
+
+#define MRM_MAX_GENERATED_TITLE_LEN 35 // maximum length of automatically generated title for recent messages
+
+int ICQStatusToGeneralStatus(int bICQStat); // TODO: get rid of these protocol-specific functions, if possible
+
+#define MS_AWAYSYS_SETCONTACTSTATMSG "AwaySys/SetContactStatMsg"
+
+#define MS_AWAYSYS_AUTOREPLY_TOGGLE "AwaySys/AutoreplyToggle"
+#define MS_AWAYSYS_AUTOREPLY_ON "AwaySys/AutoreplyOn"
+#define MS_AWAYSYS_AUTOREPLY_OFF "AwaySys/AutoreplyOff"
+#define MS_AWAYSYS_AUTOREPLY_USEDEFAULT "AwaySys/AutoreplyUseDefault"
+
+#define MS_AWAYSYS_VARIABLESHANDLER "AwaySys/VariablesHandler"
+#define MS_AWAYSYS_FREEVARMEM "AwaySys/FreeVarMem"
+// these are obsolete AwaySysMod services, though they're still here for compatibility with old plugins
+#define MS_AWAYSYS_SETSTATUSMODE "AwaySys/SetStatusMode" // change the status mode. wParam is new mode, lParam is new status message (AwaySys will interpret variables out of it), may be NULL.
+#define MS_AWAYSYS_IGNORENEXT "AwaySys/IgnoreNextStatusChange" //ignore nest status change
+
+typedef struct SetAwayMsgData_type
+{
+ CString szProtocol;
+ HANDLE hInitContact; // initial contact (filled by caller)
+ TCString Message; // initial message, NULL means default
+ bool IsModeless; // means the dialog was created with the CreateDialogParam function, not DialogBoxParam
+ int ISW_Flags; // InvokeStatusWindow service flags
+} SetAwayMsgData;
+
+typedef struct READAWAYMSGDATA_TYPE
+{
+ HANDLE hContact; // contact
+ HANDLE hSeq; // sequence for stat msg request
+ HANDLE hAwayMsgEvent; // hooked
+} READAWAYMSGDATA;
+
+typedef struct
+{
+ char *szProto;
+ TCString Message;
+ DWORD UIN;
+ int Flags; // a combination of VPF_ flags
+} VAR_PARSE_DATA;
+
+typedef struct
+{
+ HANDLE hContact;
+ int iStatusMode;
+ TCString Proto;
+} DYNAMIC_NOTIFY_DATA;
+
+typedef struct
+{
+ BYTE PopupLClickAction, PopupRClickAction;
+ HANDLE hContact;
+ HICON hStatusIcon; // needed here to destroy its handle on UM_FREEPLUGINDATA
+} PLUGIN_DATA;
+
+typedef struct
+{
+ int cbSize;
+ char *szProto;
+ HANDLE hContact;
+ char *szMsg;
+ WORD status;
+} NAS_ISWINFOv1;
+
+#define MTYPE_AUTOONLINE 0xE7 // required to support ICQ Plus online status messages
+/*
+// additional m_popup.h declarations
+#ifdef _UNICODE
+ typedef struct
+ {
+ HANDLE lchContact;
+ HICON lchIcon;
+ WCHAR lpzContactName[MAX_CONTACTNAME];
+ WCHAR lpzText[MAX_SECONDLINE];
+ COLORREF colorBack;
+ COLORREF colorText;
+ WNDPROC PluginWindowProc;
+ void * PluginData;
+ int iSeconds;
+ char cZero[16];
+ } POPUPDATAT;
+
+ #define MS_POPUP_ADDPOPUPT MS_POPUP_ADDPOPUPW
+#else
+ #define POPUPDATAT POPUPDATAEX
+ #define MS_POPUP_ADDPOPUPT MS_POPUP_ADDPOPUPEX
+#endif
+*/
+// Beware of conflicts between two different windows trying to use the same page at a time!
+// Other windows than the owner of the Page must copy the page to their own memory,
+// or use GetDBValueCopy to retrieve values
+extern COptPage g_MessagesOptPage;
+extern COptPage g_AutoreplyOptPage;
+//extern COptPage g_PopupOptPage;
+extern COptPage g_MoreOptPage;
+extern COptPage g_SetAwayMsgPage;
+
+extern HINSTANCE g_hInstance;
+extern HANDLE hMainThread;
+extern int g_Messages_RecentRootID, g_Messages_PredefinedRootID;
+extern VAR_PARSE_DATA VarParseData;
+extern bool g_fNoProcessing;
+extern int g_bIsIdle;
+extern int (*g_OldCallService)(const char *, WPARAM, LPARAM);
+
+
+// AwaySys.cpp
+TCString GetDynamicStatMsg(HANDLE hContact, char *szProto = NULL, DWORD UIN = 0, int iStatus = 0);
+int IsAnICQProto(char *szProto);
+
+// Client.cpp
+void InitUpdateMsgs();
+void ChangeProtoMessages(char* szProto, int iMode, TCString &Msg);
+int GetRecentGroupID(int iMode);
+TCString VariablesEscape(TCString Str);
+
+// SetAwayMsg.cpp
+int CALLBACK SetAwayMsgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
+// ReadAwayMsg.cpp
+extern HANDLE g_hReadWndList;
+int GetContactStatMsg(WPARAM wParam, LPARAM lParam);
+
+// AwayOpt.cpp
+int OptsDlgInit(WPARAM wParam, LPARAM lParam); // called on opening of the options dialog
+void InitOptions(); // called once when plugin is loaded
+
+//int ShowPopupNotification(COptPage &PopupNotifyData, HANDLE hContact, int iStatusMode);
+void ShowLog(TCString &LogFilePath);
+void ShowMsg(TCHAR *szFirstLine, TCHAR *szSecondLine = _T(""), bool IsErrorMsg = false, int Timeout = 0);
+
+#define AWAYSYS_STATUSMSGREQUEST_SOUND "AwaySysStatusMsgRequest"
+#define ME_AWAYSYS_WORKAROUND "AwaySys/_CallService"
+int _Workaround_CallService(const char *name, WPARAM wParam, LPARAM lParam);
+
+// MsgEventAdded.cpp
+int MsgEventAdded(WPARAM wParam, LPARAM lParam);
+
+// buttons
+//void UpdateSOEButtons(HANDLE hContact = NULL);
+int ToggleSendOnEvent(WPARAM wParam, LPARAM lParam);
+//int Create_TopToolbar(WPARAM wParam, LPARAM lParam);
+
+
+static __inline int LogMessage(const char *Format, ...)
+{
+ va_list va;
+ char szText[8096];
+ strcpy(szText, LOG_PREFIX);
+ va_start(va, Format);
+ mir_vsnprintf(szText + (lengthof(LOG_PREFIX) - 1), sizeof(szText) - (lengthof(LOG_PREFIX) - 1), Format, va);
+ va_end(va);
+ return CallService(MS_NETLIB_LOG, NULL, (LPARAM)szText);
+}
+
+__inline int CallAllowedPS_SETAWAYMSG(const char *szProto, int iMode, const char *szMsg)
+{ // we must use this function everywhere we want to call PS_SETAWAYMSG, otherwise NAS won't allow to change the message!
+ LogMessage("PS_SETAWAYMSG called by NAS. szProto=%s, Status=%d, Msg:\n%s", szProto, iMode, szMsg ? szMsg : "NULL");
+ char str[MAXMODULELABELLENGTH];
+ strcpy(str, szProto);
+ strcat(str, PS_SETAWAYMSG);
+ return g_OldCallService(str, (WPARAM)iMode, (LPARAM)szMsg);
+}
+
+static __inline void my_variables_skin_helpbutton(HWND hwndDlg, UINT uIDButton)
+{
+ HICON hIcon = ServiceExists(MS_VARS_GETSKINITEM) ? (HICON)CallService(MS_VARS_GETSKINITEM, 0, (LPARAM)VSI_HELPICON) : NULL;
+ if (hIcon)
+ {
+ SendDlgItemMessage(hwndDlg, uIDButton, BM_SETIMAGE, IMAGE_ICON, (LPARAM)hIcon);
+ }
+}
+
+static __inline int my_variables_showhelp(HWND hwndDlg, UINT uIDEdit, int flags = 0, char *szSubjectDesc = NULL, char *szExtraDesc = NULL)
+{
+ if (ServiceExists(MS_VARS_SHOWHELPEX))
+ {
+ VARHELPINFO vhi = {0};
+ vhi.cbSize = sizeof(VARHELPINFO);
+ vhi.flags = flags ? flags : (VHF_FULLDLG | VHF_SETLASTSUBJECT);
+ vhi.hwndCtrl = GetDlgItem(hwndDlg, uIDEdit);
+ vhi.szSubjectDesc = szSubjectDesc;
+ vhi.szExtraTextDesc = szExtraDesc;
+ return CallService(MS_VARS_SHOWHELPEX, (WPARAM)hwndDlg, (LPARAM)&vhi);
+ } else
+ {
+ ShowMsg(TranslateT("New Away System"), TranslateT("Variables plugin is not installed"), true);
+ return -1;
+ }
+}
diff --git a/plugins/NewAwaySysMod/CommonLibs/CString.cpp b/plugins/NewAwaySysMod/CommonLibs/CString.cpp
new file mode 100644
index 0000000000..de3b1a3297
--- /dev/null
+++ b/plugins/NewAwaySysMod/CommonLibs/CString.cpp
@@ -0,0 +1,380 @@
+/*
+ TCString.cpp - TCString class
+ Copyright (c) 2005-2008 Chervov Dmitry
+
+ 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 <stdio.h>
+#include "CString.h"
+
+#define STR_GROWBY 64
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+
+template <class T>
+void TString<T>::Empty()
+{
+ nBufSize = 1;
+ SetAllocSize(STR_GROWBY);
+ pBuf[0] = 0;
+}
+
+
+template <class T>
+void TString<T>::Free()
+{
+// HeapFree(GetProcessHeap(), 0, pBuf);
+ free(pBuf);
+ pBuf = NULL;
+ nBufSize = 0;
+ nAllocSize = 0;
+}
+
+
+template <class T>
+T *TString<T>::GetBuffer(int nNewLen)
+{
+ if (nNewLen != -1)
+ {
+ SetBufSize(nNewLen + 1);
+ }
+ _ASSERT(pBuf);
+ return pBuf;
+}
+
+
+template <class T>
+void TString<T>::ReleaseBuffer(int nNewLen)
+{
+ if (nNewLen == -1)
+ {
+ nBufSize = My_lstrlen(pBuf) + 1;
+ } else
+ {
+ nBufSize = nNewLen + 1;
+ pBuf[nNewLen] = 0;
+ _ASSERT(My_lstrlen(pBuf) == nNewLen);
+ }
+ _ASSERT(nBufSize <= nAllocSize); // prevent buffer overruns
+}
+
+
+template <class T>
+void TString<T>::SetAllocSize(int nNewAllocSize)
+{
+ _ASSERT(nNewAllocSize > 0);
+ T *pNewBuf = /*(char *)HeapAlloc(GetProcessHeap(), 0, sizeof(char) * nNewAllocSize);*/
+(T *)malloc(sizeof(T) * nNewAllocSize);
+ if (pBuf)
+ {
+ memcpy(pNewBuf, pBuf, sizeof(T) * min(nBufSize, nNewAllocSize));
+ //HeapFree(GetProcessHeap(), 0, pBuf);
+ free(pBuf);
+ }
+ pBuf = pNewBuf;
+ nAllocSize = nNewAllocSize;
+}
+
+
+template <class T>
+void TString<T>::SetBufSize(int nNewBufSize)
+{
+ _ASSERT(nNewBufSize >= 0);
+ if (nNewBufSize < nBufSize)
+ {
+ _ASSERT(pBuf);
+ pBuf[nNewBufSize - 1] = 0;
+ }
+ if ((unsigned)(nAllocSize - nNewBufSize) / STR_GROWBY)
+ {
+ SetAllocSize((nNewBufSize + STR_GROWBY - 1) - (nNewBufSize + STR_GROWBY - 1) % STR_GROWBY);
+ }
+ nBufSize = nNewBufSize;
+}
+
+
+template <class T>
+TString<T>& TString<T>::Cat(const T *pStr)
+{
+ _ASSERT(pBuf && pStr);
+ int StrLen = My_lstrlen(pStr);
+ SetAllocSize(nBufSize + StrLen);
+ My_lstrcpy(GetBuffer() + GetLen(), pStr);
+ ReleaseBuffer(nBufSize + StrLen - 1);
+ return *this;
+}
+
+
+template <class T>
+TString<T>& TString<T>::Cat(const T c)
+{
+ _ASSERT(pBuf);
+ SetAllocSize(nBufSize + 1);
+ int CurLen = GetLen();
+ T *p = GetBuffer();
+ p[CurLen] = c;
+ p[CurLen + 1] = '\0';
+ ReleaseBuffer(nBufSize);
+ return *this;
+}
+
+
+template <class T>
+TString<T>& TString<T>::DiffCat(const T *pStart, const T *pEnd)
+{
+ _ASSERT(pBuf && pStart && pEnd);
+ int StrLen = pEnd - pStart;
+ SetAllocSize(nBufSize + StrLen);
+ My_strncpy(GetBuffer() + GetLen(), pStart, StrLen);
+ ReleaseBuffer(nBufSize + StrLen - 1);
+ return *this;
+}
+
+
+template <class T>
+TString<T>& TString<T>::Replace(const T *szFind, const T *szReplaceBy)
+{
+ if (!pBuf)
+ {
+ return *this;
+ }
+ T *pCurPos = pBuf;
+ int FindLen = My_lstrlen(szFind);
+ T *p;
+ TString<T> Result;
+ Result.GetBuffer(1)[0] = '\0';
+ Result.ReleaseBuffer(0); // set the string to ""; we can't do it in a usual way (using a constructor or an assignment) because we don't know whether "" needs to be unicode or ansi
+ while (p = My_strstr(pCurPos, szFind))
+ {
+ Result.DiffCat(pCurPos, p);
+ Result += szReplaceBy;
+ pCurPos = p + FindLen;
+ }
+ Result += pCurPos;
+ *this = Result;
+ return *this;
+}
+
+
+template <class T>
+TString<T>& TString<T>::Replace(int nIndex, int nCount, const T *szReplaceBy)
+{
+ if (!pBuf || !szReplaceBy || nIndex < 0 || nCount < 0)
+ {
+ return *this;
+ }
+ T *pCurPos = pBuf;
+ TString<T> Result;
+ Result.GetBuffer(1)[0] = '\0';
+ Result.ReleaseBuffer(0); // set the string to ""; we can't do it in a usual way (using a constructor or an assignment) because we don't know whether "" needs to be unicode or ansi
+ if (nIndex > GetLen())
+ {
+ nIndex = GetLen();
+ }
+ if (nIndex + nCount > GetLen())
+ {
+ nCount = GetLen() - nIndex;
+ }
+ Result.DiffCat(pBuf, pBuf + nIndex);
+ Result += szReplaceBy;
+ Result += pBuf + nIndex + nCount;
+ *this = Result;
+ return *this;
+}
+
+
+template <class T>
+TString<T> TString<T>::Left(int nCount) const
+{
+ _ASSERT(nCount >= 0);
+ TString<T> Result(*this);
+ Result.SetBufSize(nCount + 1);
+ return Result;
+}
+
+
+template <class T>
+TString<T> TString<T>::Right(int nCount) const
+{
+ _ASSERT(nCount >= 0);
+ if (nCount < GetLen())
+ {
+ return &pBuf[GetLen() - nCount];
+ } else
+ {
+ return *this;
+ }
+}
+
+
+template <class T>
+TString<T> TString<T>::SubStr(int nIndex, int nCount) const
+{
+ _ASSERT(nIndex >= 0 && nCount >= 0);
+ TString<T> Result;
+ if (nIndex < GetLen())
+ {
+ My_strncpy(Result.GetBuffer(nCount), &pBuf[nIndex], nCount);
+ Result.ReleaseBuffer();
+ } else
+ {
+ Result.GetBuffer(1)[0] = '\0';
+ Result.ReleaseBuffer(0);
+ }
+ return Result;
+}
+
+
+template <class T>
+TString<T> TString<T>::ToLower() const
+{
+ TString<T> Result(*this);
+ if (!pBuf)
+ {
+ return Result; // return NULL string
+ }
+ My_strlwr((T*)Result);
+ return Result;
+}
+
+
+template <class T>
+TString<T>& TString<T>::operator = (const T *pStr)
+{
+ if (pStr)
+ {
+ int StrLen = My_lstrlen(pStr);
+ SetBufSize(StrLen + 1);
+ My_lstrcpy(GetBuffer(), pStr);
+ ReleaseBuffer(StrLen);
+ } else
+ {
+ Free();
+ }
+ return *this;
+}
+
+
+/*TCString& TCString::Format(char *pszFormat, ...)
+{
+ va_list argList;
+ va_start(argList, pszFormat);
+ int StrLen = _vscprintf(pszFormat, argList); // it's stupidity. in some versions of msvcrt.dll there's no _vscprintf function, so there's no any way to determine needed string length. so actually I can't use _vsnprintf too.
+ _vsnprintf(GetBuffer(StrLen), StrLen, pszFormat, argList);
+ ReleaseBuffer(StrLen);
+ va_end(argList);
+ return *this;
+}
+*/
+
+template class TString<TCHAR>;
+template class TString<char>;
+template class TString<WCHAR>;
+
+
+CString DBGetContactSettingString(HANDLE hContact, const char *szModule, const char *szSetting, const char *szDefaultValue)
+{
+ DBVARIANT dbv = {0};
+ DBCONTACTGETSETTING dbcgs;
+ dbcgs.szModule = szModule;
+ dbcgs.pValue = &dbv;
+ dbcgs.szSetting = szSetting;
+ int iRes = CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&dbcgs);
+ CString Result;
+ if (!iRes && dbv.type == DBVT_ASCIIZ)
+ {
+ Result = dbv.pszVal;
+ } else
+ {
+ Result = szDefaultValue;
+ }
+ if (!iRes)
+ {
+ CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv);
+ }
+ return Result;
+}
+
+
+#ifdef _UNICODE
+TCString DBGetContactSettingString(HANDLE hContact, const char *szModule, const char *szSetting, const TCHAR *szDefaultValue)
+{
+ DBVARIANT dbv = {0};
+ DBCONTACTGETSETTING dbcgs;
+ dbcgs.szModule = szModule;
+ dbcgs.pValue = &dbv;
+ dbcgs.szSetting = szSetting;
+ dbv.type = DBVT_WCHAR;
+ int iRes = CallService(MS_DB_CONTACT_GETSETTING_STR, (WPARAM)hContact, (LPARAM)&dbcgs);
+ TCString Result;
+ if (!iRes && dbv.type == DBVT_WCHAR)
+ {
+ Result = dbv.ptszVal;
+ } else
+ {
+ Result = szDefaultValue;
+ }
+ if (!iRes)
+ {
+ CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv);
+ }
+ return Result;
+}
+#endif
+
+
+int DBGetContactSettingString(HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv)
+{
+ //return DBGetContactSettingString_Helper(hContact, szModule, szSetting, dbv, __FILE__, __LINE__, DBVT_ASCIIZ);
+ return DBGetContactSettingString_Helper(hContact, szModule, szSetting, dbv, DBVT_ASCIIZ);
+
+}
+
+
+
+TCString DBGetContactSettingAsString(HANDLE hContact, const char *szModule, const char *szSetting, const TCHAR *szDefaultValue)
+{ // also converts numeric values to a string
+ DBVARIANT dbv = {0};
+ DBCONTACTGETSETTING dbcgs;
+ dbcgs.szModule = szModule;
+ dbcgs.pValue = &dbv;
+ dbcgs.szSetting = szSetting;
+#ifdef _UNICODE
+ dbv.type = DBVT_WCHAR;
+ int iRes = CallService(MS_DB_CONTACT_GETSETTING_STR, (WPARAM)hContact, (LPARAM)&dbcgs);
+#else
+ int iRes = CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&dbcgs);
+#endif
+ TCString Result;
+ if (!iRes && (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_WCHAR))
+ {
+ Result = dbv.ptszVal;
+ } else if (dbv.type == DBVT_BYTE || dbv.type == DBVT_WORD || dbv.type == DBVT_DWORD)
+ {
+ long value = (dbv.type == DBVT_DWORD) ? dbv.dVal : (dbv.type == DBVT_WORD ? dbv.wVal : dbv.bVal);
+ _ultot(value, Result.GetBuffer(64), 10);
+ Result.ReleaseBuffer();
+ } else
+ {
+ Result = szDefaultValue;
+ }
+ if (!iRes)
+ {
+ CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv);
+ }
+ return Result;
+}
diff --git a/plugins/NewAwaySysMod/CommonLibs/CString.h b/plugins/NewAwaySysMod/CommonLibs/CString.h
new file mode 100644
index 0000000000..8ba1a8da07
--- /dev/null
+++ b/plugins/NewAwaySysMod/CommonLibs/CString.h
@@ -0,0 +1,347 @@
+/*
+ TCString.h - TCString class
+ Copyright (c) 2005-2008 Chervov Dmitry
+
+ 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
+
+#include <windows.h>
+#include <tchar.h>
+#include <crtdbg.h>
+#ifdef CHARARRAY_CONVERT
+#include "TMyArray.h"
+#endif
+#include "newpluginapi.h"
+#include "m_system.h"
+#include "m_database.h"
+
+__inline int My_lstrlen(LPCSTR lpString) {return lstrlenA(lpString);}
+__inline int My_lstrlen(LPCWSTR lpString) {return lstrlenW(lpString);}
+__inline int My_lstrcmp(LPCSTR lpString1, LPCSTR lpString2) {return lstrcmpA(lpString1, lpString2);}
+__inline int My_lstrcmp(LPCWSTR lpString1, LPCWSTR lpString2) {return lstrcmpW(lpString1, lpString2);}
+__inline LPSTR My_strstr(LPCSTR lpString1, LPCSTR lpString2) {return strstr(lpString1, lpString2);}
+__inline LPWSTR My_strstr(LPCWSTR lpString1, LPCWSTR lpString2) {return (LPWSTR)wcsstr(lpString1, lpString2);}
+__inline LPSTR My_lstrcpy(LPSTR lpString1, LPCSTR lpString2) {return lstrcpyA(lpString1, lpString2);}
+__inline LPWSTR My_lstrcpy(LPWSTR lpString1, LPCWSTR lpString2) {return lstrcpyW(lpString1, lpString2);}
+__inline LPSTR My_strncpy(LPSTR lpString1, LPCSTR lpString2, int Len) {return strncpy(lpString1, lpString2, Len);}
+__inline LPWSTR My_strncpy(LPWSTR lpString1, LPCWSTR lpString2, int Len) {return wcsncpy(lpString1, lpString2, Len);}
+__inline LPSTR My_strlwr(LPSTR lpString) {return _strlwr(lpString);}
+__inline LPWSTR My_strlwr(LPWSTR lpString) {return _wcslwr(lpString);}
+
+template <class T>
+class TString
+{
+public:
+ TString(): pBuf(NULL), nBufSize(0), nAllocSize(0) {}
+ TString(const T *pStr): pBuf(NULL), nBufSize(0), nAllocSize(0) {*this = pStr;}
+ TString(const TString<T> &Str): pBuf(NULL), nBufSize(0), nAllocSize(0) {*this = Str.pBuf;}
+ ~TString() {Free();}
+
+ int GetLen() const {return (nBufSize) ? (nBufSize - 1) : 0;};
+ int IsEmpty() const {return (!GetLen());};
+ T *GetBuffer(int nNewLen = -1);
+ void ReleaseBuffer(int nNewLen = -1);
+ TString<T>& Cat(const T *pStr);
+ TString<T>& Cat(const T c);
+ TString<T>& DiffCat(const T *pStart, const T *pEnd);
+ TString<T>& Replace(const T *szFind, const T *szReplaceBy);
+ TString<T>& Replace(int nIndex, int nCount, const T *szReplaceBy);
+ TString<T> Left(int nCount) const;
+ TString<T> Right(int nCount) const;
+ TString<T> SubStr(int nIndex, int nCount) const;
+ TString<T> ToLower() const;
+ void Empty();
+ void Free();
+ T& operator [] (int nIndex) {_ASSERT(nIndex >= 0 && nIndex <= GetLen()); return pBuf[nIndex];}
+ operator const T*() const {return pBuf;}
+ operator T*() {return pBuf;}
+ TString<T>& operator = (const T *pStr);
+ TString<T>& operator = (const TString<T> &Str) {return *this = Str.pBuf;}
+// TCString& operator + (const char *pStr)
+// {_ASSERT(pBuf && pStr); TCString Result(*this); return Result.Cat(pStr);}
+ friend TString<T> operator + (const TString<T> &Str1, const T *Str2)
+ {_ASSERT(Str1.pBuf && Str2); TString<T> Result(Str1); return Result.Cat(Str2);}
+/* friend TCString operator + (const char *Str1, const TCString &Str2)
+ {_ASSERT(Str1 && Str2.pBuf); TCString Result(Str1); return Result.Cat(Str2);}*/
+ TString<T>& operator += (const T *pStr) {_ASSERT(pBuf && pStr); return this->Cat(pStr);}
+ TString<T>& operator += (const T c) {_ASSERT(pBuf); return this->Cat(c);}
+ int operator == (const T *pStr) const {return (!pBuf || !pStr) ? (pBuf == pStr) : !My_lstrcmp(pBuf, pStr);}
+ int operator != (const T *pStr) const {return (!pBuf || !pStr) ? (pBuf != pStr) : My_lstrcmp(pBuf, pStr);}
+ int operator < (const T *pStr) const {_ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) > 0;}
+ int operator > (const T *pStr) const {_ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) < 0;}
+ int operator <= (const T *pStr) const {_ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) >= 0;}
+ int operator >= (const T *pStr) const {_ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) <= 0;}
+// TCString& Format(char *pszFormat, ...);
+
+private:
+ void SetBufSize(int nNewBufSize);
+ void SetAllocSize(int nNewAllocSize);
+
+ T *pBuf;
+ int nBufSize; // current string length + 1 (including 0 at the end)
+ int nAllocSize; // allocated memory size
+};
+
+
+typedef TString<TCHAR> TCString;
+typedef TString<char> CString;
+typedef TString<WCHAR> WCString;
+
+
+/*#define TCString TString<TCHAR>
+#define CString TString<char>
+#define WCString TString<WCHAR>*/
+
+
+__inline CString TCHAR2ANSI(TCString Str)
+{
+#ifdef _UNICODE
+ if (Str == NULL)
+ {
+ return CString();
+ }
+ CString AStr;
+ if (!WideCharToMultiByte(CP_ACP, 0, Str, -1, AStr.GetBuffer(Str.GetLen() + 1), Str.GetLen() + 1, NULL, NULL))
+ {
+ AStr.ReleaseBuffer(0);
+ } else
+ {
+ AStr.ReleaseBuffer(Str.GetLen());
+ }
+ return AStr;
+#else
+ return Str;
+#endif
+}
+
+
+__inline TCString ANSI2TCHAR(CString Str)
+{
+#ifdef _UNICODE
+ if (Str == NULL)
+ {
+ return TCString();
+ }
+ TCString TStr;
+ int Len = MultiByteToWideChar(CP_ACP, 0, Str, -1, NULL, 0);
+ if (!MultiByteToWideChar(CP_ACP, 0, Str, -1, TStr.GetBuffer(Len), Len))
+ {
+ TStr.ReleaseBuffer(0);
+ } else
+ {
+ TStr.ReleaseBuffer(Len - 1);
+ }
+ return TStr;
+#else
+ return Str;
+#endif
+}
+
+
+__inline WCString TCHAR2WCHAR(TCString Str)
+{
+#ifdef _UNICODE
+ return Str;
+#else
+ if (Str == NULL)
+ {
+ return WCString();
+ }
+ WCString WStr;
+ int Len = MultiByteToWideChar(CP_ACP, 0, Str, -1, NULL, 0);
+ if (!MultiByteToWideChar(CP_ACP, 0, Str, -1, WStr.GetBuffer(Len), Len))
+ {
+ WStr.ReleaseBuffer(0);
+ } else
+ {
+ WStr.ReleaseBuffer(Len - 1);
+ }
+ return WStr;
+#endif
+}
+
+
+__inline TCString WCHAR2TCHAR(WCString Str)
+{
+#ifdef _UNICODE
+ return Str;
+#else
+ if (Str == NULL)
+ {
+ return TCString();
+ }
+ CString AStr;
+ if (!WideCharToMultiByte(CP_ACP, 0, Str, -1, AStr.GetBuffer(Str.GetLen() + 1), Str.GetLen() + 1, NULL, NULL))
+ {
+ AStr.ReleaseBuffer(0);
+ } else
+ {
+ AStr.ReleaseBuffer(Str.GetLen());
+ }
+ return AStr;
+#endif
+}
+
+
+#ifdef _UNICODE
+#define WCHAR2ANSI TCHAR2ANSI
+#define ANSI2WCHAR ANSI2TCHAR
+#else
+#define WCHAR2ANSI WCHAR2TCHAR
+#define ANSI2WCHAR TCHAR2WCHAR
+#endif
+
+
+#ifdef CHARARRAY_CONVERT
+
+__inline CHARARRAY WCHAR2ANSI_ARRAY(CHARARRAY &c)
+{
+ CHARARRAY Result;
+ int Len = WideCharToMultiByte(CP_ACP, 0, (WCHAR*)c.GetData(), c.GetSize() / sizeof(WCHAR), NULL, 0, NULL, NULL);
+ if (Len)
+ {
+ Result.SetAtGrow(Len - 1);
+ if (!WideCharToMultiByte(CP_ACP, 0, (WCHAR*)c.GetData(), c.GetSize() / sizeof(WCHAR), Result.GetData(), Len, NULL, NULL))
+ {
+ Result.RemoveAll();
+ }
+ if (Result.GetSize())
+ {
+ Result.RemoveElem(Result.GetSize() - 1); // remove the null terminator
+ }
+ }
+ return Result;
+}
+
+__inline CHARARRAY ANSI2WCHAR_ARRAY(CHARARRAY &c)
+{
+ CHARARRAY Result;
+ int Len = MultiByteToWideChar(CP_ACP, 0, c.GetData(), c.GetSize(), NULL, 0);
+ if (Len)
+ {
+ Result.SetAtGrow(Len * sizeof(WCHAR) - 1);
+ if (!MultiByteToWideChar(CP_ACP, 0, c.GetData(), c.GetSize(), (WCHAR*)Result.GetData(), Len))
+ {
+ Result.RemoveAll();
+ }
+ if (Result.GetSize())
+ {
+ Result.RemoveElem(Result.GetSize() - 1);
+ Result.RemoveElem(Result.GetSize() - 1); // remove the null terminator
+ }
+ }
+ return Result;
+}
+
+#ifdef _UNICODE // utf8 conversion doesn't work on win95
+__inline CHARARRAY WCHAR2UTF8(WCString Str)
+{
+ CHARARRAY Result;
+ int Len = WideCharToMultiByte(CP_UTF8, 0, Str, -1, NULL, 0, NULL, NULL);
+ if (Len)
+ {
+ Result.SetAtGrow(Len - 1);
+ if (!WideCharToMultiByte(CP_UTF8, 0, Str, -1, Result.GetData(), Len, NULL, NULL))
+ {
+ Result.RemoveAll();
+ }
+ }
+ return Result;
+}
+#endif
+
+#endif // CHARARRAY_CONVERT
+
+
+#undef DBGetContactSettingString
+CString DBGetContactSettingString(HANDLE hContact, const char *szModule, const char *szSetting, const char *szDefaultValue);
+TCString DBGetContactSettingString(HANDLE hContact, const char *szModule, const char *szSetting, const TCHAR *szDefaultValue);
+int DBGetContactSettingString(HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv);
+TCString DBGetContactSettingAsString(HANDLE hContact, const char *szModule, const char *szSetting, const TCHAR *szDefaultValue); // also converts numeric values to a string
+
+// various string helpers. their return values are valid only while the class is visible
+class UTF8Encode
+{
+public:
+ UTF8Encode(const char *str) { p = mir_utf8encode(str); }
+ UTF8Encode(const wchar_t *str) { p = mir_utf8encodeW(str); }
+ ~UTF8Encode() { mir_free(p); }
+ operator char*() { return p; }
+
+private:
+ char *p;
+};
+
+class UTF8DecodeA
+{
+public:
+ UTF8DecodeA(const char *str) { p = mir_strdup(str); mir_utf8decode(p, NULL); }
+ ~UTF8DecodeA() { mir_free(p); }
+ operator char*() { return p; }
+
+private:
+ char *p;
+};
+
+class UTF8DecodeW
+{
+public:
+ UTF8DecodeW(const char *str) { p = mir_utf8decodeW(str); }
+ ~UTF8DecodeW() { mir_free(p); }
+ operator wchar_t*() { return p; }
+
+private:
+ wchar_t *p;
+};
+
+#ifdef _UNICODE
+#define UTF8Decode UTF8DecodeW
+#else
+#define UTF8Decode UTF8DecodeA
+#endif
+
+
+/*class mallocStrA
+{
+public:
+ mallocStrA(int n) { p = (char*)malloc((n + 1) * sizeof(char)); }
+ mallocStrA(const char *str) { p = str ? strdup(str) : NULL; }
+ ~mallocStrA() { if (p) free(p); }
+ operator char*() { return p; }
+
+private:
+ char *p;
+};
+
+class mallocStrW
+{
+public:
+ mallocStrW(int n) { p = (wchar_t*)malloc((n + 1) * sizeof(wchar_t)); }
+ mallocStrW(const wchar_t *str) { p = str ? _wcsdup(str) : NULL; }
+ ~mallocStrW() { if (p) free(p); }
+ operator wchar_t*() { return p; }
+
+private:
+ wchar_t *p;
+};
+
+#ifdef _UNICODE
+#define mallocStr mallocStrW
+#else
+#define mallocStr mallocStrA
+#endif
+*/ \ No newline at end of file
diff --git a/plugins/NewAwaySysMod/CommonLibs/GroupCheckbox.cpp b/plugins/NewAwaySysMod/CommonLibs/GroupCheckbox.cpp
new file mode 100644
index 0000000000..3add46753e
--- /dev/null
+++ b/plugins/NewAwaySysMod/CommonLibs/GroupCheckbox.cpp
@@ -0,0 +1,407 @@
+/*
+ GroupCheckbox.cpp
+ Copyright (c) 2007 Chervov Dmitry
+
+ 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 "GroupCheckbox.h"
+#include "Themes.h"
+
+#define WM_THEMECHANGED 0x031A
+
+#define UM_INITCHECKBOX (WM_USER + 123)
+#define UM_AUTOSIZE (WM_USER + 124)
+
+#define CG_CHECKBOX_VERTINDENT 0
+#define CG_CHECKBOX_INDENT 1
+#define CG_CHECKBOX_WIDTH 16
+#define CG_TEXT_INDENT 2
+#define CG_ADDITIONAL_WIDTH 3
+
+// states
+#define CGS_UNCHECKED BST_UNCHECKED
+#define CGS_CHECKED BST_CHECKED
+#define CGS_INDETERMINATE BST_INDETERMINATE
+#define CGS_PRESSED BST_PUSHED // values above and including CGS_PRESSED must coincide with BST_ constants for BM_GETSTATE to work properly
+#define CGS_HOVERED 8
+
+// state masks
+#define CGSM_ISCHECKED 3 // mask for BM_GETCHECK
+#define CGSM_GETSTATE 7 // mask to get only valid values for BM_GETSTATE
+
+#ifndef lengthof
+#define lengthof(s) (sizeof(s) / sizeof(*s))
+#endif
+
+class CCheckboxData
+{
+public:
+ CCheckboxData(): OldWndProc(NULL), Style(0), State(0), hFont(NULL) {};
+
+ WNDPROC OldWndProc;
+ int Style; // BS_CHECKBOX, BS_AUTOCHECKBOX, BS_3STATE or BS_AUTO3STATE
+ int State;
+ HFONT hFont;
+};
+
+static int CALLBACK CheckboxWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ CCheckboxData *dat = (CCheckboxData*)GetWindowLong(hWnd, GWL_USERDATA);
+ if (!dat)
+ {
+ return 0;
+ }
+ switch (Msg)
+ {
+ case UM_INITCHECKBOX:
+ {
+ LOGFONT lf;
+ HFONT hFont = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0);
+ if (!hFont)
+ {
+ hFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
+ }
+ GetObject(hFont, sizeof(lf), &lf);
+ lf.lfWeight = FW_BOLD;
+ dat->hFont = CreateFontIndirect(&lf);
+ SendMessage(hWnd, UM_AUTOSIZE, 0, 0);
+ return 0;
+ } break;
+ case UM_AUTOSIZE:
+ {
+ HTHEME hTheme = pOpenThemeData ? pOpenThemeData(hWnd, L"BUTTON") : NULL;
+ int Len = GetWindowTextLength(hWnd) + 1;
+ HDC hdc = GetDC(hWnd);
+ HFONT hOldFont = (HFONT)SelectObject(hdc, dat->hFont);
+ RECT rcText = {0};
+ if (hTheme && pGetThemeTextExtent)
+ {
+ WCHAR *szText = (WCHAR*)malloc(Len * sizeof(WCHAR));
+ GetWindowTextW(hWnd, szText, Len);
+ pGetThemeTextExtent(hTheme, hdc, BP_GROUPBOX, IsWindowEnabled(hWnd) ? GBS_NORMAL : GBS_DISABLED, szText, -1, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE, 0, &rcText);
+ free(szText);
+ } else
+ {
+ SIZE size;
+ TCHAR *szText = (TCHAR*)malloc(Len * sizeof(TCHAR));
+ GetWindowText(hWnd, szText, Len);
+ GetTextExtentPoint32(hdc, szText, lstrlen(szText), &size);
+ free(szText);
+ rcText.right = size.cx;
+ rcText.bottom = size.cy;
+ }
+
+ SelectObject(hdc, hOldFont);
+ ReleaseDC(hWnd, hdc);
+ if (hTheme && pCloseThemeData)
+ {
+ pCloseThemeData(hTheme);
+ }
+ OffsetRect(&rcText, CG_CHECKBOX_INDENT + CG_CHECKBOX_WIDTH + CG_TEXT_INDENT, 0);
+ RECT rc;
+ GetClientRect(hWnd, &rc);
+ SetWindowPos(hWnd, 0, 0, 0, rcText.right + CG_ADDITIONAL_WIDTH, rc.bottom, SWP_NOMOVE | SWP_NOZORDER);
+ } break;
+ case BM_CLICK:
+ {
+ SendMessage(hWnd, WM_LBUTTONDOWN, 0, 0);
+ SendMessage(hWnd, WM_LBUTTONUP, 0, 0);
+ return 0;
+ } break;
+ case BM_GETCHECK:
+ {
+ return dat->State & CGSM_ISCHECKED;
+ } break;
+ case BM_SETCHECK:
+ {
+ if ((wParam != BST_UNCHECKED && wParam != BST_CHECKED && wParam != BST_INDETERMINATE) || (wParam == BST_INDETERMINATE && dat->Style != BS_3STATE && dat->Style != BS_AUTO3STATE))
+ { // invalid value
+ wParam = BST_CHECKED;
+ }
+ dat->State &= ~CGSM_ISCHECKED;
+ dat->State |= wParam;
+ InvalidateRect(hWnd, NULL, false);
+ SendMessage(GetParent(hWnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hWnd), BN_CLICKED), (LPARAM)hWnd);
+ return 0;
+ } break;
+ case BM_SETSTATE:
+ {
+ if (wParam)
+ {
+ dat->State |= CGS_PRESSED;
+ } else
+ {
+ dat->State &= ~CGS_PRESSED;
+ }
+ InvalidateRect(hWnd, NULL, false);
+ return 0;
+ } break;
+ case BM_GETSTATE:
+ {
+ return (dat->State & CGSM_GETSTATE) | ((GetFocus() == hWnd) ? BST_FOCUS : 0);
+ } break;
+ case WM_GETDLGCODE:
+ {
+ return DLGC_BUTTON;
+ } break;
+ case WM_THEMECHANGED:
+ case WM_ENABLE:
+ {
+ InvalidateRect(hWnd, NULL, false);
+ return 0;
+ } break;
+ case WM_SETTEXT:
+ {
+ if (CallWindowProc(dat->OldWndProc, hWnd, Msg, wParam, lParam))
+ {
+ SendMessage(hWnd, UM_AUTOSIZE, 0, 0);
+ }
+ return 0;
+ } break;
+ case WM_KEYDOWN:
+ {
+ if (wParam == VK_SPACE)
+ {
+ SendMessage(hWnd, BM_SETSTATE, true, 0);
+ }
+ return 0;
+ } break;
+ case WM_KEYUP:
+ {
+ if (wParam == VK_SPACE)
+ {
+ SendMessage(hWnd, BM_SETCHECK, (SendMessage(hWnd, BM_GETCHECK, 0, 0) + 1) % ((dat->Style == BS_AUTO3STATE) ? 3 : 2), 0);
+ SendMessage(hWnd, BM_SETSTATE, false, 0);
+ }
+ return 0;
+ } break;
+ case WM_CAPTURECHANGED:
+ {
+ SendMessage(hWnd, BM_SETSTATE, false, 0);
+ return 0;
+ } break;
+ case WM_ERASEBKGND:
+ {
+ return true;
+ } break;
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ {
+ SetFocus(hWnd);
+ SendMessage(hWnd, BM_SETSTATE, true, 0);
+ SetCapture(hWnd);
+ return 0;
+ } break;
+ case WM_LBUTTONUP:
+ {
+ if (GetCapture() == hWnd)
+ {
+ ReleaseCapture();
+ }
+ SendMessage(hWnd, BM_SETSTATE, false, 0);
+ if (dat->State & CGS_HOVERED && (dat->Style == BS_AUTOCHECKBOX || dat->Style == BS_AUTO3STATE))
+ {
+ SendMessage(hWnd, BM_SETCHECK, (SendMessage(hWnd, BM_GETCHECK, 0, 0) + 1) % ((dat->Style == BS_AUTO3STATE) ? 3 : 2), 0);
+ }
+ return 0;
+ } break;
+ case WM_MOUSEMOVE:
+ {
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = TME_LEAVE;
+ tme.dwHoverTime = HOVER_DEFAULT;
+ tme.hwndTrack = hWnd;
+ _TrackMouseEvent(&tme);
+
+ POINT pt;
+ GetCursorPos(&pt);
+ if ((WindowFromPoint(pt) == hWnd) ^ ((dat->State & CGS_HOVERED) != 0))
+ {
+ dat->State ^= CGS_HOVERED;
+ InvalidateRect(hWnd, NULL, false);
+ }
+ return 0;
+ } break;
+ case WM_MOUSELEAVE:
+ {
+ if (dat->State & CGS_HOVERED)
+ {
+ dat->State &= ~CGS_HOVERED;
+ InvalidateRect(hWnd, NULL, false);
+ }
+ return 0;
+ } break;
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ case WM_SYSCOLORCHANGE:
+ {
+ InvalidateRect(hWnd, NULL, false);
+ return 0;
+ } break;
+ case WM_PAINT:
+ {
+ HDC hdc;
+ PAINTSTRUCT ps;
+ hdc = BeginPaint(hWnd, &ps);
+ RECT rc;
+ GetClientRect(hWnd, &rc);
+ HDC hdcMem = CreateCompatibleDC(hdc);
+ HBITMAP hbmMem = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
+ HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
+ HTHEME hTheme = pOpenThemeData ? pOpenThemeData(hWnd, L"BUTTON") : NULL;
+ if (hTheme && pDrawThemeParentBackground)
+ {
+ pDrawThemeParentBackground(hWnd, hdcMem, NULL);
+ } else
+ {
+ FillRect(hdcMem, &rc, GetSysColorBrush(COLOR_3DFACE));
+ }
+ int StateID = 0;
+#define CBSCHECK_UNCHECKED 1
+#define CBSCHECK_CHECKED 5
+#define CBSCHECK_MIXED 9
+#define CBSSTATE_NORMAL 0
+#define CBSSTATE_HOT 1
+#define CBSSTATE_PRESSED 2
+#define CBSSTATE_DISABLED 3
+ switch (SendMessage(hWnd, BM_GETCHECK, 0, 0))
+ {
+ case BST_CHECKED:
+ {
+ StateID += CBSCHECK_CHECKED;
+ } break;
+ case BST_UNCHECKED:
+ {
+ StateID += CBSCHECK_UNCHECKED;
+ } break;
+ case BST_INDETERMINATE:
+ {
+ StateID += CBSCHECK_MIXED;
+ } break;
+ }
+ if (!IsWindowEnabled(hWnd))
+ {
+ StateID += CBSSTATE_DISABLED;
+ } else if (dat->State & CGS_PRESSED && (GetCapture() != hWnd || dat->State & CGS_HOVERED))
+ {
+ StateID += CBSSTATE_PRESSED;
+ } else if (dat->State & CGS_PRESSED || dat->State & CGS_HOVERED)
+ {
+ StateID += CBSSTATE_HOT;
+ }
+ rc.left += CG_CHECKBOX_INDENT;
+ rc.right = rc.left + CG_CHECKBOX_WIDTH; // left-align the image in the client area
+ rc.top += CG_CHECKBOX_VERTINDENT;
+ rc.bottom = rc.top + CG_CHECKBOX_WIDTH; // exact rc dimensions are necessary for DrawFrameControl to draw correctly
+ if (hTheme && pDrawThemeBackground)
+ {
+ pDrawThemeBackground(hTheme, hdcMem, BP_CHECKBOX, StateID, &rc, &rc);
+ } else
+ {
+ int dfcStates[] =
+ {0, 0, DFCS_PUSHED, DFCS_INACTIVE,
+ DFCS_CHECKED, DFCS_CHECKED, DFCS_CHECKED | DFCS_PUSHED, DFCS_CHECKED | DFCS_INACTIVE,
+ DFCS_BUTTON3STATE | DFCS_CHECKED, DFCS_BUTTON3STATE | DFCS_CHECKED, DFCS_BUTTON3STATE | DFCS_INACTIVE | DFCS_CHECKED | DFCS_PUSHED, DFCS_BUTTON3STATE | DFCS_INACTIVE | DFCS_CHECKED | DFCS_PUSHED};
+ _ASSERT(StateID >= 1 && StateID <= lengthof(dfcStates));
+ DrawFrameControl(hdcMem, &rc, DFC_BUTTON, dfcStates[StateID - 1]);
+ }
+
+ GetClientRect(hWnd, &rc);
+ rc.left += CG_CHECKBOX_INDENT + CG_CHECKBOX_WIDTH + CG_TEXT_INDENT;
+ int Len = GetWindowTextLength(hWnd) + 1;
+ WCHAR *szTextW = NULL;
+ TCHAR *szTextT = NULL;
+ if (hTheme && pDrawThemeText && pGetThemeTextExtent)
+ {
+ szTextW = (WCHAR*)malloc(Len * sizeof(WCHAR));
+ GetWindowTextW(hWnd, szTextW, Len);
+ } else
+ {
+ szTextT = (TCHAR*)malloc(Len * sizeof(TCHAR));
+ GetWindowText(hWnd, szTextT, Len);
+ }
+ HFONT hOldFont = (HFONT)SelectObject(hdcMem, dat->hFont);
+ SetBkMode(hdcMem, TRANSPARENT);
+ if (hTheme && pDrawThemeText && pGetThemeTextExtent)
+ {
+ pDrawThemeText(hTheme, hdcMem, BP_GROUPBOX, IsWindowEnabled(hWnd) ? GBS_NORMAL : GBS_DISABLED, szTextW, -1, DT_LEFT | DT_VCENTER | DT_SINGLELINE, 0, &rc);
+ } else
+ {
+ DrawText(hdcMem, szTextT, -1, &rc, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
+ }
+ if (GetFocus() == hWnd)
+ {
+ RECT rcText = {0};
+ if (hTheme && pDrawThemeText && pGetThemeTextExtent)
+ {
+ pGetThemeTextExtent(hTheme, hdcMem, BP_GROUPBOX, IsWindowEnabled(hWnd) ? GBS_NORMAL : GBS_DISABLED, szTextW, -1, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE, 0, &rcText);
+ } else
+ {
+ SIZE size;
+ GetTextExtentPoint32(hdcMem, szTextT, lstrlen(szTextT), &size);
+ rcText.right = size.cx;
+ rcText.bottom = size.cy;
+ }
+ rcText.bottom = rc.bottom;
+ OffsetRect(&rcText, rc.left, 0);
+ InflateRect(&rcText, 1, -1);
+ DrawFocusRect(hdcMem, &rcText);
+ }
+ free((hTheme && pDrawThemeText && pGetThemeTextExtent) ? (TCHAR*)szTextW : szTextT);
+ SelectObject(hdcMem, hOldFont);
+ if (hTheme && pCloseThemeData)
+ {
+ pCloseThemeData(hTheme);
+ }
+ BitBlt(hdc, 0, 0, rc.right, rc.bottom, hdcMem, 0, 0, SRCCOPY);
+ SelectObject(hdcMem, hbmOld);
+ DeleteObject(hbmMem);
+ DeleteDC(hdcMem);
+ EndPaint(hWnd, &ps);
+ return 0;
+ } break;
+ case WM_DESTROY:
+ {
+ if (dat->hFont)
+ {
+ DeleteObject(dat->hFont);
+ }
+ SetWindowLong(hWnd, GWL_USERDATA, NULL);
+ CallWindowProc(dat->OldWndProc, hWnd, Msg, wParam, lParam);
+ delete dat;
+ return 0;
+ } break;
+ }
+ return CallWindowProc(dat->OldWndProc, hWnd, Msg, wParam, lParam);
+}
+
+int MakeGroupCheckbox(HWND hWndCheckbox)
+{ // workaround to make SetTextColor work in WM_CTLCOLORSTATIC with windows themes enabled
+ CCheckboxData *dat = new CCheckboxData();
+ dat->OldWndProc = (WNDPROC)GetWindowLong(hWndCheckbox, GWL_WNDPROC);
+ dat->State = SendMessage(hWndCheckbox, BM_GETSTATE, 0, 0);
+ long Style = GetWindowLong(hWndCheckbox, GWL_STYLE);
+ dat->Style = Style & (BS_CHECKBOX | BS_AUTOCHECKBOX | BS_3STATE | BS_AUTO3STATE);
+ _ASSERT(dat->Style == BS_CHECKBOX || dat->Style == BS_AUTOCHECKBOX || dat->Style == BS_3STATE || dat->Style == BS_AUTO3STATE);
+ Style &= ~(BS_CHECKBOX | BS_AUTOCHECKBOX | BS_3STATE | BS_AUTO3STATE);
+ Style |= BS_OWNERDRAW;
+ SetWindowLong(hWndCheckbox, GWL_STYLE, Style);
+ SetWindowLong(hWndCheckbox, GWL_USERDATA, (LONG)dat);
+ SetWindowLong(hWndCheckbox, GWL_WNDPROC, (LONG)CheckboxWndProc);
+ SendMessage(hWndCheckbox, UM_INITCHECKBOX, 0, 0);
+ return 0;
+}
diff --git a/plugins/NewAwaySysMod/CommonLibs/GroupCheckbox.h b/plugins/NewAwaySysMod/CommonLibs/GroupCheckbox.h
new file mode 100644
index 0000000000..3aa121f869
--- /dev/null
+++ b/plugins/NewAwaySysMod/CommonLibs/GroupCheckbox.h
@@ -0,0 +1,26 @@
+/*
+ GroupCheckbox.h
+ Copyright (c) 2007 Chervov Dmitry
+
+ 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
+
+#include <windows.h>
+#include <crtdbg.h>
+#include <commctrl.h>
+
+int MakeGroupCheckbox(HWND hWndCheckbox);
diff --git a/plugins/NewAwaySysMod/CommonLibs/Options.cpp b/plugins/NewAwaySysMod/CommonLibs/Options.cpp
new file mode 100644
index 0000000000..0de5c1617a
--- /dev/null
+++ b/plugins/NewAwaySysMod/CommonLibs/Options.cpp
@@ -0,0 +1,984 @@
+/*
+ Options.cpp
+ Copyright (c) 2005-2008 Chervov Dmitry
+
+ 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 "Options.h"
+
+static CString sEmptyString("");
+
+
+COptPage::COptPage(const COptPage &Item)
+{
+ *this = Item;
+}
+
+COptPage::~COptPage()
+{
+ int I;
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ delete Items[I];
+ }
+ Items.RemoveAll();
+}
+
+void COptPage::MemToPage(int OnlyEnable)
+{
+ int I;
+ _ASSERT(hWnd);
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ if (OnlyEnable)
+ {
+ Items[I]->COptItem::MemToWnd(hWnd);
+ } else
+ {
+ Items[I]->MemToWnd(hWnd);
+ }
+ }
+}
+
+void COptPage::PageToMem()
+{
+ int I;
+ _ASSERT(hWnd);
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ Items[I]->WndToMem(hWnd);
+ }
+}
+
+void COptPage::DBToMem()
+{
+ int I;
+ _ASSERT(sModule != "");
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ Items[I]->DBToMem(sModule, &sDBSettingPrefix);
+ }
+}
+
+void COptPage::MemToDB()
+{
+ int I;
+ _ASSERT(sModule != "");
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ Items[I]->MemToDB(sModule, &sDBSettingPrefix);
+ }
+}
+
+void COptPage::CleanDBSettings()
+{
+ int I;
+ _ASSERT(sModule != "");
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ Items[I]->CleanDBSettings(sModule, &sDBSettingPrefix);
+ }
+}
+
+bool COptPage::GetModified()
+{
+ int I;
+ _ASSERT(sModule != "");
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ if (Items[I]->GetModified())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void COptPage::SetModified(bool Modified)
+{
+ int I;
+ _ASSERT(sModule != "");
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ Items[I]->SetModified(Modified);
+ }
+}
+
+COptItem *COptPage::Find(int DlgItemID)
+{
+ int I;
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ if (Items[I]->GetID() == DlgItemID)
+ {
+ return Items[I];
+ }
+ }
+ _ASSERT(0);
+ return 0;
+}
+
+COptPage& COptPage::operator = (const COptPage& Page)
+{
+ int I;
+ hWnd = Page.hWnd;
+ sModule = Page.sModule;
+ sDBSettingPrefix = Page.sDBSettingPrefix;
+ Items.RemoveAll();
+ for (I = 0; I < Page.Items.GetSize(); I++)
+ {
+ Items.AddElem(Page.Items[I]->Copy());
+ }
+ return *this;
+}
+
+
+int COptItem::GetIntDBVal(CString &sModule, int bSigned, CString *sDBSettingPrefix)
+{ // default procedure for reading value from DB; used only for integral types
+ if (sDBSetting != NULL)
+ {
+ _ASSERT(nValueSize == DBVT_BYTE || nValueSize == DBVT_WORD || nValueSize == DBVT_DWORD);
+ DBVARIANT dbv;
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule = sModule;
+ //NightFox: WTF is this shit
+ //cgs.szSetting = sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting;
+ cgs.szSetting = sDBSetting;
+ cgs.pValue = &dbv;
+ if (CallService(MS_DB_CONTACT_GETSETTING, NULL, (LPARAM)&cgs))
+ {
+ return GetDefValue();
+ }
+ return (nValueSize == DBVT_BYTE) ? (bSigned ? (signed char)dbv.bVal : (unsigned char)dbv.bVal) : ((nValueSize == DBVT_WORD) ? (bSigned ? (signed short)dbv.wVal : (unsigned short)dbv.wVal) : dbv.dVal);
+ }
+ return GetDefValue();
+}
+
+void COptItem::SetIntDBVal(CString &sModule, int Value, CString *sDBSettingPrefix)
+{ // default procedure for writing value to the DB; used only for integral types
+ if (sDBSetting != NULL && !ReadOnly)
+ {
+ _ASSERT(nValueSize == DBVT_BYTE || nValueSize == DBVT_WORD || nValueSize == DBVT_DWORD);
+ DBCONTACTWRITESETTING cws;
+ cws.szModule = sModule;
+ //NightFox: WTF is this shit
+ //cws.szSetting = sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting;
+ cws.szSetting = sDBSetting;
+
+ cws.value.type = nValueSize;
+ cws.value.dVal = Value;
+
+// DBWriteContactSettingByte(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_FLAGS + StrID, Value[I].Flags);
+
+ //itoa(Value[I].ID, StrID.GetBuffer(64), 10);
+ //StrID.ReleaseBuffer();
+
+ CallService(MS_DB_CONTACT_WRITESETTING, NULL, (LPARAM)&cws);
+
+ }
+}
+
+TCString COptItem::GetStrDBVal(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (sDBSetting != NULL)
+ {
+ _ASSERT(GetDefValue());
+ return DBGetContactSettingString(NULL, sModule, sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting, *(TCString*)GetDefValue());
+ }
+ return *(TCString*)GetDefValue();
+}
+
+void COptItem::SetStrDBVal(CString &sModule, TCString &Str, CString *sDBSettingPrefix)
+{
+ if (sDBSetting != NULL && !ReadOnly)
+ {
+ DBWriteContactSettingTString(NULL, sModule, sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting, Str);
+ }
+}
+
+
+
+void COptItem_Checkbox::DBToMem(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (ValueMask)
+ {
+ Value = (GetIntDBVal(sModule, false, sDBSettingPrefix) & ValueMask) ? BST_CHECKED : BST_UNCHECKED;
+ } else
+ {
+ Value = GetIntDBVal(sModule, false, sDBSettingPrefix);
+ }
+ COptItem::DBToMem(sModule, sDBSettingPrefix);
+}
+
+void COptItem_Checkbox::MemToDB(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (ValueMask)
+ {
+ if (Value == BST_CHECKED)
+ {
+ SetIntDBVal(sModule, GetIntDBVal(sModule, false, sDBSettingPrefix) | ValueMask, sDBSettingPrefix);
+ } else
+ {
+ SetIntDBVal(sModule, GetIntDBVal(sModule, false, sDBSettingPrefix) & ~ValueMask, sDBSettingPrefix);
+ }
+ } else
+ {
+ SetIntDBVal(sModule, Value, sDBSettingPrefix);
+ }
+ COptItem::MemToDB(sModule, sDBSettingPrefix);
+}
+
+void COptItem_Checkbox::WndToMem(HWND hWnd)
+{
+ Value = IsDlgButtonChecked(hWnd, DlgItemID);
+// tri-state checkboxes in combination with ValueMask != 0 are not supported ;)
+ _ASSERT(!ValueMask || Value != BST_INDETERMINATE);
+ COptItem::WndToMem(hWnd);
+}
+
+void COptItem_Checkbox::MemToWnd(HWND hWnd)
+{
+ CheckDlgButton(hWnd, DlgItemID, Value);
+ COptItem::MemToWnd(hWnd);
+}
+
+
+
+void COptItem_BitDBSetting::DBToMem(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (ValueMask)
+ {
+ Value = (GetIntDBVal(sModule, false, sDBSettingPrefix) & ValueMask) != 0;
+ } else
+ {
+ Value = GetIntDBVal(sModule, false, sDBSettingPrefix);
+ }
+ COptItem::DBToMem(sModule, sDBSettingPrefix);
+}
+
+void COptItem_BitDBSetting::MemToDB(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (ValueMask)
+ {
+ if (Value)
+ {
+ SetIntDBVal(sModule, GetIntDBVal(sModule, false, sDBSettingPrefix) | ValueMask, sDBSettingPrefix);
+ } else
+ {
+ SetIntDBVal(sModule, GetIntDBVal(sModule, false, sDBSettingPrefix) & ~ValueMask, sDBSettingPrefix);
+ }
+ } else
+ {
+ SetIntDBVal(sModule, Value, sDBSettingPrefix);
+ }
+ COptItem::MemToDB(sModule, sDBSettingPrefix);
+}
+
+
+// ================================================ COptItem_TreeCtrl ================================================
+
+int COptItem_TreeCtrl::IDToOrder(int ID)
+{
+ int I;
+ for (I = 0; I < RootItems.GetSize(); I++)
+ {
+ if (RootItems[I].ID == ID)
+ {
+ return ROOT_INDEX_TO_ORDER(I);
+ }
+ }
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ if (Value[I].ID == ID)
+ {
+ return I;
+ }
+ }
+ return -1;
+}
+
+int COptItem_TreeCtrl::hItemToOrder(HTREEITEM hItem)
+{
+ int I;
+ for (I = 0; I < RootItems.GetSize(); I++)
+ {
+ if (RootItems[I].hItem == hItem)
+ {
+ return ROOT_INDEX_TO_ORDER(I);
+ }
+ }
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ if (Value[I].hItem == hItem)
+ {
+ return I;
+ }
+ }
+ return -1;
+}
+
+int COptItem_TreeCtrl::GenerateID()
+{
+ int ID = 0;
+ while (IDToOrder(ID) != -1)
+ {
+ ID++;
+ }
+ return ID;
+}
+
+typedef struct
+{
+ COptItem_TreeCtrl *TreeCtrl;
+ CString *sModule;
+ CString *sDBSettingPrefix;
+} sTreeReadEnumData;
+
+int TreeReadEnum(const char *szSetting, LPARAM lParam)
+{
+ sTreeReadEnumData *TreeReadEnumData = (sTreeReadEnumData*)lParam;
+ int Len = TreeReadEnumData->TreeCtrl->sDBSetting.GetLen() + lengthof(TREEITEM_DBSTR_TITLE) - 1;
+ if (!strncmp(szSetting, TreeReadEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_TITLE, Len) && isdigit(szSetting[Len]))
+ {
+ int ID = atol(szSetting + Len);
+ short ParentID = (TreeReadEnumData->TreeCtrl->TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL) ? 0 : DBGetContactSettingWord(NULL, *TreeReadEnumData->sModule,
+ *TreeReadEnumData->sDBSettingPrefix + TreeReadEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_PARENT + (szSetting + Len), -1);
+ short Order = DBGetContactSettingWord(NULL, *TreeReadEnumData->sModule,
+ *TreeReadEnumData->sDBSettingPrefix + TreeReadEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_ORDER + (szSetting + Len), -1);
+ char Flags = (TreeReadEnumData->TreeCtrl->TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL && !(TreeReadEnumData->TreeCtrl->TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES)) ? 0 : DBGetContactSettingByte(NULL, *TreeReadEnumData->sModule,
+ *TreeReadEnumData->sDBSettingPrefix + TreeReadEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_FLAGS + (szSetting + Len), 0);
+ if (ParentID >= 0 && Order >= 0)
+ {
+ TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).ID = ID;
+ TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).ParentID = ParentID;
+ TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).Flags = Flags;
+ TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).hItem = NULL;
+ TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).Title = DBGetContactSettingString(NULL, *TreeReadEnumData->sModule, *TreeReadEnumData->sDBSettingPrefix + szSetting, _T(""));
+ TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).User_Str1 = (TreeReadEnumData->TreeCtrl->User_Str1_DBName == NULL) ? NULL :
+ DBGetContactSettingString(NULL, *TreeReadEnumData->sModule,
+ *TreeReadEnumData->sDBSettingPrefix + TreeReadEnumData->TreeCtrl->sDBSetting + TreeReadEnumData->TreeCtrl->User_Str1_DBName + (szSetting + Len), (TCHAR*)NULL);
+ }
+ }
+ return 0;
+}
+
+void COptItem_TreeCtrl::DBToMem(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (!sDBSettingPrefix)
+ {
+ sDBSettingPrefix = &sEmptyString;
+ }
+ Value.RemoveAll();
+ sTreeReadEnumData TreeReadEnumData;
+ TreeReadEnumData.TreeCtrl = this;
+ TreeReadEnumData.sModule = &sModule;
+ TreeReadEnumData.sDBSettingPrefix = sDBSettingPrefix;
+ DBCONTACTENUMSETTINGS dbEnum;
+ dbEnum.lParam = (LPARAM)&TreeReadEnumData;
+ dbEnum.ofsSettings = 0;
+ dbEnum.pfnEnumProc = TreeReadEnum;
+ dbEnum.szModule = sModule;
+ CallService(MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbEnum);
+ if (!Value.GetSize())
+ {
+ Value = DefValue;
+ } else
+ {
+ int I;
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ if (Value[I].Title == NULL)
+ {
+ Value.RemoveElem(I);
+ I--;
+ }
+ }
+ }
+ COptItem::DBToMem(sModule, sDBSettingPrefix);
+}
+
+void COptItem_TreeCtrl::MemToDB(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (!ReadOnly && Modified)
+ {
+ if (!sDBSettingPrefix)
+ {
+ sDBSettingPrefix = &sEmptyString;
+ }
+ CleanDBSettings(sModule, sDBSettingPrefix);
+ int I;
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ CString StrID;
+ itoa(Value[I].ID, StrID.GetBuffer(64), 10);
+ StrID.ReleaseBuffer();
+ DBWriteContactSettingTString(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_TITLE + StrID, Value[I].Title);
+ if (!(TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL))
+ {
+ DBWriteContactSettingWord(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_PARENT + StrID, Value[I].ParentID);
+ }
+ DBWriteContactSettingWord(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_ORDER + StrID, I);
+ if (!(TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL) || TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES)
+ {
+ DBWriteContactSettingByte(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_FLAGS + StrID, Value[I].Flags);
+ }
+ if (User_Str1_DBName != NULL && Value[I].User_Str1 != NULL)
+ {
+ DBWriteContactSettingTString(NULL, sModule, *sDBSettingPrefix + sDBSetting + User_Str1_DBName + StrID, Value[I].User_Str1);
+ }
+ }
+ COptItem::MemToDB(sModule, sDBSettingPrefix);
+ }
+}
+
+void COptItem_TreeCtrl::WndToMem(HWND hWnd)
+{ // only need to gather info of items state (expanded/collapsed, checked/unchecked)
+ HWND hTreeView = GetDlgItem(hWnd, DlgItemID);
+ int I;
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ DWORD State = TreeView_GetItemState(hTreeView, Value[I].hItem, TVIS_EXPANDED | TVIS_STATEIMAGEMASK);
+ int OldFlags = Value[I].Flags;
+ if (State & TVIS_EXPANDED)
+ {
+ Value[I].Flags |= TIF_EXPANDED;
+ } else
+ {
+ Value[I].Flags &= ~TIF_EXPANDED;
+ }
+ if (TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES && (State >> 12) - 1)
+ {
+ Value[I].Flags |= TIF_ENABLED;
+ } else
+ {
+ Value[I].Flags &= ~TIF_ENABLED;
+ }
+ if (Value[I].Flags != OldFlags)
+ {
+ Modified = true;
+ }
+ }
+ COptItem::WndToMem(hWnd);
+}
+
+void COptItem_TreeCtrl::MemToWnd(HWND hWnd)
+{
+ HWND hTreeView = GetDlgItem(hWnd, DlgItemID);
+ if (TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES)
+ { // have to set this in run-time as it's specified in MSDN
+ LONG Style = GetWindowLong(hTreeView, GWL_STYLE);
+ SetWindowLong(hTreeView, GWL_STYLE, Style & ~TVS_CHECKBOXES);
+ SetWindowLong(hTreeView, GWL_STYLE, Style | TVS_CHECKBOXES);
+ }
+ TVINSERTSTRUCT tvIn = {0};
+ int ScrollPos = GetScrollPos(hTreeView, SB_VERT);
+ int SelectOrder = IDToOrder(GetSelectedItemID(hWnd));
+ SendMessage(hTreeView, WM_SETREDRAW, false, 0);
+ TreeView_DeleteAllItems(hTreeView);
+ _ASSERT(RootItems.GetSize());
+ int I;
+ if (!(TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL))
+ {
+ for (I = 0; I < RootItems.GetSize(); I++)
+ {
+ tvIn.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ RootItems[I].Flags |= TIF_GROUP;
+ tvIn.item.state = tvIn.item.stateMask = TVIS_BOLD | ((RootItems[I].Flags & TIF_EXPANDED) ? TVIS_EXPANDED : 0);
+ tvIn.item.pszText = RootItems[I].Title;
+ tvIn.hParent = TVI_ROOT;
+ tvIn.hInsertAfter = TVI_LAST;
+ tvIn.item.lParam = RootItems[I].ID;
+ RootItems[I].hItem = TreeView_InsertItem(hTreeView, &tvIn);
+ }
+ }
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ Value[I].hItem = RootItems[0].hItem; // put an item to first group in case of some strange error
+ }
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ tvIn.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvIn.item.state = tvIn.item.stateMask = (Value[I].Flags & TIF_GROUP) ? (TVIS_BOLD | ((Value[I].Flags & TIF_EXPANDED) ? TVIS_EXPANDED : 0)) : 0;
+ if (TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES)
+ {
+ tvIn.item.stateMask |= TVIS_STATEIMAGEMASK;
+ tvIn.item.state |= INDEXTOSTATEIMAGEMASK((Value[I].Flags & TIF_ENABLED) ? 2 : 1);
+ }
+ tvIn.item.pszText = Value[I].Title;
+ int Order = IDToOrder(Value[I].ParentID);
+ if (Order != -1)
+ {
+ tvIn.hParent = (Order <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(Order)].hItem : Value[Order].hItem;
+ tvIn.hInsertAfter = TVI_LAST;
+ tvIn.item.lParam = Value[I].ID;
+ Value[I].hItem = TreeView_InsertItem(hTreeView, &tvIn);
+ } else
+ { // found an orphan item; probably it's better just to delete it
+ Value.RemoveElem(I);
+ I--;
+ }
+ }
+ TreeView_SelectItem(hTreeView, (SelectOrder >= 0) ? Value[SelectOrder].hItem : ((SelectOrder <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(SelectOrder)].hItem : NULL));
+ SendMessage(hTreeView, WM_SETREDRAW, true, 0);
+ SCROLLBARINFO sbi;
+ sbi.cbSize = sizeof(sbi);
+ GetScrollBarInfo(hTreeView, OBJID_VSCROLL, &sbi);
+ if (!(sbi.rgstate[0] & STATE_SYSTEM_INVISIBLE))
+ {
+ int MinPos, MaxPos;
+ GetScrollRange(hTreeView, SB_VERT, &MinPos, &MaxPos);
+ if (ScrollPos < MinPos)
+ {
+ ScrollPos = MinPos;
+ } else if (ScrollPos > MaxPos)
+ {
+ ScrollPos = MaxPos;
+ }
+ SetScrollPos(hTreeView, SB_VERT, ScrollPos, true);
+ }
+ COptItem::MemToWnd(hWnd);
+}
+
+
+typedef struct
+{
+ TMyArray<CString> TreeSettings;
+ COptItem_TreeCtrl *TreeCtrl;
+ CString *sDBSettingPrefix;
+} sTreeDeleteEnumData;
+
+int TreeDeleteEnum(const char *szSetting, LPARAM lParam)
+{
+ sTreeDeleteEnumData *TreeDeleteEnumData = (sTreeDeleteEnumData*)lParam;
+ CString CurSetting;
+ CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_TITLE;
+ if (!strncmp(szSetting, CurSetting, CurSetting.GetLen()))
+ {
+ TreeDeleteEnumData->TreeSettings.AddElem(szSetting);
+ }
+ CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_PARENT;
+ if (!strncmp(szSetting, CurSetting, CurSetting.GetLen()))
+ {
+ TreeDeleteEnumData->TreeSettings.AddElem(szSetting);
+ }
+ CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_ORDER;
+ if (!strncmp(szSetting, CurSetting, CurSetting.GetLen()))
+ {
+ TreeDeleteEnumData->TreeSettings.AddElem(szSetting);
+ }
+ CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_FLAGS;
+ if (!strncmp(szSetting, CurSetting, CurSetting.GetLen()))
+ {
+ TreeDeleteEnumData->TreeSettings.AddElem(szSetting);
+ }
+ if (TreeDeleteEnumData->TreeCtrl->User_Str1_DBName != NULL)
+ {
+ CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TreeDeleteEnumData->TreeCtrl->User_Str1_DBName;
+ if (!strncmp(szSetting, CurSetting, CurSetting.GetLen()))
+ {
+ TreeDeleteEnumData->TreeSettings.AddElem(szSetting);
+ }
+ }
+ return 0;
+}
+
+void COptItem_TreeCtrl::CleanDBSettings(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (!sDBSettingPrefix)
+ {
+ sDBSettingPrefix = &sEmptyString;
+ }
+ sTreeDeleteEnumData TreeDeleteEnumData;
+ TreeDeleteEnumData.TreeCtrl = this;
+ TreeDeleteEnumData.sDBSettingPrefix = sDBSettingPrefix;
+ DBCONTACTENUMSETTINGS dbEnum;
+ dbEnum.lParam = (LPARAM)&TreeDeleteEnumData;
+ dbEnum.ofsSettings = 0;
+ dbEnum.pfnEnumProc = TreeDeleteEnum;
+ dbEnum.szModule = sModule;
+ CallService(MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbEnum);
+ int I;
+ for (I = 0; I < TreeDeleteEnumData.TreeSettings.GetSize(); I++)
+ {
+ DBDeleteContactSetting(NULL, sModule, TreeDeleteEnumData.TreeSettings[I]);
+ }
+}
+
+
+int COptItem_TreeCtrl::GetSelectedItemID(HWND hWnd)
+{
+ HWND hTreeView = GetDlgItem(hWnd, DlgItemID);
+ TVITEM tvi = {0};
+ tvi.hItem = TreeView_GetSelection(hTreeView);
+ if (!tvi.hItem)
+ {
+ return -1;
+ }
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ TreeView_GetItem(hTreeView, &tvi);
+ return tvi.lParam;
+}
+
+void COptItem_TreeCtrl::Delete(HWND hWnd, int ID)
+{
+ int SelectedOrder = IDToOrder(ID);
+ _ASSERT(SelectedOrder >= 0);
+ RecursiveDelete(hWnd, SelectedOrder);
+ Modified = true;
+}
+
+void COptItem_TreeCtrl::RecursiveDelete(HWND hWnd, int I)
+{
+ if (Value[I].Flags & TIF_GROUP)
+ {
+ int J;
+ for (J = I + 1; J < Value.GetSize(); J++)
+ {
+ if (Value[J].ParentID == Value[I].ID)
+ {
+ RecursiveDelete(hWnd, J--);
+ }
+ }
+ }
+ HWND hTreeView = GetDlgItem(hWnd, DlgItemID);
+ TreeView_DeleteItem(hTreeView, Value[I].hItem);
+ Value.RemoveElem(I);
+}
+
+CTreeItem* COptItem_TreeCtrl::InsertItem(HWND hWnd, CTreeItem &Item)
+// Item's ID and ParentID are not used (the new item position is determined by current selection in the tree)
+// returns a pointer to the newly inserted item info
+{
+ _ASSERT(!(TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL) || !(Item.Flags & TIF_GROUP));
+ HWND hTreeView = GetDlgItem(hWnd, DlgItemID);
+ TVITEM tvi;
+ int SelOrder = -1;
+ Item.ParentID = RootItems[0].ID;
+ TVINSERTSTRUCT tvIn = {0};
+ tvIn.hParent = RootItems[0].hItem;
+ tvIn.hInsertAfter = TVI_FIRST;
+ if (tvi.hItem = TreeView_GetSelection(hTreeView))
+ {
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ TreeView_GetItem(hTreeView, &tvi);
+ SelOrder = IDToOrder(tvi.lParam);
+ if (SelOrder <= TREECTRL_ROOTORDEROFFS)
+ {
+ Item.ParentID = RootItems[ROOT_ORDER_TO_INDEX(SelOrder)].ID;
+ tvIn.hParent = RootItems[ROOT_ORDER_TO_INDEX(SelOrder)].hItem;
+ SelOrder = -1;
+ } else
+ {
+ if (Value[SelOrder].Flags & TIF_GROUP)
+ {
+ Item.ParentID = Value[SelOrder].ID;
+ tvIn.hParent = Value[SelOrder].hItem;
+ } else
+ {
+ Item.ParentID = Value[SelOrder].ParentID;
+ int Order = IDToOrder(Value[SelOrder].ParentID);
+ tvIn.hParent = (Order <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(Order)].hItem : Value[Order].hItem;
+ tvIn.hInsertAfter = Value[SelOrder].hItem;
+ }
+ }
+ }
+ tvIn.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvIn.item.state = tvIn.item.stateMask = (Item.Flags & TIF_GROUP) ? (TVIS_BOLD |
+ ((Item.Flags & TIF_EXPANDED) ? TVIS_EXPANDED : 0)) : 0;
+ if (TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES)
+ {
+ tvIn.item.stateMask |= TVIS_STATEIMAGEMASK;
+ tvIn.item.state |= INDEXTOSTATEIMAGEMASK((Item.Flags & TIF_ENABLED) ? 2 : 1);
+ }
+ tvIn.item.pszText = Item.Title;
+ tvIn.item.lParam = Item.ID = GenerateID();
+ Value.InsertElem(Item, SelOrder + 1);
+ Value[SelOrder + 1].hItem = TreeView_InsertItem(hTreeView, &tvIn);
+ TreeView_SelectItem(hTreeView, Value[SelOrder + 1].hItem);
+ Modified = true;
+ return &Value[SelOrder + 1];
+}
+
+int COptItem_TreeCtrl::RecursiveMove(int ItemOrder, int ParentID, int InsertAtOrder)
+// ItemOrder must be a movable item (i.e. ItemOrder >= 0)
+// InsertAtOrder must be >= 0 too.
+{
+ int ItemsMoved = 1;
+ Value.MoveElem(ItemOrder, InsertAtOrder);
+ Value[InsertAtOrder].ParentID = ParentID;
+ if (Value[InsertAtOrder].Flags & TIF_GROUP) // need to ensure that no items were left before their group by an order.
+ {
+ int GroupID = Value[InsertAtOrder].ID;
+ int I;
+ for (I = ItemOrder; I < InsertAtOrder; I++) // if ItemOrder > InsertAtOrder then there is simply nothing to do
+ {
+ if (Value[I].ParentID == GroupID)
+ {
+ int CurrentItemsMoved = RecursiveMove(I, GroupID, InsertAtOrder);
+ ItemsMoved += CurrentItemsMoved;
+ InsertAtOrder -= CurrentItemsMoved;
+ I--;
+ }
+ }
+ }
+ return ItemsMoved;
+}
+
+void COptItem_TreeCtrl::MoveItem(HWND hWnd, HTREEITEM hItem, HTREEITEM hMoveTo)
+{ // hMoveTo can be NULL and it means that we must move hItem to the beginning of the list
+ _ASSERT(hItem && (hMoveTo || TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL));
+ if (hItem == hMoveTo)
+ {
+ return;
+ }
+ HWND hTreeView = GetDlgItem(hWnd, DlgItemID);
+ TVITEM tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = hItem;
+ TreeView_GetItem(hTreeView, &tvi);
+ int ItemOrder = IDToOrder(tvi.lParam);
+ _ASSERT(ItemOrder != -1);
+ int MoveToOrder;
+ if (hMoveTo)
+ {
+ tvi.hItem = hMoveTo;
+ TreeView_GetItem(hTreeView, &tvi);
+ MoveToOrder = IDToOrder(tvi.lParam);
+ _ASSERT(MoveToOrder != -1);
+ } else
+ {
+ MoveToOrder = -1;
+ }
+ if (ItemOrder <= TREECTRL_ROOTORDEROFFS)
+ {
+ return; // can't move root items
+ }
+ if (Value[ItemOrder].Flags & TIF_GROUP)
+ { // need to check for a case when trying to move a group to its own subgroup.
+ int Order = MoveToOrder;
+ while (Order >= 0)
+ {
+ Order = IDToOrder(Value[Order].ParentID);
+ if (Order == ItemOrder)
+ {
+ return;
+ }
+ }
+ }
+// well, everything is ok, we really can move that item.
+ WndToMem(hWnd); // save groups state (expanded/collapsed)
+ if (MoveToOrder != -1 && ((MoveToOrder <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(MoveToOrder)].Flags : Value[MoveToOrder].Flags) & TIF_GROUP)
+ { // if the destination is a group, then move the item to that group
+ RecursiveMove(ItemOrder, (MoveToOrder <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(MoveToOrder)].ID : Value[MoveToOrder].ID, (MoveToOrder >= 0) ? ((ItemOrder < MoveToOrder) ? MoveToOrder : (MoveToOrder + 1)) : 0);
+ } else
+ { // else place the item after the destination item
+ RecursiveMove(ItemOrder, (MoveToOrder == -1) ? 0 : Value[MoveToOrder].ParentID, (ItemOrder < MoveToOrder) ? MoveToOrder : (MoveToOrder + 1)); // when TREECTRL_FLAG_IS_SINGLE_LEVEL, we always have a root item with ID = 0.
+ }
+ MemToWnd(hWnd); // update the tree
+ Modified = true;
+}
+
+
+// ================================================ COptItem_ListCtrl ================================================
+
+typedef struct
+{
+ COptItem_ListCtrl *ListCtrl;
+ CString *sModule;
+ CString *sDBSettingPrefix;
+} sListReadEnumData;
+
+int ListReadEnum(const char *szSetting, LPARAM lParam)
+{
+ sListReadEnumData *ListReadEnumData = (sListReadEnumData*)lParam;
+ int Len = ListReadEnumData->sDBSettingPrefix->GetLen() + ListReadEnumData->ListCtrl->sDBSetting.GetLen() + lengthof(LISTITEM_DBSTR_TEXT) - 1;
+ if (!strncmp(szSetting, *ListReadEnumData->sDBSettingPrefix + ListReadEnumData->ListCtrl->sDBSetting + LISTITEM_DBSTR_TEXT, Len) && isdigit(szSetting[Len]))
+ {
+ int ID = atol(szSetting + Len);
+ ListReadEnumData->ListCtrl->Value.SetAtGrow(ID).Text = DBGetContactSettingString(NULL, *ListReadEnumData->sModule, *ListReadEnumData->sDBSettingPrefix + szSetting, _T(""));
+ }
+ return 0;
+}
+
+void COptItem_ListCtrl::DBToMem(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (!sDBSettingPrefix)
+ {
+ sDBSettingPrefix = &sEmptyString;
+ }
+ Value.RemoveAll();
+ sListReadEnumData ListReadEnumData;
+ ListReadEnumData.ListCtrl = this;
+ ListReadEnumData.sModule = &sModule;
+ ListReadEnumData.sDBSettingPrefix = sDBSettingPrefix;
+ DBCONTACTENUMSETTINGS dbEnum;
+ dbEnum.lParam = (LPARAM)&ListReadEnumData;
+ dbEnum.ofsSettings = 0;
+ dbEnum.pfnEnumProc = ListReadEnum;
+ dbEnum.szModule = sModule;
+ CallService(MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbEnum);
+ if (!Value.GetSize())
+ {
+ Value = DefValue;
+ } else
+ {
+ int I;
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ if (Value[I].Text == NULL) // NULL is not ""!
+ {
+ Value.RemoveElem(I);
+ I--;
+ }
+ }
+ }
+ COptItem::DBToMem(sModule, sDBSettingPrefix);
+}
+
+void COptItem_ListCtrl::MemToDB(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (!ReadOnly && Modified)
+ {
+ if (!sDBSettingPrefix)
+ {
+ sDBSettingPrefix = &sEmptyString;
+ }
+ CleanDBSettings(sModule, sDBSettingPrefix);
+ int I;
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ CString StrID;
+ itoa(I, StrID.GetBuffer(64), 10);
+ StrID.ReleaseBuffer();
+ DBWriteContactSettingTString(NULL, sModule, *sDBSettingPrefix + sDBSetting + LISTITEM_DBSTR_TEXT + StrID, Value[I].Text);
+ }
+ COptItem::MemToDB(sModule, sDBSettingPrefix);
+ }
+}
+
+void COptItem_ListCtrl::WndToMem(HWND hWnd)
+{
+// nothing to do
+ COptItem::WndToMem(hWnd);
+}
+
+void COptItem_ListCtrl::MemToWnd(HWND hWnd)
+{
+ HWND hListView = GetDlgItem(hWnd, DlgItemID);
+ SendMessage(hListView, WM_SETREDRAW, false, 0);
+ SendMessage(hListView, LB_RESETCONTENT, 0, 0);
+ int I;
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ SendMessage(hListView, LB_INSERTSTRING, -1, (LPARAM)(TCHAR*)Value[I].Text);
+ }
+ SendMessage(hListView, WM_SETREDRAW, true, 0);
+ COptItem::MemToWnd(hWnd);
+}
+
+
+typedef struct
+{
+ TMyArray<CString> ListSettings;
+ COptItem_ListCtrl *ListCtrl;
+ CString *sDBSettingPrefix;
+} sListDeleteEnumData;
+
+int ListDeleteEnum(const char *szSetting, LPARAM lParam)
+{
+ sListDeleteEnumData *ListDeleteEnumData = (sListDeleteEnumData*)lParam;
+ CString CurSetting = *ListDeleteEnumData->sDBSettingPrefix + ListDeleteEnumData->ListCtrl->sDBSetting + LISTITEM_DBSTR_TEXT;
+ if (!strncmp(szSetting, CurSetting, CurSetting.GetLen()))
+ {
+ ListDeleteEnumData->ListSettings.AddElem(szSetting);
+ }
+ return 0;
+}
+
+void COptItem_ListCtrl::CleanDBSettings(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (!sDBSettingPrefix)
+ {
+ sDBSettingPrefix = &sEmptyString;
+ }
+ sListDeleteEnumData ListDeleteEnumData;
+ ListDeleteEnumData.ListCtrl = this;
+ ListDeleteEnumData.sDBSettingPrefix = sDBSettingPrefix;
+ DBCONTACTENUMSETTINGS dbEnum;
+ dbEnum.lParam = (LPARAM)&ListDeleteEnumData;
+ dbEnum.ofsSettings = 0;
+ dbEnum.pfnEnumProc = ListDeleteEnum;
+ dbEnum.szModule = sModule;
+ CallService(MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbEnum);
+ int I;
+ for (I = 0; I < ListDeleteEnumData.ListSettings.GetSize(); I++)
+ {
+ DBDeleteContactSetting(NULL, sModule, ListDeleteEnumData.ListSettings[I]);
+ }
+}
+
+
+int COptItem_ListCtrl::GetSelectedItemID(HWND hWnd)
+{
+ int Res = SendDlgItemMessage(hWnd, DlgItemID, LB_GETCURSEL, 0, 0);
+ return (Res == LB_ERR) ? -1 : Res; // I know that LB_ERR = -1 ;)
+}
+
+int COptItem_ListCtrl::SetSelectedItemID(HWND hWnd, int ID)
+{
+ int Res = SendDlgItemMessage(hWnd, DlgItemID, LB_SETCURSEL, ID, 0);
+ return (Res == LB_ERR) ? -1 : Res;
+}
+
+void COptItem_ListCtrl::Delete(HWND hWnd, int ID)
+{
+ _ASSERT(ID >= 0);
+ HWND hListView = GetDlgItem(hWnd, DlgItemID);
+ int Res = SendMessage(hListView, LB_DELETESTRING, ID, 0);
+ _ASSERT(Res != LB_ERR);
+ Value.RemoveElem(ID);
+ Modified = true;
+}
+
+void COptItem_ListCtrl::ModifyItem(HWND hWnd, int ID, CListItem &Item)
+{ // changes the text of item with the specified ID
+ _ASSERT(ID >= 0);
+ HWND hListView = GetDlgItem(hWnd, DlgItemID);
+ SendMessage(hListView, WM_SETREDRAW, false, 0);
+ int CurSel = SendMessage(hListView, LB_GETCURSEL, 0, 0);
+ int TopIndex = SendMessage(hListView, LB_GETTOPINDEX, 0, 0);
+ int Res = SendMessage(hListView, LB_DELETESTRING, ID, 0);
+ _ASSERT(Res != LB_ERR);
+ Res = SendMessage(hListView, LB_INSERTSTRING, ID, (LPARAM)(TCHAR*)(Item.Text));
+ _ASSERT(Res != LB_ERR && Res != LB_ERRSPACE);
+ SendMessage(hListView, LB_SETCURSEL, CurSel, 0);
+ SendMessage(hListView, LB_SETTOPINDEX, TopIndex, 0);
+ SendMessage(hListView, WM_SETREDRAW, true, 0);
+ Value[ID].Text = Item.Text;
+ Modified = true;
+}
+
+CListItem* COptItem_ListCtrl::InsertItem(HWND hWnd, int ID, CListItem &Item)
+// returns a pointer to the newly inserted item info
+// ID is position at which to insert the item; -1 = add to the end of the list
+{
+ HWND hListView = GetDlgItem(hWnd, DlgItemID);
+ int Res = SendMessage(hListView, LB_INSERTSTRING, ID, (LPARAM)(TCHAR*)(Item.Text)); // LB_INSERTSTRING doesn't sort the lists even with LBS_SORT style
+ _ASSERT(Res != LB_ERR && Res != LB_ERRSPACE);
+ int I = Value.AddElem(Item);
+ Modified = true;
+ return &Value[I];
+}
diff --git a/plugins/NewAwaySysMod/CommonLibs/Options.h b/plugins/NewAwaySysMod/CommonLibs/Options.h
new file mode 100644
index 0000000000..61cbc11d04
--- /dev/null
+++ b/plugins/NewAwaySysMod/CommonLibs/Options.h
@@ -0,0 +1,490 @@
+/*
+ Options.h
+ Copyright (c) 2005-2008 Chervov Dmitry
+
+ 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
+
+#include <windows.h>
+#include <crtdbg.h>
+#include <commctrl.h>
+#include <stdio.h>
+#include "newpluginapi.h"
+#include "m_database.h"
+#include "m_utils.h"
+#include "CString.h"
+#include "TMyArray.h"
+
+#ifndef lengthof
+#define lengthof(s) (sizeof(s) / sizeof(*s))
+#endif
+
+
+class COptItem
+{
+public:
+ COptItem() {}
+ COptItem(int DlgItemID, char *szDBSetting, int nValueSize, int lParam = 0, bool ReadOnly = false):
+ DlgItemID(DlgItemID), nValueSize(nValueSize), sDBSetting(szDBSetting), lParam(lParam), Enabled(true), ReadOnly(ReadOnly), Modified(false) {}
+/* COptItem(const COptItem &Item): DlgItemID(Item.DlgItemID), nValueSize(Item.nValueSize),
+ sDBSetting(Item.szDBSetting), lParam(Item.lParam), Enabled(Item.Enabled) {};*/
+ virtual ~COptItem() {}
+
+ virtual void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Modified = false;}
+ virtual void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {Modified = false;}
+ virtual void WndToMem(HWND hWnd) {}
+ virtual void MemToWnd(HWND hWnd) {EnableWindow(GetDlgItem(hWnd, DlgItemID), Enabled);}
+ void DBToMemToWnd(CString &sModule, HWND hWnd, CString *sDBSettingPrefix = NULL) {DBToMem(sModule, sDBSettingPrefix); MemToWnd(hWnd);}
+ void WndToMemToDB(HWND hWnd, CString &sModule, CString *sDBSettingPrefix = NULL) {WndToMem(hWnd); MemToDB(sModule, sDBSettingPrefix);}
+ virtual void CleanDBSettings(CString &sModule, CString *sDBSettingPrefix = NULL) {DBDeleteContactSetting(NULL, sModule, sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting);}; // TODO: also set Value to DefValue?
+
+ virtual void SetValue(int Value) {Modified = true;}
+ virtual void SetDefValue(int DefValue) {}
+ virtual int GetValue() {return 0;}
+ virtual int GetDefValue() {return 0;}
+ int GetDBValue(CString &sModule, CString *sDBSettingPrefix = NULL) {DBToMem(sModule, sDBSettingPrefix); return GetValue();}
+ void SetDBValue(CString &sModule, int Value, CString *sDBSettingPrefix = NULL) {SetValue(Value); MemToDB(sModule, sDBSettingPrefix);}
+ int GetDBValueCopy(CString &sModule, CString *sDBSettingPrefix = NULL) {COptItem* Item = Copy(); Item->DBToMem(sModule, sDBSettingPrefix); int Value = Item->GetValue(); delete Item; return Value;} // retrieves DB value, but doesn't affect current page/item state; beware! it doesn't work with string values / other dynamic pointers
+ void SetDBValueCopy(CString &sModule, int Value, CString *sDBSettingPrefix = NULL) {COptItem* Item = Copy(); Item->SetValue(Value); Item->MemToDB(sModule, sDBSettingPrefix); delete Item;}
+ int GetWndValue(HWND hWnd) {WndToMem(hWnd); return GetValue();}
+ void SetWndValue(HWND hWnd, int Value) {SetValue(Value); MemToWnd(hWnd);}
+ void SetDlgItemID(int DlgItemID) {this->DlgItemID = DlgItemID;}
+ bool GetModified() {return Modified;}
+ void SetModified(bool Modified) {this->Modified = Modified;}
+
+ void Enable(int Enabled) {this->Enabled = Enabled;}
+ int GetParam() {return lParam;}
+ int GetID() {return DlgItemID;}
+
+// virtual COptItem& operator = (const COptItem& Item) {return *this;};
+ virtual COptItem* Copy() {_ASSERT(0); return NULL;} // Attention! Free Copy() result when it's not needed anymore!
+
+ CString sDBSetting;
+
+protected:
+ int GetIntDBVal(CString &sModule, int bSigned = false, CString *sDBSettingPrefix = NULL);
+ void SetIntDBVal(CString &sModule, int Value, CString *sDBSettingPrefix = NULL);
+ TCString GetStrDBVal(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void SetStrDBVal(CString &sModule, TCString &Str, CString *sDBSettingPrefix = NULL);
+
+ int DlgItemID;
+ int Enabled;
+ bool ReadOnly;
+ bool Modified;
+ int nValueSize; // maximum pValue size in bytes
+ int lParam;
+};
+
+
+class COptItem_Generic : public COptItem
+{
+public:
+ COptItem_Generic() {}
+ COptItem_Generic(int DlgItemID, int lParam = 0): COptItem(DlgItemID, NULL, 0, lParam) {}
+ virtual COptItem* Copy() {return new COptItem_Generic(*this);}
+};
+
+
+class COptItem_Edit : public COptItem
+{
+public:
+ COptItem_Edit() {}
+ COptItem_Edit(int DlgItemID, char *szDBSetting, int nMaxLen, TCHAR *szDefValue, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nMaxLen, lParam, ReadOnly), sDefValue(szDefValue) {}
+// COptItem_Edit(const COptItem_Edit &Item): sDefValue(Item.sDefValue), sValue(Item.sValue) {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {sValue = GetStrDBVal(sModule, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetStrDBVal(sModule, sValue, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {GetDlgItemText(hWnd, DlgItemID, sValue.GetBuffer(nValueSize), nValueSize); sValue.ReleaseBuffer(); COptItem::MemToWnd(hWnd);}
+ void MemToWnd(HWND hWnd) {SetDlgItemText(hWnd, DlgItemID, sValue); COptItem::MemToWnd(hWnd);}
+ void SetValue(int Value) {sValue = *(TCString*)Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {sDefValue = *(TCString*)DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return (int)&sValue;}
+ int GetDefValue() {return (int)&sDefValue;}
+
+// COptItem_Edit& operator = (const COptItem_Edit& Item) {return *this;};
+ virtual COptItem* Copy() {return new COptItem_Edit(*this);}
+
+ TCString sDefValue;
+ TCString sValue;
+};
+
+
+class COptItem_IntEdit : public COptItem
+{
+public:
+ COptItem_IntEdit() {}
+ COptItem_IntEdit(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int bSigned = true, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), bSigned(bSigned) {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, bSigned, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {Value = GetDlgItemInt(hWnd, DlgItemID, NULL, bSigned); COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {SetDlgItemInt(hWnd, DlgItemID, Value, bSigned); COptItem::MemToWnd(hWnd);}
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_IntEdit(*this);}
+
+ int DefValue;
+ int Value;
+ int bSigned;
+};
+
+
+class COptItem_Checkbox : public COptItem
+{
+public:
+ COptItem_Checkbox() {}
+ COptItem_Checkbox(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int DefValue = 0, int ValueMask = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), ValueMask(ValueMask) {}
+
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void WndToMem(HWND hWnd);
+ void MemToWnd(HWND hWnd);
+
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_Checkbox(*this);}
+
+ int Value;
+ int DefValue;
+ int ValueMask;
+};
+
+
+class COptItem_Radiobutton : public COptItem
+{
+public:
+ COptItem_Radiobutton() {}
+ COptItem_Radiobutton(int DlgItemID, char *szDBSetting, int nValueSize, int DefValue, int ValueMask, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), ValueMask(ValueMask) {}
+
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = (GetIntDBVal(sModule, false, sDBSettingPrefix) == ValueMask) ? BST_CHECKED : BST_UNCHECKED; COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {if ((Value == BST_CHECKED)) SetIntDBVal(sModule, ValueMask, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {Value = IsDlgButtonChecked(hWnd, DlgItemID); COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {CheckDlgButton(hWnd, DlgItemID, Value); COptItem::MemToWnd(hWnd);}
+
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_Radiobutton(*this);}
+
+ int Value;
+ int DefValue;
+ int ValueMask;
+};
+
+
+class COptItem_Combobox : public COptItem
+{
+public:
+ COptItem_Combobox() {}
+ COptItem_Combobox(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0) {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, false, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {Value = SendDlgItemMessage(hWnd, DlgItemID, CB_GETITEMDATA, (WPARAM)SendDlgItemMessage(hWnd, DlgItemID, CB_GETCURSEL, 0, 0), 0); COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {SendDlgItemMessage(hWnd, DlgItemID, CB_SETCURSEL, Value, 0); COptItem::MemToWnd(hWnd);}
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_Combobox(*this);}
+
+ int DefValue;
+ int Value;
+};
+
+
+class COptItem_Colourpicker : public COptItem
+{
+public:
+ COptItem_Colourpicker() {}
+ COptItem_Colourpicker(int DlgItemID, char *szDBSetting, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, DBVT_DWORD, lParam, ReadOnly), DefValue(DefValue), Value(0) {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, false, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {Value = SendDlgItemMessage(hWnd, DlgItemID, CPM_GETCOLOUR, 0, 0); COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {SendDlgItemMessage(hWnd, DlgItemID, CPM_SETCOLOUR, 0, Value); COptItem::MemToWnd(hWnd);}
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_Colourpicker(*this);}
+
+ DWORD DefValue;
+ DWORD Value;
+};
+
+
+class COptItem_Slider : public COptItem
+{
+public:
+ COptItem_Slider() {}
+ COptItem_Slider(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0) {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, false, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {Value = SendDlgItemMessage(hWnd, DlgItemID, TBM_GETPOS, 0, 0); COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {SendDlgItemMessage(hWnd, DlgItemID, TBM_SETPOS, true, Value); COptItem::MemToWnd(hWnd);}
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_Slider(*this);}
+
+ int DefValue;
+ int Value;
+};
+
+
+class COptItem_IntDBSetting : public COptItem
+{
+public:
+ COptItem_IntDBSetting() {}
+ COptItem_IntDBSetting(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int bSigned = true, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), bSigned(bSigned) {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, bSigned, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {COptItem::MemToWnd(hWnd);}
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_IntDBSetting(*this);}
+
+ int Value;
+ int DefValue;
+ int bSigned;
+};
+
+
+class COptItem_BitDBSetting : public COptItem
+{
+public:
+ COptItem_BitDBSetting() {}
+ COptItem_BitDBSetting(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int DefValue = 0, int ValueMask = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), ValueMask(ValueMask) {}
+
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void WndToMem(HWND hWnd) {COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {COptItem::MemToWnd(hWnd);}
+
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_BitDBSetting(*this);}
+
+ int Value;
+ int DefValue;
+ int ValueMask;
+};
+
+
+class COptItem_StrDBSetting : public COptItem
+{
+public:
+ COptItem_StrDBSetting() {}
+ COptItem_StrDBSetting(int DlgItemID, char *szDBSetting, int nMaxLen, TCHAR *szDefValue, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nMaxLen, lParam, ReadOnly), sDefValue(szDefValue) {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {sValue = GetStrDBVal(sModule, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetStrDBVal(sModule, sValue, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {COptItem::MemToWnd(hWnd);}
+ void SetValue(int Value) {sValue = *(TCString*)Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {sDefValue = *(TCString*)DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return (int)&sValue;}
+ int GetDefValue() {return (int)&sDefValue;}
+ virtual COptItem* Copy() {return new COptItem_StrDBSetting(*this);}
+
+ TCString sDefValue;
+ TCString sValue;
+};
+
+
+// Tree item flags
+#define TIF_GROUP 1 // is a group
+#define TIF_EXPANDED 2 // item is expanded
+#define TIF_ENABLED 4 // item is checked (has sense when the tree has checkboxes)
+#define TIF_ROOTITEM 0x80 // item is a root item
+
+class CBaseTreeItem
+{
+public:
+ CBaseTreeItem();
+ CBaseTreeItem(TCString Title, int ID, int Flags): Title(Title), ID(ID), Flags(Flags), hItem(NULL) {}
+
+ TCString Title;
+ int ID;
+ int Flags;
+ HTREEITEM hItem;
+};
+
+class CTreeItem : public CBaseTreeItem
+{
+public:
+ CTreeItem();
+ CTreeItem(TCString Title, int ParentID, int ID, int Flags = 0, TCString User_Str1 = NULL):
+ CBaseTreeItem(Title, ID, Flags & ~TIF_ROOTITEM), ParentID(ParentID), User_Str1(User_Str1) {}
+
+ int ParentID;
+ TCString User_Str1;
+};
+
+class CTreeRootItem : public CBaseTreeItem
+{
+public:
+ CTreeRootItem();
+ CTreeRootItem(TCString Title, int ID, int Flags): CBaseTreeItem(Title, ID, Flags | TIF_ROOTITEM) {}
+};
+
+typedef TMyArray<CTreeItem> TreeItemArray;
+typedef TMyArray<CTreeRootItem> TreeRootItemArray;
+
+#define TREECTRL_ROOTORDEROFFS -2
+#define ROOT_INDEX_TO_ORDER(i) (TREECTRL_ROOTORDEROFFS - (i))
+#define ROOT_ORDER_TO_INDEX(i) (TREECTRL_ROOTORDEROFFS - (i))
+
+#define TREEITEMTITLE_MAXLEN 128
+#define TREEITEM_DBSTR_TITLE "Title"
+#define TREEITEM_DBSTR_PARENT "Parent"
+#define TREEITEM_DBSTR_ORDER "Order"
+#define TREEITEM_DBSTR_FLAGS "Flags"
+
+// Tree control flags
+#define TREECTRL_FLAG_IS_SINGLE_LEVEL 1 // means that the tree items can't have children, i.e. the tree is a plain list of items
+#define TREECTRL_FLAG_HAS_CHECKBOXES 2
+//#define TREECTRL_FLAG_UNORDERED 4 TODO?
+
+class COptItem_TreeCtrl : public COptItem
+{
+public:
+ COptItem_TreeCtrl() {}
+ COptItem_TreeCtrl(int DlgItemID, char *szDBSetting, TreeItemArray &DefValue, TreeRootItemArray RootItems, int lParam = 0, CString User_Str1_DBName = NULL, bool ReadOnly = false, int TreeFlags = 0): COptItem(DlgItemID, szDBSetting, DBVT_DWORD, lParam, ReadOnly), DefValue(DefValue), RootItems(RootItems), User_Str1_DBName(User_Str1_DBName), TreeFlags(TreeFlags)
+ {
+ if (TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL)
+ {
+ _ASSERT(!RootItems.GetSize()); // there can't be any root items when the tree is a plain list
+ this->RootItems.AddElem(CTreeRootItem(_T(""), 0, TIF_EXPANDED)); // TODO??
+ this->RootItems[0].hItem = TVI_ROOT;
+ }
+ }
+ ~COptItem_TreeCtrl() {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void WndToMem(HWND hWnd);
+ void MemToWnd(HWND hWnd);
+ void CleanDBSettings(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void SetValue(int Value) {this->Value = *(TreeItemArray*)Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = *(TreeItemArray*)DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return (int)&Value;}
+ int GetDefValue() {return (int)&DefValue;}
+ virtual COptItem* Copy() {return new COptItem_TreeCtrl(*this);}
+
+ int IDToOrder(int ID);
+ int hItemToOrder(HTREEITEM hItem);
+ int GenerateID();
+ int GetSelectedItemID(HWND hWnd);
+ void Delete(HWND hWnd, int ID);
+ CTreeItem* InsertItem(HWND hWnd, CTreeItem &Item);
+ void MoveItem(HWND hWnd, HTREEITEM hItem, HTREEITEM hMoveTo);
+
+ TreeItemArray DefValue, Value;
+ TreeRootItemArray RootItems;
+ CString User_Str1_DBName;
+ int TreeFlags;
+
+protected:
+ void RecursiveDelete(HWND hWnd, int I);
+ int RecursiveMove(int ItemOrder, int ParentID, int InsertAtOrder);
+};
+
+
+class CListItem
+{
+public:
+ CListItem();
+ CListItem(TCString Text): Text(Text) {}
+
+ TCString Text;
+};
+
+typedef TMyArray<CListItem> ListItemArray;
+
+#define LISTITEM_DBSTR_TEXT "Text"
+
+class COptItem_ListCtrl : public COptItem
+{
+public:
+ COptItem_ListCtrl() {}
+ COptItem_ListCtrl(int DlgItemID, char *szDBSetting, ListItemArray &DefValue, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, DBVT_DWORD, lParam, ReadOnly), DefValue(DefValue) {}
+ ~COptItem_ListCtrl() {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void WndToMem(HWND hWnd);
+ void MemToWnd(HWND hWnd);
+ void CleanDBSettings(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void SetValue(int Value) {this->Value = *(ListItemArray*)Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = *(ListItemArray*)DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return (int)&Value;}
+ int GetDefValue() {return (int)&DefValue;}
+ virtual COptItem* Copy() {return new COptItem_ListCtrl(*this);}
+
+ int GetSelectedItemID(HWND hWnd); // returns -1 if there's no selection
+ int SetSelectedItemID(HWND hWnd, int ID);
+ void Delete(HWND hWnd, int ID);
+ CListItem* InsertItem(HWND hWnd, int ID, CListItem &Item);
+ void ModifyItem(HWND hWnd, int ID, CListItem &Item);
+
+ ListItemArray DefValue, Value;
+};
+
+
+class COptPage
+{
+public:
+ COptPage(): hWnd(NULL), sDBSettingPrefix("") {}
+ COptPage(char *szModule, HWND hWnd, CString sDBSettingPrefix = ""): sModule(szModule), hWnd(hWnd), sDBSettingPrefix(sDBSettingPrefix) {}
+ COptPage(const COptPage &Item);
+ ~COptPage();
+
+ void DBToMem();
+ void MemToDB();
+ void MemToPage(int OnlyEnable = 0);
+ void PageToMem();
+ void DBToMemToPage() {DBToMem(); MemToPage();}
+ void PageToMemToDB() {PageToMem(); MemToDB();}
+ void CleanDBSettings();
+
+ COptItem *Find(int DlgItemID);
+ int GetValue(int DlgItemID) {return Find(DlgItemID)->GetValue();}
+ void SetValue(int DlgItemID, int Value) {Find(DlgItemID)->SetValue(Value);}
+ int GetDBValue(int DlgItemID) {return Find(DlgItemID)->GetDBValue(sModule, &sDBSettingPrefix);}
+ void SetDBValue(int DlgItemID, int Value) {Find(DlgItemID)->SetDBValue(sModule, Value, &sDBSettingPrefix);}
+ int GetDBValueCopy(int DlgItemID) {return Find(DlgItemID)->GetDBValueCopy(sModule, &sDBSettingPrefix);}
+ void SetDBValueCopy(int DlgItemID, int Value) {Find(DlgItemID)->SetDBValueCopy(sModule, Value, &sDBSettingPrefix);}
+ int GetWndValue(int DlgItemID) {return Find(DlgItemID)->GetWndValue(hWnd);}
+ void SetWndValue(int DlgItemID, int Value) {Find(DlgItemID)->SetWndValue(hWnd, Value);}
+ HWND GetWnd() {return hWnd;}
+ void SetWnd(HWND hWnd) {_ASSERT(!this->hWnd || !hWnd); this->hWnd = hWnd;}
+ void Enable(int DlgItemID, int Enabled) {Find(DlgItemID)->Enable(Enabled);}
+ bool GetModified();
+ void SetModified(bool Modified);
+
+ COptPage& operator = (const COptPage& Page);
+
+ HWND hWnd;
+ CString sModule, sDBSettingPrefix;
+ TMyArray<COptItem*, COptItem*> Items;
+};
diff --git a/plugins/NewAwaySysMod/CommonLibs/TMyArray.h b/plugins/NewAwaySysMod/CommonLibs/TMyArray.h
new file mode 100644
index 0000000000..68ca908fe1
--- /dev/null
+++ b/plugins/NewAwaySysMod/CommonLibs/TMyArray.h
@@ -0,0 +1,353 @@
+/*
+ TMyArray.h - TMyArray template
+ Copyright (c) 2005-2008 Chervov Dmitry
+
+ 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
+
+#include <stdlib.h>
+
+#define ARRAY_GROWBY 4
+// if there is more than ARRAY_FREETHRESHOLD free array elements, then we're reallocating the array
+#define ARRAY_FREETHRESHOLD 16
+
+template <class T, class ARG_T = const T&, int GrowBy = ARRAY_GROWBY, int FreeThreshold = ARRAY_FREETHRESHOLD>
+class TMyArray
+{
+public:
+ TMyArray();
+ TMyArray(const TMyArray<T, ARG_T, GrowBy, FreeThreshold> &A);
+ ~TMyArray();
+
+ int GetSize() const;
+ T* GetData() const;
+ int AddElem(ARG_T pElem);
+ int Add(const T *pItems, int nItems);
+ void InsertElem(ARG_T pElem, int nInsertAt);
+ void MoveElem(int nIndex, int nMoveTo);
+ T& SetAtGrow(int nIndex);
+ int Find(ARG_T pElem); // returns an index of the specified item, or -1 if the array doesn't contain the item
+ int BinarySearch(int (*CmpFunc)(ARG_T pItem, LPARAM lParam), LPARAM lParam, int *pIndex = NULL); // returns an index of the specified item, or -1 if the array doesn't contain the item;
+ // also it's possible to specify pIndex so that even if the array doesn't contain the item, the function will set *pIndex to a position where the item can be inserted;
+ // CmpFunc must return -1, 0 and 1 depending whether pItem is lesser, equal or greater than needed;
+ // BinarySearch() requires the array to be sorted in an ascending order
+ void RemoveElem(int nIndex, int nItems = 1);
+ void RemoveAll();
+ const T& operator[](int nIndex) const;
+ T& operator[](int nIndex);
+ TMyArray<T, ARG_T, GrowBy, FreeThreshold>& operator = (const TMyArray<T, ARG_T, GrowBy, FreeThreshold> &A);
+ TMyArray<T, ARG_T, GrowBy, FreeThreshold>& operator += (const TMyArray<T, ARG_T, GrowBy, FreeThreshold> &A);
+
+private:
+ int SetAllocNum(int nNewAllocNum);
+
+ T* pData;
+ int nElemNum;
+ int nAllocNum;
+};
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+TMyArray<T, ARG_T, GrowBy, FreeThreshold>::TMyArray()
+{
+ nElemNum = 0;
+ nAllocNum = 0;
+ pData = NULL;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+TMyArray<T, ARG_T, GrowBy, FreeThreshold>::TMyArray(const TMyArray<T, ARG_T, GrowBy, FreeThreshold> &A)//: TMyArray<T, ARG_T>()
+{
+ nElemNum = 0;
+ nAllocNum = 0;
+ pData = NULL;
+ *this = A;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+TMyArray<T, ARG_T, GrowBy, FreeThreshold>::~TMyArray()
+{
+ RemoveAll();
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline int TMyArray<T, ARG_T, GrowBy, FreeThreshold>::GetSize() const
+{
+ return nElemNum;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline T* TMyArray<T, ARG_T, GrowBy, FreeThreshold>::GetData() const
+{
+ return pData;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline int TMyArray<T, ARG_T, GrowBy, FreeThreshold>::SetAllocNum(int nNewAllocNum)
+{
+ _ASSERT(nNewAllocNum >= nElemNum);
+ T*pNewData = (nNewAllocNum) ? (T*)malloc(sizeof(T) * nNewAllocNum) : NULL;
+ if (pData)
+ {
+ if (pNewData)
+ {
+ memcpy(pNewData, pData, sizeof(T) * nElemNum);
+ }
+ free(pData);
+ }
+ pData = pNewData;
+ if (!pNewData)
+ {
+ nAllocNum = 0;
+ return -1; // not enough memory?
+ } else
+ {
+ nAllocNum = nNewAllocNum;
+ return 0; // everything's ok
+ }
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline int TMyArray<T, ARG_T, GrowBy, FreeThreshold>::AddElem(ARG_T pElem)
+{
+ if (nElemNum >= nAllocNum)
+ { // reallocate memory to fit new element
+ SetAllocNum(nAllocNum + GrowBy);
+ }
+ memset(pData + nElemNum, 0, sizeof(T));
+ pData[nElemNum] = pElem;
+ return nElemNum++;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline int TMyArray<T, ARG_T, GrowBy, FreeThreshold>::Add(const T *pItems, int nItems)
+{
+ if (nElemNum + nItems > nAllocNum)
+ { // reallocate memory to fit new items
+ SetAllocNum(nAllocNum + nElemNum + nItems - 1 - ((nElemNum + nItems - 1) % GrowBy) + GrowBy);
+ }
+ memset(pData + nElemNum, 0, sizeof(T) * nItems);
+ int I;
+ for (I = 0; I < nItems; I++)
+ {
+ pData[nElemNum++] = pItems[I];
+ }
+ return nElemNum - nItems; // returns an index of the first item added
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline void TMyArray<T, ARG_T, GrowBy, FreeThreshold>::InsertElem(ARG_T pElem, int nInsertAt)
+{
+ _ASSERT(nInsertAt >= 0 && nInsertAt <= nElemNum);
+ if (nElemNum >= nAllocNum)
+ { // reallocate memory to fit new items
+ SetAllocNum(nAllocNum + GrowBy);
+ }
+ memmove(pData + nInsertAt + 1, pData + nInsertAt, sizeof(T) * (nElemNum - nInsertAt));
+ memset(pData + nInsertAt, 0, sizeof(T));
+ pData[nInsertAt] = pElem;
+ nElemNum++;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline void TMyArray<T, ARG_T, GrowBy, FreeThreshold>::MoveElem(int nIndex, int nMoveTo)
+{
+ _ASSERT(nIndex >= 0 && nIndex < nElemNum && nMoveTo >= 0 && nMoveTo < nElemNum);
+ if (nIndex == nMoveTo)
+ {
+ return; // nothing to do
+ }
+ char Elem[sizeof(T)];
+ memmove(Elem, pData + nIndex, sizeof(T));
+ if (nIndex < nMoveTo)
+ {
+ memmove(pData + nIndex, pData + nIndex + 1, sizeof(T) * (nMoveTo - nIndex));
+ } else
+ {
+ memmove(pData + nMoveTo + 1, pData + nMoveTo, sizeof(T) * (nIndex - nMoveTo));
+ }
+ memmove(pData + nMoveTo, Elem, sizeof(T));
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline T& TMyArray<T, ARG_T, GrowBy, FreeThreshold>::SetAtGrow(int nIndex)
+{
+ _ASSERT(nIndex >= 0);
+ if (nIndex < nElemNum)
+ {
+ return pData[nIndex];
+ }
+ if (nIndex >= nAllocNum)
+ {
+ if (SetAllocNum(nIndex - (nIndex % GrowBy) + GrowBy))
+ { // if there was an error
+ nElemNum = 0;
+ return *pData;
+ }
+ }
+ memset(pData + nElemNum, 0, sizeof(T) * (nIndex - nElemNum + 1));
+ nElemNum = nIndex + 1;
+ return pData[nIndex];
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline int TMyArray<T, ARG_T, GrowBy, FreeThreshold>::Find(ARG_T pElem)
+{
+ int I;
+ for (I = 0; I < nElemNum; I++)
+ {
+ if (pData[I] == pElem)
+ {
+ return I;
+ }
+ }
+ return -1;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline int TMyArray<T, ARG_T, GrowBy, FreeThreshold>::BinarySearch(int (*CmpFunc)(ARG_T pItem, LPARAM lParam), LPARAM lParam, int *pIndex)
+{
+ int L, R;
+ int CmpResult;
+ if (!nElemNum)
+ {
+ if (pIndex)
+ {
+ *pIndex = -1;
+ }
+ return -1;
+ }
+ for (L = 0, R = nElemNum; R - L > 1;)
+ {
+ int C = (L + R) >> 1; // rounds always to a lesser index if L + R is odd
+ CmpResult = CmpFunc(pData[C], lParam); // usually, CmpFunc = pData[C] - lParam; i.e. CmpFunc > 0 when pData[C] is greater than necessary, < 0 when pData[C] is less, and = 0 when pData[C] is the item we search for
+ if (CmpResult < 0)
+ {
+ L = C;
+ } else if (CmpResult > 0)
+ {
+ R = C;
+ } else
+ { // CmpResult == 0
+ if (pIndex)
+ {
+ *pIndex = C;
+ }
+ return C;
+ }
+ }
+ if (pIndex)
+ {
+ *pIndex = L;
+ }
+ CmpResult = CmpFunc(pData[L], lParam);
+ if (!CmpResult)
+ {
+ return L;
+ }
+ if (CmpResult > 0)
+ { // we don't need to check pData[R], as pData[R] > pData[L] > lParam, i.e. there are no suitable item in the array
+ return -1;
+ }
+// CmpResult < 0, we have to check pData[R] too
+ if (pIndex)
+ {
+ *pIndex = R;
+ }
+ if (R >= nElemNum)
+ {
+ return -1;
+ }
+ return CmpFunc(pData[R], lParam) ? -1 : R;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline void TMyArray<T, ARG_T, GrowBy, FreeThreshold>::RemoveElem(int nIndex, int nItems)
+{
+ _ASSERT(nIndex >= 0 && nIndex + nItems <= nElemNum);
+ if (!nItems)
+ {
+ return;
+ }
+// delete pData[nIndex];
+// ~pData[nIndex];
+ int I;
+ for (I = nIndex; I < nIndex + nItems; I++)
+ {
+ (pData + I)->~T();
+ }
+ memmove(pData + nIndex, pData + nIndex + nItems, sizeof(T) * (nElemNum - nIndex - nItems));
+ nElemNum -= nItems;
+ if (nAllocNum - nElemNum >= FreeThreshold)
+ {
+ SetAllocNum(nAllocNum - FreeThreshold);
+ }/* else
+ {
+ memset(pData + nElemNum, 0, sizeof(T));
+ }*/
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline void TMyArray<T, ARG_T, GrowBy, FreeThreshold>::RemoveAll()
+{
+ int I;
+ for (I = 0; I < nElemNum; I++)
+ {
+ //delete pData[I];
+ (pData + I)->~T();
+ }
+ nElemNum = 0;
+ SetAllocNum(0);
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline const T& TMyArray<T, ARG_T, GrowBy, FreeThreshold>::operator[](int nIndex) const
+{
+ _ASSERT(nIndex >= 0 && nIndex < nElemNum);
+ return pData[nIndex];
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline T& TMyArray<T, ARG_T, GrowBy, FreeThreshold>::operator[](int nIndex)
+{
+ _ASSERT(nIndex >= 0 && nIndex < nElemNum);
+ return pData[nIndex];
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline TMyArray<T, ARG_T, GrowBy, FreeThreshold>& TMyArray<T, ARG_T, GrowBy, FreeThreshold>::operator = (const TMyArray<T, ARG_T, GrowBy, FreeThreshold> &A)
+{
+ RemoveAll();
+ int I;
+ for (I = 0; I < A.GetSize(); I++)
+ {
+ AddElem(A[I]);
+ }
+ return *this;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline TMyArray<T, ARG_T, GrowBy, FreeThreshold>& TMyArray<T, ARG_T, GrowBy, FreeThreshold>::operator += (const TMyArray<T, ARG_T, GrowBy, FreeThreshold> &A)
+{
+ int I;
+ for (I = 0; I < A.GetSize(); I++)
+ {
+ AddElem(A[I]);
+ }
+ return *this;
+}
+
+typedef TMyArray<char, const char&, 1024, 4096> CHARARRAY;
diff --git a/plugins/NewAwaySysMod/CommonLibs/ThemedImageCheckbox.cpp b/plugins/NewAwaySysMod/CommonLibs/ThemedImageCheckbox.cpp
new file mode 100644
index 0000000000..dbdac0bb11
--- /dev/null
+++ b/plugins/NewAwaySysMod/CommonLibs/ThemedImageCheckbox.cpp
@@ -0,0 +1,381 @@
+/*
+ ThemedImageCheckbox.cpp
+ Copyright (c) 2007 Chervov Dmitry
+
+ 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 "ThemedImageCheckbox.h"
+#include "Themes.h"
+#include "win2k.h"
+
+#define WM_THEMECHANGED 0x031A
+
+#define CG_CHECKBOX_VERTINDENT 2
+#define CG_CHECKBOX_INDENT 1
+#define CG_CHECKBOX_WIDTH 16
+#define CG_IMAGE_INDENT 7
+#define CG_ADDITIONAL_WIDTH 3
+
+// states
+#define CGS_UNCHECKED BST_UNCHECKED
+#define CGS_CHECKED BST_CHECKED
+#define CGS_INDETERMINATE BST_INDETERMINATE
+#define CGS_PRESSED BST_PUSHED // values above and including CGS_PRESSED must coincide with BST_ constants for BM_GETSTATE to work properly
+#define CGS_HOVERED 8
+
+// state masks
+#define CGSM_ISCHECKED 3 // mask for BM_GETCHECK
+#define CGSM_GETSTATE 7 // mask to get only valid values for BM_GETSTATE
+
+#ifndef lengthof
+#define lengthof(s) (sizeof(s) / sizeof(*s))
+#endif
+
+class CCheckboxData
+{
+public:
+ CCheckboxData(): OldWndProc(NULL), Style(0), State(0), hBitmap(NULL), hIcon(NULL) {};
+
+ WNDPROC OldWndProc;
+ int Style; // BS_CHECKBOX, BS_AUTOCHECKBOX, BS_3STATE or BS_AUTO3STATE
+ int State;
+ HBITMAP hBitmap;
+ HICON hIcon;
+};
+
+static int CALLBACK CheckboxWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ CCheckboxData *dat = (CCheckboxData*)GetWindowLong(hWnd, GWL_USERDATA);
+ if (!dat)
+ {
+ return 0;
+ }
+ switch (Msg)
+ {
+ case BM_CLICK:
+ {
+ SendMessage(hWnd, WM_LBUTTONDOWN, 0, 0);
+ SendMessage(hWnd, WM_LBUTTONUP, 0, 0);
+ return 0;
+ } break;
+ case BM_GETCHECK:
+ {
+ return dat->State & CGSM_ISCHECKED;
+ } break;
+ case BM_SETCHECK:
+ {
+ if ((wParam != BST_UNCHECKED && wParam != BST_CHECKED && wParam != BST_INDETERMINATE) || (wParam == BST_INDETERMINATE && dat->Style != BS_3STATE && dat->Style != BS_AUTO3STATE))
+ { // invalid value
+ wParam = BST_CHECKED;
+ }
+ dat->State &= ~CGSM_ISCHECKED;
+ dat->State |= wParam;
+ InvalidateRect(hWnd, NULL, false);
+ SendMessage(GetParent(hWnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hWnd), BN_CLICKED), (LPARAM)hWnd);
+ return 0;
+ } break;
+ case BM_SETSTATE:
+ {
+ if (wParam)
+ {
+ dat->State |= CGS_PRESSED;
+ } else
+ {
+ dat->State &= ~CGS_PRESSED;
+ }
+ InvalidateRect(hWnd, NULL, false);
+ return 0;
+ } break;
+ case BM_GETSTATE:
+ {
+ return (dat->State & CGSM_GETSTATE) | ((GetFocus() == hWnd) ? BST_FOCUS : 0);
+ } break;
+ case BM_SETIMAGE:
+ {
+ int PrevHandle = 0;
+ switch (wParam)
+ {
+ case IMAGE_BITMAP:
+ {
+ PrevHandle = (int)dat->hBitmap;
+ dat->hBitmap = (HBITMAP)lParam;
+ } break;
+ case IMAGE_ICON:
+ {
+ PrevHandle = (int)dat->hIcon;
+ dat->hIcon = (HICON)lParam;
+ } break;
+ default:
+ {
+ return 0;
+ }
+ }
+ InvalidateRect(hWnd, NULL, false);
+ return PrevHandle;
+ } break;
+ case BM_GETIMAGE:
+ {
+ switch (wParam)
+ {
+ case IMAGE_BITMAP:
+ {
+ return (int)dat->hBitmap;
+ } break;
+ case IMAGE_ICON:
+ {
+ return (int)dat->hIcon;
+ } break;
+ }
+ return 0;
+ } break;
+ case WM_GETDLGCODE:
+ {
+ return DLGC_BUTTON;
+ } break;
+ case WM_THEMECHANGED:
+ case WM_ENABLE:
+ {
+ InvalidateRect(hWnd, NULL, false);
+ return 0;
+ } break;
+ case WM_KEYDOWN:
+ {
+ if (wParam == VK_SPACE)
+ {
+ SendMessage(hWnd, BM_SETSTATE, true, 0);
+ }
+ return 0;
+ } break;
+ case WM_KEYUP:
+ {
+ if (wParam == VK_SPACE)
+ {
+ SendMessage(hWnd, BM_SETCHECK, (SendMessage(hWnd, BM_GETCHECK, 0, 0) + 1) % ((dat->Style == BS_AUTO3STATE) ? 3 : 2), 0);
+ SendMessage(hWnd, BM_SETSTATE, false, 0);
+ }
+ return 0;
+ } break;
+ case WM_CAPTURECHANGED:
+ {
+ SendMessage(hWnd, BM_SETSTATE, false, 0);
+ return 0;
+ } break;
+ case WM_ERASEBKGND:
+ {
+ return true;
+ } break;
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ {
+ SetFocus(hWnd);
+ SendMessage(hWnd, BM_SETSTATE, true, 0);
+ SetCapture(hWnd);
+ return 0;
+ } break;
+ case WM_LBUTTONUP:
+ {
+ if (GetCapture() == hWnd)
+ {
+ ReleaseCapture();
+ }
+ SendMessage(hWnd, BM_SETSTATE, false, 0);
+ if (dat->State & CGS_HOVERED && (dat->Style == BS_AUTOCHECKBOX || dat->Style == BS_AUTO3STATE))
+ {
+ SendMessage(hWnd, BM_SETCHECK, (SendMessage(hWnd, BM_GETCHECK, 0, 0) + 1) % ((dat->Style == BS_AUTO3STATE) ? 3 : 2), 0);
+ }
+ return 0;
+ } break;
+ case WM_MOUSEMOVE:
+ {
+ TRACKMOUSEEVENT tme;
+ tme.cbSize = sizeof(tme);
+ tme.dwFlags = TME_LEAVE;
+ tme.dwHoverTime = HOVER_DEFAULT;
+ tme.hwndTrack = hWnd;
+ _TrackMouseEvent(&tme);
+
+ POINT pt;
+ GetCursorPos(&pt);
+ if ((WindowFromPoint(pt) == hWnd) ^ ((dat->State & CGS_HOVERED) != 0))
+ {
+ dat->State ^= CGS_HOVERED;
+ InvalidateRect(hWnd, NULL, false);
+ }
+ return 0;
+ } break;
+ case WM_MOUSELEAVE:
+ {
+ if (dat->State & CGS_HOVERED)
+ {
+ dat->State &= ~CGS_HOVERED;
+ InvalidateRect(hWnd, NULL, false);
+ }
+ return 0;
+ } break;
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ case WM_SYSCOLORCHANGE:
+ {
+ InvalidateRect(hWnd, NULL, false);
+ return 0;
+ } break;
+ case WM_PAINT:
+ {
+ HDC hdc;
+ PAINTSTRUCT ps;
+ hdc = BeginPaint(hWnd, &ps);
+ RECT rc;
+ GetClientRect(hWnd, &rc);
+ HDC hdcMem = CreateCompatibleDC(hdc);
+ HBITMAP hbmMem = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
+ HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
+ HTHEME hTheme = pOpenThemeData ? pOpenThemeData(hWnd, L"BUTTON") : NULL;
+ if (hTheme && pDrawThemeParentBackground)
+ {
+ pDrawThemeParentBackground(hWnd, hdcMem, NULL);
+ } else
+ {
+ FillRect(hdcMem, &rc, GetSysColorBrush(COLOR_3DFACE));
+ }
+ int StateID = 0;
+#define CBSCHECK_UNCHECKED 1
+#define CBSCHECK_CHECKED 5
+#define CBSCHECK_MIXED 9
+#define CBSSTATE_NORMAL 0
+#define CBSSTATE_HOT 1
+#define CBSSTATE_PRESSED 2
+#define CBSSTATE_DISABLED 3
+ switch (SendMessage(hWnd, BM_GETCHECK, 0, 0))
+ {
+ case BST_CHECKED:
+ {
+ StateID += CBSCHECK_CHECKED;
+ } break;
+ case BST_UNCHECKED:
+ {
+ StateID += CBSCHECK_UNCHECKED;
+ } break;
+ case BST_INDETERMINATE:
+ {
+ StateID += CBSCHECK_MIXED;
+ } break;
+ }
+ if (!IsWindowEnabled(hWnd))
+ {
+ StateID += CBSSTATE_DISABLED;
+ } else if (dat->State & CGS_PRESSED && (GetCapture() != hWnd || dat->State & CGS_HOVERED))
+ {
+ StateID += CBSSTATE_PRESSED;
+ } else if (dat->State & CGS_PRESSED || dat->State & CGS_HOVERED)
+ {
+ StateID += CBSSTATE_HOT;
+ }
+ rc.left += CG_CHECKBOX_INDENT;
+ rc.right = rc.left + CG_CHECKBOX_WIDTH; // left-align the image in the client area
+ rc.top += CG_CHECKBOX_VERTINDENT;
+ rc.bottom = rc.top + CG_CHECKBOX_WIDTH; // exact rc dimensions are necessary for DrawFrameControl to draw correctly
+ if (hTheme && pDrawThemeBackground)
+ {
+ pDrawThemeBackground(hTheme, hdcMem, BP_CHECKBOX, StateID, &rc, &rc);
+ } else
+ {
+ int dfcStates[] =
+ {0, 0, DFCS_PUSHED, DFCS_INACTIVE,
+ DFCS_CHECKED, DFCS_CHECKED, DFCS_CHECKED | DFCS_PUSHED, DFCS_CHECKED | DFCS_INACTIVE,
+ DFCS_BUTTON3STATE | DFCS_CHECKED, DFCS_BUTTON3STATE | DFCS_CHECKED, DFCS_BUTTON3STATE | DFCS_INACTIVE | DFCS_CHECKED | DFCS_PUSHED, DFCS_BUTTON3STATE | DFCS_INACTIVE | DFCS_CHECKED | DFCS_PUSHED};
+ _ASSERT(StateID >= 1 && StateID <= lengthof(dfcStates));
+ DrawFrameControl(hdcMem, &rc, DFC_BUTTON, dfcStates[StateID - 1]);
+ }
+
+ GetClientRect(hWnd, &rc);
+ RECT rcImage = rc;
+ LPARAM hImage = NULL;
+ DWORD DSFlags;
+ HIMAGELIST hImageList = NULL;
+ if (dat->hBitmap)
+ {
+ BITMAP bminfo;
+ GetObject(dat->hBitmap, sizeof(bminfo), &bminfo);
+ rcImage.right = bminfo.bmWidth;
+ rcImage.bottom = bminfo.bmHeight;
+ DSFlags = DST_BITMAP;
+ hImage = (LPARAM)dat->hBitmap;
+ } else
+ {
+ rcImage.right = GetSystemMetrics(SM_CXSMICON);
+ rcImage.bottom = GetSystemMetrics(SM_CYSMICON);
+ DSFlags = DST_ICON;
+ if (dat->hIcon)
+ {
+ hImageList = ImageList_Create(rcImage.right, rcImage.bottom, IsWinVerXPPlus() ? ILC_COLOR32 | ILC_MASK : ILC_COLOR16 | ILC_MASK, 1, 0);
+ ImageList_AddIcon(hImageList, dat->hIcon);
+ hImage = (LPARAM)ImageList_GetIcon(hImageList, 0, ILD_NORMAL);
+ }
+ } // rcImage.right and rcImage.bottom are width and height, not absolute coordinates
+ rcImage.left += CG_CHECKBOX_INDENT + CG_CHECKBOX_WIDTH + CG_IMAGE_INDENT;
+ rcImage.top += (rc.bottom - rcImage.bottom) / 2;
+ DrawState(hdcMem, NULL, NULL, hImage, 0, rcImage.left, rcImage.top, rcImage.right, rcImage.bottom, DSFlags | (IsWindowEnabled(hWnd) ? DSS_NORMAL : DSS_DISABLED));
+ if (hImageList)
+ {
+ ImageList_RemoveAll(hImageList);
+ ImageList_Destroy(hImageList);
+ DestroyIcon((HICON)hImage);
+ }
+ if (GetFocus() == hWnd)
+ {
+ rcImage.right += rcImage.left;
+ rcImage.bottom += rcImage.top;
+ InflateRect(&rcImage, 1, 1);
+ DrawFocusRect(hdcMem, &rcImage);
+ }
+ if (hTheme && pCloseThemeData)
+ {
+ pCloseThemeData(hTheme);
+ }
+ BitBlt(hdc, 0, 0, rc.right, rc.bottom, hdcMem, 0, 0, SRCCOPY);
+ SelectObject(hdcMem, hbmOld);
+ DeleteObject(hbmMem);
+ DeleteDC(hdcMem);
+ EndPaint(hWnd, &ps);
+ return 0;
+ } break;
+ case WM_DESTROY:
+ {
+ SetWindowLong(hWnd, GWL_USERDATA, NULL);
+ CallWindowProc(dat->OldWndProc, hWnd, Msg, wParam, lParam);
+ delete dat;
+ return 0;
+ } break;
+ }
+ return CallWindowProc(dat->OldWndProc, hWnd, Msg, wParam, lParam);
+}
+
+int MakeThemedImageCheckbox(HWND hWndCheckbox)
+{ // workaround to make checkbox with BS_ICON or BS_BITMAP work with windows themes enabled
+ CCheckboxData *dat = new CCheckboxData();
+ dat->OldWndProc = (WNDPROC)GetWindowLong(hWndCheckbox, GWL_WNDPROC);
+ dat->State = SendMessage(hWndCheckbox, BM_GETSTATE, 0, 0);
+ long Style = GetWindowLong(hWndCheckbox, GWL_STYLE);
+ _ASSERT(Style & BS_ICON || Style & BS_BITMAP);
+ dat->Style = Style & (BS_CHECKBOX | BS_AUTOCHECKBOX | BS_3STATE | BS_AUTO3STATE);
+ _ASSERT(dat->Style == BS_CHECKBOX || dat->Style == BS_AUTOCHECKBOX || dat->Style == BS_3STATE || dat->Style == BS_AUTO3STATE);
+ Style &= ~(BS_CHECKBOX | BS_AUTOCHECKBOX | BS_3STATE | BS_AUTO3STATE);
+ Style |= BS_OWNERDRAW;
+ SetWindowLong(hWndCheckbox, GWL_STYLE, Style);
+ SetWindowLong(hWndCheckbox, GWL_USERDATA, (LONG)dat);
+ SetWindowLong(hWndCheckbox, GWL_WNDPROC, (LONG)CheckboxWndProc);
+ return 0;
+}
diff --git a/plugins/NewAwaySysMod/CommonLibs/ThemedImageCheckbox.h b/plugins/NewAwaySysMod/CommonLibs/ThemedImageCheckbox.h
new file mode 100644
index 0000000000..f3449ec8fc
--- /dev/null
+++ b/plugins/NewAwaySysMod/CommonLibs/ThemedImageCheckbox.h
@@ -0,0 +1,26 @@
+/*
+ ThemedImageCheckbox.h
+ Copyright (c) 2007 Chervov Dmitry
+
+ 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
+
+#include <windows.h>
+#include <crtdbg.h>
+#include <commctrl.h>
+
+int MakeThemedImageCheckbox(HWND hWndCheckbox);
diff --git a/plugins/NewAwaySysMod/CommonLibs/Themes.cpp b/plugins/NewAwaySysMod/CommonLibs/Themes.cpp
new file mode 100644
index 0000000000..d8213453b5
--- /dev/null
+++ b/plugins/NewAwaySysMod/CommonLibs/Themes.cpp
@@ -0,0 +1,51 @@
+/*
+ Themes.cpp
+ Copyright (c) 2005-2007 Chervov Dmitry
+
+ 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 "Themes.h"
+#include <tchar.h>
+
+#define IsWinVerXPPlus() (LOBYTE(LOWORD(GetVersion())) >= 5 && LOWORD(GetVersion()) != 5)
+
+tOpenThemeData pOpenThemeData = NULL;
+tCloseThemeData pCloseThemeData = NULL;
+tDrawThemeBackground pDrawThemeBackground = NULL;
+tDrawThemeParentBackground pDrawThemeParentBackground = NULL;
+tDrawThemeText pDrawThemeText = NULL;
+tGetThemeTextExtent pGetThemeTextExtent = NULL;
+tEnableThemeDialogTexture pEnableThemeDialogTexture = NULL;
+tSetWindowTheme pSetWindowTheme = NULL;
+
+void InitThemes()
+{
+ if (IsWinVerXPPlus())
+ {
+ HMODULE hThemeAPI = GetModuleHandle(_T("uxtheme"));
+ if (hThemeAPI)
+ {
+ pOpenThemeData = (tOpenThemeData)GetProcAddress(hThemeAPI, "OpenThemeData");
+ pCloseThemeData = (tCloseThemeData)GetProcAddress(hThemeAPI, "CloseThemeData");
+ pDrawThemeBackground = (tDrawThemeBackground)GetProcAddress(hThemeAPI, "DrawThemeBackground");
+ pDrawThemeParentBackground = (tDrawThemeParentBackground)GetProcAddress(hThemeAPI, "DrawThemeParentBackground");
+ pDrawThemeText = (tDrawThemeText)GetProcAddress(hThemeAPI, "DrawThemeText");
+ pGetThemeTextExtent = (tGetThemeTextExtent)GetProcAddress(hThemeAPI, "GetThemeTextExtent");
+ pEnableThemeDialogTexture = (tEnableThemeDialogTexture)GetProcAddress(hThemeAPI, "EnableThemeDialogTexture");
+ pSetWindowTheme = (tSetWindowTheme)GetProcAddress(hThemeAPI, "SetWindowTheme");
+ }
+ }
+}
diff --git a/plugins/NewAwaySysMod/CommonLibs/Themes.h b/plugins/NewAwaySysMod/CommonLibs/Themes.h
new file mode 100644
index 0000000000..524c7514a5
--- /dev/null
+++ b/plugins/NewAwaySysMod/CommonLibs/Themes.h
@@ -0,0 +1,51 @@
+/*
+ Themes.h
+ Copyright (c) 2007 Chervov Dmitry
+
+ 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
+
+#include <windows.h>
+#include <tmschema.h>
+
+typedef HANDLE HTHEME;
+
+// EnableThemeDialogTexture() flags
+#define ETDT_DISABLE 0x00000001
+#define ETDT_ENABLE 0x00000002
+#define ETDT_USETABTEXTURE 0x00000004
+#define ETDT_ENABLETAB (ETDT_ENABLE | ETDT_USETABTEXTURE)
+
+typedef HANDLE (WINAPI *tOpenThemeData)(HWND, LPCWSTR);
+typedef HRESULT (WINAPI *tCloseThemeData)(HANDLE);
+typedef HRESULT (WINAPI *tDrawThemeBackground)(HANDLE, HDC, int, int, const RECT*, const RECT*);
+typedef HRESULT (WINAPI *tDrawThemeParentBackground)(HWND, HDC, RECT*);
+typedef HRESULT (WINAPI *tDrawThemeText)(HANDLE, HDC, int, int, LPCWSTR, int, DWORD, DWORD, const RECT*);
+typedef HRESULT (WINAPI *tGetThemeTextExtent)(HANDLE, HDC, int, int, LPCWSTR, int, DWORD, const RECT*, RECT*);
+typedef HRESULT (WINAPI *tEnableThemeDialogTexture)(HWND, DWORD);
+typedef HRESULT (WINAPI *tSetWindowTheme)(HWND, LPCWSTR, LPCWSTR);
+
+extern tOpenThemeData pOpenThemeData;
+extern tCloseThemeData pCloseThemeData;
+extern tDrawThemeBackground pDrawThemeBackground;
+extern tDrawThemeParentBackground pDrawThemeParentBackground;
+extern tDrawThemeText pDrawThemeText;
+extern tGetThemeTextExtent pGetThemeTextExtent;
+extern tEnableThemeDialogTexture pEnableThemeDialogTexture;
+extern tSetWindowTheme pSetWindowTheme;
+
+void InitThemes();
diff --git a/plugins/NewAwaySysMod/CommonLibs/pcre.cpp b/plugins/NewAwaySysMod/CommonLibs/pcre.cpp
new file mode 100644
index 0000000000..6800a71418
--- /dev/null
+++ b/plugins/NewAwaySysMod/CommonLibs/pcre.cpp
@@ -0,0 +1,295 @@
+/*
+ Pcre.cpp
+ Copyright (c) 2007-2008 Chervov Dmitry
+
+ 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
+*/
+
+#define CHARARRAY_CONVERT
+
+#include "..\NewAwaySys\common.h"
+#include <windows.h>
+#include <stdio.h>
+#include <crtdbg.h>
+#include "newpluginapi.h"
+#include "m_utils.h"
+#include "TMyArray.h"
+#include "CString.h"
+#include "pcre.h"
+
+
+HMODULE hPcreDLL = NULL;
+
+static pcre* (*pcre_compile)(const char*, int, const char**, int*, const unsigned char*);
+static int (*pcre_config)(int, void*);
+static int (*pcre_exec)(const pcre*, const pcre_extra*, const char*, int, int, int, int*, int);
+static void (*pcre_free)(void*);
+static pcre_extra* (*pcre_study)(const pcre*, int, const char **);
+
+
+typedef struct
+{
+ pcre *pPcre;
+ pcre_extra *pExtra;
+ TCString Pattern; // used when it's not a valid regexp
+ int ID; // user-defined ID of the pattern; returned by PcreCheck on a match
+} sPcreCompileData;
+
+TMyArray<sPcreCompileData> PcreCompileData;
+
+
+void FreePcreCompileData()
+{
+ int I;
+ for (I = 0; I < PcreCompileData.GetSize(); I++)
+ {
+ if (PcreCompileData[I].pPcre)
+ {
+ pcre_free(PcreCompileData[I].pPcre);
+ if (PcreCompileData[I].pExtra)
+ {
+ pcre_free(PcreCompileData[I].pExtra);
+ }
+ }
+ }
+ PcreCompileData.RemoveAll();
+}
+
+
+TCString CompileRegexp(TCString Regexp, int bAddAsUsualSubstring, int ID)
+{
+ TCString Result(_T(""));
+ sPcreCompileData s = {0};
+ int NewID = PcreCompileData.AddElem(s);
+ PcreCompileData[NewID].ID = ID;
+ if (hPcreDLL && !bAddAsUsualSubstring)
+ {
+ const char *Err;
+ int ErrOffs;
+ int Flags = PCRE_CASELESS;
+ if (Regexp[0] == '/')
+ {
+ TCString OrigRegexp = Regexp;
+ Regexp = Regexp.Right(Regexp.GetLen() - 1);
+ TCHAR *pRegexpEnd = (TCHAR*)Regexp + Regexp.GetLen();
+ TCHAR *p = _tcsrchr(Regexp.GetBuffer(), '/');
+ if (!p)
+ {
+ Regexp = OrigRegexp;
+ } else
+ {
+ *p = 0;
+ Flags = 0;
+ while (++p < pRegexpEnd)
+ {
+ switch (*p)
+ {
+ case 'i':
+ {
+ Flags |= PCRE_CASELESS;
+ } break;
+ case 'm':
+ {
+ Flags |= PCRE_MULTILINE;
+ } break;
+ case 's':
+ {
+ Flags |= PCRE_DOTALL;
+ } break;
+ case 'x':
+ {
+ Flags |= PCRE_EXTENDED;
+ } break;
+ case 'A':
+ {
+ Flags |= PCRE_ANCHORED;
+ } break;
+ case 'f':
+ {
+ Flags |= PCRE_FIRSTLINE;
+ } break;
+ case 'D':
+ {
+ Flags |= PCRE_DOLLAR_ENDONLY;
+ } break;
+ case 'U':
+ {
+ Flags |= PCRE_UNGREEDY;
+ } break;
+ case 'X':
+ {
+ Flags |= PCRE_EXTRA;
+ } break;
+ default:
+ {
+ Result += LogMessage(TranslateT("Warning, unknown pattern modifier '%c':\n%s"), *p, (TCHAR*)OrigRegexp) + _T("\n\n");
+ } break;
+ }
+ }
+ }
+ Regexp.ReleaseBuffer();
+ }
+#ifdef _UNICODE
+ PcreCompileData[NewID].pPcre = pcre_compile(WCHAR2UTF8(Regexp).GetData(), PCRE_UTF8 | PCRE_NO_UTF8_CHECK | Flags, &Err, &ErrOffs, NULL);
+#else
+ PcreCompileData[NewID].pPcre = pcre_compile(Regexp, Flags, &Err, &ErrOffs, NULL);
+#endif
+ if (PcreCompileData[NewID].pPcre)
+ {
+ PcreCompileData[NewID].pExtra = NULL;
+ if (pcre_study)
+ {
+ PcreCompileData[NewID].pExtra = pcre_study(PcreCompileData[NewID].pPcre, 0, &Err);
+ }
+ } else
+ {
+ Result += LogMessage(TranslateT("Syntax error in regexp\n%s\nat offset %d: %s."), (TCHAR*)Regexp, ErrOffs, (TCHAR*)ANSI2TCHAR(Err)) + _T("\n\n");
+ PcreCompileData[NewID].Pattern = Regexp;
+ }
+ } else
+ {
+ PcreCompileData[NewID].Pattern = Regexp;
+ }
+ return Result;
+}
+
+
+HMODULE LoadPcreLibrary(const char *szPath)
+{
+ _ASSERT(szPath);
+ HMODULE hModule = LoadLibraryA(szPath);
+ if (!hModule)
+ {
+ return NULL;
+ }
+ *(FARPROC*)&pcre_config = GetProcAddress(hModule, "pcre_config");
+ *(FARPROC*)&pcre_compile = GetProcAddress(hModule, "pcre_compile");
+ *(FARPROC*)&pcre_exec = GetProcAddress(hModule, "pcre_exec");
+ *(FARPROC*)&pcre_study = GetProcAddress(hModule, "pcre_study");
+ *(FARPROC*)&pcre_free = *(FARPROC*)GetProcAddress(hModule, "pcre_free"); // pcre_free is a pointer to a variable containing pointer to the function %)
+ if (pcre_compile && pcre_exec && pcre_free)
+ {
+#ifdef _UNICODE
+ int Utf8Supported = 0;
+ if (pcre_config)
+ {
+ pcre_config(PCRE_CONFIG_UTF8, &Utf8Supported);
+ }
+ if (Utf8Supported)
+ {
+ return hModule;
+ }
+#else
+ return hModule;
+#endif
+ }
+ FreeLibrary(hModule);
+ return NULL;
+}
+
+
+void InitPcre()
+{
+ _ASSERT(!hPcreDLL);
+ hPcreDLL = LoadPcreLibrary("pcre.dll");
+ if (!hPcreDLL)
+ {
+ hPcreDLL = LoadPcreLibrary("pcre3.dll");
+ }
+ if (!hPcreDLL)
+ {
+ char path[MAX_PATH];
+ GetModuleFileNameA(NULL, path, sizeof(path));
+ char *p = strrchr(path, '\\');
+ if (p)
+ {
+ strcpy(p + 1, "pcre.dll");
+ } else
+ {
+ strcpy(path, "pcre.dll");
+ }
+ hPcreDLL = LoadPcreLibrary(path);
+ if (!hPcreDLL)
+ {
+ if (p)
+ {
+ strcpy(p + 1, "pcre3.dll");
+ } else
+ {
+ strcpy(path, "pcre3.dll");
+ }
+ hPcreDLL = LoadPcreLibrary(path);
+ }
+ }
+}
+
+
+void UninitPcre()
+{
+ if (hPcreDLL)
+ {
+ FreePcreCompileData();
+ FreeLibrary(hPcreDLL);
+ }
+}
+
+
+int PcreEnabled()
+{
+ return (int)hPcreDLL;
+}
+
+
+int PcreCheck(TCString Str, int StartingID)
+{ // StartingID specifies the pattern from which to start checking, i.e. the check starts from the next pattern after the one that has ID == StartingID
+ int I;
+ if (StartingID == -1)
+ {
+ I = 0;
+ } else
+ {
+ for (I = 0; I < PcreCompileData.GetSize(); I++)
+ {
+ if (PcreCompileData[I].ID == StartingID)
+ {
+ I++;
+ break;
+ }
+ }
+ }
+ for (; I < PcreCompileData.GetSize(); I++)
+ {
+ if (hPcreDLL && PcreCompileData[I].pPcre)
+ {
+#ifdef _UNICODE
+ CHARARRAY Utf8Str = WCHAR2UTF8(Str);
+ int Res = pcre_exec(PcreCompileData[I].pPcre, PcreCompileData[I].pExtra, Utf8Str.GetData(), Utf8Str.GetSize() - 1, 0, PCRE_NOTEMPTY | PCRE_NO_UTF8_CHECK, NULL, 0);
+#else
+ int Res = pcre_exec(PcreCompileData[I].pPcre, PcreCompileData[I].pExtra, Str, Str.GetLen(), 0, PCRE_NOTEMPTY, NULL, 0);
+#endif
+ if (Res >= 0)
+ {
+ return PcreCompileData[I].ID;
+ }
+ } else
+ {
+ if (_tcsstr(Str.ToLower(), PcreCompileData[I].Pattern.ToLower()))
+ {
+ return PcreCompileData[I].ID;
+ }
+ }
+ }
+ return -1;
+}
diff --git a/plugins/NewAwaySysMod/CommonLibs/pcre.h b/plugins/NewAwaySysMod/CommonLibs/pcre.h
new file mode 100644
index 0000000000..2663870f85
--- /dev/null
+++ b/plugins/NewAwaySysMod/CommonLibs/pcre.h
@@ -0,0 +1,30 @@
+/*
+ Pcre.h
+ Copyright (c) 2007-2008 Chervov Dmitry
+
+ 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 "CString.h"
+#include "pcre_main.h"
+
+#pragma once
+
+void InitPcre();
+void UninitPcre();
+int PcreEnabled();
+int PcreCheck(TCString Str, int StartingID = -1);
+void FreePcreCompileData();
+TCString CompileRegexp(TCString Regexp, int bAddAsUsualSubstring = 0, int ID = 0);
diff --git a/plugins/NewAwaySysMod/CommonLibs/pcre_main.h b/plugins/NewAwaySysMod/CommonLibs/pcre_main.h
new file mode 100644
index 0000000000..ca6e7449df
--- /dev/null
+++ b/plugins/NewAwaySysMod/CommonLibs/pcre_main.h
@@ -0,0 +1,298 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* This is the public header file for the PCRE library, to be #included by
+applications that call the PCRE functions.
+
+ Copyright (c) 1997-2006 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifndef _PCRE_H
+#define _PCRE_H
+
+/* The current PCRE version information. */
+
+/* NOTES FOR FUTURE MAINTAINERS: Do not use numbers with leading zeros, because
+they may be treated as octal constants. The PCRE_PRERELEASE feature is for
+identifying release candidates. It might be defined as -RC2, for example. In
+real releases, it should be defined empty. Do not change the alignment of these
+statments. The code in ./configure greps out the version numbers by using "cut"
+to get values from column 29 onwards. These are substituted into pcre-config
+and libpcre.pc. The values are not put into configure.ac and substituted here
+(which would simplify this issue) because that makes life harder for those who
+cannot run ./configure. As it now stands, this file need not be edited in that
+circumstance. */
+
+#define PCRE_MAJOR 7
+#define PCRE_MINOR 0
+#define PCRE_PRERELEASE
+#define PCRE_DATE 18-Dec-2006
+
+/* Win32 uses DLL by default; it needs special stuff for exported functions
+when building PCRE. */
+
+#ifdef _WIN32
+# ifdef PCRE_DEFINITION
+# ifdef DLL_EXPORT
+# define PCRE_DATA_SCOPE __declspec(dllexport)
+# endif
+# else
+# ifndef PCRE_STATIC
+# define PCRE_DATA_SCOPE extern __declspec(dllimport)
+# endif
+# endif
+#endif
+
+/* Otherwise, we use the standard "extern". */
+
+#ifndef PCRE_DATA_SCOPE
+# ifdef __cplusplus
+# define PCRE_DATA_SCOPE extern "C"
+# else
+# define PCRE_DATA_SCOPE extern
+# endif
+#endif
+
+/* Have to include stdlib.h in order to ensure that size_t is defined;
+it is needed here for malloc. */
+
+#include <stdlib.h>
+
+/* Allow for C++ users */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Options */
+
+#define PCRE_CASELESS 0x00000001
+#define PCRE_MULTILINE 0x00000002
+#define PCRE_DOTALL 0x00000004
+#define PCRE_EXTENDED 0x00000008
+#define PCRE_ANCHORED 0x00000010
+#define PCRE_DOLLAR_ENDONLY 0x00000020
+#define PCRE_EXTRA 0x00000040
+#define PCRE_NOTBOL 0x00000080
+#define PCRE_NOTEOL 0x00000100
+#define PCRE_UNGREEDY 0x00000200
+#define PCRE_NOTEMPTY 0x00000400
+#define PCRE_UTF8 0x00000800
+#define PCRE_NO_AUTO_CAPTURE 0x00001000
+#define PCRE_NO_UTF8_CHECK 0x00002000
+#define PCRE_AUTO_CALLOUT 0x00004000
+#define PCRE_PARTIAL 0x00008000
+#define PCRE_DFA_SHORTEST 0x00010000
+#define PCRE_DFA_RESTART 0x00020000
+#define PCRE_FIRSTLINE 0x00040000
+#define PCRE_DUPNAMES 0x00080000
+#define PCRE_NEWLINE_CR 0x00100000
+#define PCRE_NEWLINE_LF 0x00200000
+#define PCRE_NEWLINE_CRLF 0x00300000
+#define PCRE_NEWLINE_ANY 0x00400000
+
+/* Exec-time and get/set-time error codes */
+
+#define PCRE_ERROR_NOMATCH (-1)
+#define PCRE_ERROR_NULL (-2)
+#define PCRE_ERROR_BADOPTION (-3)
+#define PCRE_ERROR_BADMAGIC (-4)
+#define PCRE_ERROR_UNKNOWN_OPCODE (-5)
+#define PCRE_ERROR_UNKNOWN_NODE (-5) /* For backward compatibility */
+#define PCRE_ERROR_NOMEMORY (-6)
+#define PCRE_ERROR_NOSUBSTRING (-7)
+#define PCRE_ERROR_MATCHLIMIT (-8)
+#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */
+#define PCRE_ERROR_BADUTF8 (-10)
+#define PCRE_ERROR_BADUTF8_OFFSET (-11)
+#define PCRE_ERROR_PARTIAL (-12)
+#define PCRE_ERROR_BADPARTIAL (-13)
+#define PCRE_ERROR_INTERNAL (-14)
+#define PCRE_ERROR_BADCOUNT (-15)
+#define PCRE_ERROR_DFA_UITEM (-16)
+#define PCRE_ERROR_DFA_UCOND (-17)
+#define PCRE_ERROR_DFA_UMLIMIT (-18)
+#define PCRE_ERROR_DFA_WSSIZE (-19)
+#define PCRE_ERROR_DFA_RECURSE (-20)
+#define PCRE_ERROR_RECURSIONLIMIT (-21)
+#define PCRE_ERROR_NULLWSLIMIT (-22)
+#define PCRE_ERROR_BADNEWLINE (-23)
+
+/* Request types for pcre_fullinfo() */
+
+#define PCRE_INFO_OPTIONS 0
+#define PCRE_INFO_SIZE 1
+#define PCRE_INFO_CAPTURECOUNT 2
+#define PCRE_INFO_BACKREFMAX 3
+#define PCRE_INFO_FIRSTBYTE 4
+#define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */
+#define PCRE_INFO_FIRSTTABLE 5
+#define PCRE_INFO_LASTLITERAL 6
+#define PCRE_INFO_NAMEENTRYSIZE 7
+#define PCRE_INFO_NAMECOUNT 8
+#define PCRE_INFO_NAMETABLE 9
+#define PCRE_INFO_STUDYSIZE 10
+#define PCRE_INFO_DEFAULT_TABLES 11
+
+/* Request types for pcre_config(). Do not re-arrange, in order to remain
+compatible. */
+
+#define PCRE_CONFIG_UTF8 0
+#define PCRE_CONFIG_NEWLINE 1
+#define PCRE_CONFIG_LINK_SIZE 2
+#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3
+#define PCRE_CONFIG_MATCH_LIMIT 4
+#define PCRE_CONFIG_STACKRECURSE 5
+#define PCRE_CONFIG_UNICODE_PROPERTIES 6
+#define PCRE_CONFIG_MATCH_LIMIT_RECURSION 7
+
+/* Bit flags for the pcre_extra structure. Do not re-arrange or redefine
+these bits, just add new ones on the end, in order to remain compatible. */
+
+#define PCRE_EXTRA_STUDY_DATA 0x0001
+#define PCRE_EXTRA_MATCH_LIMIT 0x0002
+#define PCRE_EXTRA_CALLOUT_DATA 0x0004
+#define PCRE_EXTRA_TABLES 0x0008
+#define PCRE_EXTRA_MATCH_LIMIT_RECURSION 0x0010
+
+/* Types */
+
+struct real_pcre; /* declaration; the definition is private */
+typedef struct real_pcre pcre;
+
+/* When PCRE is compiled as a C++ library, the subject pointer type can be
+replaced with a custom type. For conventional use, the public interface is a
+const char *. */
+
+#ifndef PCRE_SPTR
+#define PCRE_SPTR const char *
+#endif
+
+/* The structure for passing additional data to pcre_exec(). This is defined in
+such as way as to be extensible. Always add new fields at the end, in order to
+remain compatible. */
+
+typedef struct pcre_extra {
+ unsigned long int flags; /* Bits for which fields are set */
+ void *study_data; /* Opaque data from pcre_study() */
+ unsigned long int match_limit; /* Maximum number of calls to match() */
+ void *callout_data; /* Data passed back in callouts */
+ const unsigned char *tables; /* Pointer to character tables */
+ unsigned long int match_limit_recursion; /* Max recursive calls to match() */
+} pcre_extra;
+
+/* The structure for passing out data via the pcre_callout_function. We use a
+structure so that new fields can be added on the end in future versions,
+without changing the API of the function, thereby allowing old clients to work
+without modification. */
+
+typedef struct pcre_callout_block {
+ int version; /* Identifies version of block */
+ /* ------------------------ Version 0 ------------------------------- */
+ int callout_number; /* Number compiled into pattern */
+ int *offset_vector; /* The offset vector */
+ PCRE_SPTR subject; /* The subject being matched */
+ int subject_length; /* The length of the subject */
+ int start_match; /* Offset to start of this match attempt */
+ int current_position; /* Where we currently are in the subject */
+ int capture_top; /* Max current capture */
+ int capture_last; /* Most recently closed capture */
+ void *callout_data; /* Data passed in with the call */
+ /* ------------------- Added for Version 1 -------------------------- */
+ int pattern_position; /* Offset to next item in the pattern */
+ int next_item_length; /* Length of next item in the pattern */
+ /* ------------------------------------------------------------------ */
+} pcre_callout_block;
+
+/* Indirection for store get and free functions. These can be set to
+alternative malloc/free functions if required. Special ones are used in the
+non-recursive case for "frames". There is also an optional callout function
+that is triggered by the (?) regex item. For Virtual Pascal, these definitions
+have to take another form. */
+
+#ifdef PCRE_EXPORTS
+
+#ifndef VPCOMPAT
+PCRE_DATA_SCOPE void *(*pcre_malloc)(size_t);
+PCRE_DATA_SCOPE void (*pcre_free)(void *);
+PCRE_DATA_SCOPE void *(*pcre_stack_malloc)(size_t);
+PCRE_DATA_SCOPE void (*pcre_stack_free)(void *);
+PCRE_DATA_SCOPE int (*pcre_callout)(pcre_callout_block *);
+#else /* VPCOMPAT */
+PCRE_DATA_SCOPE void *pcre_malloc(size_t);
+PCRE_DATA_SCOPE void pcre_free(void *);
+PCRE_DATA_SCOPE void *pcre_stack_malloc(size_t);
+PCRE_DATA_SCOPE void pcre_stack_free(void *);
+PCRE_DATA_SCOPE int pcre_callout(pcre_callout_block *);
+#endif /* VPCOMPAT */
+
+/* Exported PCRE functions */
+
+PCRE_DATA_SCOPE pcre *pcre_compile(const char *, int, const char **, int *,
+ const unsigned char *);
+PCRE_DATA_SCOPE pcre *pcre_compile2(const char *, int, int *, const char **,
+ int *, const unsigned char *);
+PCRE_DATA_SCOPE int pcre_config(int, void *);
+PCRE_DATA_SCOPE int pcre_copy_named_substring(const pcre *, const char *,
+ int *, int, const char *, char *, int);
+PCRE_DATA_SCOPE int pcre_copy_substring(const char *, int *, int, int, char *,
+ int);
+PCRE_DATA_SCOPE int pcre_dfa_exec(const pcre *, const pcre_extra *,
+ const char *, int, int, int, int *, int , int *, int);
+PCRE_DATA_SCOPE int pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR,
+ int, int, int, int *, int);
+PCRE_DATA_SCOPE void pcre_free_substring(const char *);
+PCRE_DATA_SCOPE void pcre_free_substring_list(const char **);
+PCRE_DATA_SCOPE int pcre_fullinfo(const pcre *, const pcre_extra *, int,
+ void *);
+PCRE_DATA_SCOPE int pcre_get_named_substring(const pcre *, const char *,
+ int *, int, const char *, const char **);
+PCRE_DATA_SCOPE int pcre_get_stringnumber(const pcre *, const char *);
+PCRE_DATA_SCOPE int pcre_get_stringtable_entries(const pcre *, const char *,
+ char **, char **);
+PCRE_DATA_SCOPE int pcre_get_substring(const char *, int *, int, int,
+ const char **);
+PCRE_DATA_SCOPE int pcre_get_substring_list(const char *, int *, int,
+ const char ***);
+PCRE_DATA_SCOPE int pcre_info(const pcre *, int *, int *);
+PCRE_DATA_SCOPE const unsigned char *pcre_maketables(void);
+PCRE_DATA_SCOPE int pcre_refcount(pcre *, int);
+PCRE_DATA_SCOPE pcre_extra *pcre_study(const pcre *, int, const char **);
+PCRE_DATA_SCOPE const char *pcre_version(void);
+
+#endif /* PCRE_EXPORTS */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* End of pcre.h */
diff --git a/plugins/NewAwaySysMod/ContactList.cpp b/plugins/NewAwaySysMod/ContactList.cpp
new file mode 100644
index 0000000000..70b26d1d57
--- /dev/null
+++ b/plugins/NewAwaySysMod/ContactList.cpp
@@ -0,0 +1,905 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (c) 2005-2007 Chervov Dmitry
+
+ 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 "Common.h"
+#include "ContactList.h"
+#include "Properties.h"
+
+#define INTM_CONTACTDELETED (WM_USER + 1)
+#define INTM_ICONCHANGED (WM_USER + 2)
+#define INTM_INVALIDATE (WM_USER + 3)
+
+#define HCONTACT_ISGROUP 0x80000000
+#define HCONTACT_ISINFO 0xFFFF0000
+#define IsHContactInfo(h) (((unsigned)(h) & HCONTACT_ISINFO) == HCONTACT_ISINFO)
+#define IsHContactGroup(h) (!IsHContactInfo(h) && ((unsigned)(h) & HCONTACT_ISGROUP))
+#define IsHContactContact(h) (((unsigned)(h) & HCONTACT_ISGROUP) == 0)
+
+#define EXTRAICON_XSTEP (GetSystemMetrics(SM_CXSMICON) + 1)
+
+static HANDLE hCLWindowList;
+
+
+static int CLContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_Broadcast(hCLWindowList, INTM_CONTACTDELETED, wParam, lParam);
+ return 0;
+}
+
+static int CLContactIconChanged(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_Broadcast(hCLWindowList, INTM_ICONCHANGED, wParam, lParam);
+ return 0;
+}
+
+static int CLIconsChanged(WPARAM wParam, LPARAM lParam)
+{
+ WindowList_Broadcast(hCLWindowList, INTM_INVALIDATE, 0, 0);
+ return 0;
+}
+
+void LoadCListModule()
+{
+ hCLWindowList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0);
+ HookEvent(ME_DB_CONTACT_DELETED, CLContactDeleted);
+ HookEvent(ME_CLIST_CONTACTICONCHANGED, CLContactIconChanged);
+ HookEvent(ME_SKIN_ICONSCHANGED, CLIconsChanged);
+}
+
+
+static LRESULT CALLBACK ParentSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ CCList *dat = CWndUserData(hWnd).GetCList();
+ switch (Msg)
+ {
+ case WM_NOTIFY:
+ {
+ LPNMHDR pnmh = (LPNMHDR)lParam;
+ if (pnmh->hwndFrom == dat->hTreeView)
+ {
+ switch (pnmh->code)
+ {
+ case TVN_ITEMEXPANDED: // just set an appropriate group image
+ {
+ LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam;
+ TVITEM tvItem;
+ tvItem.hItem = pnmtv->itemNew.hItem;
+ tvItem.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tvItem.iImage = tvItem.iSelectedImage = (pnmtv->itemNew.state & TVIS_EXPANDED) ? IMAGE_GROUPOPEN : IMAGE_GROUPSHUT;
+ TreeView_SetItem(dat->hTreeView, &tvItem);
+ } break;
+ case TVN_SELCHANGED:
+ {
+ LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam;
+ TREEITEMARRAY OldSelection = dat->SelectedItems;
+ int I;
+ for (I = 0; I < dat->SelectedItems.GetSize(); I++)
+ {
+ if (dat->SelectedItems[I] != pnmtv->itemNew.hItem)
+ {
+ TreeView_SetItemState(dat->hTreeView, dat->SelectedItems[I], 0, TVIS_SELECTED);
+ }
+ }
+ dat->SelectedItems.RemoveAll();
+ if (pnmtv->itemNew.hItem)
+ {
+ dat->SelectedItems.AddElem(pnmtv->itemNew.hItem);
+ dat->SelectGroups(pnmtv->itemNew.hItem, true);
+ }
+ NMCLIST nm;
+ nm.hdr.code = MCLN_SELCHANGED;
+ nm.hdr.hwndFrom = dat->hTreeView;
+ nm.hdr.idFrom = GetDlgCtrlID(dat->hTreeView);
+ nm.OldSelection = &OldSelection;
+ nm.NewSelection = &dat->SelectedItems;
+ SendMessage(hWnd, WM_NOTIFY, 0, (LPARAM)&nm);
+ } break;
+ case TVN_DELETEITEM:
+ {
+ if (dat->Items.GetSize()) // if Items size = 0, then this TVN_DELETEITEM came after WM_DESTROY, so there is no need to do anything
+ {
+ LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam;
+ TREEITEMARRAY OldSelection = dat->SelectedItems;
+ int Index = dat->SelectedItems.Find(pnmtv->itemOld.hItem);
+ if (Index != -1)
+ {
+ dat->SelectedItems.RemoveElem(Index);
+ }
+ // find an item to pass to SelectGroups()
+ HTREEITEM hItem = TreeView_GetNextSibling(dat->hTreeView, pnmtv->itemOld.hItem);
+ if (!hItem)
+ {
+ hItem = TreeView_GetPrevSibling(dat->hTreeView, pnmtv->itemOld.hItem);
+ if (!hItem)
+ {
+ hItem = TreeView_GetParent(dat->hTreeView, pnmtv->itemOld.hItem);
+ }
+ }
+ if (hItem) // if it wasn't one of the root items
+ {
+ dat->SelectGroups(hItem, dat->SelectedItems.Find(hItem) != -1);
+ }
+ NMCLIST nm;
+ nm.hdr.code = MCLN_SELCHANGED;
+ nm.hdr.hwndFrom = dat->hTreeView;
+ nm.hdr.idFrom = GetDlgCtrlID(dat->hTreeView);
+ nm.OldSelection = &OldSelection;
+ nm.NewSelection = &dat->SelectedItems;
+ SendMessage(hWnd, WM_NOTIFY, 0, (LPARAM)&nm);
+ dat->Items[pnmtv->itemOld.lParam].hContact = INVALID_HANDLE_VALUE;
+ }
+ } break;
+ case NM_CUSTOMDRAW:
+ {
+ LPNMTVCUSTOMDRAW lpNMCD = (LPNMTVCUSTOMDRAW)lParam;
+ switch (lpNMCD->nmcd.dwDrawStage)
+ {
+ case CDDS_PREPAINT: // the control is about to start painting
+ {
+ return CDRF_NOTIFYITEMDRAW; // instruct the control to return information when it draws items
+ } break;
+ case CDDS_ITEMPREPAINT:
+ {
+ return CDRF_NOTIFYPOSTPAINT;
+ } break;
+ case CDDS_ITEMPOSTPAINT:
+ {
+ RECT rc;
+ if (TreeView_GetItemRect(dat->hTreeView, (HTREEITEM)lpNMCD->nmcd.dwItemSpec, &rc, false))
+ {
+ int I;
+ for (I = 0; I < MAXEXTRAICONS; I++)
+ {
+ BYTE nIndex = dat->Items[lpNMCD->nmcd.lItemlParam].ExtraIcons[I];
+ if (nIndex != CLC_EXTRAICON_EMPTY)
+ {
+ ImageList_DrawEx(dat->ExtraImageList, nIndex, lpNMCD->nmcd.hdc, rc.right - EXTRAICON_XSTEP * (I + 1), rc.top, 0, 0, /*GetSysColor(COLOR_WINDOW)*/CLR_NONE, CLR_NONE, ILD_NORMAL);
+ }
+ }
+ }
+ } break;
+ }
+ } break;
+ }
+ }
+ }
+ }
+ return CallWindowProc(dat->OrigParentProc, hWnd, Msg, wParam, lParam);
+}
+
+
+static LRESULT CALLBACK ContactListSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ CCList *dat = CWndUserData(GetParent(hWnd)).GetCList();
+ switch (Msg)
+ {
+ case INTM_CONTACTDELETED: // wParam = (HANDLE)hContact
+ {
+ HTREEITEM hItem = dat->FindContact((HANDLE)wParam);
+ if (hItem)
+ {
+ TreeView_DeleteItem(hWnd, hItem);
+ }
+ } break;
+ case INTM_ICONCHANGED: // wParam = (HANDLE)hContact, lParam = IconID
+ {
+ TVITEM tvi;
+ tvi.hItem = dat->FindContact((HANDLE)wParam);
+ if (tvi.hItem)
+ {
+ tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tvi.iImage = tvi.iSelectedImage = lParam;
+ TreeView_SetItem(hWnd, &tvi);
+ dat->SortContacts();
+ InvalidateRect(hWnd, NULL, false);
+ }
+ } break;
+ case INTM_INVALIDATE:
+ {
+ InvalidateRect(hWnd, NULL, true);
+ } break;
+ case WM_RBUTTONDOWN:
+ {
+ SetFocus(hWnd);
+ TVHITTESTINFO hitTest;
+ hitTest.pt.x = (short)LOWORD(lParam);
+ hitTest.pt.y = (short)HIWORD(lParam);
+ TreeView_HitTest(hWnd, &hitTest);
+ if (hitTest.hItem && hitTest.flags & TVHT_ONITEM)
+ {
+ TreeView_SelectItem(hWnd, hitTest.hItem);
+ }
+ return DefWindowProc(hWnd, Msg, wParam, lParam);
+ } break;
+ case WM_LBUTTONDOWN:
+ {
+ POINT pt = {(short)LOWORD(lParam), (short)HIWORD(lParam)};
+ DWORD hitFlags;
+ HTREEITEM hItem = dat->HitTest(&pt, &hitFlags);
+ if (!hItem)
+ {
+ break;
+ }
+ if (hitFlags & MCLCHT_ONITEMICON)
+ {
+ if (TreeView_GetChild(hWnd, hItem)) // if it's a group, then toggle its state
+ {
+ NMTREEVIEW nmtv;
+ nmtv.hdr.hwndFrom = hWnd;
+ nmtv.hdr.idFrom = GetDlgCtrlID(hWnd);
+ nmtv.hdr.code = TVN_ITEMEXPANDING;
+ nmtv.action = TVE_TOGGLE;
+ nmtv.itemNew.hItem = hItem;
+ nmtv.itemNew.mask = TVIF_HANDLE | TVIF_STATE | TVIF_PARAM;
+ TreeView_GetItem(hWnd, &nmtv.itemNew);
+ nmtv.ptDrag = pt;
+ if (SendMessage(GetParent(hWnd), WM_NOTIFY, 0, (LPARAM)&nmtv))
+ {
+ return 0;
+ }
+ HTREEITEM hOldSelItem = TreeView_GetSelection(hWnd);
+ TreeView_Expand(hWnd, hItem, TVE_TOGGLE);
+ HTREEITEM hNewSelItem = TreeView_GetSelection(hWnd);
+ if (hNewSelItem != hOldSelItem)
+ {
+ TreeView_SetItemState(hWnd, hOldSelItem, (dat->SelectedItems.Find(hOldSelItem) == -1) ? 0 : TVIS_SELECTED, TVIS_SELECTED);
+ TreeView_SetItemState(hWnd, hNewSelItem, (dat->SelectedItems.Find(hNewSelItem) == -1) ? 0 : TVIS_SELECTED, TVIS_SELECTED);
+ }
+ nmtv.hdr.code = TVN_ITEMEXPANDED;
+ TreeView_GetItem(hWnd, &nmtv.itemNew);
+ SendMessage(GetParent(hWnd), WM_NOTIFY, 0, (LPARAM)&nmtv);
+ return 0;
+ }
+ }
+ if (hitFlags & MCLCHT_ONITEM)
+ {
+ if (wParam & MK_CONTROL)
+ {
+ SetFocus(hWnd);
+ TREEITEMARRAY OldSelection = dat->SelectedItems;
+ int nIndex = dat->SelectedItems.Find(hItem);
+ if (nIndex == -1)
+ {
+ TreeView_SetItemState(hWnd, hItem, TVIS_SELECTED, TVIS_SELECTED);
+ dat->SelectedItems.AddElem(hItem);
+ } else
+ {
+ TreeView_SetItemState(hWnd, hItem, 0, TVIS_SELECTED);
+ dat->SelectedItems.RemoveElem(nIndex);
+ }
+ dat->SelectGroups(hItem, nIndex == -1);
+ NMCLIST nm;
+ nm.hdr.code = MCLN_SELCHANGED;
+ nm.hdr.hwndFrom = hWnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hWnd);
+ nm.OldSelection = &OldSelection;
+ nm.NewSelection = &dat->SelectedItems;
+ SendMessage(GetParent(hWnd), WM_NOTIFY, 0, (LPARAM)&nm);
+ return 0;
+ } else
+ {
+ if (hItem == TreeView_GetSelection(hWnd) && (dat->SelectedItems.GetSize() != 1 || (dat->SelectedItems.GetSize() == 1 && dat->SelectedItems[0] != hItem))) // if it was a click on the selected item and there's need to do something in this case, then send SELCHANGED notification by ourselves, as the tree control doesn't do anything
+ {
+ TreeView_SetItemState(hWnd, hItem, TVIS_SELECTED, TVIS_SELECTED);
+ NMTREEVIEW nm = {0};
+ nm.hdr.code = TVN_SELCHANGED;
+ nm.hdr.hwndFrom = hWnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hWnd);
+ nm.itemOld.hItem = TreeView_GetSelection(hWnd);
+ nm.itemOld.mask = TVIF_HANDLE | TVIF_STATE | TVIF_PARAM;
+ TreeView_GetItem(hWnd, &nm.itemOld);
+ nm.itemNew = nm.itemOld;
+ SendMessage(GetParent(hWnd), WM_NOTIFY, 0, (LPARAM)&nm);
+ }
+ }
+ }
+ } break;
+ case WM_SETFOCUS:
+ case WM_KILLFOCUS:
+ {
+ int I;
+ for (I = 0; I < dat->SelectedItems.GetSize(); I++)
+ {
+ RECT rc;
+ if (TreeView_GetItemRect(hWnd, dat->SelectedItems[I], &rc, false))
+ {
+ InvalidateRect(hWnd, &rc, false);
+ }
+ }
+ } break;
+ case WM_SIZE:
+ case WM_HSCROLL:
+ {
+ InvalidateRect(hWnd, NULL, false);
+ } break;
+ case WM_MEASUREITEM:
+ {
+ if (!wParam) // if the message was sent by a menu
+ {
+ return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam);
+ }
+ } break;
+ case WM_DRAWITEM:
+ {
+ if (!wParam) // if the message was sent by a menu
+ {
+ return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam);
+ }
+ } break;
+ case WM_CONTEXTMENU:
+ {
+ POINT pt;
+ pt.x = (short)LOWORD(lParam);
+ pt.y = (short)HIWORD(lParam);
+ HTREEITEM hItem = NULL;
+ if (pt.x == -1 && pt.y == -1)
+ {
+ if (dat->SelectedItems.GetSize() == 1)
+ {
+ hItem = dat->SelectedItems[0];
+ TreeView_EnsureVisible(hWnd, hItem);
+ RECT rc;
+ TreeView_GetItemRect(hWnd, hItem, &rc, true);
+ pt.x = rc.left;
+ pt.y = rc.bottom;
+ }
+ } else
+ {
+ DWORD hitFlags;
+ ScreenToClient(hWnd, &pt);
+ hItem = dat->HitTest(&pt, &hitFlags);
+ if (!(hitFlags & MCLCHT_ONITEM))
+ {
+ hItem = NULL;
+ }
+ }
+ if (hItem)
+ {
+ HANDLE hContact = dat->GetItemData(hItem).hContact;
+ if (IsHContactContact(hContact))
+ {
+ HMENU hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)hContact, 0);
+ if (hMenu)
+ {
+ ClientToScreen(hWnd, &pt);
+ CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, 0, hWnd, NULL), MPCF_CONTACTMENU), (LPARAM)hContact);
+ DestroyMenu(hMenu);
+ return 0;
+ }
+ }
+ }
+ } break;
+ case WM_DESTROY:
+ {
+ if (dat->ExtraImageList)
+ {
+ ImageList_Destroy(dat->ExtraImageList);
+ }
+ dat->SelectedItems.RemoveAll();
+ dat->Items.RemoveAll();
+ } break;
+ }
+ return CallWindowProc(dat->OrigTreeViewProc, hWnd, Msg, wParam, lParam);
+}
+
+
+CCList::CCList(HWND hTreeView): hTreeView(hTreeView), ExtraImageList(NULL)
+{
+ CWndUserData(GetParent(hTreeView)).SetCList(this);
+ OrigTreeViewProc = (WNDPROC)SetWindowLongPtr(hTreeView, GWLP_WNDPROC, (LONG_PTR)ContactListSubclassProc);
+ OrigParentProc = (WNDPROC)SetWindowLongPtr(GetParent(hTreeView), GWLP_WNDPROC, (LONG_PTR)ParentSubclassProc);
+ TreeView_SetImageList(hTreeView, CallService(MS_CLIST_GETICONSIMAGELIST, 0, 0), TVSIL_NORMAL);
+ WindowList_Add(hCLWindowList, hTreeView, NULL);
+ TreeView_SetIndent(hTreeView, 5); // doesn't set it less than the initial value on my system, and I guess it's because of icons... but who knows - maybe it will work somewhere
+}
+
+
+CCList::~CCList()
+{
+ WindowList_Remove(hCLWindowList, hTreeView);
+ _ASSERT(GetWindowLongPtr(GetParent(hTreeView), GWLP_WNDPROC) == (LONG_PTR)ParentSubclassProc); // we won't allow anyone to change our WNDPROC. otherwise we're not sure that we're setting the right WNDPROC back
+ SetWindowLongPtr(hTreeView, GWLP_WNDPROC, (LONG_PTR)OrigTreeViewProc);
+ SetWindowLongPtr(GetParent(hTreeView), GWLP_WNDPROC, (LONG_PTR)OrigParentProc);
+ CWndUserData(GetParent(hTreeView)).SetCList(NULL);
+}
+
+
+HTREEITEM CCList::AddContact(HANDLE hContact)
+// adds a new contact if it doesn't exist yet; returns its hItem
+{
+ _ASSERT(IsHContactContact(hContact));
+ HTREEITEM hContactItem = FindContact(hContact);
+ if (hContactItem)
+ {
+ return hContactItem;
+ }
+ TVINSERTSTRUCT tvIns;
+ ZeroMemory(&tvIns, sizeof(tvIns));
+ tvIns.hParent = AddGroup(DBGetContactSettingString(hContact, "CList", "Group", _T("")));
+/* if (!tvIns.hParent)
+ {
+ return NULL;
+ }*/ // <- place hidden contacts in the root anyway, as otherwise we won't see icq contacts that are hidden beneath metacontacts; TODO: show metacontacts as groups??
+ tvIns.item.pszText = (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR);
+ tvIns.hInsertAfter = TVI_ROOT;
+ tvIns.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
+ tvIns.item.iImage = tvIns.item.iSelectedImage = CallService(MS_CLIST_GETCONTACTICON, (WPARAM)hContact, 0);
+ tvIns.item.lParam = Items.AddElem(CCLItemData(hContact));
+ return TreeView_InsertItem(hTreeView, &tvIns);
+}
+
+
+typedef struct
+{
+ HANDLE hGroup;
+ TCString GroupName;
+} sGroupEnumData;
+
+int GroupEnum(const char *szSetting, LPARAM lParam)
+{
+ sGroupEnumData *GroupEnumData = (sGroupEnumData*)lParam;
+ TCString GroupName = DBGetContactSettingString(NULL, "CListGroups", szSetting, _T(" "));
+ if (!lstrcmp(GroupEnumData->GroupName, &GroupName[1]))
+ {
+ GroupEnumData->hGroup = (HANDLE)(atol(szSetting) | HCONTACT_ISGROUP);
+ }
+ return 0;
+}
+
+HTREEITEM CCList::AddGroup(TCString GroupName)
+// adds a new group if it doesn't exist yet; returns its hItem
+{
+ if (GroupName == _T(""))
+ {
+ return TVI_ROOT;
+ }
+ sGroupEnumData GroupEnumData;
+ GroupEnumData.GroupName = GroupName;
+ GroupEnumData.hGroup = NULL;
+ DBCONTACTENUMSETTINGS dbEnum;
+ ZeroMemory(&dbEnum, sizeof(dbEnum));
+ dbEnum.lParam = (LPARAM)&GroupEnumData;
+ dbEnum.pfnEnumProc = GroupEnum;
+ dbEnum.szModule = "CListGroups";
+ CallService(MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbEnum);
+ if (!GroupEnumData.hGroup) // means there is no such group in the groups list
+ {
+ return NULL;
+ }
+ HTREEITEM hGroupItem = FindContact(GroupEnumData.hGroup);
+ if (hGroupItem)
+ {
+ return hGroupItem; // exists already, just return its handle
+ }
+ TVINSERTSTRUCT tvIns = {0};
+ tvIns.hParent = TVI_ROOT;
+ tvIns.item.pszText = _tcsrchr(GroupName, '\\');
+ if (tvIns.item.pszText)
+ {
+ TCString ParentGroupName(_T(""));
+ tvIns.hParent = AddGroup(ParentGroupName.DiffCat(GroupName, tvIns.item.pszText));
+ tvIns.item.pszText++;
+ } else
+ {
+ tvIns.item.pszText = GroupName;
+ }
+ tvIns.hInsertAfter = TVI_ROOT;
+ tvIns.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM;
+ tvIns.item.state = tvIns.item.stateMask = TVIS_BOLD | TVIS_EXPANDED;
+ tvIns.item.iImage = tvIns.item.iSelectedImage = IMAGE_GROUPOPEN;
+ tvIns.item.lParam = Items.AddElem(CCLItemData(GroupEnumData.hGroup));
+ return TreeView_InsertItem(hTreeView, &tvIns);
+}
+
+
+HTREEITEM CCList::AddInfo(TCString Title, HTREEITEM hParent, HTREEITEM hInsertAfter, LPARAM lParam, HICON hIcon)
+{
+ TVINSERTSTRUCT tvi = {0};
+ tvi.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvi.item.pszText = Title;
+ tvi.hParent = hParent;
+ tvi.hInsertAfter = hInsertAfter;
+ tvi.item.lParam = Items.AddElem(CCLItemData());
+ Items[tvi.item.lParam].lParam = lParam;
+ tvi.item.state = tvi.item.stateMask = TVIS_BOLD | TVIS_EXPANDED;
+ if (hIcon)
+ {
+ HIMAGELIST iml = TreeView_GetImageList(hTreeView, TVSIL_NORMAL);
+ tvi.item.mask |= TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tvi.item.iImage = tvi.item.iSelectedImage = ImageList_AddIcon(iml, hIcon); // we don't check for duplicate icons, but I think that's ok, judging that the check will require some pretty significant amount of additional coding
+ TreeView_SetImageList(hTreeView, iml, TVSIL_NORMAL);
+ }
+ return TreeView_InsertItem(hTreeView, &tvi);
+}
+
+
+void CCList::SetInfoIcon(HTREEITEM hItem, HICON hIcon)
+{
+ _ASSERT(hItem && hIcon && GetItemType(hItem) == MCLCIT_INFO);
+ TVITEM tvi = {0};
+ tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tvi.hItem = hItem;
+ HIMAGELIST iml = TreeView_GetImageList(hTreeView, TVSIL_NORMAL);
+ tvi.iImage = tvi.iSelectedImage = ImageList_AddIcon(iml, hIcon); // again, we don't check for duplicate icons
+ TreeView_SetImageList(hTreeView, iml, TVSIL_NORMAL);
+ TreeView_SetItem(hTreeView, &tvi);
+}
+
+
+static int CALLBACK CompareItemsCallback(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+ CCList *dat = (CCList*)lParamSort;
+ if (IsHContactInfo(dat->Items[lParam1].hContact)) // Info items precede all other items
+ {
+ return (IsHContactInfo(dat->Items[lParam2].hContact)) ? 0 : -1;
+ } else if (IsHContactInfo(dat->Items[lParam2].hContact))
+ {
+ return 1;
+ }
+ if (IsHContactGroup(dat->Items[lParam1].hContact)) // groups precede contacts
+ {
+ if (IsHContactGroup(dat->Items[lParam2].hContact))
+ {
+ return (unsigned)dat->Items[lParam1].hContact - (unsigned)dat->Items[lParam2].hContact;
+ } else
+ {
+ return -1;
+ }
+ } else if (IsHContactGroup(dat->Items[lParam2].hContact))
+ {
+ return 1;
+ }
+ return CallService(MS_CLIST_CONTACTSCOMPARE, (WPARAM)dat->Items[lParam1].hContact, (LPARAM)dat->Items[lParam2].hContact);
+}
+
+void CCList::SortContacts()
+{
+ TVSORTCB tvSort;
+ ZeroMemory(&tvSort, sizeof(tvSort));
+ tvSort.lpfnCompare = CompareItemsCallback;
+ tvSort.hParent = TVI_ROOT;
+ tvSort.lParam = (LPARAM)this;
+ while (tvSort.hParent)
+ {
+ TreeView_SortChildrenCB(hTreeView, &tvSort, 0);
+ tvSort.hParent = GetNextItem(MCLGN_NEXT | MCLGN_GROUP | MCLGN_MULTILEVEL, tvSort.hParent);
+ }
+}
+
+
+int CCList::GetExtraImage(HTREEITEM hItem, int iColumn) // returns iImage, or CLC_EXTRAICON_EMPTY
+{
+ _ASSERT(iColumn < MAXEXTRAICONS);
+ return GetItemData(hItem).ExtraIcons[iColumn];
+}
+
+
+void CCList::SetExtraImage(HTREEITEM hItem, int iColumn, int iImage) // set iImage to CLC_EXTRAICON_EMPTY to reset image
+{
+ _ASSERT(iColumn < MAXEXTRAICONS);
+ GetItemData(hItem).ExtraIcons[iColumn] = iImage;
+ RECT rc;
+ if (TreeView_GetItemRect(hTreeView, hItem, &rc, false))
+ {
+ InvalidateRect(hTreeView, &rc, true);
+ }
+}
+
+
+void CCList::SetExtraImageList(HIMAGELIST hImgList)
+{
+ ExtraImageList = hImgList;
+ InvalidateRect(hTreeView, NULL, false);
+}
+
+
+int CCList::GetItemType(HTREEITEM hItem) // returns a MCLCIT_ (see below)
+{
+ HANDLE hContact = GetItemData(hItem).hContact;
+ return (IsHContactInfo(hContact)) ? MCLCIT_INFO : ((IsHContactGroup(hContact)) ? MCLCIT_GROUP : MCLCIT_CONTACT);
+}
+
+
+DWORD CCList::GetItemTypeAsCLGNFlag(HTREEITEM hItem)
+{
+ HANDLE hContact = GetItemData(hItem).hContact;
+ return (IsHContactInfo(hContact)) ? MCLGN_INFO : ((IsHContactGroup(hContact)) ? MCLGN_GROUP : MCLGN_CONTACT);
+}
+
+
+HTREEITEM CCList::GetNextItem(DWORD Flags, HTREEITEM hItem)
+{
+ switch (Flags & ~(MCLGN_MULTILEVEL | MCLGN_NOTCHILD | MCLGN_ANY))
+ {
+ case MCLGN_ROOT:
+ {
+ return TreeView_GetRoot(hTreeView);
+ } break;
+ case MCLGN_LAST:
+ {
+ HTREEITEM hNextItem = TVI_ROOT;
+ do
+ {
+ hItem = hNextItem;
+ hNextItem = TreeView_GetLastChild(hTreeView, hNextItem);
+ } while (hNextItem);
+ return (hItem == TVI_ROOT) ? NULL : hItem;
+ } break;
+ case MCLGN_CHILD:
+ {
+ return TreeView_GetChild(hTreeView, hItem);
+ } break;
+ case MCLGN_LASTCHILD:
+ {
+ return TreeView_GetLastChild(hTreeView, hItem);
+ } break;
+ case MCLGN_PARENT:
+ {
+ return TreeView_GetParent(hTreeView, hItem);
+ } break;
+ case MCLGN_NEXT:
+ {
+ do
+ {
+ if (Flags & MCLGN_MULTILEVEL)
+ {
+ HTREEITEM hNextItem = NULL;
+ if ((Flags & MCLGN_NOTCHILD) != MCLGN_NOTCHILD)
+ {
+ hNextItem = TreeView_GetChild(hTreeView, hItem);
+ }
+ if (!hNextItem)
+ {
+ hNextItem = TreeView_GetNextSibling(hTreeView, hItem);
+ while (!hNextItem) // move back until we find next sibling of the item or one of its parents
+ {
+ hItem = TreeView_GetParent(hTreeView, hItem);
+ if (!hItem) // means it was the root, there are no items left.
+ {
+ break; // returns NULL as the next item
+ }
+ hNextItem = TreeView_GetNextSibling(hTreeView, hItem);
+ }
+ }
+ hItem = hNextItem;
+ } else
+ {
+ hItem = TreeView_GetNextSibling(hTreeView, hItem);
+ }
+ Flags &= ~(MCLGN_NOTCHILD & ~MCLGN_MULTILEVEL); // clear MCLGN_NOTCHILD flag
+ } while (hItem && !(Flags & GetItemTypeAsCLGNFlag(hItem)));
+ return hItem;
+ } break;
+ case MCLGN_PREV:
+ {
+ do
+ {
+ if (Flags & MCLGN_MULTILEVEL)
+ {
+ HTREEITEM hNextItem = TreeView_GetPrevSibling(hTreeView, hItem);
+ if (hNextItem)
+ {
+ if ((Flags & MCLGN_NOTCHILD) != MCLGN_NOTCHILD)
+ {
+ while (hNextItem)
+ {
+ hItem = hNextItem;
+ hNextItem = TreeView_GetLastChild(hTreeView, hItem);
+ }
+ } else
+ {
+ hItem = hNextItem;
+ }
+ } else
+ {
+ hItem = TreeView_GetParent(hTreeView, hItem);
+ }
+ } else
+ {
+ hItem = TreeView_GetPrevSibling(hTreeView, hItem);
+ }
+ Flags &= ~(MCLGN_NOTCHILD & ~MCLGN_MULTILEVEL); // clear MCLGN_NOTCHILD flag
+ } while (hItem && !(Flags & GetItemTypeAsCLGNFlag(hItem)));
+ return hItem;
+ } break;
+ default:
+ {
+ _ASSERT(0);
+ } break;
+ }
+ return NULL;
+}
+
+
+HANDLE CCList::GethContact(HTREEITEM hItem) // returns hContact, hGroup or hInfo
+{
+ HANDLE hContact = GetItemData(hItem).hContact;
+ if (IsHContactContact(hContact))
+ {
+ return hContact;
+ } else if (IsHContactGroup(hContact))
+ {
+ return (HANDLE)((int)hContact & ~HCONTACT_ISGROUP);
+ } else
+ {
+ return (HANDLE)((int)hContact & ~HCONTACT_ISINFO);
+ }
+}
+
+
+HTREEITEM CCList::HitTest(LPPOINT pt, PDWORD hitFlags) // pt is relative to control; returns hItem or NULL
+{
+ TVHITTESTINFO hti;
+ hti.pt = *pt;
+ TreeView_HitTest(hTreeView, &hti);
+ *hitFlags = 0;
+ if (hti.flags & TVHT_ABOVE)
+ {
+ *hitFlags |= MCLCHT_ABOVE;
+ }
+ if (hti.flags & TVHT_BELOW)
+ {
+ *hitFlags |= MCLCHT_BELOW;
+ }
+ if (hti.flags & TVHT_TOLEFT)
+ {
+ *hitFlags |= MCLCHT_TOLEFT;
+ }
+ if (hti.flags & TVHT_TORIGHT)
+ {
+ *hitFlags |= MCLCHT_TORIGHT;
+ }
+ if (hti.flags & TVHT_NOWHERE)
+ {
+ *hitFlags |= MCLCHT_NOWHERE;
+ }
+ if (hti.flags & TVHT_ONITEMINDENT)
+ {
+ *hitFlags |= MCLCHT_ONITEMINDENT;
+ }
+ if (hti.flags & (TVHT_ONITEMICON | TVHT_ONITEMSTATEICON))
+ {
+ *hitFlags |= MCLCHT_ONITEMICON;
+ }
+ if (hti.flags & TVHT_ONITEMLABEL)
+ {
+ *hitFlags |= MCLCHT_ONITEMLABEL;
+ }
+ if (hti.flags & TVHT_ONITEMRIGHT)
+ {
+ *hitFlags |= MCLCHT_ONITEMRIGHT;
+ }
+ if (hti.flags & (TVHT_ONITEMINDENT | TVHT_ONITEM | TVHT_ONITEMRIGHT))
+ {
+ // extraicon tests
+ RECT rc;
+ if (TreeView_GetItemRect(hTreeView, hti.hItem, &rc, false))
+ {
+ int nIndex = (rc.right - pt->x - 1) / EXTRAICON_XSTEP;
+ if (nIndex >= 0 && nIndex < MAXEXTRAICONS && GetItemData(hti.hItem).ExtraIcons[nIndex] != CLC_EXTRAICON_EMPTY)
+ {
+ *hitFlags |= MCLCHT_ONITEMEXTRA | (nIndex << 24);
+ }
+ }
+ }
+ return hti.hItem;
+}
+
+
+int CCList::Array_SetItemState(HTREEITEM hItem, bool bSelected)
+{
+ _ASSERT(hItem);
+ int nIndex = SelectedItems.Find(hItem);
+ if (nIndex == -1 && bSelected)
+ {
+ return SelectedItems.AddElem(hItem);
+ } else if (nIndex != -1 && !bSelected)
+ {
+ SelectedItems.RemoveElem(nIndex);
+ return -1;
+ }
+ return nIndex;
+}
+
+
+CCLItemData& CCList::GetItemData(HTREEITEM hItem)
+{
+ _ASSERT(hItem && hItem != INVALID_HANDLE_VALUE);
+ TVITEM tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = hItem;
+ int Res = TreeView_GetItem(hTreeView, &tvi);
+ _ASSERT(Res);
+ return Items[tvi.lParam];
+}
+
+
+HTREEITEM CCList::TreeView_GetLastChild(HWND hTreeView, HTREEITEM hItem)
+{
+ HTREEITEM hPrevItem = TreeView_GetChild(hTreeView, hItem);
+ hItem = hPrevItem;
+ while (hItem) // find last sibling
+ {
+ hPrevItem = hItem;
+ hItem = TreeView_GetNextSibling(hTreeView, hPrevItem);
+ }
+ return hPrevItem;
+}
+
+
+HTREEITEM CCList::FindContact(HANDLE hContact)
+{
+ TVITEM tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = TreeView_GetRoot(hTreeView);
+ while (tvi.hItem)
+ {
+ TreeView_GetItem(hTreeView, &tvi);
+ if (Items[tvi.lParam].hContact == hContact)
+ {
+ return tvi.hItem;
+ }
+ tvi.hItem = GetNextItem(MCLGN_NEXT | MCLGN_ANY | MCLGN_MULTILEVEL, tvi.hItem);
+ }
+ return NULL;
+}
+
+
+void CCList::SelectGroups(HTREEITEM hCurItem, bool bSelected)
+{
+// select/deselect all child items
+ HTREEITEM hItem = TreeView_GetChild(hTreeView, hCurItem);
+ HTREEITEM hLimitItem = GetNextItem(MCLGN_NEXT | MCLGN_ANY | MCLGN_NOTCHILD, hCurItem);
+ while (hItem && hItem != hLimitItem)
+ {
+ TreeView_SetItemState(hTreeView, hItem, bSelected ? TVIS_SELECTED : 0, TVIS_SELECTED);
+ Array_SetItemState(hItem, bSelected);
+ hItem = GetNextItem(MCLGN_NEXT | MCLGN_ANY | MCLGN_MULTILEVEL, hItem);
+ }
+// select/deselect all parent groups
+ hCurItem = TreeView_GetParent(hTreeView, hCurItem);
+ if (bSelected)
+ {
+ while (hCurItem) // select until we'll find an unselected item or until we'll reach the root
+ {
+ hItem = TreeView_GetChild(hTreeView, hCurItem);
+ while (hItem) // walk through all siblings
+ {
+ if (!(TreeView_GetItemState(hTreeView, hItem, TVIS_SELECTED) & TVIS_SELECTED))
+ {
+ break;
+ }
+ hItem = TreeView_GetNextSibling(hTreeView, hItem);
+ }
+ if (hItem) // means there was at least one unselected item
+ {
+ break;
+ }
+ TreeView_SetItemState(hTreeView, hCurItem, TVIS_SELECTED, TVIS_SELECTED);
+ Array_SetItemState(hCurItem, true);
+ hCurItem = TreeView_GetParent(hTreeView, hCurItem);
+ }
+ }
+ while (hCurItem) // and deselect all remaining parent groups
+ {
+ TreeView_SetItemState(hTreeView, hCurItem, 0, TVIS_SELECTED);
+ Array_SetItemState(hCurItem, false);
+ hCurItem = TreeView_GetParent(hTreeView, hCurItem);
+ }
+}
diff --git a/plugins/NewAwaySysMod/ContactList.h b/plugins/NewAwaySysMod/ContactList.h
new file mode 100644
index 0000000000..1730887954
--- /dev/null
+++ b/plugins/NewAwaySysMod/ContactList.h
@@ -0,0 +1,142 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (c) 2005-2007 Chervov Dmitry
+
+ 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
+*/
+
+// Miranda's built-in CListControl is very slow and it has too limited functionality... 8( So I had to use my own control instead.
+
+#pragma once
+
+typedef TMyArray<HTREEITEM> TREEITEMARRAY;
+typedef TREEITEMARRAY* PTREEITEMARRAY;
+
+
+#define CLC_EXTRAICON_EMPTY 0xFF
+#define CLC_ROOT TVI_ROOT
+
+#define MAXEXTRAICONS 16
+
+class CCLItemData // internal CCList's class
+{
+public:
+ CCLItemData(HANDLE hContact = INVALID_HANDLE_VALUE): hContact(hContact) {FillMemory(ExtraIcons, sizeof(ExtraIcons), CLC_EXTRAICON_EMPTY);};
+
+ BYTE ExtraIcons[MAXEXTRAICONS];
+ HANDLE hContact;
+ LPARAM lParam;
+};
+
+typedef TMyArray<CCLItemData> TREEITEMDATAARRAY;
+typedef TREEITEMDATAARRAY* PTREEITEMDATAARRAY;
+
+class CCList
+{
+public:
+ CCList(HWND hTreeView);
+ ~CCList();
+
+ HTREEITEM AddContact(HANDLE hContact);
+ HTREEITEM AddGroup(TCString GroupName);
+ HTREEITEM AddInfo(TCString Title, HTREEITEM hParent, HTREEITEM hInsertAfter, LPARAM lParam = NULL, HICON hIcon = NULL);
+ void SetInfoIcon(HTREEITEM hItem, HICON hIcon);
+ int GetExtraImage(HTREEITEM hItem, int iColumn); // returns iImage, or CLC_EXTRAICON_EMPTY
+ void SetExtraImage(HTREEITEM hItem, int iColumn, int iImage); // set iImage to CLC_EXTRAICON_EMPTY to reset image
+ void SetExtraImageList(HIMAGELIST hImgList);
+ int GetItemType(HTREEITEM hItem); // returns a MCLCIT_ (see below)
+ HTREEITEM GetNextItem(DWORD Flags, HTREEITEM hItem);
+ void SortContacts();
+ HANDLE GethContact(HTREEITEM hItem); // returns hContact, hGroup or hInfo
+ HTREEITEM HitTest(LPPOINT pt, PDWORD hitFlags); // pt is relative to control; returns hItem or NULL
+ void EnsureVisible(HTREEITEM hItem) {TreeView_EnsureVisible(hTreeView, hItem); InvalidateRect(hTreeView, NULL, false);} // sometimes horizontal scrollbar position changes too, so we must redraw extra icons - that's why here is InvalidateRect. TODO: try to find a way to invalidate it on _every_ horizontal scrollbar position change, instead of just here - unfortunately the scrollbar doesn't notify the tree control of its position change through WM_HSCROLL in some cases
+ int SelectItem(HTREEITEM hItem) {return TreeView_SelectItem(hTreeView, hItem);}
+ void SetItemParam(HTREEITEM hItem, LPARAM lParam) {GetItemData(hItem).lParam = lParam;}
+ LPARAM GetItemParam(HTREEITEM hItem) {return GetItemData(hItem).lParam;}
+ PTREEITEMARRAY GetSelection() {return &SelectedItems;}
+ void SetRedraw(bool bRedraw) {SendMessage(hTreeView, WM_SETREDRAW, bRedraw, 0);}
+
+ friend LRESULT CALLBACK ParentSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
+ friend LRESULT CALLBACK ContactListSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
+ friend int CALLBACK CompareItemsCallback(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
+
+private:
+ int Array_SetItemState(HTREEITEM hItem, bool bSelected);
+ CCLItemData& GetItemData(HTREEITEM hItem);
+ HTREEITEM TreeView_GetLastChild(HWND hTreeView, HTREEITEM hItem);
+ HTREEITEM FindContact(HANDLE hContact); // returns NULL if not found
+ void SelectGroups(HTREEITEM hCurItem, bool bSelected);
+ DWORD GetItemTypeAsCLGNFlag(HTREEITEM hItem); // returns MCLGN_CONTACT, MCLGN_GROUP or MCLGN_INFO
+
+ HWND hTreeView;
+ WNDPROC OrigTreeViewProc;
+ WNDPROC OrigParentProc;
+ TREEITEMDATAARRAY Items; // array that stores info for every tree item; array items are left even if corresponding tree item was deleted, so treeitem's lParam can be used as an index of an item in this array.
+ TREEITEMARRAY SelectedItems; // contains HTREEITEMs of all selected items
+ HIMAGELIST ExtraImageList;
+};
+
+
+// HitTest constants
+#define MCLCHT_ABOVE 0x0001 // above the client area
+#define MCLCHT_BELOW 0x0002 // below the client area
+#define MCLCHT_TOLEFT 0x0004 // to the left of the client area
+#define MCLCHT_TORIGHT 0x0008 // to the right of the client area
+#define MCLCHT_NOWHERE 0x0010 // in the client area, but below the last item
+#define MCLCHT_ONITEMINDENT 0x0020 // to the left of an item icon
+#define MCLCHT_ONITEMICON 0x0040
+#define MCLCHT_ONITEMLABEL 0x0080
+#define MCLCHT_ONITEMRIGHT 0x0100 // in the area to the right of an item
+#define MCLCHT_ONITEMEXTRA 0x0200 // on an extra icon, HIBYTE(HIWORD(hitFlags)) says which
+#define MCLCHT_ONITEM (MCLCHT_ONITEMICON | MCLCHT_ONITEMLABEL)
+
+// item types
+#define MCLCIT_GROUP 0
+#define MCLCIT_CONTACT 1
+#define MCLCIT_INFO 3
+
+// GetNextItem constants
+#define MCLGN_ROOT 0
+#define MCLGN_LAST 1
+#define MCLGN_CHILD 2
+#define MCLGN_LASTCHILD 3
+#define MCLGN_PARENT 4
+#define MCLGN_NEXT 5
+#define MCLGN_PREV 6
+// flags for use with MCLGN_NEXT and MCLGN_PREV:
+#define MCLGN_CONTACT 0x20 // you need to specify at least one of these three! otherwise GetNextItem will not find anything
+#define MCLGN_GROUP 0x40
+#define MCLGN_INFO 0x80
+#define MCLGN_ANY (MCLGN_CONTACT | MCLGN_GROUP | MCLGN_INFO)
+#define MCLGN_MULTILEVEL 0x100 // walk through items of different levels too (ex.: MCLGN_NEXT | MCLGN_MULTILEVEL)
+#define MCLGN_NOTCHILD (0x200 | MCLGN_MULTILEVEL) // when this flag is set, child items of specified hItem are ignored. for example, MCLGN_NEXT | MCLGN_CONTACT | MCLGN_NOTCHILD retrieves next contact that is not a child of hItem.
+// GetNextItem(MCLGN_PREV | MCLGN_ALL | MCLGN_NOTCHILD, CLM_GETNEXTITEM(MCLGN_NEXT | MCLGN_ALL | MCLGN_NOTCHILD, hItem) === hItem
+
+
+// notifications
+
+typedef struct
+{
+ NMHDR hdr;
+ PTREEITEMARRAY OldSelection, NewSelection;
+} NMCLIST;
+typedef NMCLIST* PNMCLIST;
+
+#define MCLN_FIRST (0U - 100U)
+
+#define MCLN_SELCHANGED (MCLN_FIRST - 20) // lParam = &NMCLIST; OldSelection and NewSelection contain selection info
+
+
+void LoadCListModule();
diff --git a/plugins/NewAwaySysMod/Images/Delete.ico b/plugins/NewAwaySysMod/Images/Delete.ico
new file mode 100644
index 0000000000..b44da83dbc
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/Delete.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/DisableNotify.ico b/plugins/NewAwaySysMod/Images/DisableNotify.ico
new file mode 100644
index 0000000000..5df846b34e
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/DisableNotify.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/Dot.ico b/plugins/NewAwaySysMod/Images/Dot.ico
new file mode 100644
index 0000000000..12ffcb1997
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/Dot.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/EnableNotify.ico b/plugins/NewAwaySysMod/Images/EnableNotify.ico
new file mode 100644
index 0000000000..da4e6af1c0
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/EnableNotify.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/Ignore.ico b/plugins/NewAwaySysMod/Images/Ignore.ico
new file mode 100644
index 0000000000..1ba34d7244
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/Ignore.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/Indefinite.ico b/plugins/NewAwaySysMod/Images/Indefinite.ico
new file mode 100644
index 0000000000..fb895622ff
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/Indefinite.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/MsgIcon.ico b/plugins/NewAwaySysMod/Images/MsgIcon.ico
new file mode 100644
index 0000000000..7880f71a70
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/MsgIcon.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/NewCat.ico b/plugins/NewAwaySysMod/Images/NewCat.ico
new file mode 100644
index 0000000000..c6d213b289
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/NewCat.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/NewMessage.ico b/plugins/NewAwaySysMod/Images/NewMessage.ico
new file mode 100644
index 0000000000..1ba04c8d6a
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/NewMessage.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/SaveAsNew.ico b/plugins/NewAwaySysMod/Images/SaveAsNew.ico
new file mode 100644
index 0000000000..6954faa978
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/SaveAsNew.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/SaveMsg.ico b/plugins/NewAwaySysMod/Images/SaveMsg.ico
new file mode 100644
index 0000000000..e972db2923
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/SaveMsg.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/Settings.ico b/plugins/NewAwaySysMod/Images/Settings.ico
new file mode 100644
index 0000000000..ddb72fb8ca
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/Settings.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/Status_Other.ico b/plugins/NewAwaySysMod/Images/Status_Other.ico
new file mode 100644
index 0000000000..922d911bbb
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/Status_Other.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/Variables.ico b/plugins/NewAwaySysMod/Images/Variables.ico
new file mode 100644
index 0000000000..7fd7196664
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/Variables.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/off.bmp b/plugins/NewAwaySysMod/Images/off.bmp
new file mode 100644
index 0000000000..fcc9507634
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/off.bmp
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/off.ico b/plugins/NewAwaySysMod/Images/off.ico
new file mode 100644
index 0000000000..0facbfa29f
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/off.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/on.bmp b/plugins/NewAwaySysMod/Images/on.bmp
new file mode 100644
index 0000000000..cf7343ef31
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/on.bmp
Binary files differ
diff --git a/plugins/NewAwaySysMod/Images/on.ico b/plugins/NewAwaySysMod/Images/on.ico
new file mode 100644
index 0000000000..f236715870
--- /dev/null
+++ b/plugins/NewAwaySysMod/Images/on.ico
Binary files differ
diff --git a/plugins/NewAwaySysMod/MsgEventAdded.cpp b/plugins/NewAwaySysMod/MsgEventAdded.cpp
new file mode 100644
index 0000000000..b9bbc80ad2
--- /dev/null
+++ b/plugins/NewAwaySysMod/MsgEventAdded.cpp
@@ -0,0 +1,322 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (C) 2005-2007 Chervov Dmitry
+ Copyright (C) 2004-2005 Iksaif Entertainment
+ Copyright (C) 2002-2003 Goblineye Entertainment
+
+ 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 "Common.h"
+#include "Properties.h"
+
+// stupid compiler.. kept returning me an "INTERNAL COMPILER ERROR" on almost every line of MsgEventAdded function with Release mode and unicode enabled >:( even disabling optimization through #pragma optimize didn't help.. The only acceptable solution I found is to move this function to a separate file and to disable optimization for the whole file in the project properties.
+
+static struct
+{
+ int Status, DisableReplyCtlID, DontShowDialogCtlID;
+} StatusModeList[] = {
+ ID_STATUS_ONLINE, IDC_REPLYDLG_DISABLE_ONL, IDC_MOREOPTDLG_DONTPOPDLG_ONL,
+ ID_STATUS_AWAY, IDC_REPLYDLG_DISABLE_AWAY, IDC_MOREOPTDLG_DONTPOPDLG_AWAY,
+ ID_STATUS_NA, IDC_REPLYDLG_DISABLE_NA, IDC_MOREOPTDLG_DONTPOPDLG_NA,
+ ID_STATUS_OCCUPIED, IDC_REPLYDLG_DISABLE_OCC, IDC_MOREOPTDLG_DONTPOPDLG_OCC,
+ ID_STATUS_DND, IDC_REPLYDLG_DISABLE_DND, IDC_MOREOPTDLG_DONTPOPDLG_DND,
+ ID_STATUS_FREECHAT, IDC_REPLYDLG_DISABLE_FFC, IDC_MOREOPTDLG_DONTPOPDLG_FFC,
+ ID_STATUS_INVISIBLE, IDC_REPLYDLG_DISABLE_INV, IDC_MOREOPTDLG_DONTPOPDLG_INV,
+ ID_STATUS_ONTHEPHONE, IDC_REPLYDLG_DISABLE_OTP, IDC_MOREOPTDLG_DONTPOPDLG_OTP,
+ ID_STATUS_OUTTOLUNCH, IDC_REPLYDLG_DISABLE_OTL, IDC_MOREOPTDLG_DONTPOPDLG_OTL
+};
+
+
+class CAutoreplyData
+{
+public:
+ CAutoreplyData(HANDLE hContact, TCString Reply): hContact(hContact), Reply(Reply) {}
+
+ HANDLE hContact;
+ TCString Reply;
+};
+
+
+void __cdecl AutoreplyDelayThread(void *_ad)
+{ // _ad must be allocated using "new CAutoreplyData()"
+ CAutoreplyData *ad = (CAutoreplyData*)_ad;
+ _ASSERT(ad && ad->hContact && ad->Reply.GetLen());
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)ad->hContact, 0);
+ if (!szProto)
+ {
+ _ASSERT(0);
+ return;
+ }
+#ifdef _UNICODE
+ int ReplyLen = (ad->Reply.GetLen() + 1) * (sizeof(char) + sizeof(WCHAR));
+ PBYTE pBuf = (PBYTE)malloc(ReplyLen);
+ memcpy(pBuf, TCHAR2ANSI(ad->Reply), ad->Reply.GetLen() + 1);
+ memcpy(pBuf + ad->Reply.GetLen() + 1, ad->Reply, (ad->Reply.GetLen() + 1) * sizeof(WCHAR));
+ CallContactService(ad->hContact, ServiceExists(CString(szProto) + PSS_MESSAGE "W") ? (PSS_MESSAGE "W") : PSS_MESSAGE, PREF_UNICODE, (LPARAM)pBuf);
+#else
+ CallContactService(ad->hContact, PSS_MESSAGE, 0, (LPARAM)(char*)ad->Reply);
+#endif
+ if (g_AutoreplyOptPage.GetDBValueCopy(IDC_REPLYDLG_LOGREPLY))
+ { // store in the history
+ DBEVENTINFO dbeo = {0};
+ dbeo.cbSize = sizeof(dbeo);
+ dbeo.eventType = EVENTTYPE_MESSAGE;
+ dbeo.flags = DBEF_SENT;
+ dbeo.szModule = szProto;
+ dbeo.timestamp = time(NULL);
+#ifdef _UNICODE
+ dbeo.cbBlob = ReplyLen;
+ dbeo.pBlob = pBuf;
+#else
+ dbeo.cbBlob = ad->Reply.GetLen() + 1;
+ dbeo.pBlob = (PBYTE)(char*)ad->Reply;
+#endif
+ SleepEx(1000, true); // delay before sending the reply, as we need it to be later than the message we're replying to (without this delay, srmm puts the messages in a wrong order)
+ CallService(MS_DB_EVENT_ADD, (WPARAM)ad->hContact, (LPARAM)&dbeo);
+ }
+#ifdef _UNICODE
+ free(pBuf);
+#endif
+/*
+ char *utf8Reply = mir_utf8encodeT(ad->Reply); // todo: use this instead of the code above, when 0.7 will be released
+ if (g_AutoreplyOptPage.GetDBValueCopy(IDC_REPLYDLG_LOGREPLY))
+ { // store in the history
+ DBEVENTINFO dbeo = {0};
+ dbeo.cbSize = sizeof(dbeo);
+ dbeo.eventType = EVENTTYPE_MESSAGE;
+ dbeo.flags = DBEF_SENT | DBEF_UTF;
+ dbeo.szModule = szProto;
+ dbeo.timestamp = time(NULL);
+ dbeo.cbBlob = strlen(utf8Reply);
+ dbeo.pBlob = utf8Reply;
+ CallService(MS_DB_EVENT_ADD, (WPARAM)ad->hContact, (LPARAM)&dbeo);
+ }
+ CallContactService(ad->hContact, ServiceExists(CString(szProto) + PSS_MESSAGE "W") ? (PSS_MESSAGE "W") : PSS_MESSAGE, PREF_UTF, (LPARAM)utf8Reply);
+ mir_free(utf8Reply);
+*/
+ delete ad;
+}
+
+
+int IsSRMsgWindowOpen(HANDLE hContact, int DefaultRetVal)
+{
+ if (ServiceExists(MS_MSG_GETWINDOWDATA))
+ {
+ MessageWindowData mwd = {0};
+ mwd.cbSize = sizeof(mwd);
+ MessageWindowInputData mwid = {0};
+ mwid.cbSize = sizeof(mwid);
+ mwid.uFlags = MSG_WINDOW_UFLAG_MSG_BOTH;
+ mwid.hContact = hContact;
+ return !CallService(MS_MSG_GETWINDOWDATA, (WPARAM)&mwid, (LPARAM)&mwd) && mwd.hwndWindow;
+ } else
+ {
+ return DefaultRetVal;
+ }
+}
+
+
+#define MAX_REPLY_TIMEDIFF 5 // maximum "age" of an event to remain unfiltered; in seconds
+#define MSGWNDOPEN_UNDEFINED (-1)
+
+class CMetacontactEvent
+{
+public:
+ CMetacontactEvent(HANDLE hMetaContact, DWORD timestamp, int bMsgWindowIsOpen): hMetaContact(hMetaContact), timestamp(timestamp), bMsgWindowIsOpen(bMsgWindowIsOpen) {};
+
+ HANDLE hMetaContact;
+ DWORD timestamp;
+ int bMsgWindowIsOpen;
+};
+
+TMyArray<CMetacontactEvent> MetacontactEvents;
+
+
+int MsgEventAdded(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact = (HANDLE)wParam;
+ DBEVENTINFO *dbei = (DBEVENTINFO*)lParam;
+ if (!hContact)
+ {
+ return 0;
+ }
+ if (dbei->flags & DBEF_SENT || (dbei->eventType != EVENTTYPE_MESSAGE && dbei->eventType != EVENTTYPE_URL && dbei->eventType != EVENTTYPE_FILE))
+ {
+ return 0;
+ }
+ if (time(NULL) - dbei->timestamp > MAX_REPLY_TIMEDIFF)
+ { // don't reply to offline messages
+ return 0;
+ }
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (!szProto)
+ {
+ return 0;
+ }
+ DWORD Flags1 = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+ if (!(Flags1 & PF1_IMSEND))
+ { // don't reply to protocols that don't support outgoing messages
+ return 0;
+ }
+ int bMsgWindowIsOpen = MSGWNDOPEN_UNDEFINED;
+ if (dbei->flags & DBEF_READ)
+ {
+ HANDLE hMetaContact;
+ if (ServiceExists(MS_MC_GETMETACONTACT) && (hMetaContact = (HANDLE)CallService(MS_MC_GETMETACONTACT, (WPARAM)hContact, 0))) // if it's a subcontact of a metacontact
+ { // ugly workaround for metacontacts, part II
+ // remove outdated events first
+ DWORD CurTime = time(NULL);
+ int I;
+ for (I = MetacontactEvents.GetSize() - 1; I >= 0; I--)
+ {
+ if (CurTime - MetacontactEvents[I].timestamp > MAX_REPLY_TIMEDIFF)
+ {
+ MetacontactEvents.RemoveElem(I);
+ }
+ }
+ // we compare only event timestamps, and do not look at the message itself. it's unlikely that there'll be two events from a contact at the same second, so it's a trade-off between speed and reliability
+ for (I = MetacontactEvents.GetSize() - 1; I >= 0; I--)
+ {
+ if (MetacontactEvents[I].timestamp == dbei->timestamp && MetacontactEvents[I].hMetaContact == hMetaContact)
+ {
+ bMsgWindowIsOpen = MetacontactEvents[I].bMsgWindowIsOpen;
+ break;
+ }
+ }
+ if (I < 0)
+ {
+ _ASSERT(0);
+ return 0;
+ }
+ } else
+ {
+ return 0;
+ }
+ }
+ if (ServiceExists(MS_MC_GETPROTOCOLNAME) && !lstrcmpA(szProto, (char*)CallService(MS_MC_GETPROTOCOLNAME, 0, 0)))
+ { // ugly workaround for metacontacts, part I; store all metacontacts' events to a temporary array, so we'll be able to get the 'source' protocol when subcontact event happens later. we need the protocol to get its status and per-status settings properly
+ // remove outdated events first
+ DWORD CurTime = time(NULL);
+ int I;
+ for (I = MetacontactEvents.GetSize() - 1; I >= 0; I--)
+ {
+ if (CurTime - MetacontactEvents[I].timestamp > MAX_REPLY_TIMEDIFF)
+ {
+ MetacontactEvents.RemoveElem(I);
+ }
+ }
+ // add the new event and wait for a subcontact's event
+ MetacontactEvents.AddElem(CMetacontactEvent(hContact, dbei->timestamp, IsSRMsgWindowOpen(hContact, false)));
+ return 0;
+ }
+ unsigned int iMode = CallProtoService(szProto, PS_GETSTATUS, 0, 0);
+ int I;
+ for (I = lengthof(StatusModeList) - 1; I >= 0; I--)
+ {
+ if (iMode == StatusModeList[I].Status)
+ {
+ break;
+ }
+ }
+ if (I < 0)
+ {
+ return 0;
+ }
+ COptPage AutoreplyOptData(g_AutoreplyOptPage);
+ AutoreplyOptData.DBToMem();
+ if (dbei->eventType == EVENTTYPE_MESSAGE)
+ {
+ DBWriteContactSettingWord(hContact, MOD_NAME, DB_MESSAGECOUNT, DBGetContactSettingWord(hContact, MOD_NAME, DB_MESSAGECOUNT, 0) + 1); // increment message counter
+ }
+ if (AutoreplyOptData.GetValue(StatusModeList[I].DisableReplyCtlID))
+ {
+ return 0;
+ }
+ HANDLE hContactForSettings = hContact; // used to take into account not-on-list contacts when getting contact settings, but at the same time allows to get correct contact info for contacts that are in the DB
+ if (hContactForSettings != INVALID_HANDLE_VALUE && DBGetContactSettingByte(hContactForSettings, "CList", "NotOnList", 0))
+ {
+ hContactForSettings = INVALID_HANDLE_VALUE; // INVALID_HANDLE_VALUE means the contact is not-on-list
+ }
+ if (!CContactSettings(iMode, hContactForSettings).Autoreply.IncludingParents(szProto) || CContactSettings(iMode, hContactForSettings).Ignore)
+ {
+ return 0;
+ }
+ if (AutoreplyOptData.GetValue(IDC_REPLYDLG_DONTREPLYINVISIBLE))
+ {
+ WORD ApparentMode = DBGetContactSettingWord(hContact, szProto, "ApparentMode", 0);
+ if ((iMode == ID_STATUS_INVISIBLE && (!(Flags1 & PF1_INVISLIST) || ApparentMode != ID_STATUS_ONLINE)) ||
+ (Flags1 & PF1_VISLIST && ApparentMode == ID_STATUS_OFFLINE))
+ {
+ return 0;
+ }
+ }
+ if (AutoreplyOptData.GetValue(IDC_REPLYDLG_ONLYCLOSEDDLGREPLY))
+ {
+ if (bMsgWindowIsOpen && bMsgWindowIsOpen != MSGWNDOPEN_UNDEFINED)
+ {
+ return 0;
+ }
+ // we never get here for a metacontact; we did check for metacontact's window earlier, and here we need to check only for subcontact's window
+ if (IsSRMsgWindowOpen(hContact, false))
+ {
+ return 0;
+ }
+ }
+ if (AutoreplyOptData.GetValue(IDC_REPLYDLG_ONLYIDLEREPLY) && !g_bIsIdle)
+ {
+ return 0;
+ }
+ int UIN = 0;
+ if (IsAnICQProto(szProto))
+ {
+ UIN = DBGetContactSettingDword(hContact, szProto, "UIN", 0);
+ }
+ int SendCount = AutoreplyOptData.GetValue(IDC_REPLYDLG_SENDCOUNT);
+ if ((AutoreplyOptData.GetValue(IDC_REPLYDLG_DONTSENDTOICQ) && UIN) || // an icq contact
+ (SendCount != -1 && DBGetContactSettingByte(hContact, MOD_NAME, DB_SENDCOUNT, 0) >= SendCount))
+ {
+ return 0;
+ }
+ if ((dbei->eventType == EVENTTYPE_MESSAGE && !AutoreplyOptData.GetValue(IDC_REPLYDLG_EVENTMSG)) || (dbei->eventType == EVENTTYPE_URL && !AutoreplyOptData.GetValue(IDC_REPLYDLG_EVENTURL)) || (dbei->eventType == EVENTTYPE_FILE && !AutoreplyOptData.GetValue(IDC_REPLYDLG_EVENTFILE)))
+ {
+ return 0;
+ }
+ DBWriteContactSettingByte(hContact, MOD_NAME, DB_SENDCOUNT, DBGetContactSettingByte(hContact, MOD_NAME, DB_SENDCOUNT, 0) + 1);
+ GetDynamicStatMsg(hContact); // it updates VarParseData.Message needed for %extratext% in the format
+ TCString Reply(*(TCString*)AutoreplyOptData.GetValue(IDC_REPLYDLG_PREFIX));
+ if (Reply != NULL && ServiceExists(MS_VARS_FORMATSTRING) && !g_SetAwayMsgPage.GetDBValueCopy(IDS_SAWAYMSG_DISABLEVARIABLES))
+ {
+ FORMATINFO fi = {0};
+ fi.cbSize = sizeof(FORMATINFO);
+ fi.tszFormat = Reply;
+ fi.hContact = hContact;
+ fi.flags = FIF_TCHAR;
+ fi.tszExtraText = VarParseData.Message;
+ TCHAR *szResult = (TCHAR *)CallService(MS_VARS_FORMATSTRING, (WPARAM)&fi, 0);
+ if (szResult != NULL)
+ {
+ Reply = szResult;
+ CallService(MS_VARS_FREEMEMORY, (WPARAM)szResult, 0);
+ }
+ }
+ if (Reply.GetLen())
+ {
+ CAutoreplyData *ad = new CAutoreplyData(hContact, Reply);
+ mir_forkthread(AutoreplyDelayThread, ad);
+ }
+ return 0;
+}
+
diff --git a/plugins/NewAwaySysMod/MsgTree.cpp b/plugins/NewAwaySysMod/MsgTree.cpp
new file mode 100644
index 0000000000..ba84ba6f61
--- /dev/null
+++ b/plugins/NewAwaySysMod/MsgTree.cpp
@@ -0,0 +1,790 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (c) 2005-2007 Chervov Dmitry
+
+ 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 "Common.h"
+#include "MsgTree.h"
+#include "Properties.h"
+
+#define UM_MSGTREE_INIT (WM_USER + 0x2103)
+#define UM_MSGTREE_UPDATE (WM_USER + 0x2104)
+
+#define MSGTREE_TIMER_ID 0x2103
+#define MSGTREE_DRAGANDDROP_GROUPEXPANDTIME 600
+
+#define IMGLIST_NEWMESSAGE 0
+#define IMGLIST_NEWCATEGORY 1
+#define IMGLIST_DELETE 2
+
+struct {
+ int DBSetting, Status, MenuItemID;
+} StatusModeList[] = {
+ IDS_MESSAGEDLG_DEF_ONL, ID_STATUS_ONLINE, IDR_MSGTREEMENU_DEF_ONL,
+ IDS_MESSAGEDLG_DEF_AWAY, ID_STATUS_AWAY, IDR_MSGTREEMENU_DEF_AWAY,
+ IDS_MESSAGEDLG_DEF_NA, ID_STATUS_NA, IDR_MSGTREEMENU_DEF_NA,
+ IDS_MESSAGEDLG_DEF_OCC, ID_STATUS_OCCUPIED, IDR_MSGTREEMENU_DEF_OCC,
+ IDS_MESSAGEDLG_DEF_DND, ID_STATUS_DND, IDR_MSGTREEMENU_DEF_DND,
+ IDS_MESSAGEDLG_DEF_FFC, ID_STATUS_FREECHAT, IDR_MSGTREEMENU_DEF_FFC,
+ IDS_MESSAGEDLG_DEF_INV, ID_STATUS_INVISIBLE, IDR_MSGTREEMENU_DEF_INV,
+ IDS_MESSAGEDLG_DEF_OTP, ID_STATUS_ONTHEPHONE, IDR_MSGTREEMENU_DEF_OTP,
+ IDS_MESSAGEDLG_DEF_OTL, ID_STATUS_OUTTOLUNCH, IDR_MSGTREEMENU_DEF_OTL
+};
+
+static HANDLE hMTWindowList;
+static WNDPROC g_OrigEditProc;
+
+
+void LoadMsgTreeModule()
+{
+ hMTWindowList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0);
+}
+
+
+static LRESULT CALLBACK EditSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (Msg)
+ {
+ case WM_GETDLGCODE:
+ {
+ return CallWindowProc(g_OrigEditProc, hWnd, Msg, wParam, lParam) | DLGC_WANTALLKEYS;
+ } break;
+ }
+ return CallWindowProc(g_OrigEditProc, hWnd, Msg, wParam, lParam);
+}
+
+static LRESULT CALLBACK ParentSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ CMsgTree *dat = CWndUserData(hWnd).GetMsgTree();
+ switch (Msg)
+ {
+ case WM_NOTIFY:
+ {
+ if (((LPNMHDR)lParam)->hwndFrom == dat->hTreeView)
+ {
+ switch (((LPNMHDR)lParam)->code)
+ {
+ case TVN_BEGINDRAGA:
+ case TVN_BEGINDRAGW:
+ {
+ LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam;
+ NMMSGTREE nm = {0};
+ COptItem_TreeCtrl *TreeCtrl = dat->GetTreeCtrl();
+ int Order = TreeCtrl->hItemToOrder(pnmtv->itemNew.hItem);
+ _ASSERT(Order != -1);
+ if (Order != -1)
+ {
+ nm.ItemOld = (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order];
+ nm.hdr.code = MTN_BEGINDRAG;
+ nm.hdr.hwndFrom = dat->hTreeView;
+ nm.hdr.idFrom = GetDlgCtrlID(dat->hTreeView);
+ if (!SendMessage(hWnd, WM_NOTIFY, 0, (LPARAM)&nm))
+ {
+ SetCapture(hWnd);
+ dat->hPrevDropTarget = dat->hDragItem = pnmtv->itemNew.hItem;
+ SetFocus(dat->hTreeView);
+ TreeView_SelectItem(dat->hTreeView, dat->hDragItem);
+ }
+ }
+ } break;
+ case TVN_SELCHANGEDA:
+ case TVN_SELCHANGEDW:
+ {
+ if (dat->UpdateLock)
+ {
+ return 0;
+ }
+ LPNMTREEVIEW pnmtv = (LPNMTREEVIEW)lParam;
+ NMMSGTREE nm = {0};
+ COptItem_TreeCtrl *TreeCtrl = dat->GetTreeCtrl();
+ if (pnmtv->itemOld.hItem)
+ {
+ int Order = TreeCtrl->IDToOrder(pnmtv->itemOld.lParam);
+ if (Order != -1)
+ {
+ nm.ItemOld = (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order];
+ }
+ }
+ if (pnmtv->itemNew.hItem)
+ {
+ int Order = TreeCtrl->IDToOrder(pnmtv->itemNew.lParam);
+ if (Order != -1)
+ {
+ nm.ItemNew = (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order];
+ }
+ }
+ nm.hdr.code = MTN_SELCHANGED;
+ nm.hdr.hwndFrom = dat->hTreeView;
+ nm.hdr.idFrom = GetDlgCtrlID(dat->hTreeView);
+ SendMessage(hWnd, WM_NOTIFY, 0, (LPARAM)&nm);
+ } break;
+ case TVN_BEGINLABELEDITA:
+ case TVN_BEGINLABELEDITW:
+ {
+ if (dat->GetTreeCtrl()->IDToOrder(((LPNMTVDISPINFO)lParam)->item.lParam) < 0)
+ {
+ return true; // cancel editing
+ }
+ g_OrigEditProc = (WNDPROC)SetWindowLongPtr(TreeView_GetEditControl(dat->hTreeView), GWLP_WNDPROC, (LONG_PTR)EditSubclassProc);
+ } break;
+// case TVN_ENDLABELEDITA: // stupid miranda options.. how am I supposed to get ptvdi->item.pszText if it's in ANSI??
+ case TVN_ENDLABELEDIT:
+ {
+ LPNMTVDISPINFO ptvdi = (LPNMTVDISPINFO)lParam;
+ if (ptvdi->item.pszText)
+ {
+ COptItem_TreeCtrl *TreeCtrl = dat->GetTreeCtrl();
+ int Order = TreeCtrl->IDToOrder(ptvdi->item.lParam);
+ if (Order >= 0)
+ {
+ TreeCtrl->Value[Order].Title = ptvdi->item.pszText;
+ TreeCtrl->SetModified(true);
+ NMMSGTREE nm = {0};
+ nm.ItemNew = &TreeCtrl->Value[Order];
+ nm.hdr.code = MTN_ITEMRENAMED;
+ nm.hdr.hwndFrom = dat->hTreeView;
+ nm.hdr.idFrom = GetDlgCtrlID(dat->hTreeView);
+ SendMessage(GetParent(dat->hTreeView), WM_NOTIFY, 0, (LPARAM)&nm);
+ return true; // commit new text
+ }
+ }
+ } break;
+ case NM_CLICK:
+ case NM_RCLICK:
+ {
+ TVHITTESTINFO hitTest;
+ hitTest.pt.x = (short)LOWORD(GetMessagePos());
+ hitTest.pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(dat->hTreeView, &hitTest.pt);
+ TreeView_HitTest(dat->hTreeView, &hitTest);
+ if (hitTest.hItem)
+ {
+ if (TreeView_GetSelection(dat->hTreeView) == hitTest.hItem)
+ { // make sure TVN_SELCHANGED notification is sent always, even if previous selected item was the same as new
+ TreeView_SelectItem(dat->hTreeView, NULL);
+ }
+ TreeView_SelectItem(dat->hTreeView, hitTest.hItem);
+ }
+ } break;
+ case NM_CUSTOMDRAW:
+ {
+ NMTVCUSTOMDRAW *lpNMCD = (NMTVCUSTOMDRAW*)lParam;
+ switch (lpNMCD->nmcd.dwDrawStage)
+ {
+ case CDDS_PREPAINT: // the control is about to start painting
+ {
+ return CDRF_NOTIFYITEMDRAW; // instruct the control to return information when it draws items
+ } break;
+ case CDDS_ITEMPREPAINT:
+ {
+ return CDRF_NOTIFYPOSTPAINT;
+ } break;
+ case CDDS_ITEMPOSTPAINT:
+ {
+ RECT rc;
+ TreeView_GetItemRect(lpNMCD->nmcd.hdr.hwndFrom, (HTREEITEM)lpNMCD->nmcd.dwItemSpec, &rc, true);
+ int iSize = GetSystemMetrics(SM_CXSMICON);
+ int I;
+ int x = rc.left - iSize - 5;
+ for (I = 0; I < lengthof(StatusModeList); I++)
+ {
+ if (lpNMCD->nmcd.lItemlParam == dat->MsgTreePage.GetValue(StatusModeList[I].DBSetting))
+ {
+ DrawIconEx(lpNMCD->nmcd.hdc, x, rc.top, LoadSkinnedProtoIcon(NULL, StatusModeList[I].Status), iSize, iSize, 0, GetSysColorBrush(COLOR_WINDOW), DI_NORMAL);
+ x -= iSize + 1;
+ }
+/* if (lpNMCD->nmcd.lItemlParam == GetRecentGroupID(StatusModeList[I].Status))
+ {
+ DrawIconEx(lpNMCD->nmcd.hdc, 3, rc.top, LoadSkinnedProtoIcon(NULL, StatusModeList[I].Status), iSize, iSize, 0, GetSysColorBrush(COLOR_WINDOW), DI_NORMAL);
+ }*/
+ }
+ } break;
+ }
+ } break;
+ }
+ }
+ } break;
+ case WM_MOUSEMOVE:
+ {
+ if (dat->hDragItem)
+ {
+ TVHITTESTINFO hti;
+ hti.pt.x = (short)LOWORD(lParam);
+ hti.pt.y = (short)HIWORD(lParam);
+ ClientToScreen(hWnd, &hti.pt);
+ ScreenToClient(dat->hTreeView, &hti.pt);
+ TreeView_HitTest(dat->hTreeView, &hti);
+ if (hti.hItem)
+ {
+ TreeView_SelectDropTarget(dat->hTreeView, hti.hItem);
+ SetTimer(hWnd, MSGTREE_TIMER_ID, MSGTREE_DRAGANDDROP_GROUPEXPANDTIME, NULL);
+ } else
+ {
+ if (hti.flags & TVHT_ABOVE)
+ {
+ SendMessage(dat->hTreeView, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), 0);
+ }
+ if (hti.flags & TVHT_BELOW)
+ {
+ SendMessage(dat->hTreeView, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), 0);
+ }
+ TreeView_SelectDropTarget(dat->hTreeView, NULL);
+ KillTimer(hWnd, MSGTREE_TIMER_ID);
+ }
+ }
+ } break;
+ case WM_LBUTTONUP:
+ {
+ if (dat->hDragItem)
+ {
+ TreeView_SelectDropTarget(dat->hTreeView, NULL);
+ KillTimer(hWnd, MSGTREE_TIMER_ID);
+ ReleaseCapture();
+ TVHITTESTINFO hti;
+ hti.pt.x = (short)LOWORD(lParam);
+ hti.pt.y = (short)HIWORD(lParam);
+ ClientToScreen(hWnd, &hti.pt);
+ ScreenToClient(dat->hTreeView, &hti.pt);
+ TreeView_HitTest(dat->hTreeView, &hti);
+ if (hti.hItem && dat->hDragItem != hti.hItem)
+ {
+ NMMSGTREE nm = {0};
+ COptItem_TreeCtrl *TreeCtrl = dat->GetTreeCtrl();
+ int OrderOld = TreeCtrl->hItemToOrder(dat->hDragItem);
+ int OrderNew = TreeCtrl->hItemToOrder(hti.hItem);
+ _ASSERT(OrderOld != -1 && OrderNew != -1);
+ nm.ItemOld = (OrderOld <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(OrderOld)] : (CBaseTreeItem*)&TreeCtrl->Value[OrderOld];
+ nm.ItemNew = (OrderNew <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(OrderNew)] : (CBaseTreeItem*)&TreeCtrl->Value[OrderNew];
+ nm.hdr.code = MTN_ENDDRAG;
+ nm.hdr.hwndFrom = dat->hTreeView;
+ nm.hdr.idFrom = GetDlgCtrlID(dat->hTreeView);
+ if (!SendMessage(hWnd, WM_NOTIFY, 0, (LPARAM)&nm))
+ {
+ dat->UpdateLock++;
+ dat->GetTreeCtrl()->MoveItem(hWnd, dat->hDragItem, hti.hItem);
+ dat->UpdateLock--;
+ }
+ }
+ dat->hDragItem = NULL;
+ }
+ } break;
+ case WM_TIMER:
+ {
+ if (wParam == MSGTREE_TIMER_ID)
+ {
+ KillTimer(hWnd, MSGTREE_TIMER_ID);
+ TVHITTESTINFO hti;
+ hti.pt.x = (short)LOWORD(GetMessagePos());
+ hti.pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(dat->hTreeView, &hti.pt);
+ TreeView_HitTest(dat->hTreeView, &hti);
+ if (hti.hItem && dat->hDragItem != hti.hItem && TreeView_GetChild(dat->hTreeView, hti.hItem)) // target is a group and is not the same item that we're dragging
+ {
+ TreeView_Expand(dat->hTreeView, hti.hItem, TVE_EXPAND);
+ }
+ }
+ } break;
+ }
+ return CallWindowProc(dat->OrigParentProc, hWnd, Msg, wParam, lParam);
+}
+
+
+static LRESULT CALLBACK MsgTreeSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ CMsgTree *dat = CWndUserData(GetParent(hWnd)).GetMsgTree();
+ switch (Msg)
+ {
+ case UM_MSGTREE_UPDATE: // returns TRUE if updated
+ {
+ bool Modified = dat->MsgTreePage.GetModified();
+ TCString WndTitle;
+ if (Modified)
+ {
+ WndTitle.GetBuffer(256);
+ HWND hCurWnd = hWnd;
+ do
+ {
+ hCurWnd = GetParent(hCurWnd);
+ } while (hCurWnd && !GetWindowText(hCurWnd, WndTitle, 256));
+ WndTitle.ReleaseBuffer();
+ }
+ if (!Modified || MessageBox(GetParent(hWnd), TCString(TranslateT("You've made changes to multiple Message trees at a time.\r\nDo you want to leave changes in \"")) + WndTitle + TranslateT("\" dialog?\r\nPress Yes to leave changes in this dialog, or No to discard its changes and save changes of the other Message tree instead."), WndTitle + _T(" - ") + TranslateT("New Away System"), MB_ICONQUESTION | MB_YESNO) == IDNO)
+ {
+ COptItem_TreeCtrl *TreeCtrl = dat->GetTreeCtrl();
+ TCString OldTitle, OldMsg, NewTitle, NewMsg;
+ int OldOrder = TreeCtrl->IDToOrder(TreeCtrl->GetSelectedItemID(GetParent(hWnd)));
+ if (OldOrder != -1)
+ {
+ CBaseTreeItem* ItemOld = (OldOrder <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(OldOrder)] : (CBaseTreeItem*)&TreeCtrl->Value[OldOrder];
+ OldTitle = ItemOld->Title;
+ if (!(ItemOld->Flags & TIF_ROOTITEM))
+ {
+ OldMsg = ((CTreeItem*)ItemOld)->User_Str1;
+ }
+ }
+ dat->UpdateLock++;
+ dat->MsgTreePage.DBToMemToPage();
+ dat->UpdateLock--;
+ NMMSGTREE nm = {0};
+ int Order = TreeCtrl->IDToOrder(TreeCtrl->GetSelectedItemID(GetParent(hWnd)));
+ if (Order != -1)
+ {
+ nm.ItemNew = (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order];
+ NewTitle = nm.ItemNew->Title;
+ if (!(nm.ItemNew->Flags & TIF_ROOTITEM))
+ {
+ NewMsg = ((CTreeItem*)nm.ItemNew)->User_Str1;
+ }
+ }
+ if (OldTitle.IsEmpty())
+ {
+ OldTitle = _T(""); // to be sure that NULL will be equal to "" in the latter comparisons
+ }
+ if (OldMsg.IsEmpty())
+ {
+ OldMsg = _T("");
+ }
+ if (NewTitle.IsEmpty())
+ {
+ NewTitle = _T("");
+ }
+ if (NewMsg.IsEmpty())
+ {
+ NewMsg = _T("");
+ }
+ if (OldTitle != (const TCHAR*)NewTitle || OldMsg != (const TCHAR*)NewMsg)
+ {
+ // probably it's better to leave nm.ItemOld = NULL, to prevent accidental rewriting of it with old data from an edit control etc.
+ nm.hdr.code = MTN_SELCHANGED;
+ nm.hdr.hwndFrom = hWnd;
+ nm.hdr.idFrom = GetDlgCtrlID(hWnd);
+ SendMessage(GetParent(hWnd), WM_NOTIFY, 0, (LPARAM)&nm);
+ }
+ return true;
+ }
+ return false;
+ } break;
+ case WM_KEYDOWN:
+ {
+ switch (wParam)
+ {
+ case VK_DELETE:
+ {
+ dat->DeleteSelectedItem();
+ } break;
+ case VK_INSERT:
+ {
+ dat->AddMessage();
+ } break;
+ }
+ } break;
+ case WM_RBUTTONDOWN:
+ {
+ SetFocus(hWnd);
+ TVHITTESTINFO hitTest;
+ hitTest.pt.x = (short)LOWORD(lParam);
+ hitTest.pt.y = (short)HIWORD(lParam);
+ TreeView_HitTest(hWnd, &hitTest);
+ if (hitTest.hItem && hitTest.flags & TVHT_ONITEM)
+ {
+ TreeView_SelectItem(hWnd, hitTest.hItem);
+ }
+ return DefWindowProc(hWnd, Msg, wParam, lParam);
+ } break;
+ case WM_CONTEXTMENU:
+ {
+ TVHITTESTINFO ht;
+ ht.pt.x = (short)LOWORD(lParam);
+ ht.pt.y = (short)HIWORD(lParam);
+ TVITEM tvi = {0};
+ if (ht.pt.x == -1 && ht.pt.y == -1) // use selected item
+ {
+ if (tvi.hItem = TreeView_GetSelection(hWnd))
+ {
+ TreeView_EnsureVisible(hWnd, tvi.hItem);
+ RECT rc;
+ TreeView_GetItemRect(hWnd, tvi.hItem, &rc, true);
+ ht.pt.x = rc.left;
+ ht.pt.y = rc.bottom;
+ }
+ } else
+ {
+ ScreenToClient(hWnd, &ht.pt);
+ TreeView_HitTest(hWnd, &ht);
+ if (ht.hItem && ht.flags & TVHT_ONITEM)
+ {
+ tvi.hItem = ht.hItem;
+ }
+ }
+ if (tvi.hItem)
+ {
+ COptItem_TreeCtrl *TreeCtrl = dat->GetTreeCtrl();
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ TreeView_GetItem(hWnd, &tvi);
+ int Order = TreeCtrl->IDToOrder(tvi.lParam);
+ if (Order >= 0)
+ {
+ HMENU hMenu;
+ if (TreeCtrl->Value[Order].Flags & TIF_GROUP)
+ {
+ hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_MSGTREE_CATEGORYMENU));
+ } else
+ {
+ hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_MSGTREE_MESSAGEMENU));
+ }
+ _ASSERT(hMenu);
+ HMENU hPopupMenu = GetSubMenu(hMenu, 0);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM)hPopupMenu, 0);
+ ClientToScreen(hWnd, &ht.pt);
+ struct
+ {
+ int ItemID, IconID;
+ } MenuItems[] = {
+ IDM_MSGTREEMENU_NEWMESSAGE, IMGLIST_NEWMESSAGE,
+ IDM_MSGTREEMENU_NEWCATEGORY, IMGLIST_NEWCATEGORY,
+ IDM_MSGTREEMENU_DELETE, IMGLIST_DELETE
+ };
+ MENUITEMINFO mii = {0};
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_BITMAP | MIIM_DATA | MIIM_STATE | MIIM_CHECKMARKS;
+ mii.hbmpItem = HBMMENU_CALLBACK;
+ int I;
+ for (I = 0; I < lengthof(MenuItems); I++) // set icons
+ {
+ mii.dwItemData = MenuItems[I].IconID;
+ SetMenuItemInfo(hPopupMenu, MenuItems[I].ItemID, false, &mii);
+ }
+ mii.fMask = MIIM_STATE;
+ mii.fState = MFS_CHECKED;
+ for (I = 0; I < lengthof(StatusModeList); I++) // set checkmarks
+ {
+ if (TreeCtrl->Value[Order].ID == dat->MsgTreePage.GetValue(StatusModeList[I].DBSetting))
+ {
+ SetMenuItemInfo(hPopupMenu, StatusModeList[I].MenuItemID, false, &mii);
+ }
+ }
+ int MenuResult = TrackPopupMenu(hPopupMenu, TPM_RIGHTBUTTON | TPM_RETURNCMD, ht.pt.x, ht.pt.y, 0, hWnd, NULL);
+ switch (MenuResult)
+ {
+ case IDM_MSGTREEMENU_NEWMESSAGE:
+ {
+ dat->AddMessage();
+ } break;
+ case IDM_MSGTREEMENU_NEWCATEGORY:
+ {
+ dat->AddCategory();
+ } break;
+ case IDM_MSGTREEMENU_RENAME:
+ {
+ TreeView_EditLabel(hWnd, tvi.hItem);
+ } break;
+ case IDM_MSGTREEMENU_DELETE:
+ {
+ dat->DeleteSelectedItem();
+ } break;
+ case IDR_MSGTREEMENU_DEF_ONL:
+ case IDR_MSGTREEMENU_DEF_AWAY:
+ case IDR_MSGTREEMENU_DEF_NA:
+ case IDR_MSGTREEMENU_DEF_OCC:
+ case IDR_MSGTREEMENU_DEF_DND:
+ case IDR_MSGTREEMENU_DEF_FFC:
+ case IDR_MSGTREEMENU_DEF_INV:
+ case IDR_MSGTREEMENU_DEF_OTP:
+ case IDR_MSGTREEMENU_DEF_OTL:
+ {
+ int I;
+ for (I = 0; I < lengthof(StatusModeList); I++)
+ {
+ if (StatusModeList[I].MenuItemID == MenuResult)
+ {
+ dat->SetDefMsg(StatusModeList[I].Status, tvi.lParam);
+ break;
+ }
+ }
+ } break;
+ }
+ DestroyMenu(hMenu);
+ return 0;
+ }
+ }
+ } break;
+ case WM_MEASUREITEM:
+ {
+ LPMEASUREITEMSTRUCT lpmi = (LPMEASUREITEMSTRUCT)lParam;
+ if (lpmi->CtlType == ODT_MENU)
+ {
+ lpmi->itemWidth = max(0, GetSystemMetrics(SM_CXSMICON) - GetSystemMetrics(SM_CXMENUCHECK) + 4);
+ lpmi->itemHeight = GetSystemMetrics(SM_CYSMICON) + 2;
+ return true;
+ }
+ } break;
+ case WM_DRAWITEM:
+ {
+ LPDRAWITEMSTRUCT dis = (LPDRAWITEMSTRUCT)lParam;
+ if (dis->CtlType == ODT_MENU)
+ {
+ ImageList_DrawEx(dat->hImageList, dis->itemData, dis->hDC, 2, (dis->rcItem.bottom + dis->rcItem.top - GetSystemMetrics(SM_CYSMICON)) / 2 + 1, 0, 0, GetSysColor(COLOR_WINDOW), CLR_NONE, ILD_NORMAL);
+ return true;
+ }
+ } break;
+ }
+ return CallWindowProc(dat->OrigTreeViewProc, hWnd, Msg, wParam, lParam);
+}
+
+
+CMsgTree::CMsgTree(HWND hTreeView): MsgTreePage(g_MsgTreePage), hTreeView(hTreeView), hDragItem(NULL), hPrevDropTarget(NULL), UpdateLock(0)
+{
+ CWndUserData(GetParent(hTreeView)).SetMsgTree(this);
+ OrigParentProc = (WNDPROC)SetWindowLongPtr(GetParent(hTreeView), GWLP_WNDPROC, (LONG_PTR)ParentSubclassProc);
+ OrigTreeViewProc = (WNDPROC)SetWindowLongPtr(hTreeView, GWLP_WNDPROC, (LONG_PTR)MsgTreeSubclassProc);
+ MsgTreePage.SetWnd(GetParent(hTreeView));
+ COptItem_TreeCtrl* TreeCtrl = (COptItem_TreeCtrl*)MsgTreePage.Find(IDV_MSGTREE);
+ TreeCtrl->SetDlgItemID(GetDlgCtrlID(hTreeView));
+ hImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), (IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16) | ILC_MASK, 5, 2);
+ ImageList_AddIcon(hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_NEWMESSAGE)));
+ ImageList_AddIcon(hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_NEWCATEGORY)));
+ ImageList_AddIcon(hImageList, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_DELETE)));
+ MsgTreePage.DBToMemToPage();
+ if (!g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_RECENTMSGSCOUNT))
+ { // show "Recent messages" group only when RECENTMSGSCOUNT is not set to 0.
+ TreeView_DeleteItem(hTreeView, TreeCtrl->RootItems[g_Messages_RecentRootID].hItem);
+ }
+ WindowList_Add(hMTWindowList, hTreeView, NULL);
+}
+
+CMsgTree::~CMsgTree()
+{
+ _ASSERT(GetWindowLongPtr(GetParent(hTreeView), GWLP_WNDPROC) == (LONG_PTR)ParentSubclassProc); // we won't allow anyone to change our WNDPROC. otherwise we're not sure that we're setting the right WNDPROC back
+ SetWindowLongPtr(hTreeView, GWLP_WNDPROC, (GetWindowLongPtr(GetParent(hTreeView), GWLP_WNDPROC) == (LONG_PTR)ParentSubclassProc) ? (LONG_PTR)OrigTreeViewProc : (LONG_PTR)DefDlgProc); // yeah, if that crazy Help plugin substituted MY WndProc again, he won't get his WndProc back.. he-he >:)
+ SetWindowLongPtr(GetParent(hTreeView), GWLP_WNDPROC, (LONG_PTR)OrigParentProc);
+ CWndUserData(GetParent(hTreeView)).SetMsgTree(NULL);
+ WindowList_Remove(hMTWindowList, hTreeView);
+ ImageList_Destroy(hImageList);
+}
+
+CBaseTreeItem* CMsgTree::GetSelection() // returns NULL if there's nothing selected
+{
+ COptItem_TreeCtrl *TreeCtrl = GetTreeCtrl();
+ int Order = TreeCtrl->IDToOrder(TreeCtrl->GetSelectedItemID(GetParent(hTreeView)));
+ if (Order != -1)
+ {
+ return (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order];
+ }
+ return NULL;
+}
+
+bool CMsgTree::SetSelection(int ID, int Flags) // set ID = -1 to unselect; returns TRUE on unselect and on successful select
+{
+ COptItem_TreeCtrl *TreeCtrl = GetTreeCtrl();
+ int Order = (Flags & MTSS_BYORDER) ? ID : TreeCtrl->IDToOrder(ID);
+ if (Order == -1 && ID != -1)
+ {
+ return false;
+ }
+ TreeView_SelectItem(hTreeView, (Order == -1) ? NULL : ((Order <= TREECTRL_ROOTORDEROFFS) ? TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)].hItem : TreeCtrl->Value[Order].hItem));
+ return true;
+}
+
+int CMsgTree::GetDefMsg(int iMode)
+{
+ int I;
+ for (I = 0; I < lengthof(StatusModeList); I++)
+ {
+ if (StatusModeList[I].Status == iMode)
+ {
+ return MsgTreePage.GetValue(StatusModeList[I].DBSetting);
+ }
+ }
+ return 0;
+}
+
+void CMsgTree::SetDefMsg(int iMode, int ID)
+{
+ int I;
+ for (I = 0; I < lengthof(StatusModeList); I++)
+ {
+ if (StatusModeList[I].Status == iMode)
+ {
+ if (MsgTreePage.GetValue(StatusModeList[I].DBSetting) != ID)
+ {
+ RECT rc;
+ COptItem_TreeCtrl *TreeCtrl = GetTreeCtrl();
+ int OrderOld = TreeCtrl->IDToOrder(MsgTreePage.GetValue(StatusModeList[I].DBSetting));
+ if (OrderOld >= 0 && TreeView_GetItemRect(hTreeView, TreeCtrl->Value[OrderOld].hItem, &rc, false))
+ {
+ InvalidateRect(hTreeView, &rc, true); // refresh icons of previous default tree item
+ }
+ int OrderNew = TreeCtrl->IDToOrder(ID);
+ if (OrderNew >= 0 && TreeView_GetItemRect(hTreeView, TreeCtrl->Value[OrderNew].hItem, &rc, false))
+ {
+ InvalidateRect(hTreeView, &rc, true); // refresh new default item icons
+ }
+ MsgTreePage.SetValue(StatusModeList[I].DBSetting, ID);
+ NMMSGTREE nm = {0};
+ if (OrderOld >= 0)
+ {
+ nm.ItemOld = &TreeCtrl->Value[OrderOld];
+ }
+ if (OrderNew >= 0)
+ {
+ nm.ItemNew = &TreeCtrl->Value[OrderNew];
+ }
+ nm.hdr.code = MTN_DEFMSGCHANGED;
+ nm.hdr.hwndFrom = hTreeView;
+ nm.hdr.idFrom = GetDlgCtrlID(hTreeView);
+ SendMessage(GetParent(hTreeView), WM_NOTIFY, 0, (LPARAM)&nm);
+ }
+ break;
+ }
+ }
+}
+
+void CMsgTree::Save()
+{
+ if (MsgTreePage.GetModified())
+ {
+ MsgTreePage.PageToMemToDB();
+ WindowList_BroadcastAsync(hMTWindowList, UM_MSGTREE_UPDATE, 0, 0);
+ }
+}
+
+void CMsgTree::UpdateItem(int ID) // updates item title, and expanded/collapsed state for groups
+{
+ COptItem_TreeCtrl *TreeCtrl = GetTreeCtrl();
+ int Order = TreeCtrl->IDToOrder(ID);
+ if (Order != -1)
+ {
+ CBaseTreeItem* TreeItem = (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order];
+ TCString NewTitle;
+ TVITEM tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_TEXT;
+ tvi.hItem = TreeItem->hItem;
+ tvi.pszText = NewTitle.GetBuffer(TREEITEMTITLE_MAXLEN);
+ tvi.cchTextMax = TREEITEMTITLE_MAXLEN;
+ TreeView_GetItem(hTreeView, &tvi);
+ if (TreeItem->Title != (const TCHAR*)tvi.pszText)
+ {
+ TreeCtrl->SetModified(true);
+ NMMSGTREE nm = {0};
+ nm.ItemNew = TreeItem;
+ nm.hdr.code = MTN_ITEMRENAMED;
+ nm.hdr.hwndFrom = hTreeView;
+ nm.hdr.idFrom = GetDlgCtrlID(hTreeView);
+ SendMessage(GetParent(hTreeView), WM_NOTIFY, 0, (LPARAM)&nm);
+ }
+ tvi.mask = TVIF_HANDLE | TVIF_TEXT;
+ tvi.pszText = TreeItem->Title;
+ TreeView_SetItem(hTreeView, &tvi);
+ TreeView_Expand(hTreeView, tvi.hItem, (TreeItem->Flags & TIF_EXPANDED) ? TVE_EXPAND : TVE_COLLAPSE);
+ }
+}
+
+bool CMsgTree::DeleteSelectedItem() // returns true if the item was deleted
+{
+ COptItem_TreeCtrl *TreeCtrl = GetTreeCtrl();
+ int Order = TreeCtrl->IDToOrder(TreeCtrl->GetSelectedItemID(GetParent(hTreeView)));
+ _ASSERT(Order >= 0);
+ CTreeItem *SelectedItem = &TreeCtrl->Value[Order];
+ //NightFox: fix for langpack and fix cut char space in text
+ //if (MessageBox(GetParent(hTreeView), TCString(TranslateT("Do you really want to delete this ")) + ((SelectedItem->Flags & TIF_GROUP) ? TranslateT("category with its messages?") : TranslateT("message?")), TranslateT("New Away System"), MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) == IDYES)
+ if (MessageBox(GetParent(hTreeView),
+ ((SelectedItem->Flags & TIF_GROUP) ?
+ TranslateT("Do you really want to delete this category with its messages?")
+ :
+ TranslateT("Do you really want to delete this message?"))
+ ,
+ TranslateT("New Away System"), MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) == IDYES)
+ {
+ NMMSGTREE nm = {0};
+ nm.ItemOld = SelectedItem;
+ nm.hdr.code = MTN_DELETEITEM;
+ nm.hdr.hwndFrom = hTreeView;
+ nm.hdr.idFrom = GetDlgCtrlID(hTreeView);
+ if (!SendMessage(GetParent(hTreeView), WM_NOTIFY, 0, (LPARAM)&nm))
+ {
+ TreeCtrl->Delete(GetParent(hTreeView), TreeCtrl->GetSelectedItemID(GetParent(hTreeView)));
+ return true;
+ }
+ }
+ return false;
+}
+
+CTreeItem* CMsgTree::AddCategory()
+{
+ COptItem_TreeCtrl *TreeCtrl = GetTreeCtrl();
+ CTreeItem* TreeItem = TreeCtrl->InsertItem(GetParent(hTreeView), CTreeItem(_T(""), 0, 0, TIF_GROUP));
+ TVITEM tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_TEXT;
+ tvi.hItem = TreeItem->hItem;
+ TreeItem->Title = tvi.pszText = TranslateT("New category");
+ TreeView_SetItem(hTreeView, &tvi);
+ TreeView_EditLabel(hTreeView, TreeItem->hItem);
+ NMMSGTREE nm = {0};
+ nm.ItemNew = TreeItem;
+ nm.hdr.code = MTN_NEWCATEGORY;
+ nm.hdr.hwndFrom = hTreeView;
+ nm.hdr.idFrom = GetDlgCtrlID(hTreeView);
+ SendMessage(GetParent(hTreeView), WM_NOTIFY, 0, (LPARAM)&nm);
+ return TreeItem;
+}
+
+CTreeItem* CMsgTree::AddMessage()
+{
+ COptItem_TreeCtrl *TreeCtrl = GetTreeCtrl();
+ CTreeItem* TreeItem = TreeCtrl->InsertItem(GetParent(hTreeView), CTreeItem(_T(""), 0, 0));
+ TVITEM tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_TEXT;
+ tvi.hItem = TreeItem->hItem;
+ TreeItem->Title = tvi.pszText = TranslateT("New message");
+ TreeView_SetItem(hTreeView, &tvi);
+ TreeView_EditLabel(hTreeView, TreeItem->hItem);
+ NMMSGTREE nm = {0};
+ nm.ItemNew = TreeItem;
+ nm.hdr.code = MTN_NEWMESSAGE;
+ nm.hdr.hwndFrom = hTreeView;
+ nm.hdr.idFrom = GetDlgCtrlID(hTreeView);
+ SendMessage(GetParent(hTreeView), WM_NOTIFY, 0, (LPARAM)&nm);
+ return TreeItem;
+}
+
+CBaseTreeItem* CMsgTree::GetNextItem(int Flags, CBaseTreeItem* Item) // Item is 'int ID' if MTGN_BYID flag is set; returns CBaseTreeItem* or NULL
+{
+ COptItem_TreeCtrl *TreeCtrl = GetTreeCtrl();
+ CBaseTreeItem* TreeItem = Item;
+ if (Flags & MTGN_BYID)
+ {
+ int Order = TreeCtrl->IDToOrder((int)Item);
+ _ASSERT(Order != -1);
+ TreeItem = (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order];
+ }
+ int TVFlag = 0;
+ switch (Flags & ~MTGN_BYID)
+ {
+ case MTGN_ROOT: TVFlag = TVGN_ROOT; break;
+ case MTGN_CHILD: TVFlag = TVGN_CHILD; break;
+ case MTGN_PARENT: TVFlag = TVGN_PARENT; break;
+ case MTGN_NEXT: TVFlag = TVGN_NEXT; break;
+ case MTGN_PREV: TVFlag = TVGN_PREVIOUS; break;
+ default: _ASSERT(0);
+ }
+ int Order = TreeCtrl->hItemToOrder(TreeView_GetNextItem(hTreeView, TreeItem ? TreeItem->hItem : NULL, TVFlag));
+ if (Order != -1)
+ {
+ return (Order <= TREECTRL_ROOTORDEROFFS) ? (CBaseTreeItem*)&TreeCtrl->RootItems[ROOT_ORDER_TO_INDEX(Order)] : (CBaseTreeItem*)&TreeCtrl->Value[Order];
+ }
+ return NULL;
+}
diff --git a/plugins/NewAwaySysMod/MsgTree.h b/plugins/NewAwaySysMod/MsgTree.h
new file mode 100644
index 0000000000..98b2f9d6cc
--- /dev/null
+++ b/plugins/NewAwaySysMod/MsgTree.h
@@ -0,0 +1,95 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (c) 2005-2007 Chervov Dmitry
+
+ 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
+
+extern COptPage g_MsgTreePage;
+
+class CMsgTree
+{
+public:
+ CMsgTree(HWND hTreeView); // warning: it changes GWLP_USERDATA of the parent window
+ ~CMsgTree();
+
+ CBaseTreeItem* GetSelection(); // returns NULL if there's nothing selected
+ bool SetSelection(int ID, int Flags); // set ID = -1 to unselect; ID specifies an order of an item if Flags = MTSS_BYORDER
+ int GetDefMsg(int iMode);
+ void SetDefMsg(int iMode, int ID);
+ void Save();
+ void UpdateItem(int ID); // updates item title, and expanded/collapsed state for groups; set SetModified to TRUE to change Modified flag of the tree
+ bool DeleteSelectedItem(); // returns true if the item was deleted
+ CTreeItem* AddCategory();
+ CTreeItem* AddMessage();
+ CBaseTreeItem* GetNextItem(int Flags, CBaseTreeItem* Item); // Item is 'int ID' if MTGN_BYID flag is set; returns CBaseTreeItem* or NULL
+ void EnsureVisible(HTREEITEM hItem) {TreeView_EnsureVisible(hTreeView, hItem);}
+ bool GetModified() {return MsgTreePage.GetModified();}
+ void SetModified(bool Modified) {MsgTreePage.SetModified(Modified);}
+
+ friend LRESULT CALLBACK ParentSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
+ friend LRESULT CALLBACK MsgTreeSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
+
+private:
+ COptItem_TreeCtrl* GetTreeCtrl() {return (COptItem_TreeCtrl*)MsgTreePage.Find(GetDlgCtrlID(hTreeView));}
+
+ HWND hTreeView;
+ WNDPROC OrigTreeViewProc;
+ WNDPROC OrigParentProc;
+ COptPage MsgTreePage;
+ HTREEITEM hDragItem;
+ HTREEITEM hPrevDropTarget;
+ int UpdateLock;
+ HIMAGELIST hImageList;
+};
+
+// SetSelection constants
+#define MTSS_BYID 0
+#define MTSS_BYORDER 1
+
+// GetNextItem constants
+#define MTGN_ROOT 0
+#define MTGN_CHILD 1
+#define MTGN_PARENT 2
+#define MTGN_NEXT 3
+#define MTGN_PREV 4
+#define MTGN_BYID 0x8000 // means that lParam is ID of an item, not a pointer to its data
+
+
+// notifications
+
+typedef struct
+{
+ NMHDR hdr;
+ CBaseTreeItem* ItemOld;
+ CBaseTreeItem* ItemNew;
+} NMMSGTREE;
+typedef NMMSGTREE* PNMMSGTREE;
+
+#define MTN_FIRST (0U - 100U)
+
+#define MTN_SELCHANGED (MTN_FIRST - 0) // lParam = &NMMSGTREE; ItemOld and ItemNew contain old and new item info
+#define MTN_BEGINDRAG (MTN_FIRST - 1) // lParam = &NMMSGTREE; ItemOld points to the item info; return TRUE to cancel dragging
+#define MTN_ENDDRAG (MTN_FIRST - 2) // lParam = &NMMSGTREE; ItemOld points to the item info; ItemNew points to the item on which ItemOld was dropped; return TRUE to cancel moving
+#define MTN_NEWCATEGORY (MTN_FIRST - 3) // lParam = &NMMSGTREE; ItemNew points to new category info
+#define MTN_NEWMESSAGE (MTN_FIRST - 4) // lParam = &NMMSGTREE; ItemNew points to new message info
+#define MTN_ITEMRENAMED (MTN_FIRST - 5) // lParam = &NMMSGTREE; ItemNew points to renamed item info
+#define MTN_DELETEITEM (MTN_FIRST - 6) // lParam = &NMMSGTREE; ItemOld points to the item info; return TRUE to prevent item from being deleted
+#define MTN_DEFMSGCHANGED (MTN_FIRST - 7) // lParam = &NMMSGTREE; ItemOld and ItemNew point to old and new default item info correspondingly
+
+
+void LoadMsgTreeModule();
diff --git a/plugins/NewAwaySysMod/NewAwaySys.rc b/plugins/NewAwaySysMod/NewAwaySys.rc
new file mode 100644
index 0000000000..7a0bfba8ee
--- /dev/null
+++ b/plugins/NewAwaySysMod/NewAwaySys.rc
@@ -0,0 +1,701 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Russian resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_RUS)
+#ifdef _WIN32
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+#pragma code_page(1251)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Russian resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE MOVEABLE PURE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE MOVEABLE PURE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_POPUPOPTDLG DIALOG DISCARDABLE 0, 0, 312, 237
+STYLE DS_SETFOREGROUND | DS_FIXEDSYS | DS_CONTROL | DS_CENTER | WS_CHILD
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "",IDC_POPUPOPTDLG_GROUP_NOTIFICATION,6,6,300,208
+ CONTROL "Popup notification",IDC_POPUPOPTDLG_USEPOPUPS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,12,5,108,10
+ GROUPBOX "Popup text format",IDC_STATIC,12,18,288,76
+ EDITTEXT IDC_POPUPOPTDLG_POPUPFORMAT,18,30,222,48,ES_MULTILINE |
+ ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN |
+ WS_VSCROLL | WS_HSCROLL
+ PUSHBUTTON "Preview",IDC_POPUPOPTDLG_POPUPPREVIEW,246,30,48,14
+ CONTROL "V",IDC_POPUPOPTDLG_VARS,"MButtonClass",WS_TABSTOP,246,
+ 50,16,14,0x18000000L
+ LTEXT "%extratext% is your status message",
+ IDC_POPUPOPTDLG_STATIC_EXTRATEXT,18,81,276,8
+ GROUPBOX "Click action",IDC_STATIC,12,100,199,54
+ RTEXT "On left click",IDC_POPUPOPTDLG_STATIC_LCLICK,17,115,55,
+ 8
+ COMBOBOX IDC_POPUPOPTDLG_LCLICK_ACTION,78,112,125,86,
+ CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ RTEXT "On right click",IDC_POPUPOPTDLG_STATIC_RCLICK,17,133,55,
+ 8
+ COMBOBOX IDC_POPUPOPTDLG_RCLICK_ACTION,78,130,125,86,
+ CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ GROUPBOX "Delay",IDC_STATIC,217,100,83,54
+ EDITTEXT IDC_POPUPOPTDLG_POPUPDELAY,240,112,32,12,ES_AUTOHSCROLL
+ CONTROL "",IDC_POPUPOPTDLG_POPUPDELAY_SPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS,260,112,12,12
+ LTEXT "Sec",IDC_POPUPOPTDLG_STATIC_SEC,275,114,21,8
+ CTEXT "0 = Default",IDC_POPUPOPTDLG_STATIC_DEFAULT,224,128,70,
+ 8
+ CTEXT "-1 = Infinite",IDC_POPUPOPTDLG_STATIC_INFINITE,224,140,
+ 70,8
+ GROUPBOX "Colours",IDC_STATIC,12,160,155,48
+ CONTROL "",IDC_POPUPOPTDLG_BGCOLOUR,"ColourPicker",WS_TABSTOP,19,
+ 172,19,12
+ LTEXT "Background",IDC_POPUPOPTDLG_STATIC_BGCOLOUR,43,175,39,8
+ CONTROL "Use default",IDC_POPUPOPTDLG_DEFBGCOLOUR,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,90,175,73,10
+ CONTROL "",IDC_POPUPOPTDLG_TEXTCOLOUR,"ColourPicker",WS_TABSTOP,
+ 19,190,19,12
+ LTEXT "Text",IDC_POPUPOPTDLG_STATIC_TEXTCOLOUR,43,193,15,8
+ CONTROL "Use default",IDC_POPUPOPTDLG_DEFTEXTCOLOUR,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,90,193,73,10
+ GROUPBOX "Only notify when:",IDC_STATIC,174,160,125,32
+ CONTROL "On&line",IDC_POPUPOPTDLG_ONLNOTIFY,"MButtonClass",
+ WS_TABSTOP,180,172,16,14,0x18000000L
+ CONTROL "&Away",IDC_POPUPOPTDLG_AWAYNOTIFY,"MButtonClass",
+ WS_TABSTOP,196,172,16,14,0x18000000L
+ CONTROL "&NA",IDC_POPUPOPTDLG_NANOTIFY,"MButtonClass",WS_TABSTOP,
+ 212,172,16,14,0x18000000L
+ CONTROL "Occ&upied",IDC_POPUPOPTDLG_OCCNOTIFY,"MButtonClass",
+ WS_TABSTOP,228,172,16,14,0x18000000L
+ CONTROL "&DND",IDC_POPUPOPTDLG_DNDNOTIFY,"MButtonClass",
+ WS_TABSTOP,244,172,16,14,0x18000000L
+ CONTROL "&Free for chat",IDC_POPUPOPTDLG_FFCNOTIFY,"MButtonClass",
+ WS_TABSTOP,260,172,16,14,0x18000000L
+ CONTROL "&Other",IDC_POPUPOPTDLG_OTHERNOTIFY,"MButtonClass",
+ WS_TABSTOP,276,172,16,14,0x18000000L
+ CONTROL "Log to a file only when popup notification for a contact is enabled",
+ IDC_POPUPOPTDLG_LOGONLYWITHPOPUP,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,6,219,300,10
+END
+
+IDD_AUTOREPLY DIALOG DISCARDABLE 0, 0, 312, 231
+STYLE DS_SETFOREGROUND | DS_FIXEDSYS | DS_CONTROL | DS_CENTER | WS_CHILD
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "",IDC_MOREOPTDLG_PANEL,6,6,300,220
+ CONTROL "Enable autoreply",IDC_REPLYDLG_ENABLEREPLY,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,12,5,139,10
+ RTEXT "On event...",IDC_REPLYDLG_STATIC_ONEVENT,43,19,59,8
+ CONTROL "",IDC_REPLYDLG_EVENTMSG,"Button",BS_AUTOCHECKBOX |
+ BS_ICON | WS_TABSTOP,110,17,29,12
+ CONTROL "",IDC_REPLYDLG_EVENTURL,"Button",BS_AUTOCHECKBOX |
+ BS_ICON | WS_TABSTOP,145,17,29,12
+ CONTROL "",IDC_REPLYDLG_EVENTFILE,"Button",BS_AUTOCHECKBOX |
+ BS_ICON | WS_TABSTOP,180,17,29,12
+ CONTROL "Don't reply to ICQ contacts",IDC_REPLYDLG_DONTSENDTOICQ,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,119,275,10
+ CONTROL "Don't reply when I'm invisible to the contact",
+ IDC_REPLYDLG_DONTREPLYINVISIBLE,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,21,107,275,10
+ CONTROL "Save autoreply to the history",IDC_REPLYDLG_LOGREPLY,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,34,275,10
+ CONTROL "Reply only when Idle",IDC_REPLYDLG_ONLYIDLEREPLY,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,21,48,275,10
+ CONTROL "Reply only when contact's message window is closed",
+ IDC_REPLYDLG_ONLYCLOSEDDLGREPLY,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,21,59,275,10
+ LTEXT "Send maximum",IDC_REPLYDLG_STATIC_SEND,33,72,90,8
+ EDITTEXT IDC_REPLYDLG_SENDCOUNT,127,70,40,12,ES_AUTOHSCROLL
+ CONTROL "",IDC_REPLYDLG_SENDCOUNT_SPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS,156,70,12,12
+ LTEXT "times (-1=infinite)",IDC_REPLYDLG_STATIC_TIMES,172,72,
+ 124,8
+ CONTROL "Reset this counter also when I just change my status text\n(when status icon remains the same)",
+ IDC_REPLYDLG_RESETCOUNTERWHENSAMEICON,"Button",
+ BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,34,
+ 84,262,18
+ LTEXT "Disable autoreply when...",
+ IDC_REPLYDLG_STATIC_DISABLEWHENSTATUS,13,134,283,8
+ CONTROL "On&line",IDC_REPLYDLG_DISABLE_ONL,"MButtonClass",
+ WS_TABSTOP,21,146,16,14,0x18000000L
+ CONTROL "&Away",IDC_REPLYDLG_DISABLE_AWAY,"MButtonClass",
+ WS_TABSTOP,37,146,16,14,0x18000000L
+ CONTROL "&NA",IDC_REPLYDLG_DISABLE_NA,"MButtonClass",WS_TABSTOP,
+ 53,146,16,14,0x18000000L
+ CONTROL "Occ&upied",IDC_REPLYDLG_DISABLE_OCC,"MButtonClass",
+ WS_TABSTOP,69,146,16,14,0x18000000L
+ CONTROL "&DND",IDC_REPLYDLG_DISABLE_DND,"MButtonClass",
+ WS_TABSTOP,85,146,16,14,0x18000000L
+ CONTROL "&Free for chat",IDC_REPLYDLG_DISABLE_FFC,"MButtonClass",
+ WS_TABSTOP,101,146,16,14,0x18000000L
+ CONTROL "&Invisible",IDC_REPLYDLG_DISABLE_INV,"MButtonClass",
+ WS_TABSTOP,117,146,16,14,0x18000000L
+ CONTROL "On the &Phone",IDC_REPLYDLG_DISABLE_OTP,"MButtonClass",
+ WS_TABSTOP,133,146,16,14,0x18000000L
+ CONTROL "Out to &Lunch",IDC_REPLYDLG_DISABLE_OTL,"MButtonClass",
+ WS_TABSTOP,149,146,16,14,0x18000000L
+ LTEXT "Autoreply format:",IDC_REPLYDLG_STATIC_FORMAT,13,168,
+ 283,8
+ EDITTEXT IDC_REPLYDLG_PREFIX,21,180,209,30,ES_MULTILINE |
+ ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ CONTROL "V",IDC_REPLYDLG_VARS,"MButtonClass",WS_TABSTOP,231,180,
+ 16,14,0x18000000L
+ LTEXT "%extratext% is your status message",
+ IDC_REPLYDLG_STATIC_EXTRATEXT,21,212,234,8
+END
+
+IDD_SETAWAYMSG DIALOGEX 0, 0, 398, 132
+STYLE DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE |
+ WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_SAWAYMSG_MSGDATA,116,1,170,114,ES_MULTILINE |
+ ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ PUSHBUTTON "OK",IDC_OK,115,117,60,14
+ CONTROL "&Variables",IDC_SAWAYMSG_VARS,"MButtonClass",WS_TABSTOP,
+ 255,117,16,14,0x18000000L
+ CONTROL "Se&ttings",IDC_SAWAYMSG_OPTIONS,"MButtonClass",
+ WS_TABSTOP,271,117,16,14,0x18000000L
+ ICON IDI_IGNORE,IDC_SAWAYMSG_STATIC_IGNOREICON,382,109,16,16,
+ SS_CENTERIMAGE | SS_REALSIZEIMAGE
+ ICON IDI_SOE_ENABLED,IDC_SAWAYMSG_STATIC_REPLYICON,382,118,16,
+ 16,SS_CENTERIMAGE | SS_REALSIZEIMAGE
+ CONTROL "",IDC_SAWAYMSG_CONTACTSTREE,"SysTreeView32",
+ TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS |
+ TVS_TRACKSELECT | WS_BORDER | WS_TABSTOP,289,1,108,114
+ CONTROL "Ignore requests",IDC_SAWAYMSG_IGNOREREQ,"Button",
+ BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,307,116,80,8,
+ WS_EX_RIGHT
+ CONTROL "Send an autoreply",IDC_SAWAYMSG_SENDMSG,"Button",
+ BS_AUTO3STATE | BS_LEFTTEXT | WS_TABSTOP,307,124,80,8,
+ WS_EX_RIGHT
+ CONTROL "",IDC_SAWAYMSG_TREE,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | TVS_EDITLABELS |
+ TVS_SHOWSELALWAYS | TVS_TRACKSELECT | WS_BORDER |
+ WS_TABSTOP,1,1,112,114
+ CONTROL "&Delete",IDC_SAWAYMSG_DELETE,"MButtonClass",WS_TABSTOP,
+ 58,116,16,14,0x18000000L
+ CONTROL "New &Category",IDC_SAWAYMSG_NEWCATEGORY,"MButtonClass",
+ WS_TABSTOP,2,116,16,14,0x18000000L
+ CONTROL "Save As &New",IDC_SAWAYMSG_SAVEASNEW,"MButtonClass",
+ WS_TABSTOP,18,116,16,14,0x18000000L
+ CONTROL "&Save",IDC_SAWAYMSG_SAVEMSG,"MButtonClass",WS_TABSTOP,
+ 34,116,16,14,0x18000000L
+ CONTROL "",IDC_SAWAYMSG_MSGSPLITTER,"Static",SS_ENHMETAFILE |
+ SS_SUNKEN,114,0,1,115
+ CONTROL "",IDC_SAWAYMSG_CONTACTSPLITTER,"Static",SS_ENHMETAFILE |
+ SS_SUNKEN,287,0,1,115
+END
+
+IDD_MESSAGES DIALOG DISCARDABLE 0, 0, 311, 221
+STYLE DS_SETFOREGROUND | DS_FIXEDSYS | DS_CONTROL | DS_CENTER | WS_CHILD
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "",IDC_MESSAGEDLG_MSGTREE,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | TVS_EDITLABELS |
+ TVS_SHOWSELALWAYS | TVS_TRACKSELECT | WS_BORDER |
+ WS_TABSTOP,6,6,126,210
+ RTEXT "Title:",IDC_STATIC,136,8,51,8
+ EDITTEXT IDC_MESSAGEDLG_MSGTITLE,189,6,115,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_MESSAGEDLG_MSGDATA,138,24,166,138,ES_MULTILINE |
+ ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ GROUPBOX "Use this message as default for",IDC_STATIC,138,186,166,
+ 30,BS_LEFT
+ CONTROL "On&line",IDC_MESSAGEDLG_DEF_ONL,"MButtonClass",
+ WS_TABSTOP,149,197,16,14,0x18000000L
+ CONTROL "&Away",IDC_MESSAGEDLG_DEF_AWAY,"MButtonClass",
+ WS_TABSTOP,165,197,16,14,0x18000000L
+ CONTROL "&NA",IDC_MESSAGEDLG_DEF_NA,"MButtonClass",WS_TABSTOP,
+ 181,197,16,14,0x18000000L
+ CONTROL "Occ&upied",IDC_MESSAGEDLG_DEF_OCC,"MButtonClass",
+ WS_TABSTOP,197,197,16,14,0x18000000L
+ CONTROL "&DND",IDC_MESSAGEDLG_DEF_DND,"MButtonClass",WS_TABSTOP,
+ 213,197,16,14,0x18000000L
+ CONTROL "&Free for chat",IDC_MESSAGEDLG_DEF_FFC,"MButtonClass",
+ WS_TABSTOP,229,197,16,14,0x18000000L
+ CONTROL "&Invisible",IDC_MESSAGEDLG_DEF_INV,"MButtonClass",
+ WS_TABSTOP,245,197,16,14,0x18000000L
+ CONTROL "On the &Phone",IDC_MESSAGEDLG_DEF_OTP,"MButtonClass",
+ WS_TABSTOP,261,197,16,14,0x18000000L
+ CONTROL "Out to &Lunch",IDC_MESSAGEDLG_DEF_OTL,"MButtonClass",
+ WS_TABSTOP,277,197,16,14,0x18000000L
+ CONTROL "New message",IDC_MESSAGEDLG_NEWMSG,"MButtonClass",
+ WS_TABSTOP,138,166,16,14,0x18000000L
+ CONTROL "New category",IDC_MESSAGEDLG_NEWCAT,"MButtonClass",
+ WS_TABSTOP,154,166,16,14,0x18000000L
+ CONTROL "Delete",IDC_MESSAGEDLG_DEL,"MButtonClass",WS_TABSTOP,
+ 170,166,16,14,0x18000000L
+ CONTROL "V",IDC_MESSAGEDLG_VARS,"MButtonClass",WS_TABSTOP,288,
+ 166,16,14,0x18000000L
+END
+
+IDD_MODERNOPT_MESSAGES DIALOG DISCARDABLE 0, 0, 373, 154
+STYLE DS_SETFOREGROUND | DS_FIXEDSYS | DS_CONTROL | DS_CENTER | WS_CHILD
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "",IDC_MESSAGEDLG_MSGTREE,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | TVS_EDITLABELS |
+ TVS_SHOWSELALWAYS | TVS_TRACKSELECT | WS_BORDER |
+ WS_TABSTOP,6,13,126,128
+ LTEXT "Title:",IDC_TXT_TITLE2,138,14,51,8
+ EDITTEXT IDC_MESSAGEDLG_MSGTITLE,194,13,172,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_MESSAGEDLG_MSGDATA,138,30,228,57,ES_MULTILINE |
+ ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ GROUPBOX "Use this message as default for",IDC_TXT_TITLE3,138,111,
+ 228,30,BS_LEFT
+ CONTROL "On&line",IDC_MESSAGEDLG_DEF_ONL,"MButtonClass",
+ WS_TABSTOP,144,122,16,14,0x18000000L
+ CONTROL "&Away",IDC_MESSAGEDLG_DEF_AWAY,"MButtonClass",
+ WS_TABSTOP,160,122,16,14,0x18000000L
+ CONTROL "&NA",IDC_MESSAGEDLG_DEF_NA,"MButtonClass",WS_TABSTOP,
+ 176,122,16,14,0x18000000L
+ CONTROL "Occ&upied",IDC_MESSAGEDLG_DEF_OCC,"MButtonClass",
+ WS_TABSTOP,192,122,16,14,0x18000000L
+ CONTROL "&DND",IDC_MESSAGEDLG_DEF_DND,"MButtonClass",WS_TABSTOP,
+ 208,122,16,14,0x18000000L
+ CONTROL "&Free for chat",IDC_MESSAGEDLG_DEF_FFC,"MButtonClass",
+ WS_TABSTOP,224,122,16,14,0x18000000L
+ CONTROL "&Invisible",IDC_MESSAGEDLG_DEF_INV,"MButtonClass",
+ WS_TABSTOP,240,122,16,14,0x18000000L
+ CONTROL "On the &Phone",IDC_MESSAGEDLG_DEF_OTP,"MButtonClass",
+ WS_TABSTOP,256,122,16,14,0x18000000L
+ CONTROL "Out to &Lunch",IDC_MESSAGEDLG_DEF_OTL,"MButtonClass",
+ WS_TABSTOP,272,122,16,14,0x18000000L
+ CONTROL "New message",IDC_MESSAGEDLG_NEWMSG,"MButtonClass",
+ WS_TABSTOP,138,95,16,14,0x18000000L
+ CONTROL "New category",IDC_MESSAGEDLG_NEWCAT,"MButtonClass",
+ WS_TABSTOP,154,95,16,14,0x18000000L
+ CONTROL "Delete",IDC_MESSAGEDLG_DEL,"MButtonClass",WS_TABSTOP,
+ 170,95,16,14,0x18000000L
+ CONTROL "V",IDC_MESSAGEDLG_VARS,"MButtonClass",WS_TABSTOP,350,95,
+ 16,14,0x18000000L
+ LTEXT "Statuses messages:",IDC_TXT_TITLE1,0,2,99,9
+ CONTROL "Configure autoaway",IDC_LNK_AUTOAWAY,"Hyperlink",
+ WS_TABSTOP,6,142,126,11
+END
+
+IDD_MOREOPTDIALOG DIALOG DISCARDABLE 0, 0, 311, 235
+STYLE DS_SETFOREGROUND | DS_FIXEDSYS | DS_CONTROL | DS_CENTER | WS_CHILD
+FONT 8, "MS Shell Dlg"
+BEGIN
+ RTEXT "Wait",IDC_STATIC_MOREOPTDLG_WAIT,2,10,36,8
+ EDITTEXT IDC_MOREOPTDLG_WAITFORMSG,41,8,28,12,ES_AUTOHSCROLL
+ CONTROL "",IDC_MOREOPTDLG_WAITFORMSG_SPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS,57,8,12,12
+ LTEXT "seconds before closing the status message dialog (-1=don't close)",
+ IDC_STATIC_MOREOPTDLG_SECONDSREMAIN,74,10,235,8
+ RTEXT "Store",IDC_STATIC,2,28,36,8
+ EDITTEXT IDC_MOREOPTDLG_RECENTMSGSCOUNT,41,26,28,12,
+ ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_MOREOPTDLG_RECENTMSGSCOUNT_SPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS,57,26,12,12
+ LTEXT "most recent messages (0=disable)",IDC_STATIC,74,28,119,
+ 8
+ CONTROL "Store for each status separately",
+ IDC_MOREOPTDLG_PERSTATUSMRM,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,41,42,267,10
+ GROUPBOX "Use default...",IDC_STATIC,6,58,294,30
+ CONTROL "Use the most recent message",IDC_MOREOPTDLG_USELASTMSG,
+ "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,12,70,138,10
+ CONTROL "Use the default message",IDC_MOREOPTDLG_USEDEFMSG,
+ "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,156,70,138,10
+ CONTROL "Reset per-protocol messages when changing global status",
+ IDC_MOREOPTDLG_RESETPROTOMSGS,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,7,95,300,10
+ CONTROL "Store protocol messages for each status separately",
+ IDC_MOREOPTDLG_PERSTATUSPROTOMSGS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,15,107,294,10
+ CONTROL "Store protocol autoreply settings for each status separately",
+ IDC_MOREOPTDLG_PERSTATUSPROTOSETTINGS,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,15,119,294,10
+ CONTROL "Remember last message used for a contact...",
+ IDC_MOREOPTDLG_SAVEPERSONALMSGS,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,6,133,297,10
+ CONTROL "Store for each status separately",
+ IDC_MOREOPTDLG_PERSTATUSPERSONAL,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,15,146,288,10
+ CONTROL "Store contact autoreply/ignore settings for each status separately",
+ IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS,"Button",
+ BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | WS_TABSTOP,15,
+ 157,294,16
+ CONTROL "Enable contact menu items",IDC_MOREOPTDLG_USEMENUITEM,
+ "Button",BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE |
+ WS_TABSTOP,167,203,142,17
+ CONTROL "Use protocol specific nick for %nas_mynick%",
+ IDC_MOREOPTDLG_MYNICKPERPROTO,"Button",BS_AUTOCHECKBOX |
+ BS_MULTILINE | WS_TABSTOP,6,175,294,8
+ CONTROL "Update status messages for non-ICQ protocols every",
+ IDC_MOREOPTDLG_UPDATEMSGS,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,6,187,199,10
+ EDITTEXT IDC_MOREOPTDLG_UPDATEMSGSPERIOD,207,186,38,12,
+ ES_AUTOHSCROLL | ES_NUMBER
+ CONTROL "",IDC_MOREOPTDLG_UPDATEMSGSPERIOD_SPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS | UDS_NOTHOUSANDS,230,186,12,12
+ LTEXT "seconds",IDC_STATIC,249,187,60,8
+ GROUPBOX "Don't show the message dialog for",IDC_STATIC,6,200,156,
+ 31
+ CONTROL "On&line",IDC_MOREOPTDLG_DONTPOPDLG_ONL,"MButtonClass",
+ WS_TABSTOP,12,212,16,14,0x18000000L
+ CONTROL "&Away",IDC_MOREOPTDLG_DONTPOPDLG_AWAY,"MButtonClass",
+ WS_TABSTOP,28,212,16,14,0x18000000L
+ CONTROL "&NA",IDC_MOREOPTDLG_DONTPOPDLG_NA,"MButtonClass",
+ WS_TABSTOP,44,212,16,14,0x18000000L
+ CONTROL "Occ&upied",IDC_MOREOPTDLG_DONTPOPDLG_OCC,"MButtonClass",
+ WS_TABSTOP,60,212,16,14,0x18000000L
+ CONTROL "&DND",IDC_MOREOPTDLG_DONTPOPDLG_DND,"MButtonClass",
+ WS_TABSTOP,76,212,16,14,0x18000000L
+ CONTROL "&Free for chat",IDC_MOREOPTDLG_DONTPOPDLG_FFC,
+ "MButtonClass",WS_TABSTOP,92,212,16,14,0x18000000L
+ CONTROL "&Invisible",IDC_MOREOPTDLG_DONTPOPDLG_INV,"MButtonClass",
+ WS_TABSTOP,108,212,16,14,0x18000000L
+ CONTROL "On the &Phone",IDC_MOREOPTDLG_DONTPOPDLG_OTP,
+ "MButtonClass",WS_TABSTOP,124,212,16,14,0x18000000L
+ CONTROL "Out to &Lunch",IDC_MOREOPTDLG_DONTPOPDLG_OTL,
+ "MButtonClass",WS_TABSTOP,140,212,16,14,0x18000000L
+END
+
+IDD_READAWAYMSG DIALOGEX 0, 0, 186, 72
+STYLE DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
+ WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+CAPTION "%s Message for %s"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_READAWAYMSG_MSG,5,5,177,43,ES_MULTILINE |
+ ES_AUTOVSCROLL | ES_READONLY | NOT WS_VISIBLE |
+ WS_VSCROLL
+ CTEXT "Retrieving %s message...",IDC_READAWAYMSG_RETRIEVE,5,21,
+ 177,8,SS_NOPREFIX
+ DEFPUSHBUTTON "&Cancel",IDOK,69,53,50,14,BS_NOTIFY
+END
+
+IDD_CONTACTSOPTDLG DIALOGEX 0, 0, 311, 221
+STYLE DS_FIXEDSYS | DS_CONTROL | DS_CENTER | WS_CHILD
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_CONTACTSDLG_LIST,"CListControl",WS_TABSTOP |
+ 0x1f0,6,30,299,160,WS_EX_CLIENTEDGE
+ ICON 141,IDC_STATIC,197,0,20,20,SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | NOT WS_VISIBLE
+ LTEXT "Notify of requests",IDC_STATIC,217,5,87,8,SS_NOPREFIX |
+ SS_CENTERIMAGE | NOT WS_VISIBLE
+ ICON 140,IDC_STATIC,197,12,20,20,SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | NOT WS_VISIBLE
+ LTEXT "Don't notify of requests",IDC_STATIC,217,18,87,8,
+ SS_NOPREFIX | SS_CENTERIMAGE | NOT WS_VISIBLE
+ ICON IDI_SOE_ENABLED,IDC_STATIC,3,190,20,20,SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE
+ LTEXT "Autoreply on",IDC_STATIC,24,196,106,8,SS_NOPREFIX |
+ SS_CENTERIMAGE
+ ICON IDI_SOE_DISABLED,IDC_STATIC,3,204,20,20,SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE
+ LTEXT "Autoreply off",IDC_STATIC,24,210,107,8,SS_NOPREFIX |
+ SS_CENTERIMAGE
+ ICON IDI_IGNORE,IDC_STATIC,132,190,20,20,SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE
+ LTEXT "Don't send status message",IDC_STATIC,151,196,153,8,
+ SS_NOPREFIX | SS_CENTERIMAGE
+ LTEXT "Note: these settings are applied to all status modes at once.",
+ IDC_STATIC,6,1,300,9
+ ICON IDI_INDEFINITE,IDC_STATIC,6,13,16,16,SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE
+ LTEXT "Means the setting is different for different status modes / contacts",
+ IDC_STATIC,22,17,281,8,SS_NOPREFIX | SS_CENTERIMAGE
+END
+
+IDD_SETAWAYMSG_BAK DIALOGEX 0, 0, 398, 133
+STYLE DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE |
+ WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ EDITTEXT IDC_SAWAYMSG_MSGDATA,115,1,172,114,ES_MULTILINE |
+ ES_AUTOVSCROLL | ES_WANTRETURN | WS_VSCROLL
+ PUSHBUTTON "OK",IDC_OK,115,117,60,14
+ CONTROL "&Variables",IDC_SAWAYMSG_VARS,"MButtonClass",WS_TABSTOP,
+ 255,117,16,14,0x18000000L
+ CONTROL "Se&ttings",IDC_SAWAYMSG_OPTIONS,"MButtonClass",
+ WS_TABSTOP,271,117,16,14,0x18000000L
+ ICON IDI_IGNORE,IDC_SAWAYMSG_STATIC_IGNOREICON,379,108,18,16,
+ SS_CENTERIMAGE | SS_REALSIZEIMAGE
+ ICON IDI_SOE_ENABLED,IDC_SAWAYMSG_STATIC_REPLYICON,379,116,18,
+ 16,SS_CENTERIMAGE | SS_REALSIZEIMAGE
+ CONTROL "",IDC_SAWAYMSG_CONTACTSTREE,"SysTreeView32",
+ TVS_DISABLEDRAGDROP | TVS_SHOWSELALWAYS |
+ TVS_TRACKSELECT | WS_BORDER | WS_TABSTOP,289,1,108,114
+ CONTROL "Ignore requests",IDC_SAWAYMSG_IGNOREREQ,"Button",
+ BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,307,116,80,8,
+ WS_EX_RIGHT
+ CONTROL "Send an autoreply",IDC_SAWAYMSG_SENDMSG,"Button",
+ BS_AUTO3STATE | BS_LEFTTEXT | WS_TABSTOP,307,124,80,8,
+ WS_EX_RIGHT
+ CONTROL "",IDC_SAWAYMSG_TREE,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | TVS_EDITLABELS |
+ TVS_SHOWSELALWAYS | TVS_TRACKSELECT | WS_BORDER |
+ WS_TABSTOP,1,1,112,114
+ CONTROL "&Delete",IDC_SAWAYMSG_DELETE,"MButtonClass",WS_TABSTOP,
+ 2,117,16,14,0x18000000L
+ CONTROL "New &Category",IDC_SAWAYMSG_NEWCATEGORY,"MButtonClass",
+ WS_TABSTOP,18,117,16,14,0x18000000L
+ CONTROL "Save As &New",IDC_SAWAYMSG_SAVEASNEW,"MButtonClass",
+ WS_TABSTOP,34,117,16,14,0x18000000L
+ CONTROL "&Save",IDC_SAWAYMSG_SAVEMSG,"MButtonClass",WS_TABSTOP,
+ 50,117,16,14,0x18000000L
+ CONTROL "",IDC_SAWAYMSG_MSGSPLITTER,"Static",SS_ENHMETAFILE,113,
+ 0,2,115,WS_EX_STATICEDGE
+ CONTROL "",IDC_SAWAYMSG_CONTACTSPLITTER,"Static",SS_ENHMETAFILE,
+ 287,0,2,115,WS_EX_STATICEDGE
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO MOVEABLE PURE
+BEGIN
+ IDD_POPUPOPTDLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 305
+ VERTGUIDE, 90
+ VERTGUIDE, 163
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 230
+ END
+
+ IDD_AUTOREPLY, DIALOG
+ BEGIN
+ RIGHTMARGIN, 297
+ VERTGUIDE, 6
+ VERTGUIDE, 21
+ VERTGUIDE, 296
+ VERTGUIDE, 306
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 224
+ END
+
+ IDD_SETAWAYMSG, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 124
+ END
+
+ IDD_MESSAGES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 304
+ VERTGUIDE, 138
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 164
+ END
+
+ IDD_MODERNOPT_MESSAGES, DIALOG
+ BEGIN
+ RIGHTMARGIN, 366
+ VERTGUIDE, 138
+ HORZGUIDE, 13
+ END
+
+ IDD_MOREOPTDIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 309
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 229
+ END
+
+ IDD_READAWAYMSG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 178
+ TOPMARGIN, 7
+ END
+
+ IDD_CONTACTSOPTDLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 304
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 214
+ END
+
+ IDD_SETAWAYMSG_BAK, DIALOG
+ BEGIN
+ VERTGUIDE, 98
+ HORZGUIDE, 111
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_MSGICON ICON DISCARDABLE "Images\\MsgIcon.ico"
+IDI_SOE_ENABLED ICON DISCARDABLE "Images\\on.ico"
+IDI_SOE_DISABLED ICON DISCARDABLE "Images\\off.ico"
+IDI_DOT ICON DISCARDABLE "Images\\Dot.ico"
+IDI_IGNORE ICON DISCARDABLE "Images\\Ignore.ico"
+IDI_SAVE ICON DISCARDABLE "Images\\SaveMsg.ico"
+IDI_SAVEASNEW ICON DISCARDABLE "Images\\SaveAsNew.ico"
+IDI_DELETE ICON DISCARDABLE "Images\\Delete.ico"
+IDI_NEWCATEGORY ICON DISCARDABLE "Images\\NewCat.ico"
+IDI_VARIABLES ICON DISCARDABLE "Images\\Variables.ico"
+IDI_NEWMESSAGE ICON DISCARDABLE "Images\\NewMessage.ico"
+IDI_SETTINGS ICON DISCARDABLE "Images\\Settings.ico"
+IDI_STATUS_OTHER ICON DISCARDABLE "Images\\Status_Other.ico"
+IDI_INDEFINITE ICON DISCARDABLE "Images\\Indefinite.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_SAM_OPTIONS MENU DISCARDABLE
+BEGIN
+ POPUP "Set away message window options"
+ BEGIN
+ MENUITEM "Show predefined &messages", IDM_SAM_OPTIONS_SHOWMSGTREE
+ MENUITEM "Show &contacts", IDM_SAM_OPTIONS_SHOWCONTACTTREE
+
+ MENUITEM SEPARATOR
+ MENUITEM "Save default window settings &automatically",
+ IDM_SAM_OPTIONS_AUTOSAVEDLGSETTINGS
+
+ MENUITEM "&Save current window settings as default",
+ IDM_SAM_OPTIONS_SAVEDLGSETTINGSNOW
+
+ MENUITEM SEPARATOR
+ MENUITEM "Disable parsing of status messages by Variables plugin",
+ IDM_SAM_OPTIONS_DISABLEVARIABLES
+
+ END
+END
+
+IDR_MSGTREE_CATEGORYMENU MENU DISCARDABLE
+BEGIN
+ POPUP "Message tree menu"
+ BEGIN
+ MENUITEM "Create new &message", IDM_MSGTREEMENU_NEWMESSAGE
+ MENUITEM "Create new &category", IDM_MSGTREEMENU_NEWCATEGORY
+ MENUITEM "&Rename", IDM_MSGTREEMENU_RENAME
+ MENUITEM "&Delete", IDM_MSGTREEMENU_DELETE
+ END
+END
+
+IDR_MSGTREE_MESSAGEMENU MENU DISCARDABLE
+BEGIN
+ POPUP "Message tree category menu"
+ BEGIN
+ POPUP "Set as &default for"
+ BEGIN
+ MENUITEM "On&line", IDR_MSGTREEMENU_DEF_ONL
+ MENUITEM "&Away", IDR_MSGTREEMENU_DEF_AWAY
+ MENUITEM "&NA", IDR_MSGTREEMENU_DEF_NA
+ MENUITEM "Occ&upied", IDR_MSGTREEMENU_DEF_OCC
+ MENUITEM "&DND", IDR_MSGTREEMENU_DEF_DND
+ MENUITEM "&Free for chat", IDR_MSGTREEMENU_DEF_FFC
+ MENUITEM "&Invisible", IDR_MSGTREEMENU_DEF_INV
+ MENUITEM "On the &Phone", IDR_MSGTREEMENU_DEF_OTP
+ MENUITEM "Out to &Lunch", IDR_MSGTREEMENU_DEF_OTL
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "Create new &message", 40022
+ MENUITEM "Create new &category", 40024
+ MENUITEM "&Rename", IDM_MSGTREEMENU_RENAME
+ MENUITEM "&Delete", 40026
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_SOE_ENABLED BITMAP MOVEABLE PURE "Images\\on.bmp"
+IDB_SOE_DISABLED BITMAP MOVEABLE PURE "Images\\off.bmp"
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/plugins/NewAwaySysMod/NewAwaySys.sln b/plugins/NewAwaySysMod/NewAwaySys.sln
new file mode 100644
index 0000000000..b420783798
--- /dev/null
+++ b/plugins/NewAwaySysMod/NewAwaySys.sln
@@ -0,0 +1,24 @@
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NewAwaySys", "NewAwaySys.vcxproj", "{076543A3-41D6-6CD5-E1AE-14CAF9819D48}"
+EndProject
+Global
+ GlobalSection(DPCodeReviewSolutionGUID) = preSolution
+ DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000}
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ DebugW|Win32 = DebugW|Win32
+ Release|Win32 = Release|Win32
+ ReleaseW|Win32 = ReleaseW|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {076543A3-41D6-6CD5-E1AE-14CAF9819D48}.Debug|Win32.ActiveCfg = Debug|Win32
+ {076543A3-41D6-6CD5-E1AE-14CAF9819D48}.DebugW|Win32.ActiveCfg = DebugW|Win32
+ {076543A3-41D6-6CD5-E1AE-14CAF9819D48}.Release|Win32.ActiveCfg = Release|Win32
+ {076543A3-41D6-6CD5-E1AE-14CAF9819D48}.ReleaseW|Win32.ActiveCfg = ReleaseW|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/plugins/NewAwaySysMod/NewAwaySys.vcxproj b/plugins/NewAwaySysMod/NewAwaySys.vcxproj
new file mode 100644
index 0000000000..9077f56283
--- /dev/null
+++ b/plugins/NewAwaySysMod/NewAwaySys.vcxproj
@@ -0,0 +1,363 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="DebugW|Win32">
+ <Configuration>DebugW</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="ReleaseW|Win32">
+ <Configuration>ReleaseW</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <RootNamespace>NewAwaySys</RootNamespace>
+ <SccProjectName />
+ <SccLocalPath />
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugW|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ <CLRSupport>false</CLRSupport>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseW|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseOfMfc>false</UseOfMfc>
+ <CharacterSet>MultiByte</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugW|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseW|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\Debug\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\Release\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='ReleaseW|Win32'">$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='ReleaseW|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='ReleaseW|Win32'">false</LinkIncremental>
+ <OutDir Condition="'$(Configuration)|$(Platform)'=='DebugW|Win32'">$(Configuration)\</OutDir>
+ <IntDir Condition="'$(Configuration)|$(Platform)'=='DebugW|Win32'">$(Configuration)\</IntDir>
+ <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='DebugW|Win32'">false</LinkIncremental>
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='DebugW|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='DebugW|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='DebugW|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='ReleaseW|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='ReleaseW|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='ReleaseW|Win32'" />
+ <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
+ <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../../include;../ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <BasicRuntimeChecks>Default</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>.\Debug/NewAwaySys.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Debug/</AssemblerListingLocation>
+ <ObjectFileName>.\Debug/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Debug/</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <OutputFile>..\..\bin7\Debug\Plugins\NewAwaySys.dll</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AssemblyDebug>
+ </AssemblyDebug>
+ <ProgramDatabaseFile>.\Debug\NewAwaySys.pdb</ProgramDatabaseFile>
+ <GenerateMapFile>true</GenerateMapFile>
+ <MapFileName>.\Debug\NewAwaySys.map</MapFileName>
+ <MapExports>true</MapExports>
+ <EntryPointSymbol>MyDllMain</EntryPointSymbol>
+ <BaseAddress>0x325A0000</BaseAddress>
+ <ImportLibrary>.\Debug\NewAwaySys.lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Debug\NewAwaySys.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>../../include;../ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <BasicRuntimeChecks>Default</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <FunctionLevelLinking>false</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>.\Release/NewAwaySys.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\Release/</AssemblerListingLocation>
+ <ObjectFileName>.\Release/</ObjectFileName>
+ <ProgramDataBaseFileName>.\Release/</ProgramDataBaseFileName>
+ <WarningLevel>Level4</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <OutputFile>..\..\bin7\Debug\Plugins\NewAwaySys.dll</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>.\Release\NewAwaySys.pdb</ProgramDatabaseFile>
+ <GenerateMapFile>true</GenerateMapFile>
+ <MapFileName>.\Release\NewAwaySys.map</MapFileName>
+ <MapExports>true</MapExports>
+ <EntryPointSymbol>MyDllMain</EntryPointSymbol>
+ <BaseAddress>0x325A0000</BaseAddress>
+ <ImportLibrary>.\Release/NewAwaySys.lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Release/NewAwaySys.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseW|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
+ <AdditionalIncludeDirectories>../../include;../ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;UNICODE;_UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ <BasicRuntimeChecks>Default</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <FunctionLevelLinking>false</FunctionLevelLinking>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>.\ReleaseW/NewAwaySys.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\ReleaseW/</AssemblerListingLocation>
+ <ObjectFileName>.\ReleaseW/</ObjectFileName>
+ <ProgramDataBaseFileName>.\ReleaseW/</ProgramDataBaseFileName>
+ <WarningLevel>Level4</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>
+ </DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <OutputFile>..\..\bin7\Debug\Plugins\NewAwaySysW.dll</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
+ <IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>.\ReleaseW\NewAwaySys.pdb</ProgramDatabaseFile>
+ <GenerateMapFile>true</GenerateMapFile>
+ <MapFileName>.\ReleaseW\NewAwaySys.map</MapFileName>
+ <MapExports>true</MapExports>
+ <EntryPointSymbol>MyDllMain</EntryPointSymbol>
+ <BaseAddress>0x325A0000</BaseAddress>
+ <ImportLibrary>.\ReleaseW/NewAwaySys.lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <Midl>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Release/NewAwaySys.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugW|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../../include;../ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;UNICODE;_UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <BasicRuntimeChecks>Default</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <PrecompiledHeaderOutputFile>.\DebugW/NewAwaySys.pch</PrecompiledHeaderOutputFile>
+ <AssemblerListingLocation>.\DebugW/</AssemblerListingLocation>
+ <ObjectFileName>.\DebugW/</ObjectFileName>
+ <ProgramDataBaseFileName>.\DebugW/</ProgramDataBaseFileName>
+ <WarningLevel>Level3</WarningLevel>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <OutputFile>..\..\bin7\Debug\Plugins\NewAwaySysW.dll</OutputFile>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AssemblyDebug>true</AssemblyDebug>
+ <ProgramDatabaseFile>.\DebugW\NewAwaySys.pdb</ProgramDatabaseFile>
+ <GenerateMapFile>true</GenerateMapFile>
+ <MapFileName>.\DebugW\NewAwaySys.map</MapFileName>
+ <MapExports>true</MapExports>
+ <EntryPointSymbol>MyDllMain</EntryPointSymbol>
+ <BaseAddress>0x325A0000</BaseAddress>
+ <ImportLibrary>.\DebugW\NewAwaySys.lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ </Link>
+ <Midl>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MkTypLibCompatible>true</MkTypLibCompatible>
+ <SuppressStartupBanner>true</SuppressStartupBanner>
+ <TargetEnvironment>Win32</TargetEnvironment>
+ <TypeLibraryName>.\Debug\NewAwaySys.tlb</TypeLibraryName>
+ <HeaderFileName>
+ </HeaderFileName>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <Culture>0x0409</Culture>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="AwayOpt.cpp" />
+ <ClCompile Include="AwaySys.cpp" />
+ <ClCompile Include="Client.cpp" />
+ <ClCompile Include="ContactList.cpp" />
+ <ClCompile Include="..\CommonLibs\CString.cpp" />
+ <ClCompile Include="..\CommonLibs\GroupCheckbox.cpp" />
+ <ClCompile Include="MsgEventAdded.cpp">
+ <Optimization Condition="'$(Configuration)|$(Platform)'=='ReleaseW|Win32'">MinSpace</Optimization>
+ </ClCompile>
+ <ClCompile Include="MsgTree.cpp" />
+ <ClCompile Include="Notification.cpp" />
+ <ClCompile Include="..\CommonLibs\Options.cpp" />
+ <ClCompile Include="Properties.cpp" />
+ <ClCompile Include="ReadAwayMsg.cpp" />
+ <ClCompile Include="Services.cpp" />
+ <ClCompile Include="SetAwayMsg.cpp" />
+ <ClCompile Include="..\CommonLibs\ThemedImageCheckbox.cpp" />
+ <ClCompile Include="..\CommonLibs\Themes.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="AggressiveOptimize.h" />
+ <ClInclude Include="Common.h" />
+ <ClInclude Include="ContactList.h" />
+ <ClInclude Include="..\CommonLibs\CString.h" />
+ <ClInclude Include="..\CommonLibs\GroupCheckbox.h" />
+ <ClInclude Include="..\CommonLibs\m_ContactSettings.h" />
+ <ClInclude Include="..\CommonLibs\m_LogService.h" />
+ <ClInclude Include="..\CommonLibs\m_NewAwaySys.h" />
+ <ClInclude Include="m_popup.h" />
+ <ClInclude Include="m_popupw.h" />
+ <ClInclude Include="m_statusplugins.h" />
+ <ClInclude Include="m_toptoolbar.h" />
+ <ClInclude Include="m_updater.h" />
+ <ClInclude Include="m_variables.h" />
+ <ClInclude Include="MsgTree.h" />
+ <ClInclude Include="..\CommonLibs\Options.h" />
+ <ClInclude Include="Path.h" />
+ <ClInclude Include="Properties.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="Services.h" />
+ <ClInclude Include="..\CommonLibs\ThemedImageCheckbox.h" />
+ <ClInclude Include="..\CommonLibs\Themes.h" />
+ <ClInclude Include="..\CommonLibs\TMyArray.h" />
+ <ClInclude Include="VersionNo.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Images\Delete.ico" />
+ <None Include="Images\DisableNotify.ico" />
+ <None Include="Images\Dot.ico" />
+ <None Include="Images\EditMsgs.ico" />
+ <None Include="Images\EnableNotify.ico" />
+ <None Include="Images\Ignore.ico" />
+ <None Include="Images\Indefinite.ico" />
+ <None Include="Images\MsgIcon.ico" />
+ <None Include="Images\NewCat.ico" />
+ <None Include="Images\NewMessage.ico" />
+ <None Include="Images\off.bmp" />
+ <None Include="Images\off.ico" />
+ <None Include="Images\on.bmp" />
+ <None Include="Images\on.ico" />
+ <None Include="Resources.rc2" />
+ <None Include="Images\SaveAsNew.ico" />
+ <None Include="Images\SaveMsg.ico" />
+ <None Include="Images\Settings.ico" />
+ <None Include="Images\Status_Other.ico" />
+ <None Include="Images\Variables.ico" />
+ <None Include="copying.txt" />
+ <None Include="nas_readme.txt" />
+ <None Include="nas_translation.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="Resources.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/plugins/NewAwaySysMod/NewAwaySys.vcxproj.filters b/plugins/NewAwaySysMod/NewAwaySys.vcxproj.filters
new file mode 100644
index 0000000000..01a9090e9d
--- /dev/null
+++ b/plugins/NewAwaySysMod/NewAwaySys.vcxproj.filters
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{116110a1-b9f8-4995-aab2-1de50eab806f}</UniqueIdentifier>
+ <Extensions>cpp;c;cxx;rc;def;r;odl;idl;hpj;bat</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{7c639270-1dc0-403f-a6ba-7da092e1f885}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{bbdb7c3b-6f74-434a-b577-46de841df2af}</UniqueIdentifier>
+ <Extensions>ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe</Extensions>
+ </Filter>
+ <Filter Include="Documentation">
+ <UniqueIdentifier>{b1737ff9-4769-4f5b-b414-ee0f5256de7f}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="AwayOpt.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="AwaySys.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Client.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ContactList.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\CommonLibs\CString.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\CommonLibs\GroupCheckbox.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="MsgEventAdded.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="MsgTree.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Notification.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\CommonLibs\Options.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Properties.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ReadAwayMsg.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Services.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="SetAwayMsg.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\CommonLibs\ThemedImageCheckbox.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\CommonLibs\Themes.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="AggressiveOptimize.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Common.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ContactList.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\CommonLibs\CString.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\CommonLibs\GroupCheckbox.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\CommonLibs\m_ContactSettings.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\CommonLibs\m_LogService.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\CommonLibs\m_NewAwaySys.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_popup.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_popupw.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_statusplugins.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_toptoolbar.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_updater.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="m_variables.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="MsgTree.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\CommonLibs\Options.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Path.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Properties.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Services.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\CommonLibs\ThemedImageCheckbox.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\CommonLibs\Themes.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\CommonLibs\TMyArray.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="VersionNo.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Images\Delete.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\DisableNotify.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\Dot.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\EditMsgs.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\EnableNotify.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\Ignore.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\Indefinite.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\MsgIcon.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\NewCat.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\NewMessage.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\off.bmp">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\off.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\on.bmp">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\on.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Resources.rc2">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\SaveAsNew.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\SaveMsg.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\Settings.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\Status_Other.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="Images\Variables.ico">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="copying.txt">
+ <Filter>Documentation</Filter>
+ </None>
+ <None Include="nas_readme.txt">
+ <Filter>Documentation</Filter>
+ </None>
+ <None Include="nas_translation.txt">
+ <Filter>Documentation</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="Resources.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/plugins/NewAwaySysMod/Notification.cpp b/plugins/NewAwaySysMod/Notification.cpp
new file mode 100644
index 0000000000..b1434d0155
--- /dev/null
+++ b/plugins/NewAwaySysMod/Notification.cpp
@@ -0,0 +1,289 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (C) 2005-2007 Chervov Dmitry
+
+ 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 "Common.h"
+#include "Path.h"
+#include "Properties.h"
+
+
+void ShowMsg(TCHAR *FirstLine, TCHAR *SecondLine, bool IsErrorMsg, int Timeout)
+{
+ if (ServiceExists(MS_POPUP_ADDPOPUPEX))
+ {
+ POPUPDATAT ppd = {0};
+ ppd.lchIcon = LoadIcon(NULL, IsErrorMsg ? IDI_EXCLAMATION : IDI_INFORMATION);
+// lstrcpy(ppd.lpzContactName, FirstLine);
+// lstrcpy(ppd.lpzText, SecondLine);
+ lstrcpy(ppd.lpwzContactName, FirstLine);
+ lstrcpy(ppd.lpwzText, SecondLine);
+ ppd.colorBack = IsErrorMsg ? 0x0202E3 : 0xE8F1FD;
+ ppd.colorText = IsErrorMsg ? 0xE8F1FD : 0x000000;
+ ppd.iSeconds = Timeout;
+ CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&ppd, 0);
+ } else
+ {
+ MessageBox(NULL, SecondLine, FirstLine, MB_OK | (IsErrorMsg ? MB_ICONEXCLAMATION : MB_ICONINFORMATION));
+ }
+}
+
+
+static int CALLBACK MenuWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ switch (uMsg)
+ {
+ case WM_MEASUREITEM:
+ {
+ return CallService(MS_CLIST_MENUMEASUREITEM, wParam, lParam);
+ }
+ case WM_DRAWITEM:
+ {
+ return CallService(MS_CLIST_MENUDRAWITEM, wParam, lParam);
+ }
+ }
+ return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+
+static VOID CALLBACK ShowContactMenu(DWORD wParam)
+// wParam = hContact
+{
+ POINT pt;
+ HWND hMenuWnd = CreateWindowEx(WS_EX_TOOLWINDOW, _T("static"), _T(MOD_NAME)_T("_MenuWindow"), 0, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, NULL, g_hInstance, NULL);
+ SetWindowLong(hMenuWnd, GWL_WNDPROC, (LONG)(WNDPROC)MenuWndProc);
+ HMENU hMenu = (HMENU)CallService(MS_CLIST_MENUBUILDCONTACT, (WPARAM)wParam, 0);
+ GetCursorPos(&pt);
+ SetForegroundWindow(hMenuWnd);
+ CallService(MS_CLIST_MENUPROCESSCOMMAND, MAKEWPARAM(TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD, pt.x, pt.y, 0, hMenuWnd, NULL), MPCF_CONTACTMENU), (LPARAM)wParam);
+ PostMessage(hMenuWnd, WM_NULL, 0, 0);
+ DestroyMenu(hMenu);
+ DestroyWindow(hMenuWnd);
+}
+
+/*
+void Popup_DoAction(HWND hWnd, BYTE Action, PLUGIN_DATA *pdata)
+{
+ HANDLE hContact = (HANDLE)CallService(MS_POPUP_GETCONTACT, (WPARAM)hWnd, 0);
+ switch (Action)
+ {
+ case PCA_OPENMESSAGEWND: // open message window
+ {
+ if (hContact && hContact != INVALID_HANDLE_VALUE)
+ {
+ CallServiceSync(ServiceExists("SRMsg/LaunchMessageWindow") ? "SRMsg/LaunchMessageWindow" : MS_MSG_SENDMESSAGE, (WPARAM)hContact, 0);
+ }
+ } break;
+ case PCA_OPENMENU: // open contact menu
+ {
+ if (hContact && hContact != INVALID_HANDLE_VALUE)
+ {
+ QueueUserAPC(ShowContactMenu, hMainThread, (ULONG_PTR)hContact);
+ }
+ } break;
+ case PCA_OPENDETAILS: // open contact details window
+ {
+ if (hContact != INVALID_HANDLE_VALUE)
+ {
+ CallServiceSync(MS_USERINFO_SHOWDIALOG, (WPARAM)hContact, 0);
+ }
+ } break;
+ case PCA_OPENHISTORY: // open contact history
+ {
+ if (hContact != INVALID_HANDLE_VALUE)
+ {
+ CallServiceSync(MS_HISTORY_SHOWCONTACTHISTORY, (WPARAM)hContact, 0);
+ }
+ } break;
+ case PCA_OPENLOG: // open log file
+ {
+ TCString LogFilePath;
+ LS_LOGINFO li = {0};
+ li.cbSize = sizeof(li);
+ li.szID = LOG_ID;
+ li.hContact = hContact;
+ li.Flags = LSLI_TCHAR;
+ li.tszLogPath = LogFilePath.GetBuffer(MAX_PATH);
+ if (!CallService(MS_LOGSERVICE_GETLOGINFO, (WPARAM)&li, 0))
+ {
+ LogFilePath.ReleaseBuffer();
+ ShowLog(LogFilePath);
+ } else
+ {
+ LogFilePath.ReleaseBuffer();
+ }
+ } break;
+ case PCA_CLOSEPOPUP: // close popup
+ {
+ PUDeletePopUp(hWnd);
+ } break;
+ case PCA_DONOTHING: // do nothing
+ break;
+ }
+}
+
+
+static int CALLBACK ReqNotifyPopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ PLUGIN_DATA *pdata;
+ switch (message)
+ {
+ case WM_COMMAND:
+ {
+ if (HIWORD(wParam) == STN_CLICKED) // left mouse button
+ {
+ pdata = (PLUGIN_DATA*)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd, 0);
+ if (pdata)
+ {
+ Popup_DoAction(hWnd, pdata->PopupLClickAction, pdata);
+ }
+ return true;
+ }
+ } break;
+ case WM_CONTEXTMENU: // right mouse button
+ {
+ pdata = (PLUGIN_DATA*)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd, 0);
+ if (pdata)
+ {
+ Popup_DoAction(hWnd, pdata->PopupRClickAction, pdata);
+ }
+ return true;
+ } break;
+ case UM_FREEPLUGINDATA:
+ {
+ pdata = (PLUGIN_DATA*)CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd, 0);
+ if (pdata)
+ {
+ if (pdata->hStatusIcon)
+ {
+ DestroyIcon(pdata->hStatusIcon);
+ }
+ free(pdata);
+ }
+ return true;
+ } break;
+ }
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+
+int ShowPopupNotification(COptPage &PopupNotifyData, HANDLE hContact, int iStatusMode)
+{ // returns TRUE if popup was shown
+// we take szProto, UIN and Message from VarParseData
+ POPUPDATAT ppd = {0};
+ ppd.lchContact = hContact;
+ TCString ExtraText;
+ if (!iStatusMode)
+ { // if it's an xstatus message request
+ ExtraText = DBGetContactSettingString(NULL, VarParseData.szProto, "XStatusName", _T(""));
+ TCString XMsg(DBGetContactSettingString(NULL, VarParseData.szProto, "XStatusMsg", _T("")));
+ if (XMsg.GetLen())
+ {
+ if (ExtraText.GetLen())
+ {
+ ExtraText += _T("\r\n");
+ }
+ ExtraText += XMsg;
+ }
+ } else
+ {
+ ExtraText = VarParseData.Message;
+ }
+ TCString PopupMsg(*(TCString*)PopupNotifyData.GetValue(IDC_POPUPOPTDLG_POPUPFORMAT));
+ if (ServiceExists(MS_VARS_FORMATSTRING))
+ {
+ FORMATINFO fi = {0};
+ fi.cbSize = sizeof(fi);
+ fi.flags = FIF_TCHAR;
+ fi.tszFormat = PopupMsg;
+ fi.hContact = hContact;
+ fi.tszExtraText = ExtraText;
+ TCHAR *szResult = (TCHAR*)CallService(MS_VARS_FORMATSTRING, (WPARAM)&fi, 0);
+ if (szResult)
+ {
+ PopupMsg = szResult;
+ CallService(MS_VARS_FREEMEMORY, (WPARAM)szResult, 0);
+ }
+ } else
+ {
+ TCString szUIN;
+ _ultot(VarParseData.UIN, szUIN.GetBuffer(16), 10);
+ szUIN.ReleaseBuffer();
+ TCHAR *szStatDesc = iStatusMode ? (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, iStatusMode, GCMDF_TCHAR) : STR_XSTATUSDESC;
+ _ASSERT(szStatDesc);
+ PopupMsg = TCString((TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)) + _T(" (") + szUIN + TranslateT(") is reading your ") + szStatDesc + TranslateT(" message:\r\n") + ExtraText;
+ }
+ if (PopupMsg.GetLen())
+ {
+ TCHAR *pLineBreak = _tcsstr(PopupMsg, _T("\n"));
+ if (pLineBreak)
+ {
+ PopupMsg.GetBuffer();
+ TCHAR *pNextLine = pLineBreak + 1;
+ while ((*pNextLine == '\r' || *pNextLine == '\n') && *pNextLine)
+ {
+ *pNextLine++;
+ }
+ _tcsncpy(ppd.lpzText, pNextLine, 499);
+ while ((*pLineBreak == '\r' || *pLineBreak == '\n') && (pLineBreak >= PopupMsg))
+ {
+ *pLineBreak-- = 0;
+ }
+ PopupMsg.ReleaseBuffer();
+ } else
+ {
+ lstrcpy(ppd.lpzText, _T(""));
+ }
+ _tcsncpy(ppd.lpzContactName, PopupMsg, 499);
+ ppd.colorBack = (PopupNotifyData.GetValue(IDC_POPUPOPTDLG_DEFBGCOLOUR) ? 0 : PopupNotifyData.GetValue(IDC_POPUPOPTDLG_BGCOLOUR));
+ ppd.colorText = (PopupNotifyData.GetValue(IDC_POPUPOPTDLG_DEFTEXTCOLOUR) ? 0 : PopupNotifyData.GetValue(IDC_POPUPOPTDLG_TEXTCOLOUR));
+ ppd.PluginWindowProc = (WNDPROC)ReqNotifyPopupDlgProc;
+ PLUGIN_DATA *pdata = (PLUGIN_DATA*)calloc(1, sizeof(PLUGIN_DATA));
+ if (!iStatusMode)
+ { // it's an xstatus message request
+ ppd.lchIcon = pdata->hStatusIcon = (HICON)CallProtoService(VarParseData.szProto, PS_ICQ_GETCUSTOMSTATUSICON, 0, 0);
+ }
+ if (!pdata->hStatusIcon || (DWORD)pdata->hStatusIcon == CALLSERVICE_NOTFOUND)
+ {
+ pdata->hStatusIcon = NULL;
+ ppd.lchIcon = LoadSkinnedProtoIcon(VarParseData.szProto, iStatusMode);
+ }
+ pdata->PopupLClickAction = PopupNotifyData.GetValue(IDC_POPUPOPTDLG_LCLICK_ACTION);
+ pdata->PopupRClickAction = PopupNotifyData.GetValue(IDC_POPUPOPTDLG_RCLICK_ACTION);
+ ppd.PluginData = pdata;
+ ppd.iSeconds = PopupNotifyData.GetValue(IDC_POPUPOPTDLG_POPUPDELAY);
+ CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&ppd, 0);
+ if (hContact)
+ {
+ SkinPlaySound(AWAYSYS_STATUSMSGREQUEST_SOUND);
+ }
+ return true;
+ }
+ return false;
+}
+*/
+
+void ShowLog(TCString &LogFilePath)
+{
+ int Result = (int)ShellExecute(NULL, _T("open"), LogFilePath, NULL, NULL, SW_SHOW);
+ if (Result <= 32) // Error
+ {
+ TCHAR szError[64];
+ _stprintf(szError, TranslateT("Error #%d"), Result);
+ ShowMsg(szError, TranslateT("Can't open log file ") + LogFilePath, true);
+ }
+}
diff --git a/plugins/NewAwaySysMod/Path.h b/plugins/NewAwaySysMod/Path.h
new file mode 100644
index 0000000000..e64b7ceb3c
--- /dev/null
+++ b/plugins/NewAwaySysMod/Path.h
@@ -0,0 +1,43 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (c) 2005-2007 Chervov Dmitry
+
+ 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
+
+#include "m_utils.h"
+#include "..\CommonLibs\CString.h"
+
+
+__inline TCString Path_ToRelative(TCString &Path)
+{
+ CString Str;
+ Str.GetBuffer(MAX_PATH);
+ CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)(const char*)TCHAR2ANSI(Path), (LPARAM)(char*)Str);
+ Str.ReleaseBuffer();
+ return ANSI2TCHAR(Str);
+}
+
+
+__inline TCString Path_ToAbsolute(TCString &Path)
+{
+ CString Str;
+ Str.GetBuffer(MAX_PATH);
+ CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)(const char*)TCHAR2ANSI(Path), (LPARAM)(char*)Str);
+ Str.ReleaseBuffer();
+ return ANSI2TCHAR(Str);
+}
diff --git a/plugins/NewAwaySysMod/Properties.cpp b/plugins/NewAwaySysMod/Properties.cpp
new file mode 100644
index 0000000000..97ecf7d665
--- /dev/null
+++ b/plugins/NewAwaySysMod/Properties.cpp
@@ -0,0 +1,447 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (C) 2005-2007 Chervov Dmitry
+
+ 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 "Common.h"
+#include "Properties.h"
+
+CProtoStates g_ProtoStates;
+
+
+/*char *mystrdup(const char *szStr)
+{
+ char *szNew = (char *)malloc(lstrlen(szStr) + 1);
+ lstrcpy(szNew, szStr);
+ return szNew;
+}
+
+
+void *mymalloc(size_t size)
+{
+ return HeapAlloc(GetProcessHeap(), 0, size);//GlobalAlloc(GPTR, size);
+}
+
+
+void myfree(void *p)
+{
+ //GlobalFree(p);
+ HeapFree(GetProcessHeap(), 0, p);
+}
+
+
+void *__cdecl operator new(unsigned int size)
+{
+ return (void *)HeapAlloc(GetProcessHeap(), 0, size);//GlobalAlloc(GPTR, size);
+}
+
+
+void __cdecl operator delete(void *p)
+{
+// GlobalFree((HGLOBAL)p);
+ HeapFree(GetProcessHeap(), 0, p);
+}
+*/
+
+
+void ResetContactSettingsOnStatusChange(HANDLE hContact)
+{
+ DBDeleteContactSetting(hContact, MOD_NAME, DB_REQUESTCOUNT);
+ DBDeleteContactSetting(hContact, MOD_NAME, DB_SENDCOUNT);
+ DBDeleteContactSetting(hContact, MOD_NAME, DB_MESSAGECOUNT);
+}
+
+
+void ResetSettingsOnStatusChange(const char *szProto = NULL, int bResetPersonalMsgs = false, int Status = 0)
+{
+ if (bResetPersonalMsgs)
+ { // bResetPersonalMsgs &&= g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_SAVEPERSONALMSGS);
+ bResetPersonalMsgs = !g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_SAVEPERSONALMSGS);
+ }
+ HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact)
+ {
+ const char *szCurProto;
+ if (!szProto || ((szCurProto = (const char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0)) && !lstrcmpA(szProto, szCurProto)))
+ {
+ ResetContactSettingsOnStatusChange(hContact);
+ if (bResetPersonalMsgs)
+ {
+ CContactSettings(Status, hContact).SetMsgFormat(SMF_PERSONAL, NULL); // TODO: delete only when SAM dialog opens?
+ }
+ }
+ hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0);
+ }
+}
+
+
+CProtoState::CStatus& CProtoState::CStatus::operator = (int Status)
+{
+ _ASSERT(Status >= ID_STATUS_OFFLINE && Status <= ID_STATUS_OUTTOLUNCH);
+ if (Status < ID_STATUS_OFFLINE || Status > ID_STATUS_OUTTOLUNCH)
+ {
+ return *this; // ignore status change if the new status is unknown
+ }
+ bool bModified = false;
+ if (szProto)
+ {
+ if (this->Status != Status)
+ {
+ this->Status = Status;
+ (*GrandParent)[szProto].AwaySince.Reset();
+ ResetSettingsOnStatusChange(szProto, true, Status);
+ bModified = true;
+ }
+ if ((*GrandParent)[szProto].TempMsg.IsSet())
+ {
+ (*GrandParent)[szProto].TempMsg.Unset();
+ bModified = true;
+ }
+ } else // global status change
+ {
+ int I;
+ int bStatusModified = false;
+ for (I = 0; I < GrandParent->GetSize(); I++)
+ {
+ CProtoState &State = (*GrandParent)[I];
+ if (!DBGetContactSettingByte(NULL, State.GetProto(), "LockMainStatus", 0)) // if the protocol isn't locked
+ {
+ if (State.Status != Status)
+ {
+ State.Status.Status = Status; // "Status.Status" - changing Status directly to prevent recursive calls to the function
+ State.AwaySince.Reset();
+ bModified = true;
+ bStatusModified = true;
+ }
+ if (State.TempMsg.IsSet())
+ {
+ State.TempMsg.Unset();
+ bModified = true;
+ }
+ if (g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_RESETPROTOMSGS))
+ {
+ CProtoSettings(State.szProto, Status).SetMsgFormat(SMF_PERSONAL, NULL);
+ }
+ }
+ }
+ if (bStatusModified)
+ {
+ ResetSettingsOnStatusChange(NULL, true, Status);
+ }
+ }
+ if (bModified && g_SetAwayMsgPage.GetWnd())
+ {
+ SendMessage(g_SetAwayMsgPage.GetWnd(), UM_SAM_PROTOSTATUSCHANGED, (WPARAM)(char*)szProto, 0);
+ }
+ return *this;
+}
+
+
+void CProtoState::CAwaySince::Reset()
+{
+ GetLocalTime(&AwaySince);
+ if (GrandParent && !szProto)
+ {
+ int I;
+ for (I = 0; I < GrandParent->GetSize(); I++)
+ {
+ GetLocalTime((*GrandParent)[I].AwaySince);
+ }
+ }
+}
+
+
+void CContactSettings::SetMsgFormat(int Flags, TCString Message)
+{
+ if (Flags & SMF_PERSONAL)
+ { // set a personal message for a contact. also it's used to set global status message (hContact = NULL).
+ // if Message == NULL, then the function deletes the message.
+ CString DBSetting(StatusToDBSetting(Status, DB_STATUSMSG, IDC_MOREOPTDLG_PERSTATUSPERSONAL));
+ if (g_AutoreplyOptPage.GetDBValueCopy(IDC_REPLYDLG_RESETCOUNTERWHENSAMEICON) && GetMsgFormat(SMF_PERSONAL) != (const TCHAR*)Message)
+ {
+ ResetContactSettingsOnStatusChange(hContact);
+ }
+ if (Message != NULL)
+ {
+ DBWriteContactSettingTString(hContact, MOD_NAME, DBSetting, Message);
+ } else
+ {
+ DBDeleteContactSetting(hContact, MOD_NAME, DBSetting);
+ }
+ }
+ if (Flags & (SMF_LAST | SMF_TEMPORARY))
+ {
+ _ASSERT(!hContact);
+ CProtoSettings().SetMsgFormat(Flags & (SMF_LAST | SMF_TEMPORARY), Message);
+ }
+}
+
+
+TCString CContactSettings::GetMsgFormat(int Flags, int *pOrder, char *szProtoOverride)
+// returns the requested message; sets Order to the order of the message in the message tree, if available; or to -1 otherwise.
+// szProtoOverride is needed only to get status message of the right protocol when the ICQ contact is on list, but not with the same protocol on which it requests the message - this way we can still get contact details.
+{
+ TCString Message = NULL;
+ if (pOrder)
+ {
+ *pOrder = -1;
+ }
+ if (Flags & GMF_PERSONAL)
+ { // try getting personal message (it overrides global)
+ Message = DBGetContactSettingString(hContact, MOD_NAME, StatusToDBSetting(Status, DB_STATUSMSG, IDC_MOREOPTDLG_PERSTATUSPERSONAL), (TCHAR*)NULL);
+ }
+ if (Flags & (GMF_LASTORDEFAULT | GMF_PROTOORGLOBAL | GMF_TEMPORARY) && Message.IsEmpty())
+ {
+ char *szProto = szProtoOverride ? szProtoOverride : (hContact ? (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0) : NULL);
+ if (Flags & (GMF_LASTORDEFAULT | GMF_PROTOORGLOBAL))
+ { // we mustn't pass here by GMF_TEMPORARY flag, as otherwise we'll handle GMF_TEMPORARY | GMF_PERSONAL combination incorrectly, which is supposed to get only per-contact messages, and at the same time also may be used with NULL contact to get the global status message
+ Message = CProtoSettings(szProto).GetMsgFormat(Flags, pOrder);
+ } else if (!hContact)
+ { // handle global temporary message too
+ if (g_ProtoStates[szProto].TempMsg.IsSet())
+ {
+ Message = g_ProtoStates[szProto].TempMsg;
+ }
+ }
+ }
+ return Message;
+}
+
+
+void CProtoSettings::SetMsgFormat(int Flags, TCString Message)
+{
+ if (Flags & (SMF_TEMPORARY | SMF_PERSONAL) && g_AutoreplyOptPage.GetDBValueCopy(IDC_REPLYDLG_RESETCOUNTERWHENSAMEICON) && GetMsgFormat(Flags & (SMF_TEMPORARY | SMF_PERSONAL)) != (const TCHAR*)Message)
+ {
+ ResetSettingsOnStatusChange(szProto);
+ }
+ if (Flags & SMF_TEMPORARY)
+ {
+ _ASSERT(!Status || Status == g_ProtoStates[szProto].Status);
+ g_ProtoStates[szProto].TempMsg = (szProto || Message != NULL) ? Message : CProtoSettings(NULL, Status).GetMsgFormat(GMF_LASTORDEFAULT);
+ }
+ if (Flags & SMF_PERSONAL)
+ { // set a "personal" message for a protocol. also it's used to set global status message (hContact = NULL).
+ // if Message == NULL, then we'll use the "default" message - i.e. it's either the global message for szProto != NULL (we delete the per-proto DB setting), or it's just a default message for a given status for szProto == NULL.
+ g_ProtoStates[szProto].TempMsg.Unset();
+ CString DBSetting(ProtoStatusToDBSetting(DB_STATUSMSG, IDC_MOREOPTDLG_PERSTATUSPROTOMSGS));
+ if (Message != NULL)
+ {
+ DBWriteContactSettingTString(NULL, MOD_NAME, DBSetting, Message);
+ } else
+ {
+ if (!szProto)
+ {
+ DBWriteContactSettingTString(NULL, MOD_NAME, DBSetting, CProtoSettings(NULL, Status).GetMsgFormat(GMF_LASTORDEFAULT)); // global message can't be NULL; we can use an empty string instead if it's really necessary
+ } else
+ {
+ DBDeleteContactSetting(NULL, MOD_NAME, DBSetting);
+ }
+ }
+ }
+ if (Flags & SMF_LAST)
+ {
+ COptPage MsgTreeData(g_MsgTreePage);
+ COptItem_TreeCtrl *TreeCtrl = (COptItem_TreeCtrl*)MsgTreeData.Find(IDV_MSGTREE);
+ TreeCtrl->DBToMem(CString(MOD_NAME));
+ int RecentGroupID = GetRecentGroupID(Status);
+ if (RecentGroupID == -1)
+ { // we didn't find the group, it also means that we're using per status messages; so we need to create it
+ TreeCtrl->Value.AddElem(CTreeItem(Status ? (const TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, Status, GCMDF_TCHAR) : MSGTREE_RECENT_OTHERGROUP, g_Messages_RecentRootID, RecentGroupID = TreeCtrl->GenerateID(), TIF_GROUP));
+ TreeCtrl->SetModified(true);
+ }
+ int I;
+ TCString Title(_T(""));
+ for (I = 0; I < TreeCtrl->Value.GetSize(); I++) // try to find an identical message in the same group (to prevent saving multiple identical messages), or at least if we'll find an identical message somewhere else, then we'll use its title for our new message
+ {
+ if (!(TreeCtrl->Value[I].Flags & TIF_GROUP) && TreeCtrl->Value[I].User_Str1 == (const TCHAR*)Message)
+ {
+ if (TreeCtrl->Value[I].ParentID == RecentGroupID)
+ { // found it in the same group
+ int GroupOrder = TreeCtrl->IDToOrder(RecentGroupID);
+ TreeCtrl->Value.MoveElem(I, (GroupOrder >= 0) ? (GroupOrder + 1) : 0); // now move it to the top of recent messages list
+ TreeCtrl->SetModified(true);
+ break; // no reason to search for anything else
+ } else if (Title.IsEmpty())
+ { // it's not in the same group, but at least we'll use its title
+ Title = TreeCtrl->Value[I].Title;
+ }
+ }
+ }
+ if (I == TreeCtrl->Value.GetSize())
+ { // we didn't find an identical message in the same group, so we'll add our new message here
+ if (Title.IsEmpty())
+ { // didn't find a title for our message either
+ if (Message.GetLen() > MRM_MAX_GENERATED_TITLE_LEN)
+ {
+ Title = Message.Left(MRM_MAX_GENERATED_TITLE_LEN - 3) + _T("...");
+ } else
+ {
+ Title = Message;
+ }
+ TCHAR *p = Title.GetBuffer();
+ while (*p) // remove "garbage"
+ {
+ if (!(p = _tcspbrk(p, _T("\r\n\t"))))
+ {
+ break;
+ }
+ *p++ = ' ';
+ }
+ Title.ReleaseBuffer();
+ }
+ int GroupOrder = TreeCtrl->IDToOrder(RecentGroupID);
+ TreeCtrl->Value.InsertElem(CTreeItem(Title, RecentGroupID, TreeCtrl->GenerateID(), 0, Message), (GroupOrder >= 0) ? (GroupOrder + 1) : 0);
+ TreeCtrl->SetModified(true);
+ }
+ // now clean up here
+ int MRMNum = 0;
+ int MaxMRMNum = g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_RECENTMSGSCOUNT);
+ for (I = 0; I < TreeCtrl->Value.GetSize(); I++)
+ {
+ if (TreeCtrl->Value[I].ParentID == RecentGroupID)
+ { // found a child of our group
+ if (TreeCtrl->Value[I].Flags & TIF_GROUP || ++MRMNum > MaxMRMNum) // what groups are doing here?! :))
+ {
+ TreeCtrl->Value.RemoveElem(I);
+ TreeCtrl->SetModified(true);
+ I--;
+ }
+ }
+ }
+ if (g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_PERSTATUSMRM))
+ { // if we're saving recent messages per status, then remove any messages that were left at the recent messages' root
+ for (I = 0; I < TreeCtrl->Value.GetSize(); I++)
+ {
+ if (TreeCtrl->Value[I].ParentID == g_Messages_RecentRootID)
+ {
+ if (!(TreeCtrl->Value[I].Flags & TIF_GROUP))
+ {
+ TreeCtrl->Value.RemoveElem(I);
+ TreeCtrl->SetModified(true);
+ I--;
+ }
+ }
+ }
+ }
+ TreeCtrl->MemToDB(CString(MOD_NAME));
+ }
+}
+
+
+TCString CProtoSettings::GetMsgFormat(int Flags, int *pOrder)
+// returns the requested message; sets Order to the order of the message in the message tree, if available; or to -1 otherwise.
+{
+ TCString Message = NULL;
+ if (pOrder)
+ {
+ *pOrder = -1;
+ }
+ if (Flags & GMF_TEMPORARY)
+ {
+ _ASSERT(!Status || Status == g_ProtoStates[szProto].Status);
+ if (g_ProtoStates[szProto].TempMsg.IsSet())
+ {
+ Message = g_ProtoStates[szProto].TempMsg;
+ Flags &= ~GMF_PERSONAL; // don't allow personal message to overwrite our NULL temporary message
+ }
+ }
+ if (Flags & GMF_PERSONAL && Message == NULL)
+ { // try getting personal message (it overrides global)
+ Message = DBGetContactSettingString(NULL, MOD_NAME, ProtoStatusToDBSetting(DB_STATUSMSG, IDC_MOREOPTDLG_PERSTATUSPROTOMSGS), (TCHAR*)NULL);
+ }
+ if (Flags & GMF_PROTOORGLOBAL && Message == NULL)
+ {
+ Message = CProtoSettings().GetMsgFormat(GMF_PERSONAL | (Flags & GMF_TEMPORARY), pOrder);
+ return (Message == NULL) ? _T("") : Message; // global message can't be NULL
+ }
+ if (Flags & GMF_LASTORDEFAULT && Message == NULL)
+ { // try to get the last or default message, depending on current settings
+ COptPage MsgTreeData(g_MsgTreePage);
+ COptItem_TreeCtrl *TreeCtrl = (COptItem_TreeCtrl*)MsgTreeData.Find(IDV_MSGTREE);
+ TreeCtrl->DBToMem(CString(MOD_NAME));
+ Message = NULL;
+ if (g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_USELASTMSG)) // if using last message by default...
+ {
+ Message = DBGetContactSettingString(NULL, MOD_NAME, ProtoStatusToDBSetting(DB_STATUSMSG, IDC_MOREOPTDLG_PERSTATUSPROTOMSGS), (TCHAR*)NULL); // try per-protocol message first
+ if (Message.IsEmpty())
+ {
+ Message = NULL; // to be sure it's NULL, not "" - as we're checking 'Message == NULL' later
+ int RecentGroupID = GetRecentGroupID(Status);
+ if (RecentGroupID != -1)
+ {
+ int I;
+ for (I = 0; I < TreeCtrl->Value.GetSize(); I++) // find first message in the group
+ {
+ if (TreeCtrl->Value[I].ParentID == RecentGroupID && !(TreeCtrl->Value[I].Flags & TIF_GROUP))
+ {
+ Message = TreeCtrl->Value[I].User_Str1;
+ if (pOrder)
+ {
+ *pOrder = I;
+ }
+ break;
+ }
+ }
+ }
+ }
+ } // else, if using default message by default...
+ if (Message == NULL) // ...or we didn't succeed retrieving the last message
+ { // get default message for this status
+ int DefMsgID = -1;
+ static struct {
+ int DBSetting, Status;
+ } DefMsgDlgItems[] = {
+ IDS_MESSAGEDLG_DEF_ONL, ID_STATUS_ONLINE,
+ IDS_MESSAGEDLG_DEF_AWAY, ID_STATUS_AWAY,
+ IDS_MESSAGEDLG_DEF_NA, ID_STATUS_NA,
+ IDS_MESSAGEDLG_DEF_OCC, ID_STATUS_OCCUPIED,
+ IDS_MESSAGEDLG_DEF_DND, ID_STATUS_DND,
+ IDS_MESSAGEDLG_DEF_FFC, ID_STATUS_FREECHAT,
+ IDS_MESSAGEDLG_DEF_INV, ID_STATUS_INVISIBLE,
+ IDS_MESSAGEDLG_DEF_OTP, ID_STATUS_ONTHEPHONE,
+ IDS_MESSAGEDLG_DEF_OTL, ID_STATUS_OUTTOLUNCH
+ };
+ int I;
+ for (I = 0; I < lengthof(DefMsgDlgItems); I++)
+ {
+ if (DefMsgDlgItems[I].Status == Status)
+ {
+ DefMsgID = MsgTreeData.GetDBValue(DefMsgDlgItems[I].DBSetting);
+ break;
+ }
+ }
+ if (DefMsgID == -1)
+ {
+ DefMsgID = MsgTreeData.GetDBValue(IDS_MESSAGEDLG_DEF_AWAY); // use away message for unknown statuses
+ }
+ int Order = TreeCtrl->IDToOrder(DefMsgID); // this will return -1 in any case if something goes wrong
+ if (Order >= 0)
+ {
+ Message = TreeCtrl->Value[Order].User_Str1;
+ }
+ if (pOrder)
+ {
+ *pOrder = Order;
+ }
+ }
+ if (Message == NULL)
+ {
+ Message = _T(""); // last or default message can't be NULL.. otherwise ICQ won't reply to status message requests and won't notify us of status message requests at all
+ }
+ }
+ return Message;
+}
diff --git a/plugins/NewAwaySysMod/Properties.h b/plugins/NewAwaySysMod/Properties.h
new file mode 100644
index 0000000000..6b981bd77e
--- /dev/null
+++ b/plugins/NewAwaySysMod/Properties.h
@@ -0,0 +1,605 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (c) 2005-2007 Chervov Dmitry
+
+ 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
+
+#include "Common.h"
+#include "MsgTree.h"
+#include "ContactList.h"
+#include "statusmodes.h"
+
+#define DB_STATUSMSG "StatusMsg"
+#define DB_ENABLEREPLY "EnableReply"
+#define DB_IGNOREREQUESTS "IgnoreRequests"
+//#define DB_POPUPNOTIFY "UsePopups"
+#define DB_UNK_CONTACT_PREFIX "Unk" // DB_ENABLEREPLY, DB_IGNOREREQUESTS and DB_POPUPNOTIFY settings prefix for not-on-list contacts
+
+class _CWndUserData
+{
+public:
+ _CWndUserData(): MsgTree(NULL), CList(NULL) {}
+
+ CMsgTree *MsgTree;
+ CCList *CList;
+};
+
+
+class CWndUserData
+{
+public:
+ CWndUserData(HWND hWnd): hWnd(hWnd)
+ {
+ _ASSERT(hWnd);
+ dat = (_CWndUserData*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
+ if (!dat)
+ {
+ dat = new _CWndUserData;
+ SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)dat);
+ }
+ }
+
+ ~CWndUserData()
+ {
+ _ASSERT(dat == (_CWndUserData*)GetWindowLongPtr(hWnd, GWLP_USERDATA));
+ if (!dat->MsgTree && !dat->CList) // TODO: Uninitialized Memory Read on closing the options dialog - fix it
+ {
+ SetWindowLongPtr(hWnd, GWLP_USERDATA, NULL);
+ delete dat; // TODO: memory leak - this is never executed - fix it
+ }
+ }
+
+ CMsgTree *GetMsgTree() {return dat->MsgTree;}
+ void SetMsgTree(CMsgTree *MsgTree) {dat->MsgTree = MsgTree;}
+ CCList *GetCList() {return dat->CList;}
+ void SetCList(CCList *CList) {dat->CList = CList;}
+
+private:
+ HWND hWnd;
+ _CWndUserData *dat;
+};
+
+#define IL_SKINICON 0x80000000
+#define IL_PROTOICON 0x40000000
+
+#define ILI_NOICON (-1)
+#define ILI_EVENT_MESSAGE 0
+#define ILI_EVENT_URL 1
+#define ILI_EVENT_FILE 2
+#define ILI_PROTO_ONL 3
+#define ILI_PROTO_AWAY 4
+#define ILI_PROTO_NA 5
+#define ILI_PROTO_OCC 6
+#define ILI_PROTO_DND 7
+#define ILI_PROTO_FFC 8
+#define ILI_PROTO_INV 9
+#define ILI_PROTO_OTP 10
+#define ILI_PROTO_OTL 11
+#define ILI_DOT 12
+#define ILI_MSGICON 13
+#define ILI_IGNORE 14
+#define ILI_SOE_DISABLED 15
+#define ILI_SOE_ENABLED 16
+#define ILI_NEWMESSAGE 17
+#define ILI_NEWCATEGORY 18
+#define ILI_SAVE 19
+#define ILI_SAVEASNEW 20
+#define ILI_DELETE 21
+#define ILI_SETTINGS 22
+#define ILI_STATUS_OTHER 23
+
+static int Icons[] = {
+ SKINICON_EVENT_MESSAGE | IL_SKINICON, SKINICON_EVENT_URL | IL_SKINICON, SKINICON_EVENT_FILE | IL_SKINICON,
+ ID_STATUS_ONLINE | IL_PROTOICON, ID_STATUS_AWAY | IL_PROTOICON, ID_STATUS_NA | IL_PROTOICON, ID_STATUS_OCCUPIED | IL_PROTOICON, ID_STATUS_DND | IL_PROTOICON, ID_STATUS_FREECHAT | IL_PROTOICON, ID_STATUS_INVISIBLE | IL_PROTOICON, ID_STATUS_ONTHEPHONE | IL_PROTOICON, ID_STATUS_OUTTOLUNCH | IL_PROTOICON,
+ IDI_DOT, IDI_MSGICON, IDI_IGNORE, IDI_SOE_ENABLED, IDI_SOE_DISABLED, IDI_NEWMESSAGE, IDI_NEWCATEGORY, IDI_SAVE, IDI_SAVEASNEW, IDI_DELETE, IDI_SETTINGS, IDI_STATUS_OTHER
+};
+
+
+class CIconList
+{
+public:
+ ~CIconList()
+ {
+ int I;
+ for (I = 0; I < IconList.GetSize(); I++)
+ {
+ if (IconList[I])
+ {
+ DestroyIcon(IconList[I]);
+ }
+ }
+ }
+
+ HICON& operator [] (int nIndex) {return IconList[nIndex];}
+ void ReloadIcons()
+ {
+ int cxIcon = GetSystemMetrics(SM_CXSMICON);
+ int cyIcon = GetSystemMetrics(SM_CYSMICON);
+ int I;
+ for (I = 0; I < lengthof(Icons); I++)
+ {
+ if (IconList.GetSize() > I && IconList[I])
+ {
+ DestroyIcon(IconList[I]);
+ }
+ if (Icons[I] & IL_SKINICON)
+ {
+ IconList.SetAtGrow(I) = (HICON)CopyImage(LoadSkinnedIcon(Icons[I] & ~IL_SKINICON), IMAGE_ICON, cxIcon, cyIcon, LR_COPYFROMRESOURCE);
+ } else if (Icons[I] & IL_PROTOICON)
+ {
+ IconList.SetAtGrow(I) = (HICON)CopyImage(LoadSkinnedProtoIcon(NULL, Icons[I] & ~IL_PROTOICON), IMAGE_ICON, cxIcon, cyIcon, LR_COPYFROMRESOURCE);
+ } else
+ {
+ IconList.SetAtGrow(I) = (HICON)LoadImage(g_hInstance, MAKEINTRESOURCE(Icons[I]), IMAGE_ICON, cxIcon, cyIcon, 0);
+ }
+ }
+ }
+
+private:
+ TMyArray<HICON> IconList;
+};
+
+extern CIconList g_IconList;
+
+
+class CProtoStates;
+
+class CProtoState
+{
+public:
+ CProtoState(const char* szProto, CProtoStates* Parent): szProto(szProto), Parent(Parent), Status(szProto, Parent), AwaySince(szProto, Parent) {}
+
+ class CStatus
+ {
+ public:
+ CStatus(const char* szProto, CProtoStates* GrandParent): szProto(szProto), GrandParent(GrandParent), Status(ID_STATUS_OFFLINE) {}
+ CStatus& operator = (int Status);
+ operator int() {return Status;}
+ friend class CProtoState;
+ private:
+ int Status;
+ CString szProto;
+ CProtoStates* GrandParent;
+ } Status;
+
+ class CAwaySince
+ {
+ public:
+ CAwaySince(const char* szProto, CProtoStates* GrandParent): szProto(szProto), GrandParent(GrandParent) {Reset();}
+ void Reset();
+ operator LPSYSTEMTIME() {return &AwaySince;}
+ friend class CProtoState;
+ private:
+ SYSTEMTIME AwaySince;
+ CString szProto;
+ CProtoStates* GrandParent;
+ } AwaySince;
+
+ class CCurStatusMsg
+ {
+ public:
+ CCurStatusMsg() {*this = NULL;}
+ CCurStatusMsg& operator = (TCString Msg)
+ {
+ CurStatusMsg = Msg;
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ SystemTimeToFileTime(&st, (LPFILETIME)&LastUpdateTime); // I'm too lazy to declare FILETIME structure and then copy its data to absolutely equivalent ULARGE_INTEGER structure, so we'll just pass a pointer to the ULARGE_INTEGER directly ;-P
+ return *this;
+ }
+ operator TCString() {return CurStatusMsg;}
+ DWORD GetUpdateTimeDifference()
+ {
+ ULARGE_INTEGER CurTime;
+ SYSTEMTIME st;
+ GetLocalTime(&st);
+ SystemTimeToFileTime(&st, (LPFILETIME)&CurTime);
+ return (DWORD)((CurTime.QuadPart - LastUpdateTime.QuadPart) / 10000); // in milliseconds
+ }
+ private:
+ TCString CurStatusMsg;
+ ULARGE_INTEGER LastUpdateTime;
+ } CurStatusMsg;
+
+ class CTempMsg
+ { // we use temporary messages to keep user-defined per-protocol messages intact, when changing messages through MS_NAS_SETSTATE, or when autoaway becomes active etc.. temporary messages are automatically resetted when protocol status changes
+ public:
+ CTempMsg(): iIsSet(0) {}
+ CTempMsg& operator = (TCString Msg) {this->Msg = Msg; iIsSet = true; return *this;}
+ operator TCString()
+ {
+ _ASSERT(iIsSet);
+ return Msg;
+ }
+ void Unset() {iIsSet = false;}
+ int IsSet() {return iIsSet;}
+
+ private:
+ int iIsSet; // as we need TempMsg to support every possible value, including NULL and "", we'll use this variable to specify whether TempMsg is set
+ TCString Msg;
+ } TempMsg;
+
+ void SetParent(CProtoStates* Parent)
+ {
+ this->Parent = Parent;
+ Status.GrandParent = Parent;
+ AwaySince.GrandParent = Parent;
+ }
+
+ CString &GetProto() {return szProto;}
+
+//NightFox: fix?
+//private:
+public:
+ CString szProto;
+ CProtoStates* Parent;
+};
+
+
+class CProtoStates // this class stores all protocols' dynamic data
+{
+public:
+ CProtoStates() {}
+
+ CProtoStates(const CProtoStates &States) {*this = States;}
+ CProtoStates& operator = (const CProtoStates& States)
+ {
+ ProtoStates = States.ProtoStates;
+ int I;
+ for (I = 0; I < ProtoStates.GetSize(); I++)
+ {
+ ProtoStates[I].SetParent(this);
+ }
+ return *this;
+ }
+
+ CProtoState& operator[](const char *szProto)
+ {
+ int I;
+ for (I = 0; I < ProtoStates.GetSize(); I++)
+ {
+ if (ProtoStates[I].GetProto() == szProto)
+ {
+ return ProtoStates[I];
+ }
+ }
+ if (!szProto) // we need to be sure that we have _all_ protocols in the list, before dealing with global status, so we're adding them here.
+ {
+ int ProtoCount;
+ PROTOCOLDESCRIPTOR **proto;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&ProtoCount, (LPARAM)&proto);
+ int I;
+ for (I = 0; I < ProtoCount; I++)
+ {
+ if (proto[I]->type == PROTOTYPE_PROTOCOL)
+ {
+ (*this)[proto[I]->szName]; // add a protocol if it isn't in the list yet
+ }
+ }
+ }
+ return ProtoStates[ProtoStates.AddElem(CProtoState(szProto, this))];
+ }
+
+ friend class CProtoState;
+ friend class CProtoState::CStatus;
+ friend class CProtoState::CAwaySince;
+
+private:
+ CProtoState& operator[](int nIndex) {return ProtoStates[nIndex];}
+ int GetSize() {return ProtoStates.GetSize();}
+
+ TMyArray<CProtoState> ProtoStates;
+};
+
+extern CProtoStates g_ProtoStates;
+
+
+static struct
+{
+ int Status;
+ char *Setting;
+} StatusSettings[] = {
+ ID_STATUS_OFFLINE, "Off",
+ ID_STATUS_ONLINE, "Onl",
+ ID_STATUS_AWAY, "Away",
+ ID_STATUS_NA, "Na",
+ ID_STATUS_DND, "Dnd",
+ ID_STATUS_OCCUPIED, "Occ",
+ ID_STATUS_FREECHAT, "Ffc",
+ ID_STATUS_INVISIBLE, "Inv",
+ ID_STATUS_ONTHEPHONE, "Otp",
+ ID_STATUS_OUTTOLUNCH, "Otl",
+ ID_STATUS_IDLE, "Idle"
+};
+
+
+class CProtoSettings
+{
+public:
+ CProtoSettings(const char *szProto = NULL, int iStatus = 0): szProto(szProto), Status(iStatus, szProto)
+ {
+ Autoreply.Parent = this;
+ }
+
+ CString ProtoStatusToDBSetting(const char *Prefix, int MoreOpt_PerStatusID = 0)
+ {
+ if (!MoreOpt_PerStatusID || g_MoreOptPage.GetDBValueCopy(MoreOpt_PerStatusID))
+ {
+ int I;
+ for (I = 0; I < lengthof(StatusSettings); I++)
+ {
+ if (Status == StatusSettings[I].Status)
+ {
+ return szProto ? (CString(Prefix) + "_" + szProto + "_" + StatusSettings[I].Setting) : (CString(Prefix) + StatusSettings[I].Setting);
+ }
+ }
+ }
+ return szProto ? (CString(Prefix) + "_" + szProto) : CString(Prefix);
+ }
+
+ class CAutoreply
+ {
+ public:
+ CAutoreply& operator = (const int Value)
+ {
+ CString Setting(Parent->szProto ? Parent->ProtoStatusToDBSetting(DB_ENABLEREPLY, IDC_MOREOPTDLG_PERSTATUSPROTOSETTINGS) : DB_ENABLEREPLY);
+ if (DBGetContactSettingByte(NULL, MOD_NAME, Setting, VAL_USEDEFAULT) == Value)
+ {
+ return *this; // prevent deadlocks when calling UpdateSOEButtons
+ }
+ if (Value != VAL_USEDEFAULT)
+ {
+ DBWriteContactSettingByte(NULL, MOD_NAME, Setting, Value != 0);
+ } else
+ {
+ DBDeleteContactSetting(NULL, MOD_NAME, Setting);
+ }
+ /*if (!Parent->szProto)
+ {
+ UpdateSOEButtons();
+ }*/
+ return *this;
+ }
+ operator int() {return DBGetContactSettingByte(NULL, MOD_NAME, Parent->szProto ? Parent->ProtoStatusToDBSetting(DB_ENABLEREPLY, IDC_MOREOPTDLG_PERSTATUSPROTOSETTINGS) : DB_ENABLEREPLY, Parent->szProto ? VAL_USEDEFAULT : AUTOREPLY_DEF_REPLY);}
+ int IncludingParents() // takes into account global data also, if per-protocol setting is not defined
+ {
+ _ASSERT(Parent->szProto);
+ int Value = *this;
+ return (Value == VAL_USEDEFAULT) ? CProtoSettings(NULL).Autoreply : Value;
+ }
+ friend class CProtoSettings;
+ private:
+ CProtoSettings *Parent;
+ } Autoreply;
+
+ class CStatus
+ {
+ public:
+ CStatus(int iStatus = 0, const char *szProto = NULL): Status(iStatus), szProto(szProto) {}
+ CStatus& operator = (int Status) {this->Status = Status; return *this;}
+ operator int()
+ {
+ if (!Status)
+ {
+ Status = g_ProtoStates[szProto].Status;
+ }
+ return Status;
+ }
+ private:
+ int Status;
+ const char *szProto;
+ } Status;
+
+ void SetMsgFormat(int Flags, TCString Message);
+ TCString GetMsgFormat(int Flags, int *pOrder = NULL);
+
+//NightFox: fix?
+//private:
+public:
+ const char *szProto;
+};
+
+
+__inline CString StatusToDBSetting(int Status, const char *Prefix, int MoreOpt_PerStatusID = 0)
+{
+ if (!MoreOpt_PerStatusID || g_MoreOptPage.GetDBValueCopy(MoreOpt_PerStatusID))
+ {
+ int I;
+ for (I = 0; I < lengthof(StatusSettings); I++)
+ {
+ if (Status == StatusSettings[I].Status)
+ {
+ return CString(Prefix) + StatusSettings[I].Setting;
+ }
+ }
+ }
+ return CString(Prefix);
+}
+
+
+__inline CString ContactStatusToDBSetting(int Status, const char *Prefix, int MoreOpt_PerStatusID, HANDLE hContact)
+{
+ if (hContact == INVALID_HANDLE_VALUE)
+ { // it's a not-on-list contact
+ return CString(DB_UNK_CONTACT_PREFIX) + Prefix;
+ }
+ if (hContact)
+ {
+ StatusToDBSetting(Status, Prefix, MoreOpt_PerStatusID);
+ }
+ return CString(Prefix);
+}
+
+
+class CContactSettings
+{
+public:
+ CContactSettings(int iStatus = 0, HANDLE hContact = NULL): Status(iStatus, hContact), hContact(hContact)
+ {
+ Ignore.Parent = this;
+ Autoreply.Parent = this;
+// PopupNotify.Parent = this;
+ }
+
+ CString ContactStatusToDBSetting(const char *Prefix, int MoreOpt_PerStatusID = 0)
+ {
+ return ::ContactStatusToDBSetting((hContact != INVALID_HANDLE_VALUE) ? Status : NULL, Prefix, MoreOpt_PerStatusID, hContact);
+ }
+
+ class CIgnore
+ {
+ public:
+ CIgnore& operator = (const int Value)
+ {
+ CString Setting(Parent->ContactStatusToDBSetting(DB_IGNOREREQUESTS, IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS));
+ HANDLE hContact = (Parent->hContact != INVALID_HANDLE_VALUE) ? Parent->hContact : NULL;
+ if (Value)
+ {
+ DBWriteContactSettingByte(hContact, MOD_NAME, Setting, 1);
+ } else
+ {
+ DBDeleteContactSetting(hContact, MOD_NAME, Setting);
+ }
+ return *this;
+ }
+ operator int() {return DBGetContactSettingByte((Parent->hContact != INVALID_HANDLE_VALUE) ? Parent->hContact : NULL, MOD_NAME, Parent->ContactStatusToDBSetting(DB_IGNOREREQUESTS, IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS), 0);}
+ friend class CContactSettings;
+ private:
+ CContactSettings *Parent;
+ } Ignore;
+
+ class CAutoreply
+ {
+ public:
+ CAutoreply& operator = (const int Value)
+ {
+ CString Setting(Parent->ContactStatusToDBSetting(DB_ENABLEREPLY, IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS));
+ HANDLE hContact = (Parent->hContact != INVALID_HANDLE_VALUE) ? Parent->hContact : NULL;
+ if (DBGetContactSettingByte(hContact, MOD_NAME, Setting, VAL_USEDEFAULT) == Value)
+ {
+ return *this; // prevent deadlocks when calling UpdateSOEButtons
+ }
+ if (Value != VAL_USEDEFAULT)
+ {
+ DBWriteContactSettingByte(hContact, MOD_NAME, Setting, Value != 0);
+ } else
+ {
+ DBDeleteContactSetting(hContact, MOD_NAME, Setting);
+ }
+ /*if (Parent->hContact != INVALID_HANDLE_VALUE)
+ {
+ UpdateSOEButtons(Parent->hContact);
+ }*/
+ return *this;
+ }
+ operator int() {return DBGetContactSettingByte((Parent->hContact != INVALID_HANDLE_VALUE) ? Parent->hContact : NULL, MOD_NAME, Parent->ContactStatusToDBSetting(DB_ENABLEREPLY, IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS), Parent->hContact ? VAL_USEDEFAULT : AUTOREPLY_DEF_REPLY);}
+ int IncludingParents(const char *szProtoOverride = NULL) // takes into account protocol and global data also, if per-contact setting is not defined
+ {
+ _ASSERT((Parent->hContact && Parent->hContact != INVALID_HANDLE_VALUE) || szProtoOverride); // we need either correct protocol or a correct hContact to determine its protocol
+ int Value = *this;
+ if (Value == VAL_USEDEFAULT)
+ {
+ const char *szProto = (Parent->hContact && Parent->hContact != INVALID_HANDLE_VALUE) ? (const char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)Parent->hContact, 0) : szProtoOverride;
+ return CProtoSettings(szProto).Autoreply.IncludingParents();
+ }
+ return Value;
+ }
+ int GetNextToggleValue()
+ {
+ switch ((int)*this)
+ {
+ case VAL_USEDEFAULT: return 0; break;
+ case 0: return 1; break;
+ default: return Parent->hContact ? VAL_USEDEFAULT : AUTOREPLY_DEF_REPLY; break;
+ }
+ }
+ int Toggle() {return *this = GetNextToggleValue();}
+ friend class CContactSettings;
+ private:
+ CContactSettings *Parent;
+ } Autoreply;
+
+/* class CPopupNotify
+ {
+ public:
+ CPopupNotify& operator = (const int Value)
+ {
+ //CString Setting(Parent->ContactStatusToDBSetting(DB_POPUPNOTIFY, 0)); //IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS
+ HANDLE hContact = (Parent->hContact != INVALID_HANDLE_VALUE) ? Parent->hContact : NULL;
+ if (DBGetContactSettingByte(hContact, MOD_NAME, Setting, VAL_USEDEFAULT) == Value)
+ {
+ return *this; // prevent deadlocks when calling UpdateSOEButtons
+ }
+ if (Value != VAL_USEDEFAULT)
+ {
+ DBWriteContactSettingByte(hContact, MOD_NAME, Setting, Value != 0);
+ } else
+ {
+ DBDeleteContactSetting(hContact, MOD_NAME, Setting);
+ }
+ if (!Parent->hContact)
+ {
+ //UpdateSOEButtons();
+ }
+ return *this;
+ }
+ operator int() {return DBGetContactSettingByte((Parent->hContact != INVALID_HANDLE_VALUE) ? Parent->hContact : NULL, MOD_NAME, Parent->ContactStatusToDBSetting(DB_POPUPNOTIFY, 0), Parent->hContact ? VAL_USEDEFAULT : POPUP_DEF_USEPOPUPS);} //IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS
+ int IncludingParents() // takes into account protocol and global data also, if per-contact setting is not defined
+ {
+ int Value = *this;
+ if (Value == VAL_USEDEFAULT)
+ { // PopupNotify setting is not per-status
+ return CContactSettings(ID_STATUS_ONLINE).PopupNotify;
+ }
+ return Value;
+ }
+ friend class CContactSettings;
+ private:
+ CContactSettings *Parent;
+ } PopupNotify;
+*/
+ class CStatus
+ {
+ public:
+ CStatus(int iStatus = 0, HANDLE hContact = NULL): Status(iStatus), hContact(hContact) {}
+ CStatus& operator = (int Status) {this->Status = Status; return *this;}
+ operator int()
+ {
+ if (!Status)
+ {
+ _ASSERT(hContact != INVALID_HANDLE_VALUE);
+ char *szProto = hContact ? (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0) : NULL;
+ Status = (szProto || !hContact) ? g_ProtoStates[szProto].Status : ID_STATUS_AWAY;
+ }
+ return Status;
+ }
+ friend class CPopupNotify;
+ friend class CAutoreply;
+ private:
+ int Status;
+ HANDLE hContact;
+ } Status;
+
+ void SetMsgFormat(int Flags, TCString Message);
+ TCString GetMsgFormat(int Flags, int *pOrder = NULL, char *szProtoOverride = NULL);
+
+//NightFox: fix?
+//private:
+public:
+ HANDLE hContact;
+};
diff --git a/plugins/NewAwaySysMod/ReadAwayMsg.cpp b/plugins/NewAwaySysMod/ReadAwayMsg.cpp
new file mode 100644
index 0000000000..c5524911c1
--- /dev/null
+++ b/plugins/NewAwaySysMod/ReadAwayMsg.cpp
@@ -0,0 +1,161 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (C) 2005-2007 Chervov Dmitry
+ Copyright (C) 2004-2005 Iksaif Entertainment
+ Copyright (C) 2002-2003 Goblineye Entertainment
+
+ 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 "Common.h"
+
+#define RAMDLGSIZESETTING "ReadAwayMsgDlg"
+
+HANDLE g_hReadWndList = NULL;
+
+
+static int ReadAwayMsgDlgResize(HWND hwndDlg, LPARAM lParam, UTILRESIZECONTROL *urc)
+{
+ switch (urc->wId)
+ {
+ case IDC_READAWAYMSG_MSG:
+ {
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
+ }
+ case IDC_READAWAYMSG_RETRIEVE:
+ {
+ return RD_ANCHORX_CENTRE | RD_ANCHORY_CENTRE;
+ }
+ case IDOK:
+ {
+ return RD_ANCHORX_CENTRE | RD_ANCHORY_BOTTOM;
+ }
+ }
+ return RD_ANCHORX_LEFT | RD_ANCHORY_TOP;
+}
+
+
+static INT_PTR CALLBACK ReadAwayMsgDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ TranslateDialogDefault(hwndDlg);
+ HICON hTitleIcon = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hTitleIcon);
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)hTitleIcon);
+ Utils_RestoreWindowPosition(hwndDlg, NULL, MOD_NAME, RAMDLGSIZESETTING);
+ READAWAYMSGDATA *awayData = new READAWAYMSGDATA;
+ SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)awayData);
+ awayData->hContact = (HANDLE)lParam;
+ awayData->hAwayMsgEvent = HookEventMessage(ME_PROTO_ACK, hwndDlg, UM_RAM_AWAYMSGACK);
+ awayData->hSeq = (HANDLE)CallContactService(awayData->hContact, PSS_GETAWAYMSG, 0, 0);
+ WindowList_Add(g_hReadWndList, hwndDlg, awayData->hContact);
+
+ TCHAR str[256], format[128];
+ TCHAR *status, *contactName;
+ contactName = (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)awayData->hContact, GCDNF_TCHAR);
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)awayData->hContact, 0);
+ status = (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, DBGetContactSettingWord(awayData->hContact, szProto, "Status", ID_STATUS_OFFLINE), GCMDF_TCHAR);
+ GetWindowText(hwndDlg, format, lengthof(format));
+ _sntprintf(str, lengthof(str), format, status, contactName);
+ SetWindowText(hwndDlg, str);
+ GetDlgItemText(hwndDlg, IDC_READAWAYMSG_RETRIEVE, format, sizeof(format));
+ _sntprintf(str, lengthof(str), format, status);
+ SetDlgItemText(hwndDlg, IDC_READAWAYMSG_RETRIEVE, str);
+ return true;
+ } break;
+ case UM_RAM_AWAYMSGACK: // got away msg
+ {
+ ACKDATA *ack = (ACKDATA*)lParam;
+ READAWAYMSGDATA *awayData = (READAWAYMSGDATA*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ // make sure everything is ok, and this is our ack
+ if (ack->hContact != awayData->hContact || ack->type != ACKTYPE_AWAYMSG || ack->hProcess != awayData->hSeq || ack->result != ACKRESULT_SUCCESS)
+ {
+ break;
+ }
+ // done with the event
+ if (awayData->hAwayMsgEvent)
+ {
+ UnhookEvent(awayData->hAwayMsgEvent);
+ awayData->hAwayMsgEvent = NULL;
+ }
+ SetDlgItemTextA(hwndDlg, IDC_READAWAYMSG_MSG, (const char*)ack->lParam);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_READAWAYMSG_RETRIEVE), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_READAWAYMSG_MSG), SW_SHOW);
+ SetDlgItemText(hwndDlg, IDOK, TranslateT("&Close"));
+ DBWriteContactSettingString(awayData->hContact, "CList", "StatusMsg", (const char*)ack->lParam);
+ } break;
+ case WM_COMMAND:
+ {
+ switch (HIWORD(wParam))
+ {
+ case BN_CLICKED:
+ {
+ switch(LOWORD(wParam))
+ {
+ case IDCANCEL:
+ case IDOK:
+ {
+ DestroyWindow(hwndDlg);
+ } break;
+ }
+ } break;
+ }
+ } break;
+ case WM_SIZE:
+ {
+ UTILRESIZEDIALOG urd = {0};
+ urd.cbSize = sizeof(urd);
+ urd.hInstance = g_hInstance;
+ urd.hwndDlg = hwndDlg;
+ urd.lpTemplate = MAKEINTRESOURCEA(IDD_READAWAYMSG);
+ urd.pfnResizer = ReadAwayMsgDlgResize;
+ CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd);
+ break;
+ }
+ case WM_CLOSE:
+ {
+ DestroyWindow(hwndDlg);
+ } break;
+ case WM_DESTROY:
+ {
+ READAWAYMSGDATA *awayData = (READAWAYMSGDATA*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
+ if (awayData->hAwayMsgEvent)
+ {
+ UnhookEvent(awayData->hAwayMsgEvent);
+ awayData->hAwayMsgEvent = NULL;
+ }
+ delete awayData;
+ Utils_SaveWindowPosition(hwndDlg, NULL, MOD_NAME, RAMDLGSIZESETTING);
+ WindowList_Remove(g_hReadWndList, hwndDlg);
+ } break;
+ }
+ return false;
+}
+
+
+int GetContactStatMsg(WPARAM wParam, LPARAM lParam)
+{
+ if (HWND hWnd = WindowList_Find(g_hReadWndList, (HANDLE)wParam)) // already have it
+ {
+ SetForegroundWindow(hWnd);
+ } else
+ {
+ CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_READAWAYMSG), NULL, ReadAwayMsgDlgProc, wParam);
+ }
+ return 0;
+}
diff --git a/plugins/NewAwaySysMod/Services.cpp b/plugins/NewAwaySysMod/Services.cpp
new file mode 100644
index 0000000000..74cb52be8e
--- /dev/null
+++ b/plugins/NewAwaySysMod/Services.cpp
@@ -0,0 +1,254 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (c) 2005-2007 Chervov Dmitry
+
+ 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 "Common.h"
+#include "Properties.h"
+#include "..\CommonLibs\m_NewAwaySys.h"
+
+
+typedef struct {
+ int cbSize;
+ char *szProto;
+ union
+ {
+ char *szMsg;
+ WCHAR *wszMsg;
+ TCHAR *tszMsg;
+ };
+ WORD status;
+} NAS_PROTOINFOv1;
+
+
+__inline void PSSetStatus(char *szProto, WORD Status, int bNoClistSetStatusMode = false) // just a helper function that sets the status and handles szProto==NULL correctly
+{
+ g_ProtoStates[szProto].Status = Status;
+ if (szProto)
+ {
+ CallProtoService(szProto, PS_SETSTATUS, Status, 0);
+ } else if (!bNoClistSetStatusMode) // global status
+ {
+/* int ProtoCount;
+ PROTOCOLDESCRIPTOR **proto;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&ProtoCount, (LPARAM)&proto);
+ int I;
+ for (I = 0; I < ProtoCount; I++)
+ {
+ if (proto[I]->type == PROTOTYPE_PROTOCOL)
+ {
+ CallProtoService(proto[I]->szName, PS_SETSTATUS, Status, 0);
+ }
+ }*/
+ g_fNoProcessing = true;
+ CallService(MS_CLIST_SETSTATUSMODE, Status, 0);
+ _ASSERT(!g_fNoProcessing && g_ProtoStates[(char*)NULL].Status == Status);
+ g_fNoProcessing = false;
+ }
+}
+
+
+int GetStatusMsg(WPARAM wParam, LPARAM lParam) // called by GamerStatus and built-in miranda autoaway module
+// wParam = (int)status, lParam = 0
+// MS_AWAYMSG_GETSTATUSMSG "SRAway/GetStatusMessage"
+{
+ LogMessage("MS_AWAYMSG_GETSTATUSMSG called. status=%d", wParam);
+ struct MM_INTERFACE mm;
+ mm.cbSize = sizeof(mm);
+ CallService(MS_SYSTEM_GET_MMI, 0, (LPARAM)&mm);
+ CString Msg(TCHAR2ANSI(GetDynamicStatMsg(INVALID_HANDLE_VALUE, NULL, 0, wParam)));
+ char *szMsg;
+ if (Msg == NULL)
+ { // it's ok to return NULL, so we'll do it
+ szMsg = NULL;
+ } else
+ {
+ szMsg = (char*)mm.mmi_malloc(Msg.GetLen() + 1);
+ lstrcpyA(szMsg, Msg);
+ }
+ LogMessage("returned szMsg:\n%s", szMsg ? szMsg : "NULL");
+ return (int)szMsg;
+}
+
+
+int SetStatusMode(WPARAM wParam, LPARAM lParam) // called by GamerStatus and StatCtrl
+{
+// wParam = int iMode
+// lParam = char* szMsg, may be null - then we need to use the default message
+/* if (CallService(MS_CLIST_GETSTATUSMODE, 0, 0) != wParam) // not same status
+ {*/ // try this way; global status may be not the same as current status of some separate protocol
+ LogMessage("MS_AWAYSYS_SETSTATUSMODE called. status=%d, szMsg:\n%s", wParam, lParam ? (char*)lParam : "NULL");
+ g_fNoProcessing = true;
+ CallService(MS_CLIST_SETSTATUSMODE, wParam, 0);
+// }
+ _ASSERT(!g_fNoProcessing && g_ProtoStates[(char*)NULL].Status == wParam);
+ g_fNoProcessing = false;
+ CProtoSettings(NULL, wParam).SetMsgFormat(SMF_TEMPORARY, lParam ? ANSI2TCHAR((char*)lParam) : CProtoSettings(NULL, wParam).GetMsgFormat(GMF_LASTORDEFAULT));
+ ChangeProtoMessages(NULL, wParam, TCString());
+ return 0;
+}
+
+
+int GetState(WPARAM wParam, LPARAM lParam, int Widechar)
+// wParam = (WPARAM)(NAS_PROTOINFO*)pi - pointer to an array of NAS_PROTOINFO items to be filled.
+// lParam = (LPARAM)(int)protoCount - number of items in pi.
+// returns 0 on success
+{
+ NAS_PROTOINFO *pi = (NAS_PROTOINFO*)wParam;
+ LogMessage("MS_NAS_GETSTATE called with %d items and Widechar=%d:", lParam, Widechar);
+ struct MM_INTERFACE mm;
+ mm.cbSize = sizeof(mm);
+ CallService(MS_SYSTEM_GET_MMI, 0, (LPARAM)&mm);
+ int I;
+ for (I = 0; I < lParam; I++)
+ {
+ if (pi->cbSize < sizeof(NAS_PROTOINFO) && pi->cbSize != sizeof(NAS_PROTOINFOv1))
+ {
+ return 1;
+ }
+ int Flags = (pi->cbSize > sizeof(NAS_PROTOINFOv1)) ? pi->Flags : 0;
+ LogMessage("%d (received): cbSize=%d, status=%d, szProto=%s, Flags=0x%x", I + 1, pi->cbSize, pi->status, pi->szProto ? pi->szProto : "NULL", Flags);
+ if ((pi->status >= ID_STATUS_ONLINE && pi->status <= ID_STATUS_OUTTOLUNCH) || !pi->status)
+ {
+ TCString Msg(pi->status ? CProtoSettings(pi->szProto, pi->status).GetMsgFormat(GMF_LASTORDEFAULT) : CProtoSettings(pi->szProto).GetMsgFormat(((Flags & PIF_NOTTEMPORARY) ? 0 : GMF_TEMPORARY) | GMF_PERSONAL));
+ if (Msg != NULL)
+ {
+ pi->szMsg = (char*)mm.mmi_malloc(Msg.GetLen() + 1);
+ _ASSERT(pi->szMsg);
+ if (Widechar)
+ {
+ lstrcpyW(pi->wszMsg, TCHAR2WCHAR(Msg));
+ } else
+ {
+ lstrcpyA(pi->szMsg, TCHAR2ANSI(Msg));
+ }
+ } else
+ {
+ pi->szMsg = NULL;
+ }
+ if (!pi->status)
+ {
+ pi->status = g_ProtoStates[pi->szProto].Status;
+ }
+ } else
+ {
+ pi->szMsg = NULL;
+ }
+ LogMessage("%d (returned): status=%d, Flags=0x%x, szMsg:\n%s", I + 1, pi->status, (pi->cbSize > sizeof(NAS_PROTOINFOv1)) ? pi->Flags : 0, pi->szMsg ? (Widechar ? WCHAR2ANSI(pi->wszMsg) : pi->szMsg) : "NULL");
+ *(char**)&pi += pi->cbSize;
+ }
+ return 0;
+}
+
+
+int GetStateA(WPARAM wParam, LPARAM lParam)
+{
+ return GetState(wParam, lParam, false);
+}
+
+
+int GetStateW(WPARAM wParam, LPARAM lParam)
+{
+ return GetState(wParam, lParam, true);
+}
+
+
+int SetState(WPARAM wParam, LPARAM lParam, int Widechar)
+// wParam = (WPARAM)(NAS_PROTOINFO*)pi - pointer to an array of NAS_PROTOINFO items.
+// lParam = (LPARAM)(int)protoCount - number of items in pi.
+// returns 0 on success
+{
+ NAS_PROTOINFO *pi = (NAS_PROTOINFO*)wParam;
+ LogMessage("MS_NAS_SETSTATE called with %d items and Widechar=%d:", lParam, Widechar);
+ struct MM_INTERFACE mm;
+ mm.cbSize = sizeof(mm);
+ CallService(MS_SYSTEM_GET_MMI, 0, (LPARAM)&mm);
+ int I;
+ for (I = 0; I < lParam; I++)
+ {
+ _ASSERT(pi->szMsg != (char*)(-1));
+ if (pi->cbSize < sizeof(NAS_PROTOINFO) && pi->cbSize != sizeof(NAS_PROTOINFOv1))
+ {
+ return 1;
+ }
+ int Flags = (pi->cbSize > sizeof(NAS_PROTOINFOv1)) ? pi->Flags : 0;
+ LogMessage("%d: cbSize=%d, status=%d, szProto=%s, Flags=0x%x, szMsg:\n%s", I + 1, pi->cbSize, pi->status, pi->szProto ? pi->szProto : "NULL", Flags, pi->szMsg ? (Widechar ? WCHAR2ANSI(pi->wszMsg) : pi->szMsg) : "NULL");
+ if (pi->status)
+ {
+ PSSetStatus(pi->szProto, pi->status, Flags & PIF_NO_CLIST_SETSTATUSMODE);
+ } else
+ {
+ pi->status = g_ProtoStates[pi->szProto].Status;
+ }
+ CProtoSettings(pi->szProto).SetMsgFormat((Flags & PIF_NOTTEMPORARY) ? SMF_PERSONAL : SMF_TEMPORARY, Widechar ? WCHAR2TCHAR(pi->wszMsg) : ANSI2TCHAR(pi->szMsg));
+ if (pi->szMsg || !(Flags & PIF_NO_CLIST_SETSTATUSMODE))
+ {
+ ChangeProtoMessages(pi->szProto, pi->status, TCString());
+ }
+ mm.mmi_free(pi->szMsg);
+ pi->szMsg = (char*)(-1);
+ *(char**)&pi += pi->cbSize;
+ }
+ return 0;
+}
+
+
+int SetStateA(WPARAM wParam, LPARAM lParam)
+{
+ return SetState(wParam, lParam, false);
+}
+
+
+int SetStateW(WPARAM wParam, LPARAM lParam)
+{
+ return SetState(wParam, lParam, true);
+}
+
+
+int InvokeStatusWindow(WPARAM wParam, LPARAM lParam)
+// wParam = (WPARAM)(NAS_ISWINFO*)iswi - pointer to a NAS_ISWINFO structure.
+// lParam = 0
+// returns HWND of the window on success, or NULL on failure.
+{
+ NAS_ISWINFO *iswi = (NAS_ISWINFO*)wParam;
+ if (iswi->cbSize != sizeof(NAS_ISWINFOv1) && iswi->cbSize < sizeof(NAS_ISWINFO))
+ {
+ return NULL;
+ }
+ LogMessage("MS_NAS_INVOKESTATUSWINDOW called. cbSize=%d, status=%d, szProto=%s, hContact=0x%08x, Flags=0x%x, szMsg:\n%s", iswi->cbSize, iswi->status, iswi->szProto ? iswi->szProto : "NULL", iswi->hContact, (iswi->cbSize < sizeof(NAS_ISWINFO)) ? 0 : iswi->Flags, iswi->szMsg ? ((iswi->Flags & ISWF_UNICODE) ? WCHAR2ANSI(iswi->wszMsg) : iswi->szMsg) : "NULL");
+ if (iswi->status)
+ {
+ PSSetStatus(iswi->szProto, iswi->status);
+ }
+ if (g_SetAwayMsgPage.GetWnd()) // already setting something
+ {
+ SetForegroundWindow(g_SetAwayMsgPage.GetWnd());
+ return (int)g_SetAwayMsgPage.GetWnd();
+ }
+ SetAwayMsgData *dat = new SetAwayMsgData;
+ ZeroMemory(dat, sizeof(SetAwayMsgData));
+ dat->hInitContact = iswi->hContact;
+ dat->szProtocol = iswi->szProto;
+ dat->Message = (iswi->Flags & ISWF_UNICODE) ? WCHAR2TCHAR(iswi->wszMsg) : ANSI2TCHAR(iswi->szMsg);
+ dat->IsModeless = true;
+ if (iswi->cbSize > sizeof(NAS_ISWINFOv1))
+ {
+ dat->ISW_Flags = iswi->Flags;
+ }
+ return (int)CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_SETAWAYMSG), NULL, SetAwayMsgDlgProc, (LPARAM)dat);
+}
diff --git a/plugins/NewAwaySysMod/Services.h b/plugins/NewAwaySysMod/Services.h
new file mode 100644
index 0000000000..27eabf6945
--- /dev/null
+++ b/plugins/NewAwaySysMod/Services.h
@@ -0,0 +1,27 @@
+/*
+ New Away System - plugin for Miranda IM
+ Copyright (c) 2005-2007 Chervov Dmitry
+
+ 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
+*/
+
+int GetStatusMsg(WPARAM wParam, LPARAM lParam);
+int SetStatusMode(WPARAM wParam, LPARAM lParam);
+// int IgnoreNextStatusChange(WPARAM wParam, LPARAM lParam);
+int GetStateA(WPARAM wParam, LPARAM lParam);
+int SetStateA(WPARAM wParam, LPARAM lParam);
+int GetStateW(WPARAM wParam, LPARAM lParam);
+int SetStateW(WPARAM wParam, LPARAM lParam);
+int InvokeStatusWindow(WPARAM wParam, LPARAM lParam);
diff --git a/plugins/NewAwaySysMod/SetAwayMsg.cpp b/plugins/NewAwaySysMod/SetAwayMsg.cpp
new file mode 100644
index 0000000000..2a6d17a86f
--- /dev/null
+++ b/plugins/NewAwaySysMod/SetAwayMsg.cpp
@@ -0,0 +1,1706 @@
+/*
+ New Away System plugin for Miranda IM
+ Copyright (c) 2005-2007 Chervov Dmitry
+ Copyright (c) 2004-2005 Iksaif Entertainment
+ Copyright (c) 2002-2003 Goblineye Entertainment
+
+ 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 "Common.h"
+#include "m_button.h"
+#include "m_icolib.h"
+#include "ContactList.h"
+#include "MsgTree.h"
+#include "Properties.h"
+#include "..\CommonLibs\m_NewAwaySys.h"
+
+#define EXTRAIMGLIST_DOT 0
+#define EXTRAIMGLIST_IGNORE 1
+#define EXTRAIMGLIST_MSG 2
+#define EXTRAIMGLIST_AUTOREPLY_ON 3
+#define EXTRAIMGLIST_AUTOREPLY_OFF 4
+
+#define EXTRACOLUMN_IGNORE 0
+#define EXTRACOLUMN_REPLY 1
+
+#define MINSPLITTERPOS 176
+#define MINYDLGSIZE 100
+
+#define SAM_TIMER_ID 1
+
+#define UM_SAM_INITCLIST (WM_USER + 100)
+
+#define CLSEL_DAT_CONTACT ((PTREEITEMARRAY)(-1)) // these constants are used to specify selection when the contact list is not loaded
+#define CLSEL_DAT_NOTHING ((PTREEITEMARRAY)(-2))
+
+static WNDPROC g_OrigEditMsgProc;
+static WNDPROC g_OrigSplitterProc;
+static WNDPROC g_OrigCListProc;
+static int g_VariablesButtonDX;
+static int g_MsgSplitterX, g_ContactSplitterX;
+static int MinMsgSplitterX, MinContactSplitterX;
+static int MinMsgEditSize; // used to calculate minimal X size of the dialog
+
+
+
+static LRESULT CALLBACK MsgEditSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (Msg)
+ {
+ case WM_CHAR:
+ {
+ if (GetKeyState(VK_CONTROL) & 0x8000)
+ {
+ if (wParam == '\n')
+ { // ctrl-enter
+ PostMessage(GetParent(hWnd), WM_COMMAND, IDC_OK, 0);
+ return 0;
+ }
+ if (wParam == 1)
+ { // ctrl-a
+ SendMessage(hWnd, EM_SETSEL, 0, -1);
+ return 0;
+ }
+ if (wParam == 23)
+ { // ctrl-w
+ SendMessage(GetParent(hWnd), WM_CLOSE, 0, 0);
+ return 0;
+ }
+ if (wParam == 127)
+ { // ctrl-backspace
+ DWORD start, end;
+ SendMessage(hWnd, EM_GETSEL, (WPARAM)&end, NULL);
+ SendMessage(hWnd, WM_KEYDOWN, VK_LEFT, 0);
+ SendMessage(hWnd, EM_GETSEL, (WPARAM)&start, NULL);
+ int nLen = GetWindowTextLength(hWnd);
+ TCHAR *text = (TCHAR*)malloc((nLen + 1) * sizeof(TCHAR));
+ GetWindowText(hWnd, text, nLen + 1);
+ MoveMemory(text + start, text + end, sizeof(TCHAR) * (_tcslen(text) + 1 - end));
+ SetWindowText(hWnd, text);
+ free(text);
+ SendMessage(hWnd, EM_SETSEL, start, start);
+ SendMessage(GetParent(hWnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hWnd), EN_CHANGE), (LPARAM)hWnd);
+ return 0;
+ }
+ }
+ } break;
+ case WM_KEYDOWN:
+ {
+ SendMessage(GetParent(hWnd), UM_SAM_KILLTIMER, 0, 0);
+ } break;
+ }
+ return CallWindowProc(g_OrigEditMsgProc, hWnd, Msg, wParam, lParam);
+}
+
+// used splitter code from TabSRMM as a base
+static LRESULT CALLBACK SplitterSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (Msg)
+ {
+ case WM_NCHITTEST:
+ {
+ return HTCLIENT;
+ }
+ case WM_SETCURSOR:
+ {
+ SetCursor(LoadCursor(NULL, IDC_SIZEWE));
+ return true;
+ }
+ case WM_LBUTTONDOWN:
+ {
+ SetCapture(hWnd);
+ return false;
+ }
+ case WM_MOUSEMOVE:
+ {
+ if (GetCapture() == hWnd)
+ {
+ RECT rc;
+ GetClientRect(hWnd, &rc);
+ SendMessage(GetParent(hWnd), UM_SAM_SPLITTERMOVED, (short)LOWORD(GetMessagePos()) + rc.right / 2, (LPARAM)GetDlgCtrlID(hWnd));
+ }
+ return 0;
+ }
+ case WM_LBUTTONUP:
+ {
+ ReleaseCapture();
+ return false;
+ }
+ }
+ return CallWindowProc(g_OrigSplitterProc, hWnd, Msg, wParam, lParam);
+}
+
+static LRESULT CALLBACK CListSubclassProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+ CCList *dat = CWndUserData(GetParent(hWnd)).GetCList();
+ switch (Msg)
+ {
+ case WM_MOUSEMOVE:
+ {
+ DWORD hitFlags;
+ POINT pt = {(short)LOWORD(lParam), (short)HIWORD(lParam)};
+ if (dat->HitTest(&pt, &hitFlags) && hitFlags & MCLCHT_ONITEMEXTRA)
+ {
+ lParam = 0; // reset mouse coordinates, so TreeView's wndproc will not draw any item in a hovered state
+ }
+ } break;
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONDBLCLK:
+ {
+ DWORD hitFlags;
+ POINT pt = {(short)LOWORD(lParam), (short)HIWORD(lParam)};
+ if (dat->HitTest(&pt, &hitFlags) && hitFlags & MCLCHT_ONITEMEXTRA)
+ {
+ SetFocus(hWnd);
+ NMHDR nmhdr;
+ nmhdr.code = NM_CLICK;
+ nmhdr.hwndFrom = hWnd;
+ nmhdr.idFrom = GetDlgCtrlID(hWnd);
+ SendMessage(GetParent(hWnd), WM_NOTIFY, 0, (LPARAM)&nmhdr);
+ return DefWindowProc(hWnd, Msg, wParam, lParam);
+ }
+ } break;
+ }
+ return CallWindowProc(g_OrigCListProc, hWnd, Msg, wParam, lParam);
+}
+
+
+static int SetAwayMsgDlgResize(HWND hwndDlg, LPARAM lParam, UTILRESIZECONTROL *urc)
+{
+ COptPage *SetAwayMsgPage = (COptPage*)lParam;
+ int bShowMsgTree = SetAwayMsgPage->GetValue(IDS_SAWAYMSG_SHOWMSGTREE);
+ int bShowContactTree = SetAwayMsgPage->GetValue(IDS_SAWAYMSG_SHOWCONTACTTREE);
+ switch (urc->wId)
+ {
+ case IDC_SAWAYMSG_MSGDATA:
+ {
+ urc->rcItem.right = urc->dlgOriginalSize.cx - 2;
+ if (bShowContactTree)
+ {
+ urc->rcItem.right -= g_ContactSplitterX;
+ }
+ urc->rcItem.left = (bShowMsgTree) ? (g_MsgSplitterX + 2) : 2;
+ return RD_ANCHORX_WIDTH | RD_ANCHORY_HEIGHT;
+ }
+ case IDC_SAWAYMSG_TREE:
+ {
+ urc->rcItem.right = g_MsgSplitterX - 2;
+ return RD_ANCHORX_LEFT | RD_ANCHORY_HEIGHT;
+ }
+ case IDC_SAWAYMSG_CONTACTSTREE:
+ {
+ urc->rcItem.left = urc->dlgOriginalSize.cx - g_ContactSplitterX + 2;
+ return RD_ANCHORX_RIGHT | RD_ANCHORY_HEIGHT;
+ }
+ case IDC_OK:
+ {
+ int X = bShowMsgTree ? min(max(g_MsgSplitterX, MinMsgSplitterX), urc->dlgNewSize.cx - ((bShowContactTree ? MinContactSplitterX : 0) + MinMsgEditSize)) : 0;
+ OffsetRect(&urc->rcItem, X + 2 - urc->rcItem.left, 0);
+ return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM;
+ }
+ case IDC_SAWAYMSG_EDITMSGS:
+ case IDC_SAWAYMSG_SAVEMSG:
+ case IDC_SAWAYMSG_SAVEASNEW:
+ case IDC_SAWAYMSG_NEWCATEGORY:
+ case IDC_SAWAYMSG_DELETE:
+ {
+ return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM;
+ }
+ case IDC_SAWAYMSG_VARS:
+ case IDC_SAWAYMSG_OPTIONS:
+ {
+ int X = bShowContactTree ? max(min(g_ContactSplitterX, urc->dlgNewSize.cx - (bShowMsgTree ? max(g_MsgSplitterX, MinMsgSplitterX) : 0) - MinMsgEditSize), MinContactSplitterX) : 0;
+ OffsetRect(&urc->rcItem, urc->dlgOriginalSize.cx - X - 2 - urc->rcItem.right - ((urc->wId == IDC_SAWAYMSG_VARS) ? g_VariablesButtonDX : 0), 0);
+ return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM;
+ }
+ case IDC_SAWAYMSG_STATIC_IGNOREICON:
+ case IDC_SAWAYMSG_STATIC_REPLYICON:
+ {
+ urc->rcItem.left = urc->rcItem.right - 16;
+ urc->rcItem.top = urc->rcItem.bottom - 16;
+ } // go through
+ case IDC_SAWAYMSG_IGNOREREQ:
+ case IDC_SAWAYMSG_SENDMSG:
+ {
+ return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM;
+ }
+ case IDC_SAWAYMSG_MSGSPLITTER:
+ {
+ OffsetRect(&urc->rcItem, g_MsgSplitterX - (urc->rcItem.left + ++urc->rcItem.right) / 2, 0);
+ return RD_ANCHORX_LEFT | RD_ANCHORY_HEIGHT;
+ }
+ case IDC_SAWAYMSG_CONTACTSPLITTER:
+ {
+ OffsetRect(&urc->rcItem, urc->dlgOriginalSize.cx - g_ContactSplitterX - (urc->rcItem.left + urc->rcItem.right) / 2, 0);
+ return RD_ANCHORX_RIGHT | RD_ANCHORY_HEIGHT;
+ }
+ }
+
+
+ return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM;
+}
+
+
+__inline int DBValueToReplyIcon(int Value)
+{
+ switch (Value)
+ {
+ case VAL_USEDEFAULT: return EXTRAIMGLIST_DOT;
+ case 0: return EXTRAIMGLIST_AUTOREPLY_OFF;
+ default: return EXTRAIMGLIST_AUTOREPLY_ON;
+ }
+}
+
+
+int GetRealReplyIcon(CCList *CList, HTREEITEM hItem)
+{
+ _ASSERT(CList);
+ HANDLE hContact = CList->GethContact(hItem);
+ int ItemType = CList->GetItemType(hItem);
+ char *szProto = (char*)CList->GetItemParam(hItem);
+ return (ItemType == MCLCIT_GROUP) ? CList->GetItemParam(hItem) : DBValueToReplyIcon((ItemType == MCLCIT_CONTACT) ? (int)CContactSettings(0, hContact).Autoreply : CProtoSettings(szProto).Autoreply);
+}
+
+
+void SetExtraIcon(CCList *CList, int nColumn, HTREEITEM hItem, int nIcon)
+{
+ _ASSERT(CList);
+ int ItemType = CList->GetItemType(hItem);
+ HANDLE hContact = CList->GethContact(hItem);
+ if (ItemType == MCLCIT_CONTACT)
+ {
+ if (nIcon == -1) // means we need to retrieve it from the db by ourselves
+ {
+ if (nColumn == EXTRACOLUMN_IGNORE)
+ {
+ nIcon = CContactSettings(0, hContact).Ignore ? EXTRAIMGLIST_IGNORE : EXTRAIMGLIST_DOT;
+ } else
+ {
+ _ASSERT(nColumn == EXTRACOLUMN_REPLY);
+ nIcon = DBValueToReplyIcon(CContactSettings(0, hContact).Autoreply);
+ }
+ } else // save it back to the db
+ {
+ if (nColumn == EXTRACOLUMN_IGNORE)
+ {
+ CContactSettings(0, hContact).Ignore = nIcon == EXTRAIMGLIST_IGNORE;
+ } else
+ {
+ _ASSERT(nColumn == EXTRACOLUMN_REPLY);
+ CContactSettings(0, hContact).Autoreply = (nIcon == EXTRAIMGLIST_DOT) ? VAL_USEDEFAULT : (nIcon == EXTRAIMGLIST_AUTOREPLY_ON);
+ }
+ }
+ if (nColumn == EXTRACOLUMN_IGNORE && nIcon != EXTRAIMGLIST_IGNORE)
+ {
+ nIcon = (CContactSettings(0, hContact).GetMsgFormat(GMF_PERSONAL) == NULL) ? EXTRAIMGLIST_DOT : EXTRAIMGLIST_MSG;
+ }
+ } else if (ItemType == MCLCIT_INFO)
+ {
+ char *szProto = (char*)CList->GetItemParam(hItem);
+ if (nColumn == EXTRACOLUMN_REPLY)
+ {
+ if (nIcon == -1)
+ {
+ nIcon = DBValueToReplyIcon(CProtoSettings(szProto).Autoreply);
+ } else
+ {
+ CProtoSettings(szProto).Autoreply = (nIcon == EXTRAIMGLIST_DOT) ? VAL_USEDEFAULT : (nIcon == EXTRAIMGLIST_AUTOREPLY_ON);
+ }
+ if (!szProto && nIcon == EXTRAIMGLIST_DOT)
+ {
+ nIcon = EXTRAIMGLIST_AUTOREPLY_OFF;
+ }
+ } else
+ {
+ nIcon = (CProtoSettings(szProto).GetMsgFormat(GMF_TEMPORARY | GMF_PERSONAL) == NULL) ? EXTRAIMGLIST_DOT : EXTRAIMGLIST_MSG;
+ }
+ }
+ int Ignore = (nColumn == EXTRACOLUMN_IGNORE) ? (nIcon == EXTRAIMGLIST_IGNORE) : ((ItemType == MCLCIT_CONTACT) ? CContactSettings(0, hContact).Ignore : ((ItemType == MCLCIT_GROUP) ? CList->GetExtraImage(hItem, EXTRACOLUMN_IGNORE) : false));
+ if (Ignore)
+ {
+ if (nColumn == EXTRACOLUMN_IGNORE)
+ {
+ CList->SetExtraImage(hItem, EXTRACOLUMN_REPLY, CLC_EXTRAICON_EMPTY);
+ } else
+ {
+ nIcon = CLC_EXTRAICON_EMPTY;
+ }
+ } else
+ {
+ int nReplyIcon;
+ if (ItemType == MCLCIT_CONTACT)
+ {
+ nReplyIcon = DBValueToReplyIcon(CContactSettings(0, hContact).Autoreply);
+ } else if (ItemType == MCLCIT_GROUP)
+ {
+ nReplyIcon = GetRealReplyIcon(CList, hItem);
+ } else
+ {
+ _ASSERT(ItemType == MCLCIT_INFO);
+ char *szProto = (char*)CList->GetItemParam(hItem);
+ nReplyIcon = DBValueToReplyIcon(CProtoSettings(szProto).Autoreply);
+ }
+ if (nColumn == EXTRACOLUMN_IGNORE)
+ {
+ CList->SetExtraImage(hItem, EXTRACOLUMN_REPLY, nReplyIcon);
+ } else if (nIcon == CLC_EXTRAICON_EMPTY)
+ {
+ nIcon = nReplyIcon;
+ }
+ }
+ CList->SetExtraImage(hItem, nColumn, nIcon);
+}
+
+
+void SetCListGroupIcons(SetAwayMsgData *dat, CCList *CList)
+{
+ _ASSERT(CList);
+ HTREEITEM hItem = CList->GetNextItem(MCLGN_LAST, NULL); // start from last item, so every item is processed before its parents
+ if (!hItem)
+ {
+ return;
+ }
+ if (CList->GetItemType(hItem) != MCLCIT_GROUP)
+ {
+ hItem = CList->GetNextItem(MCLGN_PREV | MCLGN_GROUP | MCLGN_MULTILEVEL, hItem);
+ if (!hItem)
+ {
+ return;
+ }
+ }
+ do
+ {
+ HTREEITEM hCurItem = CList->GetNextItem(MCLGN_CHILD, hItem);
+ if (hCurItem)
+ {
+ int IgnoreIcon = CList->GetExtraImage(hCurItem, EXTRACOLUMN_IGNORE);
+ int AutoreplyIcon = GetRealReplyIcon(CList, hCurItem);
+ if (IgnoreIcon == EXTRAIMGLIST_MSG)
+ {
+ IgnoreIcon = EXTRAIMGLIST_DOT;
+ }
+ while ((hCurItem = CList->GetNextItem(MCLGN_NEXT | MCLGN_ANY, hCurItem)) && (IgnoreIcon != EXTRAIMGLIST_DOT || AutoreplyIcon != EXTRAIMGLIST_DOT))
+ {
+ if (CList->GetExtraImage(hCurItem, EXTRACOLUMN_IGNORE) != EXTRAIMGLIST_IGNORE)
+ {
+ IgnoreIcon = EXTRAIMGLIST_DOT;
+ }
+ int CurReplyIcon = GetRealReplyIcon(CList, hCurItem);
+ if (CurReplyIcon != AutoreplyIcon)
+ {
+ AutoreplyIcon = EXTRAIMGLIST_DOT;
+ }
+ }
+ CList->SetItemParam(hItem, AutoreplyIcon); // store Reply icon in item's Param, so that we can always get real reply icon for groups later, even if CLC_EXTRAICON_EMPTY is set instead of it
+ SetExtraIcon(CList, EXTRACOLUMN_IGNORE, hItem, IgnoreIcon);
+ SetExtraIcon(CList, EXTRACOLUMN_REPLY, hItem, AutoreplyIcon);
+ }
+ } while (hItem = CList->GetNextItem(MCLGN_PREV | MCLGN_GROUP | MCLGN_MULTILEVEL, hItem));
+}
+
+
+int GetSelContactsNum(CCList *CList, PTREEITEMARRAY Selection = NULL, bool *bOnlyInfo = NULL) // "SelContacts" mean not only contacts, but everything with "personal" status messages and settings - i.e. "All contacts" and protocol items are counted too.
+{
+ if (!CList)
+ {
+ return (Selection == CLSEL_DAT_NOTHING) ? 0 : 1; // Selection == NULL means we need to retrieve current selection by ourselves, and current selection is always CLSEL_DAT_CONTACT in this case
+ }
+ if (!Selection)
+ {
+ Selection = CList->GetSelection();
+ }
+ int I;
+ int nContacts = 0;
+ if (bOnlyInfo)
+ {
+ *bOnlyInfo = true;
+ }
+ for (I = 0; I < Selection->GetSize(); I++)
+ {
+ int ItemType = CList->GetItemType((*Selection)[I]);
+ if (bOnlyInfo && ItemType != MCLCIT_INFO)
+ {
+ *bOnlyInfo = false;
+ }
+ nContacts += ItemType == MCLCIT_CONTACT || ItemType == MCLCIT_INFO;
+ }
+ return nContacts;
+}
+
+
+void ApplySelContactsMessage(SetAwayMsgData* dat, CCList *CList, PTREEITEMARRAY Selection = NULL)
+{
+ TCString Message;
+ HWND hwndDlg = g_SetAwayMsgPage.GetWnd();
+ GetDlgItemText(hwndDlg, IDC_SAWAYMSG_MSGDATA, Message.GetBuffer(AWAY_MSGDATA_MAX), AWAY_MSGDATA_MAX);
+ Message.ReleaseBuffer();
+ if (!lstrlen(Message))
+ {
+ Message = NULL; // delete personal message if it's empty
+ }
+ if (CList)
+ {
+ if (!Selection)
+ {
+ Selection = CList->GetSelection();
+ }
+ int I;
+ for (I = 0; I < Selection->GetSize(); I++)
+ {
+ HTREEITEM hItem = (*Selection)[I];
+ int ItemType = CList->GetItemType(hItem);
+ if (ItemType == MCLCIT_CONTACT)
+ {
+ HANDLE hContact = CList->GethContact(hItem);
+ CContactSettings(0, hContact).SetMsgFormat(SMF_PERSONAL, Message);
+ } else if (ItemType == MCLCIT_INFO)
+ {
+ char *szProto = (char*)CList->GetItemParam(hItem);
+ CProtoSettings(szProto).SetMsgFormat(SMF_PERSONAL, (szProto || Message != NULL) ? Message : _T("")); // "szProto || Message != NULL..." means that we'll set an empty message instead of NULL for the global status, if the message is empty (NULL for the global status has a special meaning - SetMsgFormat will set the default message instead of NULL)
+ } else
+ {
+ continue;
+ }
+ SetExtraIcon(CList, EXTRACOLUMN_IGNORE, hItem, -1); // refresh contact's personal message icon (MSG or DOT)
+ }
+ } else if (Selection != CLSEL_DAT_NOTHING)
+ {
+ if (dat->hInitContact)
+ {
+ CContactSettings(0, dat->hInitContact).SetMsgFormat(SMF_PERSONAL, Message);
+ } else
+ {
+ CProtoSettings(dat->szProtocol).SetMsgFormat(SMF_PERSONAL, (dat->szProtocol || Message != NULL) ? Message : _T(""));
+ }
+ }
+ SendDlgItemMessage(hwndDlg, IDC_SAWAYMSG_MSGDATA, EM_SETMODIFY, false, 0);
+ SetDlgItemText(hwndDlg, IDC_OK, TranslateT("OK"));
+}
+
+
+void UpdateCheckboxesState(CCList *CList)
+{
+ _ASSERT(CList);
+ PTREEITEMARRAY Selection = CList->GetSelection();
+ int I;
+ int ReplyIcon = -1;
+ int IgnoreIcon = -1;
+ for (I = 0; I < Selection->GetSize() && (IgnoreIcon != EXTRAIMGLIST_DOT || ReplyIcon != EXTRAIMGLIST_DOT); I++)
+ {
+ HTREEITEM hItem = (*Selection)[I];
+ int ItemType = CList->GetItemType(hItem);
+ if (ItemType == MCLCIT_CONTACT || ItemType == MCLCIT_INFO)
+ {
+ int CurIgnoreIcon = CList->GetExtraImage(hItem, EXTRACOLUMN_IGNORE);
+ if (IgnoreIcon == -1)
+ {
+ IgnoreIcon = CurIgnoreIcon;
+ } else if (CurIgnoreIcon != EXTRAIMGLIST_IGNORE)
+ {
+ IgnoreIcon = EXTRAIMGLIST_DOT;
+ }
+ int CurReplyIcon = CList->GetExtraImage(hItem, EXTRACOLUMN_REPLY);
+ if (ReplyIcon == -1)
+ {
+ ReplyIcon = CurReplyIcon;
+ } else if (CurReplyIcon != ReplyIcon)
+ {
+ ReplyIcon = EXTRAIMGLIST_DOT;
+ }
+ }
+ }
+ HWND hwndDlg = g_SetAwayMsgPage.GetWnd();
+ CheckDlgButton(hwndDlg, IDC_SAWAYMSG_IGNOREREQ, (IgnoreIcon == EXTRAIMGLIST_IGNORE) ? BST_CHECKED : BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_SENDMSG), IgnoreIcon != EXTRAIMGLIST_IGNORE);
+ CheckDlgButton(hwndDlg, IDC_SAWAYMSG_SENDMSG, (ReplyIcon == EXTRAIMGLIST_AUTOREPLY_ON) ? BST_CHECKED : ((ReplyIcon == EXTRAIMGLIST_AUTOREPLY_OFF) ? BST_UNCHECKED : BST_INDETERMINATE));
+}
+
+HICON g_LoadIconEx( const char* name, bool big )
+{
+ char szSettingName[100];
+ mir_snprintf( szSettingName, sizeof( szSettingName ), "%s_%s", "", name );
+ return ( HICON )CallService( MS_SKIN2_GETICON, big, (LPARAM)szSettingName );
+}
+int CALLBACK SetAwayMsgDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static int SetMsgSplitterX, SetContactSplitterX;
+ static SetAwayMsgData *dat;
+ static HWND hWndTooltips;
+ static int UpdateLock = 0;
+ static int Countdown;
+ static CMsgTree *MsgTree = NULL;
+ static CCList *CList = NULL;
+ static struct {
+ int DlgItem, IconIndex;
+ TCHAR* Text;
+ } Buttons[] = {
+ IDC_SAWAYMSG_SAVEMSG, ILI_SAVE, LPGENT("Save, replacing the selected message"),
+ IDC_SAWAYMSG_SAVEASNEW, ILI_SAVEASNEW, LPGENT("Save as a new message"),
+ IDC_SAWAYMSG_NEWCATEGORY, ILI_NEWCATEGORY, LPGENT("Create new category"),
+ IDC_SAWAYMSG_DELETE, ILI_DELETE, LPGENT("Delete"),
+ IDC_SAWAYMSG_VARS, ILI_NOICON, LPGENT("Open Variables help dialog"),
+ IDC_SAWAYMSG_OPTIONS, ILI_SETTINGS, LPGENT("Show settings menu")
+ };
+
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ dat = (SetAwayMsgData*)lParam;
+ TranslateDialogDefault(hwndDlg);
+ g_SetAwayMsgPage.SetWnd(hwndDlg);
+ g_SetAwayMsgPage.DBToMemToPage();
+/*
+ HICON hTitleIcon = LoadSkinnedIcon(SKINICON_OTHER_MIRANDA);
+ HICON hTitleIconBig = LoadSkinnedIconBig(SKINICON_OTHER_MIRANDA);
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hTitleIconBig);
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)hTitleIcon);
+*/
+ HICON hTitleIconBigElse = LoadSkinnedIconBig(SKINICON_OTHER_MIRANDA);
+
+ char *szProto = dat->hInitContact ? (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)dat->hInitContact, 0) : dat->szProtocol;
+ int Status = 0;
+ Status = g_ProtoStates[dat->szProtocol].Status;
+ HICON hTitleIcon = LoadSkinnedProtoIcon(szProto, Status);
+ HICON hTitleIconBig = LoadSkinnedProtoIconBig(szProto, Status);
+
+
+
+
+ if(hTitleIconBig == NULL || (HICON)CALLSERVICE_NOTFOUND == hTitleIconBig) {
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hTitleIconBigElse);
+ } else {
+ SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)hTitleIconBig);
+ }
+
+ SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)hTitleIcon);
+
+
+ SendDlgItemMessage(hwndDlg, IDC_SAWAYMSG_MSGDATA, EM_LIMITTEXT, AWAY_MSGDATA_MAX, 0);
+
+
+
+
+ // init window size variables / resize the window
+ RECT rc;
+ POINT pt;
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_SAWAYMSG_MSGSPLITTER), &rc);
+ pt.x = (rc.left + rc.right) / 2;
+ pt.y = 0;
+ ScreenToClient(hwndDlg, &pt);
+ g_MsgSplitterX = pt.x;
+ RECT rcContactSplitter;
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_SAWAYMSG_CONTACTSPLITTER), &rcContactSplitter);
+ RECT rcMsgDlg;
+ GetWindowRect(hwndDlg, &rcMsgDlg);
+ g_ContactSplitterX = rcMsgDlg.right - rcContactSplitter.left - (rcContactSplitter.right - rcContactSplitter.left) / 2;
+ RECT rcVars;
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_SAWAYMSG_VARS), &rcVars);
+ g_VariablesButtonDX = rcContactSplitter.left - rcVars.right;
+// GetWindowRect(GetDlgItem(hwndDlg, IDC_OK), &rc);
+ RECT rcOK;
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_OK), &rcOK);
+ //MinMsgEditSize = rc.right - rc.left + rcContactSplitter.right - rcVars.left + 3;
+ MinMsgEditSize = rcOK.right - rc.left + rcContactSplitter.right - rcVars.left + 3;
+ rc.left = MINSPLITTERPOS;
+
+ //NightFox: use MINSPLITTERPOS as min size ;
+// GetWindowRect(GetDlgItem(hwndDlg, IDC_SAWAYMSG_SAVEMSG), &rc);
+// GetWindowRect(GetDlgItem(hwndDlg, IDC_SAWAYMSG_DELETE), &rc);
+// rc.left = MINSPLITTERPOS;
+ //GetWindowRect(GetDlgItem(hwndDlg, IDC_OK), &rc);
+ //GetWindowRect(GetDlgItem(hwndDlg, IDC_OK), &rc);
+
+ pt.x = rc.right;
+ pt.y = 0;
+ ScreenToClient(hwndDlg, &pt);
+ MinMsgSplitterX = pt.x;
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_SAWAYMSG_IGNOREREQ), &rc);
+ MinContactSplitterX = rcMsgDlg.right - rc.left + 1;
+
+ /*
+
+ //NightFox: add status bar
+
+ PROTOACCOUNT * acc = ProtoGetAccount(szProto);
+
+ //HWND hWndStatusBar = CreateStatusWindow(WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | SBARS_SIZEGRIP, NULL, hwndDlg, 999);//IDC_STATUSBAR);
+ SetWindowPos(hWndStatusBar, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
+
+
+ SIZE sz;
+
+ HDC hdc = GetDC(hWndStatusBar);
+ HFONT hFntSave = (HFONT)SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
+ GetTextExtentPoint32(hdc, acc->tszAccountName, lstrlen(acc->tszAccountName), &sz);
+ sz.cx += GetSystemMetrics(SM_CXSMICON) * 3;
+ SelectObject(hdc, hFntSave);
+ ReleaseDC(hWndStatusBar, hdc);
+
+ RECT rcStatus; GetWindowRect(hWndStatusBar, &rcStatus);
+ int parts[] = { rcStatus.right-rcStatus.left - sz.cx, -1 };
+ SendMessage(hWndStatusBar, SB_SETPARTS, 2, (LPARAM)parts);
+ SendMessage(hWndStatusBar, SB_SETICON, 1, (LPARAM)LoadSkinnedProtoIcon(szProto, Status));
+ SendMessage(hWndStatusBar, SB_SETTEXT, 1, (LPARAM)acc->tszAccountName);
+ */
+
+
+
+
+
+
+
+
+
+
+ // [try] getting dialog position
+ int DlgPosX = DBGetContactSettingDword(NULL, MOD_NAME, SAM_DB_DLGPOSX, -1);
+ int DlgPosY = DBGetContactSettingDword(NULL, MOD_NAME, SAM_DB_DLGPOSY, -1);
+ int DlgSizeX = DBGetContactSettingDword(NULL, MOD_NAME, SAM_DB_DLGSIZEX, -1);
+ int DlgSizeY = DBGetContactSettingDword(NULL, MOD_NAME, SAM_DB_DLGSIZEY, -1);
+ int MsgSplitterX = DBGetContactSettingDword(NULL, MOD_NAME, SAM_DB_MSGSPLITTERPOS, -1);
+ int ContactSplitterX = DBGetContactSettingDword(NULL, MOD_NAME, SAM_DB_CONTACTSPLITTERPOS, -1);
+ if (DlgPosX >= 0 && DlgPosY >= 0 && DlgSizeX > 0 && DlgSizeY > 0 && MsgSplitterX > 0 && ContactSplitterX > 0)
+ {
+ RECT rcWorkArea, rcIntersect;
+ SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWorkArea, 0);
+ RECT rcDlgPos = {DlgPosX, DlgPosY, DlgPosX + DlgSizeX, DlgPosY + DlgSizeY};
+ if (!IntersectRect(&rcIntersect, &rcDlgPos, &rcWorkArea)) // make sure the window will be visible
+ {
+ DlgPosX = rcWorkArea.left;
+ DlgPosY = rcWorkArea.top;
+ }
+ SetWindowPos(hwndDlg, NULL, DlgPosX, DlgPosY, DlgSizeX, DlgSizeY, SWP_NOZORDER);
+ g_MsgSplitterX = MsgSplitterX;
+ g_ContactSplitterX = ContactSplitterX;
+ }
+
+ SetMsgSplitterX = g_MsgSplitterX;
+ SetContactSplitterX = g_ContactSplitterX;
+ SendMessage(hwndDlg, WM_SIZE, 0, 0); // show/hide dialog controls accordingly to the settings
+
+ MsgTree = new CMsgTree(GetDlgItem(hwndDlg, IDC_SAWAYMSG_TREE)); // Attention: it's important to call NEW and DELETE in a proper order, as CMsgTree and CCList are setting their own WNDPROCs for the parent window, so we must prevent WNDPROC conflicts.
+ CList = NULL;
+ if (g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_SHOWCONTACTTREE))
+ {
+ SendMessage(hwndDlg, UM_SAM_INITCLIST, 0, 0);
+ } else
+ {
+ NMCLIST nm;
+ nm.hdr.code = MCLN_SELCHANGED;
+ nm.hdr.hwndFrom = GetDlgItem(hwndDlg, IDC_SAWAYMSG_CONTACTSTREE);
+ nm.hdr.idFrom = IDC_SAWAYMSG_CONTACTSTREE;
+ nm.OldSelection = CLSEL_DAT_NOTHING;
+ nm.NewSelection = CLSEL_DAT_CONTACT;
+ SendMessage(hwndDlg, WM_NOTIFY, 0, (LPARAM)&nm);
+ }
+
+ // init message tree
+ if (g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_RECENTMSGSCOUNT) && g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_PERSTATUSMRM))
+ {
+ char *szProto = dat->hInitContact ? (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)dat->hInitContact, 0) : dat->szProtocol;
+ int ID = GetRecentGroupID((szProto || !dat->hInitContact) ? g_ProtoStates[szProto].Status : ID_STATUS_AWAY);
+ CBaseTreeItem* pTreeItem = MsgTree->GetNextItem(MTGN_CHILD | MTGN_BYID, (CBaseTreeItem*)g_Messages_RecentRootID);
+ while (pTreeItem)
+ {
+ if (pTreeItem->Flags & TIF_GROUP)
+ {
+ if (pTreeItem->ID == ID)
+ {
+ pTreeItem->Flags |= TIF_EXPANDED; // leave expanded only one appropriate subgroup of Recent Messages group
+ } else
+ {
+ pTreeItem->Flags &= ~TIF_EXPANDED;
+ }
+ MsgTree->UpdateItem(pTreeItem->ID);
+ }
+ pTreeItem = MsgTree->GetNextItem(MTGN_NEXT, pTreeItem);
+ }
+// InvalidateRect(GetDlgItem(hwndDlg, IDC_SAWAYMSG_TREE), NULL, true);
+ }
+ int Order;
+ CProtoSettings(dat->szProtocol).GetMsgFormat(GMF_LASTORDEFAULT, &Order);
+ if (Order >= 0)
+ { // so just select an appropriate message tree item; MSGDATA text is filled automatically through SELCHANGED notification
+ MsgTree->SetSelection(Order, MTSS_BYORDER);
+ }
+
+ if (dat->Message != NULL) // this allows to override the default message
+ {
+ SetDlgItemText(hwndDlg, IDC_SAWAYMSG_MSGDATA, dat->Message);
+ SendDlgItemMessage(hwndDlg, IDC_SAWAYMSG_MSGDATA, EM_SETMODIFY, true, 0);
+ }
+ SendDlgItemMessage(hwndDlg, IDC_SAWAYMSG_MSGDATA, EM_SETSEL, 0, -1); // select all the text in the edit control
+
+ // init timer
+ Countdown = (dat->ISW_Flags & ISWF_NOCOUNTDOWN) ? -1 : g_MoreOptPage.GetDBValueCopy(IDC_MOREOPTDLG_WAITFORMSG);
+ if (Countdown == -1) // infinite
+ {
+ SetDlgItemText(hwndDlg, IDC_OK, TranslateT("OK"));
+ } else
+ {
+ SendMessage(hwndDlg, WM_TIMER, SAM_TIMER_ID, NULL);
+ SetTimer(hwndDlg, SAM_TIMER_ID, 1000, NULL);
+ }
+
+ // init image buttons
+ int I;
+ for (I = 0; I < lengthof(Buttons); I++)
+ {
+ HWND hButton = GetDlgItem(hwndDlg, Buttons[I].DlgItem);
+ SendMessage(hButton, BUTTONADDTOOLTIP, (WPARAM)TranslateTS(Buttons[I].Text), BATF_TCHAR);
+ SendMessage(hButton, BUTTONSETASFLATBTN, 0, 0);
+ }
+
+ // init tooltips
+ struct {
+ int DlgItemID;
+ TCHAR* Text;
+ } Tooltips[] = {
+ IDC_SAWAYMSG_IGNOREREQ, LPGENT("Don't send the status message to selected contact(s)"),
+ IDC_SAWAYMSG_SENDMSG, LPGENT("Send an autoreply to selected contact(s)"),
+ };
+ TOOLINFO ti = {0};
+ hWndTooltips = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS, _T(""), WS_POPUP, 0, 0, 0, 0, NULL, NULL, GetModuleHandle(NULL), NULL);
+ ti.cbSize = sizeof(ti);
+ ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
+ for (I = 0; I < lengthof(Tooltips); I++)
+ {
+ ti.uId = (UINT)GetDlgItem(hwndDlg, Tooltips[I].DlgItemID);
+ ti.lpszText = TranslateTS(Tooltips[I].Text);
+ SendMessage(hWndTooltips, TTM_ADDTOOL, 0, (LPARAM)&ti);
+ }
+ SendMessage(hwndDlg, UM_ICONSCHANGED, 0, 0);
+
+ g_OrigCListProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SAWAYMSG_CONTACTSTREE), GWLP_WNDPROC, (LONG_PTR)CListSubclassProc);
+ g_OrigEditMsgProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SAWAYMSG_MSGDATA), GWLP_WNDPROC, (LONG_PTR)MsgEditSubclassProc);
+ g_OrigSplitterProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SAWAYMSG_MSGSPLITTER), GWLP_WNDPROC, (LONG_PTR)SplitterSubclassProc);
+ SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_SAWAYMSG_CONTACTSPLITTER), GWLP_WNDPROC, (LONG_PTR)SplitterSubclassProc);
+ return false;
+ } break;
+ case WM_NOTIFY:
+ {
+ switch (((NMHDR*)lParam)->idFrom)
+ {
+ case IDC_SAWAYMSG_CONTACTSTREE:
+ {
+ switch (((NMHDR*)lParam)->code) // check the notification code
+ {
+ case NM_CLICK:
+ {
+ _ASSERT(CList);
+ HWND hTreeView = GetDlgItem(hwndDlg, IDC_SAWAYMSG_CONTACTSTREE);
+ POINT pt = {(short)LOWORD(GetMessagePos()), (short)HIWORD(GetMessagePos())};
+ ScreenToClient(hTreeView, &pt);
+ DWORD hitFlags;
+ HTREEITEM hItem = CList->HitTest(&pt, &hitFlags);
+ if (hitFlags & MCLCHT_ONITEMEXTRA)
+ {
+ int nColumn = HIBYTE(HIWORD(hitFlags));
+ int CurIcon = CList->GetExtraImage(hItem, nColumn);
+ int ItemType = CList->GetItemType(hItem);
+ if (nColumn == EXTRACOLUMN_IGNORE)
+ {
+ CurIcon = (CurIcon == EXTRAIMGLIST_IGNORE) ? EXTRAIMGLIST_DOT : EXTRAIMGLIST_IGNORE;
+ } else
+ {
+ _ASSERT(nColumn == EXTRACOLUMN_REPLY);
+ switch (CurIcon)
+ {
+ case EXTRAIMGLIST_DOT: CurIcon = EXTRAIMGLIST_AUTOREPLY_OFF; break;
+ case EXTRAIMGLIST_AUTOREPLY_OFF: CurIcon = EXTRAIMGLIST_AUTOREPLY_ON; break;
+ case EXTRAIMGLIST_AUTOREPLY_ON: CurIcon = EXTRAIMGLIST_DOT; break;
+ }
+ }
+ SetExtraIcon(CList, nColumn, hItem, CurIcon);
+ if (ItemType == MCLCIT_GROUP) // set all child items
+ {
+ HTREEITEM hCurItem = CList->GetNextItem(MCLGN_CHILD, hItem);
+ HTREEITEM hLimitItem = CList->GetNextItem(MCLGN_NEXT | MCLGN_ANY | MCLGN_NOTCHILD, hItem);
+ while (hCurItem && hCurItem != hLimitItem)
+ {
+ SetExtraIcon(CList, nColumn, hCurItem, CurIcon);
+ hCurItem = CList->GetNextItem(MCLGN_NEXT | MCLGN_ANY | MCLGN_MULTILEVEL, hCurItem);
+ }
+ }
+ SetCListGroupIcons(dat, CList);
+ UpdateCheckboxesState(CList);
+ }
+ } break;
+ case MCLN_SELCHANGED:
+ {
+ PNMCLIST nm = (PNMCLIST)lParam;
+ TCString BtnTitle(TranslateT("OK"));
+ if (CList)
+ {
+ UpdateCheckboxesState(CList);
+ }
+ bool bOnlyInfo;
+ bool bLeaveOldMessage = nm->OldSelection == nm->NewSelection; // OldSelection == NewSelection when we send MCLN_SELCHANGED from UM_SAM_PROTOSTATUSCHANGED; seems that it's better to leave old message then
+ int nOldContacts = GetSelContactsNum(CList, nm->OldSelection);
+ int nNewContacts = GetSelContactsNum(CList, nm->NewSelection, &bOnlyInfo);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_IGNOREREQ), !bOnlyInfo);
+ if (CList)
+ {
+ if (SendDlgItemMessage(hwndDlg, IDC_SAWAYMSG_MSGDATA, EM_GETMODIFY, 0, 0))
+ {
+ int I, J;
+ for (I = nm->OldSelection->GetSize() - 1; I >= 0; I--)
+ {
+ for (J = nm->NewSelection->GetSize() - 1; J >= 0; J--)
+ {
+ if ((*nm->NewSelection)[J] == (*nm->OldSelection)[I])
+ {
+ break;
+ }
+ }
+ if (J < 0)
+ {
+ break;
+ }
+ }
+ if (nNewContacts > 1)
+ {
+ BtnTitle = TranslateT("Apply");
+ }
+ if (I >= 0 && nOldContacts) // there's at least one item in the old selection that is not present in the new one
+ {
+ if ((nOldContacts == 1) || MessageBox(hwndDlg, TranslateT("Do you want to apply the message?"), TranslateT("New Away System"), MB_ICONQUESTION | MB_YESNO) == IDYES)
+ {
+ ApplySelContactsMessage(dat, CList, nm->OldSelection);
+ }
+ } else if (nOldContacts)
+ {
+ bLeaveOldMessage = true; // don't change the edit control text yet - we're still writing...
+ }
+ }
+ } else
+ {
+ if (nOldContacts && !nNewContacts)
+ {
+ ApplySelContactsMessage(dat, CList, nm->OldSelection);
+ }
+ }
+
+ // determine the right new message and window title for the edit control now
+ TCString Message;
+ int Status = 0;
+ if (CList)
+ {
+ bool MessageDetermined = false;
+ bool StatusDetermined = false;
+ int I;
+ for (I = 0; I < nm->NewSelection->GetSize(); I++)
+ {
+ HTREEITEM hItem = (*nm->NewSelection)[I];
+ HANDLE hContact;
+ char *szProto;
+ int ItemType = CList->GetItemType(hItem);
+ if (ItemType == MCLCIT_CONTACT)
+ {
+ hContact = CList->GethContact(hItem);
+ _ASSERT(hContact);
+ szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ _ASSERT(szProto);
+ } else if (ItemType == MCLCIT_INFO)
+ {
+ szProto = (char*)CList->GetItemParam(hItem);
+ }
+ if (ItemType == MCLCIT_CONTACT || ItemType == MCLCIT_INFO)
+ {
+ int CurStatus = g_ProtoStates[szProto].Status;
+ if (!MessageDetermined)
+ {
+ TCString CurMessage((ItemType == MCLCIT_CONTACT) ? CContactSettings(0, hContact).GetMsgFormat(GMF_PERSONAL) : CProtoSettings(szProto).GetMsgFormat(GMF_TEMPORARY | GMF_PERSONAL));
+ if (CurMessage == NULL)
+ {
+ CurMessage = _T("");
+ }
+ if (Message == NULL)
+ {
+ Message = CurMessage;
+ } else if (CurMessage != (const TCHAR*)Message)
+ {
+ Message = _T("");
+ BtnTitle = TranslateT("Apply");
+ MessageDetermined = true;
+ }
+ }
+ if (!StatusDetermined)
+ {
+ if (!Status)
+ {
+ Status = CurStatus;
+ } else if (CurStatus != Status)
+ {
+ Status = 0;
+ StatusDetermined = true;
+ }
+ }
+ }
+ }
+ } else if (nNewContacts) // if (!CList)
+ {
+ Status = g_ProtoStates[dat->szProtocol].Status;
+ Message = dat->hInitContact ? CContactSettings(0, dat->hInitContact).GetMsgFormat(GMF_PERSONAL) : CProtoSettings(dat->szProtocol).GetMsgFormat(GMF_TEMPORARY | GMF_PERSONAL);
+ }
+ if (!bLeaveOldMessage)
+ {
+ SetDlgItemText(hwndDlg, IDC_SAWAYMSG_MSGDATA, (Message == NULL) ? _T("") : Message);
+ }
+ SetDlgItemText(hwndDlg, IDC_OK, BtnTitle);
+ //NightFox: fix titlebar
+ //TCString WindowTitle(TranslateT("Set "));
+ TCString WindowTitle(TranslateT("Set message for"));
+ WindowTitle += _T(" \"");
+ WindowTitle += Status ? (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, Status, GCMDF_TCHAR) : TranslateT("Statuses");
+ //WindowTitle += TranslateT(" message");
+ if (nNewContacts == 1)
+ {
+ WindowTitle += TCString(TranslateT("\" ("));
+ HANDLE hContact = NULL;
+ char *szProto = NULL;
+ if (CList)
+ {
+ int I;
+ for (I = 0; I < nm->NewSelection->GetSize(); I++)
+ {
+ HTREEITEM hItem = (*nm->NewSelection)[I];
+ int ItemType = CList->GetItemType(hItem);
+ if (ItemType == MCLCIT_CONTACT)
+ {
+ hContact = CList->GethContact((*nm->NewSelection)[I]);
+ break;
+ } else if (ItemType == MCLCIT_INFO)
+ {
+ szProto = (char*)CList->GetItemParam(hItem);
+ break;
+ }
+ }
+ } else
+ {
+ hContact = dat->hInitContact;
+ szProto = dat->szProtocol;
+ }
+ if (hContact)
+ {
+
+ if (IsAnICQProto((char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0))) {
+ WindowTitle += TranslateT("message for");
+ WindowTitle += _T(" ");
+ } else {
+ WindowTitle += TranslateT("for");
+ WindowTitle += _T(" ");
+ }
+
+
+ WindowTitle += (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR);
+ if (!IsAnICQProto((char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0)))
+ {
+ //WindowTitle += TranslateT(" (autoreply only)");
+ WindowTitle += _T(" ");
+ WindowTitle += TranslateT("available autoreply only");
+ WindowTitle += _T(")");
+ } else {
+ WindowTitle += _T(")");
+ }
+ } else
+ {
+ if (!szProto)
+ {
+ //WindowTitle += TranslateT("all contacts");
+ WindowTitle += TranslateT("all accounts");
+ WindowTitle += _T(")");
+ } else
+ {
+ //CString ProtoTitle;
+
+ /*if (CallProtoService(szProto, PS_GETNAME, 256, (LPARAM)ProtoTitle.GetBuffer(256)))
+ { // on a failure, set ProtoTitle to an empty string
+ //ProtoTitle[0] = '\0';
+ }*/
+ //ProtoTitle.ReleaseBuffer();
+ //WindowTitle += ANSI2TCHAR(ProtoTitle) + TranslateT(" protocol");
+
+ PROTOACCOUNT * acc = ProtoGetAccount(szProto);
+
+ WindowTitle += acc->tszAccountName;
+ //WindowTitle += _T(" ");
+ //WindowTitle += TranslateT("account");
+ WindowTitle += _T(")");
+ }
+ }
+ } else {
+ WindowTitle += _T("\"");
+ }
+ SetWindowText(hwndDlg, WindowTitle);
+ } break;
+ }
+ } break;
+ case IDC_SAWAYMSG_TREE:
+ {
+ switch (((NMHDR*)lParam)->code)
+ {
+ case MTN_SELCHANGED:
+ {
+ if (!UpdateLock)
+ {
+ PNMMSGTREE pnm = (PNMMSGTREE)lParam;
+ if (pnm->ItemNew && !(pnm->ItemNew->Flags & (TIF_ROOTITEM | TIF_GROUP)))
+ {
+ SetDlgItemText(hwndDlg, IDC_SAWAYMSG_MSGDATA, ((CTreeItem*)pnm->ItemNew)->User_Str1);
+ SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_SAWAYMSG_MSGDATA, EN_CHANGE), (LPARAM)GetDlgItem(hwndDlg, IDC_SAWAYMSG_MSGDATA));
+ SendDlgItemMessage(hwndDlg, IDC_SAWAYMSG_MSGDATA, EM_SETMODIFY, true, 0);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_SAVEMSG), true);
+ } else
+ {
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_SAVEMSG), false);
+ }
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_DELETE), pnm->ItemNew && !(pnm->ItemNew->Flags & TIF_ROOTITEM));
+ }
+ } break;
+ }
+ } break;
+ }
+ return true;
+ } break;
+ case WM_TIMER:
+ {
+ if (wParam == SAM_TIMER_ID)
+ {
+ if (!Countdown)
+ {
+ SendMessage(hwndDlg, UM_SAM_APPLYANDCLOSE, 0, 0);
+ return true;
+ }
+ TCHAR BtnTitle[64];
+ _sntprintf(BtnTitle, sizeof(BtnTitle), TranslateT("Closing in %d"), Countdown);
+ SetDlgItemText(hwndDlg, IDC_OK, BtnTitle);
+ Countdown--;
+ }
+ } break;
+ case UM_SAM_INITCLIST:
+ {
+ _ASSERT(!CList);
+ CList = new CCList(GetDlgItem(hwndDlg, IDC_SAWAYMSG_CONTACTSTREE));
+
+ // init contact tree
+ HIMAGELIST hil;
+ hil = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), (IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16) | ILC_MASK, 5, 2);
+ ImageList_AddIcon(hil, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_DOT)));
+ ImageList_AddIcon(hil, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_IGNORE)));
+ ImageList_AddIcon(hil, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_MSGICON)));
+ ImageList_AddIcon(hil, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SOE_ENABLED)));
+ ImageList_AddIcon(hil, LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SOE_DISABLED)));
+ CList->SetExtraImageList(hil);
+
+ HTREEITEM hSelItem;
+ HTREEITEM hItem = hSelItem = CList->AddInfo(TranslateT("** All contacts **"), CLC_ROOT, CLC_ROOT, NULL, LoadSkinnedProtoIcon(NULL, g_ProtoStates[(char*)NULL].Status));
+ int ProtoCount;
+ PROTOCOLDESCRIPTOR **proto;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&ProtoCount, (LPARAM)&proto);
+ int I;
+ for (I = 0; I < ProtoCount; I++)
+ {
+ if (proto[I]->type == PROTOTYPE_PROTOCOL && CallProtoService(proto[I]->szName, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGSEND) // don't forget to change Recent Message Save loop in the UM_SAM_APPLYANDCLOSE if you're changing something here
+ {
+ //CString ProtoTitle;
+ //CallProtoService(proto[I]->szName, PS_GETNAME, 256, (LPARAM)ProtoTitle.GetBuffer(256));
+ //ProtoTitle.ReleaseBuffer();
+
+ PROTOACCOUNT * acc = ProtoGetAccount(proto[I]->szName);
+ //NightFox: protocols -> accounts
+ //hItem = CList->AddInfo(TCString(_T("* ")) + ANSI2TCHAR(ProtoTitle) + TranslateT(" contacts *"), CLC_ROOT, hItem, (LPARAM)proto[I]->szName, LoadSkinnedProtoIcon(proto[I]->szName, g_ProtoStates[proto[I]->szName].Status));
+ hItem = CList->AddInfo(TCString(_T("* ")) + acc->tszAccountName/* + TranslateT(" contacts *")*/ + _T(" *"), CLC_ROOT, hItem, (LPARAM)proto[I]->szName, LoadSkinnedProtoIcon(proto[I]->szName, g_ProtoStates[proto[I]->szName].Status));
+ if (dat->szProtocol && !strcmp(proto[I]->szName, dat->szProtocol))
+ {
+ hSelItem = hItem;
+ }
+ }
+ }
+
+ HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ CList->SetRedraw(false);
+ do
+ {
+ char *szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if (szProto)
+ {
+ int Flag1 = CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0);
+ if ((Flag1 & PF1_IM) == PF1_IM || Flag1 & PF1_INDIVMODEMSG)
+ { // check if the protocol supports message sending/receiving or individual status messages before adding this contact
+ HTREEITEM hItem = CList->AddContact(hContact);
+ if (dat->hInitContact == hContact)
+ {
+ hSelItem = hItem;
+ }
+ }
+ }
+ } while (hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0));
+ CList->SortContacts();
+ hItem = CLC_ROOT;
+ while (hItem = CList->GetNextItem(MCLGN_NEXT | MCLGN_CONTACT | MCLGN_INFO | MCLGN_MULTILEVEL, hItem))
+ {
+ SetExtraIcon(CList, EXTRACOLUMN_IGNORE, hItem, -1);
+ SetExtraIcon(CList, EXTRACOLUMN_REPLY, hItem, -1);
+ }
+ SetCListGroupIcons(dat, CList);
+ CList->SetRedraw(true); // SetRedraw must be before SelectItem - otherwise SelectItem won't change scrollbar position to make the selected contact visible
+ CList->SelectItem(hSelItem); // must be selected after setting all extra icons, to set checkboxes properly
+ } break;
+ case UM_SAM_APPLYANDCLOSE:
+ {
+ KillTimer(hwndDlg, SAM_TIMER_ID);
+ if (CList)
+ {
+ CList->SelectItem(NULL);
+ } else
+ {
+ NMCLIST nm;
+ nm.hdr.code = MCLN_SELCHANGED;
+ nm.hdr.hwndFrom = GetDlgItem(hwndDlg, IDC_SAWAYMSG_CONTACTSTREE);
+ nm.hdr.idFrom = IDC_SAWAYMSG_CONTACTSTREE;
+ nm.OldSelection = CLSEL_DAT_CONTACT;
+ nm.NewSelection = CLSEL_DAT_NOTHING;
+ SendMessage(hwndDlg, WM_NOTIFY, 0, (LPARAM)&nm);
+ }
+ MsgTree->Save();
+ // save Recent Messages
+ int ProtoCount;
+ PROTOCOLDESCRIPTOR **proto;
+ CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&ProtoCount, (LPARAM)&proto);
+ int I;
+ for (I = 0; I < ProtoCount; I++)
+ {
+ if (proto[I]->type == PROTOTYPE_PROTOCOL && CallProtoService(proto[I]->szName, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_MODEMSGSEND)
+ {
+ TCString Message(CProtoSettings(proto[I]->szName).GetMsgFormat(GMF_PERSONAL)); // yes, we don't specify GMF_TEMPORARY here, because we don't need to save it
+ if (Message != NULL)
+ {
+ CProtoSettings(proto[I]->szName).SetMsgFormat(SMF_LAST, Message); // if the user set a message for this protocol, save it to the recent messages
+ }
+ ChangeProtoMessages(proto[I]->szName, g_ProtoStates[proto[I]->szName].Status, TCString(NULL)); // and actual setting of a status message for the protocol
+ }
+ }
+ TCString Message(CProtoSettings().GetMsgFormat(GMF_PERSONAL));
+ if (Message != NULL)
+ {
+ CProtoSettings().SetMsgFormat(SMF_LAST, Message); // save the global message to the recent messages
+ }
+ if (g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_AUTOSAVEDLGSETTINGS))
+ {
+ SendMessage(hwndDlg, UM_SAM_SAVEDLGSETTINGS, 0, 0);
+ }
+ if (dat->IsModeless)
+ {
+ DestroyWindow(hwndDlg);
+ } else
+ {
+ EndDialog(hwndDlg, 2);
+ }
+ return true;
+ } break;
+ case UM_SAM_SAVEDLGSETTINGS:
+ {
+ RECT rcRect;
+ GetWindowRect(hwndDlg, &rcRect);
+ DBWriteContactSettingDword(NULL, MOD_NAME, SAM_DB_DLGPOSX, rcRect.left);
+ DBWriteContactSettingDword(NULL, MOD_NAME, SAM_DB_DLGPOSY, rcRect.top);
+ DBWriteContactSettingDword(NULL, MOD_NAME, SAM_DB_DLGSIZEX, rcRect.right - rcRect.left);
+ DBWriteContactSettingDword(NULL, MOD_NAME, SAM_DB_DLGSIZEY, rcRect.bottom - rcRect.top);
+ DBWriteContactSettingDword(NULL, MOD_NAME, SAM_DB_MSGSPLITTERPOS, g_MsgSplitterX);
+ DBWriteContactSettingDword(NULL, MOD_NAME, SAM_DB_CONTACTSPLITTERPOS, g_ContactSplitterX);
+ g_SetAwayMsgPage.PageToMemToDB();
+ } break;
+ case UM_SAM_REPLYSETTINGCHANGED:
+ { // wParam = (HANDLE)hContact
+ if (CList)
+ {
+ HTREEITEM hItem = CLC_ROOT;
+ if (!wParam)
+ { // it's the global autoreply setting
+ while (hItem = CList->GetNextItem(MCLGN_NEXT | MCLGN_INFO | MCLGN_MULTILEVEL, hItem))
+ {
+ if (!CList->GetItemParam(hItem))
+ { // we found the item
+ SetExtraIcon(CList, EXTRACOLUMN_REPLY, hItem, -1); // update it
+ break;
+ }
+ }
+ } else
+ { // it's a contact's autoreply setting
+ while (hItem = CList->GetNextItem(MCLGN_NEXT | MCLGN_CONTACT | MCLGN_MULTILEVEL, hItem))
+ {
+ HANDLE hContact = CList->GethContact(hItem);
+ if (CList->GethContact(hItem) == (HANDLE)wParam)
+ { // we found the item
+ SetExtraIcon(CList, EXTRACOLUMN_REPLY, hItem, -1); // update it
+ break;
+ }
+ }
+ }
+ UpdateCheckboxesState(CList);
+ }
+ } break;
+ case UM_SAM_PROTOSTATUSCHANGED:
+ { // wParam = (char*)szProto
+ if (CList)
+ {
+ HTREEITEM hItem = CLC_ROOT;
+ while (hItem = CList->GetNextItem(MCLGN_NEXT | MCLGN_CONTACT | MCLGN_INFO | MCLGN_MULTILEVEL, hItem))
+ {
+ if (CList->GetItemType(hItem) == MCLCIT_INFO)
+ {
+ char *szProto = (char*)CList->GetItemParam(hItem);
+ if (!wParam || !lstrcmpA(szProto, (char*)wParam))
+ {
+ CList->SetInfoIcon(hItem, LoadSkinnedProtoIcon(szProto, g_ProtoStates[szProto].Status));
+ }
+ }
+ SetExtraIcon(CList, EXTRACOLUMN_IGNORE, hItem, -1);
+ SetExtraIcon(CList, EXTRACOLUMN_REPLY, hItem, -1);
+ }
+ SetCListGroupIcons(dat, CList);
+ }
+/* dat->hInitContact = NULL; // TODO: test it
+ dat->szProtocol = (char*)wParam;*/
+ NMCLIST nm;
+ nm.hdr.code = MCLN_SELCHANGED;
+ nm.hdr.hwndFrom = GetDlgItem(hwndDlg, IDC_SAWAYMSG_CONTACTSTREE);
+ nm.hdr.idFrom = IDC_SAWAYMSG_CONTACTSTREE;
+ nm.OldSelection = nm.NewSelection = CList ? CList->GetSelection() : CLSEL_DAT_CONTACT;
+ SendMessage(hwndDlg, WM_NOTIFY, 0, (LPARAM)&nm); // everything else is in the MCLN_SELCHANGED handler, so we'll just call it from here.
+ } break;
+ case UM_ICONSCHANGED:
+ {
+ int I;
+ for (I = 0; I < lengthof(Buttons); I++)
+ {
+ if (Buttons[I].IconIndex != ILI_NOICON)
+ {
+ SendDlgItemMessage(hwndDlg, Buttons[I].DlgItem, BM_SETIMAGE, IMAGE_ICON, (LPARAM)g_IconList[Buttons[I].IconIndex]);
+ }
+ }
+ my_variables_skin_helpbutton(hwndDlg, IDC_SAWAYMSG_VARS);
+ } break;
+ case WM_COMMAND:
+ {
+ switch (HIWORD(wParam))
+ {
+ case EN_CHANGE:
+ {
+ if (LOWORD(wParam) == IDC_SAWAYMSG_MSGDATA)
+ {
+ SetDlgItemText(hwndDlg, IDC_OK, TranslateTS((GetSelContactsNum(CList) > 1) ? LPGENT("Apply") : LPGENT("OK")));
+ }
+ } break;
+ case EN_KILLFOCUS:
+ {
+ if (LOWORD(wParam) == IDC_SAWAYMSG_MSGDATA && GetForegroundWindow() == hwndDlg)
+ {
+ SendMessage(hwndDlg, UM_SAM_KILLTIMER, 0, 0);
+ }
+ } break;
+ case BN_CLICKED:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_SAWAYMSG_IGNOREREQ:
+ {
+ _ASSERT(CList);
+ int Ignore = IsDlgButtonChecked(hwndDlg, IDC_SAWAYMSG_IGNOREREQ) == BST_CHECKED;
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_SENDMSG), !Ignore);
+ PTREEITEMARRAY Selection = CList->GetSelection();
+ int I;
+ for (I = 0; I < Selection->GetSize(); I++)
+ {
+ if (CList->GetItemType((*Selection)[I]) == MCLCIT_CONTACT)
+ {
+ SetExtraIcon(CList, EXTRACOLUMN_IGNORE, (*Selection)[I], Ignore ? EXTRAIMGLIST_IGNORE : EXTRAIMGLIST_DOT);
+ }
+ }
+ if (Selection->GetSize() == 1)
+ {
+ CList->EnsureVisible((*Selection)[0]);
+ }
+ SetCListGroupIcons(dat, CList);
+ } break;
+ case IDC_SAWAYMSG_SENDMSG:
+ {
+ _ASSERT(CList);
+ int Reply = IsDlgButtonChecked(hwndDlg, IDC_SAWAYMSG_SENDMSG);
+ int ReplyIcon = (Reply == BST_CHECKED) ? EXTRAIMGLIST_AUTOREPLY_ON : ((Reply == BST_UNCHECKED) ? EXTRAIMGLIST_AUTOREPLY_OFF : EXTRAIMGLIST_DOT);
+ PTREEITEMARRAY Selection = CList->GetSelection();
+ int I;
+ for (I = 0; I < Selection->GetSize(); I++)
+ {
+ SetExtraIcon(CList, EXTRACOLUMN_REPLY, (*Selection)[I], ReplyIcon);
+ }
+ if (Selection->GetSize() == 1)
+ {
+ CList->EnsureVisible((*Selection)[0]);
+ }
+ SetCListGroupIcons(dat, CList);
+ } break;
+ case IDC_SAWAYMSG_OPTIONS:
+ {
+ HMENU hMenu = LoadMenu(g_hInstance, MAKEINTRESOURCE(IDR_SAM_OPTIONS));
+ _ASSERT(hMenu);
+ HMENU hPopupMenu = GetSubMenu(hMenu, 0);
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM)hPopupMenu, 0);
+ CheckMenuItem(hPopupMenu, IDM_SAM_OPTIONS_SHOWMSGTREE, MF_BYCOMMAND | (g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_SHOWMSGTREE) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(hPopupMenu, IDM_SAM_OPTIONS_SHOWCONTACTTREE, MF_BYCOMMAND | (g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_SHOWCONTACTTREE) ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(hPopupMenu, IDM_SAM_OPTIONS_AUTOSAVEDLGSETTINGS, MF_BYCOMMAND | (g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_AUTOSAVEDLGSETTINGS) ? MF_CHECKED : MF_UNCHECKED));
+ int VariablesInstalled = ServiceExists(MS_VARS_FORMATSTRING);
+ CheckMenuItem(hPopupMenu, IDM_SAM_OPTIONS_DISABLEVARIABLES, MF_BYCOMMAND | ((g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_DISABLEVARIABLES) || !VariablesInstalled) ? MF_CHECKED : MF_UNCHECKED));
+ if (!VariablesInstalled)
+ {
+ EnableMenuItem(hPopupMenu, IDM_SAM_OPTIONS_DISABLEVARIABLES, MF_BYCOMMAND | MF_GRAYED);
+ }
+ switch (TrackPopupMenu(hPopupMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_NONOTIFY | TPM_RETURNCMD, (short)LOWORD(GetMessagePos()), (short)HIWORD(GetMessagePos()), 0, hwndDlg, NULL))
+ {
+ case IDM_SAM_OPTIONS_SHOWMSGTREE:
+ {
+ int bShow = !g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_SHOWMSGTREE);
+ g_SetAwayMsgPage.SetValue(IDS_SAWAYMSG_SHOWMSGTREE, bShow);
+ RECT rcDlg;
+ GetWindowRect(hwndDlg, &rcDlg);
+ rcDlg.left -= bShow ? g_MsgSplitterX : -g_MsgSplitterX;
+ SendMessage(hwndDlg, WM_SIZING, WMSZ_LEFT, (LPARAM)&rcDlg);
+ SetWindowPos(hwndDlg, NULL, rcDlg.left, rcDlg.top, rcDlg.right - rcDlg.left, rcDlg.bottom - rcDlg.top, SWP_NOZORDER);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0); // show/hide dialog controls accordingly
+ } break;
+ case IDM_SAM_OPTIONS_SHOWCONTACTTREE:
+ {
+ int bShow = !g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_SHOWCONTACTTREE);
+ if (bShow && !CList)
+ {
+ NMCLIST nm;
+ nm.hdr.code = MCLN_SELCHANGED;
+ nm.hdr.hwndFrom = GetDlgItem(hwndDlg, IDC_SAWAYMSG_CONTACTSTREE);
+ nm.hdr.idFrom = IDC_SAWAYMSG_CONTACTSTREE;
+ nm.OldSelection = CLSEL_DAT_CONTACT;
+ nm.NewSelection = CLSEL_DAT_NOTHING;
+ SendMessage(hwndDlg, WM_NOTIFY, 0, (LPARAM)&nm); // save current message
+ SendMessage(hwndDlg, UM_SAM_INITCLIST, 0, 0);
+ }
+ g_SetAwayMsgPage.SetValue(IDS_SAWAYMSG_SHOWCONTACTTREE, bShow);
+ RECT rcDlg;
+ GetWindowRect(hwndDlg, &rcDlg);
+ rcDlg.right += bShow ? g_ContactSplitterX : -g_ContactSplitterX;
+ SendMessage(hwndDlg, WM_SIZING, WMSZ_RIGHT, (LPARAM)&rcDlg);
+ SetWindowPos(hwndDlg, NULL, 0, 0, rcDlg.right - rcDlg.left, rcDlg.bottom - rcDlg.top, SWP_NOZORDER | SWP_NOMOVE);
+ SendMessage(hwndDlg, WM_SIZE, 0, 0); // show/hide dialog controls accordingly
+ } break;
+ case IDM_SAM_OPTIONS_AUTOSAVEDLGSETTINGS:
+ {
+ g_SetAwayMsgPage.SetDBValue(IDS_SAWAYMSG_AUTOSAVEDLGSETTINGS, !g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_AUTOSAVEDLGSETTINGS));
+ } break;
+ case IDM_SAM_OPTIONS_SAVEDLGSETTINGSNOW:
+ {
+ SendMessage(hwndDlg, UM_SAM_SAVEDLGSETTINGS, 0, 0);
+ } break;
+ case IDM_SAM_OPTIONS_DISABLEVARIABLES:
+ {
+ g_SetAwayMsgPage.SetDBValue(IDS_SAWAYMSG_DISABLEVARIABLES, !g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_DISABLEVARIABLES));
+ } break;
+ }
+ DestroyMenu(hMenu);
+ } break;
+ case IDC_SAWAYMSG_SAVEMSG:
+ {
+ CBaseTreeItem* TreeItem = MsgTree->GetSelection();
+ if (TreeItem && !(TreeItem->Flags & TIF_ROOTITEM))
+ {
+ MsgTree->EnsureVisible(TreeItem->hItem);
+ TCString NewMsg;
+ GetDlgItemText(hwndDlg, IDC_SAWAYMSG_MSGDATA, NewMsg.GetBuffer(AWAY_MSGDATA_MAX), AWAY_MSGDATA_MAX);
+ NewMsg.ReleaseBuffer();
+ if (((CTreeItem*)TreeItem)->User_Str1 != (const TCHAR*)NewMsg)
+ {
+ ((CTreeItem*)TreeItem)->User_Str1 = NewMsg;
+ MsgTree->SetModified(true);
+ }
+ }
+ } break;
+ case IDC_SAWAYMSG_SAVEASNEW:
+ {
+ TCString Text;
+ GetDlgItemText(hwndDlg, IDC_SAWAYMSG_MSGDATA, Text.GetBuffer(AWAY_MSGDATA_MAX), AWAY_MSGDATA_MAX);
+ Text.ReleaseBuffer();
+ UpdateLock++;
+ CTreeItem* TreeItem = MsgTree->AddMessage();
+ UpdateLock--;
+ TreeItem->User_Str1 = Text;
+ } break;
+ case IDC_SAWAYMSG_NEWCATEGORY:
+ {
+ MsgTree->AddCategory();
+ } break;
+ case IDC_SAWAYMSG_DELETE:
+ {
+ MsgTree->EnsureVisible(MsgTree->GetSelection()->hItem);
+ MsgTree->DeleteSelectedItem();
+ } break;
+ case IDC_SAWAYMSG_VARS:
+ {
+ my_variables_showhelp(hwndDlg, IDC_SAWAYMSG_MSGDATA);
+ } break;
+ case IDC_OK:
+ {
+ // save OK button title before resetting it in SetSelContactsMessage
+ TCString BtnTitle;
+ GetDlgItemText(hwndDlg, IDC_OK, BtnTitle.GetBuffer(64), 64);
+ BtnTitle.ReleaseBuffer();
+ ApplySelContactsMessage(dat, CList);
+ if (BtnTitle != (const TCHAR*)TranslateT("Apply"))
+ {
+ SendMessage(hwndDlg, UM_SAM_APPLYANDCLOSE, 0, 0);
+ }
+ } break;
+ }
+ } break;
+ }
+ } break;
+ case UM_SAM_SPLITTERMOVED:
+ {
+ switch (lParam)
+ {
+ RECT rc;
+ POINT pt;
+ case IDC_SAWAYMSG_MSGSPLITTER:
+ {
+ GetClientRect(hwndDlg, &rc);
+ pt.x = wParam;
+ pt.y = 0;
+ ScreenToClient(hwndDlg, &pt);
+ g_MsgSplitterX = (pt.x < MINSPLITTERPOS) ? MINSPLITTERPOS : pt.x;
+ int MaxSetSplitterX = rc.right - MINSPLITTERPOS + 2;
+ int MaxSplitterX = MaxSetSplitterX;
+ if (g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_SHOWCONTACTTREE))
+ {
+ MaxSetSplitterX -= g_ContactSplitterX;
+ MaxSplitterX -= MINSPLITTERPOS;
+ }
+ if (g_MsgSplitterX > MaxSetSplitterX)
+ {
+ if (g_MsgSplitterX > MaxSplitterX)
+ {
+ g_ContactSplitterX = MINSPLITTERPOS;
+ g_MsgSplitterX = MaxSplitterX;
+ } else
+ {
+ g_ContactSplitterX = MINSPLITTERPOS + MaxSplitterX - g_MsgSplitterX;
+ }
+ }
+ } break;
+ case IDC_SAWAYMSG_CONTACTSPLITTER:
+ {
+ GetClientRect(hwndDlg, &rc);
+ pt.x = wParam;
+ pt.y = 0;
+ ScreenToClient(hwndDlg, &pt);
+ g_ContactSplitterX = (rc.right - pt.x < MINSPLITTERPOS) ? MINSPLITTERPOS : (rc.right - pt.x);
+ int MaxSetSplitterX = rc.right - MINSPLITTERPOS + 2;
+ int MaxSplitterX = MaxSetSplitterX;
+ if (g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_SHOWMSGTREE))
+ {
+ MaxSetSplitterX -= g_MsgSplitterX;
+ MaxSplitterX -= MINSPLITTERPOS;
+ }
+ if (g_ContactSplitterX > MaxSetSplitterX)
+ {
+ if (g_ContactSplitterX > MaxSplitterX)
+ {
+ g_MsgSplitterX = MINSPLITTERPOS;
+ g_ContactSplitterX = MaxSplitterX;
+ } else
+ {
+ g_MsgSplitterX = MINSPLITTERPOS + MaxSplitterX - g_ContactSplitterX;
+ }
+ }
+ } break;
+ }
+ SetMsgSplitterX = g_MsgSplitterX;
+ SetContactSplitterX = g_ContactSplitterX;
+ SendMessage(hwndDlg, WM_SIZE, 0, 0);
+ } break;
+ case WM_SIZING:
+ {
+ RECT *prcDlg = (RECT*)lParam;
+ int MinSetXSize = MINSPLITTERPOS + 7;
+ int MinXSize = MinMsgEditSize + 7;
+ if (g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_SHOWMSGTREE))
+ {
+ MinSetXSize += SetMsgSplitterX - 1;
+ MinXSize += MinMsgSplitterX - 1;
+ }
+ if (g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_SHOWCONTACTTREE))
+ {
+ MinSetXSize += SetContactSplitterX - 1;
+ MinXSize += MinContactSplitterX - 1;
+ }
+ if (prcDlg->right - prcDlg->left < MinXSize)
+ {
+ if (wParam != WMSZ_LEFT && wParam != WMSZ_TOPLEFT && wParam != WMSZ_BOTTOMLEFT)
+ {
+ prcDlg->right = prcDlg->left + MinXSize;
+ } else
+ {
+ prcDlg->left = prcDlg->right - MinXSize;
+ }
+ }
+ if (prcDlg->right - prcDlg->left < MinSetXSize)
+ {
+ int Delta = MinSetXSize - (prcDlg->right - prcDlg->left);
+ if (SetMsgSplitterX > MinMsgSplitterX)
+ {
+ int D2 = min(Delta, SetMsgSplitterX - MinMsgSplitterX);
+ g_MsgSplitterX = SetMsgSplitterX - D2;
+ Delta -= D2;
+ }
+ g_ContactSplitterX = SetContactSplitterX - Delta;
+ } else
+ {
+ g_MsgSplitterX = SetMsgSplitterX;
+ g_ContactSplitterX = SetContactSplitterX;
+ }
+ if (prcDlg->bottom - prcDlg->top < MINYDLGSIZE)
+ {
+ if (wParam != WMSZ_TOP && wParam != WMSZ_TOPLEFT && wParam != WMSZ_TOPRIGHT)
+ {
+ prcDlg->bottom = prcDlg->top + MINYDLGSIZE;
+ } else
+ {
+ prcDlg->top = prcDlg->bottom - MINYDLGSIZE;
+ }
+ }
+ return true;
+ } break;
+ case WM_SIZE:
+ {
+ UTILRESIZEDIALOG urd = {0};
+ urd.cbSize = sizeof(urd);
+ urd.hInstance = g_hInstance;
+ urd.hwndDlg = hwndDlg;
+ urd.lParam = (LPARAM)&g_SetAwayMsgPage;
+ urd.lpTemplate = MAKEINTRESOURCEA(IDD_SETAWAYMSG);
+ urd.pfnResizer = SetAwayMsgDlgResize;
+ CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd);
+ if (!wParam && !lParam) // means that we sent WM_SIZE message to apply new settings to the dialog; probably it's somewhat a misuse, but who cares ;-P
+ {
+ int bShow;
+ bShow = g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_SHOWMSGTREE) ? SW_SHOW : SW_HIDE;
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_TREE), bShow);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_SAVEMSG), bShow);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_SAVEASNEW), bShow);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_NEWCATEGORY), bShow);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_DELETE), bShow);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_MSGSPLITTER), bShow);
+ bShow = g_SetAwayMsgPage.GetValue(IDS_SAWAYMSG_SHOWCONTACTTREE) ? SW_SHOW : SW_HIDE;
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_CONTACTSTREE), bShow);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_IGNOREREQ), bShow);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_SENDMSG), bShow);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_CONTACTSPLITTER), bShow);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_STATIC_IGNOREICON), bShow);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_SAWAYMSG_STATIC_REPLYICON), bShow);
+ }
+ /*if (hWndStatusBar)
+ {
+ RECT rcStatus; GetWindowRect(hWndStatusBar, &rcStatus);
+ RECT rcClient; GetClientRect(hwndDlg, &rcClient);
+ SetWindowPos(hWndStatusBar, NULL, 0, rcClient.bottom-(rcStatus.bottom-rcStatus.top), rcClient.right, (rcStatus.bottom-rcStatus.top), SWP_NOZORDER);
+ }*/
+
+
+ } // go through
+ case UM_SAM_KILLTIMER:
+ case WM_LBUTTONDOWN:
+ case WM_MOUSEACTIVATE:
+ case WM_MOVING: // stops counting
+ {
+ if (Countdown != -1) // still counting
+ {
+ KillTimer(hwndDlg, SAM_TIMER_ID);
+ SetDlgItemText(hwndDlg, IDC_OK, TranslateT("OK"));
+ Countdown = -1;
+ }
+ } break;
+ case WM_SETCURSOR:
+ {
+ HWND hTreeView = GetDlgItem(hwndDlg, IDC_SAWAYMSG_CONTACTSTREE);
+ if ((HWND)wParam == hTreeView && LOWORD(lParam) == HTCLIENT)
+ {
+ _ASSERT(CList);
+ DWORD hitFlags;
+ POINT pt;
+ pt.x = (short)LOWORD(GetMessagePos());
+ pt.y = (short)HIWORD(GetMessagePos());
+ ScreenToClient(hTreeView, &pt);
+ CList->HitTest(&pt, &hitFlags);
+ HCURSOR hCursor = NULL;
+ if (hitFlags & (MCLCHT_ONITEM | MCLCHT_ONITEMEXTRA))
+ {
+ SetClassLong(hTreeView, GCL_HCURSOR, NULL);
+ hCursor = LoadCursor(NULL, IDC_HAND); // set mouse cursor to a hand when hovering over items or their extra images
+ } else
+ {
+ SetClassLong(hTreeView, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW));
+ }
+ if (!hCursor)
+ {
+ hCursor = LoadCursor(NULL, IDC_ARROW);
+ }
+ SetCursor(hCursor);
+ return true;
+ } else
+ {
+ SetClassLong(hTreeView, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_ARROW));
+ }
+ } break;
+ case WM_CLOSE:
+ {
+ KillTimer(hwndDlg, SAM_TIMER_ID);
+ if (dat->IsModeless)
+ {
+ DestroyWindow(hwndDlg);
+ } else
+ {
+ EndDialog(hwndDlg, 2);
+ }
+ } break;
+ case WM_DESTROY:
+ {
+ if (dat)
+ {
+ delete dat;
+ }
+ if (CList)
+ {
+ delete CList;
+ CList = NULL;
+ }
+ delete MsgTree;
+ MsgTree = NULL;
+ g_SetAwayMsgPage.SetWnd(NULL);
+ DestroyWindow(hWndTooltips);
+ return false;
+ } break;
+ }
+ return false;
+}
diff --git a/plugins/NewAwaySysMod/VersionNo.h b/plugins/NewAwaySysMod/VersionNo.h
new file mode 100644
index 0000000000..3634e99662
--- /dev/null
+++ b/plugins/NewAwaySysMod/VersionNo.h
@@ -0,0 +1,5 @@
+#define STRSPECIALBUILD "2636"
+#define FILEVER 0, 3, 8, 4
+#define STRFILEVER "0, 3, 8, 4"
+#define PRODUCTVER FILEVER
+#define STRPRODUCTVER STRFILEVER
diff --git a/plugins/NewAwaySysMod/copying.txt b/plugins/NewAwaySysMod/copying.txt
new file mode 100644
index 0000000000..45645b4b53
--- /dev/null
+++ b/plugins/NewAwaySysMod/copying.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/plugins/NewAwaySysMod/nas_readme.txt b/plugins/NewAwaySysMod/nas_readme.txt
new file mode 100644
index 0000000000..83395abf60
--- /dev/null
+++ b/plugins/NewAwaySysMod/nas_readme.txt
@@ -0,0 +1,281 @@
+New Away System plugin
+ by Chervov Dmitry aka Deathdemon
+
+You can always find the latest plugin version here: http://deathdemon.int.ru/projects.php
+If you have some questions, you'll find answers on most of them on the Miranda forums: http://forums.miranda-im.org/showthread.php?t=2179
+
+New Away System requires at least Miranda v0.6 to work properly. v0.7 or above is recommended.
+If you use an older Miranda core, either update it or use New Away System v0.3.7.8, which is available here:
+http://deathdemon.int.ru/projects/archive/NewAwaySysW_build2371.zip (Unicode; Windows XP/2000/NT)
+http://deathdemon.int.ru/projects/archive/NewAwaySys_build2371.zip (ANSI; Windows 95/98/ME)
+
+Overview
+========
+
+New Away System is a successor to AwaySysMod plugin by XF007 and Tornado.
+It allows to set your status messages using dynamic variables and do some interesting tricks, like different message each time someone requests it, or different status message depending on a time of the day, and much more...
+
+If you're confused by all these variables, it's not a problem :) NAS can also be used in a usual way, by entering usual text as a status message. the only thing you really need to remember is that if your message gets parsed incorrectly (and this happens in some rare cases, when you accidentally use some special characters in the message, like # character), try enclosing that part of your message in `quotes` (note, it's `, not ' !)
+
+Main features:
+- categorized predefined status messages (a message tree is used to store them)
+- autoreply
+- per-protocol status messages, and (ICQ only) per-contact status messages
+- optional notification through a popup that someone read your status message (works only for ICQ, as it's the only protocol that stores status messages on the client side)
+- logging ICQ status message requests to a file (requires LogService plugin)
+- optional updating of your status messages on non-ICQ protocols every X seconds
+- multiple ICQ accounts support
+
+Known issues:
+- currently there is no way to show UINs of contacts that are not on the contact list and requesting a status message - it requires some changes to Variables plugin
+- there's still no proper unicode status message support in protocol plugins, so even with unicode NAS version much depends on protocol itself
+
+To use dynamic variables in NAS, you need to install Variables plugin by Unregistered: http://www.pboon.nl/projects.htm (highly recommended, as without Variables NAS will have a limited functionality).
+To log ICQ status message requests to a file, you need LogService plugin: http://deathdemon.int.ru/projects.php
+
+some useful variables:
+?cinfo(%subject%,display) - nick of the contact who is reading your status message
+?cinfo(%subject%,first) - first name of the contact
+?cinfo(%subject%,last) - last name of the contact
+(for detailed description of other possible values, see the Variables help dialog and readme)
+
+A brief description of the plugin options, just to make things more clear:
+Default messages are used by default for each status, unless you set "by default... use the message from last time" in the miranda options -> Status -> Away System -> Main options tab.
+Each status can have one and only one default message. that's why it's not possible to 'uncheck' "use this message as default for.." buttons, once they were checked. - just select another message in the tree and set it as default.
+You can set any predefined message to be default for certain statuses.
+Also you can add/delete/modify/move your messages/categories in the "Predefined messages" category of the message tree.
+Most recent status messages are placed in the "Recent messages" category; it's not recommended to put your messages manually there, as they'll be replaced by your recent messages. However this category is editable too, just like "predefined messages" is.
+
+FAQ
+===
+
+Q: when I click on the blue question mark button, nothing happens
+A: make sure you have the latest build of Variables plugin installed
+
+Q: all variables remain unparsed and other contacts read my status message, for example, as "Gone since %nas_awaysince_time%" instead of "Gone since 11:45"
+A: Either a) see the previous answer Or b) you checked the "Disable parsing of status messages by Variables plugin" checkbox in the settings menu (one of the buttons on the bottom of the status message change dialog)
+
+Q: NAS uses a wrong status message when miranda sets idle status automatically after several minutes of inactivity
+A: it's a known incompatibility with the built-in autoaway module and it's impossible to solve it in a reasonable way without changes to the miranda core. you can use AdvancedAutoAway plugin if you really need a correct status message with autoaway
+
+Q: NAS uses a wrong status message even when I set it manually
+A: You cannot ever trust contact list's status bar tooltips that show your own status message (though in many cases they still show it correctly). The only way to make sure that your status message is correct is to ask your friend to read it.
+
+Q: what about xstatus support?
+A: it's planned
+
+Q: why does NAS show ?cinfo variables unparsed ("?cinfo(%subject%,display)", "?cinfo(%subject%,id)" etc.) when the contact is not on the contact list?
+A: it requires changes to Variables plugin to allow NAS to override the default behavior of ?cinfo variable. currently there's no any solution of this issue
+
+Q: I can't read or set a status message in unicode
+A: there's still no proper support of unicode status messages by protocol plugins. So, currently even the unicode build of NAS is unable to show unicode status messages of your contacts. I'll fix it as soon as protocol plugins allow me to do that.
+
+Q: I updated NAS and an autoreply doesn't contain my status message now. with an old version it appended the status message at the end.
+A: check that %extratext% is present at the end of Autoreply format (options ->Status->Away System->Autoreply tab). If it's not there, just add it at the end. for example, the default format is:
+Miranda IM autoreply >
+%extratext%
+
+
+Thanks to
+=========
+
+- Faith Healer for icons and useful suggestions
+- Nullbie for his ideas
+- Bio for a nice idea of msvcr70->msvcrt patch
+- UnregistereD for Variables plugin
+- ...and to many other people who reported bugs and gave me ideas
+
+
+Contact
+=======
+The preferable way for questions, bug reports or some suggestions is using Miranda forums:
+http://forums.miranda-im.org/showthread.php?t=2179
+Otherwise, if you have something extremely important to say, you can contact me on ICQ or e-mail :) ICQ: 310927; e-mail: dchervov@yahoo.com
+
+
+Changelog
+=========
+
+v0.3.8.3 (build 26xx; xxx xx, 2007)
+---------
+ - fixed some GDI leaks
+
+v0.3.8.2 (build 2628; Oct 13, 2007)
+---------
+ - fixed a bug with default messages and per-contact notification settings, introduced in the previous build
+
+v0.3.8.1 (build 2626; Oct 13, 2007)
+---------
+ - added "Not-on-list contacts" setting to the NAS' contact list in the options
+ - added back an option to log to a file only when popup notification for a contact is enabled
+ - fix for %nas_timepassed% to return correct value
+ - minor interface improvements
+ - ContactSettings api change
+ - some minor fixes
+
+v0.3.8.0 (build 2601; Oct 4, 2007)
+---------
+ - added Miranda 0.8 support
+ - significantly improved autoreply, added more options and fixed bugs
+ - added support for ICQ Plus online status messages
+ - removed %nas_message% variable. use %extratext% instead
+ - fixed xstatus request notifications
+ - moved logging features to a separate plugin - LogService
+ - added support for ContactSettings plugin
+ - MS_VARS_GETICON service is used now to get an icon for Variables help buttons
+ - some more minor fixes and improvements
+
+v0.3.7.8 (build 2371; Jul 2, 2006)
+---------
+ - fixed a bug with disappeared notification icons under the Contacts tab
+ - other minor fixes
+
+v0.3.7.7 (build 2368; Jul 2, 2006)
+---------
+ - support for locked protocols
+ - implemented unicode logging correctly (thanks to Unregistered)
+ - fix for MS_AWAYMSG_GETSTATUSMSG to return parsed status message
+ - made xstatus notification popups show current xstatus icon
+ - added possibility to change per-contact autoreply setting from the contact menu
+ - fix for wrong extra icons in the contact list of the status message change window
+ - other minor fixes and improvements
+
+v0.3.7.6 (build 2348; May 12, 2006)
+---------
+ - changed NAS behavior so that it accepts status message changes through PS_SETAWAYMSG service now
+ - removed some obsolete implementations of NAS services (update your MyDetails/StartupStatus/AdvancedAutoAway plugins if they stopped working with this release of NAS)
+ - fixed a minor bug - empty status message after setting it through a service, in some specific cases
+
+v0.3.7.5 (build 2346; May 8, 2006)
+---------
+ - fixed crash on startup on some systems
+
+v0.3.7.4 (build 2344; May 5, 2006)
+---------
+ - fix due to database API change in nightly build #53 that made NAS reset its message tree to the defaults
+
+v0.3.7.3 (build 2341; May 4, 2006)
+---------
+ - fix for a wrong message in some cases, when using NAS' services
+ - some other minor fixes
+
+v0.3.7.2 (build 2338; April 30, 2006)
+---------
+ - various improvements and fixes to the NAS services (finally managed to get SS and NAS working together ok (hopefully); thanks to Unregistered)
+ - improved compatibility with plugins that don't support NAS (implemented a method to detect status changes by such plugins)
+ - disabled autoreply on protocols that don't support outgoing messages
+ - fixed a bug with usual status in popups on extended status message request when logging is disabled
+ - fixed some other bugs
+
+v0.3.7.1 (build 2311; April 22, 2006)
+---------
+ - fix for contact menu items in unicode build (only the first letter was displayed)
+ - some other minor changes
+
+v0.3.7.0 (build 2305; April 21, 2006)
+---------
+ - unicode support
+ - some fixes to the NAS services for compatibility with StartupStatus and AdvancedAutoAway plugins
+ - fixed an unnecessary 0x13 character at the end of the popup header
+
+v0.3.6.9 (build 2264; March 15, 2006)
+--------
+ - now it's possible to get default messages for any status mode using NAS services
+
+v0.3.6.8 (build 2262; March 13, 2006)
+--------
+ - %nas_requestcount% and %nas_messagecount% fix
+ - status message is automatically selected now when the status selection window opens
+ - now NAS doesn't add status message to an autoreply automatically. use %extratext% variable in the Autoreply format for that
+
+v0.3.6.7 (build 2257; February 12, 2006)
+--------
+ - some minor changes to improve MyDetails plugin support
+
+v0.3.6.6 (build 2256; November 2, 2005)
+--------
+ - status message change dialog didn't ever pop up for Online and Invisible modes, regardless of settings. fixed.
+
+v0.3.6.5 (build 2253; October 30, 2005)
+--------
+ - updated all the links (also for Updater plugin) to point to deathdemon.int.ru
+
+v0.3.6.4 (build 2250; October 16, 2005)
+--------
+ - now NAS shares contact status messages with other plugins when requesting them through contact's menu.
+ - improved accuracy of status message updates
+ - Read status message window is resizeable now
+ - Updater plugin support
+ - implemented MS_NAS_INVOKESTATUSWINDOW service
+
+v0.3.6.3 (build 2216; September 14, 2005)
+--------
+ - correct ICQ XStatus logging and popup notification.
+ - fixed a bug with status message refresh on startup when setting status through StartupStatus.
+
+v0.3.6.3 (build 2210; September 12, 2005)
+--------
+ - added a possibility to use %nas_message% variable in the autoreply format, to specify where exactly NAS should place usual status message.
+ - added "Log requests only if popup notification for a contact is enabled" checkbox in the Log tab
+ - some strings were untranslatable. fixed.
+
+v0.3.6.3 (build 2200; September 11, 2005)
+--------
+ - workaround for contact list's CLGN_NEXT bug.
+
+v0.3.6.3 (build 2193; September 10, 2005)
+--------
+ - now NAS will open the status message change window much faster when "Show contacts" is disabled
+ - optimized tabs in the options - now NAS' options will load faster
+ - previous NAS build didn't load on systems with an old msvcrt.dll version. fixed. (thanks to scHacklaban)
+
+v0.3.6.3 (build 2186; September 8, 2005)
+--------
+ - fixed a crash on status change when there are no groups in a contact list (thanks to Ladiko)
+ - added "Contacts" options tab - it allows to set per-contact settings, and also there is a new setting - per-contact popup notification
+ - added %nas_protocol% variable that returns current protocol name
+ - fixed a bug with message tree scrolling when per-status recent messages are enabled
+ - NAS stored per-protocol recent messages in wrong categories with per-status recent messages enabled
+ - some other minor bugfixes
+
+v0.3.6.2 (build 2136; August 28, 2005)
+--------
+ - fixed a bug with wrong status messages that was introduced in the previous build
+ - implemented services that will allow other plugins to get/set status messages in a way compatible with NAS
+
+v0.3.6.2 (build 2129; August 27, 2005)
+--------
+ - added support for StartupStatus and AdvancedAutoAway, and also hopefully for some other plugins that change status
+ - added nas_predefinedmessage variable
+ - some minor bugfixes
+
+v0.3.6.2 (build 2110; August 26, 2005)
+--------
+bugfixes:
+ - hopefully fixed problems with autoreply
+ - previous builds set an empty message on statuses for which "don't show status message dialog.." was enabled
+
+v0.3.6.2 (build 2108; August 26, 2005)
+--------
+ - multiple ICQ accounts support
+ - optional updating of your status messages on non-ICQ protocols
+ - now NAS works pretty well even without Variables plugin
+ - some bugfixes
+ - added translation.txt
+
+v0.3.6.1 (build 2083; August 25, 2005)
+--------
+Added a lot of new features:
+ - categorized predefined status messages
+ - separate default messages for different statuses
+ - (bugfix) NAS stores status messages separately for different protocols now. for example, if you'll change your MSN status message, your ICQ message won't be overwritten now.
+ - many improvements in user interface
+ - some bugfixes
+
+v0.3.6.0 (build 733; August 13, 2005)
+--------
+ - Just a quick fix of an old build to stop notification of custom status message requests (newer builds are still very unstable).
+
+v0.3.6.0 (build 732; May 16, 2005)
+--------
+ - First public release. \ No newline at end of file
diff --git a/plugins/NewAwaySysMod/nas_translation.txt b/plugins/NewAwaySysMod/nas_translation.txt
new file mode 100644
index 0000000000..9d7053a732
--- /dev/null
+++ b/plugins/NewAwaySysMod/nas_translation.txt
@@ -0,0 +1,238 @@
+Miranda Language Pack Version 1
+Locale: 0809
+Authors: Deathdemon; XF007; Goblineye Entertainment
+Author-email: dchervov@yahoo.com
+Last-Modified-Using: Miranda IM 0.7svn
+Plugins-included: NewAwaySys
+; Generated by lpgen on Sat Oct 13 14:56:33 2007
+; Translations: 210
+
+; Common strings that belong to many files
+;[ message:\r\n]
+;[** All contacts **]
+;[Autoreply]
+;[Create new category]
+;[Delete]
+;[Don't send status message]
+;[Enable autoreply]
+;[New Away System]
+;[New category]
+;[New message]
+;[OK]
+;[Open Variables help dialog]
+;[PopUps]
+;[Toggle autoreply on/off]
+
+; C:/VSProjects/Miranda/plugins/NewAwaySys/AwayOpt.cpp
+;[** Not-on-list contacts **]
+;[Away]
+;[Been gone since %nas_awaysince_time%, will be back later.]
+;[Been having ?ifgreater(?ctime(H),2,?ifgreater(?ctime(H),10,?ifgreater(?ctime(H),16,supper,dinner),breakfast),supper) since %nas_awaysince_time%.]
+;[Close popup]
+;[Contacts]
+;[Create new message]
+;[Creepy]
+;[DND]
+;[Default messages]
+;[Do nothing]
+;[Edit status messages]
+;[File]
+;[Free for chat]
+;[Give a guy some peace, would ya?]
+;[Give it up, I'm not in!]
+;[Gone fragging]
+;[I'm a chatbot!]
+;[I'm hiding from the mafia.]
+;[I've been on the phone since %nas_awaysince_time%, give me a sec!]
+;[Invisible]
+;[Main options]
+;[Message]
+;[Miranda]
+;[NA]
+;[Not right now.]
+;[Occupied]
+;[On the phone]
+;[Online]
+;[Open contact details window]
+;[Open contact history]
+;[Open contact menu]
+;[Open log file]
+;[Open message window]
+;[Other (XStatus)]
+;[Out to lunch]
+;[Predefined messages]
+;[Recent messages]
+;[URL]
+;[When this checkbox is ticked, NewAwaySys counts \"send times\" starting from the last status message change, even if status mode didn't change.\nWhen the checkbox isn't ticked, \"send times\" are counted from last status mode change (i.e. disabled state is more restrictive).]
+;[Windows]
+;[Yep, I'm here.]
+;[You can put your frequently used and favorite messages in this category.]
+;[Your master, %nas_mynick%, has been %nas_statdesc% since the day that is only known as ?nas_awaysince_date(dddd)... When he gets back, I'll tell him you dropped by...]
+;[Your most recent status messages are placed in this category. It's not recommended to put your messages manually here, as they'll be replaced by your recent messages.]
+
+; C:/VSProjects/Miranda/plugins/NewAwaySys/AwaySys.cpp
+;[%d hours]
+;[%d minutes]
+;[%d seconds]
+;[) read your ]
+;[Don't send status message when you are %s]
+;[Enable autoreply when you are %s]
+;[Ignore status message requests from this contact and don't send an autoreply]
+;[Ignore status message requests from this contact and don't send an autoreply.\r\n\"Store contact autoreply/ignore settings for each status separately\" is enabled, so this setting is per-contact AND per-status.]
+;[New Away System plugin requires Miranda version 0.6.0.0 or above.]
+;[New Away System: Status message request notifications]
+;[New Away System\t(x)\tAway since date in format x (x is optional)]
+;[New Away System\t(x)\tAway since time in format x (x is optional)]
+;[New Away System\t(x)\tReturns one of your predefined messages by its title: ?nas_predefinedmessage(creepy)]
+;[New Away System\tCurrent protocol name]
+;[New Away System\tNumber of messages from the contact]
+;[New Away System\tNumber of status message requests from the contact]
+;[New Away System\tStatus description]
+;[New Away System\tTime passed until request]
+;[New Away System\tYour nick for current protocol]
+;[NewAwaySys: Incoming status message request]
+;[Off]
+;[On]
+;[Re&ad %s Message]
+;[Read status message]
+;[Set %s message for the contact]
+;[Set status message]
+;[Stranger]
+;[Use the default setting]
+;[\"Store contact autoreply/ignore settings for each status separately\" is enabled, so this setting is per-contact AND per-status.]
+
+; C:/VSProjects/Miranda/plugins/NewAwaySys/Common.h
+;[?cinfo(%subject%,display) (?cinfo(%subject%,id)) is reading your %nas_statdesc% message:\r\n%extratext%]
+;[Away System]
+;[Miranda IM autoreply >\r\n%extratext%]
+;[Status]
+;[Toggle autoreply off]
+;[Toggle autoreply on]
+;[Variables plugin is not installed]
+;[extended status]
+
+; C:/VSProjects/Miranda/plugins/NewAwaySys/MsgTree.cpp
+;[Do you really want to delete this ]
+;[You've made changes to multiple Message trees at a time.\r\nDo you want to leave changes in \"]
+;[\" dialog?\r\nPress Yes to leave changes in this dialog, or No to discard its changes and save changes of the other Message tree instead.]
+;[category with its messages?]
+;[message?]
+
+; C:/VSProjects/Miranda/plugins/NewAwaySys/Notification.cpp
+;[) is reading your ]
+;[Can't open log file ]
+;[Error #%d]
+
+; C:/VSProjects/Miranda/plugins/NewAwaySys/ReadAwayMsg.cpp
+;[&Close]
+
+; C:/VSProjects/Miranda/plugins/NewAwaySys/Resources.rc
+;[%extratext% is your status message]
+;[%s Message for %s]
+;[&Away]
+;[&Cancel]
+;[&DND]
+;[&Delete]
+;[&Free for chat]
+;[&Invisible]
+;[&NA]
+;[&Other]
+;[&Rename]
+;[&Save]
+;[&Save current window settings as default]
+;[&Variables]
+;[-1 = Infinite]
+;[...for each status separately]
+;[0 = Default]
+;[Autoreply format:]
+;[Autoreply off]
+;[Autoreply on]
+;[Background]
+;[By default...]
+;[Click action]
+;[Colours]
+;[Create new &category]
+;[Create new &message]
+;[Delay]
+;[Disable autoreply when...]
+;[Disable parsing of status messages by Variables plugin]
+;[Don't notify of requests]
+;[Don't reply to ICQ contacts]
+;[Don't reply when I'm invisible to the contact]
+;[Don't show the message dialog for]
+;[Enable contact menu items]
+;[Ignore requests]
+;[Log to a file only when popup notification for a contact is enabled]
+;[Means the setting is different for different status modes / contacts]
+;[Message tree category menu]
+;[Message tree menu]
+;[New &Category]
+;[Note: these settings are applied to all status modes at once.]
+;[Notify of requests]
+;[Occ&upied]
+;[On event...]
+;[On left click]
+;[On right click]
+;[On the &Phone]
+;[On&line]
+;[Only notify when:]
+;[Out to &Lunch]
+;[Popup notification]
+;[Popup text format]
+;[Preview]
+;[Remember last message used for a contact...]
+;[Reply only when Idle]
+;[Reply only when contact's message window is closed]
+;[Reset per-protocol messages when changing global status]
+;[Reset this counter also when I just change my status text\n(when status icon remains the same)]
+;[Retrieving %s message...]
+;[Save As &New]
+;[Save autoreply to the history]
+;[Save default window settings &automatically]
+;[Se&ttings]
+;[Sec]
+;[Send an autoreply]
+;[Send maximum]
+;[Set as &default for]
+;[Set away message window options]
+;[Show &contacts]
+;[Show predefined &messages]
+;[Store]
+;[Store contact autoreply/ignore settings for each status separately]
+;[Store protocol autoreply settings for each status separately]
+;[Store protocol messages for each status separately]
+;[Text]
+;[Title:]
+;[Update status messages for non-ICQ protocols every]
+;[Use default]
+;[Use protocol specific nick for %nas_mynick%]
+;[Use the default message]
+;[Use the most recent message]
+;[Use this message as default for]
+;[V]
+;[Wait]
+;[most recent messages (0=disable)]
+;[seconds]
+;[seconds before closing the status message dialog (-1=don't close)]
+;[times (-1=infinite)]
+
+; C:/VSProjects/Miranda/plugins/NewAwaySys/SetAwayMsg.cpp
+;[ (autoreply only)]
+;[ contacts *]
+;[ for ]
+;[ message]
+;[ protocol]
+;[Apply]
+;[Closing in %d]
+;[Do you want to apply the message?]
+;[Don't send the status message to selected contact(s)]
+;[Save as a new message]
+;[Save, replacing the selected message]
+;[Send an autoreply to selected contact(s)]
+;[Set ]
+;[Show settings menu]
+;[all contacts]
+;[status]
+
+; C:/VSProjects/Miranda/plugins/NewAwaySys/m_variables.h
+;[Open String Formatting Help]
diff --git a/plugins/NewAwaySysMod/resource.h b/plugins/NewAwaySysMod/resource.h
new file mode 100644
index 0000000000..1c6190554b
--- /dev/null
+++ b/plugins/NewAwaySysMod/resource.h
@@ -0,0 +1,261 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by NewAwaySys.rc
+//
+#define IDD_OPTDIALOGMAIN 101
+#define IDD_MESSAGES 101
+#define IDD_MODERNOPT_MESSAGES 102
+#define IDI_MSGICON 109
+#define IDI_SOE_ENABLED 110
+#define IDD_READAWAYMSG 111
+#define IDI_SOE_DISABLED 111
+#define IDB_SOE_ENABLED 112
+#define IDB_SOE_DISABLED 114
+#define IDD_NOTIFYOPTDLG 115
+#define IDD_NOTIFYVARSDLG 116
+#define IDD_AUTOREPLY 121
+#define IDR_SAM_OPTIONS 122
+#define IDI_DOT 123
+#define IDI_IGNORE 124
+#define IDI_SAVEMSG 127
+#define IDI_SAVE 127
+#define IDI_SAVEASNEW 128
+#define IDI_DELETE 130
+#define IDI_NEWCATEGORY 133
+#define IDR_MSGTREE_CATEGORYMENU 134
+#define IDR_MSGTREE_MESSAGEMENU 135
+#define IDI_NEWMESSAGE 136
+#define IDI_SETTINGS 137
+#define IDI_STATUS_OTHER 138
+#define IDD_CONTACTSOPTDLG 139
+#define IDI_DISABLENOTIFY 140
+#define IDI_ENABLENOTIFY 141
+#define IDI_INDEFINITE 142
+#define IDD_SETAWAYMSG_BAK 144
+#define IDD_SETAWAYMSG 216
+#define IDD_MOREOPTDIALOG 217
+#define IDD_POPUPOPTDLG 218
+#define IDC_STATUSBAR 999
+#define IDC_SAWAYMSG_MSGNAME 1001
+#define IDC_MESSAGEDLG_DEL 1002
+#define IDC_OPTDLG_MSGDATA 1003
+#define IDC_MESSAGEDLG_MSGDATA 1003
+#define IDC_OPTDLG_MSGNAME 1004
+#define IDC_OPTDLG_MAKEDEFAULT 1005
+#define IDC_OPTDLG_USELASTMSG 1007
+#define IDC_MOREOPTDLG_USELASTMSG 1007
+#define IDC_OPTDLG_USEDEFAULT 1008
+#define IDC_SAWAYMSG_MSGDATA 1008
+#define IDC_MOREOPTDLG_USEDEFMSG 1008
+#define IDC_OPTDLG_SAVE 1010
+#define IDC_LNK_AUTOAWAY 1010
+#define IDC_OPTDLG_RESET 1012
+#define IDC_OPTDLG_VARSLIST 1013
+#define IDC_MESSAGEDLG_VARS 1013
+#define IDC_SAWAYMSG_STATIC_CHARSTXT 1014
+#define IDC_STATIC_BYDEFAULT 1017
+#define IDC_STATIC_MSG 1021
+#define IDC_MOREOPTDLG_NEVERSTATDLG 1028
+#define IDC_MOREOPTDLG_WAITFORMSG 1029
+#define IDC_STATIC_MOREOPTDLG_WAIT 1030
+#define IDC_STATIC_MOREOPTDLG_SECONDSREMAIN 1031
+#define IDC_MOREOPTDLG_LMESTAT 1032
+#define IDC_MOREOPTDLG_PERSTATUSMRM 1032
+#define IDC_MOREOPTDLG_RMDLGPOS 1033
+#define IDC_MOREOPTDLG_SAVEDLGPOS 1033
+#define IDC_MOREOPTDLG_SETLASTCONTCAT 1034
+#define IDC_MOREOPTDLG_SAVECONTACTMSGS 1034
+#define IDC_MOREOPTDLG_SAVEPERSONALMSGS 1034
+#define IDC_MOREOPTDLG_USEMENUITEM 1035
+#define IDC_MOREOPTDLG_PERSTATUSPERSONAL 1036
+#define IDC_MOREOPTDLG_RESETPROTOMSGS 1037
+#define IDC_MOREOPTDLG_PERSTATUSPROTOMSGS 1038
+#define IDC_MOREOPTDLG_PERSTATUSPROTOSETTINGS 1039
+#define IDC_SAWAYMSG_CONTACTSTREE 1040
+#define IDC_MOREOPTDLG_PERSTATUSPERSONALSETTINGS 1040
+#define IDC_SAWAYMSG_STATIC_VARS 1041
+#define IDC_SAWAYMSG_SHOWCONTACTS 1042
+#define IDC_SAWAYMSG_STATIC_RESETCHNG 1043
+#define IDC_SAWAYMSG_OPTIONS 1043
+#define IDC_MOREOPTDLG_SENDNONICQ 1049
+#define IDC_REPLYDLG_DONTSENDTOICQ 1049
+#define IDC_MOREOPTDLG_EVNTMSG 1050
+#define IDC_REPLYDLG_EVENTMSG 1050
+#define IDC_MOREOPTDLG_EVNTURL 1051
+#define IDC_REPLYDLG_EVENTURL 1051
+#define IDC_MOREOPTDLG_EVNTFILE 1052
+#define IDC_REPLYDLG_EVENTFILE 1052
+#define IDC_MOREOPTDLG_SENDONCE 1053
+#define IDC_SAWAYMSG_SENDMSG 1054
+#define IDC_MOREOPTDLG_SENDALL 1054
+#define IDC_SAWAYMSG_IGNOREREQ 1055
+#define IDC_MOREOPTDLG_STATIC_SEND 1057
+#define IDC_REPLYDLG_STATIC_SEND 1057
+#define IDC_MOREOPTDLG_STATIC_ONEVENT 1058
+#define IDC_REPLYDLG_STATIC_ONEVENT 1058
+#define IDC_VARSLIST_STATIC_TIME 1061
+#define IDC_MOREOPTDLG_NOPOPLIST 1062
+#define IDC_MOREOPTDLG_NOPOP 1063
+#define IDC_MOREOPTDLG_NOSSMLIST 1064
+#define IDC_MOREOPTDLG_NOSSM 1065
+#define IDC_OPTDLG_PREFIX 1065
+#define IDC_REPLYDLG_PREFIX 1065
+#define IDC_MOREOPTDLG_LOGMSG 1066
+#define IDC_REPLYDLG_LOGREPLY 1066
+#define IDC_OPTDLG_USEDEFNICK 1068
+#define IDC_MOREOPTDLG_MYNICKPERPROTO 1068
+#define IDC_MOREOPTDLG_SHOWRMSG 1069
+#define IDC_MOREOPTDLG_SENDMSG 1070
+#define IDC_REPLYDLG_ENABLEREPLY 1070
+#define IDC_POPUPOPTDLG_POPUPFORMAT 1071
+#define IDC_POPUPOPTDLG_USEPOPUPS 1072
+#define IDC_POPUPOPTDLG_BGCOLOUR 1073
+#define IDC_POPUPOPTDLG_TEXTCOLOUR 1074
+#define IDC_POPUPOPTDLG_LCLICK_ACTION 1075
+#define IDC_POPUPOPTDLG_RCLICK_ACTION 1077
+#define IDC_POPUPOPTDLG_POPUPPREVIEW 1078
+#define IDC_POPUPOPTDLG_AWAYNOTIFY 1084
+#define IDC_POPUPOPTDLG_NANOTIFY 1085
+#define IDC_POPUPOPTDLG_OCCNOTIFY 1086
+#define IDC_POPUPOPTDLG_DNDNOTIFY 1087
+#define IDC_POPUPOPTDLG_FFCNOTIFY 1088
+#define IDC_POPUPOPTDLG_DEFBGCOLOUR 1089
+#define IDC_POPUPOPTDLG_DEFTEXTCOLOUR 1090
+#define IDC_NOTIFYVARS_STATIC_TIME 1091
+#define IDC_VARS_STATIC_TIME 1091
+#define IDC_POPUPOPTDLG_OTHERNOTIFY 1091
+#define IDC_POPUPOPTDLG_STATIC_LCLICK 1092
+#define IDC_POPUPOPTDLG_STATIC_RCLICK 1093
+#define IDC_POPUPOPTDLG_STATIC_BGCOLOUR 1094
+#define IDC_POPUPOPTDLG_STATIC_TEXTCOLOUR 1095
+#define IDC_POPUPOPTDLG_ONLNOTIFY 1096
+#define IDC_POPUPOPTDLG_POPUPDELAY 1099
+#define IDC_POPUPOPTDLG_STATIC_SEC 1100
+#define IDC_POPUPOPTDLG_STATIC_DEFAULT 1101
+#define IDC_POPUPOPTDLG_STATIC_INFINITE 1102
+#define IDC_MESSAGEDLG_DEF_AWAY 1109
+#define IDC_SAWAYMSG_SAVEMSG 1109
+#define IDC_REPLYDLG_ONLYIDLEREPLY 1109
+#define IDC_POPUPOPTDLG_VARS 1110
+#define IDC_REPLYDLG_DISABLE_AWAY 1110
+#define IDC_SAWAYMSG_SAVEASNEW 1110
+#define IDC_MOREOPTDLG_PANEL 1111
+#define IDC_SAWAYMSG_NEWCATEGORY 1111
+#define IDC_SAWAYMSG_DELETE 1112
+#define IDC_MESSAGEDLG_DEF_ONL 1113
+#define IDC_MESSAGEDLG_DEF_NA 1114
+#define IDC_MESSAGEDLG_DEF_OCC 1115
+#define IDC_MESSAGEDLG_DEF_DND 1116
+#define IDC_MESSAGEDLG_DEF_FFC 1117
+#define IDC_MESSAGEDLG_DEF_OTP 1118
+#define IDC_MESSAGEDLG_DEF_OTL 1119
+#define IDC_MESSAGEDLG_MSGTITLE 1120
+#define IDC_MOREOPTDLG_DONTPOPDLG_INV 1120
+#define IDC_MESSAGEDLG_MSGTREE 1121
+#define IDC_REPLYDLG_DISABLE_ONL 1121
+#define IDC_MESSAGEDLG_NEWCAT 1122
+#define IDC_REPLYDLG_DISABLE_NA 1122
+#define IDC_MESSAGEDLG_NEWMSG 1123
+#define IDC_REPLYDLG_DISABLE_OCC 1123
+#define IDC_REPLYDLG_DISABLE_DND 1124
+#define IDC_REPLYDLG_DISABLE_FFC 1125
+#define IDC_REPLYDLG_DISABLE_OTP 1126
+#define IDC_REPLYDLG_DISABLE_OTL 1127
+#define IDC_REPLYDLG_DISABLE_INV 1128
+#define IDC_MOREOPTDLG_RECENTMSGSCOUNT 1129
+#define IDC_MOREOPTDLG_UPDATEMSGSPERIOD 1130
+#define IDC_MESSAGEDLG_DEF_INV 1131
+#define IDC_REPLYDLG_SENDCOUNT 1132
+#define IDC_MOREOPTDLG_DONTPOPDLG_ONL 1133
+#define IDC_MOREOPTDLG_DONTPOPDLG_AWAY 1134
+#define IDC_MOREOPTDLG_DONTPOPDLG_NA 1135
+#define IDC_MOREOPTDLG_DONTPOPDLG_OCC 1136
+#define IDC_MOREOPTDLG_DONTPOPDLG_DND 1137
+#define IDC_MOREOPTDLG_DONTPOPDLG_FFC 1138
+#define IDC_MOREOPTDLG_DONTPOPDLG_OTP 1139
+#define IDC_MOREOPTDLG_DONTPOPDLG_OTL 1140
+#define IDC_REPLYDLG_STATIC_TIMES 1141
+#define IDC_MESSAGEDLG_TEST 1142
+#define IDC_MOREOPTDLG_EDITMESSAGES 1142
+#define IDC_SAWAYMSG_VARS 1142
+#define IDC_SAWAYMSG_TREE 1149
+#define IDC_SAWAYMSG_EDITMSGS 1150
+#define IDC_SAWAYMSG_RESET 1151
+#define IDC_OK 1152
+#define IDC_MSGSPLITTER 1154
+#define IDC_SAWAYMSG_MSGSPLITTER 1154
+#define IDC_CONTACTSPLITTER 1155
+#define IDC_SAWAYMSG_CONTACTSPLITTER 1155
+#define IDC_SAWAYMSG_STATIC_IGNOREICON 1157
+#define IDC_SAWAYMSG_STATIC_REPLYICON 1158
+#define IDC_MOREOPTDLG_WAITFORMSG_SPIN 1161
+#define IDC_MOREOPTDLG_RECENTMSGSCOUNT_SPIN 1162
+#define IDC_REPLYDLG_SENDCOUNT_SPIN 1163
+#define IDC_MOREOPTDLG_UPDATEMSGSPERIOD_SPIN 1163
+#define IDC_POPUPOPTDLG_POPUPDELAY_SPIN 1164
+#define IDC_REPLYDLG_VARS 1165
+#define IDC_MOREOPTDLG_UPDATEMSGS 1166
+#define IDC_CONTACTSDLG_LIST 1168
+#define IDC_REPLYDLG_DONTREPLYINVISIBLE 1169
+#define IDC_REPLYDLG_ONLYIDLEREPLY_COMBO 1170
+#define IDC_REPLYDLG_ONLYCLOSEDDLGREPLY 1171
+#define IDC_REPLYDLG_RESETCOUNTERWHENSAMEICON 1172
+#define IDC_REPLYDLG_STATIC_DISABLEWHENSTATUS 1174
+#define IDC_REPLYDLG_STATIC_FORMAT 1175
+#define IDC_POPUPOPTDLG_GROUP_NOTIFICATION 1176
+#define IDC_POPUPOPTDLG_LOGONLYWITHPOPUP 1177
+#define IDC_POPUPOPTDLG_STATIC_EXTRATEXT 1178
+#define IDC_REPLYDLG_STATIC_EXTRATEXT 1179
+#define IDC_TXT_TITLE1 1181
+#define IDC_TXT_TITLE2 1182
+#define IDC_TXT_TITLE3 1183
+#define IDC_SAWAYMSG_STATIC_COUNTER 1202
+#define IDC_READAWAYMSG_RETRIEVE 3453
+#define IDS_MESSAGEDLG_DEF_ONL 20000
+#define IDS_MESSAGEDLG_DEF_AWAY 20001
+#define IDS_MESSAGEDLG_DEF_NA 20002
+#define IDS_MESSAGEDLG_DEF_OCC 20003
+#define IDS_MESSAGEDLG_DEF_DND 20004
+#define IDS_MESSAGEDLG_DEF_FFC 20005
+#define IDS_MESSAGEDLG_DEF_INV 20006
+#define IDS_MESSAGEDLG_DEF_OTP 20007
+#define IDS_MESSAGEDLG_DEF_OTL 20008
+#define IDV_MSGTREE 20009
+#define IDS_SAWAYMSG_SHOWMSGTREE 20100
+#define IDS_SAWAYMSG_SHOWCONTACTTREE 20101
+#define IDS_SAWAYMSG_AUTOSAVEDLGSETTINGS 20102
+#define IDS_SAWAYMSG_DISABLEVARIABLES 20103
+#define IDM_SAM_OPTIONS_SHOWMSGTREE 40007
+#define IDM_SAM_OPTIONS_SHOWCONTACTTREE 40008
+#define IDM_SAM_OPTIONS_EDITMSGS 40009
+#define IDM_SAM_OPTIONS_AUTOSAVEDLGSETTINGS 40014
+#define IDM_SAM_OPTIONS_SAVEDLGSETTINGSNOW 40015
+#define IDM_MSGTREEMENU_RENAME 40017
+#define IDM_MSGTREEMENU_NEWMESSAGE 40022
+#define IDM_MSGTREEMENU_NEWCATEGORY 40024
+#define IDM_MSGTREEMENU_DELETE 40026
+#define ID_MESSAGETREECATEGORYMENU_SETASDEFAULTFOR 40027
+#define IDR_MSGTREEMENU_DEF_ONL 40037
+#define IDR_MSGTREEMENU_DEF_AWAY 40038
+#define IDR_MSGTREEMENU_DEF_NA 40039
+#define IDR_MSGTREEMENU_DEF_OCC 40040
+#define IDR_MSGTREEMENU_DEF_DND 40041
+#define IDR_MSGTREEMENU_DEF_FFC 40042
+#define IDR_MSGTREEMENU_DEF_INV 40043
+#define IDR_MSGTREEMENU_DEF_OTP 40044
+#define IDR_MSGTREEMENU_DEF_OTL 40045
+#define IDM_SAM_OPTIONS_DISABLEVARIABLES 40047
+#define IDC_READAWAYMSG_MSG 54765
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_3D_CONTROLS 1
+#define _APS_NEXT_RESOURCE_VALUE 145
+#define _APS_NEXT_COMMAND_VALUE 40048
+#define _APS_NEXT_CONTROL_VALUE 1185
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/plugins/NewAwaySysMod/resources.rc b/plugins/NewAwaySysMod/resources.rc
new file mode 100644
index 0000000000..5ce1657aa7
--- /dev/null
+++ b/plugins/NewAwaySysMod/resources.rc
@@ -0,0 +1,6 @@
+#include "resource.h"
+#include "VersionNo.h"
+#include "NewAwaySys.rc"
+#include "version.rc"
+
+
diff --git a/plugins/NewAwaySysMod/version.rc b/plugins/NewAwaySysMod/version.rc
new file mode 100644
index 0000000000..b72d1be4d4
--- /dev/null
+++ b/plugins/NewAwaySysMod/version.rc
@@ -0,0 +1,59 @@
+//
+// version.rc - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+#error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#include "VersionNo.h"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION FILEVER
+ PRODUCTVERSION PRODUCTVER
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x21L
+#else
+ FILEFLAGS 0x20L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "NightFox; Deathdemon; XF007; Goblineye Entertainment"
+ VALUE "FileDescription", "New Away System plugin for Miranda IM"
+ VALUE "FileVersion", STRFILEVER
+ VALUE "LegalCopyright", "© 2010 NightFox; © 2005-2006 Chervov Dmitry; © 2004-2005 Iksaif Entertainment; © 2002-2003 Goblineye Entertainment"
+#ifdef _UNICODE
+ VALUE "InternalName", "NewAwaySysW"
+ VALUE "OriginalFilename", "NewAwaySysW.dll"
+ VALUE "ProductName", "New Away System (Unicode)"
+#else
+ VALUE "InternalName", "NewAwaySys"
+ VALUE "OriginalFilename", "NewAwaySys.dll"
+ VALUE "ProductName", "New Away System (ANSI)"
+#endif
+ VALUE "ProductVersion", STRPRODUCTVER
+ VALUE "SpecialBuild", STRSPECIALBUILD
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+/////////////////////////////////////////////////////////////////////////////