From 78d71d2cad6f243c6ff31d41380b8c5b58407de5 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Thu, 17 May 2012 17:37:22 +0000 Subject: added some plugins git-svn-id: http://svn.miranda-ng.org/main/trunk@20 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Boltun/actionQueue.cpp | 256 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 plugins/Boltun/actionQueue.cpp (limited to 'plugins/Boltun/actionQueue.cpp') diff --git a/plugins/Boltun/actionQueue.cpp b/plugins/Boltun/actionQueue.cpp new file mode 100644 index 0000000000..7040778c85 --- /dev/null +++ b/plugins/Boltun/actionQueue.cpp @@ -0,0 +1,256 @@ +//*********************************************************** +// Copyright 2003-2008 Alexander S. Kiselev, Valentin Pavlyuchenko +// +// This file is part of Boltun. +// +// Boltun 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. +// +// Boltun 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 Boltun. If not, see . +// +//*********************************************************** + +#include "actionQueue.h" +#include "config.h" +#include "boltun.h" +#include "Engine/tstring.h" +#include "Engine/TalkEngine.h" + +#include +#include +#include +#include "Engine/CriticalSection.h" +#ifdef _DEBUG +#include +#endif + +#define MIRANDA_VER 0x0700 +#include "newpluginapi.h" +#include "m_database.h" +#include "m_system.h" +#include "m_protosvc.h" + +using namespace std; + +extern TalkBot* bot; + +typedef void (*ActionHandler)(HANDLE hContact, const TalkBot::MessageInfo *inf); + +typedef struct _QueueElement { + HANDLE hContact; + const TalkBot::MessageInfo *inf; + ActionHandler Handler; + bool Sticky; + int TimeOffset; + _QueueElement(HANDLE contact, ActionHandler handler, int timeOffset, const TalkBot::MessageInfo *info = NULL, bool sticky = false) + :hContact(contact), Handler(handler), TimeOffset(timeOffset), inf(info), Sticky(sticky) + { + } +} QueueElement; + +static list actionQueue; +static set typingContacts; +UINT_PTR timerID = 0; + +CriticalSection cs; +CriticalSection typingContactsLock; + +void UpdateTimer(); + +VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) +{ + cs.Enter(); + QueueElement q = actionQueue.front(); + actionQueue.pop_front(); + UpdateTimer(); + cs.Leave(); + q.Handler(q.hContact, q.inf); +} + +void UpdateTimer() +{ + if (timerID) + KillTimer(NULL, timerID); + if (actionQueue.size()) + timerID = SetTimer(NULL, 0, actionQueue.front().TimeOffset, TimerProc); + else + timerID = 0; +} + +static bool NotifyTyping(HANDLE hContact) +{ + int res = DBGetContactSettingByte(hContact, "SRMsg", "SupportTyping", 2); + if (res == 2) + res = DBGetContactSettingByte(NULL, "SRMsg", "DefaultTyping", 1); + return res != 0; +} + +static char *MsgServiceName(HANDLE hContact) +{ +#ifdef _UNICODE + char szServiceName[100]; + char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (szProto == NULL) + return PSS_MESSAGE; + + mir_snprintf(szServiceName, sizeof(szServiceName), "%s%sW", szProto, PSS_MESSAGE); + if (ServiceExists(szServiceName)) + return PSS_MESSAGE "W"; +#endif + return PSS_MESSAGE; +} + +static void TimerAnswer(HANDLE hContact, const TalkBot::MessageInfo* info) +{ + DBEVENTINFO ldbei; + int size = info->Answer.length() + 1; + int bufsize = size; + char* msg; +#ifdef UNICODE + bufsize *= sizeof(TCHAR) + 1; + msg = new char[bufsize]; + //msg[size - 1] = '\0'; + + if (!WideCharToMultiByte(CP_ACP, 0, info->Answer.c_str(), -1, msg, size, + NULL, NULL)) + FillMemory(msg, size - 1, '-'); //In case of fault return "----" in ANSI part + CopyMemory(msg + size, info->Answer.c_str(), size * 2); +#else + msg = respItem->szMes; +#endif + + CallContactService(hContact, MsgServiceName(hContact), PREF_TCHAR, (LPARAM)msg); + + ZeroMemory(&ldbei, sizeof(ldbei)); + ldbei.cbSize = sizeof(ldbei); + //FIXME: Error may happen + ldbei.cbBlob = bufsize; + ldbei.pBlob = (PBYTE)(void*)msg; + ldbei.eventType = EVENTTYPE_MESSAGE; + ldbei.flags = DBEF_SENT; + ldbei.szModule = BOLTUN_NAME; + ldbei.timestamp = (DWORD)time(NULL); + + CallService(MS_DB_EVENT_ADD, (WPARAM)hContact, (LPARAM)&ldbei); + bot->AnswerGiven(hContact, *info); + delete info; +#ifdef UNICODE + delete msg; +#endif + typingContactsLock.Enter(); + typingContacts.erase(hContact); + typingContactsLock.Leave(); +} + +static void StartTyping(HANDLE hContact, const TalkBot::MessageInfo*) +{ + CallService(MS_PROTO_SELFISTYPING, (WPARAM)hContact, + (LPARAM)PROTOTYPE_SELFTYPING_ON); + typingContactsLock.Enter(); + typingContacts.insert(hContact); + typingContactsLock.Leave(); +} + +void DoAnswer(HANDLE hContact, const TalkBot::MessageInfo *info, bool sticky = false) +{ + if (info->Answer[0] == _T('\0')) + return; + int waitTime, thinkTime = 0; + int defWaitTime = Config.AnswerPauseTime * 1000; + if (Config.PauseDepends) + waitTime = defWaitTime * info->Answer.length() / 25; + else + waitTime = defWaitTime; + if (Config.PauseRandom) + { + //Let it be up to 4 times longer. + waitTime = waitTime * (rand() % 300) / 100 + waitTime; + } + if (waitTime == 0) + waitTime = 50; //it's essential, because otherwise message will be added later + //then its response, that will cause incorrect ordering of + //messages in the opened history (reopening will + //help, but anyway it's no good) + if (NotifyTyping(hContact) && Config.AnswerThinkTime) + { + thinkTime = Config.AnswerThinkTime * 1000; + if (Config.PauseRandom) + { + //Let it be up to 4 times longer. + thinkTime = thinkTime * (rand() % 300) / 100 + thinkTime; + } + } + cs.Enter(); + //Check if this contact's timer handler is now waiting for a cs. + bool needTimerRearrange = false; + if (!actionQueue.empty() && actionQueue.front().hContact == hContact) + { + needTimerRearrange = true; + KillTimer(NULL, timerID); + cs.Leave(); + cs.Enter(); + } + if (!actionQueue.empty()) + { + list::iterator it = actionQueue.end(); + it--; + while (true) + { + if ((*it).hContact == hContact) + { + if ((*it).Sticky) + break; + list::iterator tmp = it; + if (tmp != actionQueue.begin()) + tmp--; + actionQueue.erase(it); + it = tmp; + if (actionQueue.empty()) + break; + } + if (it == actionQueue.begin()) + break; + it--; + } + } + typingContactsLock.Enter(); + if (typingContacts.find(hContact) != typingContacts.end()) + { + CallService(MS_PROTO_SELFISTYPING, (WPARAM)hContact, (LPARAM)PROTOTYPE_SELFTYPING_OFF); + typingContacts.erase(hContact); + } + typingContactsLock.Leave(); + if (actionQueue.empty()) + needTimerRearrange = true; + if (thinkTime) + actionQueue.push_back(QueueElement(hContact, StartTyping, thinkTime, NULL, sticky)); + actionQueue.push_back(QueueElement(hContact, TimerAnswer, waitTime, info, sticky)); + if (needTimerRearrange) + UpdateTimer(); + cs.Leave(); +} + +void AnswerToContact(HANDLE hContact, const TCHAR* messageToAnswer) +{ + if (Config.TalkWarnContacts && DBGetContactSettingByte(hContact, BOLTUN_KEY, + DB_CONTACT_WARNED, FALSE) == FALSE) + { + DoAnswer(hContact, new TalkBot::MessageInfo((const TCHAR*)Config.WarnText), true); + DBWriteContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_WARNED, TRUE); + } + else + DoAnswer(hContact, bot->Reply(hContact, messageToAnswer, false)); +} + +void StartChatting(HANDLE hContact) +{ + DoAnswer(hContact, new TalkBot::MessageInfo(bot->GetInitMessage(hContact)), true); +} -- cgit v1.2.3