diff options
26 files changed, 2089 insertions, 0 deletions
diff --git a/protocols/MinecraftDynmap/MinecraftDynmap.vcxproj b/protocols/MinecraftDynmap/MinecraftDynmap.vcxproj new file mode 100644 index 0000000000..6228f36c7c --- /dev/null +++ b/protocols/MinecraftDynmap/MinecraftDynmap.vcxproj @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectGuid>{D5E2FEC1-B29A-476C-BD41-469FE282EE0F}</ProjectGuid> + <ProjectName>MinecraftDynmap</ProjectName> + </PropertyGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(ProjectDir)..\..\build\vc.common\common.props" /> + </ImportGroup> + <ItemDefinitionGroup> + <ClCompile> + <ExceptionHandling>Sync</ExceptionHandling> + </ClCompile> + </ItemDefinitionGroup> +</Project>
\ No newline at end of file diff --git a/protocols/MinecraftDynmap/MinecraftDynmap.vcxproj.filters b/protocols/MinecraftDynmap/MinecraftDynmap.vcxproj.filters new file mode 100644 index 0000000000..fcae13a9d8 --- /dev/null +++ b/protocols/MinecraftDynmap/MinecraftDynmap.vcxproj.filters @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" /> +</Project>
\ No newline at end of file diff --git a/protocols/MinecraftDynmap/docs/readme.txt b/protocols/MinecraftDynmap/docs/readme.txt new file mode 100644 index 0000000000..2b9ed73043 --- /dev/null +++ b/protocols/MinecraftDynmap/docs/readme.txt @@ -0,0 +1,2 @@ +Icons by alex watts +From: http://findicons.com/icon/457062/minecraft1
\ No newline at end of file diff --git a/protocols/MinecraftDynmap/proto_minecraftdynmap/minecraftdynmap_icons.vcxproj b/protocols/MinecraftDynmap/proto_minecraftdynmap/minecraftdynmap_icons.vcxproj new file mode 100644 index 0000000000..a96b125f8a --- /dev/null +++ b/protocols/MinecraftDynmap/proto_minecraftdynmap/minecraftdynmap_icons.vcxproj @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <PropertyGroup Label="Globals"> + <ProjectName>Proto_MinecraftDynmap</ProjectName> + <ProjectGuid>{C5AB34D2-15F5-4CBA-8F42-DB48A4E52910}</ProjectGuid> + </PropertyGroup> + <ImportGroup Label="PropertySheets"> + <Import Project="$(ProjectDir)..\..\..\build\vc.common\icons.props" /> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/protocols/MinecraftDynmap/proto_minecraftdynmap/minecraftdynmap_icons.vcxproj.filters b/protocols/MinecraftDynmap/proto_minecraftdynmap/minecraftdynmap_icons.vcxproj.filters new file mode 100644 index 0000000000..28f81e7f1b --- /dev/null +++ b/protocols/MinecraftDynmap/proto_minecraftdynmap/minecraftdynmap_icons.vcxproj.filters @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(ProjectDir)..\..\..\build\vc.common\common.filters" /> +</Project>
\ No newline at end of file diff --git a/protocols/MinecraftDynmap/proto_minecraftdynmap/res/Offline.ico b/protocols/MinecraftDynmap/proto_minecraftdynmap/res/Offline.ico Binary files differnew file mode 100644 index 0000000000..a44000b281 --- /dev/null +++ b/protocols/MinecraftDynmap/proto_minecraftdynmap/res/Offline.ico diff --git a/protocols/MinecraftDynmap/proto_minecraftdynmap/res/Online.ico b/protocols/MinecraftDynmap/proto_minecraftdynmap/res/Online.ico Binary files differnew file mode 100644 index 0000000000..38e4cf30fe --- /dev/null +++ b/protocols/MinecraftDynmap/proto_minecraftdynmap/res/Online.ico diff --git a/protocols/MinecraftDynmap/proto_minecraftdynmap/res/minecraftdynmap_icons.rc b/protocols/MinecraftDynmap/proto_minecraftdynmap/res/minecraftdynmap_icons.rc new file mode 100644 index 0000000000..7e1f349d9c --- /dev/null +++ b/protocols/MinecraftDynmap/proto_minecraftdynmap/res/minecraftdynmap_icons.rc @@ -0,0 +1,73 @@ +// Microsoft Visual C++ generated resource script. +// +#include "..\src\resource_icons.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// Czech resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CSY) +#ifdef _WIN32 +LANGUAGE LANG_CZECH, SUBLANG_DEFAULT +#pragma code_page(1250) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "..\\src\\resource_icons.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_OFFLINE ICON "Offline.ico" +IDI_ONLINE ICON "Online.ico" +#endif // Czech resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/protocols/MinecraftDynmap/proto_minecraftdynmap/src/resource_icons.h b/protocols/MinecraftDynmap/proto_minecraftdynmap/src/resource_icons.h new file mode 100644 index 0000000000..3b6e06c058 --- /dev/null +++ b/protocols/MinecraftDynmap/proto_minecraftdynmap/src/resource_icons.h @@ -0,0 +1,17 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by omegle_icons.rc +// +#define IDI_OFFLINE 105 +#define IDI_ONLINE 104 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/protocols/MinecraftDynmap/res/proto.ico b/protocols/MinecraftDynmap/res/proto.ico Binary files differnew file mode 100644 index 0000000000..38e4cf30fe --- /dev/null +++ b/protocols/MinecraftDynmap/res/proto.ico diff --git a/protocols/MinecraftDynmap/res/resource.rc b/protocols/MinecraftDynmap/res/resource.rc new file mode 100644 index 0000000000..fa15f960a8 --- /dev/null +++ b/protocols/MinecraftDynmap/res/resource.rc @@ -0,0 +1,127 @@ +// Microsoft Visual C++ generated resource script.
+//
+#include "..\src\resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+#include "..\src\constants.h"
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Czech (Czech Republic) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CSY)
+LANGUAGE LANG_CZECH, SUBLANG_DEFAULT
+#pragma code_page(1250)
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "..\\src\\resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "#include ""..\\src\\constants.h""\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_PROTO ICON "proto.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_OPTIONS DIALOGEX 0, 0, 316, 235
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Server:",IDC_STATIC,14,9,64,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_SERVER,84,7,124,14,ES_AUTOHSCROLL
+ LTEXT "Visible name:",IDC_STATIC,14,25,64,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_NAME,84,22,124,14,ES_AUTOHSCROLL
+END
+
+IDD_MinecraftDynmapACCOUNT DIALOGEX 0, 0, 186, 134
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ LTEXT "Server:",IDC_STATIC,0,2,60,8
+ EDITTEXT IDC_SERVER,60,0,125,14,ES_AUTOHSCROLL
+ LTEXT "Visible name:",IDC_STATIC,0,18,60,8
+ EDITTEXT IDC_NAME,60,16,125,14,ES_AUTOHSCROLL
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_OPTIONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 309
+ VERTGUIDE, 14
+ VERTGUIDE, 78
+ VERTGUIDE, 84
+ VERTGUIDE, 208
+ VERTGUIDE, 214
+ VERTGUIDE, 302
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 228
+ END
+
+ IDD_MinecraftDynmapACCOUNT, DIALOG
+ BEGIN
+ VERTGUIDE, 60
+ VERTGUIDE, 185
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // Czech (Czech Republic) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/protocols/MinecraftDynmap/res/version.rc b/protocols/MinecraftDynmap/res/version.rc new file mode 100644 index 0000000000..675d852de7 --- /dev/null +++ b/protocols/MinecraftDynmap/res/version.rc @@ -0,0 +1,38 @@ +// Microsoft Visual C++ generated resource script. +// +#ifdef APSTUDIO_INVOKED +#error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + +#include "afxres.h" +#include "..\src\version.h" + +VS_VERSION_INFO VERSIONINFO + FILEVERSION __FILEVERSION_STRING + PRODUCTVERSION __FILEVERSION_STRING + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x0L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "000004b0" + BEGIN + VALUE "FileDescription", __DESCRIPTION + VALUE "InternalName", __PLUGIN_NAME + VALUE "LegalCopyright", __COPYRIGHT + VALUE "OriginalFilename", __FILENAME + VALUE "ProductName", __PLUGIN_NAME + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0, 1200 + END +END diff --git a/protocols/MinecraftDynmap/src/chat.cpp b/protocols/MinecraftDynmap/src/chat.cpp new file mode 100644 index 0000000000..cf40209b30 --- /dev/null +++ b/protocols/MinecraftDynmap/src/chat.cpp @@ -0,0 +1,235 @@ +/* + +Minecraft Dynmap plugin for Miranda Instant Messenger +_____________________________________________ + +Copyright © 2015 Robert Pösel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" + +void MinecraftDynmapProto::UpdateChat(const TCHAR *name, const TCHAR *message, const time_t timestamp, bool addtolog) +{ + // replace % to %% to not interfere with chat color codes + std::tstring smessage = message; + utils::text::treplace_all(&smessage, _T("%"), _T("%%")); + + GCDEST gcd = { m_szModuleName, m_tszUserName, GC_EVENT_MESSAGE }; + GCEVENT gce = { sizeof(gce), &gcd }; + gce.time = timestamp; + gce.ptszText = smessage.c_str(); + + if (name == NULL) { + gcd.iType = GC_EVENT_INFORMATION; + name = TranslateT("Server"); + gce.bIsMe = false; + } + else gce.bIsMe = !mir_tstrcmp(name, this->nick_); + + if (addtolog) + gce.dwFlags |= GCEF_ADDTOLOG; + + gce.ptszNick = name; + gce.ptszUID = gce.ptszNick; + CallServiceSync(MS_GC_EVENT,0,reinterpret_cast<LPARAM>(&gce)); +} + +int MinecraftDynmapProto::OnChatEvent(WPARAM, LPARAM lParam) +{ + GCHOOK *hook = reinterpret_cast<GCHOOK*>(lParam); + + if(strcmp(hook->pDest->pszModule,m_szModuleName)) + return 0; + + switch(hook->pDest->iType) + { + case GC_USER_MESSAGE: + { + std::string text = mir_t2a_cp(hook->ptszText,CP_UTF8); + + // replace %% back to %, because chat automatically does this to sent messages + utils::text::replace_all(&text, "%%", "%"); + + if (text.empty()) + break; + + // Outgoing message + debugLogA("**Chat - Outgoing message: %s", text.c_str()); + ForkThread(&MinecraftDynmapProto::SendMsgWorker, new std::string(text)); + + break; + } + + case GC_USER_LEAVE: + case GC_SESSION_TERMINATE: + nick_ = NULL; + SetStatus(ID_STATUS_OFFLINE); + break; + } + + return 0; +} + +void MinecraftDynmapProto::AddChatContact(const TCHAR *name) +{ + GCDEST gcd = { m_szModuleName, m_tszUserName, GC_EVENT_JOIN }; + GCEVENT gce = { sizeof(gce), &gcd }; + gce.time = DWORD(time(0)); + gce.dwFlags = GCEF_ADDTOLOG; + gce.ptszNick = name; + gce.ptszUID = gce.ptszNick; + + if (name == NULL) + gce.bIsMe = false; + else + gce.bIsMe = mir_tstrcmp(name, this->nick_); + + if (gce.bIsMe) + gce.ptszStatus = _T("Admin"); + else + gce.ptszStatus = _T("Normal"); + + CallServiceSync(MS_GC_EVENT,0,reinterpret_cast<LPARAM>(&gce)); +} + +void MinecraftDynmapProto::DeleteChatContact(const TCHAR *name) +{ + GCDEST gcd = { m_szModuleName, m_tszUserName, GC_EVENT_PART }; + GCEVENT gce = { sizeof(gce), &gcd }; + gce.dwFlags = GCEF_ADDTOLOG; + gce.ptszNick = name; + gce.ptszUID = gce.ptszNick; + gce.time = DWORD(time(0)); + if (name == NULL) + gce.bIsMe = false; + else + gce.bIsMe = mir_tstrcmp(name, this->nick_); + + CallServiceSync(MS_GC_EVENT,0,reinterpret_cast<LPARAM>(&gce)); +} + +INT_PTR MinecraftDynmapProto::OnJoinChat(WPARAM,LPARAM suppress) +{ + ptrT tszTitle(mir_a2t(m_title.c_str())); + + // Create the group chat session + GCSESSION gcw = {sizeof(gcw)}; + gcw.iType = GCW_PRIVMESS; + gcw.ptszID = m_tszUserName; + gcw.ptszName = tszTitle; + gcw.pszModule = m_szModuleName; + CallServiceSync(MS_GC_NEWSESSION, 0, (LPARAM)&gcw); + + if (m_iStatus == ID_STATUS_OFFLINE) + return 0; + + // Create a group + GCDEST gcd = { m_szModuleName, m_tszUserName, GC_EVENT_ADDGROUP }; + GCEVENT gce = { sizeof(gce), &gcd }; + + gce.ptszStatus = _T("Admin"); + CallServiceSync(MS_GC_EVENT, NULL, reinterpret_cast<LPARAM>(&gce)); + + gce.ptszStatus = _T("Normal"); + CallServiceSync(MS_GC_EVENT, NULL, reinterpret_cast<LPARAM>(&gce)); + + // Note: Initialization will finish up in SetChatStatus, called separately + if (!suppress) + SetChatStatus(m_iStatus); + + return 0; +} + +void MinecraftDynmapProto::SetTopic(const TCHAR *topic) +{ + GCDEST gcd = { m_szModuleName, m_tszUserName, GC_EVENT_TOPIC }; + GCEVENT gce = { sizeof(gce), &gcd }; + gce.time = ::time(NULL); + gce.ptszText = topic; + + CallServiceSync(MS_GC_EVENT,0, reinterpret_cast<LPARAM>(&gce)); +} + +INT_PTR MinecraftDynmapProto::OnLeaveChat(WPARAM,LPARAM) +{ + GCDEST gcd = { m_szModuleName, m_tszUserName, GC_EVENT_CONTROL }; + GCEVENT gce = { sizeof(gce), &gcd }; + gce.time = ::time(NULL); + + CallServiceSync(MS_GC_EVENT,SESSION_OFFLINE, reinterpret_cast<LPARAM>(&gce)); + CallServiceSync(MS_GC_EVENT,SESSION_TERMINATE,reinterpret_cast<LPARAM>(&gce)); + + return 0; +} + +void MinecraftDynmapProto::SetChatStatus(int status) +{ + GCDEST gcd = { m_szModuleName, m_tszUserName, GC_EVENT_CONTROL }; + GCEVENT gce = { sizeof(gce), &gcd }; + gce.time = ::time(NULL); + + if (status == ID_STATUS_ONLINE) + { + // Load actual name from database + nick_ = db_get_tsa(NULL, m_szModuleName, MINECRAFTDYNMAP_KEY_NAME); + if (nick_ == NULL) { + nick_ = mir_tstrdup(TranslateT("You")); + db_set_ts(NULL, m_szModuleName, MINECRAFTDYNMAP_KEY_NAME, nick_); + } + + // Add self contact + AddChatContact(nick_); + + CallServiceSync(MS_GC_EVENT,SESSION_INITDONE,reinterpret_cast<LPARAM>(&gce)); + CallServiceSync(MS_GC_EVENT,SESSION_ONLINE, reinterpret_cast<LPARAM>(&gce)); + } + else + { + CallServiceSync(MS_GC_EVENT,SESSION_OFFLINE,reinterpret_cast<LPARAM>(&gce)); + } +} + +void MinecraftDynmapProto::ClearChat() +{ + GCDEST gcd = { m_szModuleName, m_tszUserName, GC_EVENT_CONTROL }; + GCEVENT gce = { sizeof(gce), &gcd }; + CallServiceSync(MS_GC_EVENT, WINDOW_CLEARLOG, reinterpret_cast<LPARAM>(&gce)); +} + +// TODO: Could this be done better? +MCONTACT MinecraftDynmapProto::GetChatHandle() +{ + /*if (chatHandle_ != NULL) + return chatHandle_; + + for (MCONTACT hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) { + if (db_get_b(hContact, m_szModuleName, "ChatRoom", 0) > 0) { + ptrA id = db_get_sa(hContact, m_szModuleName, "ChatRoomId"); + if (id != NULL && !strcmp(id, m_szModuleName)) + return hContact; + } + } + + return NULL;*/ + + GC_INFO gci = {0}; + gci.Flags = GCF_HCONTACT; + gci.pszModule = m_szModuleName; + gci.pszID = m_tszUserName; + CallService(MS_GC_GETINFO, 0, (LPARAM)&gci); + + return gci.hContact; +}
\ No newline at end of file diff --git a/protocols/MinecraftDynmap/src/communication.cpp b/protocols/MinecraftDynmap/src/communication.cpp new file mode 100644 index 0000000000..98b0728483 --- /dev/null +++ b/protocols/MinecraftDynmap/src/communication.cpp @@ -0,0 +1,465 @@ +/* + +Minecraft Dynmap plugin for Miranda Instant Messenger +_____________________________________________ + +Copyright © 2015 Robert Pösel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h" + +http::response MinecraftDynmapProto::sendRequest(const int request_type, std::string *post_data, std::string *get_data) +{ + http::response resp; + + // Prepare the request + NETLIBHTTPREQUEST nlhr = { sizeof(NETLIBHTTPREQUEST) }; + + // FIXME: get server + + // Set request URL + std::string url = m_server + chooseAction(request_type, get_data); + nlhr.szUrl = (char*)url.c_str(); + + // Set timeout (bigger for channel request) + nlhr.timeout = 1000 * ((request_type == MINECRAFTDYNMAP_REQUEST_EVENTS) ? 65 : 20); + + // Set request type (GET/POST) and eventually also POST data + if (post_data != NULL) { + nlhr.requestType = REQUEST_POST; + nlhr.pData = (char*)(*post_data).c_str(); + nlhr.dataLength = (int)post_data->length(); + } + else { + nlhr.requestType = REQUEST_GET; + } + + // Set headers - it depends on requestType so it must be after setting that + nlhr.headers = get_request_headers(nlhr.requestType, &nlhr.headersCount); + + // Set flags + nlhr.flags = NLHRF_HTTP11; + +#ifdef _DEBUG + nlhr.flags |= NLHRF_DUMPASTEXT; +#else + nlhr.flags |= NLHRF_NODUMP; +#endif + + // Set persistent connection (or not) + switch (request_type) + { + case MINECRAFTDYNMAP_REQUEST_HOME: + nlhr.nlc = NULL; + break; + + case MINECRAFTDYNMAP_REQUEST_EVENTS: + nlhr.nlc = hEventsConnection; + nlhr.flags |= NLHRF_PERSISTENT; + break; + + default: + WaitForSingleObject(connection_lock_, INFINITE); + nlhr.nlc = hConnection; + nlhr.flags |= NLHRF_PERSISTENT; + break; + } + + debugLogA("@@@@@ Sending request to '%s'", nlhr.szUrl); + + // Send the request + NETLIBHTTPREQUEST *pnlhr = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)&nlhr); + + mir_free(nlhr.headers); + + // Remember the persistent connection handle (or not) + switch (request_type) + { + case MINECRAFTDYNMAP_REQUEST_HOME: + break; + + case MINECRAFTDYNMAP_REQUEST_EVENTS: + hEventsConnection = pnlhr ? pnlhr->nlc : NULL; + break; + + default: + ReleaseMutex(connection_lock_); + hConnection = pnlhr ? pnlhr->nlc : NULL; + break; + } + + // Check and copy response data + if (pnlhr != NULL) + { + debugLogA("@@@@@ Got response with code %d", pnlhr->resultCode); + store_headers(&resp, pnlhr->headers, pnlhr->headersCount); + resp.code = pnlhr->resultCode; + resp.data = pnlhr->pData ? pnlhr->pData : ""; + + // debugLogA("&&&&& Got response: %s", resp.data.c_str()); + + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)pnlhr); + } else { + debugLogA("!!!!! No response from server (time-out)"); + resp.code = HTTP_CODE_FAKE_DISCONNECTED; + // Better to have something set explicitely as this value is compaired in all communication requests + } + + return resp; +} + +////////////////////////////////////////////////////////////////////////////// + +std::string MinecraftDynmapProto::chooseAction(int request_type, std::string *get_data) +{ + switch (request_type) { + case MINECRAFTDYNMAP_REQUEST_MESSAGE: { + return "/up/sendmessage"; + } + + case MINECRAFTDYNMAP_REQUEST_CONFIGURATION: { + return "/up/configuration"; + } + + case MINECRAFTDYNMAP_REQUEST_EVENTS: { + std::string request = "/up/world/%s/%s"; + + // Set world + std::string world = "world"; // TODO: configurable world? + utils::text::replace_first(&request, "%s", world); + + // Set timestamp + utils::text::replace_first(&request, "%s", !m_timestamp.empty() ? m_timestamp : "0"); + + return request; + } + + //case MINECRAFTDYNMAP_REQUEST_HOME: + default: { + return "/" + *get_data; + } + } +} + + +NETLIBHTTPHEADER* MinecraftDynmapProto::get_request_headers(int request_type, int* headers_count) +{ + if (request_type == REQUEST_POST) + *headers_count = 5; + else + *headers_count = 4; + + NETLIBHTTPHEADER *headers = (NETLIBHTTPHEADER*)mir_calloc(sizeof(NETLIBHTTPHEADER)*(*headers_count)); + + if (request_type == REQUEST_POST) { + headers[4].szName = "Content-Type"; + headers[4].szValue = "application/json; charset=utf-8"; + } + + headers[3].szName = "Cookie"; + headers[3].szValue = (char *)m_cookie.c_str(); + headers[2].szName = "User-Agent"; + headers[2].szValue = (char *)g_strUserAgent.c_str(); + headers[1].szName = "Accept"; + headers[1].szValue = "*/*"; + headers[0].szName = "Accept-Language"; + headers[0].szValue = "en,en-US;q=0.9"; + + return headers; +} + +void MinecraftDynmapProto::store_headers(http::response* resp, NETLIBHTTPHEADER* headers, int headersCount) +{ + for (size_t i = 0; i < (size_t)headersCount; i++) { + std::string header_name = headers[i].szName; + std::string header_value = headers[i].szValue; + + resp->headers[header_name] = header_value; + } +} + +////////////////////////////////////////////////////////////////////////////// + +bool MinecraftDynmapProto::doSignOn() +{ + handleEntry(__FUNCTION__); + + http::response resp = sendRequest(MINECRAFTDYNMAP_REQUEST_CONFIGURATION); + + if (resp.code != HTTP_CODE_OK) { + return handleError(__FUNCTION__, "Can't load configuration", true); + } + + JSONROOT root(resp.data.c_str()); + if (root == NULL) + return false; + + /* + JSONNODE *allowchat_ = json_get(root, "allowchat"); // boolean + JSONNODE *allowwebchat_ = json_get(root, "allowwebchat"); // boolean + JSONNODE *loggedin_ = json_get(root, "loggedin"); // boolean + JSONNODE *loginEnabled_ = json_get(root, "login-enabled"); // boolean + JSONNODE *loginRequired_ = json_get(root, "webchat-requires-login"); // boolean + */ + + JSONNODE *title_ = json_get(root, "title"); // name of server + JSONNODE *interval_ = json_get(root, "webchat-interval"); // limit in seconds for sending messages + JSONNODE *rate_ = json_get(root, "updaterate"); // probably update rate for events request + + if (title_ == NULL || interval_ == NULL || rate_ == NULL) { + return handleError(__FUNCTION__, "No title, interval or rate in configuration", true); + } + + m_title = json_as_pstring(title_); + m_interval = json_as_int(interval_); + m_updateRate = json_as_int(rate_); + m_cookie.clear(); + + if (resp.headers.find("Set-Cookie") != resp.headers.end()) { + // Load Session identifier + std::string cookies = resp.headers["Set-Cookie"]; + + const char *findStr = "JSESSIONID="; + std::string::size_type start = cookies.find(findStr); + + if (start != std::string::npos) { + m_cookie = cookies.substr(start, cookies.find(";") - start); + } + } + + if (m_cookie.empty()) { + return handleError(__FUNCTION__, "Empty session id", true); + } + + return handleSuccess(__FUNCTION__); +} + +bool MinecraftDynmapProto::doEvents() +{ + handleEntry(__FUNCTION__); + + // Get update + http::response resp = sendRequest(MINECRAFTDYNMAP_REQUEST_EVENTS); + + if (resp.code != HTTP_CODE_OK) + return handleError(__FUNCTION__, "Response is not code 200"); + + JSONROOT root(resp.data.c_str()); + if (root == NULL) + return handleError(__FUNCTION__, "Invalid JSON response"); + + JSONNODE *timestamp_ = json_get(root, "timestamp"); + if (timestamp_ == NULL) + return handleError(__FUNCTION__, "Received no timestamp node"); + + m_timestamp = json_as_pstring(timestamp_); + + JSONNODE *updates_ = json_get(root, "updates"); + if (updates_ == NULL) + return handleError(__FUNCTION__, "Received no updates node"); + + for (unsigned int i = 0; i < json_size(updates_); i++) { + JSONNODE *it = json_at(updates_, i); + + JSONNODE *type_ = json_get(it, "type"); + if (type_ != NULL && json_as_pstring(type_) == "chat") { + JSONNODE *time_ = json_get(it, "timestamp"); + // JSONNODE *source_ = json_get(it, "source"); // e.g. "web" + JSONNODE *playerName_ = json_get(it, "playerName"); + JSONNODE *message_ = json_get(it, "message"); + // TODO: there are also "channel" and "account" elements + + if (time_ == NULL || playerName_ == NULL || message_ == NULL) { + debugLog(_T("Error: No player name, time or text for message")); + continue; + } + + time_t timestamp = utils::time::from_string(json_as_pstring(time_)); + ptrT name(json_as_string(playerName_)); + ptrT message(json_as_string(message_)); + + debugLog(_T("Received message: [%d] %s -> %s"), timestamp, name, message); + UpdateChat(name, message, timestamp); + } + } + + return handleSuccess(__FUNCTION__); +} + +bool MinecraftDynmapProto::doSendMessage(const std::string &message_text) +{ + handleEntry(__FUNCTION__); + + std::string data = "{\"name\":\""; + data += this->nick_; + data += "\", \"message\" : \""; + data += message_text; + data += "\"}"; + + http::response resp = sendRequest(MINECRAFTDYNMAP_REQUEST_MESSAGE, &data); + + if (resp.code == HTTP_CODE_OK) { + JSONROOT root(resp.data.c_str()); + if (root != NULL) { + JSONNODE *error_ = json_get(root, "error"); + if (error_ != NULL) { + std::string error = json_as_pstring(error_); + if (error == "none") { + return handleSuccess(__FUNCTION__); + } + else if (error == "not-allowed") { + UpdateChat(NULL, TranslateT("Message was not sent. Probably you are sending them too fast or chat is disabled completely.")); + } + } + } + } + + return handleError(__FUNCTION__); +} + +std::string MinecraftDynmapProto::doGetPage(const int request_type) +{ + handleEntry(__FUNCTION__); + + http::response resp = sendRequest(request_type); + + if (resp.code == HTTP_CODE_OK) { + handleSuccess(__FUNCTION__); + } else { + handleError(__FUNCTION__); + } + + return resp.data; +} + +void MinecraftDynmapProto::SignOnWorker(void*) +{ + SYSTEMTIME t; + GetLocalTime(&t); + debugLogA("[%d.%d.%d] Using Omegle Protocol %s", t.wDay, t.wMonth, t.wYear, __VERSION_STRING_DOTS); + + ScopedLock s(signon_lock_); + + int old_status = m_iStatus; + + // Load server from database + m_server = ptrA(db_get_sa(NULL, m_szModuleName, MINECRAFTDYNMAP_KEY_SERVER)); + + if (m_server.empty()) { + MessageBox(NULL, TranslateT("Set server address to connect."), m_tszUserName, MB_OK); + SetStatus(ID_STATUS_OFFLINE); + return; + } + + // Fix format of given server + if (m_server.substr(0, 7) != "http://" && m_server.substr(0, 8) != "https://") + m_server = "http://" + m_server; + if (m_server.substr(m_server.length() - 1, 1) == "/") + m_server = m_server.substr(0, m_server.length() -1); + + if (doSignOn()) { + // Signed in, switch to online, create chatroom and start events loop + m_iStatus = m_iDesiredStatus; + ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); + + setDword("LogonTS", (DWORD)time(NULL)); + ClearChat(); + OnJoinChat(0, false); + + ResetEvent(events_loop_event_); + + ForkThread(&MinecraftDynmapProto::EventsLoop, this); + } + else { + // Some error + ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_FAILED, (HANDLE)old_status, m_iStatus); + } + +} + +void MinecraftDynmapProto::SignOffWorker(void*) +{ + ScopedLock s(signon_lock_); + + SetEvent(events_loop_event_); + + m_cookie.clear(); + m_title.clear(); + m_server.clear(); + m_timestamp.clear(); + + int old_status = m_iStatus; + m_iStatus = ID_STATUS_OFFLINE; + + Netlib_Shutdown(hEventsConnection); + + OnLeaveChat(NULL, NULL); + + delSetting("LogonTS"); + + ProtoBroadcastAck(0, ACKTYPE_STATUS, ACKRESULT_SUCCESS, (HANDLE)old_status, m_iStatus); + + //SetAllContactStatuses(ID_STATUS_OFFLINE); + //ToggleStatusMenuItems(false); + + if (hConnection) + Netlib_CloseHandle(hConnection); + hConnection = NULL; + + if (hEventsConnection) + Netlib_CloseHandle(hEventsConnection); + hEventsConnection = NULL; +} + +void MinecraftDynmapProto::EventsLoop(void *) +{ + ScopedLock s(events_loop_lock_); + + time_t tim = ::time(NULL); + debugLogA(">>>>> Entering %s[%d]", __FUNCTION__, tim); + + while (doEvents()) + { + if (!isOnline()) + break; + + if (WaitForSingleObjectEx(events_loop_event_, m_updateRate, true) != WAIT_TIMEOUT) // FIXME: correct timeout + break; + + debugLogA("***** %s[%d] refreshing...", __FUNCTION__, tim); + } + + ResetEvent(events_loop_event_); + ResetEvent(events_loop_lock_); + debugLogA("<<<<< Exiting %s[%d]", __FUNCTION__, tim); +} + +void MinecraftDynmapProto::SendMsgWorker(void *p) +{ + if (p == NULL) + return; + + ScopedLock s(send_message_lock_); + + std::string data = *(std::string*)p; + delete (std::string*)p; + + data = utils::text::trim(data); + + if (isOnline() && data.length()) { + doSendMessage(data); + } +} diff --git a/protocols/MinecraftDynmap/src/constants.h b/protocols/MinecraftDynmap/src/constants.h new file mode 100644 index 0000000000..44dd3816ab --- /dev/null +++ b/protocols/MinecraftDynmap/src/constants.h @@ -0,0 +1,46 @@ +/* + +Minecraft Dynmap plugin for Miranda Instant Messenger +_____________________________________________ + +Copyright © 2015 Robert Pösel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#pragma once + +// Product management +#define MINECRAFTDYNMAP_NAME "Mincraft Dynmap" + +// Limits +#define MINECRAFTDYNMAP_TIMEOUTS_LIMIT 6 +// This is just guessed some wise limit +#define MINECRAFTDYNMAP_MESSAGE_LIMIT 256 +#define MINECRAFTDYNMAP_MESSAGE_LIMIT_TEXT "256" + +#define MINECRAFTDYNMAP_QUESTION_MIN_LENGTH 10 + +// Request types +#define MINECRAFTDYNMAP_REQUEST_HOME 100 // getting server homepage +#define MINECRAFTDYNMAP_REQUEST_CONFIGURATION 101 // getting server configuration +#define MINECRAFTDYNMAP_REQUEST_EVENTS 102 // receiving events +#define MINECRAFTDYNMAP_REQUEST_MESSAGE 103 // sending messages + +// DB settings +#define MINECRAFTDYNMAP_KEY_TIMEOUTS_LIMIT "TimeoutsLimit" // [HIDDEN] + +#define MINECRAFTDYNMAP_KEY_NAME "Nick" +#define MINECRAFTDYNMAP_KEY_SERVER "Server" diff --git a/protocols/MinecraftDynmap/src/dialogs.cpp b/protocols/MinecraftDynmap/src/dialogs.cpp new file mode 100644 index 0000000000..67e90edde6 --- /dev/null +++ b/protocols/MinecraftDynmap/src/dialogs.cpp @@ -0,0 +1,129 @@ +/* + +Minecraft Dynmap plugin for Miranda Instant Messenger +_____________________________________________ + +Copyright © 2015 Robert Pösel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "stdafx.h" + +// Icons + +extern HINSTANCE g_hInstance; + +static IconItem icons[] = { + { "proto", LPGEN("Protocol Icon"), IDI_PROTO }, +}; + +static HANDLE hIconLibItem[SIZEOF(icons)]; + +void InitIcons(void) { + Icon_Register(g_hInstance, "Protocols/MinecraftDynmap", icons, SIZEOF(icons), "MinecraftDynmap"); +} + +HANDLE GetIconHandle(const char* name) { + for (size_t i = 0; i < SIZEOF(icons); i++) { + if (strcmp(icons[i].szName, name) == 0) { + return hIconLibItem[i]; + } + } + return 0; +} + + +// Dialogs + +static BOOL LoadDBCheckState(MinecraftDynmapProto* ppro, HWND hwnd, int idCtrl, const char* szSetting, BYTE bDef = 0) +{ + BOOL state = db_get_b(NULL, ppro->m_szModuleName, szSetting, bDef); + CheckDlgButton(hwnd, idCtrl, state ? BST_CHECKED : BST_UNCHECKED); + return state; +} + +static BOOL StoreDBCheckState(MinecraftDynmapProto* ppro, HWND hwnd, int idCtrl, const char* szSetting) +{ + BOOL state = IsDlgButtonChecked(hwnd, idCtrl); + db_set_b(NULL, ppro->m_szModuleName, szSetting, (BYTE)state); + return state; +} + +static void LoadDBText(MinecraftDynmapProto* ppro, HWND hwnd, int idCtrl, const char* szSetting) +{ + ptrT tstr(db_get_tsa(NULL, ppro->m_szModuleName, szSetting)); + if (tstr) + SetDlgItemText(hwnd, idCtrl, tstr); +} + +static void StoreDBText(MinecraftDynmapProto* ppro, HWND hwnd, int idCtrl, const char* szSetting) +{ + TCHAR tstr[250+1]; + + GetDlgItemText(hwnd, idCtrl, tstr, SIZEOF(tstr)); + if (tstr[0] != '\0') { + db_set_ts(NULL, ppro->m_szModuleName, szSetting, tstr); + } else { + db_unset(NULL, ppro->m_szModuleName, szSetting); + } +} + + +INT_PTR CALLBACK MinecraftDynmapAccountProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) +{ + MinecraftDynmapProto *proto; + + switch (message) + { + + case WM_INITDIALOG: + TranslateDialogDefault(hwnd); + + proto = reinterpret_cast<MinecraftDynmapProto*>(lparam); + SetWindowLongPtr(hwnd,GWLP_USERDATA,lparam); + + LoadDBText(proto, hwnd, IDC_SERVER, MINECRAFTDYNMAP_KEY_SERVER); + LoadDBText(proto, hwnd, IDC_NAME, MINECRAFTDYNMAP_KEY_NAME); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wparam)) { + case IDC_NAME: { + if (HIWORD(wparam) != EN_CHANGE || (HWND)lparam != GetFocus()) { + return TRUE; + } else { + SendMessage(GetParent(hwnd), PSM_CHANGED, 0, 0); + } + break; + } + } + break; + + case WM_NOTIFY: + if (reinterpret_cast<NMHDR*>(lparam)->code == PSN_APPLY) { + proto = reinterpret_cast<MinecraftDynmapProto*>(GetWindowLongPtr(hwnd,GWLP_USERDATA)); + + StoreDBText(proto, hwnd, IDC_SERVER, MINECRAFTDYNMAP_KEY_SERVER); + StoreDBText(proto, hwnd, IDC_NAME, MINECRAFTDYNMAP_KEY_NAME); + + return TRUE; + } + break; + + } + return FALSE; +} diff --git a/protocols/MinecraftDynmap/src/dialogs.h b/protocols/MinecraftDynmap/src/dialogs.h new file mode 100644 index 0000000000..7478004559 --- /dev/null +++ b/protocols/MinecraftDynmap/src/dialogs.h @@ -0,0 +1,29 @@ +/* + +Minecraft Dynmap plugin for Miranda Instant Messenger +_____________________________________________ + +Copyright © 2015 Robert Pösel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#pragma once + +void InitIcons(void); +HANDLE GetIconHandle(const char *name); + +INT_PTR CALLBACK MinecraftDynmapAccountProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); +INT_PTR CALLBACK MinecraftDynmapOptionsProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); diff --git a/protocols/MinecraftDynmap/src/main.cpp b/protocols/MinecraftDynmap/src/main.cpp new file mode 100644 index 0000000000..e1b34cfa53 --- /dev/null +++ b/protocols/MinecraftDynmap/src/main.cpp @@ -0,0 +1,136 @@ +/* + +Minecraft Dynmap plugin for Miranda Instant Messenger +_____________________________________________ + +Copyright © 2015 Robert Pösel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "stdafx.h" + +CLIST_INTERFACE* pcli; +int hLangpack; + +HINSTANCE g_hInstance; +std::string g_strUserAgent; +DWORD g_mirandaVersion; + +PLUGININFOEX pluginInfo = { + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESCRIPTION, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + // {9E1D9244-606C-4ef4-99A0-1D7D23CB7601} + { 0x9e1d9244, 0x606c, 0x4ef4, { 0x99, 0xa0, 0x1d, 0x7d, 0x23, 0xcb, 0x76, 0x1 } } +}; + +///////////////////////////////////////////////////////////////////////////// +// Protocol instances +static int compare_protos(const MinecraftDynmapProto *p1, const MinecraftDynmapProto *p2) +{ + return _tcscmp(p1->m_tszUserName, p2->m_tszUserName); +} + +OBJLIST<MinecraftDynmapProto> g_Instances(1, compare_protos); + +DWORD WINAPI DllMain(HINSTANCE hInstance,DWORD,LPVOID) +{ + g_hInstance = hInstance; + return TRUE; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + g_mirandaVersion = mirandaVersion; + return &pluginInfo; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Interface information + +extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Load + +static PROTO_INTERFACE* protoInit(const char *proto_name,const TCHAR *username) +{ + MinecraftDynmapProto *proto = new MinecraftDynmapProto(proto_name, username); + g_Instances.insert(proto); + return proto; +} + +static int protoUninit(PROTO_INTERFACE* proto) +{ + g_Instances.remove((MinecraftDynmapProto*)proto); + return EXIT_SUCCESS; +} + +static HANDLE g_hEvents[1]; + +extern "C" int __declspec(dllexport) Load(void) +{ + mir_getLP(&pluginInfo); + mir_getCLI(); + + PROTOCOLDESCRIPTOR pd = { sizeof(pd) }; + pd.szName = "MinecraftDynmap"; + pd.type = PROTOTYPE_PROTOCOL; + pd.fnInit = protoInit; + pd.fnUninit = protoUninit; + CallService(MS_PROTO_REGISTERMODULE, 0, reinterpret_cast<LPARAM>(&pd)); + + InitIcons(); + + // Init native User-Agent + { + std::stringstream agent; + agent << "Miranda NG/"; + agent << ((g_mirandaVersion >> 24) & 0xFF); + agent << "."; + agent << ((g_mirandaVersion >> 16) & 0xFF); + agent << "."; + agent << ((g_mirandaVersion >> 8) & 0xFF); + agent << "."; + agent << ((g_mirandaVersion ) & 0xFF); + #ifdef _WIN64 + agent << " Minecraft Dynmap Protocol x64/"; + #else + agent << " Minecraft Dynmap Protocol/"; + #endif + agent << __VERSION_STRING_DOTS; + g_strUserAgent = agent.str(); + } + + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Unload + +extern "C" int __declspec(dllexport) Unload(void) +{ + for (size_t i=0; i < SIZEOF(g_hEvents); i++) + UnhookEvent(g_hEvents[i]); + + return 0; +} diff --git a/protocols/MinecraftDynmap/src/proto.cpp b/protocols/MinecraftDynmap/src/proto.cpp new file mode 100644 index 0000000000..b39bf1d827 --- /dev/null +++ b/protocols/MinecraftDynmap/src/proto.cpp @@ -0,0 +1,236 @@ +/* + +Minecraft Dynmap plugin for Miranda Instant Messenger +_____________________________________________ + +Copyright © 2015 Robert Pösel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "stdafx.h" + +MinecraftDynmapProto::MinecraftDynmapProto(const char* proto_name, const TCHAR* username) : + PROTO<MinecraftDynmapProto>(proto_name, username) +{ + this->signon_lock_ = CreateMutex(NULL, FALSE, NULL); + this->send_message_lock_ = CreateMutex(NULL, FALSE, NULL); + this->connection_lock_ = CreateMutex(NULL, FALSE, NULL); + this->events_loop_lock_ = CreateMutex(NULL, FALSE, NULL); + this->events_loop_event_ = CreateEvent(NULL, FALSE, FALSE, NULL); + + // Group chats + CreateProtoService(PS_JOINCHAT, &MinecraftDynmapProto::OnJoinChat); + CreateProtoService(PS_LEAVECHAT, &MinecraftDynmapProto::OnLeaveChat); + + CreateProtoService(PS_CREATEACCMGRUI, &MinecraftDynmapProto::SvcCreateAccMgrUI); + + // HookProtoEvent(ME_OPT_INITIALISE, &MinecraftDynmapProto::OnOptionsInit); + HookProtoEvent(ME_GC_EVENT, &MinecraftDynmapProto::OnChatEvent); + + // Create standard network connection + TCHAR descr[512]; + NETLIBUSER nlu = {sizeof(nlu)}; + nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_TCHAR; + nlu.szSettingsModule = m_szModuleName; + mir_sntprintf(descr, SIZEOF(descr), TranslateT("%s server connection"), m_tszUserName); + nlu.ptszDescriptiveName = descr; + m_hNetlibUser = (HANDLE)CallService(MS_NETLIB_REGISTERUSER, 0, (LPARAM)&nlu); + if (m_hNetlibUser == NULL) { + MessageBox(NULL, TranslateT("Unable to get Netlib connection for Minecraft Dynmap."), m_tszUserName, MB_OK); + } + + // Http connection handles + this->hConnection = NULL; + this->hEventsConnection = NULL; + + // Client instantiation + this->nick_ = NULL; + this->error_count_ = 0; + this->chatHandle_ = NULL; + this->m_updateRate = 5000; // Some default update rate +} + +MinecraftDynmapProto::~MinecraftDynmapProto() +{ + Netlib_CloseHandle(m_hNetlibUser); + + WaitForSingleObject(this->signon_lock_, IGNORE); + WaitForSingleObject(this->send_message_lock_, IGNORE); + WaitForSingleObject(this->connection_lock_, IGNORE); + WaitForSingleObject(this->events_loop_lock_, IGNORE); + + CloseHandle(this->signon_lock_); + CloseHandle(this->send_message_lock_); + CloseHandle(this->connection_lock_); + CloseHandle(this->events_loop_lock_); + CloseHandle(this->events_loop_event_); +} + +////////////////////////////////////////////////////////////////////////////// + +DWORD_PTR MinecraftDynmapProto::GetCaps(int type, MCONTACT) +{ + switch(type) { + case PFLAGNUM_1: + return PF1_CHAT; + case PFLAGNUM_2: + return PF2_ONLINE; + case PFLAG_MAXLENOFMESSAGE: + return MINECRAFTDYNMAP_MESSAGE_LIMIT; + case PFLAG_UNIQUEIDTEXT: + return (DWORD_PTR) Translate("Visible name"); + case PFLAG_UNIQUEIDSETTING: + return (DWORD_PTR) "Nick"; + } + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + +int MinecraftDynmapProto::SetStatus(int new_status) +{ + // Routing not supported statuses + switch (new_status) { + case ID_STATUS_OFFLINE: + case ID_STATUS_CONNECTING: + new_status = ID_STATUS_OFFLINE; + break; + default: + new_status = ID_STATUS_ONLINE; + break; + } + + m_iDesiredStatus = new_status; + + if (new_status == m_iStatus) { + return 0; + } + + if (m_iStatus == ID_STATUS_CONNECTING && new_status != ID_STATUS_OFFLINE) { + return 0; + } + + if (new_status == ID_STATUS_OFFLINE) { + ForkThread(&MinecraftDynmapProto::SignOffWorker, this); + } else { + ForkThread(&MinecraftDynmapProto::SignOnWorker, this); + } + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + +int MinecraftDynmapProto::OnEvent(PROTOEVENTTYPE event,WPARAM wParam,LPARAM lParam) +{ + switch(event) { + case EV_PROTO_ONLOAD: + return OnModulesLoaded(wParam, lParam); + + case EV_PROTO_ONEXIT: + return OnPreShutdown (wParam, lParam); + + // case EV_PROTO_ONOPTIONS: + // return OnOptionsInit (wParam, lParam); + + case EV_PROTO_ONCONTACTDELETED: + return OnContactDeleted(wParam, lParam); + } + + return 1; +} + +////////////////////////////////////////////////////////////////////////////// +// EVENTS + +INT_PTR MinecraftDynmapProto::SvcCreateAccMgrUI(WPARAM, LPARAM lParam) +{ + return (INT_PTR)CreateDialogParam(g_hInstance,MAKEINTRESOURCE(IDD_MinecraftDynmapACCOUNT), + (HWND)lParam, MinecraftDynmapAccountProc, (LPARAM)this); +} + +int MinecraftDynmapProto::OnModulesLoaded(WPARAM, LPARAM) +{ + // Register group chat + GCREGISTER gcr = {sizeof(gcr)}; + gcr.dwFlags = 0; + gcr.pszModule = m_szModuleName; + gcr.ptszDispName = m_tszUserName; + gcr.iMaxText = MINECRAFTDYNMAP_MESSAGE_LIMIT; + gcr.nColors = 0; + gcr.pColors = NULL; + CallService(MS_GC_REGISTER, 0, reinterpret_cast<LPARAM>(&gcr)); + + return 0; +} + +/*int MinecraftDynmapProto::OnOptionsInit(WPARAM wParam, LPARAM) +{ + OPTIONSDIALOGPAGE odp = { 0 }; + odp.hInstance = g_hInstance; + odp.ptszTitle = m_tszUserName; + odp.dwInitParam = LPARAM(this); + odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR | ODPF_DONTTRANSLATE; + + odp.position = 271828; + odp.ptszGroup = LPGENT("Network"); + odp.ptszTab = LPGENT("Account"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS); + odp.pfnDlgProc = MinecraftDynmapOptionsProc; + Options_AddPage(wParam, &odp); + return 0; +}*/ + +int MinecraftDynmapProto::OnPreShutdown(WPARAM, LPARAM) +{ + SetStatus(ID_STATUS_OFFLINE); + return 0; +} + +int MinecraftDynmapProto::OnContactDeleted(WPARAM, LPARAM) +{ + OnLeaveChat(NULL, NULL); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// +// HELPERS + +bool MinecraftDynmapProto::handleEntry(const std::string &method) +{ + debugLogA(" >> Entering %s()", method.c_str()); + return true; +} + +bool MinecraftDynmapProto::handleSuccess(const std::string &method) +{ + debugLogA(" << Quitting %s()", method.c_str()); + reset_error(); + return true; +} + +bool MinecraftDynmapProto::handleError(const std::string &method, const std::string &error, bool force_disconnect) +{ + increment_error(); + debugLogA("!!!!! Quitting %s() with error: %s", method.c_str(), !error.empty() ? error.c_str() : "Something went wrong"); + + if (!force_disconnect && error_count_ <= (UINT)db_get_b(NULL, m_szModuleName, MINECRAFTDYNMAP_KEY_TIMEOUTS_LIMIT, MINECRAFTDYNMAP_TIMEOUTS_LIMIT)) { + return true; + } + + reset_error(); + SetStatus(ID_STATUS_OFFLINE); + return false; +} diff --git a/protocols/MinecraftDynmap/src/proto.h b/protocols/MinecraftDynmap/src/proto.h new file mode 100644 index 0000000000..45cc6ab6fe --- /dev/null +++ b/protocols/MinecraftDynmap/src/proto.h @@ -0,0 +1,134 @@ +/* + +Minecraft Dynmap plugin for Miranda Instant Messenger +_____________________________________________ + +Copyright © 2015 Robert Pösel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#pragma once + +class MinecraftDynmapProto : public PROTO<MinecraftDynmapProto> +{ +public: + MinecraftDynmapProto(const char *proto_name, const TCHAR *username); + ~MinecraftDynmapProto(); + + inline const char* ModuleName() const { + return m_szModuleName; + } + + inline bool isOnline() { + return (m_iStatus != ID_STATUS_OFFLINE && m_iStatus != ID_STATUS_CONNECTING); + } + + inline bool isOffline() { + return (m_iStatus == ID_STATUS_OFFLINE); + } + + // PROTO_INTERFACE + virtual DWORD_PTR __cdecl GetCaps(int type, MCONTACT hContact = NULL); + virtual int __cdecl SetStatus(int iNewStatus); + virtual int __cdecl OnEvent(PROTOEVENTTYPE iEventType, WPARAM wParam, LPARAM lParam); + + // Services + INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM, LPARAM); + + // Events + int __cdecl OnModulesLoaded(WPARAM, LPARAM); + // int __cdecl OnOptionsInit(WPARAM, LPARAM); + int __cdecl OnContactDeleted(WPARAM,LPARAM); + int __cdecl OnPreShutdown(WPARAM,LPARAM); + int __cdecl OnPrebuildContactMenu(WPARAM,LPARAM); + + // Chat handling + int __cdecl OnChatEvent(WPARAM,LPARAM); + INT_PTR __cdecl OnJoinChat(WPARAM,LPARAM); + INT_PTR __cdecl OnLeaveChat(WPARAM,LPARAM); + + // Loops + void __cdecl EventsLoop(void*); + + // Worker threads + void __cdecl SignOnWorker(void*); + void __cdecl SignOffWorker(void*); + void __cdecl SendMsgWorker(void*); + + // Chat handling + void AddChat(const TCHAR *id,const TCHAR *name); + void UpdateChat(const TCHAR *name, const TCHAR *message, const time_t timestamp = time(NULL), bool addtochat = true); + void SendChatMessage(std::string message); + void AddChatContact(const TCHAR *nick); + void DeleteChatContact(const TCHAR *name); + void SetChatStatus(int); + void ClearChat(); + void SetTopic(const TCHAR *topic = NULL); + MCONTACT GetChatHandle(); + + // Locks + HANDLE signon_lock_; + HANDLE connection_lock_; + HANDLE send_message_lock_; + HANDLE events_loop_lock_; + + HANDLE events_loop_event_; + + // Handles + HANDLE hConnection; + HANDLE hEventsConnection; + HANDLE chatHandle_; + + // Data storage + void store_headers(http::response *resp, NETLIBHTTPHEADER *headers, int headers_count); + + std::string get_server(bool not_last = false); + std::string get_language(); + + // Connection handling + unsigned int error_count_; + + // Helpers + bool handleEntry(const std::string &method); + bool handleSuccess(const std::string &method); + bool handleError(const std::string &method, const std::string &error = "", bool force_disconnect = false); + + void __inline increment_error() { error_count_++; } + void __inline decrement_error() { if (error_count_ > 0) error_count_--; } + void __inline reset_error() { error_count_ = 0; } + + // HTTP communication + http::response sendRequest(const int request_type, std::string *post_data = NULL, std::string *get_data = NULL); + std::string chooseAction(int, std::string *get_data = NULL); + NETLIBHTTPHEADER *get_request_headers(int request_type, int *headers_count); + + // Requests and processing + bool doSignOn(); + bool doEvents(); + bool doSendMessage(const std::string &message_text); + + std::string doGetPage(int); + + // Configuration + ptrT nick_; + std::string m_cookie; + std::string m_server; + std::string m_title; + std::string m_timestamp; + int m_interval; + int m_updateRate; + +}; diff --git a/protocols/MinecraftDynmap/src/resource.h b/protocols/MinecraftDynmap/src/resource.h new file mode 100644 index 0000000000..a7f5df593c --- /dev/null +++ b/protocols/MinecraftDynmap/src/resource.h @@ -0,0 +1,20 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by D:\Development\Miranda NG\Miranda NG\protocols\MinecraftDynmap\res\resource.rc +// +#define IDI_PROTO 101 +#define IDD_MinecraftDynmapACCOUNT 111 +#define IDD_OPTIONS 122 +#define IDC_SERVER 1204 +#define IDC_NAME 1205 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 124 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1208 +#define _APS_NEXT_SYMED_VALUE 131 +#endif +#endif diff --git a/protocols/MinecraftDynmap/src/stdafx.cxx b/protocols/MinecraftDynmap/src/stdafx.cxx new file mode 100644 index 0000000000..e6f635a0de --- /dev/null +++ b/protocols/MinecraftDynmap/src/stdafx.cxx @@ -0,0 +1,18 @@ +/* +Copyright (C) 2012-15 Miranda NG project (http://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "stdafx.h"
\ No newline at end of file diff --git a/protocols/MinecraftDynmap/src/stdafx.h b/protocols/MinecraftDynmap/src/stdafx.h new file mode 100644 index 0000000000..bff97adae0 --- /dev/null +++ b/protocols/MinecraftDynmap/src/stdafx.h @@ -0,0 +1,73 @@ +/* + +Minecraft Dynmap plugin for Miranda Instant Messenger +_____________________________________________ + +Copyright © 2015 Robert Pösel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#pragma once + +#pragma warning(disable:4996) + +#include <string> +#include <cstring> +#include <sstream> +#include <fstream> +#include <map> +#include <stdarg.h> +#include <time.h> +#include <assert.h> +#include <io.h> + +#include <windows.h> +#include <win2k.h> +#include <commctrl.h> + +#include <newpluginapi.h> +#include <m_system.h> +#include <m_system_cpp.h> +#include <m_chat.h> +#include <m_clistint.h> +#include <m_langpack.h> +#include <m_netlib.h> +#include <m_options.h> +#include <m_popup.h> +#include <m_protocols.h> +#include <m_protosvc.h> +#include <m_protoint.h> +#include <m_skin.h> +#include <statusmodes.h> +#include <m_icolib.h> +#include <m_utils.h> +#include <m_hotkeys.h> +#include <m_message.h> +#include <m_json.h> + +#include "version.h" + +class MinecraftDynmapProto; + +#include "utils.h" +#include "proto.h" +#include "constants.h" +#include "dialogs.h" +#include "resource.h" + +extern HINSTANCE g_hInstance; +extern std::string g_strUserAgent; +extern DWORD g_mirandaVersion; diff --git a/protocols/MinecraftDynmap/src/utils.cpp b/protocols/MinecraftDynmap/src/utils.cpp new file mode 100644 index 0000000000..15fea63aaf --- /dev/null +++ b/protocols/MinecraftDynmap/src/utils.cpp @@ -0,0 +1,131 @@ +/* + +Minecraft Dynmap plugin for Miranda Instant Messenger +_____________________________________________ + +Copyright © 2015 Robert Pösel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include "stdafx.h" + +std::string utils::url::encode(const std::string &s) +{ + return (char*)ptrA(mir_urlEncode(s.c_str())); +} + +void utils::text::replace_first(std::string* data, const std::string &from, const std::string &to) +{ + std::string::size_type position = 0; + + if ((position = data->find(from, position)) != std::string::npos) + { + data->replace(position, from.size(), to); + position++; + } +} + +void utils::text::replace_all(std::string* data, const std::string &from, const std::string &to) +{ + std::string::size_type position = 0; + + while ((position = data->find(from, position)) != std::string::npos) + { + data->replace(position, from.size(), to); + position++; + } +} + +void utils::text::treplace_all(std::tstring* data, const std::tstring &from, const std::tstring &to) +{ + std::tstring::size_type position = 0; + + while ((position = data->find(from, position)) != std::tstring::npos) + { + data->replace(position, from.size(), to); + position++; + } +} + +std::string utils::text::special_expressions_decode(std::string data) +{ + utils::text::replace_all(&data, "\\r", "\r"); + utils::text::replace_all(&data, "\\n", "\n"); + utils::text::replace_all(&data, "\\\"", "\""); + utils::text::replace_all(&data, "\\\\", "\\"); + + return data; +} + +std::string utils::text::slashu_to_utf8(const std::string &data) +{ + std::string new_string = ""; + + for (std::string::size_type i = 0; i < data.length(); i++) + { + if (data.at(i) == '\\' && (i+1) < data.length() && data.at(i+1) == 'u') + { + unsigned int udn = strtol(data.substr(i + 2, 4).c_str(), NULL, 16); + + if (udn >= 128 && udn <= 2047) + { // U+0080 .. U+07FF + new_string += (char)(192 + (udn / 64)); + new_string += (char)(128 + (udn % 64)); + } + else if (udn >= 2048 && udn <= 65535) + { // U+0800 .. U+FFFF + new_string += (char)(224 + (udn / 4096)); + new_string += (char)(128 + ((udn / 64) % 64)); + new_string += (char)(128 + (udn % 64 )); + } + else if (udn <= 127) + { // U+0000 .. U+007F (should not appear) + new_string += (char)udn; + } + + i += 5; + continue; + } + + new_string += data.at(i); + } + + return new_string; +} + +std::string utils::text::trim(const std::string &data) +{ + std::string spaces = " \t\r\n"; + std::string::size_type begin = data.find_first_not_of(spaces); + std::string::size_type end = data.find_last_not_of(spaces) + 1; + + return (begin != std::string::npos) ? data.substr(begin, end - begin) : ""; +} + +time_t utils::time::from_string(const std::string &data) +{ + long long timestamp = _strtoi64(data.c_str(), NULL, 10); + + // If it is milli timestamp + if (timestamp > 100000000000) + timestamp /= 1000; + + // If conversion fails, use local time? + //if (!timestamp) + // timestamp = ::time(NULL); + + return (time_t)timestamp; +} diff --git a/protocols/MinecraftDynmap/src/utils.h b/protocols/MinecraftDynmap/src/utils.h new file mode 100644 index 0000000000..02c0acb9b1 --- /dev/null +++ b/protocols/MinecraftDynmap/src/utils.h @@ -0,0 +1,97 @@ +/* + +Minecraft Dynmap plugin for Miranda Instant Messenger +_____________________________________________ + +Copyright © 2015 Robert Pösel + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#pragma once + +// DB macros +#define getU8String(setting, dest) db_get_utf(NULL, m_szModuleName, setting, dest) +#define setU8String(setting, value) db_set_utf(NULL, m_szModuleName, setting, value) + +// HTTP constants and object +#define HTTP_CODE_OK 200 +#define HTTP_CODE_MOVED_PERMANENTLY 301 +#define HTTP_CODE_FOUND 302 +#define HTTP_CODE_FORBIDDEN 403 +#define HTTP_CODE_NOT_FOUND 404 +#define HTTP_CODE_REQUEST_TIMEOUT 408 +#define HTTP_CODE_INTERNAL_SERVER_ERROR 500 +#define HTTP_CODE_NOT_IMPLEMENTED 501 +#define HTTP_CODE_BAD_GATEWAY 502 +#define HTTP_CODE_SERVICE_UNAVAILABLE 503 + +#define HTTP_CODE_FAKE_DISCONNECTED 0 +#define HTTP_CODE_FAKE_ERROR 1 + +namespace http +{ + struct response + { + response() : code(0) {} + int code; + std::map< std::string, std::string > headers; + std::string data; + }; +} + +namespace utils +{ + namespace url + { + std::string encode(const std::string &s); + }; + + namespace text + { + void replace_first(std::string* data, const std::string &from, const std::string &to); + void replace_all(std::string* data, const std::string &from, const std::string &to); + void treplace_all(std::tstring* data, const std::tstring &from, const std::tstring &to); + std::string special_expressions_decode(std::string data); + std::string slashu_to_utf8(const std::string &data); + std::string trim(const std::string &data); + }; + + namespace time + { + time_t from_string(const std::string &data); + }; +}; + +class ScopedLock +{ +public: + ScopedLock(HANDLE h) : handle_(h) + { + WaitForSingleObject(handle_,INFINITE); + } + ~ScopedLock() + { + if (handle_) + ReleaseMutex(handle_); + } + void Unlock() + { + ReleaseMutex(handle_); + handle_ = 0; + } +private: + HANDLE handle_; +}; diff --git a/protocols/MinecraftDynmap/src/version.h b/protocols/MinecraftDynmap/src/version.h new file mode 100644 index 0000000000..d60801e52b --- /dev/null +++ b/protocols/MinecraftDynmap/src/version.h @@ -0,0 +1,14 @@ +#define __MAJOR_VERSION 0 +#define __MINOR_VERSION 0 +#define __RELEASE_NUM 0 +#define __BUILD_NUM 1 + +#include <stdver.h> + +#define __PLUGIN_NAME "Minecraft Dynmap protocol" +#define __FILENAME "MinecraftDynmap.dll" +#define __DESCRIPTION "Minecraft Dynmap support for Miranda NG." +#define __AUTHOR "Robert P\xf6" "sel" +#define __AUTHOREMAIL "robyer@seznam.cz" +#define __AUTHORWEB "http://miranda-ng.org/p/MinecraftDynmap/" +#define __COPYRIGHT "© 2015 Robert P\xf6" "sel" |