summaryrefslogtreecommitdiff
path: root/plugins/NewAwaySysMod/src/MsgEventAdded.cpp
diff options
context:
space:
mode:
authorGeorge Hazan <george.hazan@gmail.com>2014-02-20 18:43:33 +0000
committerGeorge Hazan <george.hazan@gmail.com>2014-02-20 18:43:33 +0000
commitb26198b243f682cfd66aa5d06acbb62d6d35206c (patch)
tree0bb4c9efbcb9b3418a82f804ca5825e055f6169e /plugins/NewAwaySysMod/src/MsgEventAdded.cpp
parentb9567416b251f589ba5ac4ed1dadc644e79d6912 (diff)
attempt to revive NAS
git-svn-id: http://svn.miranda-ng.org/main/trunk@8194 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/NewAwaySysMod/src/MsgEventAdded.cpp')
-rw-r--r--plugins/NewAwaySysMod/src/MsgEventAdded.cpp291
1 files changed, 291 insertions, 0 deletions
diff --git a/plugins/NewAwaySysMod/src/MsgEventAdded.cpp b/plugins/NewAwaySysMod/src/MsgEventAdded.cpp
new file mode 100644
index 0000000000..6995a6c683
--- /dev/null
+++ b/plugins/NewAwaySysMod/src/MsgEventAdded.cpp
@@ -0,0 +1,291 @@
+/*
+ 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(MCONTACT hContact, TCString Reply): hContact(hContact), Reply(Reply) {}
+
+ MCONTACT 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 = GetContactProto(ad->hContact);
+ if (!szProto)
+ {
+ _ASSERT(0);
+ return;
+ }
+
+ int ReplyLen = (ad->Reply.GetLen() + 1) * (sizeof(char) + sizeof(WCHAR));
+ PBYTE pBuf = (PBYTE)malloc(ReplyLen);
+ memcpy(pBuf, _T2A(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);
+
+ 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);
+
+ dbeo.cbBlob = ReplyLen;
+ dbeo.pBlob = pBuf;
+
+ 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)
+ db_event_add(ad->hContact, &dbeo);
+ }
+
+ free(pBuf);
+ delete ad;
+}
+
+
+int IsSRMsgWindowOpen(MCONTACT 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(MCONTACT hMetaContact, DWORD timestamp, int bMsgWindowIsOpen): hMetaContact(hMetaContact), timestamp(timestamp), bMsgWindowIsOpen(bMsgWindowIsOpen) {};
+
+ MCONTACT hMetaContact;
+ DWORD timestamp;
+ int bMsgWindowIsOpen;
+};
+
+TMyArray<CMetacontactEvent> MetacontactEvents;
+
+
+int MsgEventAdded(WPARAM hContact, LPARAM lParam)
+{
+ 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 = GetContactProto(hContact);
+ 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) {
+ MCONTACT hMetaContact;
+ if (ServiceExists(MS_MC_GETMETACONTACT) && (hMetaContact = 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)
+ {
+ db_set_w(hContact, MOD_NAME, DB_MESSAGECOUNT, db_get_w(hContact, MOD_NAME, DB_MESSAGECOUNT, 0) + 1); // increment message counter
+ }
+ if (AutoreplyOptData.GetValue(StatusModeList[I].DisableReplyCtlID))
+ {
+ return 0;
+ }
+ MCONTACT 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_CONTACT_ID && db_get_b(hContactForSettings, "CList", "NotOnList", 0))
+ {
+ hContactForSettings = INVALID_CONTACT_ID; // 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 = db_get_w(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 = db_get_dw(hContact, szProto, "UIN", 0);
+ }
+ int SendCount = AutoreplyOptData.GetValue(IDC_REPLYDLG_SENDCOUNT);
+ if ((AutoreplyOptData.GetValue(IDC_REPLYDLG_DONTSENDTOICQ) && UIN) || // an icq contact
+ (SendCount != -1 && db_get_b(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;
+ }
+ db_set_b(hContact, MOD_NAME, DB_SENDCOUNT, db_get_b(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;
+ mir_free(szResult);
+ }
+ }
+ if (Reply.GetLen())
+ {
+ CAutoreplyData *ad = new CAutoreplyData(hContact, Reply);
+ mir_forkthread(AutoreplyDelayThread, ad);
+ }
+ return 0;
+}