summaryrefslogtreecommitdiff
path: root/!Deprecated/NewAwaySysMod/AwaySys.cpp
diff options
context:
space:
mode:
Diffstat (limited to '!Deprecated/NewAwaySysMod/AwaySys.cpp')
-rw-r--r--!Deprecated/NewAwaySysMod/AwaySys.cpp1025
1 files changed, 1025 insertions, 0 deletions
diff --git a/!Deprecated/NewAwaySysMod/AwaySys.cpp b/!Deprecated/NewAwaySysMod/AwaySys.cpp
new file mode 100644
index 0000000000..d573009ede
--- /dev/null
+++ b/!Deprecated/NewAwaySysMod/AwaySys.cpp
@@ -0,0 +1,1025 @@
+/*
+ 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.
+*/
+
+#include "Common.h"
+#include "m_genmenu.h"
+#include "m_idle.h"
+#include "m_statusplugins.h"
+#include "m_NewAwaySys.h"
+#include "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>
+#include <process.h> // needed for MSVC 7 msvcr7*.dll patch
+
+HINSTANCE g_hInstance;
+
+int hLangpack = 0;
+LIST<void> hHooks(5), hServices(5);
+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_PTR (*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",
+ my_make_version(PRODUCTVER), // see VersionNo.h
+ "New Away System Mod plugin for Miranda IM.",
+ "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,
+ {0xb2dd9270, 0xce5e, 0x11df, {0xbd, 0x3d, 0x8, 0x0, 0x20, 0xc, 0x9a, 0x66}}
+};
+
+BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ g_hInstance = hinstDLL;
+ return TRUE;
+}
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_SRAWAY, MIID_LAST}; // TODO: add MIID_WHOISREADING here if there'll be any some time in future..
+
+extern "C" __declspec(dllexport) PLUGININFOEX *MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ return &pluginInfo;
+}
+
+//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
+ mir_sntprintf(szSetStr, SIZEOF(szSetStr), TranslateT("Set %s message for the contact"), CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, iMode, GSMDF_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
+ mir_sntprintf(szReadStr, SIZEOF(szReadStr), TranslateT("Re&ad %s Message"), CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, iContactMode, GSMDF_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_PTR 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_PTR 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_PTR 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_PTR 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_PTR 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))
+ {
+ mir_sntprintf(Title, SIZEOF(Title), TranslateT("Enable autoreply when you are %s"), (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, StatusMode, GSMDF_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))
+ {
+ mir_sntprintf(Title, SIZEOF(Title), TranslateT("Don't send status message when you are %s"), (TCHAR*)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, StatusMode, GSMDF_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_PTR 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, GSMDF_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)))
+ {
+ mir_sntprintf(Result.GetBuffer(16), 16, _T("%d"), DBGetContactSettingWord(ai->fi->hContact, MOD_NAME, DB_REQUESTCOUNT, 0));
+ Result.ReleaseBuffer();
+ } else if (!lstrcmp(ai->targv[0], _T(VAR_MESSAGENUM)))
+ {
+ mir_sntprintf(Result.GetBuffer(16), 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
+ {
+ mir_sntprintf(Result, 256, TranslateT("%d hours"), ul_Now.LowPart / 3600);
+ } else if (ul_Now.LowPart >= 120) // more than 2 minutes
+ {
+ mir_sntprintf(Result, 256, TranslateT("%d minutes"), ul_Now.LowPart / 60);
+ } else
+ {
+ mir_sntprintf(Result, 256, 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_PTR srvFreeVarMem(WPARAM wParam, LPARAM lParam)
+{
+ if (!lParam)
+ {
+ return -1;
+ }
+ free((void*)lParam);
+ return 0;
+}
+
+
+static INT_PTR 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
+ {
+ const 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.insert(hHook);
+ ICQProtoList[CurProtoIndex] = proto[i]->szName;
+ CurProtoIndex++;
+ }
+ }
+ }
+ hServices.insert(CreateServiceFunction(MS_AWAYSYS_SETCONTACTSTATMSG, SetContactStatMsg));
+ hServices.insert(CreateServiceFunction(MS_AWAYSYS_AUTOREPLY_TOGGLE, ToggleSendOnEvent));
+ hServices.insert(CreateServiceFunction(MS_AWAYSYS_AUTOREPLY_ON, srvAutoreplyOn));
+ hServices.insert(CreateServiceFunction(MS_AWAYSYS_AUTOREPLY_OFF, srvAutoreplyOff));
+ hServices.insert(CreateServiceFunction(MS_AWAYSYS_AUTOREPLY_USEDEFAULT, srvAutoreplyUseDefault));
+ hServices.insert(CreateServiceFunction(MS_NAS_GETSTATEA, GetStateA));
+ hServices.insert(CreateServiceFunction(MS_NAS_SETSTATEA, SetStateA));
+ hServices.insert(CreateServiceFunction(MS_NAS_GETSTATEW, GetStateW));
+ hServices.insert(CreateServiceFunction(MS_NAS_SETSTATEW, SetStateW));
+ hServices.insert(CreateServiceFunction(MS_NAS_INVOKESTATUSWINDOW, InvokeStatusWindow));
+ hServices.insert(CreateServiceFunction(MS_AWAYMSG_GETSTATUSMSG, GetStatusMsg));
+// and old AwaySysMod service, for compatibility reasons
+ hServices.insert(CreateServiceFunction(MS_AWAYSYS_SETSTATUSMODE, SetStatusMode));
+//NightFox: none;
+// hHooks.insert(HookEvent(ME_TTB_MODULELOADED, Create_TopToolbar));
+ hHooks.insert(HookEvent(ME_OPT_INITIALISE, OptsDlgInit));
+ hHooks.insert(HookEvent(ME_CLIST_STATUSMODECHANGE, StatusChanged));
+ hHooks.insert(HookEvent(ME_CS_STATUSCHANGEEX, CSStatusChange)); // for compatibility with StartupStatus and AdvancedAutoAway
+ hHooks.insert(HookEvent(ME_DB_EVENT_FILTER_ADD, MsgEventAdded));
+ hHooks.insert(HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PreBuildContactMenu));
+ hHooks.insert(HookEvent(ME_SKIN_ICONSCHANGED, IconsChanged));
+ hHooks.insert(HookEvent(ME_IDLE_CHANGED, IdleChangeEvent));
+ hHooks.insert(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 = Menu_AddMainMenuItem(&mi);
+
+ ZeroMemory(&mi, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ mi.position = -2000005000;
+ mi.flags = CMIF_TCHAR | CMIF_NOTOFFLINE | CMIF_HIDDEN;
+ mi.ptszName = LPGENT("Read status message"); // never seen...
+ mi.pszService = MS_AWAYMSG_SHOWAWAYMSG;
+ g_hReadStatMenuItem = Menu_AddContactMenuItem(&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 = Menu_AddContactMenuItem(&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 = Menu_AddContactMenuItem(&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 = Menu_AddContactMenuItem(&mi);
+
+ mi.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_SOE_DISABLED));
+ mi.ptszName = LPGENT("Off");
+ mi.pszService = MS_AWAYSYS_AUTOREPLY_OFF;
+ g_hAutoreplyOffContactMenuItem = Menu_AddContactMenuItem(&mi);
+
+ mi.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_DOT));
+ mi.ptszName = LPGENT("Use the default setting");
+ mi.pszService = MS_AWAYSYS_AUTOREPLY_USEDEFAULT;
+ g_hAutoreplyUseDefaultContactMenuItem = Menu_AddContactMenuItem(&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.insert(CreateServiceFunction(MS_AWAYMSG_SHOWAWAYMSG, GetContactStatMsg));
+
+ SkinAddNewSoundEx(AWAYSYS_STATUSMSGREQUEST_SOUND, NULL, LPGEN("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.insert(CreateServiceFunction(MS_AWAYSYS_FREEVARMEM, srvFreeVarMem));
+ hServices.insert(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);
+ }
+ }
+
+ //NightFox
+ HookEvent(ME_MODERNOPT_INITIALIZE, ModernOptInitialise);
+
+
+ return 0;
+}
+
+
+extern "C" int __declspec(dllexport) Load(void)
+{
+
+ mir_getLP( &pluginInfo );
+
+ hHooks.insert(HookEvent(ME_SYSTEM_MODULESLOADED, MirandaLoaded));
+ 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
+
+ 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()
+{
+ CloseHandle(hMainThread);
+ int i;
+ for (i = 0; i < hHooks.getCount(); i++)
+ UnhookEvent(hHooks[i]);
+
+ for (i = 0; i < hServices.getCount(); i++)
+ DestroyServiceFunction(hServices[i]);
+
+ return 0;
+}