From f17646aaa5e410a2e673e0de69358c9d5e09f63b Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Mon, 9 Jul 2012 06:47:31 +0000 Subject: Boltun: changed folder structure git-svn-id: http://svn.miranda-ng.org/main/trunk@866 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/Boltun/Boltun.rc | 155 ------- plugins/Boltun/Boltun_10.vcxproj | 36 +- plugins/Boltun/Boltun_10.vcxproj.filters | 24 +- plugins/Boltun/TODO.txt | 35 -- plugins/Boltun/actionQueue.cpp | 254 ---------- plugins/Boltun/actionQueue.h | 30 -- plugins/Boltun/boltun-translation.txt | 23 - plugins/Boltun/boltun.cpp | 713 ----------------------------- plugins/Boltun/boltun.h | 74 --- plugins/Boltun/config.cpp | 159 ------- plugins/Boltun/config.h | 157 ------- plugins/Boltun/docs/TODO.txt | 35 ++ plugins/Boltun/docs/boltun-translation.txt | 23 + plugins/Boltun/docs/mind.txt | 142 ++++++ plugins/Boltun/docs/readme.txt | 124 +++++ plugins/Boltun/mind.txt | 142 ------ plugins/Boltun/readme.txt | 124 ----- plugins/Boltun/res/Boltun.rc | 155 +++++++ plugins/Boltun/resource.h | 46 -- plugins/Boltun/src/actionQueue.cpp | 254 ++++++++++ plugins/Boltun/src/actionQueue.h | 30 ++ plugins/Boltun/src/boltun.cpp | 713 +++++++++++++++++++++++++++++ plugins/Boltun/src/boltun.h | 74 +++ plugins/Boltun/src/config.cpp | 159 +++++++ plugins/Boltun/src/config.h | 157 +++++++ plugins/Boltun/src/resource.h | 46 ++ 26 files changed, 1940 insertions(+), 1944 deletions(-) delete mode 100644 plugins/Boltun/Boltun.rc delete mode 100644 plugins/Boltun/TODO.txt delete mode 100644 plugins/Boltun/actionQueue.cpp delete mode 100644 plugins/Boltun/actionQueue.h delete mode 100644 plugins/Boltun/boltun-translation.txt delete mode 100644 plugins/Boltun/boltun.cpp delete mode 100644 plugins/Boltun/boltun.h delete mode 100644 plugins/Boltun/config.cpp delete mode 100644 plugins/Boltun/config.h create mode 100644 plugins/Boltun/docs/TODO.txt create mode 100644 plugins/Boltun/docs/boltun-translation.txt create mode 100644 plugins/Boltun/docs/mind.txt create mode 100644 plugins/Boltun/docs/readme.txt delete mode 100644 plugins/Boltun/mind.txt delete mode 100644 plugins/Boltun/readme.txt create mode 100644 plugins/Boltun/res/Boltun.rc delete mode 100644 plugins/Boltun/resource.h create mode 100644 plugins/Boltun/src/actionQueue.cpp create mode 100644 plugins/Boltun/src/actionQueue.h create mode 100644 plugins/Boltun/src/boltun.cpp create mode 100644 plugins/Boltun/src/boltun.h create mode 100644 plugins/Boltun/src/config.cpp create mode 100644 plugins/Boltun/src/config.h create mode 100644 plugins/Boltun/src/resource.h (limited to 'plugins/Boltun') diff --git a/plugins/Boltun/Boltun.rc b/plugins/Boltun/Boltun.rc deleted file mode 100644 index 4ae46eea47..0000000000 --- a/plugins/Boltun/Boltun.rc +++ /dev/null @@ -1,155 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "afxres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (Canada) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENC) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_CAN -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_MAINBOLTUN ICON "res\\boltun.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// SMILES -// - -IDR_SMILES SMILES "res\\smiles.dat" - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""afxres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -IDD_MAIN DIALOGEX 0, 0, 307, 231 -STYLE DS_SETFONT | WS_CHILD | WS_BORDER -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - GROUPBOX "Boltun",IDC_PLUGINRM,5,2,297,222 - CONTROL "Boltun Autochat everybody",IDC_EVERYBODY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,20,230,10 - CONTROL "Boltun Autochat everybody not in contact list",IDC_NOTINLIST, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,33,230,10 - CONTROL "Boltun Autochat everybody while away",IDC_AUTOAWAY, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,46,230,10 - CONTROL "Warn contacts Boltun is chatting",IDC_WARN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,59,230,10 - CONTROL "Mark replied messages as read",IDC_MARKREAD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,72,230,10 - EDITTEXT IDC_WAITTIME,26,161,24,12,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "sec",IDC_LSEC,53,161,72,8 - EDITTEXT IDC_WARNTXT,17,97,272,31,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL - GROUPBOX "Warning text",IDC_LWARN,12,85,283,50 - GROUPBOX "Time before the answer",IDC_LWAITTIME,12,138,283,72 - CONTROL "Typing time depends on message length (in chars)",IDC_PAUSEDEPENDS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,178,270,11 - CONTROL "Typing and thinking time can be much longer",IDC_PAUSERANDOM, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,193,270,10 - LTEXT "Typing time (for a message of 4 words):",IDC_STATIC,21,148,145,8 - LTEXT "Thinking time:",IDC_STATIC,173,148,111,8 - EDITTEXT IDC_THINKTIME,177,161,24,12,ES_AUTOHSCROLL | ES_NUMBER - LTEXT "sec",IDC_LSEC2,205,161,72,8 -END - -IDD_ENGINE DIALOGEX 0, 0, 307, 231 -STYLE DS_SETFONT | WS_CHILD | WS_BORDER -EXSTYLE WS_EX_CONTROLPARENT -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - GROUPBOX "Engine",IDC_PLUGINRM,5,48,297,174 - EDITTEXT IDC_MINDFILE,12,19,210,14,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP - PUSHBUTTON "...",IDC_BTNPATH,226,18,16,16 - GROUPBOX "Base of remarks",IDC_TXTREPLICPATH,5,6,297,36 - PUSHBUTTON "Reload",IDC_BTNRELOAD,246,18,52,16 - CONTROL "Stay silent, if have no good aswers",IDC_ENGINE_SILENT, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,62,283,10 - CONTROL "Start answers with a lowercase letter",IDC_ENGINE_LOWERCASE, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,94,282,10 - CONTROL "Don't use ""I don't understand""-like answers",IDC_ENGINE_UNDERSTAND_ALWAYS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,27,78,248,10 -END - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO -BEGIN - IDD_MAIN, DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 300 - TOPMARGIN, 7 - BOTTOMMARGIN, 224 - END - - IDD_ENGINE, DIALOG - BEGIN - RIGHTMARGIN, 306 - END -END -#endif // APSTUDIO_INVOKED - -#endif // English (Canada) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED - diff --git a/plugins/Boltun/Boltun_10.vcxproj b/plugins/Boltun/Boltun_10.vcxproj index fc830ad499..6da050cdd2 100644 --- a/plugins/Boltun/Boltun_10.vcxproj +++ b/plugins/Boltun/Boltun_10.vcxproj @@ -75,11 +75,10 @@ OnlyExplicitInline Size ..\..\include;..\ExternalAPI;%(AdditionalIncludeDirectories) - NDEBUG;BOLTUN_EXPORTS;WIN32;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_UNICODE;UNICODE;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions) + WIN32;NDEBUG;_WINDOWS;_USRDLL;BOLTUN_EXPORTS;%(PreprocessorDefinitions) true true Level3 - 4996;%(DisableSpecificWarnings) NDEBUG;%(PreprocessorDefinitions) @@ -100,11 +99,10 @@ OnlyExplicitInline Size ..\..\include;..\ExternalAPI;%(AdditionalIncludeDirectories) - NDEBUG;BOLTUN_EXPORTS;WIN64;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;_UNICODE;UNICODE;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions) + WIN64;NDEBUG;_WINDOWS;_USRDLL;BOLTUN_EXPORTS;%(PreprocessorDefinitions) true true Level3 - 4996;%(DisableSpecificWarnings) NDEBUG;%(PreprocessorDefinitions) @@ -123,13 +121,12 @@ Disabled ..\..\include;..\ExternalAPI;%(AdditionalIncludeDirectories) - _DEBUG;WIN32;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;BOLTUN_EXPORTS;_UNICODE;UNICODE;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions) + WIN32;_DEBUG;_WINDOWS;_USRDLL;BOLTUN_EXPORTS;%(PreprocessorDefinitions) true EnableFastChecks MultiThreadedDebugDLL Level3 EditAndContinue - 4996;%(DisableSpecificWarnings) _DEBUG;%(PreprocessorDefinitions) @@ -147,12 +144,11 @@ Disabled ..\..\include;..\ExternalAPI;%(AdditionalIncludeDirectories) - _DEBUG;WIN64;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;BOLTUN_EXPORTS;_UNICODE;UNICODE;_WIN32_WINNT=0x0501;%(PreprocessorDefinitions) + WIN64;_DEBUG;_WINDOWS;_USRDLL;BOLTUN_EXPORTS;%(PreprocessorDefinitions) EnableFastChecks MultiThreadedDebugDLL Level3 ProgramDatabase - 4996;%(DisableSpecificWarnings) _DEBUG;%(PreprocessorDefinitions) @@ -166,9 +162,9 @@ - - - + + + @@ -176,10 +172,10 @@ - - - - + + + + @@ -194,13 +190,13 @@ - - - - + + + + - + diff --git a/plugins/Boltun/Boltun_10.vcxproj.filters b/plugins/Boltun/Boltun_10.vcxproj.filters index e025146d37..03a5b48eb1 100644 --- a/plugins/Boltun/Boltun_10.vcxproj.filters +++ b/plugins/Boltun/Boltun_10.vcxproj.filters @@ -21,13 +21,13 @@ - + Source Files - + Source Files - + Source Files @@ -47,16 +47,16 @@ - + Header Files - + Header Files - + Header Files - + Header Files @@ -94,16 +94,16 @@ Resource Files - - - - + + + + Source Files - + Resource Files diff --git a/plugins/Boltun/TODO.txt b/plugins/Boltun/TODO.txt deleted file mode 100644 index 6ea2151d2d..0000000000 --- a/plugins/Boltun/TODO.txt +++ /dev/null @@ -1,35 +0,0 @@ -TODO list: - --------------------------------------------------------- -Release-critical: - -- Add study capability to engine - -Done: -- Add reaction for duplicate phrases. -- Add aliases. -- Check for critical section double enter -- Multicontact talk support in engine -- Add "Start talking" option to cantact menu. -- Check bot warning. -- Add "be silent, not stupid" to options -- Add start answers with a little letter. -- Add README about bot algorithm. -- Add README for mind file format. -- Add "don't use "don't understand"" option -- Division between question and non-question sentenses -- Empty keywords or specials should not be loaded -- Check "каким-либо" -- Check :-) on "ок" -- Add answer-on status info to the readme. -- Make AI options dependent. -- Update mind.txt with UpdateStartChar -- Sort keywords matches by priority -- Use chooser everywhere - --------------------------------------------------------- -Future: -- Speed-up loading -- Load mind from UTF8 files -- Expert mode support -- Add different choises of reaction for message series. diff --git a/plugins/Boltun/actionQueue.cpp b/plugins/Boltun/actionQueue.cpp deleted file mode 100644 index c464c92f39..0000000000 --- a/plugins/Boltun/actionQueue.cpp +++ /dev/null @@ -1,254 +0,0 @@ -//*********************************************************** -// 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 0x0A00 -#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) -{ - - 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"; - - return PSS_MESSAGE; -} - -static void TimerAnswer(HANDLE hContact, const TalkBot::MessageInfo* info) -{ - DBEVENTINFO ldbei; - int size = (int)info->Answer.length() + 1; - int bufsize = size; - char* msg; - - 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); - - - 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; - - delete msg; - - 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 * (int)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); -} diff --git a/plugins/Boltun/actionQueue.h b/plugins/Boltun/actionQueue.h deleted file mode 100644 index 78f6ce5f9e..0000000000 --- a/plugins/Boltun/actionQueue.h +++ /dev/null @@ -1,30 +0,0 @@ -//*********************************************************** -// 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 . -// -//*********************************************************** - -#ifndef ACTIONQUEUE_H -#define ACTIONQUEUE_H - -#include - -void AnswerToContact(HANDLE hContact, const TCHAR* messageToAnswer); - -void StartChatting(HANDLE hContact); - -#endif /* ACTIONQUEUE_H */ \ No newline at end of file diff --git a/plugins/Boltun/boltun-translation.txt b/plugins/Boltun/boltun-translation.txt deleted file mode 100644 index c3bce4a2f2..0000000000 --- a/plugins/Boltun/boltun-translation.txt +++ /dev/null @@ -1,23 +0,0 @@ -; Common strings that belong to many files -;[] - -; ../../plugins/Boltun/Boltun.rc -;[Base of remarks] -;[Boltun] -;[Boltun Autochat everybody] -;[Boltun Autochat everybody not in contact list] -;[Boltun Autochat everybody while away] -;[Don't use \"I don't understand\"-like answers] -;[Engine] -;[Mark replied messages as read] -;[Reload] -;[Start answers with a lowercase letter] -;[Stay silent, if have no good aswers] -;[Thinking time:] -;[Time before the answer] -;[Typing and thinking time can be much longer] -;[Typing time (for a message of 4 words):] -;[Typing time depends on message length (in chars)] -;[Warn contacts Boltun is chatting] -;[Warning text] -;[sec] diff --git a/plugins/Boltun/boltun.cpp b/plugins/Boltun/boltun.cpp deleted file mode 100644 index 52e140d509..0000000000 --- a/plugins/Boltun/boltun.cpp +++ /dev/null @@ -1,713 +0,0 @@ -//*********************************************************** -// 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 . -// -//*********************************************************** - -#define MIRANDA_VER 0x0A00 - -#include "Engine/TalkEngine.h" - -#include -#include -#include - -#include "newpluginapi.h" -#include "m_clist.h" -#include "m_skin.h" -#include "m_database.h" -#include "m_system.h" -#include "m_protosvc.h" -#include "m_options.h" -#include "m_langpack.h" -#include "resource.h" - -#include "resource.h" - -#include "boltun.h" -#include "config.h" -#include "actionQueue.h" - -//#define DEBUG_LOAD_TIME - -int hLangpack; - -TalkBot* bot = NULL; - - -#define MAX_WARN_TEXT 1024 -#define MAX_MIND_FILE 1024 - -HINSTANCE hInst; -BOOL blInit = FALSE; -UINT pTimer = 0; -TCHAR *path; - -PLUGININFOEX pluginInfo={ - sizeof(PLUGININFOEX), - BOLTUN_NAME, - PLUGIN_MAKE_VERSION(0,0,3,0), - PLUGIN_DESCRIPTION, - "Alexander S. Kiselev, Valentin Pavlyuchenko", - "Valentin.Pavlyuchenko@gmail.com", - "© 2003-2008 Alexander S. Kiselev A.K.A. KAS, Valentin Pavlyuchenko", - "http://miranda-im.org", - UNICODE_AWARE, - // {488C5C84-56DA-434F-96F1-B18900DEF760} - { 0x488c5c84, 0x56da, 0x434f, { 0x96, 0xf1, 0xb1, 0x89, 0x0, 0xde, 0xf7, 0x60 } } -}; - -static HANDLE hEventDbEventAdded; -static HANDLE hEventOptInitialise; -static HANDLE hEventPrebuild; -static HANDLE hMenuItemAutoChat; -static HANDLE hMenuItemNotToChat; -static HANDLE hMenuItemStartChatting; - - -#define MIND_DIALOG_FILTER _T("%s (*.mindw)\1*.mindw\1%s (*.*)\1*.*\1") - - -#ifdef DEBUG_LOAD_TIME -#include -#endif - -void UpdateEngine() -{ - if (bot) - { - bot->SetSilent(Config.EngineStaySilent); - bot->SetLowercase(Config.EngineMakeLowerCase); - bot->SetUnderstandAlways(Config.EngineUnderstandAlways); - } -} - -TCHAR* GetFullName(const TCHAR* filename) -{ - size_t flen = _tcslen(filename); - TCHAR* fullname = const_cast(filename); - if (!_tcschr(filename, _T(':'))) - { - size_t plen = _tcslen(path); - fullname = new TCHAR[plen+flen+1]; - fullname[0] = NULL; - _tcscat(fullname, path); - _tcscat(fullname, filename); - } - return fullname; -} - -static bool LoadMind(const TCHAR* filename, int &line) -{ - TCHAR* fullname = GetFullName(filename); - HCURSOR newCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT)); - HCURSOR oldCur = SetCursor(newCur); -#ifdef DEBUG_LOAD_TIME - unsigned __int64 t = __rdtsc(); -#endif - Mind* mind = new Mind(); - line = -1; - try - { - mind->Load(fullname); - } - catch(Mind::CorruptedMind c) - { - line = c.line; - delete mind; - if (fullname != filename) - delete[] fullname; - SetCursor(oldCur); - return false; - } - catch(...) - { - delete mind; - if (fullname != filename) - delete[] fullname; - SetCursor(oldCur); - return false; - } - if (fullname != filename) - delete[] fullname; - -#ifdef DEBUG_LOAD_TIME - t = __rdtsc() - t; - char dest[101]; - sprintf_s(dest, 100, "%I64d ticks\n", t / 3200000); - MessageBoxA(NULL, dest, NULL, 0); - //exit(0); -#endif - SetCursor(oldCur); - HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(IDR_SMILES), _T("SMILES")); - if (!hRes) - { - delete mind; - return false; - } - DWORD size = SizeofResource(hInst, hRes); - if (!size) - { - delete mind; - return false; - } - HGLOBAL hGlob = LoadResource(hInst, hRes); - if (!hGlob) - { - delete mind; - return false; - } - void *data = LockResource(hGlob); - if (!data) - { - FreeResource(hGlob); - delete mind; - return false; - } - bool res = true; - try - { - mind->LoadSmiles(data, size); - } - catch(...) - { - res = false; - } - UnlockResource(data); - FreeResource(hGlob); - if (!res) - { - delete mind; - return false; - } - if (bot) - delete bot; - bot = new TalkBot(*mind); - delete mind; - UpdateEngine(); - return true; -} - -/*static bool SaveMind(const TCHAR* filename) -{ - if (!bot) - return false; - bot->GetMind().Save(filename); - return true; -}*/ - -static bool BoltunAutoChat(HANDLE hContact) -{ - if (DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_NOT_TO_CHAT - , FALSE) == TRUE) - return false; - - if (Config.TalkWithEverybody) - return true; - - if (Config.TalkEveryoneWhileAway) - { - int status = CallService(MS_CLIST_GETSTATUSMODE, 0, 0); - if (status == ID_STATUS_AWAY || - status == ID_STATUS_DND || - status == ID_STATUS_NA || - status == ID_STATUS_OCCUPIED || - status == ID_STATUS_ONTHEPHONE || - status == ID_STATUS_OUTTOLUNCH) - return true; - } - - if ((DBGetContactSettingByte(hContact,"CList","NotOnList",0) == 1) && - Config.TalkWithNotInList) - return true; - - if (DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_AUTO_CHAT, - FALSE) == TRUE) - return true; - - return false; -} - -static int MessageEventAdded(WPARAM wParam, LPARAM lParam) -{ - //DBEVENTINFO ldbei; - HANDLE hContact = (HANDLE)wParam; - if (!BoltunAutoChat(hContact)) - return 0; - - DBEVENTINFO dbei; - ZeroMemory(&dbei, sizeof(dbei)); - dbei.cbSize = sizeof(dbei); - dbei.cbBlob = 0; - - dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, lParam, 0); - if (dbei.cbBlob == -1) - return 0; - - dbei.pBlob = (PBYTE)malloc(dbei.cbBlob); - if (dbei.pBlob == NULL) - return 0; - - CallService(MS_DB_EVENT_GET, lParam, (LPARAM)&dbei); - if (dbei.flags & DBEF_SENT || dbei.flags & DBEF_READ || dbei.eventType != EVENTTYPE_MESSAGE) - return 0; - DBEVENTGETTEXT egt; - egt.codepage = CP_ACP; - egt.datatype = DBVT_TCHAR; - egt.dbei = &dbei; - TCHAR* s = (TCHAR*)(void*)CallService(MS_DB_EVENT_GETTEXT, 0, (LPARAM)&egt); - free(dbei.pBlob); - if (Config.MarkAsRead) - CallService(MS_DB_EVENT_MARKREAD, wParam, lParam); - - AnswerToContact(hContact, s); - mir_free(s); - return 0; -} - -BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) -{ - hInst = hinstDLL; - return TRUE; -} - -void UpdateEverybodyCheckboxes(HWND hwndDlg) -{ - bool Enable = !IsDlgButtonChecked(hwndDlg, IDC_EVERYBODY) == BST_CHECKED; - HWND wnd; - wnd = GetDlgItem(hwndDlg, IDC_NOTINLIST); - EnableWindow(wnd, Enable); - wnd = GetDlgItem(hwndDlg, IDC_AUTOAWAY); - EnableWindow(wnd, Enable); -} - -static INT_PTR CALLBACK MainDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - BOOL bTranslated = FALSE; - static bool loading = true; - switch (uMsg) - { - case WM_INITDIALOG: - loading = true; - TranslateDialogDefault(hwndDlg); - CheckDlgButton(hwndDlg, IDC_EVERYBODY, Config.TalkWithEverybody ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_NOTINLIST, Config.TalkWithNotInList ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_AUTOAWAY, Config.TalkEveryoneWhileAway ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_WARN, Config.TalkWarnContacts ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_MARKREAD, Config.MarkAsRead ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_PAUSEDEPENDS, Config.PauseDepends ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_PAUSERANDOM, Config.PauseRandom ? BST_CHECKED : BST_UNCHECKED); - SendDlgItemMessage(hwndDlg, IDC_WAITTIME, EM_SETLIMITTEXT, 3, 0); - SetDlgItemInt(hwndDlg, IDC_WAITTIME, Config.AnswerPauseTime, FALSE); - SendDlgItemMessage(hwndDlg, IDC_THINKTIME, EM_SETLIMITTEXT, 3, 0); - SetDlgItemInt(hwndDlg, IDC_THINKTIME, Config.AnswerThinkTime, FALSE); - SendDlgItemMessage(hwndDlg, IDC_WARNTXT, EM_SETLIMITTEXT, MAX_WARN_TEXT, 0); - SetDlgItemText(hwndDlg, IDC_WARNTXT, Config.WarnText); - UpdateEverybodyCheckboxes(hwndDlg); - loading = false; - return TRUE; - case WM_COMMAND: - if (LOWORD(wParam) == IDC_EVERYBODY && HIWORD(wParam) == BN_CLICKED) - UpdateEverybodyCheckboxes(hwndDlg); - if (!loading) - { - bool notify = true; - switch (LOWORD(wParam)) - { - case IDC_WARNTXT: - case IDC_WAITTIME: - case IDC_THINKTIME: - if (HIWORD(wParam) != EN_CHANGE) - notify = false; - break; - } - if (notify) - SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); - } - break; - case WM_NOTIFY: - { - NMHDR* nmhdr = (NMHDR*)lParam; - switch (nmhdr->code) - { - case PSN_APPLY: - case PSN_KILLACTIVE: - { - Config.TalkWithEverybody = IsDlgButtonChecked(hwndDlg, IDC_EVERYBODY) == BST_CHECKED ? TRUE : FALSE; - Config.TalkWithNotInList = IsDlgButtonChecked(hwndDlg, IDC_NOTINLIST) == BST_CHECKED ? TRUE : FALSE; - Config.TalkEveryoneWhileAway = IsDlgButtonChecked(hwndDlg, IDC_AUTOAWAY) == BST_CHECKED ? TRUE : FALSE; - Config.TalkWarnContacts = IsDlgButtonChecked(hwndDlg, IDC_WARN) == BST_CHECKED ? TRUE : FALSE; - Config.MarkAsRead = IsDlgButtonChecked(hwndDlg, IDC_MARKREAD) == BST_CHECKED ? TRUE : FALSE; - Config.PauseDepends = IsDlgButtonChecked(hwndDlg, IDC_PAUSEDEPENDS) == BST_CHECKED ? TRUE : FALSE; - Config.PauseRandom = IsDlgButtonChecked(hwndDlg, IDC_PAUSERANDOM) == BST_CHECKED ? TRUE : FALSE; - Config.AnswerPauseTime = GetDlgItemInt(hwndDlg, IDC_WAITTIME, &bTranslated, FALSE); - if (!bTranslated) - Config.AnswerPauseTime = 2; - Config.AnswerThinkTime = GetDlgItemInt(hwndDlg, IDC_THINKTIME, &bTranslated, FALSE); - if (!bTranslated) - Config.AnswerThinkTime = 4; - TCHAR c[MAX_WARN_TEXT]; - bTranslated = GetDlgItemText(hwndDlg, IDC_WARNTXT, c, MAX_WARN_TEXT); - if(bTranslated) - Config.WarnText = c; - else - Config.WarnText = TranslateTS(DEFAULT_WARN_TEXT); - } - return TRUE; - } - break; - } - break; - } - return 0; -} - -void UpdateUnderstandAlwaysCheckbox(HWND hwndDlg) -{ - bool Enable = !IsDlgButtonChecked(hwndDlg, IDC_ENGINE_SILENT) == BST_CHECKED; - HWND wnd; - wnd = GetDlgItem(hwndDlg, IDC_ENGINE_UNDERSTAND_ALWAYS); - EnableWindow(wnd, Enable); -} - -static INT_PTR CALLBACK EngineDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - WORD param; - BOOL bTranslated = FALSE; - static bool loading = true; - static int changeCount = 0; - switch (uMsg) - { - case WM_INITDIALOG: - loading = true; - TranslateDialogDefault(hwndDlg); - CheckDlgButton(hwndDlg, IDC_ENGINE_SILENT, Config.EngineStaySilent ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_ENGINE_LOWERCASE, Config.EngineMakeLowerCase ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwndDlg, IDC_ENGINE_UNDERSTAND_ALWAYS, Config.EngineUnderstandAlways ? BST_CHECKED : BST_UNCHECKED); - SetDlgItemText(hwndDlg, IDC_MINDFILE, Config.MindFileName); - EnableWindow(GetDlgItem(hwndDlg, IDC_BTNSAVE), blInit); - UpdateUnderstandAlwaysCheckbox(hwndDlg); - loading = false; - return TRUE; - case WM_COMMAND: - param = LOWORD(wParam); - if (param == IDC_ENGINE_SILENT && HIWORD(wParam) == BN_CLICKED) - UpdateUnderstandAlwaysCheckbox(hwndDlg); - OPENFILENAME ofn; - switch(param) - { - case IDC_BTNPATH: - { - const size_t fileNameSize = 5000; - TCHAR *filename = new TCHAR[fileNameSize]; - TCHAR *fullname = GetFullName(Config.MindFileName); - _tcscpy(filename, fullname); - if (fullname != Config.MindFileName) - delete[] fullname; - - ZeroMemory(&ofn, sizeof(ofn)); - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = GetParent(hwndDlg); - - TCHAR* mind = TranslateTS(MIND_FILE_DESC); - TCHAR* anyfile = TranslateTS(ALL_FILES_DESC); - size_t l = _tcslen(MIND_DIALOG_FILTER) - + _tcslen(mind) + _tcslen(anyfile); - TCHAR *filt = new TCHAR[l]; - wsprintf(filt, MIND_DIALOG_FILTER, mind, anyfile); - for (size_t i = 0; i < l; i++) - if (filt[i] == '\1') - filt[i] = '\0'; - ofn.lpstrFilter = filt; - - ofn.lpstrFile = filename; - ofn.nMaxFile = fileNameSize; - ofn.Flags = OFN_FILEMUSTEXIST; - ofn.lpstrInitialDir = path; - if (!GetOpenFileName(&ofn)) - { - delete filename; - delete[] filt; - break; - } - delete[] filt; - TCHAR* origf = filename; - TCHAR* f = filename; - TCHAR* p = path; - while (*p && *f) - { - TCHAR p1 = (TCHAR)CharLower((TCHAR*)(long)*p++); - TCHAR f1 = (TCHAR)CharLower((TCHAR*)(long)*f++); - if (p1 != f1) - break; - } - if (!*p) - filename = f; - Config.MindFileName = filename; - SetDlgItemText(hwndDlg, IDC_MINDFILE, filename); - delete origf; - } - case IDC_BTNRELOAD: - { - const TCHAR *c = Config.MindFileName; - int line; - bTranslated = blInit = LoadMind(c, line); - if (!bTranslated) - { - TCHAR* message = new TCHAR[5000]; - wsprintf(message, TranslateTS(FAILED_TO_LOAD_BASE), line, c); - MessageBox(NULL, message, TranslateTS(BOLTUN_ERROR), MB_ICONERROR|MB_TASKMODAL|MB_OK); - delete[] message; - } - break; - } - default: - if (!loading) - { - if (param == IDC_MINDFILE/* && HIWORD(wParam) != EN_CHANGE*/) - break; - SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); - } - } - break; - case WM_NOTIFY: - { - NMHDR* nmhdr = (NMHDR*)lParam; - switch (nmhdr->code) - { - case PSN_APPLY: - case PSN_KILLACTIVE: - { - Config.EngineStaySilent = IsDlgButtonChecked(hwndDlg, IDC_ENGINE_SILENT) == BST_CHECKED ? TRUE : FALSE; - Config.EngineMakeLowerCase = IsDlgButtonChecked(hwndDlg, IDC_ENGINE_LOWERCASE) == BST_CHECKED ? TRUE : FALSE; - Config.EngineUnderstandAlways = IsDlgButtonChecked(hwndDlg, IDC_ENGINE_UNDERSTAND_ALWAYS) == BST_CHECKED ? TRUE : FALSE; - UpdateEngine(); - TCHAR c[MAX_MIND_FILE]; - bTranslated = GetDlgItemText(hwndDlg, IDC_MINDFILE, c, MAX_MIND_FILE); - if (bTranslated) - Config.MindFileName = c; - else - Config.MindFileName = DEFAULT_MIND_FILE; - } - return TRUE; - } - break; - } - break; - } - return 0; -} - -static int MessageOptInit(WPARAM wParam, LPARAM lParam) -{ - OPTIONSDIALOGPAGE odp; - - ZeroMemory(&odp, sizeof(odp)); - odp.cbSize = sizeof(odp); - odp.position = 910000000; - odp.hInstance = hInst; - odp.pszGroup = BOLTUN_GROUP; - odp.pszTitle = BOLTUN_NAME; - odp.pfnDlgProc = MainDlgProc; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_MAIN); - odp.pszTab = TAB_GENERAL; - Options_AddPage(wParam, &odp); - odp.pfnDlgProc = EngineDlgProc; - odp.pszTemplate = MAKEINTRESOURCEA(IDD_ENGINE); - odp.pszTab = TAB_ENGINE; - Options_AddPage(wParam, &odp); - return 0; -} - -static int ContactClick(WPARAM wParam, LPARAM lParam, BOOL clickNotToChat) -{ - HANDLE hContact = (HANDLE)wParam; - - BOOL boltunautochat = DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_AUTO_CHAT, FALSE); - BOOL boltunnottochat = DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_NOT_TO_CHAT, FALSE); - - if (clickNotToChat) - { - boltunnottochat = !boltunnottochat; - if(boltunnottochat) - { - boltunautochat = FALSE; - } - } - else - { - boltunautochat = !boltunautochat; - if(boltunautochat) - { - boltunnottochat = FALSE; - } - else - { - DBWriteContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_WARNED, FALSE); - } - } - - DBWriteContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_AUTO_CHAT, (BYTE)boltunautochat); - DBWriteContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_NOT_TO_CHAT, (BYTE)boltunnottochat); - - return 0; -} - -static INT_PTR ContactClickAutoChat(WPARAM wParam, LPARAM lParam) -{ - return ContactClick(wParam, lParam, 0); -} - -static INT_PTR ContactClickNotToChat(WPARAM wParam, LPARAM lParam) -{ - return ContactClick(wParam, lParam, 1); -} - -static INT_PTR ContactClickStartChatting(WPARAM wParam, LPARAM lParam) -{ - HANDLE hContact = (HANDLE)wParam; - StartChatting(hContact); - return 0; -} - -static int MessagePrebuild(WPARAM wParam, LPARAM lParam) -{ - CLISTMENUITEM clmi; - HANDLE hContact = (HANDLE)wParam; - - if (!blInit || (DBGetContactSettingByte(hContact,"CList","NotOnList",0) == 1)) - { - ZeroMemory(&clmi, sizeof(clmi)); - clmi.cbSize = sizeof(clmi); - clmi.flags = CMIM_FLAGS | CMIF_GRAYED; - - CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemAutoChat, (LPARAM)&clmi); - CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemNotToChat, (LPARAM)&clmi); - } - else - { - BOOL boltunautochat = DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_AUTO_CHAT, FALSE); - BOOL boltunnottochat = DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_NOT_TO_CHAT, FALSE); - ZeroMemory(&clmi, sizeof(clmi)); - clmi.cbSize = sizeof(clmi); - clmi.flags = CMIM_FLAGS | CMIM_ICON | (boltunautochat ? CMIF_CHECKED : 0); - clmi.hIcon = LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE((boltunautochat ? IDI_TICK : IDI_NOTICK))); - CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemAutoChat, (LPARAM)&clmi); - - clmi.flags = CMIM_FLAGS | CMIM_ICON | (boltunnottochat ? CMIF_CHECKED : 0); - clmi.hIcon = LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE((boltunnottochat ? IDI_TICK : IDI_NOTICK))); - CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemNotToChat, (LPARAM)&clmi); - } - return 0; -} - -extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) -{ - return &pluginInfo; -} - -extern "C" int __declspec(dllexport) Load(void) -{ - mir_getLP(&pluginInfo); - - path = new TCHAR[MAX_PATH]; - int len = GetModuleFileName(hInst, path, MAX_PATH); - if (len > MAX_PATH) - { - delete[] path; - TCHAR *path = new TCHAR[len]; - int len2 = GetModuleFileName(hInst, path, len); - if (len2 != len) - { - delete[] path; - return false; - } - } - *(_tcsrchr(path, _T('\\'))+1) = _T('\0'); - - /*initialize miranda hooks and services on options dialog*/ - hEventOptInitialise = HookEvent(ME_OPT_INITIALISE, MessageOptInit); - /*initialize miranda hooks and services*/ - hEventDbEventAdded = HookEvent(ME_DB_EVENT_ADDED, MessageEventAdded); - hEventPrebuild = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, MessagePrebuild); - - CreateServiceFunction(SERV_CONTACT_AUTO_CHAT, ContactClickAutoChat); - CreateServiceFunction(SERV_CONTACT_NOT_TO_CHAT, ContactClickNotToChat); - CreateServiceFunction(SERV_CONTACT_START_CHATTING, ContactClickStartChatting); - { - CLISTMENUITEM mi; - - ZeroMemory(&mi,sizeof(mi)); - mi.cbSize = sizeof(mi); - mi.position = -50010002; //TODO: check the warning - mi.flags = 0; - mi.hIcon = NULL; - mi.pszContactOwner = NULL; - mi.pszName = BOLTUN_AUTO_CHAT; - mi.pszService = SERV_CONTACT_AUTO_CHAT; - hMenuItemAutoChat = Menu_AddContactMenuItem(&mi); - - mi.position = -50010001; //TODO: check the warning - mi.pszName = BOLTUN_NOT_TO_CHAT; - mi.pszService = SERV_CONTACT_NOT_TO_CHAT; - hMenuItemNotToChat = Menu_AddContactMenuItem(&mi); - - mi.flags = CMIF_NOTOFFLINE; - mi.position = -50010000; //TODO: check the warning - mi.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_RECVMSG)); - mi.pszName = BOLTUN_START_CHATTING; - mi.pszService = SERV_CONTACT_START_CHATTING; - hMenuItemStartChatting = Menu_AddContactMenuItem(&mi); - } - int line; - blInit = LoadMind(Config.MindFileName, line); - if (!blInit) - { - TCHAR path[2000]; - wsprintf(path, TranslateTS(FAILED_TO_LOAD_BASE), line, (const TCHAR*)Config.MindFileName); - MessageBox(NULL, path, TranslateTS(BOLTUN_ERROR), MB_ICONERROR|MB_TASKMODAL|MB_OK); - } - /*record for Uninstall plugin*/ - DBWriteContactSettingString(NULL, "Uninstall", BOLTUN_NAME, BOLTUN_KEY); - return 0; -} - -extern "C" int __declspec(dllexport) Unload(void) -{ - if (pTimer) - KillTimer(NULL, pTimer); - if(blInit) - { -#if 0 //No need to save, we don't have studying algorithm - if(Config.MindFileName && !SaveMind(Config.MindFileName)) - { -//This causes errors with development core when calling MessageBox. -//It seems that it's now a Boltun problem. -//So in case of saving error we will remain silent -#if 0 - TCHAR path[MAX_PATH]; - wsprintf(path, TranslateTS(FAILED_TO_SAVE_BASE), (const TCHAR*)Config.MindFileName); - TCHAR* err = TranslateTS(BOLTUN_ERROR); - MessageBox(NULL, path, err, MB_ICONERROR|MB_TASKMODAL|MB_OK);*/ -#endif - } -#endif - delete bot; - } - delete[] path; - return 0; -} diff --git a/plugins/Boltun/boltun.h b/plugins/Boltun/boltun.h deleted file mode 100644 index 914869387c..0000000000 --- a/plugins/Boltun/boltun.h +++ /dev/null @@ -1,74 +0,0 @@ -//*********************************************************** -// 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 . -// -//*********************************************************** - -#ifndef _BOLTUN_H -#define _BOLTUN_H - -//Should use different keys in UNICODE and ANSI builds, because usage of plugin -//with old (another) configs will cause crashes. - -#define BOLTUN_KEY "Boltun" - - -//Service names -#define SERV_CONTACT_AUTO_CHAT "Boltun/ContactAutoChat" -#define SERV_CONTACT_NOT_TO_CHAT "Boltun/ContactNotToChat" -#define SERV_CONTACT_START_CHATTING "Boltun/ContactStartChatting" - -//Database keys -#define DB_CONTACT_BOLTUN_NOT_TO_CHAT "BoltunNotToChat" -#define DB_CONTACT_BOLTUN_AUTO_CHAT "BoltunAutoChat" -#define DB_CONTACT_WARNED "Warned" - -//Plugin group in settings -#define BOLTUN_GROUP "Message sessions" - -//Filename depends on UNICODE -#define DEFAULT_MIND_FILE _T("boltun.mindw") - -//=============================================== -// These are strings for translation: -//=============================================== - -//Plugin name -#define BOLTUN_NAME "Boltun" - -#define PLUGIN_DESCRIPTION "Boltun, the chat bot in the russian language." - -#define MIND_FILE_DESC _T("Mind Files") -#define ALL_FILES_DESC _T("All Files") - -//UI strings -#define BOLTUN_AUTO_CHAT "Boltun/Auto Chat" -#define BOLTUN_NOT_TO_CHAT "Boltun/Not to Chat" -#define BOLTUN_START_CHATTING "Boltun/Start Chatting" - -#define DEFAULT_WARN_TEXT _T("Hello. I'm Boltun! I'll talk to you, while my owner is away. Please write without mistakes!") - -// Error messages -#define BOLTUN_ERROR _T("Boltun Error") -#define FAILED_TO_LOAD_BASE _T("Failed to load base of remarks. Error at line %d of %s. (Or few lines before).") -#define FAILED_TO_SAVE_BASE _T("Failed to save base of remarks to %s") - -//Settings tab names -#define TAB_GENERAL "General Settings" -#define TAB_ENGINE "Engine Settings" - -#endif /*_BOLTUN_H*/ diff --git a/plugins/Boltun/config.cpp b/plugins/Boltun/config.cpp deleted file mode 100644 index 4a88bf2df3..0000000000 --- a/plugins/Boltun/config.cpp +++ /dev/null @@ -1,159 +0,0 @@ -//*********************************************************** -// 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 "config.h" - -#include -#include -#include - -#include "newpluginapi.h" -#include "m_database.h" -#include "m_langpack.h" -#include "boltun.h" - -//Database keys -#define DB_EVERYBODY "Everybody" -#define DB_NOT_IN_LIST "NotInList" -#define DB_AUTOAWAY "AutoAway" -#define DB_WARN "Warn" -#define DB_MARK_READ "MarkRead" -#define DB_WAIT_TIME "WaitTime" -#define DB_THINK_TIME "ThinkTime" -#define DB_PAUSE_DEPENDS "PauseDepends" -#define DB_PAUSE_RANDOM "PauseRandom" -#define DB_WARN_TEXT "WarnText" -#define DB_MIND_FILE_NAME "MindFileName" -#define DB_ENGINE_SILENT "SilentEngine" -#define DB_ENGINE_LOWERCASE "MakeLowerCase" -#define DB_ENGINE_UNDERSTAND_ALWAYS "UnderstandAlways" - -inline TCHAR* GetString(char* key, const TCHAR* def) -{ - DBVARIANT dbv; - TCHAR* val; - if (!DBGetContactSettingTString(NULL, BOLTUN_KEY, key, &dbv)) - { - size_t len = wcslen(dbv.ptszVal) + 1; - val = new TCHAR[len]; - _tcscpy_s(val, len, dbv.ptszVal); - DBFreeVariant(&dbv); - } - else - { - size_t len = wcslen(def) + 1; - val = new TCHAR[len]; - _tcscpy_s(val, len, def); - } - return val; -} - -inline const TCHAR* SetString(char* key, const TCHAR* value) -{ - size_t len = _tcslen(value) + 1; - TCHAR* val = new TCHAR[len]; - _tcscpy_s(val, len, value); - DBWriteContactSettingTString(NULL, BOLTUN_KEY, key, val); - return val; -} - -#define BUILDETTERS(x, str, def) \ - const bool BoltunConfig::Get##x() { \ - return DBGetContactSettingDword(NULL, BOLTUN_KEY, str, def) != 0; } \ - const bool BoltunConfig::Set##x(const bool value) { \ - DBWriteContactSettingDword(NULL, BOLTUN_KEY, str, value); \ - return value; } - -#define BUILDINTETTERS(x, str, def) \ - const int BoltunConfig::Get##x() { \ - return DBGetContactSettingDword(NULL, BOLTUN_KEY, str, def); } \ - const int BoltunConfig::Set##x(const int value) { \ - DBWriteContactSettingDword(NULL, BOLTUN_KEY, str, value); \ - return value; } - -#define BUILDSTRETTERS(x, str, def) \ - const TCHAR* BoltunConfig::Get##x() { \ - return GetString(str, def); } \ - const TCHAR* BoltunConfig::Set##x(const TCHAR* value) { \ - return SetString(str, value); } - -#define BUILDINIT(x) \ - x(&BoltunConfig::Get##x, &BoltunConfig::Set##x) - -BUILDETTERS(TalkWithNotInList, DB_NOT_IN_LIST, false); -BUILDETTERS(TalkWithEverybody, DB_EVERYBODY, false); -BUILDETTERS(TalkWarnContacts, DB_WARN, false); -BUILDETTERS(TalkEveryoneWhileAway, DB_AUTOAWAY, false); -BUILDETTERS(MarkAsRead, DB_MARK_READ, true); -BUILDINTETTERS(AnswerPauseTime, DB_WAIT_TIME, 2); -BUILDINTETTERS(AnswerThinkTime, DB_THINK_TIME, 4); -BUILDETTERS(PauseDepends, DB_PAUSE_DEPENDS, TRUE); -BUILDETTERS(PauseRandom, DB_PAUSE_RANDOM, TRUE); -BUILDSTRETTERS(WarnText, DB_WARN_TEXT, TranslateTS(DEFAULT_WARN_TEXT)); -BUILDSTRETTERS(MindFileName, DB_MIND_FILE_NAME, DEFAULT_MIND_FILE); -BUILDETTERS(EngineStaySilent, DB_ENGINE_SILENT, FALSE); -BUILDETTERS(EngineMakeLowerCase, DB_ENGINE_LOWERCASE, FALSE); -BUILDETTERS(EngineUnderstandAlways, DB_ENGINE_UNDERSTAND_ALWAYS, FALSE); - -BoltunConfig::BoltunConfig() - :BUILDINIT(TalkWithEverybody), - BUILDINIT(TalkWithNotInList), - BUILDINIT(TalkWarnContacts), - BUILDINIT(TalkEveryoneWhileAway), - BUILDINIT(MarkAsRead), - BUILDINIT(AnswerPauseTime), - BUILDINIT(AnswerThinkTime), - BUILDINIT(PauseDepends), - BUILDINIT(PauseRandom), - BUILDINIT(WarnText), - BUILDINIT(MindFileName), - BUILDINIT(EngineStaySilent), - BUILDINIT(EngineMakeLowerCase), - BUILDINIT(EngineUnderstandAlways) -{ - TalkWithEverybody.SetOwner(this); - TalkWithNotInList.SetOwner(this); - TalkWarnContacts.SetOwner(this); - TalkEveryoneWhileAway.SetOwner(this); - MarkAsRead.SetOwner(this); - AnswerPauseTime.SetOwner(this); - AnswerThinkTime.SetOwner(this); - PauseDepends.SetOwner(this); - PauseRandom.SetOwner(this); - WarnText.SetOwner(this); - MindFileName.SetOwner(this); - EngineStaySilent.SetOwner(this); - EngineMakeLowerCase.SetOwner(this); - EngineUnderstandAlways.SetOwner(this); -} - -BoltunConfig::~BoltunConfig() -{ -} - -class _BoltunConfigInit -{ -public: - BoltunConfig cfg; -}; - -_BoltunConfigInit inst; - -BoltunConfig &Config = inst.cfg; \ No newline at end of file diff --git a/plugins/Boltun/config.h b/plugins/Boltun/config.h deleted file mode 100644 index c5bb20e700..0000000000 --- a/plugins/Boltun/config.h +++ /dev/null @@ -1,157 +0,0 @@ -//*********************************************************** -// 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 . -// -//*********************************************************** - -#ifndef _CONFIG_H -#define _CONFIG_H - -#include - -class BoltunConfig; - -template -class Property -{ -public: - typedef const T (__thiscall BaseClass::*Getter)(); - typedef const T (__thiscall BaseClass::*Setter)(const T); -private: - const Getter getter; - const Setter setter; - BaseClass* owner; - bool cacheValid; - T cached; -public: - Property(Getter g, Setter s) - :getter(g), setter(s), cacheValid(false) - { - } - - void SetOwner(BaseClass* o) - { - owner = o; - } - - inline operator const T() - { - if (cacheValid) - return cached; - cached = (owner->*getter)(); - cacheValid = true; - return cached; - } - - inline const T operator= (const T& value) - { - cacheValid = true; - return (owner->*setter)(cached = value); - } -}; - -template -class PtrProperty -{ -public: - typedef const T* (__thiscall BaseClass::*Getter)(); - typedef const T* (__thiscall BaseClass::*Setter)(const T*); -private: - const Getter getter; - const Setter setter; - BaseClass* owner; - bool cacheValid; - const T* cached; -public: - PtrProperty(Getter g, Setter s) - :getter(g), setter(s), cacheValid(false), cached(NULL) - { - } - - ~PtrProperty() - { - delete cached; - } - - void SetOwner(BaseClass* o) - { - owner = o; - } - - inline operator const T*() - { - if (cacheValid) - return cached; - cached = (owner->*getter)(); - cacheValid = true; - return cached; - } - - inline const T* operator= (const T* value) - { - cacheValid = true; - delete cached; - cached = (owner->*setter)(value); - return cached; - } -}; - -class _BoltunConfigInit; - -#define BUILDDEFETTERS(x, typ) \ - const typ Get##x(); \ - const typ Set##x(const typ value); - -class BoltunConfig -{ - BUILDDEFETTERS(TalkWithEverybody, bool); - BUILDDEFETTERS(TalkWithNotInList, bool); - BUILDDEFETTERS(TalkWarnContacts, bool); - BUILDDEFETTERS(TalkEveryoneWhileAway, bool); - BUILDDEFETTERS(MarkAsRead, bool); - BUILDDEFETTERS(AnswerPauseTime, int); - BUILDDEFETTERS(AnswerThinkTime, int); - BUILDDEFETTERS(PauseDepends, bool); - BUILDDEFETTERS(PauseRandom, bool); - BUILDDEFETTERS(WarnText, TCHAR*); - BUILDDEFETTERS(MindFileName, TCHAR*); - BUILDDEFETTERS(EngineStaySilent, bool); - BUILDDEFETTERS(EngineMakeLowerCase, bool); - BUILDDEFETTERS(EngineUnderstandAlways, bool); - BoltunConfig(); - ~BoltunConfig(); - friend class _BoltunConfigInit; -public: - Property TalkWithEverybody; - Property TalkWithNotInList; - Property TalkWarnContacts; - Property TalkEveryoneWhileAway; - Property MarkAsRead; - Property AnswerPauseTime; - Property AnswerThinkTime; - Property PauseDepends; - Property PauseRandom; - PtrProperty WarnText; - PtrProperty MindFileName; - Property EngineStaySilent; - Property EngineMakeLowerCase; - Property EngineUnderstandAlways; -}; - -extern BoltunConfig &Config; - -#endif /* _CONFIG_H */ \ No newline at end of file diff --git a/plugins/Boltun/docs/TODO.txt b/plugins/Boltun/docs/TODO.txt new file mode 100644 index 0000000000..6ea2151d2d --- /dev/null +++ b/plugins/Boltun/docs/TODO.txt @@ -0,0 +1,35 @@ +TODO list: + +-------------------------------------------------------- +Release-critical: + +- Add study capability to engine + +Done: +- Add reaction for duplicate phrases. +- Add aliases. +- Check for critical section double enter +- Multicontact talk support in engine +- Add "Start talking" option to cantact menu. +- Check bot warning. +- Add "be silent, not stupid" to options +- Add start answers with a little letter. +- Add README about bot algorithm. +- Add README for mind file format. +- Add "don't use "don't understand"" option +- Division between question and non-question sentenses +- Empty keywords or specials should not be loaded +- Check "каким-либо" +- Check :-) on "ок" +- Add answer-on status info to the readme. +- Make AI options dependent. +- Update mind.txt with UpdateStartChar +- Sort keywords matches by priority +- Use chooser everywhere + +-------------------------------------------------------- +Future: +- Speed-up loading +- Load mind from UTF8 files +- Expert mode support +- Add different choises of reaction for message series. diff --git a/plugins/Boltun/docs/boltun-translation.txt b/plugins/Boltun/docs/boltun-translation.txt new file mode 100644 index 0000000000..c3bce4a2f2 --- /dev/null +++ b/plugins/Boltun/docs/boltun-translation.txt @@ -0,0 +1,23 @@ +; Common strings that belong to many files +;[] + +; ../../plugins/Boltun/Boltun.rc +;[Base of remarks] +;[Boltun] +;[Boltun Autochat everybody] +;[Boltun Autochat everybody not in contact list] +;[Boltun Autochat everybody while away] +;[Don't use \"I don't understand\"-like answers] +;[Engine] +;[Mark replied messages as read] +;[Reload] +;[Start answers with a lowercase letter] +;[Stay silent, if have no good aswers] +;[Thinking time:] +;[Time before the answer] +;[Typing and thinking time can be much longer] +;[Typing time (for a message of 4 words):] +;[Typing time depends on message length (in chars)] +;[Warn contacts Boltun is chatting] +;[Warning text] +;[sec] diff --git a/plugins/Boltun/docs/mind.txt b/plugins/Boltun/docs/mind.txt new file mode 100644 index 0000000000..01dcd6e5ba --- /dev/null +++ b/plugins/Boltun/docs/mind.txt @@ -0,0 +1,142 @@ +В этом файле описан формат файла базы реплик и принцип работы Болтуна. + +============================================================== +Формат файла. +Файл базы реплик имеет кодировку UNICODE и состоит из пар строк. +Такие пары строк являются допустимыми: + +1) Фразы обучения: + +"Фраза" +"Ответ" + +2) Ответы по ключевым словам: + + ("список ключевых слов") +"Ответ" + +При этом список ключевых слов состоит из слов, ОБЯЗАТЕЛЬНО должен заканчиваться символом +типа предложения ('?' - вопросительное, '.' - любое другое). Если список предваряется +символом '~', то это является разрешением нечеткого совпадения. + +3) Ответы по специальным словам: + + {"список специальных слов"} +"Ответ" + +4) Часто используемые фразы: + + ["Фраза"] +"Ответ" + +5) Слова-признаки вопросительного предложения: + + +"слово" + +6) Специальные слова: + + +"Специальное слово" + +7) Общие ответы: + + +"Общий ответ" + +8) Начальные фразы (Для начала разговора): + + +"Начальная фраза" + +9) Общие ответы (то же, что и 7): + + +"Общий ответ" + +10) Алиасы + +@"привет" +"превед прю прифф" + +11) Ответы на повторы + + +"Я уже сказал." + +============================================================== + +Припцип работы движка бота: + +Во время работы движку передается реплика клиента, а движок на основе реплики формирует ответ. +Нахождение ответа имеет такие фазы: + +0) Если эта реплика совпадает с предыдущей (точное совпадение), сказанной не более 30 мин. назад +- выдается одна из реплик-ответов на повторы (11). После 2-3 повторов Болтун перестает реагировать +на повторы этой реплики и просто не отвечает. После 30 мин Болтун нормально реагирует на эту же +реплику, но на повтор сразу будет молчать. Так будет до первой реплики, отличной от уже +повторенной. + +1) Поиск реплики целиком среди часто используемых (4) реплик. При нахождении реплики ее ответ +возвращается как ответ бота. Если ответов для этом реплики несколько, то выбирается +один из них. + +Если реплика не найдена среди (4), то поиск ответов продолжается. +Далее все найденные ответы запоминаются с учетом их приоритета и в конце осуществляется +выбор. 0 - наивысший приоритет. + +2) Далее происходит поиск среди реплик обучения (1) аналогично пункту 1). Результаты имеют +приоритет 1. + +3) Производится разбиение реплики на предложения. Разделителями предложений являются симолы +'.' '!' '?', при этом игнорируется '!' в составе смайлика ':-!'. + +Следующие действия производятся для каждого предложения: + + 4) Поиск предложения целиком среди часто используемых (4) фраз. Результаты имеют + приоритет 0. + + 5) Поиск среди фраз обучения (1). Результаты имеют приоритет 1. + + 6) Далее происходит разделение предложения на слова. При этом в предложении выделяются + как слова все смайлики, а также скобки количеством больше двух ( "))" ). + Производится определение типа предложения: вопросительное или нет. Вопросительное + предложение или имеет в конце восклицательный знак, или содержит хотя бы одно слово, + которое относится к вопросительным (5). + Отдельно записываются слова, которые относятся к специальным (6). + + 7) Поиск совпадения среди ключевых слов (2). Все ключевые слова должны присутствовать в + предложении и тип предложения должен совпадать. Результаты имеют приоритет 1. + Предпочтительным является совпадение как можно большего количества ключевых слов. + + 8) Поиск совпадения среди специальных слов (3). Специальные - это слова из (6). + Подразумевается, что они не несут особой смысловой нагрузки и по ним возможны только + обобщенные ответы. В предложении должно присутствовать не менее одного специального + слова (как правило, присутствует только одно). Также, тип предложения должен совпадать. + Результаты имеют приоритет 2. + +Результаты, полученные от разных предложений, имеют одинаковый приоритет и только один из +них может стать ответом. + +Пункты 9 и 10 ипользуются, только если опция "Молчать, если нету хороших ответов" +(aka "Иногда лучше жевать") отключена. + +9) Выбор одного случайного ответа среди общих ответов (7). Результаты имеют приоритет 3. + +10) Выбор одного случайного ответа среди общих ответов (9). Обычно (9) - это несколько +реплик в духе "не понял". Результаты имеют приоритет 3. + +Таким образом, в случае непонятной фразы используется или 9 или 10 с равной вероятностью. + +После этого производится замена алиасов (10) в исходной реплике на соответствующие слова и +повторение пунктов 1-10 для такой реплики. + +Как ответ бота выбирается случайный ответ с наименьшим значением приоритета. При нескольких +ответах одинакового приоритета выбирается тот, который не использовался до этого +(учитываются предыдушие ответы Болтуна этому контакту за последние 30 минут). +Если никаких вариантов ответа нет (например, для пустой базы реплик), то ответа и не +следует. + +Если ответ должен начинаться с маленькой буквы, то первая найденная буква в ответе +заменяется на маленькую. Этого не происходит, если ответ начинается с пробела. +При этом пробел удаляется. \ No newline at end of file diff --git a/plugins/Boltun/docs/readme.txt b/plugins/Boltun/docs/readme.txt new file mode 100644 index 0000000000..f20c3ec466 --- /dev/null +++ b/plugins/Boltun/docs/readme.txt @@ -0,0 +1,124 @@ +Болтун 0.3.0 Unicode Alpha 7 + +08.01.2009. + +Плагин предназначен только для тестирования. +И нечего его распостранять без приметки "beta" + +================================================ + +Список файлов: + +readme.txt - Этот файл +boltunw.dll - Собственно плагин +boltun.mindw - База реплик для плагина +lang_pack.txt - Файл с переводом интерфейса Болтуна на русский язык. +mind.txt - Описание формата файла базы реплик и принципа работы Болтуна. + +================================================ + +Установка: + +Скопировать файлы boltunw.dll и boltun.mindw в папку Plugins Миранды. +Строки из lang_pack.txt могут быть использованы для русификации интерфейса. + +================================================ + +Описание настроек: + +Основные настройки: +"Болтун говорит со всеми" - Болтун говорит абсолютно со всеми контактами +"Болтун говорит со всеми, кто не в списке контактов" - Болтун говорит с теми, кто отсутствует в вашем списке контактов +"Болтун говорит со всеми, когда меня нет" - Болтун говорит абсолютно со всеми контактами, когда статус отличается от "невидимый" или "в сети" +"Предупреждать о разговоре с Болтуном" - Каждый контакт один раз в жизни будет предупрежден о разговоре с Болтуном. +"Отмечать сообщения как прочитанные" - Отмечать сообщения контакта, с которым говорит Болтун, как прочитанные. Таким образом вы не увидите уведомлений о них. +"Текст предупреждения" - Сообщение, которое Болтун передает контакту в качестве предупреждения. +"Время печати" - время набора сообщения, в секундах. +"Время печати зависит от длины сообщения (в буквах)" - время набора зависит от длины сообщения. "Время печати" тогда указывает время набора сообщения из 25 символов. +"Время обдумывания ответа" - время паузы перед началом набора сообщения, в секундах. +"Время печати и обдумывания может увеличиваться" - Время набора и обдумывания случайным образом может быть до 4-х раз больше заданного. + +Установки движка: +"База реплик" - имя файла, с которого будет загружаться и в который будет сохраняться база реплик. +Кнопка "..." - выбор файла базы реплик в диалоге. +Кнопка "Сохранить" - сохранение базы реплик в файл, не дожидаясь автосохраниния при выходе из Миранды. +Кнопка "Перегрузить" - загрузка базы реплик из файла. +"Молчать, если нету хороших ответов" - Для непонятной реплики не используются общие ответы, а Болтун просто молчит. +"Начинать ответы с маленькой буквы" - Заменыть в ответе первую букву на маленькую. Но если ответ начинается с пробела, то замены не происходит, а пробел удаляется. +"Не испольозвать ответы типа "Не понял?"" - Пытаться ответить общими фразами вместо проявления непонимания. + +================================================ + +Список изменений: + +08.01.2009: +- Добавлена реакция на повторяющиеся реплики +- Исправления ошибок в ядре движка. +- При ошибке загрузки базы теперь приблизительно указывается строка с ошибкой в файле базы (не верьте ему!!!!). + +04.01.2009: +- Удалена утечка памяти при загрузке базы +- Поддержка алиасов +- Небольшие оптимизации + +30.09.2008: +- Исправлены некоторые недочеты, которые вызывали повторяемость бота. +- Обновлен файл описания базы (т.к. добавлены начальные фразы в базу реплик). + +29.09.2008: +- Устранено влияние истории одного контакта на разговор с другим. +- Убрано запоминание не отосланных ответов. + +28.09.2008: +- Болтун теперь в случае нескольких реплик подряд отвечает только на последнюю. +- Предотвращены возможные проблемы при одновременном разговоре с несколькими контактами. +- Болтун теперь отслеживает историю каждого контакта отдельно, чтобы лучше избегать повторений. + +19.09.2008: +- Добавлена возможность Болтуна начинать разговор. + +14.09.2008: +- Улучшен алгоритм выбора во избежание повторяющихся ответов. + +13.09.2008: +- Переделано определение текущего каталога. +- Убрано сохранение базы, чтобы никто не строил иллюзий касательно самообучения. +- Изменены настройки выбора файла базы, исправлено некоторые ошибки в диалоге настроек. +- Добавлена смена курсора на песочные часы на время загрузки базы. + +12.09.2008: +- Исправлена ошибка, приводившая к исчезновению значков статусов в плагине MRA. + +10.08.2008: +- Предупреждение о разговоре с Болтуном теперь работает не только когда включен "Болтун разговаривает со всеми" +- Изменено расширение файла базы, чтобы не путать его с файлом профиля. +- Исправлены ошибки с включением кнопки "Применить" в настройках при отсутствии изменений. +- Создан файл перевода интерфейса Болтуна на русский язык. +- Добавлена опция "Молчать, если нет хорошего ответа" +- Добавлена опция "Отвечать с маленькой буквы" +- Исправлен поиск предложения без финальной точки среди часто используемых. +- Исправлен алгоритм работы движка для разных типов предложений. +- Поиск среди ключевых слов теперь более лояльный. +- Добавлен файл с описанием формата файла базы реплик и принципа работы бота. +- Пустые списки ключевых и специальных слов теперь удаляются при загрузке. +- Исправлена ошибка при ответе английскими символами. +- Исправлена ошибка при разделении предложения на слова для слов типа "каким-нибудь". +- Исправлена ошибка, связанная с обработкой перевода стоки в реплике. +- Разбиение совпадений по ключевым словам на приоритеты и выбор согласно им. +- Болтун теперь старается меньше повторяться. + +28.07.2008: +- Переписан движок по образу и подобию старого (скорее всего, он несколько потупел). +- Добавлена поддержка Unicode (для чего и переписан движок) +- Добавлено время "обдумывания" ответа, предваряющее процесс написания. +- Добавлено оповещение "набирает текст" при ответе бота. +- Время "набора" зависит от длины сообщения. +- Исправлена ошибка с появлением сообщения пользователя при установленной задержке ответа +- Изменен порядок добавления сообжений в историю так, что теперь всегда ответы идут после вопросов (было не всегда так). +- Файл базы реплик теперь чем-то отличается от предыдушего формата (не помню так навскидку чем...). Как минимум тем, что он в Unicode-кодировке. + +================================================ + +Контакты: + +valentin.pavlyuchenko@gmail.com \ No newline at end of file diff --git a/plugins/Boltun/mind.txt b/plugins/Boltun/mind.txt deleted file mode 100644 index 01dcd6e5ba..0000000000 --- a/plugins/Boltun/mind.txt +++ /dev/null @@ -1,142 +0,0 @@ -В этом файле описан формат файла базы реплик и принцип работы Болтуна. - -============================================================== -Формат файла. -Файл базы реплик имеет кодировку UNICODE и состоит из пар строк. -Такие пары строк являются допустимыми: - -1) Фразы обучения: - -"Фраза" -"Ответ" - -2) Ответы по ключевым словам: - - ("список ключевых слов") -"Ответ" - -При этом список ключевых слов состоит из слов, ОБЯЗАТЕЛЬНО должен заканчиваться символом -типа предложения ('?' - вопросительное, '.' - любое другое). Если список предваряется -символом '~', то это является разрешением нечеткого совпадения. - -3) Ответы по специальным словам: - - {"список специальных слов"} -"Ответ" - -4) Часто используемые фразы: - - ["Фраза"] -"Ответ" - -5) Слова-признаки вопросительного предложения: - - -"слово" - -6) Специальные слова: - - -"Специальное слово" - -7) Общие ответы: - - -"Общий ответ" - -8) Начальные фразы (Для начала разговора): - - -"Начальная фраза" - -9) Общие ответы (то же, что и 7): - - -"Общий ответ" - -10) Алиасы - -@"привет" -"превед прю прифф" - -11) Ответы на повторы - - -"Я уже сказал." - -============================================================== - -Припцип работы движка бота: - -Во время работы движку передается реплика клиента, а движок на основе реплики формирует ответ. -Нахождение ответа имеет такие фазы: - -0) Если эта реплика совпадает с предыдущей (точное совпадение), сказанной не более 30 мин. назад -- выдается одна из реплик-ответов на повторы (11). После 2-3 повторов Болтун перестает реагировать -на повторы этой реплики и просто не отвечает. После 30 мин Болтун нормально реагирует на эту же -реплику, но на повтор сразу будет молчать. Так будет до первой реплики, отличной от уже -повторенной. - -1) Поиск реплики целиком среди часто используемых (4) реплик. При нахождении реплики ее ответ -возвращается как ответ бота. Если ответов для этом реплики несколько, то выбирается -один из них. - -Если реплика не найдена среди (4), то поиск ответов продолжается. -Далее все найденные ответы запоминаются с учетом их приоритета и в конце осуществляется -выбор. 0 - наивысший приоритет. - -2) Далее происходит поиск среди реплик обучения (1) аналогично пункту 1). Результаты имеют -приоритет 1. - -3) Производится разбиение реплики на предложения. Разделителями предложений являются симолы -'.' '!' '?', при этом игнорируется '!' в составе смайлика ':-!'. - -Следующие действия производятся для каждого предложения: - - 4) Поиск предложения целиком среди часто используемых (4) фраз. Результаты имеют - приоритет 0. - - 5) Поиск среди фраз обучения (1). Результаты имеют приоритет 1. - - 6) Далее происходит разделение предложения на слова. При этом в предложении выделяются - как слова все смайлики, а также скобки количеством больше двух ( "))" ). - Производится определение типа предложения: вопросительное или нет. Вопросительное - предложение или имеет в конце восклицательный знак, или содержит хотя бы одно слово, - которое относится к вопросительным (5). - Отдельно записываются слова, которые относятся к специальным (6). - - 7) Поиск совпадения среди ключевых слов (2). Все ключевые слова должны присутствовать в - предложении и тип предложения должен совпадать. Результаты имеют приоритет 1. - Предпочтительным является совпадение как можно большего количества ключевых слов. - - 8) Поиск совпадения среди специальных слов (3). Специальные - это слова из (6). - Подразумевается, что они не несут особой смысловой нагрузки и по ним возможны только - обобщенные ответы. В предложении должно присутствовать не менее одного специального - слова (как правило, присутствует только одно). Также, тип предложения должен совпадать. - Результаты имеют приоритет 2. - -Результаты, полученные от разных предложений, имеют одинаковый приоритет и только один из -них может стать ответом. - -Пункты 9 и 10 ипользуются, только если опция "Молчать, если нету хороших ответов" -(aka "Иногда лучше жевать") отключена. - -9) Выбор одного случайного ответа среди общих ответов (7). Результаты имеют приоритет 3. - -10) Выбор одного случайного ответа среди общих ответов (9). Обычно (9) - это несколько -реплик в духе "не понял". Результаты имеют приоритет 3. - -Таким образом, в случае непонятной фразы используется или 9 или 10 с равной вероятностью. - -После этого производится замена алиасов (10) в исходной реплике на соответствующие слова и -повторение пунктов 1-10 для такой реплики. - -Как ответ бота выбирается случайный ответ с наименьшим значением приоритета. При нескольких -ответах одинакового приоритета выбирается тот, который не использовался до этого -(учитываются предыдушие ответы Болтуна этому контакту за последние 30 минут). -Если никаких вариантов ответа нет (например, для пустой базы реплик), то ответа и не -следует. - -Если ответ должен начинаться с маленькой буквы, то первая найденная буква в ответе -заменяется на маленькую. Этого не происходит, если ответ начинается с пробела. -При этом пробел удаляется. \ No newline at end of file diff --git a/plugins/Boltun/readme.txt b/plugins/Boltun/readme.txt deleted file mode 100644 index f20c3ec466..0000000000 --- a/plugins/Boltun/readme.txt +++ /dev/null @@ -1,124 +0,0 @@ -Болтун 0.3.0 Unicode Alpha 7 - -08.01.2009. - -Плагин предназначен только для тестирования. -И нечего его распостранять без приметки "beta" - -================================================ - -Список файлов: - -readme.txt - Этот файл -boltunw.dll - Собственно плагин -boltun.mindw - База реплик для плагина -lang_pack.txt - Файл с переводом интерфейса Болтуна на русский язык. -mind.txt - Описание формата файла базы реплик и принципа работы Болтуна. - -================================================ - -Установка: - -Скопировать файлы boltunw.dll и boltun.mindw в папку Plugins Миранды. -Строки из lang_pack.txt могут быть использованы для русификации интерфейса. - -================================================ - -Описание настроек: - -Основные настройки: -"Болтун говорит со всеми" - Болтун говорит абсолютно со всеми контактами -"Болтун говорит со всеми, кто не в списке контактов" - Болтун говорит с теми, кто отсутствует в вашем списке контактов -"Болтун говорит со всеми, когда меня нет" - Болтун говорит абсолютно со всеми контактами, когда статус отличается от "невидимый" или "в сети" -"Предупреждать о разговоре с Болтуном" - Каждый контакт один раз в жизни будет предупрежден о разговоре с Болтуном. -"Отмечать сообщения как прочитанные" - Отмечать сообщения контакта, с которым говорит Болтун, как прочитанные. Таким образом вы не увидите уведомлений о них. -"Текст предупреждения" - Сообщение, которое Болтун передает контакту в качестве предупреждения. -"Время печати" - время набора сообщения, в секундах. -"Время печати зависит от длины сообщения (в буквах)" - время набора зависит от длины сообщения. "Время печати" тогда указывает время набора сообщения из 25 символов. -"Время обдумывания ответа" - время паузы перед началом набора сообщения, в секундах. -"Время печати и обдумывания может увеличиваться" - Время набора и обдумывания случайным образом может быть до 4-х раз больше заданного. - -Установки движка: -"База реплик" - имя файла, с которого будет загружаться и в который будет сохраняться база реплик. -Кнопка "..." - выбор файла базы реплик в диалоге. -Кнопка "Сохранить" - сохранение базы реплик в файл, не дожидаясь автосохраниния при выходе из Миранды. -Кнопка "Перегрузить" - загрузка базы реплик из файла. -"Молчать, если нету хороших ответов" - Для непонятной реплики не используются общие ответы, а Болтун просто молчит. -"Начинать ответы с маленькой буквы" - Заменыть в ответе первую букву на маленькую. Но если ответ начинается с пробела, то замены не происходит, а пробел удаляется. -"Не испольозвать ответы типа "Не понял?"" - Пытаться ответить общими фразами вместо проявления непонимания. - -================================================ - -Список изменений: - -08.01.2009: -- Добавлена реакция на повторяющиеся реплики -- Исправления ошибок в ядре движка. -- При ошибке загрузки базы теперь приблизительно указывается строка с ошибкой в файле базы (не верьте ему!!!!). - -04.01.2009: -- Удалена утечка памяти при загрузке базы -- Поддержка алиасов -- Небольшие оптимизации - -30.09.2008: -- Исправлены некоторые недочеты, которые вызывали повторяемость бота. -- Обновлен файл описания базы (т.к. добавлены начальные фразы в базу реплик). - -29.09.2008: -- Устранено влияние истории одного контакта на разговор с другим. -- Убрано запоминание не отосланных ответов. - -28.09.2008: -- Болтун теперь в случае нескольких реплик подряд отвечает только на последнюю. -- Предотвращены возможные проблемы при одновременном разговоре с несколькими контактами. -- Болтун теперь отслеживает историю каждого контакта отдельно, чтобы лучше избегать повторений. - -19.09.2008: -- Добавлена возможность Болтуна начинать разговор. - -14.09.2008: -- Улучшен алгоритм выбора во избежание повторяющихся ответов. - -13.09.2008: -- Переделано определение текущего каталога. -- Убрано сохранение базы, чтобы никто не строил иллюзий касательно самообучения. -- Изменены настройки выбора файла базы, исправлено некоторые ошибки в диалоге настроек. -- Добавлена смена курсора на песочные часы на время загрузки базы. - -12.09.2008: -- Исправлена ошибка, приводившая к исчезновению значков статусов в плагине MRA. - -10.08.2008: -- Предупреждение о разговоре с Болтуном теперь работает не только когда включен "Болтун разговаривает со всеми" -- Изменено расширение файла базы, чтобы не путать его с файлом профиля. -- Исправлены ошибки с включением кнопки "Применить" в настройках при отсутствии изменений. -- Создан файл перевода интерфейса Болтуна на русский язык. -- Добавлена опция "Молчать, если нет хорошего ответа" -- Добавлена опция "Отвечать с маленькой буквы" -- Исправлен поиск предложения без финальной точки среди часто используемых. -- Исправлен алгоритм работы движка для разных типов предложений. -- Поиск среди ключевых слов теперь более лояльный. -- Добавлен файл с описанием формата файла базы реплик и принципа работы бота. -- Пустые списки ключевых и специальных слов теперь удаляются при загрузке. -- Исправлена ошибка при ответе английскими символами. -- Исправлена ошибка при разделении предложения на слова для слов типа "каким-нибудь". -- Исправлена ошибка, связанная с обработкой перевода стоки в реплике. -- Разбиение совпадений по ключевым словам на приоритеты и выбор согласно им. -- Болтун теперь старается меньше повторяться. - -28.07.2008: -- Переписан движок по образу и подобию старого (скорее всего, он несколько потупел). -- Добавлена поддержка Unicode (для чего и переписан движок) -- Добавлено время "обдумывания" ответа, предваряющее процесс написания. -- Добавлено оповещение "набирает текст" при ответе бота. -- Время "набора" зависит от длины сообщения. -- Исправлена ошибка с появлением сообщения пользователя при установленной задержке ответа -- Изменен порядок добавления сообжений в историю так, что теперь всегда ответы идут после вопросов (было не всегда так). -- Файл базы реплик теперь чем-то отличается от предыдушего формата (не помню так навскидку чем...). Как минимум тем, что он в Unicode-кодировке. - -================================================ - -Контакты: - -valentin.pavlyuchenko@gmail.com \ No newline at end of file diff --git a/plugins/Boltun/res/Boltun.rc b/plugins/Boltun/res/Boltun.rc new file mode 100644 index 0000000000..4ae46eea47 --- /dev/null +++ b/plugins/Boltun/res/Boltun.rc @@ -0,0 +1,155 @@ +// Microsoft Visual C++ generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (Canada) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENC) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_CAN +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_MAINBOLTUN ICON "res\\boltun.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// SMILES +// + +IDR_SMILES SMILES "res\\smiles.dat" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_MAIN DIALOGEX 0, 0, 307, 231 +STYLE DS_SETFONT | WS_CHILD | WS_BORDER +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Boltun",IDC_PLUGINRM,5,2,297,222 + CONTROL "Boltun Autochat everybody",IDC_EVERYBODY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,20,230,10 + CONTROL "Boltun Autochat everybody not in contact list",IDC_NOTINLIST, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,33,230,10 + CONTROL "Boltun Autochat everybody while away",IDC_AUTOAWAY, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,46,230,10 + CONTROL "Warn contacts Boltun is chatting",IDC_WARN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,59,230,10 + CONTROL "Mark replied messages as read",IDC_MARKREAD,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,72,230,10 + EDITTEXT IDC_WAITTIME,26,161,24,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "sec",IDC_LSEC,53,161,72,8 + EDITTEXT IDC_WARNTXT,17,97,272,31,ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_WANTRETURN | WS_VSCROLL + GROUPBOX "Warning text",IDC_LWARN,12,85,283,50 + GROUPBOX "Time before the answer",IDC_LWAITTIME,12,138,283,72 + CONTROL "Typing time depends on message length (in chars)",IDC_PAUSEDEPENDS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,178,270,11 + CONTROL "Typing and thinking time can be much longer",IDC_PAUSERANDOM, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,21,193,270,10 + LTEXT "Typing time (for a message of 4 words):",IDC_STATIC,21,148,145,8 + LTEXT "Thinking time:",IDC_STATIC,173,148,111,8 + EDITTEXT IDC_THINKTIME,177,161,24,12,ES_AUTOHSCROLL | ES_NUMBER + LTEXT "sec",IDC_LSEC2,205,161,72,8 +END + +IDD_ENGINE DIALOGEX 0, 0, 307, 231 +STYLE DS_SETFONT | WS_CHILD | WS_BORDER +EXSTYLE WS_EX_CONTROLPARENT +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + GROUPBOX "Engine",IDC_PLUGINRM,5,48,297,174 + EDITTEXT IDC_MINDFILE,12,19,210,14,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP + PUSHBUTTON "...",IDC_BTNPATH,226,18,16,16 + GROUPBOX "Base of remarks",IDC_TXTREPLICPATH,5,6,297,36 + PUSHBUTTON "Reload",IDC_BTNRELOAD,246,18,52,16 + CONTROL "Stay silent, if have no good aswers",IDC_ENGINE_SILENT, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,62,283,10 + CONTROL "Start answers with a lowercase letter",IDC_ENGINE_LOWERCASE, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,94,282,10 + CONTROL "Don't use ""I don't understand""-like answers",IDC_ENGINE_UNDERSTAND_ALWAYS, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,27,78,248,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO +BEGIN + IDD_MAIN, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 300 + TOPMARGIN, 7 + BOTTOMMARGIN, 224 + END + + IDD_ENGINE, DIALOG + BEGIN + RIGHTMARGIN, 306 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (Canada) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/plugins/Boltun/resource.h b/plugins/Boltun/resource.h deleted file mode 100644 index b4fa069c0e..0000000000 --- a/plugins/Boltun/resource.h +++ /dev/null @@ -1,46 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Boltun.rc -// -#define IDM_HIDE 0x0010 -#define IDD_MAIN 101 -#define IDI_MAINBOLTUN 102 -#define IDD_ENGINE 103 -#define IDR_SMILES 105 -#define IDI_TICK 106 -#define IDI_NOTICK 107 -#define IDI_RECVMSG 108 -#define IDC_EVERYBODY 1000 -#define IDC_NOTINLIST 1001 -#define IDC_AUTOAWAY 1002 -#define IDC_WARN 1003 -#define IDC_MARKREAD 1004 -#define IDC_LWAITTIME 1005 -#define IDC_WAITTIME 1006 -#define IDC_LSEC 1007 -#define IDC_LWARN 1008 -#define IDC_WARNTXT 1009 -#define IDC_PLUGINRM 1010 -#define IDC_TXTREPLICPATH 1011 -#define IDC_MINDFILE 1012 -#define IDC_BTNPATH 1013 -#define IDC_BTNSAVE 1014 -#define IDC_BTNRELOAD 1015 -#define IDC_PAUSEDEPENDS 1016 -#define IDC_PAUSERANDOM 1017 -#define IDC_THINKTIME 1018 -#define IDC_LSEC2 1019 -#define IDC_ENGINE_SILENT 1020 -#define IDC_ENGINE_LOWERCASE 1021 -#define IDC_ENGINE_UNDERSTAND_ALWAYS 1022 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 106 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1023 -#define _APS_NEXT_SYMED_VALUE 102 -#endif -#endif diff --git a/plugins/Boltun/src/actionQueue.cpp b/plugins/Boltun/src/actionQueue.cpp new file mode 100644 index 0000000000..c464c92f39 --- /dev/null +++ b/plugins/Boltun/src/actionQueue.cpp @@ -0,0 +1,254 @@ +//*********************************************************** +// 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 0x0A00 +#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) +{ + + 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"; + + return PSS_MESSAGE; +} + +static void TimerAnswer(HANDLE hContact, const TalkBot::MessageInfo* info) +{ + DBEVENTINFO ldbei; + int size = (int)info->Answer.length() + 1; + int bufsize = size; + char* msg; + + 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); + + + 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; + + delete msg; + + 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 * (int)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); +} diff --git a/plugins/Boltun/src/actionQueue.h b/plugins/Boltun/src/actionQueue.h new file mode 100644 index 0000000000..78f6ce5f9e --- /dev/null +++ b/plugins/Boltun/src/actionQueue.h @@ -0,0 +1,30 @@ +//*********************************************************** +// 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 . +// +//*********************************************************** + +#ifndef ACTIONQUEUE_H +#define ACTIONQUEUE_H + +#include + +void AnswerToContact(HANDLE hContact, const TCHAR* messageToAnswer); + +void StartChatting(HANDLE hContact); + +#endif /* ACTIONQUEUE_H */ \ No newline at end of file diff --git a/plugins/Boltun/src/boltun.cpp b/plugins/Boltun/src/boltun.cpp new file mode 100644 index 0000000000..52e140d509 --- /dev/null +++ b/plugins/Boltun/src/boltun.cpp @@ -0,0 +1,713 @@ +//*********************************************************** +// 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 . +// +//*********************************************************** + +#define MIRANDA_VER 0x0A00 + +#include "Engine/TalkEngine.h" + +#include +#include +#include + +#include "newpluginapi.h" +#include "m_clist.h" +#include "m_skin.h" +#include "m_database.h" +#include "m_system.h" +#include "m_protosvc.h" +#include "m_options.h" +#include "m_langpack.h" +#include "resource.h" + +#include "resource.h" + +#include "boltun.h" +#include "config.h" +#include "actionQueue.h" + +//#define DEBUG_LOAD_TIME + +int hLangpack; + +TalkBot* bot = NULL; + + +#define MAX_WARN_TEXT 1024 +#define MAX_MIND_FILE 1024 + +HINSTANCE hInst; +BOOL blInit = FALSE; +UINT pTimer = 0; +TCHAR *path; + +PLUGININFOEX pluginInfo={ + sizeof(PLUGININFOEX), + BOLTUN_NAME, + PLUGIN_MAKE_VERSION(0,0,3,0), + PLUGIN_DESCRIPTION, + "Alexander S. Kiselev, Valentin Pavlyuchenko", + "Valentin.Pavlyuchenko@gmail.com", + "© 2003-2008 Alexander S. Kiselev A.K.A. KAS, Valentin Pavlyuchenko", + "http://miranda-im.org", + UNICODE_AWARE, + // {488C5C84-56DA-434F-96F1-B18900DEF760} + { 0x488c5c84, 0x56da, 0x434f, { 0x96, 0xf1, 0xb1, 0x89, 0x0, 0xde, 0xf7, 0x60 } } +}; + +static HANDLE hEventDbEventAdded; +static HANDLE hEventOptInitialise; +static HANDLE hEventPrebuild; +static HANDLE hMenuItemAutoChat; +static HANDLE hMenuItemNotToChat; +static HANDLE hMenuItemStartChatting; + + +#define MIND_DIALOG_FILTER _T("%s (*.mindw)\1*.mindw\1%s (*.*)\1*.*\1") + + +#ifdef DEBUG_LOAD_TIME +#include +#endif + +void UpdateEngine() +{ + if (bot) + { + bot->SetSilent(Config.EngineStaySilent); + bot->SetLowercase(Config.EngineMakeLowerCase); + bot->SetUnderstandAlways(Config.EngineUnderstandAlways); + } +} + +TCHAR* GetFullName(const TCHAR* filename) +{ + size_t flen = _tcslen(filename); + TCHAR* fullname = const_cast(filename); + if (!_tcschr(filename, _T(':'))) + { + size_t plen = _tcslen(path); + fullname = new TCHAR[plen+flen+1]; + fullname[0] = NULL; + _tcscat(fullname, path); + _tcscat(fullname, filename); + } + return fullname; +} + +static bool LoadMind(const TCHAR* filename, int &line) +{ + TCHAR* fullname = GetFullName(filename); + HCURSOR newCur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT)); + HCURSOR oldCur = SetCursor(newCur); +#ifdef DEBUG_LOAD_TIME + unsigned __int64 t = __rdtsc(); +#endif + Mind* mind = new Mind(); + line = -1; + try + { + mind->Load(fullname); + } + catch(Mind::CorruptedMind c) + { + line = c.line; + delete mind; + if (fullname != filename) + delete[] fullname; + SetCursor(oldCur); + return false; + } + catch(...) + { + delete mind; + if (fullname != filename) + delete[] fullname; + SetCursor(oldCur); + return false; + } + if (fullname != filename) + delete[] fullname; + +#ifdef DEBUG_LOAD_TIME + t = __rdtsc() - t; + char dest[101]; + sprintf_s(dest, 100, "%I64d ticks\n", t / 3200000); + MessageBoxA(NULL, dest, NULL, 0); + //exit(0); +#endif + SetCursor(oldCur); + HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(IDR_SMILES), _T("SMILES")); + if (!hRes) + { + delete mind; + return false; + } + DWORD size = SizeofResource(hInst, hRes); + if (!size) + { + delete mind; + return false; + } + HGLOBAL hGlob = LoadResource(hInst, hRes); + if (!hGlob) + { + delete mind; + return false; + } + void *data = LockResource(hGlob); + if (!data) + { + FreeResource(hGlob); + delete mind; + return false; + } + bool res = true; + try + { + mind->LoadSmiles(data, size); + } + catch(...) + { + res = false; + } + UnlockResource(data); + FreeResource(hGlob); + if (!res) + { + delete mind; + return false; + } + if (bot) + delete bot; + bot = new TalkBot(*mind); + delete mind; + UpdateEngine(); + return true; +} + +/*static bool SaveMind(const TCHAR* filename) +{ + if (!bot) + return false; + bot->GetMind().Save(filename); + return true; +}*/ + +static bool BoltunAutoChat(HANDLE hContact) +{ + if (DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_NOT_TO_CHAT + , FALSE) == TRUE) + return false; + + if (Config.TalkWithEverybody) + return true; + + if (Config.TalkEveryoneWhileAway) + { + int status = CallService(MS_CLIST_GETSTATUSMODE, 0, 0); + if (status == ID_STATUS_AWAY || + status == ID_STATUS_DND || + status == ID_STATUS_NA || + status == ID_STATUS_OCCUPIED || + status == ID_STATUS_ONTHEPHONE || + status == ID_STATUS_OUTTOLUNCH) + return true; + } + + if ((DBGetContactSettingByte(hContact,"CList","NotOnList",0) == 1) && + Config.TalkWithNotInList) + return true; + + if (DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_AUTO_CHAT, + FALSE) == TRUE) + return true; + + return false; +} + +static int MessageEventAdded(WPARAM wParam, LPARAM lParam) +{ + //DBEVENTINFO ldbei; + HANDLE hContact = (HANDLE)wParam; + if (!BoltunAutoChat(hContact)) + return 0; + + DBEVENTINFO dbei; + ZeroMemory(&dbei, sizeof(dbei)); + dbei.cbSize = sizeof(dbei); + dbei.cbBlob = 0; + + dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, lParam, 0); + if (dbei.cbBlob == -1) + return 0; + + dbei.pBlob = (PBYTE)malloc(dbei.cbBlob); + if (dbei.pBlob == NULL) + return 0; + + CallService(MS_DB_EVENT_GET, lParam, (LPARAM)&dbei); + if (dbei.flags & DBEF_SENT || dbei.flags & DBEF_READ || dbei.eventType != EVENTTYPE_MESSAGE) + return 0; + DBEVENTGETTEXT egt; + egt.codepage = CP_ACP; + egt.datatype = DBVT_TCHAR; + egt.dbei = &dbei; + TCHAR* s = (TCHAR*)(void*)CallService(MS_DB_EVENT_GETTEXT, 0, (LPARAM)&egt); + free(dbei.pBlob); + if (Config.MarkAsRead) + CallService(MS_DB_EVENT_MARKREAD, wParam, lParam); + + AnswerToContact(hContact, s); + mir_free(s); + return 0; +} + +BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved) +{ + hInst = hinstDLL; + return TRUE; +} + +void UpdateEverybodyCheckboxes(HWND hwndDlg) +{ + bool Enable = !IsDlgButtonChecked(hwndDlg, IDC_EVERYBODY) == BST_CHECKED; + HWND wnd; + wnd = GetDlgItem(hwndDlg, IDC_NOTINLIST); + EnableWindow(wnd, Enable); + wnd = GetDlgItem(hwndDlg, IDC_AUTOAWAY); + EnableWindow(wnd, Enable); +} + +static INT_PTR CALLBACK MainDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + BOOL bTranslated = FALSE; + static bool loading = true; + switch (uMsg) + { + case WM_INITDIALOG: + loading = true; + TranslateDialogDefault(hwndDlg); + CheckDlgButton(hwndDlg, IDC_EVERYBODY, Config.TalkWithEverybody ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_NOTINLIST, Config.TalkWithNotInList ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_AUTOAWAY, Config.TalkEveryoneWhileAway ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_WARN, Config.TalkWarnContacts ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_MARKREAD, Config.MarkAsRead ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_PAUSEDEPENDS, Config.PauseDepends ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_PAUSERANDOM, Config.PauseRandom ? BST_CHECKED : BST_UNCHECKED); + SendDlgItemMessage(hwndDlg, IDC_WAITTIME, EM_SETLIMITTEXT, 3, 0); + SetDlgItemInt(hwndDlg, IDC_WAITTIME, Config.AnswerPauseTime, FALSE); + SendDlgItemMessage(hwndDlg, IDC_THINKTIME, EM_SETLIMITTEXT, 3, 0); + SetDlgItemInt(hwndDlg, IDC_THINKTIME, Config.AnswerThinkTime, FALSE); + SendDlgItemMessage(hwndDlg, IDC_WARNTXT, EM_SETLIMITTEXT, MAX_WARN_TEXT, 0); + SetDlgItemText(hwndDlg, IDC_WARNTXT, Config.WarnText); + UpdateEverybodyCheckboxes(hwndDlg); + loading = false; + return TRUE; + case WM_COMMAND: + if (LOWORD(wParam) == IDC_EVERYBODY && HIWORD(wParam) == BN_CLICKED) + UpdateEverybodyCheckboxes(hwndDlg); + if (!loading) + { + bool notify = true; + switch (LOWORD(wParam)) + { + case IDC_WARNTXT: + case IDC_WAITTIME: + case IDC_THINKTIME: + if (HIWORD(wParam) != EN_CHANGE) + notify = false; + break; + } + if (notify) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + break; + case WM_NOTIFY: + { + NMHDR* nmhdr = (NMHDR*)lParam; + switch (nmhdr->code) + { + case PSN_APPLY: + case PSN_KILLACTIVE: + { + Config.TalkWithEverybody = IsDlgButtonChecked(hwndDlg, IDC_EVERYBODY) == BST_CHECKED ? TRUE : FALSE; + Config.TalkWithNotInList = IsDlgButtonChecked(hwndDlg, IDC_NOTINLIST) == BST_CHECKED ? TRUE : FALSE; + Config.TalkEveryoneWhileAway = IsDlgButtonChecked(hwndDlg, IDC_AUTOAWAY) == BST_CHECKED ? TRUE : FALSE; + Config.TalkWarnContacts = IsDlgButtonChecked(hwndDlg, IDC_WARN) == BST_CHECKED ? TRUE : FALSE; + Config.MarkAsRead = IsDlgButtonChecked(hwndDlg, IDC_MARKREAD) == BST_CHECKED ? TRUE : FALSE; + Config.PauseDepends = IsDlgButtonChecked(hwndDlg, IDC_PAUSEDEPENDS) == BST_CHECKED ? TRUE : FALSE; + Config.PauseRandom = IsDlgButtonChecked(hwndDlg, IDC_PAUSERANDOM) == BST_CHECKED ? TRUE : FALSE; + Config.AnswerPauseTime = GetDlgItemInt(hwndDlg, IDC_WAITTIME, &bTranslated, FALSE); + if (!bTranslated) + Config.AnswerPauseTime = 2; + Config.AnswerThinkTime = GetDlgItemInt(hwndDlg, IDC_THINKTIME, &bTranslated, FALSE); + if (!bTranslated) + Config.AnswerThinkTime = 4; + TCHAR c[MAX_WARN_TEXT]; + bTranslated = GetDlgItemText(hwndDlg, IDC_WARNTXT, c, MAX_WARN_TEXT); + if(bTranslated) + Config.WarnText = c; + else + Config.WarnText = TranslateTS(DEFAULT_WARN_TEXT); + } + return TRUE; + } + break; + } + break; + } + return 0; +} + +void UpdateUnderstandAlwaysCheckbox(HWND hwndDlg) +{ + bool Enable = !IsDlgButtonChecked(hwndDlg, IDC_ENGINE_SILENT) == BST_CHECKED; + HWND wnd; + wnd = GetDlgItem(hwndDlg, IDC_ENGINE_UNDERSTAND_ALWAYS); + EnableWindow(wnd, Enable); +} + +static INT_PTR CALLBACK EngineDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + WORD param; + BOOL bTranslated = FALSE; + static bool loading = true; + static int changeCount = 0; + switch (uMsg) + { + case WM_INITDIALOG: + loading = true; + TranslateDialogDefault(hwndDlg); + CheckDlgButton(hwndDlg, IDC_ENGINE_SILENT, Config.EngineStaySilent ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_ENGINE_LOWERCASE, Config.EngineMakeLowerCase ? BST_CHECKED : BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_ENGINE_UNDERSTAND_ALWAYS, Config.EngineUnderstandAlways ? BST_CHECKED : BST_UNCHECKED); + SetDlgItemText(hwndDlg, IDC_MINDFILE, Config.MindFileName); + EnableWindow(GetDlgItem(hwndDlg, IDC_BTNSAVE), blInit); + UpdateUnderstandAlwaysCheckbox(hwndDlg); + loading = false; + return TRUE; + case WM_COMMAND: + param = LOWORD(wParam); + if (param == IDC_ENGINE_SILENT && HIWORD(wParam) == BN_CLICKED) + UpdateUnderstandAlwaysCheckbox(hwndDlg); + OPENFILENAME ofn; + switch(param) + { + case IDC_BTNPATH: + { + const size_t fileNameSize = 5000; + TCHAR *filename = new TCHAR[fileNameSize]; + TCHAR *fullname = GetFullName(Config.MindFileName); + _tcscpy(filename, fullname); + if (fullname != Config.MindFileName) + delete[] fullname; + + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = GetParent(hwndDlg); + + TCHAR* mind = TranslateTS(MIND_FILE_DESC); + TCHAR* anyfile = TranslateTS(ALL_FILES_DESC); + size_t l = _tcslen(MIND_DIALOG_FILTER) + + _tcslen(mind) + _tcslen(anyfile); + TCHAR *filt = new TCHAR[l]; + wsprintf(filt, MIND_DIALOG_FILTER, mind, anyfile); + for (size_t i = 0; i < l; i++) + if (filt[i] == '\1') + filt[i] = '\0'; + ofn.lpstrFilter = filt; + + ofn.lpstrFile = filename; + ofn.nMaxFile = fileNameSize; + ofn.Flags = OFN_FILEMUSTEXIST; + ofn.lpstrInitialDir = path; + if (!GetOpenFileName(&ofn)) + { + delete filename; + delete[] filt; + break; + } + delete[] filt; + TCHAR* origf = filename; + TCHAR* f = filename; + TCHAR* p = path; + while (*p && *f) + { + TCHAR p1 = (TCHAR)CharLower((TCHAR*)(long)*p++); + TCHAR f1 = (TCHAR)CharLower((TCHAR*)(long)*f++); + if (p1 != f1) + break; + } + if (!*p) + filename = f; + Config.MindFileName = filename; + SetDlgItemText(hwndDlg, IDC_MINDFILE, filename); + delete origf; + } + case IDC_BTNRELOAD: + { + const TCHAR *c = Config.MindFileName; + int line; + bTranslated = blInit = LoadMind(c, line); + if (!bTranslated) + { + TCHAR* message = new TCHAR[5000]; + wsprintf(message, TranslateTS(FAILED_TO_LOAD_BASE), line, c); + MessageBox(NULL, message, TranslateTS(BOLTUN_ERROR), MB_ICONERROR|MB_TASKMODAL|MB_OK); + delete[] message; + } + break; + } + default: + if (!loading) + { + if (param == IDC_MINDFILE/* && HIWORD(wParam) != EN_CHANGE*/) + break; + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + break; + case WM_NOTIFY: + { + NMHDR* nmhdr = (NMHDR*)lParam; + switch (nmhdr->code) + { + case PSN_APPLY: + case PSN_KILLACTIVE: + { + Config.EngineStaySilent = IsDlgButtonChecked(hwndDlg, IDC_ENGINE_SILENT) == BST_CHECKED ? TRUE : FALSE; + Config.EngineMakeLowerCase = IsDlgButtonChecked(hwndDlg, IDC_ENGINE_LOWERCASE) == BST_CHECKED ? TRUE : FALSE; + Config.EngineUnderstandAlways = IsDlgButtonChecked(hwndDlg, IDC_ENGINE_UNDERSTAND_ALWAYS) == BST_CHECKED ? TRUE : FALSE; + UpdateEngine(); + TCHAR c[MAX_MIND_FILE]; + bTranslated = GetDlgItemText(hwndDlg, IDC_MINDFILE, c, MAX_MIND_FILE); + if (bTranslated) + Config.MindFileName = c; + else + Config.MindFileName = DEFAULT_MIND_FILE; + } + return TRUE; + } + break; + } + break; + } + return 0; +} + +static int MessageOptInit(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp; + + ZeroMemory(&odp, sizeof(odp)); + odp.cbSize = sizeof(odp); + odp.position = 910000000; + odp.hInstance = hInst; + odp.pszGroup = BOLTUN_GROUP; + odp.pszTitle = BOLTUN_NAME; + odp.pfnDlgProc = MainDlgProc; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_MAIN); + odp.pszTab = TAB_GENERAL; + Options_AddPage(wParam, &odp); + odp.pfnDlgProc = EngineDlgProc; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_ENGINE); + odp.pszTab = TAB_ENGINE; + Options_AddPage(wParam, &odp); + return 0; +} + +static int ContactClick(WPARAM wParam, LPARAM lParam, BOOL clickNotToChat) +{ + HANDLE hContact = (HANDLE)wParam; + + BOOL boltunautochat = DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_AUTO_CHAT, FALSE); + BOOL boltunnottochat = DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_NOT_TO_CHAT, FALSE); + + if (clickNotToChat) + { + boltunnottochat = !boltunnottochat; + if(boltunnottochat) + { + boltunautochat = FALSE; + } + } + else + { + boltunautochat = !boltunautochat; + if(boltunautochat) + { + boltunnottochat = FALSE; + } + else + { + DBWriteContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_WARNED, FALSE); + } + } + + DBWriteContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_AUTO_CHAT, (BYTE)boltunautochat); + DBWriteContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_NOT_TO_CHAT, (BYTE)boltunnottochat); + + return 0; +} + +static INT_PTR ContactClickAutoChat(WPARAM wParam, LPARAM lParam) +{ + return ContactClick(wParam, lParam, 0); +} + +static INT_PTR ContactClickNotToChat(WPARAM wParam, LPARAM lParam) +{ + return ContactClick(wParam, lParam, 1); +} + +static INT_PTR ContactClickStartChatting(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + StartChatting(hContact); + return 0; +} + +static int MessagePrebuild(WPARAM wParam, LPARAM lParam) +{ + CLISTMENUITEM clmi; + HANDLE hContact = (HANDLE)wParam; + + if (!blInit || (DBGetContactSettingByte(hContact,"CList","NotOnList",0) == 1)) + { + ZeroMemory(&clmi, sizeof(clmi)); + clmi.cbSize = sizeof(clmi); + clmi.flags = CMIM_FLAGS | CMIF_GRAYED; + + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemAutoChat, (LPARAM)&clmi); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemNotToChat, (LPARAM)&clmi); + } + else + { + BOOL boltunautochat = DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_AUTO_CHAT, FALSE); + BOOL boltunnottochat = DBGetContactSettingByte(hContact, BOLTUN_KEY, DB_CONTACT_BOLTUN_NOT_TO_CHAT, FALSE); + ZeroMemory(&clmi, sizeof(clmi)); + clmi.cbSize = sizeof(clmi); + clmi.flags = CMIM_FLAGS | CMIM_ICON | (boltunautochat ? CMIF_CHECKED : 0); + clmi.hIcon = LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE((boltunautochat ? IDI_TICK : IDI_NOTICK))); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemAutoChat, (LPARAM)&clmi); + + clmi.flags = CMIM_FLAGS | CMIM_ICON | (boltunnottochat ? CMIF_CHECKED : 0); + clmi.hIcon = LoadIcon( GetModuleHandle(NULL), MAKEINTRESOURCE((boltunnottochat ? IDI_TICK : IDI_NOTICK))); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hMenuItemNotToChat, (LPARAM)&clmi); + } + return 0; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +extern "C" int __declspec(dllexport) Load(void) +{ + mir_getLP(&pluginInfo); + + path = new TCHAR[MAX_PATH]; + int len = GetModuleFileName(hInst, path, MAX_PATH); + if (len > MAX_PATH) + { + delete[] path; + TCHAR *path = new TCHAR[len]; + int len2 = GetModuleFileName(hInst, path, len); + if (len2 != len) + { + delete[] path; + return false; + } + } + *(_tcsrchr(path, _T('\\'))+1) = _T('\0'); + + /*initialize miranda hooks and services on options dialog*/ + hEventOptInitialise = HookEvent(ME_OPT_INITIALISE, MessageOptInit); + /*initialize miranda hooks and services*/ + hEventDbEventAdded = HookEvent(ME_DB_EVENT_ADDED, MessageEventAdded); + hEventPrebuild = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, MessagePrebuild); + + CreateServiceFunction(SERV_CONTACT_AUTO_CHAT, ContactClickAutoChat); + CreateServiceFunction(SERV_CONTACT_NOT_TO_CHAT, ContactClickNotToChat); + CreateServiceFunction(SERV_CONTACT_START_CHATTING, ContactClickStartChatting); + { + CLISTMENUITEM mi; + + ZeroMemory(&mi,sizeof(mi)); + mi.cbSize = sizeof(mi); + mi.position = -50010002; //TODO: check the warning + mi.flags = 0; + mi.hIcon = NULL; + mi.pszContactOwner = NULL; + mi.pszName = BOLTUN_AUTO_CHAT; + mi.pszService = SERV_CONTACT_AUTO_CHAT; + hMenuItemAutoChat = Menu_AddContactMenuItem(&mi); + + mi.position = -50010001; //TODO: check the warning + mi.pszName = BOLTUN_NOT_TO_CHAT; + mi.pszService = SERV_CONTACT_NOT_TO_CHAT; + hMenuItemNotToChat = Menu_AddContactMenuItem(&mi); + + mi.flags = CMIF_NOTOFFLINE; + mi.position = -50010000; //TODO: check the warning + mi.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_RECVMSG)); + mi.pszName = BOLTUN_START_CHATTING; + mi.pszService = SERV_CONTACT_START_CHATTING; + hMenuItemStartChatting = Menu_AddContactMenuItem(&mi); + } + int line; + blInit = LoadMind(Config.MindFileName, line); + if (!blInit) + { + TCHAR path[2000]; + wsprintf(path, TranslateTS(FAILED_TO_LOAD_BASE), line, (const TCHAR*)Config.MindFileName); + MessageBox(NULL, path, TranslateTS(BOLTUN_ERROR), MB_ICONERROR|MB_TASKMODAL|MB_OK); + } + /*record for Uninstall plugin*/ + DBWriteContactSettingString(NULL, "Uninstall", BOLTUN_NAME, BOLTUN_KEY); + return 0; +} + +extern "C" int __declspec(dllexport) Unload(void) +{ + if (pTimer) + KillTimer(NULL, pTimer); + if(blInit) + { +#if 0 //No need to save, we don't have studying algorithm + if(Config.MindFileName && !SaveMind(Config.MindFileName)) + { +//This causes errors with development core when calling MessageBox. +//It seems that it's now a Boltun problem. +//So in case of saving error we will remain silent +#if 0 + TCHAR path[MAX_PATH]; + wsprintf(path, TranslateTS(FAILED_TO_SAVE_BASE), (const TCHAR*)Config.MindFileName); + TCHAR* err = TranslateTS(BOLTUN_ERROR); + MessageBox(NULL, path, err, MB_ICONERROR|MB_TASKMODAL|MB_OK);*/ +#endif + } +#endif + delete bot; + } + delete[] path; + return 0; +} diff --git a/plugins/Boltun/src/boltun.h b/plugins/Boltun/src/boltun.h new file mode 100644 index 0000000000..914869387c --- /dev/null +++ b/plugins/Boltun/src/boltun.h @@ -0,0 +1,74 @@ +//*********************************************************** +// 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 . +// +//*********************************************************** + +#ifndef _BOLTUN_H +#define _BOLTUN_H + +//Should use different keys in UNICODE and ANSI builds, because usage of plugin +//with old (another) configs will cause crashes. + +#define BOLTUN_KEY "Boltun" + + +//Service names +#define SERV_CONTACT_AUTO_CHAT "Boltun/ContactAutoChat" +#define SERV_CONTACT_NOT_TO_CHAT "Boltun/ContactNotToChat" +#define SERV_CONTACT_START_CHATTING "Boltun/ContactStartChatting" + +//Database keys +#define DB_CONTACT_BOLTUN_NOT_TO_CHAT "BoltunNotToChat" +#define DB_CONTACT_BOLTUN_AUTO_CHAT "BoltunAutoChat" +#define DB_CONTACT_WARNED "Warned" + +//Plugin group in settings +#define BOLTUN_GROUP "Message sessions" + +//Filename depends on UNICODE +#define DEFAULT_MIND_FILE _T("boltun.mindw") + +//=============================================== +// These are strings for translation: +//=============================================== + +//Plugin name +#define BOLTUN_NAME "Boltun" + +#define PLUGIN_DESCRIPTION "Boltun, the chat bot in the russian language." + +#define MIND_FILE_DESC _T("Mind Files") +#define ALL_FILES_DESC _T("All Files") + +//UI strings +#define BOLTUN_AUTO_CHAT "Boltun/Auto Chat" +#define BOLTUN_NOT_TO_CHAT "Boltun/Not to Chat" +#define BOLTUN_START_CHATTING "Boltun/Start Chatting" + +#define DEFAULT_WARN_TEXT _T("Hello. I'm Boltun! I'll talk to you, while my owner is away. Please write without mistakes!") + +// Error messages +#define BOLTUN_ERROR _T("Boltun Error") +#define FAILED_TO_LOAD_BASE _T("Failed to load base of remarks. Error at line %d of %s. (Or few lines before).") +#define FAILED_TO_SAVE_BASE _T("Failed to save base of remarks to %s") + +//Settings tab names +#define TAB_GENERAL "General Settings" +#define TAB_ENGINE "Engine Settings" + +#endif /*_BOLTUN_H*/ diff --git a/plugins/Boltun/src/config.cpp b/plugins/Boltun/src/config.cpp new file mode 100644 index 0000000000..4a88bf2df3 --- /dev/null +++ b/plugins/Boltun/src/config.cpp @@ -0,0 +1,159 @@ +//*********************************************************** +// 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 "config.h" + +#include +#include +#include + +#include "newpluginapi.h" +#include "m_database.h" +#include "m_langpack.h" +#include "boltun.h" + +//Database keys +#define DB_EVERYBODY "Everybody" +#define DB_NOT_IN_LIST "NotInList" +#define DB_AUTOAWAY "AutoAway" +#define DB_WARN "Warn" +#define DB_MARK_READ "MarkRead" +#define DB_WAIT_TIME "WaitTime" +#define DB_THINK_TIME "ThinkTime" +#define DB_PAUSE_DEPENDS "PauseDepends" +#define DB_PAUSE_RANDOM "PauseRandom" +#define DB_WARN_TEXT "WarnText" +#define DB_MIND_FILE_NAME "MindFileName" +#define DB_ENGINE_SILENT "SilentEngine" +#define DB_ENGINE_LOWERCASE "MakeLowerCase" +#define DB_ENGINE_UNDERSTAND_ALWAYS "UnderstandAlways" + +inline TCHAR* GetString(char* key, const TCHAR* def) +{ + DBVARIANT dbv; + TCHAR* val; + if (!DBGetContactSettingTString(NULL, BOLTUN_KEY, key, &dbv)) + { + size_t len = wcslen(dbv.ptszVal) + 1; + val = new TCHAR[len]; + _tcscpy_s(val, len, dbv.ptszVal); + DBFreeVariant(&dbv); + } + else + { + size_t len = wcslen(def) + 1; + val = new TCHAR[len]; + _tcscpy_s(val, len, def); + } + return val; +} + +inline const TCHAR* SetString(char* key, const TCHAR* value) +{ + size_t len = _tcslen(value) + 1; + TCHAR* val = new TCHAR[len]; + _tcscpy_s(val, len, value); + DBWriteContactSettingTString(NULL, BOLTUN_KEY, key, val); + return val; +} + +#define BUILDETTERS(x, str, def) \ + const bool BoltunConfig::Get##x() { \ + return DBGetContactSettingDword(NULL, BOLTUN_KEY, str, def) != 0; } \ + const bool BoltunConfig::Set##x(const bool value) { \ + DBWriteContactSettingDword(NULL, BOLTUN_KEY, str, value); \ + return value; } + +#define BUILDINTETTERS(x, str, def) \ + const int BoltunConfig::Get##x() { \ + return DBGetContactSettingDword(NULL, BOLTUN_KEY, str, def); } \ + const int BoltunConfig::Set##x(const int value) { \ + DBWriteContactSettingDword(NULL, BOLTUN_KEY, str, value); \ + return value; } + +#define BUILDSTRETTERS(x, str, def) \ + const TCHAR* BoltunConfig::Get##x() { \ + return GetString(str, def); } \ + const TCHAR* BoltunConfig::Set##x(const TCHAR* value) { \ + return SetString(str, value); } + +#define BUILDINIT(x) \ + x(&BoltunConfig::Get##x, &BoltunConfig::Set##x) + +BUILDETTERS(TalkWithNotInList, DB_NOT_IN_LIST, false); +BUILDETTERS(TalkWithEverybody, DB_EVERYBODY, false); +BUILDETTERS(TalkWarnContacts, DB_WARN, false); +BUILDETTERS(TalkEveryoneWhileAway, DB_AUTOAWAY, false); +BUILDETTERS(MarkAsRead, DB_MARK_READ, true); +BUILDINTETTERS(AnswerPauseTime, DB_WAIT_TIME, 2); +BUILDINTETTERS(AnswerThinkTime, DB_THINK_TIME, 4); +BUILDETTERS(PauseDepends, DB_PAUSE_DEPENDS, TRUE); +BUILDETTERS(PauseRandom, DB_PAUSE_RANDOM, TRUE); +BUILDSTRETTERS(WarnText, DB_WARN_TEXT, TranslateTS(DEFAULT_WARN_TEXT)); +BUILDSTRETTERS(MindFileName, DB_MIND_FILE_NAME, DEFAULT_MIND_FILE); +BUILDETTERS(EngineStaySilent, DB_ENGINE_SILENT, FALSE); +BUILDETTERS(EngineMakeLowerCase, DB_ENGINE_LOWERCASE, FALSE); +BUILDETTERS(EngineUnderstandAlways, DB_ENGINE_UNDERSTAND_ALWAYS, FALSE); + +BoltunConfig::BoltunConfig() + :BUILDINIT(TalkWithEverybody), + BUILDINIT(TalkWithNotInList), + BUILDINIT(TalkWarnContacts), + BUILDINIT(TalkEveryoneWhileAway), + BUILDINIT(MarkAsRead), + BUILDINIT(AnswerPauseTime), + BUILDINIT(AnswerThinkTime), + BUILDINIT(PauseDepends), + BUILDINIT(PauseRandom), + BUILDINIT(WarnText), + BUILDINIT(MindFileName), + BUILDINIT(EngineStaySilent), + BUILDINIT(EngineMakeLowerCase), + BUILDINIT(EngineUnderstandAlways) +{ + TalkWithEverybody.SetOwner(this); + TalkWithNotInList.SetOwner(this); + TalkWarnContacts.SetOwner(this); + TalkEveryoneWhileAway.SetOwner(this); + MarkAsRead.SetOwner(this); + AnswerPauseTime.SetOwner(this); + AnswerThinkTime.SetOwner(this); + PauseDepends.SetOwner(this); + PauseRandom.SetOwner(this); + WarnText.SetOwner(this); + MindFileName.SetOwner(this); + EngineStaySilent.SetOwner(this); + EngineMakeLowerCase.SetOwner(this); + EngineUnderstandAlways.SetOwner(this); +} + +BoltunConfig::~BoltunConfig() +{ +} + +class _BoltunConfigInit +{ +public: + BoltunConfig cfg; +}; + +_BoltunConfigInit inst; + +BoltunConfig &Config = inst.cfg; \ No newline at end of file diff --git a/plugins/Boltun/src/config.h b/plugins/Boltun/src/config.h new file mode 100644 index 0000000000..c5bb20e700 --- /dev/null +++ b/plugins/Boltun/src/config.h @@ -0,0 +1,157 @@ +//*********************************************************** +// 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 . +// +//*********************************************************** + +#ifndef _CONFIG_H +#define _CONFIG_H + +#include + +class BoltunConfig; + +template +class Property +{ +public: + typedef const T (__thiscall BaseClass::*Getter)(); + typedef const T (__thiscall BaseClass::*Setter)(const T); +private: + const Getter getter; + const Setter setter; + BaseClass* owner; + bool cacheValid; + T cached; +public: + Property(Getter g, Setter s) + :getter(g), setter(s), cacheValid(false) + { + } + + void SetOwner(BaseClass* o) + { + owner = o; + } + + inline operator const T() + { + if (cacheValid) + return cached; + cached = (owner->*getter)(); + cacheValid = true; + return cached; + } + + inline const T operator= (const T& value) + { + cacheValid = true; + return (owner->*setter)(cached = value); + } +}; + +template +class PtrProperty +{ +public: + typedef const T* (__thiscall BaseClass::*Getter)(); + typedef const T* (__thiscall BaseClass::*Setter)(const T*); +private: + const Getter getter; + const Setter setter; + BaseClass* owner; + bool cacheValid; + const T* cached; +public: + PtrProperty(Getter g, Setter s) + :getter(g), setter(s), cacheValid(false), cached(NULL) + { + } + + ~PtrProperty() + { + delete cached; + } + + void SetOwner(BaseClass* o) + { + owner = o; + } + + inline operator const T*() + { + if (cacheValid) + return cached; + cached = (owner->*getter)(); + cacheValid = true; + return cached; + } + + inline const T* operator= (const T* value) + { + cacheValid = true; + delete cached; + cached = (owner->*setter)(value); + return cached; + } +}; + +class _BoltunConfigInit; + +#define BUILDDEFETTERS(x, typ) \ + const typ Get##x(); \ + const typ Set##x(const typ value); + +class BoltunConfig +{ + BUILDDEFETTERS(TalkWithEverybody, bool); + BUILDDEFETTERS(TalkWithNotInList, bool); + BUILDDEFETTERS(TalkWarnContacts, bool); + BUILDDEFETTERS(TalkEveryoneWhileAway, bool); + BUILDDEFETTERS(MarkAsRead, bool); + BUILDDEFETTERS(AnswerPauseTime, int); + BUILDDEFETTERS(AnswerThinkTime, int); + BUILDDEFETTERS(PauseDepends, bool); + BUILDDEFETTERS(PauseRandom, bool); + BUILDDEFETTERS(WarnText, TCHAR*); + BUILDDEFETTERS(MindFileName, TCHAR*); + BUILDDEFETTERS(EngineStaySilent, bool); + BUILDDEFETTERS(EngineMakeLowerCase, bool); + BUILDDEFETTERS(EngineUnderstandAlways, bool); + BoltunConfig(); + ~BoltunConfig(); + friend class _BoltunConfigInit; +public: + Property TalkWithEverybody; + Property TalkWithNotInList; + Property TalkWarnContacts; + Property TalkEveryoneWhileAway; + Property MarkAsRead; + Property AnswerPauseTime; + Property AnswerThinkTime; + Property PauseDepends; + Property PauseRandom; + PtrProperty WarnText; + PtrProperty MindFileName; + Property EngineStaySilent; + Property EngineMakeLowerCase; + Property EngineUnderstandAlways; +}; + +extern BoltunConfig &Config; + +#endif /* _CONFIG_H */ \ No newline at end of file diff --git a/plugins/Boltun/src/resource.h b/plugins/Boltun/src/resource.h new file mode 100644 index 0000000000..b4fa069c0e --- /dev/null +++ b/plugins/Boltun/src/resource.h @@ -0,0 +1,46 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Boltun.rc +// +#define IDM_HIDE 0x0010 +#define IDD_MAIN 101 +#define IDI_MAINBOLTUN 102 +#define IDD_ENGINE 103 +#define IDR_SMILES 105 +#define IDI_TICK 106 +#define IDI_NOTICK 107 +#define IDI_RECVMSG 108 +#define IDC_EVERYBODY 1000 +#define IDC_NOTINLIST 1001 +#define IDC_AUTOAWAY 1002 +#define IDC_WARN 1003 +#define IDC_MARKREAD 1004 +#define IDC_LWAITTIME 1005 +#define IDC_WAITTIME 1006 +#define IDC_LSEC 1007 +#define IDC_LWARN 1008 +#define IDC_WARNTXT 1009 +#define IDC_PLUGINRM 1010 +#define IDC_TXTREPLICPATH 1011 +#define IDC_MINDFILE 1012 +#define IDC_BTNPATH 1013 +#define IDC_BTNSAVE 1014 +#define IDC_BTNRELOAD 1015 +#define IDC_PAUSEDEPENDS 1016 +#define IDC_PAUSERANDOM 1017 +#define IDC_THINKTIME 1018 +#define IDC_LSEC2 1019 +#define IDC_ENGINE_SILENT 1020 +#define IDC_ENGINE_LOWERCASE 1021 +#define IDC_ENGINE_UNDERSTAND_ALWAYS 1022 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 106 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1023 +#define _APS_NEXT_SYMED_VALUE 102 +#endif +#endif -- cgit v1.2.3