summaryrefslogtreecommitdiff
path: root/protocols/MinecraftDynmap/src
diff options
context:
space:
mode:
authordartraiden <wowemuh@gmail.com>2023-01-02 21:10:29 +0300
committerdartraiden <wowemuh@gmail.com>2023-01-02 21:10:29 +0300
commit1979fd80424d16b2e489f9b57d01d9c7811d25a2 (patch)
tree960d42c5fe4a51f0fe2850bea91256e226bce221 /protocols/MinecraftDynmap/src
parentadfbbb217d4f4a05acf198755f219a5223d31c27 (diff)
Update copyrights
Diffstat (limited to 'protocols/MinecraftDynmap/src')
-rw-r--r--protocols/MinecraftDynmap/src/chat.cpp368
-rw-r--r--protocols/MinecraftDynmap/src/communication.cpp884
-rw-r--r--protocols/MinecraftDynmap/src/constants.h92
-rw-r--r--protocols/MinecraftDynmap/src/dialogs.cpp196
-rw-r--r--protocols/MinecraftDynmap/src/dialogs.h54
-rw-r--r--protocols/MinecraftDynmap/src/main.cpp180
-rw-r--r--protocols/MinecraftDynmap/src/proto.cpp360
-rw-r--r--protocols/MinecraftDynmap/src/proto.h272
-rw-r--r--protocols/MinecraftDynmap/src/stdafx.cxx34
-rw-r--r--protocols/MinecraftDynmap/src/stdafx.h140
-rw-r--r--protocols/MinecraftDynmap/src/utils.h126
-rw-r--r--protocols/MinecraftDynmap/src/version.h2
12 files changed, 1354 insertions, 1354 deletions
diff --git a/protocols/MinecraftDynmap/src/chat.cpp b/protocols/MinecraftDynmap/src/chat.cpp
index a6f15cc115..c0c1f80542 100644
--- a/protocols/MinecraftDynmap/src/chat.cpp
+++ b/protocols/MinecraftDynmap/src/chat.cpp
@@ -1,185 +1,185 @@
-/*
-
-Minecraft Dynmap plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2015-17 Robert Pösel, 2017-22 Miranda NG team
-
-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 char *name, const char *message, const time_t timestamp, bool addtolog)
-{
- // replace % to %% to not interfere with chat color codes
- CMStringA szMessage(message);
- szMessage.Replace("%", "%%");
-
- GCEVENT gce = { m_szModuleName, szRoomName, GC_EVENT_MESSAGE };
- gce.dwFlags = GCEF_UTF8;
- gce.time = timestamp;
- gce.pszText.a = szMessage.c_str();
-
- if (name == NULL) {
- gce.iType = GC_EVENT_INFORMATION;
- name = TranslateU("Server");
- gce.bIsMe = false;
- }
- else gce.bIsMe = (m_nick == name);
-
- if (addtolog)
- gce.dwFlags |= GCEF_ADDTOLOG;
-
- gce.pszUID.a = gce.pszNick.a = name;
- Chat_Event(&gce);
-}
-
-int MinecraftDynmapProto::OnChatEvent(WPARAM, LPARAM lParam)
-{
- GCHOOK *hook = reinterpret_cast<GCHOOK*>(lParam);
- if(strcmp(hook->si->pszModule,m_szModuleName))
- return 0;
-
- switch(hook->iType) {
- case GC_USER_MESSAGE:
- {
- CMStringA szText(ptrA(mir_utf8encodeW(hook->ptszText)));
- szText.Replace("%%", "%");
- if (szText.IsEmpty())
- break;
-
- // Outgoing message
- debugLogA("**Chat - Outgoing message: %s", szText.c_str());
- ForkThread(&MinecraftDynmapProto::SendMsgWorker, new std::string(szText));
- }
- break;
-
- case GC_SESSION_TERMINATE:
- m_nick.clear();
- SetStatus(ID_STATUS_OFFLINE);
- break;
- }
-
- return 0;
-}
-
-void MinecraftDynmapProto::AddChatContact(const char *name)
-{
- GCEVENT gce = { m_szModuleName, szRoomName, GC_EVENT_JOIN };
- gce.time = uint32_t(time(0));
- gce.dwFlags = GCEF_UTF8 + GCEF_ADDTOLOG;
- gce.pszUID.a = gce.pszNick.a = name;
- gce.bIsMe = (m_nick == name);
-
- if (gce.bIsMe)
- gce.pszStatus.a = "Admin";
- else
- gce.pszStatus.a = "Normal";
-
- Chat_Event(&gce);
-}
-
-void MinecraftDynmapProto::DeleteChatContact(const char *name)
-{
- GCEVENT gce = { m_szModuleName, szRoomName, GC_EVENT_PART };
- gce.dwFlags = GCEF_UTF8 + GCEF_ADDTOLOG;
- gce.pszUID.a = gce.pszNick.a = name;
- gce.time = uint32_t(time(0));
- gce.bIsMe = (m_nick == name);
- Chat_Event(&gce);
-}
-
-INT_PTR MinecraftDynmapProto::OnJoinChat(WPARAM,LPARAM suppress)
-{
- ptrW tszTitle(mir_a2u_cp(m_title.c_str(), CP_UTF8));
-
- // Create the group chat session
- SESSION_INFO *si = Chat_NewSession(GCW_PRIVMESS, m_szModuleName, m_tszUserName, tszTitle);
- if (!si || m_iStatus == ID_STATUS_OFFLINE)
- return 0;
-
- // Create a group
- Chat_AddGroup(si, TranslateT("Admin"));
- Chat_AddGroup(si, TranslateT("Normal"));
-
- // Note: Initialization will finish up in SetChatStatus, called separately
- if (!suppress)
- SetChatStatus(m_iStatus);
-
- return 0;
-}
-
-void MinecraftDynmapProto::SetTopic(const char *topic)
-{
- GCEVENT gce = { m_szModuleName, szRoomName, GC_EVENT_TOPIC };
- gce.dwFlags = GCEF_UTF8;
- gce.time = ::time(0);
- gce.pszText.a = topic;
- Chat_Event( &gce);
-}
-
-INT_PTR MinecraftDynmapProto::OnLeaveChat(WPARAM,LPARAM)
-{
- Chat_Control(m_szModuleName, m_tszUserName, SESSION_OFFLINE);
- Chat_Terminate(m_szModuleName, m_tszUserName);
- return 0;
-}
-
-void MinecraftDynmapProto::SetChatStatus(int status)
-{
- if (status == ID_STATUS_ONLINE)
- {
- // Load actual name from database
- ptrA nick(db_get_sa(0, m_szModuleName, MINECRAFTDYNMAP_KEY_NAME, Translate("You")));
- m_nick = nick;
-
- // Add self contact
- AddChatContact(m_nick.c_str());
-
- Chat_Control(m_szModuleName, m_tszUserName, SESSION_INITDONE);
- Chat_Control(m_szModuleName, m_tszUserName, SESSION_ONLINE);
- }
- else Chat_Control(m_szModuleName, m_tszUserName, SESSION_OFFLINE);
-}
-
-void MinecraftDynmapProto::ClearChat()
-{
- Chat_Control(m_szModuleName, m_tszUserName, WINDOW_CLEARLOG);
-}
-
-// TODO: Could this be done better?
-MCONTACT MinecraftDynmapProto::GetChatHandle()
-{
- /*if (chatHandle_ != NULL)
- return chatHandle_;
-
- for (auto &hContact : AccContacts()) {
- 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;
- Chat_GetInfo(&gci);
-
- return gci.hContact;
+/*
+
+Minecraft Dynmap plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2015-17 Robert Pösel, 2017-23 Miranda NG team
+
+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 char *name, const char *message, const time_t timestamp, bool addtolog)
+{
+ // replace % to %% to not interfere with chat color codes
+ CMStringA szMessage(message);
+ szMessage.Replace("%", "%%");
+
+ GCEVENT gce = { m_szModuleName, szRoomName, GC_EVENT_MESSAGE };
+ gce.dwFlags = GCEF_UTF8;
+ gce.time = timestamp;
+ gce.pszText.a = szMessage.c_str();
+
+ if (name == NULL) {
+ gce.iType = GC_EVENT_INFORMATION;
+ name = TranslateU("Server");
+ gce.bIsMe = false;
+ }
+ else gce.bIsMe = (m_nick == name);
+
+ if (addtolog)
+ gce.dwFlags |= GCEF_ADDTOLOG;
+
+ gce.pszUID.a = gce.pszNick.a = name;
+ Chat_Event(&gce);
+}
+
+int MinecraftDynmapProto::OnChatEvent(WPARAM, LPARAM lParam)
+{
+ GCHOOK *hook = reinterpret_cast<GCHOOK*>(lParam);
+ if(strcmp(hook->si->pszModule,m_szModuleName))
+ return 0;
+
+ switch(hook->iType) {
+ case GC_USER_MESSAGE:
+ {
+ CMStringA szText(ptrA(mir_utf8encodeW(hook->ptszText)));
+ szText.Replace("%%", "%");
+ if (szText.IsEmpty())
+ break;
+
+ // Outgoing message
+ debugLogA("**Chat - Outgoing message: %s", szText.c_str());
+ ForkThread(&MinecraftDynmapProto::SendMsgWorker, new std::string(szText));
+ }
+ break;
+
+ case GC_SESSION_TERMINATE:
+ m_nick.clear();
+ SetStatus(ID_STATUS_OFFLINE);
+ break;
+ }
+
+ return 0;
+}
+
+void MinecraftDynmapProto::AddChatContact(const char *name)
+{
+ GCEVENT gce = { m_szModuleName, szRoomName, GC_EVENT_JOIN };
+ gce.time = uint32_t(time(0));
+ gce.dwFlags = GCEF_UTF8 + GCEF_ADDTOLOG;
+ gce.pszUID.a = gce.pszNick.a = name;
+ gce.bIsMe = (m_nick == name);
+
+ if (gce.bIsMe)
+ gce.pszStatus.a = "Admin";
+ else
+ gce.pszStatus.a = "Normal";
+
+ Chat_Event(&gce);
+}
+
+void MinecraftDynmapProto::DeleteChatContact(const char *name)
+{
+ GCEVENT gce = { m_szModuleName, szRoomName, GC_EVENT_PART };
+ gce.dwFlags = GCEF_UTF8 + GCEF_ADDTOLOG;
+ gce.pszUID.a = gce.pszNick.a = name;
+ gce.time = uint32_t(time(0));
+ gce.bIsMe = (m_nick == name);
+ Chat_Event(&gce);
+}
+
+INT_PTR MinecraftDynmapProto::OnJoinChat(WPARAM,LPARAM suppress)
+{
+ ptrW tszTitle(mir_a2u_cp(m_title.c_str(), CP_UTF8));
+
+ // Create the group chat session
+ SESSION_INFO *si = Chat_NewSession(GCW_PRIVMESS, m_szModuleName, m_tszUserName, tszTitle);
+ if (!si || m_iStatus == ID_STATUS_OFFLINE)
+ return 0;
+
+ // Create a group
+ Chat_AddGroup(si, TranslateT("Admin"));
+ Chat_AddGroup(si, TranslateT("Normal"));
+
+ // Note: Initialization will finish up in SetChatStatus, called separately
+ if (!suppress)
+ SetChatStatus(m_iStatus);
+
+ return 0;
+}
+
+void MinecraftDynmapProto::SetTopic(const char *topic)
+{
+ GCEVENT gce = { m_szModuleName, szRoomName, GC_EVENT_TOPIC };
+ gce.dwFlags = GCEF_UTF8;
+ gce.time = ::time(0);
+ gce.pszText.a = topic;
+ Chat_Event( &gce);
+}
+
+INT_PTR MinecraftDynmapProto::OnLeaveChat(WPARAM,LPARAM)
+{
+ Chat_Control(m_szModuleName, m_tszUserName, SESSION_OFFLINE);
+ Chat_Terminate(m_szModuleName, m_tszUserName);
+ return 0;
+}
+
+void MinecraftDynmapProto::SetChatStatus(int status)
+{
+ if (status == ID_STATUS_ONLINE)
+ {
+ // Load actual name from database
+ ptrA nick(db_get_sa(0, m_szModuleName, MINECRAFTDYNMAP_KEY_NAME, Translate("You")));
+ m_nick = nick;
+
+ // Add self contact
+ AddChatContact(m_nick.c_str());
+
+ Chat_Control(m_szModuleName, m_tszUserName, SESSION_INITDONE);
+ Chat_Control(m_szModuleName, m_tszUserName, SESSION_ONLINE);
+ }
+ else Chat_Control(m_szModuleName, m_tszUserName, SESSION_OFFLINE);
+}
+
+void MinecraftDynmapProto::ClearChat()
+{
+ Chat_Control(m_szModuleName, m_tszUserName, WINDOW_CLEARLOG);
+}
+
+// TODO: Could this be done better?
+MCONTACT MinecraftDynmapProto::GetChatHandle()
+{
+ /*if (chatHandle_ != NULL)
+ return chatHandle_;
+
+ for (auto &hContact : AccContacts()) {
+ 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;
+ Chat_GetInfo(&gci);
+
+ return gci.hContact;
} \ No newline at end of file
diff --git a/protocols/MinecraftDynmap/src/communication.cpp b/protocols/MinecraftDynmap/src/communication.cpp
index 7ca5f0a732..47e6ec4480 100644
--- a/protocols/MinecraftDynmap/src/communication.cpp
+++ b/protocols/MinecraftDynmap/src/communication.cpp
@@ -1,442 +1,442 @@
-/*
-
-Minecraft Dynmap plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2015-17 Robert Pösel, 2017-22 Miranda NG team
-
-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 != nullptr) {
- 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 = nullptr;
- 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
- NLHR_PTR pnlhr(Netlib_HttpTransaction(m_hNetlibUser, &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 : nullptr;
- break;
-
- default:
- ReleaseMutex(connection_lock_);
- hConnection = pnlhr ? pnlhr->nlc : nullptr;
- break;
- }
-
- // Check and copy response data
- if (pnlhr != nullptr)
- {
- 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());
- } 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:
- return std::string("/up/world/world/") + (!m_timestamp.empty() ? m_timestamp : "0");
-
- //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);
- }
-
- JSONNode root = JSONNode::parse(resp.data.c_str());
- if (!root)
- return false;
-
- /*
- const JSONNode &allowchat_ = root["allowchat"]; // boolean
- const JSONNode &allowwebchat_ = root["allowwebchat"]; // boolean
- const JSONNode &loggedin_ = root["loggedin"]; // boolean
- const JSONNode &loginEnabled_ = root["login-enabled"]; // boolean
- const JSONNode &loginRequired_ = root["webchat-requires-login"]; // boolean
- */
-
- const JSONNode &title_ = root["title"]; // name of server
- const JSONNode &interval_ = root["webchat-interval"]; // limit in seconds for sending messages
- const JSONNode &rate_ = root["updaterate"]; // probably update rate for events request
-
- if (!title_ || !interval_ || !rate_) {
- return handleError(__FUNCTION__, "No title, interval or rate in configuration", true);
- }
-
- m_title = title_.as_string();
- m_interval = interval_.as_int();
- m_updateRate = rate_.as_int();
- 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");
-
- JSONNode root = JSONNode::parse(resp.data.c_str());
- if (!root)
- return handleError(__FUNCTION__, "Invalid JSON response");
-
- const JSONNode &timestamp_ = root["timestamp"];
- if (!timestamp_)
- return handleError(__FUNCTION__, "Received no timestamp node");
-
- m_timestamp = timestamp_.as_string();
-
- const JSONNode &updates_ = root["updates"];
- if (!updates_)
- return handleError(__FUNCTION__, "Received no updates node");
-
- for (auto it = updates_.begin(); it != updates_.end(); ++it) {
- const JSONNode &type_ = (*it)["type"];
- if (type_ && type_.as_string() == "chat") {
- const JSONNode &time_ = (*it)["timestamp"];
- // const JSONNode &source_ = (*it)["source"]; // e.g. "web"
- const JSONNode &playerName_ = (*it)["playerName"];
- const JSONNode &message_ = (*it)["message"];
- // TODO: there are also "channel" and "account" elements
-
- if (!time_ || !playerName_ || !message_) {
- debugLogW(L"Error: No player name, time or text for message");
- continue;
- }
-
- time_t timestamp = atoi(time_.as_string().c_str());
- std::string name = playerName_.as_string();
- std::string message = message_.as_string();
-
- debugLogW(L"Received message: [%d] %s -> %s", timestamp, name.c_str(), message.c_str());
- UpdateChat(name.c_str(), message.c_str(), timestamp);
- }
- }
-
- return handleSuccess(__FUNCTION__);
-}
-
-bool MinecraftDynmapProto::doSendMessage(const std::string &message_text)
-{
- handleEntry(__FUNCTION__);
-
- JSONNode json(JSON_NODE);
- json.push_back(JSONNode("name", m_nick.c_str()));
- json.push_back(JSONNode("message", message_text.c_str()));
- std::string data = json.write();
-
- http::response resp = sendRequest(MINECRAFTDYNMAP_REQUEST_MESSAGE, &data);
-
- if (resp.code == HTTP_CODE_OK) {
- JSONNode root = JSONNode::parse(resp.data.c_str());
- if (root) {
- const JSONNode &error_ = root["error"];
- if (error_) {
- std::string error = error_.as_string();
- if (error == "none") {
- return handleSuccess(__FUNCTION__);
- }
- else if (error == "not-allowed") {
- UpdateChat(nullptr, Translate("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
- ptrA str(db_get_sa(0, m_szModuleName, MINECRAFTDYNMAP_KEY_SERVER));
- if (!str || !str[0]) {
- MessageBox(nullptr, TranslateT("Set server address to connect."), m_tszUserName, MB_OK);
- SetStatus(ID_STATUS_OFFLINE);
- return;
- }
- m_server = str;
-
- // 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", (uint32_t)time(0));
- 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);
-
- if (hConnection)
- Netlib_CloseHandle(hConnection);
- hConnection = nullptr;
-
- if (hEventsConnection)
- Netlib_CloseHandle(hEventsConnection);
- hEventsConnection = nullptr;
-}
-
-void MinecraftDynmapProto::EventsLoop(void *)
-{
- ScopedLock s(events_loop_lock_);
-
- time_t tim = ::time(0);
- 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 == nullptr)
- return;
-
- ScopedLock s(send_message_lock_);
-
- CMStringA data = ((std::string*)p)->c_str();
- delete (std::string*)p;
-
- data.TrimRight();
-
- if (isOnline() && data.GetLength())
- doSendMessage(data.c_str());
-}
+/*
+
+Minecraft Dynmap plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2015-17 Robert Pösel, 2017-23 Miranda NG team
+
+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 != nullptr) {
+ 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 = nullptr;
+ 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
+ NLHR_PTR pnlhr(Netlib_HttpTransaction(m_hNetlibUser, &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 : nullptr;
+ break;
+
+ default:
+ ReleaseMutex(connection_lock_);
+ hConnection = pnlhr ? pnlhr->nlc : nullptr;
+ break;
+ }
+
+ // Check and copy response data
+ if (pnlhr != nullptr)
+ {
+ 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());
+ } 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:
+ return std::string("/up/world/world/") + (!m_timestamp.empty() ? m_timestamp : "0");
+
+ //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);
+ }
+
+ JSONNode root = JSONNode::parse(resp.data.c_str());
+ if (!root)
+ return false;
+
+ /*
+ const JSONNode &allowchat_ = root["allowchat"]; // boolean
+ const JSONNode &allowwebchat_ = root["allowwebchat"]; // boolean
+ const JSONNode &loggedin_ = root["loggedin"]; // boolean
+ const JSONNode &loginEnabled_ = root["login-enabled"]; // boolean
+ const JSONNode &loginRequired_ = root["webchat-requires-login"]; // boolean
+ */
+
+ const JSONNode &title_ = root["title"]; // name of server
+ const JSONNode &interval_ = root["webchat-interval"]; // limit in seconds for sending messages
+ const JSONNode &rate_ = root["updaterate"]; // probably update rate for events request
+
+ if (!title_ || !interval_ || !rate_) {
+ return handleError(__FUNCTION__, "No title, interval or rate in configuration", true);
+ }
+
+ m_title = title_.as_string();
+ m_interval = interval_.as_int();
+ m_updateRate = rate_.as_int();
+ 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");
+
+ JSONNode root = JSONNode::parse(resp.data.c_str());
+ if (!root)
+ return handleError(__FUNCTION__, "Invalid JSON response");
+
+ const JSONNode &timestamp_ = root["timestamp"];
+ if (!timestamp_)
+ return handleError(__FUNCTION__, "Received no timestamp node");
+
+ m_timestamp = timestamp_.as_string();
+
+ const JSONNode &updates_ = root["updates"];
+ if (!updates_)
+ return handleError(__FUNCTION__, "Received no updates node");
+
+ for (auto it = updates_.begin(); it != updates_.end(); ++it) {
+ const JSONNode &type_ = (*it)["type"];
+ if (type_ && type_.as_string() == "chat") {
+ const JSONNode &time_ = (*it)["timestamp"];
+ // const JSONNode &source_ = (*it)["source"]; // e.g. "web"
+ const JSONNode &playerName_ = (*it)["playerName"];
+ const JSONNode &message_ = (*it)["message"];
+ // TODO: there are also "channel" and "account" elements
+
+ if (!time_ || !playerName_ || !message_) {
+ debugLogW(L"Error: No player name, time or text for message");
+ continue;
+ }
+
+ time_t timestamp = atoi(time_.as_string().c_str());
+ std::string name = playerName_.as_string();
+ std::string message = message_.as_string();
+
+ debugLogW(L"Received message: [%d] %s -> %s", timestamp, name.c_str(), message.c_str());
+ UpdateChat(name.c_str(), message.c_str(), timestamp);
+ }
+ }
+
+ return handleSuccess(__FUNCTION__);
+}
+
+bool MinecraftDynmapProto::doSendMessage(const std::string &message_text)
+{
+ handleEntry(__FUNCTION__);
+
+ JSONNode json(JSON_NODE);
+ json.push_back(JSONNode("name", m_nick.c_str()));
+ json.push_back(JSONNode("message", message_text.c_str()));
+ std::string data = json.write();
+
+ http::response resp = sendRequest(MINECRAFTDYNMAP_REQUEST_MESSAGE, &data);
+
+ if (resp.code == HTTP_CODE_OK) {
+ JSONNode root = JSONNode::parse(resp.data.c_str());
+ if (root) {
+ const JSONNode &error_ = root["error"];
+ if (error_) {
+ std::string error = error_.as_string();
+ if (error == "none") {
+ return handleSuccess(__FUNCTION__);
+ }
+ else if (error == "not-allowed") {
+ UpdateChat(nullptr, Translate("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
+ ptrA str(db_get_sa(0, m_szModuleName, MINECRAFTDYNMAP_KEY_SERVER));
+ if (!str || !str[0]) {
+ MessageBox(nullptr, TranslateT("Set server address to connect."), m_tszUserName, MB_OK);
+ SetStatus(ID_STATUS_OFFLINE);
+ return;
+ }
+ m_server = str;
+
+ // 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", (uint32_t)time(0));
+ 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);
+
+ if (hConnection)
+ Netlib_CloseHandle(hConnection);
+ hConnection = nullptr;
+
+ if (hEventsConnection)
+ Netlib_CloseHandle(hEventsConnection);
+ hEventsConnection = nullptr;
+}
+
+void MinecraftDynmapProto::EventsLoop(void *)
+{
+ ScopedLock s(events_loop_lock_);
+
+ time_t tim = ::time(0);
+ 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 == nullptr)
+ return;
+
+ ScopedLock s(send_message_lock_);
+
+ CMStringA data = ((std::string*)p)->c_str();
+ delete (std::string*)p;
+
+ data.TrimRight();
+
+ if (isOnline() && data.GetLength())
+ doSendMessage(data.c_str());
+}
diff --git a/protocols/MinecraftDynmap/src/constants.h b/protocols/MinecraftDynmap/src/constants.h
index 42d1d2c33c..b8f454fe0f 100644
--- a/protocols/MinecraftDynmap/src/constants.h
+++ b/protocols/MinecraftDynmap/src/constants.h
@@ -1,46 +1,46 @@
-/*
-
-Minecraft Dynmap plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2015-17 Robert Pösel, 2017-22 Miranda NG team
-
-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 "Minecraft 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"
+/*
+
+Minecraft Dynmap plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2015-17 Robert Pösel, 2017-23 Miranda NG team
+
+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 "Minecraft 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
index 54ea975fae..38707c6870 100644
--- a/protocols/MinecraftDynmap/src/dialogs.cpp
+++ b/protocols/MinecraftDynmap/src/dialogs.cpp
@@ -1,98 +1,98 @@
-/*
-
-Minecraft Dynmap plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2015-17 Robert Pösel, 2017-22 Miranda NG team
-
-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
-
-static IconItem iconList[] =
-{
- { "proto", LPGEN("Protocol icon"), IDI_PROTO },
-};
-
-static HANDLE hIconLibItem[_countof(iconList)];
-
-void InitIcons(void)
-{
- g_plugin.registerIcon("Protocols/MinecraftDynmap", iconList, "MinecraftDynmap");
-}
-
-// Dialogs
-
-static void LoadDBText(MinecraftDynmapProto* ppro, HWND hwnd, int idCtrl, const char* szSetting)
-{
- ptrW tstr(db_get_wsa(0, ppro->m_szModuleName, szSetting));
- if (tstr)
- SetDlgItemText(hwnd, idCtrl, tstr);
-}
-
-static void StoreDBText(MinecraftDynmapProto* ppro, HWND hwnd, int idCtrl, const char* szSetting)
-{
- wchar_t tstr[250 + 1];
-
- GetDlgItemText(hwnd, idCtrl, tstr, _countof(tstr));
- if (tstr[0] != '\0')
- db_set_ws(0, ppro->m_szModuleName, szSetting, tstr);
- else
- db_unset(0, 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;
-
- 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;
-}
+/*
+
+Minecraft Dynmap plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2015-17 Robert Pösel, 2017-23 Miranda NG team
+
+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
+
+static IconItem iconList[] =
+{
+ { "proto", LPGEN("Protocol icon"), IDI_PROTO },
+};
+
+static HANDLE hIconLibItem[_countof(iconList)];
+
+void InitIcons(void)
+{
+ g_plugin.registerIcon("Protocols/MinecraftDynmap", iconList, "MinecraftDynmap");
+}
+
+// Dialogs
+
+static void LoadDBText(MinecraftDynmapProto* ppro, HWND hwnd, int idCtrl, const char* szSetting)
+{
+ ptrW tstr(db_get_wsa(0, ppro->m_szModuleName, szSetting));
+ if (tstr)
+ SetDlgItemText(hwnd, idCtrl, tstr);
+}
+
+static void StoreDBText(MinecraftDynmapProto* ppro, HWND hwnd, int idCtrl, const char* szSetting)
+{
+ wchar_t tstr[250 + 1];
+
+ GetDlgItemText(hwnd, idCtrl, tstr, _countof(tstr));
+ if (tstr[0] != '\0')
+ db_set_ws(0, ppro->m_szModuleName, szSetting, tstr);
+ else
+ db_unset(0, 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;
+
+ 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
index 0af8617bae..f9d4586590 100644
--- a/protocols/MinecraftDynmap/src/dialogs.h
+++ b/protocols/MinecraftDynmap/src/dialogs.h
@@ -1,27 +1,27 @@
-/*
-
-Minecraft Dynmap plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2015-17 Robert Pösel, 2017-22 Miranda NG team
-
-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);
-
-INT_PTR CALLBACK MinecraftDynmapAccountProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
+/*
+
+Minecraft Dynmap plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2015-17 Robert Pösel, 2017-23 Miranda NG team
+
+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);
+
+INT_PTR CALLBACK MinecraftDynmapAccountProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
diff --git a/protocols/MinecraftDynmap/src/main.cpp b/protocols/MinecraftDynmap/src/main.cpp
index 5aa5c93460..a108fc6244 100644
--- a/protocols/MinecraftDynmap/src/main.cpp
+++ b/protocols/MinecraftDynmap/src/main.cpp
@@ -1,90 +1,90 @@
-/*
-
-Minecraft Dynmap plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2015-17 Robert Pösel, 2017-22 Miranda NG team
-
-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"
-
-CMPlugin g_plugin;
-
-std::string g_strUserAgent;
-
-PLUGININFOEX pluginInfoEx = {
- sizeof(PLUGININFOEX),
- __PLUGIN_NAME,
- PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
- __DESCRIPTION,
- __AUTHOR,
- __COPYRIGHT,
- __AUTHORWEB,
- UNICODE_AWARE,
- // {40DA5EBD-4F2D-4BEA-841C-EAB77BEE6F4F}
- { 0x40da5ebd, 0x4f2d, 0x4bea, 0x84, 0x1c, 0xea, 0xb7, 0x7b, 0xee, 0x6f, 0x4f }
-};
-
-CMPlugin::CMPlugin() :
- ACCPROTOPLUGIN<MinecraftDynmapProto>("MinecraftDynmap", pluginInfoEx)
-{
- SetUniqueId("Nick");
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Interface information
-
-extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST};
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Load
-
-static HANDLE g_hEvents[1];
-
-int CMPlugin::Load()
-{
- InitIcons();
-
- // Init native User-Agent
- {
- MFileVersion w;
- Miranda_GetFileVersion(&w);
- std::stringstream agent;
- agent << "Miranda NG/" << w[0] << "." << w[1] << "." << w[2] << "." << w[3];
- #ifdef _WIN64
- agent << " Minecraft Dynmap Protocol x64/";
- #else
- agent << " Minecraft Dynmap Protocol/";
- #endif
- agent << __VERSION_STRING_DOTS;
- g_strUserAgent = agent.str();
- }
-
- return 0;
-}
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Unload
-
-int CMPlugin::Unload()
-{
- for (size_t i=0; i < _countof(g_hEvents); i++)
- UnhookEvent(g_hEvents[i]);
-
- return 0;
-}
-
+/*
+
+Minecraft Dynmap plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2015-17 Robert Pösel, 2017-23 Miranda NG team
+
+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"
+
+CMPlugin g_plugin;
+
+std::string g_strUserAgent;
+
+PLUGININFOEX pluginInfoEx = {
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {40DA5EBD-4F2D-4BEA-841C-EAB77BEE6F4F}
+ { 0x40da5ebd, 0x4f2d, 0x4bea, 0x84, 0x1c, 0xea, 0xb7, 0x7b, 0xee, 0x6f, 0x4f }
+};
+
+CMPlugin::CMPlugin() :
+ ACCPROTOPLUGIN<MinecraftDynmapProto>("MinecraftDynmap", pluginInfoEx)
+{
+ SetUniqueId("Nick");
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Interface information
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Load
+
+static HANDLE g_hEvents[1];
+
+int CMPlugin::Load()
+{
+ InitIcons();
+
+ // Init native User-Agent
+ {
+ MFileVersion w;
+ Miranda_GetFileVersion(&w);
+ std::stringstream agent;
+ agent << "Miranda NG/" << w[0] << "." << w[1] << "." << w[2] << "." << w[3];
+ #ifdef _WIN64
+ agent << " Minecraft Dynmap Protocol x64/";
+ #else
+ agent << " Minecraft Dynmap Protocol/";
+ #endif
+ agent << __VERSION_STRING_DOTS;
+ g_strUserAgent = agent.str();
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Unload
+
+int CMPlugin::Unload()
+{
+ for (size_t i=0; i < _countof(g_hEvents); i++)
+ UnhookEvent(g_hEvents[i]);
+
+ return 0;
+}
+
diff --git a/protocols/MinecraftDynmap/src/proto.cpp b/protocols/MinecraftDynmap/src/proto.cpp
index e787b831da..47c05d5105 100644
--- a/protocols/MinecraftDynmap/src/proto.cpp
+++ b/protocols/MinecraftDynmap/src/proto.cpp
@@ -1,180 +1,180 @@
-/*
-
-Minecraft Dynmap plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2015-17 Robert Pösel, 2017-22 Miranda NG team
-
-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 wchar_t* username) :
- PROTO<MinecraftDynmapProto>(proto_name, username), m_interval(0), hConnection(nullptr), hEventsConnection(nullptr),
- m_updateRate(5000), m_nick("")
-{
- this->signon_lock_ = CreateMutex(nullptr, FALSE, nullptr);
- this->send_message_lock_ = CreateMutex(nullptr, FALSE, nullptr);
- this->connection_lock_ = CreateMutex(nullptr, FALSE, nullptr);
- this->events_loop_lock_ = CreateMutex(nullptr, FALSE, nullptr);
- this->events_loop_event_ = CreateEvent(nullptr, FALSE, FALSE, nullptr);
-
- // Group chats
- CreateProtoService(PS_JOINCHAT, &MinecraftDynmapProto::OnJoinChat);
- CreateProtoService(PS_LEAVECHAT, &MinecraftDynmapProto::OnLeaveChat);
-
- CreateProtoService(PS_CREATEACCMGRUI, &MinecraftDynmapProto::SvcCreateAccMgrUI);
-
- HookProtoEvent(ME_GC_EVENT, &MinecraftDynmapProto::OnChatEvent);
-
- // Create standard network connection
- NETLIBUSER nlu = {};
- nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE;
- nlu.szSettingsModule = m_szModuleName;
- nlu.szDescriptiveName.w = m_tszUserName;
- m_hNetlibUser = Netlib_RegisterUser(&nlu);
- if (m_hNetlibUser == nullptr) {
- wchar_t error[200];
- mir_snwprintf(error, TranslateT("Unable to initialize Netlib for %s."), m_tszUserName);
- MessageBox(nullptr, error, L"Miranda NG", MB_OK | MB_ICONERROR);
- }
-
- // Register group chat
- GCREGISTER gcr = {};
- gcr.pszModule = m_szModuleName;
- gcr.ptszDispName = m_tszUserName;
- gcr.iMaxText = MINECRAFTDYNMAP_MESSAGE_LIMIT;
- Chat_Register(&gcr);
-
- // Client instantiation
- this->error_count_ = 0;
- this->chatHandle_ = nullptr;
- this->szRoomName = mir_utf8encodeW(username);
-}
-
-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_);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-INT_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 (INT_PTR) TranslateT("Visible name");
- }
- 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;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// EVENTS
-
-INT_PTR MinecraftDynmapProto::SvcCreateAccMgrUI(WPARAM, LPARAM lParam)
-{
- return (INT_PTR)CreateDialogParam(g_plugin.getInst(),MAKEINTRESOURCE(IDD_MinecraftDynmapACCOUNT), (HWND)lParam, MinecraftDynmapAccountProc, (LPARAM)this);
-}
-
-void MinecraftDynmapProto::OnShutdown()
-{
- SetStatus(ID_STATUS_OFFLINE);
-}
-
-void MinecraftDynmapProto::OnContactDeleted(MCONTACT)
-{
- OnLeaveChat(NULL, NULL);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-// 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(0, m_szModuleName, MINECRAFTDYNMAP_KEY_TIMEOUTS_LIMIT, MINECRAFTDYNMAP_TIMEOUTS_LIMIT)) {
- return true;
- }
-
- reset_error();
- SetStatus(ID_STATUS_OFFLINE);
- return false;
-}
+/*
+
+Minecraft Dynmap plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2015-17 Robert Pösel, 2017-23 Miranda NG team
+
+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 wchar_t* username) :
+ PROTO<MinecraftDynmapProto>(proto_name, username), m_interval(0), hConnection(nullptr), hEventsConnection(nullptr),
+ m_updateRate(5000), m_nick("")
+{
+ this->signon_lock_ = CreateMutex(nullptr, FALSE, nullptr);
+ this->send_message_lock_ = CreateMutex(nullptr, FALSE, nullptr);
+ this->connection_lock_ = CreateMutex(nullptr, FALSE, nullptr);
+ this->events_loop_lock_ = CreateMutex(nullptr, FALSE, nullptr);
+ this->events_loop_event_ = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+
+ // Group chats
+ CreateProtoService(PS_JOINCHAT, &MinecraftDynmapProto::OnJoinChat);
+ CreateProtoService(PS_LEAVECHAT, &MinecraftDynmapProto::OnLeaveChat);
+
+ CreateProtoService(PS_CREATEACCMGRUI, &MinecraftDynmapProto::SvcCreateAccMgrUI);
+
+ HookProtoEvent(ME_GC_EVENT, &MinecraftDynmapProto::OnChatEvent);
+
+ // Create standard network connection
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE;
+ nlu.szSettingsModule = m_szModuleName;
+ nlu.szDescriptiveName.w = m_tszUserName;
+ m_hNetlibUser = Netlib_RegisterUser(&nlu);
+ if (m_hNetlibUser == nullptr) {
+ wchar_t error[200];
+ mir_snwprintf(error, TranslateT("Unable to initialize Netlib for %s."), m_tszUserName);
+ MessageBox(nullptr, error, L"Miranda NG", MB_OK | MB_ICONERROR);
+ }
+
+ // Register group chat
+ GCREGISTER gcr = {};
+ gcr.pszModule = m_szModuleName;
+ gcr.ptszDispName = m_tszUserName;
+ gcr.iMaxText = MINECRAFTDYNMAP_MESSAGE_LIMIT;
+ Chat_Register(&gcr);
+
+ // Client instantiation
+ this->error_count_ = 0;
+ this->chatHandle_ = nullptr;
+ this->szRoomName = mir_utf8encodeW(username);
+}
+
+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_);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+INT_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 (INT_PTR) TranslateT("Visible name");
+ }
+ 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;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// EVENTS
+
+INT_PTR MinecraftDynmapProto::SvcCreateAccMgrUI(WPARAM, LPARAM lParam)
+{
+ return (INT_PTR)CreateDialogParam(g_plugin.getInst(),MAKEINTRESOURCE(IDD_MinecraftDynmapACCOUNT), (HWND)lParam, MinecraftDynmapAccountProc, (LPARAM)this);
+}
+
+void MinecraftDynmapProto::OnShutdown()
+{
+ SetStatus(ID_STATUS_OFFLINE);
+}
+
+void MinecraftDynmapProto::OnContactDeleted(MCONTACT)
+{
+ OnLeaveChat(NULL, NULL);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// 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(0, 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
index b863b2547c..852edaef74 100644
--- a/protocols/MinecraftDynmap/src/proto.h
+++ b/protocols/MinecraftDynmap/src/proto.h
@@ -1,136 +1,136 @@
-/*
-
-Minecraft Dynmap plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2015-17 Robert Pösel, 2017-22 Miranda NG team
-
-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>
-{
- ptrA szRoomName;
-
-public:
- MinecraftDynmapProto(const char *proto_name, const wchar_t *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
- INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override;
- int SetStatus(int iNewStatus) override;
-
- void OnContactDeleted(MCONTACT) override;
- void OnShutdown() override;
-
- // Services
- INT_PTR __cdecl SvcCreateAccMgrUI(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 UpdateChat(const char *name, const char *message, const time_t timestamp = time(0), bool addtochat = true);
- void AddChatContact(const char *nick);
- void DeleteChatContact(const char *name);
- void SetChatStatus(int);
- void ClearChat();
- void SetTopic(const char *topic);
- MCONTACT GetChatHandle();
-
- // Locks
- HANDLE signon_lock_;
- HANDLE connection_lock_;
- HANDLE send_message_lock_;
- HANDLE events_loop_lock_;
-
- HANDLE events_loop_event_;
-
- // Handles
- HNETLIBCONN hConnection;
- HNETLIBCONN 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 = nullptr, std::string *get_data = nullptr);
- std::string chooseAction(int, std::string *get_data = nullptr);
- 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
- std::string m_nick;
- std::string m_cookie;
- std::string m_server;
- std::string m_title;
- std::string m_timestamp;
- int m_interval;
- int m_updateRate;
-};
-
-struct CMPlugin : public ACCPROTOPLUGIN<MinecraftDynmapProto>
-{
- CMPlugin();
-
- int Load() override;
- int Unload() override;
-};
+/*
+
+Minecraft Dynmap plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2015-17 Robert Pösel, 2017-23 Miranda NG team
+
+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>
+{
+ ptrA szRoomName;
+
+public:
+ MinecraftDynmapProto(const char *proto_name, const wchar_t *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
+ INT_PTR GetCaps(int type, MCONTACT hContact = NULL) override;
+ int SetStatus(int iNewStatus) override;
+
+ void OnContactDeleted(MCONTACT) override;
+ void OnShutdown() override;
+
+ // Services
+ INT_PTR __cdecl SvcCreateAccMgrUI(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 UpdateChat(const char *name, const char *message, const time_t timestamp = time(0), bool addtochat = true);
+ void AddChatContact(const char *nick);
+ void DeleteChatContact(const char *name);
+ void SetChatStatus(int);
+ void ClearChat();
+ void SetTopic(const char *topic);
+ MCONTACT GetChatHandle();
+
+ // Locks
+ HANDLE signon_lock_;
+ HANDLE connection_lock_;
+ HANDLE send_message_lock_;
+ HANDLE events_loop_lock_;
+
+ HANDLE events_loop_event_;
+
+ // Handles
+ HNETLIBCONN hConnection;
+ HNETLIBCONN 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 = nullptr, std::string *get_data = nullptr);
+ std::string chooseAction(int, std::string *get_data = nullptr);
+ 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
+ std::string m_nick;
+ std::string m_cookie;
+ std::string m_server;
+ std::string m_title;
+ std::string m_timestamp;
+ int m_interval;
+ int m_updateRate;
+};
+
+struct CMPlugin : public ACCPROTOPLUGIN<MinecraftDynmapProto>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
diff --git a/protocols/MinecraftDynmap/src/stdafx.cxx b/protocols/MinecraftDynmap/src/stdafx.cxx
index 1ab0efee94..ebbde0ade1 100644
--- a/protocols/MinecraftDynmap/src/stdafx.cxx
+++ b/protocols/MinecraftDynmap/src/stdafx.cxx
@@ -1,18 +1,18 @@
-/*
-Copyright (C) 2012-22 Miranda NG team (https://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/>.
-*/
-
+/*
+Copyright (C) 2012-23 Miranda NG team (https://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
index 929267ae60..f5cc740bca 100644
--- a/protocols/MinecraftDynmap/src/stdafx.h
+++ b/protocols/MinecraftDynmap/src/stdafx.h
@@ -1,70 +1,70 @@
-/*
-
-Minecraft Dynmap plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2015-17 Robert Pösel, 2017-22 Miranda NG team
-
-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 <commctrl.h>
-
-#include <newpluginapi.h>
-#include <m_system.h>
-#include <m_chat_int.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 <m_http.h>
-
-#include "version.h"
-
-class MinecraftDynmapProto;
-
-#include "utils.h"
-#include "proto.h"
-#include "constants.h"
-#include "dialogs.h"
-#include "resource.h"
-
-extern std::string g_strUserAgent;
+/*
+
+Minecraft Dynmap plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2015-17 Robert Pösel, 2017-23 Miranda NG team
+
+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 <commctrl.h>
+
+#include <newpluginapi.h>
+#include <m_system.h>
+#include <m_chat_int.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 <m_http.h>
+
+#include "version.h"
+
+class MinecraftDynmapProto;
+
+#include "utils.h"
+#include "proto.h"
+#include "constants.h"
+#include "dialogs.h"
+#include "resource.h"
+
+extern std::string g_strUserAgent;
diff --git a/protocols/MinecraftDynmap/src/utils.h b/protocols/MinecraftDynmap/src/utils.h
index e4f3d3ff37..c42fb86d9e 100644
--- a/protocols/MinecraftDynmap/src/utils.h
+++ b/protocols/MinecraftDynmap/src/utils.h
@@ -1,63 +1,63 @@
-/*
-
-Minecraft Dynmap plugin for Miranda Instant Messenger
-_____________________________________________
-
-Copyright © 2015-17 Robert Pösel, 2017-22 Miranda NG team
-
-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_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;
- };
-}
-
-class ScopedLock
-{
-public:
- ScopedLock(HANDLE h) : handle_(h)
- {
- WaitForSingleObject(handle_,INFINITE);
- }
- ~ScopedLock()
- {
- if (handle_)
- ReleaseMutex(handle_);
- }
- void Unlock()
- {
- ReleaseMutex(handle_);
- handle_ = nullptr;
- }
-private:
- HANDLE handle_;
-};
+/*
+
+Minecraft Dynmap plugin for Miranda Instant Messenger
+_____________________________________________
+
+Copyright © 2015-17 Robert Pösel, 2017-23 Miranda NG team
+
+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_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;
+ };
+}
+
+class ScopedLock
+{
+public:
+ ScopedLock(HANDLE h) : handle_(h)
+ {
+ WaitForSingleObject(handle_,INFINITE);
+ }
+ ~ScopedLock()
+ {
+ if (handle_)
+ ReleaseMutex(handle_);
+ }
+ void Unlock()
+ {
+ ReleaseMutex(handle_);
+ handle_ = nullptr;
+ }
+private:
+ HANDLE handle_;
+};
diff --git a/protocols/MinecraftDynmap/src/version.h b/protocols/MinecraftDynmap/src/version.h
index fa021b8cae..1e71a749da 100644
--- a/protocols/MinecraftDynmap/src/version.h
+++ b/protocols/MinecraftDynmap/src/version.h
@@ -10,4 +10,4 @@
#define __DESCRIPTION "Minecraft Dynmap support for Miranda NG."
#define __AUTHOR "Robert Pösel"
#define __AUTHORWEB "https://miranda-ng.org/p/MinecraftDynmap"
-#define __COPYRIGHT "© 2015-17 Robert Pösel, 2017-22 Miranda NG team"
+#define __COPYRIGHT "© 2015-17 Robert Pösel, 2017-23 Miranda NG team"