summaryrefslogtreecommitdiff
path: root/plugins/TabSRMM/src/globals.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/TabSRMM/src/globals.cpp')
-rw-r--r--plugins/TabSRMM/src/globals.cpp967
1 files changed, 967 insertions, 0 deletions
diff --git a/plugins/TabSRMM/src/globals.cpp b/plugins/TabSRMM/src/globals.cpp
new file mode 100644
index 0000000000..689b4cb53b
--- /dev/null
+++ b/plugins/TabSRMM/src/globals.cpp
@@ -0,0 +1,967 @@
+/*
+ * astyle --force-indent=tab=4 --brackets=linux --indent-switches
+ * --pad=oper --one-line=keep-blocks --unpad=paren
+ *
+ * Miranda IM: the free IM client for Microsoft* Windows*
+ *
+ * Copyright 2000-2009 Miranda ICQ/IM project,
+ * all portions of this codebase are copyrighted to the people
+ * listed in contributors.txt.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * you should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * part of tabSRMM messaging plugin for Miranda.
+ *
+ * (C) 2005-2010 by silvercircle _at_ gmail _dot_ com and contributors
+ *
+ * $Id: globals.cpp 13447 2011-03-14 19:55:07Z george.hazan $
+ *
+ * Plugin configuration variables and functions. Implemented as a class
+ * though there will always be only a single instance.
+ *
+ */
+
+#include "commonheaders.h"
+extern PLUGININFOEX pluginInfo;
+
+CGlobals PluginConfig;
+CGlobals* pConfig = &PluginConfig;
+
+static TContainerSettings _cnt_default = {
+ false,
+ CNT_FLAGS_DEFAULT,
+ CNT_FLAGSEX_DEFAULT,
+ 255,
+ CInfoPanel::DEGRADE_THRESHOLD,
+ 60,
+ _T("%n (%s)"),
+ 1,
+ 0
+};
+
+HANDLE CGlobals::m_event_ModulesLoaded = 0, CGlobals::m_event_PrebuildMenu = 0, CGlobals::m_event_SettingChanged = 0;
+HANDLE CGlobals::m_event_ContactDeleted = 0, CGlobals::m_event_Dispatch = 0, CGlobals::m_event_EventAdded = 0;
+HANDLE CGlobals::m_event_IconsChanged = 0, CGlobals::m_event_TypingEvent = 0, CGlobals::m_event_ProtoAck = 0;
+HANDLE CGlobals::m_event_PreShutdown = 0, CGlobals::m_event_OkToExit = 0;
+HANDLE CGlobals::m_event_IcoLibChanged = 0, CGlobals::m_event_AvatarChanged = 0, CGlobals::m_event_MyAvatarChanged = 0, CGlobals::m_event_FontsChanged = 0;
+HANDLE CGlobals::m_event_SmileyAdd = 0, CGlobals::m_event_IEView = 0, CGlobals::m_event_FoldersChanged = 0;
+HANDLE CGlobals::m_event_ME_MC_SUBCONTACTSCHANGED = 0, CGlobals::m_event_ME_MC_FORCESEND = 0, CGlobals::m_event_ME_MC_UNFORCESEND = 0;
+TCHAR* CGlobals::m_default_container_name = _T("default");
+
+extern HANDLE hHookButtonPressedEvt;
+extern HANDLE hHookToolBarLoadedEvt;
+
+EXCEPTION_RECORD CGlobals::m_exRecord = {0};
+CONTEXT CGlobals::m_exCtx = {0};
+LRESULT CGlobals::m_exLastResult = 0;
+char CGlobals::m_exSzFile[MAX_PATH] = "\0";
+wchar_t CGlobals::m_exReason[256] = L"\0";
+int CGlobals::m_exLine = 0;
+bool CGlobals::m_exAllowContinue = false;
+
+#if defined(_WIN64)
+ static char szCurrentVersion[30];
+ static char *szVersionUrl = "http://download.miranda.or.at/tabsrmm/3/version.txt";
+ static char *szUpdateUrl = "http://silvercircle.googlecode.com/files/tabsrmm-3_x64.zip";
+ static char *szFLVersionUrl = "http://addons.miranda-im.org/details.php?action=viewfile&id=3699";
+ static char *szFLUpdateurl = "http://addons.miranda-im.org/feed.php?dlfile=3699";
+#else
+ static char szCurrentVersion[30];
+ static char *szVersionUrl = "http://download.miranda.or.at/tabsrmm/3/version.txt";
+ static char *szUpdateUrl = "http://silvercircle.googlecode.com/files/tabsrmm-3_x86.zip";
+ static char *szFLVersionUrl = ADDONS_UPDATE_URL;
+ static char *szFLUpdateurl = ADDONS_DL_URL;
+#endif
+ static char *szPrefix = "tabsrmm ";
+
+
+CRTException::CRTException(const char *szMsg, const TCHAR *szParam) : std::runtime_error(std::string(szMsg))
+{
+ mir_sntprintf(m_szParam, MAX_PATH, szParam);
+}
+
+void CRTException::display() const
+{
+ TCHAR* tszMsg = mir_a2t(what());
+ TCHAR tszBoxMsg[500];
+
+ mir_sntprintf(tszBoxMsg, 500, _T("%s\n\n(%s)"), tszMsg, m_szParam);
+ ::MessageBox(0, tszBoxMsg, _T("TabSRMM runtime error"), MB_OK | MB_ICONERROR);
+ mir_free(tszMsg);
+}
+
+void CGlobals::RegisterWithUpdater()
+{
+ Update upd = {0};
+
+ if (!ServiceExists(MS_UPDATE_REGISTER))
+ return;
+
+ upd.cbSize = sizeof(upd);
+ upd.szComponentName = pluginInfo.shortName;
+ upd.pbVersion = (BYTE *)CreateVersionString(pluginInfo.version, szCurrentVersion);
+ upd.cpbVersion = (int)(strlen((char *)upd.pbVersion));
+ upd.szVersionURL = szFLVersionUrl;
+ upd.szUpdateURL = szFLUpdateurl;
+ upd.pbVersionPrefix = (BYTE *)"<span class=\"fileNameHeader\">tabSRMM Unicode 2.0 ";
+ upd.cpbVersionPrefix = (int)(strlen((char *)upd.pbVersionPrefix));
+
+ upd.szBetaUpdateURL = szUpdateUrl;
+ upd.szBetaVersionURL = szVersionUrl;
+ upd.pbVersion = (unsigned char *)szCurrentVersion;
+ upd.cpbVersion = lstrlenA(szCurrentVersion);
+ upd.pbBetaVersionPrefix = (BYTE *)szPrefix;
+ upd.cpbBetaVersionPrefix= (int)(strlen((char *)upd.pbBetaVersionPrefix));
+ upd.szBetaChangelogURL = "http://blog.miranda.or.at/tabsrmm-articles/tabsrmm-version-3-changelog";
+
+ CallService(MS_UPDATE_REGISTER, 0, (LPARAM)&upd);
+}
+/**
+ * reload system values. These are read ONCE and are not allowed to change
+ * without a restart
+ */
+void CGlobals::reloadSystemStartup()
+{
+ HDC hScrnDC;
+ DBVARIANT dbv = {0};
+
+ m_WinVerMajor = WinVerMajor();
+ m_WinVerMinor = WinVerMinor();
+ m_bIsXP = IsWinVerXPPlus();
+ m_bIsVista = IsWinVerVistaPlus();
+ m_bIsWin7 = IsWinVer7Plus();
+
+ ::LoadTSButtonModule();
+ ::RegisterTabCtrlClass();
+ CTip::registerClass();
+
+ dwThreadID = GetCurrentThreadId();
+
+ PluginConfig.g_hMenuContext = LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_TABCONTEXT));
+ CallService(MS_LANGPACK_TRANSLATEMENU, (WPARAM)g_hMenuContext, 0);
+
+ SkinAddNewSoundEx("RecvMsgActive", "Instant messages", "Incoming (Focused Window)");
+ SkinAddNewSoundEx("RecvMsgInactive", "Instant messages", "Incoming (Unfocused Window)");
+ SkinAddNewSoundEx("AlertMsg", "Instant messages", "Incoming (New Session)");
+ SkinAddNewSoundEx("SendMsg", "Instant messages", "Outgoing");
+ SkinAddNewSoundEx("SendError", "Instant messages", "Message send error");
+
+ hCurSplitNS = LoadCursor(NULL, IDC_SIZENS);
+ hCurSplitWE = LoadCursor(NULL, IDC_SIZEWE);
+ hCurHyperlinkHand = LoadCursor(NULL, IDC_HAND);
+ if (hCurHyperlinkHand == NULL)
+ hCurHyperlinkHand = LoadCursor(g_hInst, MAKEINTRESOURCE(IDC_HYPERLINKHAND));
+
+ hScrnDC = GetDC(0);
+ g_DPIscaleX = GetDeviceCaps(hScrnDC, LOGPIXELSX) / 96.0;
+ g_DPIscaleY = GetDeviceCaps(hScrnDC, LOGPIXELSY) / 96.0;
+ ReleaseDC(0, hScrnDC);
+
+ reloadSettings(false);
+ reloadAdv();
+ hookSystemEvents();
+}
+
+/**
+ * this runs ONCE at startup when the Modules Loaded event is fired
+ * by the core. all plugins are loaded and ready to use.
+ *
+ * any initialation for 3rd party plugins must go here.
+ */
+void CGlobals::reloadSystemModulesChanged()
+{
+ BOOL bIEView = FALSE;
+ CLISTMENUITEM mi = { 0 };
+
+ m_MathModAvail = ServiceExists(MATH_RTF_REPLACE_FORMULAE);
+
+ /*
+ * smiley add
+ */
+ if (ServiceExists(MS_SMILEYADD_REPLACESMILEYS)) {
+ PluginConfig.g_SmileyAddAvail = 1;
+ m_event_SmileyAdd = HookEvent(ME_SMILEYADD_OPTIONSCHANGED, ::SmileyAddOptionsChanged);
+ }
+ else
+ m_event_SmileyAdd = 0;
+
+ /*
+ * Flashavatars
+ */
+
+ g_FlashAvatarAvail = (ServiceExists(MS_FAVATAR_GETINFO) ? 1 : 0);
+
+ /*
+ * ieView
+ */
+
+ bIEView = ServiceExists(MS_IEVIEW_WINDOW);
+ if (bIEView) {
+ BOOL bOldIEView = M->GetByte("ieview_installed", 0);
+ if (bOldIEView != bIEView)
+ M->WriteByte(SRMSGMOD_T, "default_ieview", 1);
+ M->WriteByte(SRMSGMOD_T, "ieview_installed", 1);
+ m_event_IEView = HookEvent(ME_IEVIEW_OPTIONSCHANGED, ::IEViewOptionsChanged);
+ } else {
+ M->WriteByte(SRMSGMOD_T, "ieview_installed", 0);
+ m_event_IEView = 0;
+ }
+
+ g_iButtonsBarGap = M->GetByte("ButtonsBarGap", 1);
+ m_hwndClist = (HWND)CallService(MS_CLUI_GETHWND, 0, 0);
+ m_MathModAvail = (ServiceExists(MATH_RTF_REPLACE_FORMULAE) ? 1 : 0);
+ if (m_MathModAvail) {
+ char *szDelim = (char *)CallService(MATH_GET_STARTDELIMITER, 0, 0);
+ if (szDelim) {
+ MultiByteToWideChar(CP_ACP, 0, szDelim, -1, PluginConfig.m_MathModStartDelimiter, safe_sizeof(PluginConfig.m_MathModStartDelimiter));
+ CallService(MTH_FREE_MATH_BUFFER, 0, (LPARAM)szDelim);
+ }
+ }
+ else
+ PluginConfig.m_MathModStartDelimiter[0] = 0;
+
+ g_MetaContactsAvail = (ServiceExists(MS_MC_GETDEFAULTCONTACT) ? 1 : 0);
+
+
+ if(g_MetaContactsAvail) {
+ mir_snprintf(szMetaName, 256, "%s", (char *)CallService(MS_MC_GETPROTOCOLNAME, 0, 0));
+ bMetaEnabled = abs(M->GetByte(0, szMetaName, "Enabled", -1));
+ }
+ else {
+ szMetaName[0] = 0;
+ bMetaEnabled = 0;
+ }
+
+ g_PopupAvail = (ServiceExists(MS_POPUP_ADDPOPUPEX) ? 1 : 0);
+ g_PopupWAvail = (ServiceExists(MS_POPUP_ADDPOPUPW) ? 1 : 0);
+
+ mi.cbSize = sizeof(mi);
+ mi.position = -2000090000;
+ if (ServiceExists(MS_SKIN2_GETICONBYHANDLE)) {
+ mi.flags = CMIF_ICONFROMICOLIB | CMIF_DEFAULT;
+ mi.icolibItem = LoadSkinnedIconHandle(SKINICON_EVENT_MESSAGE);
+ } else {
+ mi.flags = CMIF_DEFAULT;
+ mi.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ }
+ mi.pszName = LPGEN("&Message");
+ mi.pszService = MS_MSG_SENDMESSAGE;
+ PluginConfig.m_hMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+
+ m_useAeroPeek = M->GetByte("useAeroPeek", 1);
+}
+
+/**
+ * reload plugin settings on startup and runtime. Most of these setttings can be
+ * changed while plugin is running.
+ */
+void CGlobals::reloadSettings(bool fReloadSkins)
+{
+ m_ncm.cbSize = sizeof(NONCLIENTMETRICS);
+ SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &m_ncm, 0);
+
+ DWORD dwFlags = M->GetDword("mwflags", MWF_LOG_DEFAULT);
+
+ m_SendOnShiftEnter = (int)M->GetByte("sendonshiftenter", 0);
+ m_SendOnEnter = (int)M->GetByte(SRMSGSET_SENDONENTER, SRMSGDEFSET_SENDONENTER);
+ m_SendOnDblEnter = (int)M->GetByte("SendOnDblEnter", 0);
+ m_AutoLocaleSupport = (int)M->GetByte("al", 0);
+ m_AutoSwitchTabs = (int)M->GetByte("autoswitchtabs", 1);
+ m_CutContactNameTo = (int) DBGetContactSettingWord(NULL, SRMSGMOD_T, "cut_at", 15);
+ m_CutContactNameOnTabs = (int)M->GetByte("cuttitle", 0);
+ m_StatusOnTabs = (int)M->GetByte("tabstatus", 1);
+ m_LogStatusChanges = (int)dwFlags & MWF_LOG_STATUSCHANGES;
+ m_UseDividers = (int)M->GetByte("usedividers", 0);
+ m_DividersUsePopupConfig = (int)M->GetByte("div_popupconfig", 0);
+ m_MsgTimeout = (int)M->GetDword(SRMSGMOD, SRMSGSET_MSGTIMEOUT, SRMSGDEFSET_MSGTIMEOUT);
+
+ if (m_MsgTimeout < SRMSGSET_MSGTIMEOUT_MIN)
+ m_MsgTimeout = SRMSGSET_MSGTIMEOUT_MIN;
+
+ m_EscapeCloses = (int)M->GetByte("escmode", 0);
+
+ m_HideOnClose = (int) M->GetByte("hideonclose", 0);
+ m_AllowTab = (int) M->GetByte("tabmode", 0);
+
+ m_FlashOnClist = (int)M->GetByte("flashcl", 0);
+ m_AlwaysFullToolbarWidth = (int)M->GetByte("alwaysfulltoolbar", 1);
+ m_LimitStaticAvatarHeight = (int)M->GetDword("avatarheight", 96);
+ m_SendFormat = (int)M->GetByte("sendformat", 0);
+ m_FormatWholeWordsOnly = 1;
+ m_RTLDefault = (int)M->GetByte("rtldefault", 0);
+ m_TabAppearance = (int)M->GetDword("tabconfig", TCF_FLASHICON | TCF_SINGLEROWTABCONTROL);
+ m_panelHeight = (DWORD)M->GetDword("panelheight", CInfoPanel::DEGRADE_THRESHOLD);
+ m_MUCpanelHeight = M->GetDword("Chat", "panelheight", CInfoPanel::DEGRADE_THRESHOLD);
+ m_IdleDetect = (int)M->GetByte("dimIconsForIdleContacts", 1);
+ m_smcxicon = 16;
+ m_smcyicon = 16;
+ m_PasteAndSend = (int)M->GetByte("pasteandsend", 1);
+ m_szNoStatus = const_cast<TCHAR *>(CTranslator::get(CTranslator::GEN_NO_STATUS));
+ m_LangPackCP = ServiceExists(MS_LANGPACK_GETCODEPAGE) ? CallService(MS_LANGPACK_GETCODEPAGE, 0, 0) : CP_ACP;
+ m_visualMessageSizeIndicator = M->GetByte("msgsizebar", 0);
+ m_autoSplit = M->GetByte("autosplit", 0);
+ m_FlashOnMTN = M->GetByte(SRMSGMOD, SRMSGSET_SHOWTYPINGWINFLASH, SRMSGDEFSET_SHOWTYPINGWINFLASH);
+ if(m_MenuBar == 0) {
+ m_MenuBar = ::LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_MENUBAR));
+ CallService(MS_LANGPACK_TRANSLATEMENU, WPARAM(m_MenuBar), 0);
+ }
+
+ m_ipBackgroundGradient = M->GetDword(FONTMODULE, "ipfieldsbg", 0x62caff);
+ if(0 == m_ipBackgroundGradient)
+ m_ipBackgroundGradient = 0x62caff;
+
+ m_ipBackgroundGradientHigh = M->GetDword(FONTMODULE, "ipfieldsbgHigh", 0xf0f0f0);
+ if(0 == m_ipBackgroundGradientHigh)
+ m_ipBackgroundGradientHigh = 0xf0f0f0;
+
+ m_tbBackgroundHigh = M->GetDword(FONTMODULE, "tbBgHigh", 0);
+ m_tbBackgroundLow = M->GetDword(FONTMODULE, "tbBgLow", 0);
+ m_fillColor = M->GetDword(FONTMODULE, "fillColor", 0);
+ if(CSkin::m_BrushFill) {
+ ::DeleteObject(CSkin::m_BrushFill);
+ CSkin::m_BrushFill = 0;
+ }
+ m_genericTxtColor = M->GetDword(FONTMODULE, "genericTxtClr", GetSysColor(COLOR_BTNTEXT));
+ m_cRichBorders = M->GetDword(FONTMODULE, "cRichBorders", 0);
+
+ ::CopyMemory(&globalContainerSettings, &_cnt_default, sizeof(TContainerSettings));
+ Utils::ReadContainerSettingsFromDB(0, &globalContainerSettings);
+ globalContainerSettings.fPrivate = false;
+ if(fReloadSkins)
+ Skin->setupAeroSkins();
+}
+
+/**
+ * reload "advanced tweaks" that can be applied w/o a restart
+ */
+void CGlobals::reloadAdv()
+{
+ g_bDisableAniAvatars= M->GetByte("adv_DisableAniAvatars", 0);
+ g_bSoundOnTyping = M->GetByte("adv_soundontyping", 0);
+ m_dontUseDefaultKbd= M->GetByte("adv_leaveKeyboardAlone", 1);
+ g_bClientInStatusBar = M->GetByte("adv_ClientIconInStatusBar", 0);
+
+ if(g_bSoundOnTyping && m_TypingSoundAdded == false) {
+ SkinAddNewSoundEx("SoundOnTyping", "Other", "TABSRMM: Typing");
+ m_TypingSoundAdded = true;
+ }
+ m_AllowOfflineMultisend = M->GetByte("AllowOfflineMultisend", 0);
+}
+
+const HMENU CGlobals::getMenuBar()
+{
+ if(m_MenuBar == 0) {
+ m_MenuBar = ::LoadMenu(g_hInst, MAKEINTRESOURCE(IDR_MENUBAR));
+ CallService(MS_LANGPACK_TRANSLATEMENU, WPARAM(m_MenuBar), 0);
+ }
+ return(m_MenuBar);
+}
+
+/**
+ * hook core events. This runs in LoadModule()
+ * only core events and services are guaranteed to exist at this time
+ */
+void CGlobals::hookSystemEvents()
+{
+ m_event_ModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded);
+ m_event_IconsChanged = HookEvent(ME_SKIN_ICONSCHANGED, ::IconsChanged);
+ m_event_TypingEvent = HookEvent(ME_PROTO_CONTACTISTYPING, CMimAPI::TypingMessage);
+ m_event_ProtoAck = HookEvent(ME_PROTO_ACK, CMimAPI::ProtoAck);
+ m_event_PreShutdown = HookEvent(ME_SYSTEM_PRESHUTDOWN, PreshutdownSendRecv);
+ m_event_OkToExit = HookEvent(ME_SYSTEM_OKTOEXIT, OkToExit);
+
+ m_event_PrebuildMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, CMimAPI::PrebuildContactMenu);
+
+ m_event_IcoLibChanged = HookEvent(ME_SKIN2_ICONSCHANGED, ::IcoLibIconsChanged);
+ m_event_AvatarChanged = HookEvent(ME_AV_AVATARCHANGED, ::AvatarChanged);
+ m_event_MyAvatarChanged = HookEvent(ME_AV_MYAVATARCHANGED, ::MyAvatarChanged);
+}
+
+/**
+ * second part of the startup initialisation. All plugins are now fully loaded
+ */
+
+int CGlobals::ModulesLoaded(WPARAM wParam, LPARAM lParam)
+{
+ int i;
+ MENUITEMINFOA mii = {0};
+ HMENU submenu;
+ CLISTMENUITEM mi = { 0 };
+
+ ::UnhookEvent(m_event_ModulesLoaded);
+
+ M->configureCustomFolders();
+
+ Skin->Init(true);
+ CSkin::initAeroEffect();
+
+ for (i = 0; i < NR_BUTTONBARICONS; i++)
+ PluginConfig.g_buttonBarIcons[i] = 0;
+ ::LoadIconTheme();
+ ::CreateImageList(TRUE);
+
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_BITMAP;
+ mii.hbmpItem = HBMMENU_CALLBACK;
+ submenu = GetSubMenu(PluginConfig.g_hMenuContext, 7);
+ for (i = 0; i <= 8; i++)
+ SetMenuItemInfoA(submenu, (UINT_PTR)i, TRUE, &mii);
+
+ PluginConfig.reloadSystemModulesChanged();
+
+ ::BuildContainerMenu();
+
+ ::CB_InitDefaultButtons();
+ ::ModPlus_Init(wParam, lParam);
+ ::NotifyEventHooks(hHookToolBarLoadedEvt, (WPARAM)0, (LPARAM)0);
+ //
+
+ if (M->GetByte("avatarmode", -1) == -1)
+ M->WriteByte(SRMSGMOD_T, "avatarmode", 2);
+
+ PluginConfig.g_hwndHotkeyHandler = CreateWindowEx(0, _T("TSHK"), _T(""), WS_POPUP,
+ 0, 0, 40, 40, 0, 0, g_hInst, NULL);
+
+ ::CreateTrayMenus(TRUE);
+ if (nen_options.bTraySupport)
+ ::CreateSystrayIcon(TRUE);
+
+ mi.cbSize = sizeof(mi);
+ mi.position = -500050005;
+ mi.hIcon = PluginConfig.g_iconContainer;
+ mi.pszContactOwner = NULL;
+ mi.pszName = LPGEN("&Messaging settings...");
+ mi.pszService = MS_TABMSG_SETUSERPREFS;
+ PluginConfig.m_UserMenuItem = (HANDLE)CallService(MS_CLIST_ADDCONTACTMENUITEM, 0, (LPARAM) & mi);
+
+ if(sendLater->isAvail()) {
+ mi.cbSize = sizeof(mi);
+ mi.position = -500050006;
+ mi.hIcon = 0;
+ mi.pszContactOwner = NULL;
+ mi.pszName = LPGEN("&Send later job list...");
+ mi.pszService = MS_TABMSG_SLQMGR;
+ PluginConfig.m_UserMenuItem = (HANDLE)CallService(MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM) & mi);
+ }
+ RestoreUnreadMessageAlerts();
+
+ RegisterWithUpdater();
+
+ ::RegisterFontServiceFonts();
+ ::CacheLogFonts();
+ ::Chat_ModulesLoaded(wParam, lParam);
+ if(PluginConfig.g_PopupWAvail||PluginConfig.g_PopupAvail)
+ TN_ModuleInit();
+
+ m_event_SettingChanged = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, DBSettingChanged);
+ m_event_ContactDeleted = HookEvent(ME_DB_CONTACT_DELETED, DBContactDeleted);
+
+ m_event_Dispatch = HookEvent(ME_DB_EVENT_ADDED, CMimAPI::DispatchNewEvent);
+ m_event_EventAdded = HookEvent(ME_DB_EVENT_ADDED, CMimAPI::MessageEventAdded);
+ if(PluginConfig.g_MetaContactsAvail) {
+ m_event_ME_MC_SUBCONTACTSCHANGED = HookEvent(ME_MC_SUBCONTACTSCHANGED, MetaContactEvent);
+ m_event_ME_MC_FORCESEND = HookEvent(ME_MC_FORCESEND, MetaContactEvent);
+ m_event_ME_MC_UNFORCESEND = HookEvent(ME_MC_UNFORCESEND, MetaContactEvent);
+ }
+ m_event_FontsChanged = HookEvent(ME_FONT_RELOAD, ::FontServiceFontsChanged);
+ return 0;
+}
+
+/**
+ * watches various important database settings and reacts accordingly
+ * needed to catch status, nickname and other changes in order to update open message
+ * sessions.
+ */
+
+int CGlobals::DBSettingChanged(WPARAM wParam, LPARAM lParam)
+{
+ DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam;
+ const char *szProto = NULL;
+ const char *setting = cws->szSetting;
+ HWND hwnd = 0;
+ CContactCache* c = 0;
+ bool fChanged = false, fNickChanged = false, fExtendedStatusChange = false;
+
+ hwnd = M->FindWindow((HANDLE)wParam);
+
+ if (hwnd == 0 && wParam != 0) { // we are not interested in this event if there is no open message window/tab
+ if(!strcmp(setting, "Status") || !strcmp(setting, "MyHandle") || !strcmp(setting, "Nick") || !strcmp(cws->szModule, SRMSGMOD_T)) {
+ c = CContactCache::getContactCache((HANDLE)wParam);
+ if(c) {
+ fChanged = c->updateStatus();
+ if(strcmp(setting, "Status"))
+ c->updateNick();
+ if(!strcmp(setting, "isFavorite") || !strcmp(setting, "isRecent"))
+ c->updateFavorite();
+ }
+ }
+ return(0);
+ }
+
+ if (wParam == 0 && !strcmp("Nick", setting)) {
+ M->BroadcastMessage(DM_OWNNICKCHANGED, 0, (LPARAM)cws->szModule);
+ return(0);
+ }
+
+ if(wParam) {
+ c = CContactCache::getContactCache((HANDLE)wParam);
+ if(c) {
+ szProto = c->getProto();
+ if(!strcmp(cws->szModule, SRMSGMOD_T)) { // catch own relevant settings
+ if(!strcmp(setting, "isFavorite") || !strcmp(setting, "isRecent"))
+ c->updateFavorite();
+ }
+ }
+ }
+
+ if(wParam == 0 && !lstrcmpA(setting, "Enabled")) {
+ if(PluginConfig.g_MetaContactsAvail && !lstrcmpA(cws->szModule, PluginConfig.szMetaName)) { // catch the disabled meta contacts
+ PluginConfig.bMetaEnabled = abs(M->GetByte(0, PluginConfig.szMetaName, "Enabled", -1));
+ cacheUpdateMetaChanged();
+ }
+ }
+
+ if (lstrcmpA(cws->szModule, "CList") && (szProto == NULL || lstrcmpA(cws->szModule, szProto)))
+ return(0);
+
+ if (PluginConfig.g_MetaContactsAvail && !lstrcmpA(cws->szModule, PluginConfig.szMetaName)) {
+ if(wParam != 0 && !lstrcmpA(setting, "Nick")) // filter out this setting to avoid infinite loops while trying to obtain the most online contact
+ return(0);
+ }
+
+ if (hwnd) {
+ if(c) {
+ fChanged = c->updateStatus();
+ fNickChanged = c->updateNick();
+ }
+ if (lstrlenA(setting) > 6 && lstrlenA(setting) < 9 && !strncmp(setting, "Status", 6)) {
+ fChanged = true;
+ if(c) {
+ c->updateMeta(true);
+ c->updateUIN();
+ }
+ }
+ else if (!strcmp(setting, "MirVer"))
+ PostMessage(hwnd, DM_CLIENTCHANGED, 0, 0);
+ else if (!strcmp(setting, "display_uid")) {
+ if(c)
+ c->updateUIN();
+ PostMessage(hwnd, DM_UPDATEUIN, 0, 0);
+ }
+ else if(lstrlenA(setting) > 6 && strstr("StatusMsg,XStatusMsg,XStatusName,XStatusId,ListeningTo", setting)) {
+ if(c) {
+ c->updateStatusMsg(setting);
+ fExtendedStatusChange = true;
+ }
+ }
+ if(fChanged || fNickChanged || fExtendedStatusChange)
+ PostMessage(hwnd, DM_UPDATETITLE, 0, 1);
+ if(fExtendedStatusChange)
+ PostMessage(hwnd, DM_UPDATESTATUSMSG, 0, 0);
+ if(fChanged) {
+ if(c && c->getStatus() == ID_STATUS_OFFLINE) { // clear typing notification in the status bar when contact goes offline
+ TWindowData* dat = c->getDat();
+ if(dat) {
+ dat->nTypeSecs = 0;
+ dat->showTyping = 0;
+ dat->szStatusBar[0] = 0;
+ PostMessage(c->getHwnd(), DM_UPDATELASTMESSAGE, 0, 0);
+ }
+ }
+ if(c)
+ PostMessage(PluginConfig.g_hwndHotkeyHandler, DM_LOGSTATUSCHANGE, MAKELONG(c->getStatus(), c->getOldStatus()), (LPARAM)c);
+ }
+ }
+ return(0);
+}
+
+/**
+ * event fired when a contact has been deleted. Make sure to close its message session
+ */
+
+int CGlobals::DBContactDeleted(WPARAM wParam, LPARAM lParam)
+{
+ if(wParam) {
+ CContactCache *c = CContactCache::getContactCache((HANDLE)wParam);
+ if(c)
+ c->deletedHandler();
+ }
+ return 0;
+}
+
+/**
+ * Handle events from metacontacts protocol. Basically, just update
+ * our contact cache and, if a message window exists, tell it to update
+ * relevant information.
+ */
+int CGlobals::MetaContactEvent(WPARAM wParam, LPARAM lParam)
+{
+ if(wParam) {
+ CContactCache *c = CContactCache::getContactCache((HANDLE)wParam);
+ if(c) {
+ c->updateMeta(true);
+ if(c->getHwnd()) {
+ c->updateUIN(); // only do this for open windows, not needed normally
+ ::PostMessage(c->getHwnd(), DM_UPDATETITLE, 0, 0);
+ }
+ }
+ }
+ return(0);
+}
+
+int CGlobals::PreshutdownSendRecv(WPARAM wParam, LPARAM lParam)
+{
+ HANDLE hContact;
+ int i;
+
+#if defined(__USE_EX_HANDLERS)
+ __try {
+#endif
+ if (PluginConfig.m_chat_enabled)
+ ::Chat_PreShutdown();
+
+ ::TN_ModuleDeInit();
+
+ while(pFirstContainer){
+ if (PluginConfig.m_HideOnClose)
+ PluginConfig.m_HideOnClose = FALSE;
+ ::SendMessage(pFirstContainer->hwnd, WM_CLOSE, 0, 1);
+ }
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+ M->WriteDword(hContact, SRMSGMOD_T, "messagecount", 0);
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+
+ for(i = 0; i < SERVICE_LAST; i++) {
+ if(PluginConfig.hSvc[i])
+ DestroyServiceFunction(PluginConfig.hSvc[i]);
+ }
+
+ ::SI_DeinitStatusIcons();
+ ::CB_DeInitCustomButtons();
+ /*
+ * the event API
+ */
+
+ DestroyHookableEvent(PluginConfig.m_event_MsgWin);
+ DestroyHookableEvent(PluginConfig.m_event_MsgPopup);
+
+ ::NEN_WriteOptions(&nen_options);
+ ::DestroyWindow(PluginConfig.g_hwndHotkeyHandler);
+
+ ::UnregisterClass(_T("TSStatusBarClass"), g_hInst);
+ ::UnregisterClass(_T("SideBarClass"), g_hInst);
+ ::UnregisterClassA("TSTabCtrlClass", g_hInst);
+ ::UnregisterClass(_T("RichEditTipClass"), g_hInst);
+ ::UnregisterClass(_T("TSHK"), g_hInst);
+#if defined(__USE_EX_HANDLERS)
+ }
+ __except(CGlobals::Ex_ShowDialog(GetExceptionInformation(), __FILE__, __LINE__, L"SHUTDOWN_STAGE2", false)) {
+ return(0);
+ }
+#endif
+ return 0;
+}
+
+int CGlobals::OkToExit(WPARAM wParam, LPARAM lParam)
+{
+ UnhookEvent(m_event_OkToExit);
+#if defined(__USE_EX_HANDLERS)
+ __try {
+#endif
+ ::CreateSystrayIcon(0);
+ ::CreateTrayMenus(0);
+
+ CWarning::destroyAll();
+
+ CMimAPI::m_shutDown = true;
+ UnhookEvent(m_event_EventAdded);
+ UnhookEvent(m_event_Dispatch);
+ UnhookEvent(m_event_PrebuildMenu);
+ UnhookEvent(m_event_SettingChanged);
+ UnhookEvent(m_event_ContactDeleted);
+ UnhookEvent(m_event_AvatarChanged);
+ UnhookEvent(m_event_MyAvatarChanged);
+ UnhookEvent(m_event_ProtoAck);
+ UnhookEvent(m_event_TypingEvent);
+ UnhookEvent(m_event_FontsChanged);
+ UnhookEvent(m_event_IcoLibChanged);
+ UnhookEvent(m_event_IconsChanged);
+
+ if(m_event_SmileyAdd)
+ UnhookEvent(m_event_SmileyAdd);
+
+ if(m_event_IEView)
+ UnhookEvent(m_event_IEView);
+
+ if(m_event_FoldersChanged)
+ UnhookEvent(m_event_FoldersChanged);
+
+ if(m_event_ME_MC_FORCESEND) {
+ UnhookEvent(m_event_ME_MC_FORCESEND);
+ UnhookEvent(m_event_ME_MC_SUBCONTACTSCHANGED);
+ UnhookEvent(m_event_ME_MC_UNFORCESEND);
+ }
+ ::ModPlus_PreShutdown(wParam, lParam);
+ PluginConfig.globalContainerSettings.fPrivate = false;
+ ::DBWriteContactSettingBlob(0, SRMSGMOD_T, CNT_KEYNAME, &PluginConfig.globalContainerSettings, sizeof(TContainerSettings));
+#if defined(__USE_EX_HANDLERS)
+ }
+ __except(CGlobals::Ex_ShowDialog(GetExceptionInformation(), __FILE__, __LINE__, L"SHUTDOWN_STAGE1", false)) {
+ return(0);
+ }
+#endif
+ return 0;
+}
+
+/**
+ * used on startup to restore flashing tray icon if one or more messages are
+ * still "unread"
+ */
+
+void CGlobals::RestoreUnreadMessageAlerts(void)
+{
+ CLISTEVENT cle = { 0 };
+ DBEVENTINFO dbei = { 0 };
+ TCHAR toolTip[256];
+ int windowAlreadyExists;
+ int usingReadNext = 0;
+
+ int autoPopup = M->GetByte(SRMSGMOD, SRMSGSET_AUTOPOPUP, SRMSGDEFSET_AUTOPOPUP);
+ HANDLE hDbEvent, hContact;
+
+ dbei.cbSize = sizeof(dbei);
+ cle.cbSize = sizeof(cle);
+ cle.hIcon = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE);
+ cle.pszService = "SRMsg/ReadMessage";
+ cle.flags = CLEF_TCHAR;
+
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ while (hContact) {
+
+ if(M->GetDword(hContact, "SendLater", "count", 0))
+ sendLater->addContact(hContact);
+
+ hDbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDFIRSTUNREAD, (WPARAM) hContact, 0);
+ while (hDbEvent) {
+ dbei.cbBlob = 0;
+ CallService(MS_DB_EVENT_GET, (WPARAM) hDbEvent, (LPARAM) & dbei);
+ if (!(dbei.flags & (DBEF_SENT | DBEF_READ)) && dbei.eventType == EVENTTYPE_MESSAGE) {
+ windowAlreadyExists = M->FindWindow(hContact) != NULL;
+ if (!usingReadNext && windowAlreadyExists)
+ continue;
+
+ cle.hContact = hContact;
+ cle.hDbEvent = hDbEvent;
+ mir_sntprintf(toolTip, safe_sizeof(toolTip), CTranslator::get(CTranslator::GEN_STRING_MESSAGEFROM),
+ (TCHAR *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, GCDNF_TCHAR));
+ cle.ptszTooltip = toolTip;
+ CallService(MS_CLIST_ADDEVENT, 0, (LPARAM) & cle);
+ }
+ hDbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDNEXT, (WPARAM) hDbEvent, 0);
+ }
+ hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0);
+ }
+}
+
+void CGlobals::logStatusChange(WPARAM wParam, const CContactCache *c)
+{
+ if(c == 0)
+ return;
+
+ HANDLE hContact = c->getContact();
+
+ bool fGlobal = PluginConfig.m_LogStatusChanges ? true : false;
+ DWORD dwMask = M->GetDword(hContact, SRMSGMOD_T, "mwmask", 0);
+ DWORD dwFlags = M->GetDword(hContact, SRMSGMOD_T, "mwflags", 0);
+
+ bool fLocal = ((dwMask & MWF_LOG_STATUSCHANGES) ? (dwFlags & MWF_LOG_STATUSCHANGES ? true : false) : false);
+
+ if(fGlobal || fLocal) {
+ /*
+ * don't log them if WE are logging off
+ */
+ if(CallProtoService(c->getProto(), PS_GETSTATUS, 0, 0) == ID_STATUS_OFFLINE)
+ return;
+
+ WORD wStatus, wOldStatus;
+
+ wStatus = LOWORD(wParam);
+ wOldStatus = HIWORD(wParam);
+
+ if(wStatus == wOldStatus)
+ return;
+
+ DBEVENTINFO dbei;
+ TCHAR buffer[450];
+ HANDLE hNewEvent;
+
+ TCHAR* szOldStatus = (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)wOldStatus, GSMDF_TCHAR);
+ TCHAR* szNewStatus = (TCHAR *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, (WPARAM)wStatus, GSMDF_TCHAR);
+
+ if(szOldStatus == 0 || szNewStatus == 0)
+ return;
+
+ if (c->isValid()) {
+ if (wStatus == ID_STATUS_OFFLINE)
+ mir_sntprintf(buffer, safe_sizeof(buffer), CTranslator::get(CTranslator::GEN_MSG_SIGNEDOFF));
+ else if (wOldStatus == ID_STATUS_OFFLINE)
+ mir_sntprintf(buffer, safe_sizeof(buffer), CTranslator::get(CTranslator::GEN_MSG_SIGNEDON), szNewStatus);
+ else
+ mir_sntprintf(buffer, safe_sizeof(buffer), CTranslator::get(CTranslator::GEN_MSG_CHANGEDSTATUS), szOldStatus, szNewStatus);
+ }
+
+ char *szMsg = M->utf8_encodeT(buffer);
+
+ dbei.pBlob = (PBYTE)szMsg;
+ dbei.cbBlob = lstrlenA(szMsg) + 1;
+ dbei.flags = DBEF_UTF | DBEF_READ;
+ dbei.cbSize = sizeof(dbei);
+ dbei.eventType = EVENTTYPE_STATUSCHANGE;
+ dbei.timestamp = time(NULL);
+ dbei.szModule = const_cast<char *>(c->getProto());
+ hNewEvent = (HANDLE) CallService(MS_DB_EVENT_ADD, (WPARAM) hContact, (LPARAM) & dbei);
+
+ mir_free(szMsg);
+ }
+}
+
+/**
+ * when the state of the meta contacts protocol changes from enabled to disabled
+ * (or vice versa), this updates the contact cache
+ *
+ * it is ONLY called from the DBSettingChanged() event handler when the relevant
+ * database value is touched.
+ */
+void CGlobals::cacheUpdateMetaChanged()
+{
+ CContactCache* c = CContactCache::m_cCache;
+ bool fMetaActive = (PluginConfig.g_MetaContactsAvail && PluginConfig.bMetaEnabled) ? true : false;
+
+ while(c) {
+ if(c->isMeta() && PluginConfig.bMetaEnabled == false) {
+ c->closeWindow();
+ c->resetMeta();
+ }
+
+ // meta contacts are enabled, but current contact is a subcontact - > close window
+
+ if(fMetaActive && c->isSubContact())
+ c->closeWindow();
+
+ // reset meta contact information, if metacontacts protocol became avail
+
+ if(fMetaActive && !strcmp(c->getProto(), PluginConfig.szMetaName))
+ c->resetMeta();
+
+ c = c->m_next;
+ }
+}
+
+/**
+ * on Windows 7, when using new task bar features (grouping mode and per tab
+ * previews), autoswitching does not work relieably, so it is disabled.
+ *
+ * @return: true if configuration dictates autoswitch
+ */
+bool CGlobals::haveAutoSwitch()
+{
+ if(m_bIsWin7) {
+ if(m_useAeroPeek && !CSkin::m_skinEnabled)
+ return(false);
+ }
+ return(m_AutoSwitchTabs ? true : false);
+}
+/**
+ * exception handling - copy error message to clip board
+ * @param hWnd: window handle of the edit control containing the error message
+ */
+void CGlobals::Ex_CopyEditToClipboard(HWND hWnd)
+{
+ SendMessage(hWnd, EM_SETSEL, 0, 65535L);
+ SendMessage(hWnd, WM_COPY, 0 , 0);
+ SendMessage(hWnd, EM_SETSEL, 0, 0);
+}
+
+INT_PTR CALLBACK CGlobals::Ex_DlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ WORD wNotifyCode, wID;
+
+ switch(uMsg) {
+ case WM_INITDIALOG: {
+ char szBuffer[2048];
+#ifdef _WIN64
+ sprintf(szBuffer,
+ "Exception %16.16X at address %16.16X occured in %s at line %d.\r\n\r\nEAX=%16.16X EBX=%16.16X ECX=%16.16X\r\nEDX=%16.16X ESI=%16.16X EDI=%16.16X\r\nEBP=%16.16X ESP=%16.16X EIP=%16.16X",
+ m_exRecord.ExceptionCode, m_exRecord.ExceptionAddress, m_exSzFile, m_exLine,
+ m_exCtx.Rax,m_exCtx.Rbx, m_exCtx.Rcx, m_exCtx.Rdx,
+ m_exCtx.Rsi, m_exCtx.Rdi, m_exCtx.Rbp, m_exCtx.Rsp, m_exCtx.Rip);
+#else
+ sprintf(szBuffer,
+ "Exception %8.8X at address %8.8X occured in %s at line %d.\r\n\r\nEAX=%8.8X EBX=%8.8X ECX=%8.8X\r\nEDX=%8.8X ESI=%8.8X EDI=%8.8X\r\nEBP=%8.8X ESP=%8.8X EIP=%8.8X",
+ m_exRecord.ExceptionCode, m_exRecord.ExceptionAddress, m_exSzFile, m_exLine,
+ m_exCtx.Eax,m_exCtx.Ebx, m_exCtx.Ecx, m_exCtx.Edx,
+ m_exCtx.Esi, m_exCtx.Edi, m_exCtx.Ebp, m_exCtx.Esp, m_exCtx.Eip);
+#endif
+ SetDlgItemTextA(hwndDlg, IDC_EXCEPTION_DETAILS, szBuffer);
+ SetFocus(GetDlgItem(hwndDlg, IDC_EXCEPTION_DETAILS));
+ SendDlgItemMessage(hwndDlg, IDC_EXCEPTION_DETAILS, WM_SETFONT, (WPARAM)GetStockObject(OEM_FIXED_FONT), 0);
+ SetDlgItemTextW(hwndDlg, IDC_EX_REASON, m_exReason);
+ Utils::enableDlgControl(hwndDlg, IDOK, m_exAllowContinue ? TRUE : FALSE);
+ }
+ break;
+
+ case WM_COMMAND:
+ wNotifyCode = HIWORD(wParam);
+ wID = LOWORD(wParam);
+ if (wNotifyCode == BN_CLICKED)
+ {
+ if (wID == IDOK || wID == IDCANCEL)
+ EndDialog(hwndDlg, wID);
+
+ if (wID == IDC_COPY_EXCEPTION)
+ Ex_CopyEditToClipboard(GetDlgItem(hwndDlg, IDC_EXCEPTION_DETAILS));
+ }
+
+ break;
+ }
+ return FALSE;
+}
+
+void CGlobals::Ex_Handler()
+{
+ if (m_exLastResult == IDCANCEL)
+ ExitProcess(1);
+}
+
+int CGlobals::Ex_ShowDialog(EXCEPTION_POINTERS *ep, const char *szFile, int line, wchar_t* szReason, bool fAllowContinue)
+{
+ char szDrive[MAX_PATH], szDir[MAX_PATH], szName[MAX_PATH], szExt[MAX_PATH];
+
+ _splitpath(szFile, szDrive, szDir, szName, szExt);
+ memcpy(&m_exRecord, ep->ExceptionRecord, sizeof(EXCEPTION_RECORD));
+ memcpy(&m_exCtx, ep->ContextRecord, sizeof(CONTEXT));
+
+ _snprintf(m_exSzFile, MAX_PATH, "%s%s", szName, szExt);
+ mir_sntprintf(m_exReason, 256, L"An application error has occured: %s", szReason);
+ m_exLine = line;
+ m_exLastResult = DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_EXCEPTION), 0, CGlobals::Ex_DlgProc, 0);
+ m_exAllowContinue = fAllowContinue;
+ if(IDCANCEL == m_exLastResult)
+ ExitProcess(1);
+ return 1;
+}