/* 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 . */ #include "stdafx.h" MinecraftDynmapProto::MinecraftDynmapProto(const char* proto_name, const TCHAR* username) : PROTO(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) { TCHAR error[200]; mir_sntprintf(error, SIZEOF(error), TranslateT("Unable to initialize Netlib for %s."), m_tszUserName); MessageBox(NULL, error, _T("Miranda NG"), MB_OK | MB_ICONERROR); } // 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(&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; }