/* Paste It plugin Copyright (C) 2011 Krzysztof Kral 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 . */ #include "stdafx.h" PasteToWeb* pasteToWebs[PasteToWeb::pages]; std::map* contactWindows; HNETLIBUSER g_hNetlibUser; HANDLE hModulesLoaded, hTabsrmmButtonPressed; HANDLE hPrebuildContactMenu; HGENMENU hContactMenu; HGENMENU hWebPageMenus[PasteToWeb::pages]; HANDLE hOptionsInit; HANDLE hWindowEvent = nullptr; static IconItem iconList[] = { { LPGEN("Paste It"), "PasteIt_main", IDI_MENU } }; CMPlugin g_plugin; #define FROM_CLIPBOARD 10 #define FROM_FILE 11 #define DEF_PAGES_START 20 #define MS_PASTEIT_CONTACTMENU "PasteIt/ContactMenu" ///////////////////////////////////////////////////////////////////////////////////////// PLUGININFOEX pluginInfoEx = { sizeof(PLUGININFOEX), __PLUGIN_NAME, PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), __DESCRIPTION, __AUTHOR, __COPYRIGHT, __AUTHORWEB, UNICODE_AWARE, // {1AAC15E8-DCEC-4050-B66F-2AA0E6120C22} { 0x1aac15e8, 0xdcec, 0x4050, { 0xb6, 0x6f, 0x2a, 0xa0, 0xe6, 0x12, 0xc, 0x22 } } }; CMPlugin::CMPlugin() : PLUGIN(MODULENAME, pluginInfoEx) { } ///////////////////////////////////////////////////////////////////////////////////////// std::wstring GetFile() { wchar_t filter[512]; mir_wstrncpy(filter, TranslateT("All Files (*.*)"), _countof(filter)); memcpy(filter + mir_wstrlen(filter), L"\0*.*\0", 6 * sizeof(wchar_t)); wchar_t stzFilePath[1024]; stzFilePath[0] = 0; stzFilePath[1] = 0; OPENFILENAME ofn = { 0 }; ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = nullptr; ofn.lpstrFilter = filter; ofn.nFilterIndex = 1; ofn.lpstrFile = stzFilePath; ofn.lpstrTitle = TranslateT("Paste It - Select file"); ofn.nMaxFile = _countof(stzFilePath); ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_EXPLORER | OFN_NOCHANGEDIR; if (GetOpenFileName(&ofn)) { return stzFilePath; } return L""; } static void PasteIt(MCONTACT hContact, int mode) { PasteToWeb* pasteToWeb = pasteToWebs[Options::instance->defWeb]; if (mode == FROM_CLIPBOARD) { pasteToWeb->FromClipboard(); } else if (mode == FROM_FILE) { std::wstring file = GetFile(); if (file.length() > 0) { pasteToWeb->FromFile(file); } else return; } else return; if (pasteToWeb->szFileLink[0] == 0 && pasteToWeb->error != nullptr) { MessageBox(nullptr, pasteToWeb->error, TranslateT("Error"), MB_OK | MB_ICONERROR); } else if (hContact != NULL && pasteToWeb->szFileLink[0] != 0) { char *szProto = Proto_GetBaseAccountName(hContact); if (szProto && (INT_PTR)szProto != CALLSERVICE_NOTFOUND) { BOOL isChat = db_get_b(hContact, szProto, "ChatRoom", 0); if (Options::instance->autoSend) { if (!isChat) { DBEVENTINFO dbei = {}; dbei.eventType = EVENTTYPE_MESSAGE; dbei.flags = DBEF_SENT; dbei.szModule = szProto; dbei.timestamp = (uint32_t)time(0); dbei.cbBlob = (uint32_t)mir_strlen(pasteToWeb->szFileLink) + 1; dbei.pBlob = (uint8_t*)pasteToWeb->szFileLink; db_event_add(hContact, &dbei); ProtoChainSend(hContact, PSS_MESSAGE, 0, (LPARAM)pasteToWeb->szFileLink); } else { // PSS_MESSAGE is not compatible with chat rooms // there are no simple method to send text to all users // in chat room. // Next step is to get all protocol sessions and find // one with correct hContact int cnt = g_chatApi.SM_GetCount(szProto); for (int i = 0; i < cnt; i++) { GC_INFO gci = {}; gci.iItem = i; gci.pszModule = szProto; gci.Flags = GCF_BYINDEX | GCF_HCONTACT | GCF_ID; Chat_GetInfo(&gci); if (gci.hContact == hContact) { // In this place session was finded, gci.pszID contains // session ID, but it is in unicode or ascii format, // depends on protocol wersion Chat_SendUserMessage(szProto, gci.pszID, _A2T(pasteToWeb->szFileLink)); break; } } } // Send message to focus window CallServiceSync(MS_MSG_SENDMESSAGE, hContact, 0); } else { if (isChat) { // MS_MSG_SENDMESSAGE in incompatible with chat rooms, // because it sends text to IDC_MESSAGE window, // but in chat rooms is only IDC_CHAT_MESSAGE window. // contactWindows map contains all opened hContact // with assaigned to them chat windows. // This map is prepared in ME_MSG_WINDOWEVENT event. std::map::iterator it = contactWindows->find(hContact); if (it != contactWindows->end()) { // it->second is imput window, so now I can send to them // new text. Afterr all is sended MS_MSG_SENDMESSAGE // to focus window. SendMessage(it->second, EM_SETSEL, -1, GetWindowTextLength(it->second)); SendMessageA(it->second, EM_REPLACESEL, FALSE, (LPARAM)pasteToWeb->szFileLink); CallServiceSync(MS_MSG_SENDMESSAGE, hContact, NULL); } else { // If window do not exist, maybe it is not chat CallServiceSync(MS_MSG_SENDMESSAGE, hContact, (LPARAM)pasteToWeb->szFileLink); } } else { CallServiceSync(MS_MSG_SENDMESSAGE, hContact, (LPARAM)pasteToWeb->szFileLink); } } } } } static int TabsrmmButtonPressed(WPARAM hContact, LPARAM lParam) { CustomButtonClickData *cbc = (CustomButtonClickData *)lParam; if (!mir_strcmp(cbc->pszModule, MODULENAME) && cbc->dwButtonId == 1 && hContact) { if (cbc->flags == BBCF_ARROWCLICKED) { HMENU hMenu = CreatePopupMenu(); if (hMenu) { AppendMenu(hMenu, MF_STRING, FROM_CLIPBOARD, TranslateT("Paste from clipboard")); AppendMenu(hMenu, MF_STRING, FROM_FILE, TranslateT("Paste from file")); HMENU hDefMenu = CreatePopupMenu(); for (int i = 0; i < PasteToWeb::pages; ++i) { UINT flags = MF_STRING; if (Options::instance->defWeb == i) flags |= MF_CHECKED; AppendMenu(hDefMenu, flags, DEF_PAGES_START + i, pasteToWebs[i]->GetName()); } AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT_PTR)hDefMenu, TranslateT("Default web page")); POINT pt; GetCursorPos(&pt); HWND hwndBtn = WindowFromPoint(pt); if (hwndBtn) { RECT rc; GetWindowRect(hwndBtn, &rc); SetForegroundWindow(cbc->hwndFrom); int selected = TrackPopupMenu(hMenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, cbc->hwndFrom, nullptr); if (selected != 0) { if (selected >= DEF_PAGES_START) { Options::instance->SetDefWeb(selected - DEF_PAGES_START); } else { PasteIt(hContact, selected); } } } DestroyMenu(hDefMenu); DestroyMenu(hMenu); } } else { PasteIt(hContact, FROM_CLIPBOARD); } } return 0; } static int PrebuildContactMenu(WPARAM wParam, LPARAM) { bool bIsContact = false; char *szProto = Proto_GetBaseAccountName(wParam); if (szProto && (INT_PTR)szProto != CALLSERVICE_NOTFOUND) bIsContact = (CallProtoService(szProto, PS_GETCAPS, PFLAGNUM_1, 0) & PF1_IM) != 0; Menu_ShowItem(hContactMenu, bIsContact); return 0; } static INT_PTR ContactMenuService(WPARAM hContact, LPARAM lParam) { if (lParam >= DEF_PAGES_START) Options::instance->SetDefWeb(lParam - DEF_PAGES_START); else PasteIt(hContact, lParam); return 0; } static void InitMenuItems() { CMenuItem mi(&g_plugin); SET_UID(mi, 0x33ecc112, 0x6, 0x487d, 0xbb, 0x8b, 0x76, 0xb4, 0x17, 0x9b, 0xdb, 0xc5); mi.flags = CMIF_UNICODE; mi.hIcolibItem = iconList[0].hIcolib; mi.position = 3000090005; mi.name.w = LPGENW("Paste It"); hContactMenu = Menu_AddContactMenuItem(&mi); memset(&mi, 0, sizeof(mi)); SET_UID(mi, 0xedc0456d, 0x5aa8, 0x4a61, 0xbe, 0xfd, 0xed, 0x34, 0xb2, 0xcc, 0x6, 0x54); mi.flags = CMIF_UNICODE; mi.pszService = MS_PASTEIT_CONTACTMENU; mi.root = hContactMenu; mi.name.w = LPGENW("Paste from clipboard"); Menu_ConfigureItem(Menu_AddContactMenuItem(&mi), MCI_OPT_EXECPARAM, FROM_CLIPBOARD); SET_UID(mi, 0x7af7c3cb, 0xedc4, 0x4f3e, 0xb5, 0xe1, 0x42, 0x64, 0x5b, 0x7d, 0xd8, 0x1e); mi.name.w = LPGENW("Paste from file"); Menu_ConfigureItem(Menu_AddContactMenuItem(&mi), MCI_OPT_EXECPARAM, FROM_FILE); SET_UID(mi, 0xe58410ad, 0xa723, 0x48b9, 0xab, 0x7e, 0x5e, 0x42, 0x8b, 0x8, 0x32, 0x2f); mi.name.w = LPGENW("Default web page"); HGENMENU hDefWebMenu = Menu_AddContactMenuItem(&mi); Menu_ConfigureItem(hDefWebMenu, MCI_OPT_EXECPARAM, DEF_PAGES_START - 1); CMenuItem mi2(&g_plugin); mi2.pszService = MS_PASTEIT_CONTACTMENU; mi2.root = hDefWebMenu; for (int i = 0; i < PasteToWeb::pages; ++i) { mi2.flags = CMIF_UNICODE | CMIF_UNMOVABLE; if (Options::instance->defWeb == i) mi2.flags |= CMIF_CHECKED; mi2.name.w = pasteToWebs[i]->GetName(); hWebPageMenus[i] = Menu_AddContactMenuItem(&mi2); Menu_ConfigureItem(hWebPageMenus[i], MCI_OPT_EXECPARAM, mi2.position = DEF_PAGES_START + i); } hPrebuildContactMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PrebuildContactMenu); } void DefWebPageChanged() { for (int i = 0; i < PasteToWeb::pages; i++) { int flags = (Options::instance->defWeb == i) ? CMIF_CHECKED : 0; Menu_ModifyItem(hWebPageMenus[i], nullptr, INVALID_HANDLE_VALUE, flags); } } static void InitTabsrmmButton() { BBButton btn = {}; btn.dwButtonID = 1; btn.pszModuleName = MODULENAME; btn.dwDefPos = 110; btn.hIcon = iconList[0].hIcolib; btn.bbbFlags = BBBF_ISARROWBUTTON | BBBF_ISIMBUTTON | BBBF_CANBEHIDDEN | BBBF_ISCHATBUTTON; btn.pwszTooltip = TranslateT("Paste It"); Srmm_AddButton(&btn, &g_plugin); if (hTabsrmmButtonPressed != nullptr) UnhookEvent(hTabsrmmButtonPressed); hTabsrmmButtonPressed = HookEvent(ME_MSG_BUTTONPRESSED, TabsrmmButtonPressed); } static int WindowEvent(WPARAM, MessageWindowEventData* lParam) { if (lParam->uType == MSG_WINDOW_EVT_OPEN) { char *szProto = Proto_GetBaseAccountName(lParam->hContact); if (szProto && (INT_PTR)szProto != CALLSERVICE_NOTFOUND) { if (db_get_b(lParam->hContact, szProto, "ChatRoom", 0)) { (*contactWindows)[lParam->hContact] = lParam->hwndInput; } } } else if (lParam->uType == MSG_WINDOW_EVT_CLOSE) { std::map::iterator it = contactWindows->find(lParam->hContact); if (it != contactWindows->end()) { contactWindows->erase(it); } } return 0; } static int ModulesLoaded(WPARAM, LPARAM) { InitMenuItems(); InitTabsrmmButton(); hWindowEvent = HookEvent(ME_MSG_WINDOWEVENT, (MIRANDAHOOK)WindowEvent); return 0; } int CMPlugin::Load() { g_plugin.registerIcon(LPGEN("Paste It"), iconList); NETLIBUSER nlu = {}; nlu.flags = NUF_UNICODE | NUF_OUTGOING | NUF_HTTPCONNS; nlu.szSettingsModule = MODULENAME; nlu.szDescriptiveName.w = TranslateT("Paste It"); g_hNetlibUser = Netlib_RegisterUser(&nlu); pasteToWebs[0] = new PasteToWeb1(); pasteToWebs[0]->pageIndex = 0; pasteToWebs[1] = new PasteToWeb2(); pasteToWebs[1]->pageIndex = 1; Options::instance = new Options(); pasteToWebs[0]->ConfigureSettings(); pasteToWebs[1]->ConfigureSettings(); Options::instance->Load(); hModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded); hOptionsInit = HookEvent(ME_OPT_INITIALISE, Options::InitOptions); hTabsrmmButtonPressed = nullptr; CreateServiceFunction(MS_PASTEIT_CONTACTMENU, ContactMenuService); contactWindows = new std::map(); return 0; } ///////////////////////////////////////////////////////////////////////////////////////// int CMPlugin::Unload() { UnhookEvent(hModulesLoaded); UnhookEvent(hPrebuildContactMenu); UnhookEvent(hOptionsInit); if (hWindowEvent != nullptr) UnhookEvent(hWindowEvent); Netlib_CloseHandle(g_hNetlibUser); if (hTabsrmmButtonPressed != nullptr) UnhookEvent(hTabsrmmButtonPressed); for (int i = 0; i < PasteToWeb::pages; ++i) if (pasteToWebs[i] != nullptr) { delete pasteToWebs[i]; pasteToWebs[i] = nullptr; } if (Options::instance != nullptr) { delete Options::instance; Options::instance = nullptr; } delete contactWindows; return 0; }