summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--protocols/MinecraftDynmap/MinecraftDynmap.vcxproj33
-rw-r--r--protocols/MinecraftDynmap/MinecraftDynmap.vcxproj.filters4
-rw-r--r--protocols/MinecraftDynmap/docs/readme.txt2
-rw-r--r--protocols/MinecraftDynmap/proto_minecraftdynmap/minecraftdynmap_icons.vcxproj28
-rw-r--r--protocols/MinecraftDynmap/proto_minecraftdynmap/minecraftdynmap_icons.vcxproj.filters4
-rw-r--r--protocols/MinecraftDynmap/proto_minecraftdynmap/res/Offline.icobin0 -> 5430 bytes
-rw-r--r--protocols/MinecraftDynmap/proto_minecraftdynmap/res/Online.icobin0 -> 5430 bytes
-rw-r--r--protocols/MinecraftDynmap/proto_minecraftdynmap/res/minecraftdynmap_icons.rc73
-rw-r--r--protocols/MinecraftDynmap/proto_minecraftdynmap/src/resource_icons.h17
-rw-r--r--protocols/MinecraftDynmap/res/proto.icobin0 -> 5430 bytes
-rw-r--r--protocols/MinecraftDynmap/res/resource.rc127
-rw-r--r--protocols/MinecraftDynmap/res/version.rc38
-rw-r--r--protocols/MinecraftDynmap/src/chat.cpp235
-rw-r--r--protocols/MinecraftDynmap/src/communication.cpp465
-rw-r--r--protocols/MinecraftDynmap/src/constants.h46
-rw-r--r--protocols/MinecraftDynmap/src/dialogs.cpp129
-rw-r--r--protocols/MinecraftDynmap/src/dialogs.h29
-rw-r--r--protocols/MinecraftDynmap/src/main.cpp136
-rw-r--r--protocols/MinecraftDynmap/src/proto.cpp236
-rw-r--r--protocols/MinecraftDynmap/src/proto.h134
-rw-r--r--protocols/MinecraftDynmap/src/resource.h20
-rw-r--r--protocols/MinecraftDynmap/src/stdafx.cxx18
-rw-r--r--protocols/MinecraftDynmap/src/stdafx.h73
-rw-r--r--protocols/MinecraftDynmap/src/utils.cpp131
-rw-r--r--protocols/MinecraftDynmap/src/utils.h97
-rw-r--r--protocols/MinecraftDynmap/src/version.h14
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
new file mode 100644
index 0000000000..a44000b281
--- /dev/null
+++ b/protocols/MinecraftDynmap/proto_minecraftdynmap/res/Offline.ico
Binary files differ
diff --git a/protocols/MinecraftDynmap/proto_minecraftdynmap/res/Online.ico b/protocols/MinecraftDynmap/proto_minecraftdynmap/res/Online.ico
new file mode 100644
index 0000000000..38e4cf30fe
--- /dev/null
+++ b/protocols/MinecraftDynmap/proto_minecraftdynmap/res/Online.ico
Binary files differ
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
new file mode 100644
index 0000000000..38e4cf30fe
--- /dev/null
+++ b/protocols/MinecraftDynmap/res/proto.ico
Binary files differ
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"