diff options
Diffstat (limited to 'plugins/New_GPG/src/messages.cpp')
| -rw-r--r-- | plugins/New_GPG/src/messages.cpp | 1576 |
1 files changed, 788 insertions, 788 deletions
diff --git a/plugins/New_GPG/src/messages.cpp b/plugins/New_GPG/src/messages.cpp index f79d09361c..c71281696d 100644 --- a/plugins/New_GPG/src/messages.cpp +++ b/plugins/New_GPG/src/messages.cpp @@ -1,788 +1,788 @@ -// Copyright © 2010-22 sss -// -// 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, write to the Free Software -// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -#include "stdafx.h" - -std::list<HANDLE> sent_msgs; - -struct RecvParams -{ - RecvParams(MCONTACT _p1, std::wstring _p2, const char *_p3, uint32_t _p4) : - hContact(_p1), - str(_p2), - msg(_p3), - timestamp(_p4) - {} - - MCONTACT hContact; - std::wstring str; - std::string msg; - uint32_t timestamp; -}; - -static void RecvMsgSvc_func(RecvParams *param) -{ - MCONTACT hContact = param->hContact; - std::string szScreenName(toUTF8(Clist_GetContactDisplayName(hContact))); - - // check for gpg related data - wstring::size_type s1 = param->str.find(L"-----BEGIN PGP MESSAGE-----"); - wstring::size_type s2 = param->str.find(L"-----END PGP MESSAGE-----"); - if (s2 != wstring::npos && s1 != wstring::npos) { //this is generic encrypted data block - if (!isContactSecured(hContact)) { - if (globals.debuglog) - globals.debuglog << "info: received encrypted message from: " + szScreenName + " with turned off encryption"; - if (MessageBox(nullptr, TranslateT("We received encrypted message from contact with encryption turned off.\nDo you want to turn on encryption for this contact?"), TranslateT("Warning"), MB_YESNO) == IDYES) { - if (!isContactHaveKey(hContact)) - ShowLoadPublicKeyDialog(hContact, true); - else { - g_plugin.setByte(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "GPGEncryption", 1); - setSrmmIcon(hContact); - } - - if (isContactHaveKey(hContact)) { - g_plugin.setByte(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "GPGEncryption", 1); - setSrmmIcon(hContact); - } - } - else if (MessageBox(nullptr, TranslateT("Do you want to try to decrypt encrypted message?"), TranslateT("Warning"), MB_YESNO) == IDNO) { - HistoryLog(hContact, param->msg.c_str(), param->timestamp); - delete param; - return; - } - } - else if (globals.debuglog) - globals.debuglog << "info: received encrypted message from: " + szScreenName; - boost::algorithm::erase_all(param->str, "\r"); - s2 += mir_wstrlen(L"-----END PGP MESSAGE-----"); - - ptrW ptszHomePath(g_plugin.getWStringA("szHomePath", L"")); - wstring encfile = toUTF16(get_random(10)); - wstring decfile = toUTF16(get_random(10)); - { - wstring path = wstring(ptszHomePath) + L"\\tmp\\" + encfile; - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(path, e); - } - - { - const int timeout = 5000, step = 100; - int count = 0; - - fstream f(path.c_str(), std::ios::out); - while (!f.is_open()) { - ::Sleep(step); - count += step; - if (count >= timeout) { - g_plugin.setByte(hContact, "GPGEncryption", 0); - setSrmmIcon(hContact); - globals.debuglog << "info: failed to create temporary file for decryption, disabling gpg for contact to avoid deadlock"; - delete param; - return; - } - f.open(path.c_str(), std::ios::out); - } - char *tmp = mir_u2a(param->str.substr(s1, s2 - s1).c_str()); - f << tmp; - mir_free(tmp); - f.close(); - } - - gpg_execution_params params; - params.addParam(L"--batch"); - { - CMStringA inkeyid = g_plugin.getMStringA(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "InKeyID"); - CMStringW pass; - if (!inkeyid.IsEmpty()) { - string dbsetting = "szKey_"; - dbsetting += inkeyid; - dbsetting += "_Password"; - pass = g_plugin.getMStringW(dbsetting.c_str()); - if (!pass.IsEmpty() && globals.debuglog) - globals.debuglog << "info: found password in database for key ID: " + string(inkeyid.c_str()) + ", trying to decrypt message from " + szScreenName + " with password"; - } - else { - pass = g_plugin.getMStringW("szKeyPassword"); - if (!pass.IsEmpty() && globals.debuglog) - globals.debuglog << "info: found password for all keys in database, trying to decrypt message from " + szScreenName + " with password"; - } - if (!pass.IsEmpty()) { - params.addParam(L"--passphrase"); - params.addParam(pass.c_str()); - } - else if (!globals.wszPassword.IsEmpty()) { - if (globals.debuglog) - globals.debuglog << "info: found password in memory, trying to decrypt message from " + szScreenName + " with password"; - params.addParam(L"--passphrase"); - params.addParam(globals.wszPassword.c_str()); - } - else if (globals.debuglog) - globals.debuglog << "info: passwords not found in database or memory, trying to decrypt message from " + szScreenName + " without password"; - } - - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(wstring(ptszHomePath) + L"\\tmp\\" + decfile, e); - } - - params.addParam(L"--output"); - params.addParam(std::wstring(ptszHomePath) + L"\\tmp\\" + decfile); - params.addParam(L"-d"); - params.addParam(L"-a"); - params.addParam(path); - - bool bRes = gpg_launcher(params); - if (!bRes || params.result == pxNotFound) { - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(path, e); - } - - SendErrorMessage(hContact); - HistoryLog(hContact, TranslateU("GPG cannot decrypt incoming message"), param->timestamp); - delete param; - return; - } - - // TODO: check gpg output for errors - globals._terminate = false; - - string out(params.out); - while (out.find("public key decryption failed: bad passphrase") != string::npos) { - if (globals.debuglog) - globals.debuglog << "info: failed to decrypt message from " + szScreenName + " password needed, trying to get one"; - if (globals._terminate) { - SendErrorMessage(hContact); - break; - } - { - // save inkey id - string::size_type s = out.find(" encrypted with "); - s = out.find(" ID ", s); - s += mir_strlen(" ID "); - g_plugin.setString(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "InKeyID", out.substr(s, out.find(",", s) - s).c_str()); - } - - CDlgKeyPasswordMsgBox(hContact).DoModal(); - - gpg_execution_params params2; - params2.aargv = params.aargv; - if (!globals.wszPassword.IsEmpty()) { - if (globals.debuglog) - globals.debuglog << "info: found password in memory, trying to decrypt message from " + szScreenName; - - params2.addParam(L"--passphrase"); - params2.addParam(globals.wszPassword.c_str()); - } - - bRes = gpg_launcher(params2); - if (!bRes || params2.result == pxNotFound) { - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(path, e); - } - - HistoryLog(hContact, TranslateU("GPG cannot decrypt incoming message"), param->timestamp); - SendErrorMessage(hContact); - delete param; - return; - } - } - - out.clear(); - bRes = gpg_launcher(params); - if (!bRes || params.result == pxNotFound) { - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(path, e); - } - - HistoryLog(hContact, TranslateU("GPG cannot decrypt incoming message"), param->timestamp); - SendErrorMessage(hContact); - delete param; - return; - } - - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(wstring(ptszHomePath) + L"\\tmp\\" + encfile, e); - } - - if (!boost::filesystem::exists(wstring(ptszHomePath) + L"\\tmp\\" + decfile)) { - if (globals.debuglog) - globals.debuglog << "info: Failed to decrypt GPG encrypted message."; - - string str1 = param->msg; - str1.insert(0, "\n"); - str1.insert(0, TranslateU("Received unencrypted message:")); - - HistoryLog(hContact, str1.c_str(), param->timestamp); - SendErrorMessage(hContact); - delete param; - return; - } - - std::string str; - - wstring tszDecPath = wstring(ptszHomePath) + L"\\tmp\\" + decfile; - - fstream f(tszDecPath.c_str(), std::ios::in | std::ios::ate | std::ios::binary); - if (f.is_open()) { - size_t size = f.tellg(); - char *tmp = new char[size + 1]; - f.seekg(0, std::ios::beg); - f.read(tmp, size); - tmp[size] = '\0'; - - str.append(tmp); - delete[] tmp; - f.close(); - if (!globals.debuglog) { - boost::system::error_code ec; - boost::filesystem::remove(tszDecPath, ec); - if (ec) { - //TODO: handle error - } - } - } - - if (str.empty()) { - if (globals.debuglog) - globals.debuglog << "info: Failed to decrypt GPG encrypted message."; - - string szMsg = param->msg; - szMsg.insert(0, TranslateU("Failed to decrypt GPG encrypted message.\nMessage body for manual decryption:\n")); - - HistoryLog(hContact, param->msg.c_str(), param->timestamp); - SendErrorMessage(hContact); - delete param; - return; - } - - fix_line_term(str); - if (g_plugin.bAppendTags) { - str.insert(0, toUTF8(globals.wszInopentag.c_str())); - str.append(toUTF8(globals.wszInclosetag.c_str())); - } - - HistoryLog(hContact, str.c_str(), param->timestamp); - delete param; - return; - } - } - - if (g_plugin.getByte(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "GPGEncryption")) - HistoryLog(hContact, param->msg.c_str(), param->timestamp, DBEF_READ); - else - HistoryLog(hContact, param->msg.c_str(), param->timestamp); - - delete param; -} - -INT_PTR RecvMsgSvc(WPARAM w, LPARAM l) -{ - CCSDATA *ccs = (CCSDATA*)l; - if (!ccs) - return Proto_ChainRecv(w, ccs); - - PROTORECVEVENT *pre = (PROTORECVEVENT*)(ccs->lParam); - if (!pre) - return Proto_ChainRecv(w, ccs); - - char *msg = pre->szMessage; - if (!msg) - return Proto_ChainRecv(w, ccs); - - if (db_mc_isMeta(ccs->hContact)) { - if (!strstr(msg, "-----BEGIN PGP MESSAGE-----")) - return Proto_ChainRecv(w, ccs); - else { - if (globals.debuglog) - globals.debuglog << "info: blocked pgp message to metacontact:" + toUTF8(Clist_GetContactDisplayName(ccs->hContact)); - return 0; - } - } - - wstring str = toUTF16(msg); - size_t s1, s2; - if (g_plugin.bAutoExchange && (str.find(L"-----PGP KEY RESPONSE-----") != wstring::npos)) { - if (globals.debuglog) - globals.debuglog << "info(autoexchange): parsing key response:" + toUTF8(Clist_GetContactDisplayName(ccs->hContact)); - s2 = str.find(L"-----END PGP PUBLIC KEY BLOCK-----"); - s1 = str.find(L"-----BEGIN PGP PUBLIC KEY BLOCK-----"); - if (s1 != wstring::npos && s2 != wstring::npos) { - if (globals.debuglog) - globals.debuglog << "info(autoexchange): found pubkey block:" + toUTF8(Clist_GetContactDisplayName(ccs->hContact)); - s2 += mir_wstrlen(L"-----END PGP PUBLIC KEY BLOCK-----"); - g_plugin.setWString(ccs->hContact, "GPGPubKey", str.substr(s1, s2 - s1).c_str()); - { - // gpg execute block - CMStringW tmp2(g_plugin.getMStringW("szHomePath")); - tmp2 += L"\\"; - tmp2 += get_random(5).c_str(); - tmp2 += L".asc"; - - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(tmp2.c_str(), e); - } - wfstream f(tmp2, std::ios::out); - { - const int timeout = 5000, step = 100; - int count = 0; - while (!f.is_open()) { - ::Sleep(step); - count += step; - if (count >= timeout) { - g_plugin.setByte(ccs->hContact, "GPGEncryption", 0); - setSrmmIcon(ccs->hContact); - globals.debuglog << "info: failed to create temporary file for decryption, disabling gpg for contact to avoid deadlock"; - return 1; - } - f.open(tmp2, std::ios::out); - } - } - f << g_plugin.getMStringW(ccs->hContact, "GPGPubKey").c_str(); - f.close(); - - gpg_execution_params params; - params.addParam(L"--batch"); - params.addParam(L"--import"); - params.addParam(tmp2.c_str()); - if (!gpg_launcher(params)) - return 1; - - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(tmp2.c_str(), e); - } - if (params.result == pxNotFound) - return 1; - - string output(params.out); - s1 = output.find("gpg: key ") + mir_strlen("gpg: key "); - s2 = output.find(":", s1); - g_plugin.setString(ccs->hContact, "KeyID", output.substr(s1, s2 - s1).c_str()); - s2 += 2; - s1 = output.find(RUS_QUOTE, s2); - if (s1 == string::npos) { - s1 = output.find("\"", s2); - s1 += 1; - } - else s1 += sizeof(RUS_QUOTE) - 1; - - if ((s2 = output.find("(", s1)) == string::npos) - s2 = output.find("<", s1); - else if (s2 > output.find("<", s1)) - s2 = output.find("<", s1); - - char *tmp = (char*)mir_alloc(output.substr(s1, s2 - s1 - 1).length() + 1); - mir_strcpy(tmp, output.substr(s1, s2 - s1 - 1).c_str()); - mir_utf8decode(tmp, nullptr); - g_plugin.setString(ccs->hContact, "KeyMainName", tmp); - mir_free(tmp); - if ((s1 = output.find(")", s2)) == string::npos) - s1 = output.find(">", s2); - else if (s1 > output.find(">", s2)) - s1 = output.find(">", s2); - s2++; - if (output[s1] == ')') { - tmp = (char*)mir_alloc(output.substr(s2, s1 - s2).length() + 1); - mir_strcpy(tmp, output.substr(s2, s1 - s2).c_str()); - mir_utf8decode(tmp, nullptr); - g_plugin.setString(ccs->hContact, "KeyComment", tmp); - mir_free(tmp); - s1 += 3; - s2 = output.find(">", s1); - tmp = (char*)mir_alloc(output.substr(s1, s2 - s1).length() + 1); - mir_strcpy(tmp, output.substr(s1, s2 - s1).c_str()); - mir_utf8decode(tmp, nullptr); - g_plugin.setString(ccs->hContact, "KeyMainEmail", tmp); - mir_free(tmp); - } - else { - tmp = (char*)mir_alloc(output.substr(s2, s1 - s2).length() + 1); - mir_strcpy(tmp, output.substr(s2, s1 - s2).c_str()); - mir_utf8decode(tmp, nullptr); - g_plugin.setString(ccs->hContact, "KeyMainEmail", output.substr(s2, s1 - s2).c_str()); - mir_free(tmp); - } - g_plugin.setByte(ccs->hContact, "GPGEncryption", 1); - g_plugin.setByte(ccs->hContact, "bAlwatsTrust", 1); - setSrmmIcon(ccs->hContact); - if (db_mc_isSub(ccs->hContact)) - setSrmmIcon(db_mc_getMeta(ccs->hContact)); - - HistoryLog(ccs->hContact, "PGP Encryption turned on by key autoexchange feature"); - } - return 1; - } - } - if (((s2 = str.find(L"-----END PGP PUBLIC KEY BLOCK-----")) == wstring::npos) || ((s1 = str.find(L"-----BEGIN PGP PUBLIC KEY BLOCK-----")) == wstring::npos)) { - s2 = str.find(L"-----END PGP PRIVATE KEY BLOCK-----"); - s1 = str.find(L"-----BEGIN PGP PRIVATE KEY BLOCK-----"); - } - if ((s2 != wstring::npos) && (s1 != wstring::npos)) { //this is public key - if (globals.debuglog) - globals.debuglog << "info: received key from: " + toUTF8(Clist_GetContactDisplayName(ccs->hContact)); - s1 = 0; - while ((s1 = str.find(L"\r", s1)) != wstring::npos) - str.erase(s1, 1); - if (((s2 = str.find(L"-----END PGP PUBLIC KEY BLOCK-----")) != wstring::npos) && ((s1 = str.find(L"-----BEGIN PGP PUBLIC KEY BLOCK-----")) != wstring::npos)) - s2 += mir_wstrlen(L"-----END PGP PUBLIC KEY BLOCK-----"); - else if (((s2 = str.find(L"-----BEGIN PGP PRIVATE KEY BLOCK-----")) != wstring::npos) && ((s1 = str.find(L"-----END PGP PRIVATE KEY BLOCK-----")) != wstring::npos)) - s2 += mir_wstrlen(L"-----END PGP PRIVATE KEY BLOCK-----"); - CDlgNewKey *d = new CDlgNewKey(ccs->hContact, str.substr(s1, s2 - s1)); - d->Show(); - HistoryLog(ccs->hContact, msg); - return 0; - } - - if (g_plugin.bAutoExchange && strstr(msg, "-----PGP KEY REQUEST-----") && globals.gpg_valid && globals.gpg_keyexist) { - if (globals.debuglog) - globals.debuglog << "info(autoexchange): received key request from: " + toUTF8(Clist_GetContactDisplayName(ccs->hContact)); - - CMStringA tmp(g_plugin.getMStringA("GPGPubKey")); - if (!tmp.IsEmpty()) { - int enc_state = g_plugin.getByte(ccs->hContact, "GPGEncryption"); - if (enc_state) - g_plugin.setByte(ccs->hContact, "GPGEncryption", 0); - - string str1 = "-----PGP KEY RESPONSE-----"; - str1.append(tmp); - ProtoChainSend(ccs->hContact, PSS_MESSAGE, 0, (LPARAM)str1.c_str()); - if (enc_state) - g_plugin.setByte(ccs->hContact, "GPGEncryption", 1); - } - return 0; - } - else if (!isContactHaveKey(ccs->hContact) && g_plugin.bAutoExchange && globals.gpg_valid && globals.gpg_keyexist) { - char *proto = Proto_GetBaseAccountName(ccs->hContact); - ptrA jid(db_get_utfa(ccs->hContact, proto, "jid", "")); - if (jid[0]) { - for (auto p : globals.Accounts) { - ptrA caps(p->getJabberInterface()->GetResourceFeatures(jid)); - if (caps) { - string str1; - for (int i = 0;; i++) { - str1.push_back(caps[i]); - if (caps[i] == '\0') - if (caps[i + 1] == '\0') - break; - } - - if (str1.find("GPG_Key_Auto_Exchange:0") != string::npos) { - ProtoChainSend(ccs->hContact, PSS_MESSAGE, 0, (LPARAM)"-----PGP KEY REQUEST-----"); - return 0; - } - } - } - } - } - - if (!strstr(msg, "-----BEGIN PGP MESSAGE-----")) - return Proto_ChainRecv(w, ccs); - - mir_forkThread<RecvParams>(RecvMsgSvc_func, new RecvParams(ccs->hContact, str, msg, pre->timestamp)); - return 0; -} - -void SendMsgSvc_func(MCONTACT hContact, char *msg, uint32_t flags) -{ - string str = msg; - if (g_plugin.bStripTags && g_plugin.bAppendTags) { - if (globals.debuglog) - globals.debuglog << "info: stripping tags in outgoing message, name: " + toUTF8(Clist_GetContactDisplayName(hContact)); - strip_tags(str); - } - -LBL_Relaunch: - wstring file = toUTF16(get_random(10)); - gpg_execution_params params; - { - CMStringA tmp(g_plugin.getMStringA(hContact, "KeyID")); - if (tmp.IsEmpty()) { - HistoryLog(hContact, "Failed to encrypt message with GPG (not found key for encryption in db", DBEF_SENT); - ProtoChainSend(hContact, PSS_MESSAGE, flags, (LPARAM)msg); - return; - } - - if (g_plugin.getByte(hContact, "bAlwaysTrust", 0)) { - params.addParam(L"--trust-model"); - params.addParam(L"always"); - } - params.addParam(L"--batch"); - params.addParam(L"--yes"); - params.addParam(L"-eatr"); - params.addParam(_A2T(tmp).get()); - } - - CMStringW path(g_plugin.getMStringW("szHomePath")); - path += L"\\tmp\\"; - path += file.c_str(); - params.addParam(path.c_str()); - - const int timeout = 5000, step = 100; - int count = 0; - { - fstream f(path.c_str(), std::ios::out); - while (!f.is_open()) { - ::Sleep(step); - count += step; - if (count >= timeout) { - g_plugin.setByte(hContact, "GPGEncryption", 0); //disable encryption - setSrmmIcon(hContact); - globals.debuglog << "info: failed to create temporary file for encryption, disabling encryption to avoid deadlock"; - break; - } - f.open(path.c_str(), std::ios::out); - } - if (count < timeout) { - f.write(str.c_str(), str.size()); - f.close(); - } - } - - if (!gpg_launcher(params)) { - ProtoChainSend(hContact, PSS_MESSAGE, flags, (LPARAM)msg); - return; - } - - if (params.result == pxNotFound) { - ProtoChainSend(hContact, PSS_MESSAGE, flags, (LPARAM)msg); - return; - } - - if (params.out.Find("There is no assurance this key belongs to the named user") != -1) { - if (IDYES != MessageBox(nullptr, TranslateT("We're trying to encrypt with untrusted key. Do you want to trust this key permanently?"), TranslateT("Warning"), MB_YESNO)) - return; - - g_plugin.setByte(hContact, "bAlwaysTrust", 1); - params.aargv.clear(); - goto LBL_Relaunch; - } - - if (params.out.Find("usage: ") != -1) { - MessageBox(nullptr, TranslateT("Something is wrong, GPG does not understand us, aborting encryption."), TranslateT("Warning"), MB_OK); - //mir_free(msg); - ProtoChainSend(hContact, PSS_MESSAGE, flags, (LPARAM)msg); - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(path.c_str(), e); - } - return; - } - - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(path.c_str(), e); - } - - path += L".asc"; - fstream f(path.c_str(), std::ios::in | std::ios::ate | std::ios::binary); - count = 0; - while (!f.is_open()) { - ::Sleep(step); - f.open(path.c_str(), std::ios::in | std::ios::ate | std::ios::binary); - count += step; - if (count >= timeout) { - g_plugin.setByte(hContact, "GPGEncryption", 0); //disable encryption - setSrmmIcon(hContact); - globals.debuglog << "info: gpg failed to encrypt message, disabling encryption to avoid deadlock"; - break; - } - } - - str.clear(); - if (f.is_open()) { - size_t size = f.tellg(); - char *tmp = new char[size + 1]; - f.seekg(0, std::ios::beg); - f.read(tmp, size); - tmp[size] = '\0'; - str.append(tmp); - delete[] tmp; - f.close(); - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(path.c_str(), e); - } - } - - if (str.empty()) { - HistoryLog(hContact, "Failed to encrypt message with GPG", DBEF_SENT); - if (globals.debuglog) - globals.debuglog << "info: Failed to encrypt message with GPG"; - ProtoChainSend(hContact, PSS_MESSAGE, flags, (LPARAM)msg); - return; - } - - string str_event = msg; - if (g_plugin.bAppendTags) { - str_event.insert(0, toUTF8(globals.wszOutopentag.c_str())); - str_event.append(toUTF8(globals.wszOutclosetag.c_str())); - } - - if (globals.debuglog) - globals.debuglog << "adding event to contact: " + toUTF8(Clist_GetContactDisplayName(hContact)) + " on send message."; - - fix_line_term(str); - sent_msgs.push_back((HANDLE)ProtoChainSend(hContact, PSS_MESSAGE, flags, (LPARAM)str.c_str())); -} - -INT_PTR SendMsgSvc(WPARAM w, LPARAM l) -{ - CCSDATA *ccs = (CCSDATA*)l; - if (!ccs) - return Proto_ChainSend(w, ccs); - - if (!ccs->lParam) - return Proto_ChainSend(w, ccs); - - std::string szScreenName(toUTF8(Clist_GetContactDisplayName(ccs->hContact))); - char *msg = (char*)ccs->lParam; - if (!msg) { - if (globals.debuglog) - globals.debuglog << "info: failed to get message data, name: " + szScreenName; - return Proto_ChainSend(w, ccs); - } - - if (strstr(msg, "-----BEGIN PGP MESSAGE-----")) { - if (globals.debuglog) - globals.debuglog << "info: encrypted message, let it go, name: " + szScreenName; - return Proto_ChainSend(w, ccs); - } - - if (globals.debuglog) - globals.debuglog << "info: contact have key, name: " + szScreenName; - - if (globals.debuglog && db_mc_isMeta(ccs->hContact)) - globals.debuglog << "info: protocol is metacontacts, name: " + szScreenName; - - if (!isContactSecured(ccs->hContact) || db_mc_isMeta(ccs->hContact)) { - if (globals.debuglog) - globals.debuglog << "info: contact not secured, name: " + szScreenName; - return Proto_ChainSend(w, ccs); - } - - ProtoBroadcastAsync(Proto_GetBaseAccountName(ccs->hContact), ccs->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)777); - return 777; -} - -int HookSendMsg(WPARAM w, LPARAM l) -{ - if (!l) - return 0; - - DBEVENTINFO *dbei = (DBEVENTINFO*)l; - if (dbei->eventType != EVENTTYPE_MESSAGE || (dbei->flags & DBEF_READ)) - return 0; - - MCONTACT hContact = (MCONTACT)w; - std::string szScreenName(toUTF8(Clist_GetContactDisplayName(hContact))); - - if (dbei->flags & DBEF_SENT) { - if (isContactSecured(hContact) && strstr((char*)dbei->pBlob, "-----BEGIN PGP MESSAGE-----")) //our service data, can be double added by metacontacts e.w.c. - { - if (globals.debuglog) - globals.debuglog << "info(send handler): block pgp message event, name: " + szScreenName; - return 1; - } - if (g_plugin.bAutoExchange && (strstr((char*)dbei->pBlob, "-----PGP KEY RESPONSE-----") || strstr((char*)dbei->pBlob, "-----PGP KEY REQUEST-----"))) ///do not show service data in history - { - if (globals.debuglog) - globals.debuglog << "info(send handler): block pgp key request/response event, name: " + szScreenName; - return 1; - } - } - - if (db_mc_isMeta(hContact)) - return 0; - - if (!isContactHaveKey(hContact)) { - if (globals.debuglog) - globals.debuglog << "info: contact have not key, name: " + szScreenName; - - if (g_plugin.bAutoExchange && !strstr((char*)dbei->pBlob, "-----PGP KEY REQUEST-----") && !strstr((char*)dbei->pBlob, "-----BEGIN PGP PUBLIC KEY BLOCK-----") && globals.gpg_valid) { - if (globals.debuglog) - globals.debuglog << "info: checking for autoexchange possibility, name: " + szScreenName; - - LPSTR proto = Proto_GetBaseAccountName(hContact); - ptrA jid(db_get_utfa(hContact, proto, "jid", "")); - if (jid[0]) { - if (globals.debuglog) - globals.debuglog << "info(autoexchange): protocol looks like jabber, name: " + szScreenName; - for (auto p : globals.Accounts) { - ptrA caps(p->getJabberInterface()->GetResourceFeatures(jid)); - if (caps) { - string str; - for (int i = 0;; i++) { - str.push_back(caps[i]); - if (caps[i] == '\0') - if (caps[i + 1] == '\0') - break; - } - - if (str.find("GPG_Key_Auto_Exchange:0") != string::npos) { - if (globals.debuglog) - globals.debuglog << "info(autoexchange, jabber): autoexchange capability found, sending key request, name: " + szScreenName; - ProtoChainSend(hContact, PSS_MESSAGE, 0, (LPARAM)"-----PGP KEY REQUEST-----"); - globals.hcontact_data[hContact].msgs_to_send.push_back((char*)dbei->pBlob); - mir_forkthread(send_encrypted_msgs_thread, (void*)hContact); - return 0; - } - } - } - } - } - else return 0; - } - - if (isContactSecured(hContact) && (dbei->flags & DBEF_SENT)) //aggressive outgoing events filtering - { - SendMsgSvc_func(hContact, (char*)dbei->pBlob, 0); - //TODO: handle errors somehow ... - if (g_plugin.bAppendTags) { - string str_event = (char*)dbei->pBlob; - //mir_free(dbei->pBlob); - str_event.insert(0, toUTF8(globals.wszOutopentag.c_str())); - str_event.append(toUTF8(globals.wszOutclosetag.c_str())); - dbei->pBlob = (uint8_t*)mir_strdup(str_event.c_str()); - dbei->cbBlob = (uint32_t)str_event.length() + 1; - } - - return 0; - } - - if (!isContactSecured(hContact)) { - if (globals.debuglog) - globals.debuglog << "event message: \"" + string((char*)dbei->pBlob) + "\" passed event filter, contact " + szScreenName + " is unsecured"; - return 0; - } - - if (!(dbei->flags & DBEF_SENT) && db_mc_isMeta((MCONTACT)w)) { - char tmp[29]; - strncpy(tmp, (char*)dbei->pBlob, 27); - tmp[28] = '\0'; - if (strstr(tmp, "-----BEGIN PGP MESSAGE-----")) { - if (globals.debuglog) - globals.debuglog << "info(send handler): block pgp message event, name: " + szScreenName; - return 1; - } - } - return 0; -} +// Copyright © 2010-23 sss
+//
+// 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, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#include "stdafx.h"
+
+std::list<HANDLE> sent_msgs;
+
+struct RecvParams
+{
+ RecvParams(MCONTACT _p1, std::wstring _p2, const char *_p3, uint32_t _p4) :
+ hContact(_p1),
+ str(_p2),
+ msg(_p3),
+ timestamp(_p4)
+ {}
+
+ MCONTACT hContact;
+ std::wstring str;
+ std::string msg;
+ uint32_t timestamp;
+};
+
+static void RecvMsgSvc_func(RecvParams *param)
+{
+ MCONTACT hContact = param->hContact;
+ std::string szScreenName(toUTF8(Clist_GetContactDisplayName(hContact)));
+
+ // check for gpg related data
+ wstring::size_type s1 = param->str.find(L"-----BEGIN PGP MESSAGE-----");
+ wstring::size_type s2 = param->str.find(L"-----END PGP MESSAGE-----");
+ if (s2 != wstring::npos && s1 != wstring::npos) { //this is generic encrypted data block
+ if (!isContactSecured(hContact)) {
+ if (globals.debuglog)
+ globals.debuglog << "info: received encrypted message from: " + szScreenName + " with turned off encryption";
+ if (MessageBox(nullptr, TranslateT("We received encrypted message from contact with encryption turned off.\nDo you want to turn on encryption for this contact?"), TranslateT("Warning"), MB_YESNO) == IDYES) {
+ if (!isContactHaveKey(hContact))
+ ShowLoadPublicKeyDialog(hContact, true);
+ else {
+ g_plugin.setByte(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "GPGEncryption", 1);
+ setSrmmIcon(hContact);
+ }
+
+ if (isContactHaveKey(hContact)) {
+ g_plugin.setByte(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "GPGEncryption", 1);
+ setSrmmIcon(hContact);
+ }
+ }
+ else if (MessageBox(nullptr, TranslateT("Do you want to try to decrypt encrypted message?"), TranslateT("Warning"), MB_YESNO) == IDNO) {
+ HistoryLog(hContact, param->msg.c_str(), param->timestamp);
+ delete param;
+ return;
+ }
+ }
+ else if (globals.debuglog)
+ globals.debuglog << "info: received encrypted message from: " + szScreenName;
+ boost::algorithm::erase_all(param->str, "\r");
+ s2 += mir_wstrlen(L"-----END PGP MESSAGE-----");
+
+ ptrW ptszHomePath(g_plugin.getWStringA("szHomePath", L""));
+ wstring encfile = toUTF16(get_random(10));
+ wstring decfile = toUTF16(get_random(10));
+ {
+ wstring path = wstring(ptszHomePath) + L"\\tmp\\" + encfile;
+ if (!globals.debuglog) {
+ boost::system::error_code e;
+ boost::filesystem::remove(path, e);
+ }
+
+ {
+ const int timeout = 5000, step = 100;
+ int count = 0;
+
+ fstream f(path.c_str(), std::ios::out);
+ while (!f.is_open()) {
+ ::Sleep(step);
+ count += step;
+ if (count >= timeout) {
+ g_plugin.setByte(hContact, "GPGEncryption", 0);
+ setSrmmIcon(hContact);
+ globals.debuglog << "info: failed to create temporary file for decryption, disabling gpg for contact to avoid deadlock";
+ delete param;
+ return;
+ }
+ f.open(path.c_str(), std::ios::out);
+ }
+ char *tmp = mir_u2a(param->str.substr(s1, s2 - s1).c_str());
+ f << tmp;
+ mir_free(tmp);
+ f.close();
+ }
+
+ gpg_execution_params params;
+ params.addParam(L"--batch");
+ {
+ CMStringA inkeyid = g_plugin.getMStringA(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "InKeyID");
+ CMStringW pass;
+ if (!inkeyid.IsEmpty()) {
+ string dbsetting = "szKey_";
+ dbsetting += inkeyid;
+ dbsetting += "_Password";
+ pass = g_plugin.getMStringW(dbsetting.c_str());
+ if (!pass.IsEmpty() && globals.debuglog)
+ globals.debuglog << "info: found password in database for key ID: " + string(inkeyid.c_str()) + ", trying to decrypt message from " + szScreenName + " with password";
+ }
+ else {
+ pass = g_plugin.getMStringW("szKeyPassword");
+ if (!pass.IsEmpty() && globals.debuglog)
+ globals.debuglog << "info: found password for all keys in database, trying to decrypt message from " + szScreenName + " with password";
+ }
+ if (!pass.IsEmpty()) {
+ params.addParam(L"--passphrase");
+ params.addParam(pass.c_str());
+ }
+ else if (!globals.wszPassword.IsEmpty()) {
+ if (globals.debuglog)
+ globals.debuglog << "info: found password in memory, trying to decrypt message from " + szScreenName + " with password";
+ params.addParam(L"--passphrase");
+ params.addParam(globals.wszPassword.c_str());
+ }
+ else if (globals.debuglog)
+ globals.debuglog << "info: passwords not found in database or memory, trying to decrypt message from " + szScreenName + " without password";
+ }
+
+ if (!globals.debuglog) {
+ boost::system::error_code e;
+ boost::filesystem::remove(wstring(ptszHomePath) + L"\\tmp\\" + decfile, e);
+ }
+
+ params.addParam(L"--output");
+ params.addParam(std::wstring(ptszHomePath) + L"\\tmp\\" + decfile);
+ params.addParam(L"-d");
+ params.addParam(L"-a");
+ params.addParam(path);
+
+ bool bRes = gpg_launcher(params);
+ if (!bRes || params.result == pxNotFound) {
+ if (!globals.debuglog) {
+ boost::system::error_code e;
+ boost::filesystem::remove(path, e);
+ }
+
+ SendErrorMessage(hContact);
+ HistoryLog(hContact, TranslateU("GPG cannot decrypt incoming message"), param->timestamp);
+ delete param;
+ return;
+ }
+
+ // TODO: check gpg output for errors
+ globals._terminate = false;
+
+ string out(params.out);
+ while (out.find("public key decryption failed: bad passphrase") != string::npos) {
+ if (globals.debuglog)
+ globals.debuglog << "info: failed to decrypt message from " + szScreenName + " password needed, trying to get one";
+ if (globals._terminate) {
+ SendErrorMessage(hContact);
+ break;
+ }
+ {
+ // save inkey id
+ string::size_type s = out.find(" encrypted with ");
+ s = out.find(" ID ", s);
+ s += mir_strlen(" ID ");
+ g_plugin.setString(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "InKeyID", out.substr(s, out.find(",", s) - s).c_str());
+ }
+
+ CDlgKeyPasswordMsgBox(hContact).DoModal();
+
+ gpg_execution_params params2;
+ params2.aargv = params.aargv;
+ if (!globals.wszPassword.IsEmpty()) {
+ if (globals.debuglog)
+ globals.debuglog << "info: found password in memory, trying to decrypt message from " + szScreenName;
+
+ params2.addParam(L"--passphrase");
+ params2.addParam(globals.wszPassword.c_str());
+ }
+
+ bRes = gpg_launcher(params2);
+ if (!bRes || params2.result == pxNotFound) {
+ if (!globals.debuglog) {
+ boost::system::error_code e;
+ boost::filesystem::remove(path, e);
+ }
+
+ HistoryLog(hContact, TranslateU("GPG cannot decrypt incoming message"), param->timestamp);
+ SendErrorMessage(hContact);
+ delete param;
+ return;
+ }
+ }
+
+ out.clear();
+ bRes = gpg_launcher(params);
+ if (!bRes || params.result == pxNotFound) {
+ if (!globals.debuglog) {
+ boost::system::error_code e;
+ boost::filesystem::remove(path, e);
+ }
+
+ HistoryLog(hContact, TranslateU("GPG cannot decrypt incoming message"), param->timestamp);
+ SendErrorMessage(hContact);
+ delete param;
+ return;
+ }
+
+ if (!globals.debuglog) {
+ boost::system::error_code e;
+ boost::filesystem::remove(wstring(ptszHomePath) + L"\\tmp\\" + encfile, e);
+ }
+
+ if (!boost::filesystem::exists(wstring(ptszHomePath) + L"\\tmp\\" + decfile)) {
+ if (globals.debuglog)
+ globals.debuglog << "info: Failed to decrypt GPG encrypted message.";
+
+ string str1 = param->msg;
+ str1.insert(0, "\n");
+ str1.insert(0, TranslateU("Received unencrypted message:"));
+
+ HistoryLog(hContact, str1.c_str(), param->timestamp);
+ SendErrorMessage(hContact);
+ delete param;
+ return;
+ }
+
+ std::string str;
+
+ wstring tszDecPath = wstring(ptszHomePath) + L"\\tmp\\" + decfile;
+
+ fstream f(tszDecPath.c_str(), std::ios::in | std::ios::ate | std::ios::binary);
+ if (f.is_open()) {
+ size_t size = f.tellg();
+ char *tmp = new char[size + 1];
+ f.seekg(0, std::ios::beg);
+ f.read(tmp, size);
+ tmp[size] = '\0';
+
+ str.append(tmp);
+ delete[] tmp;
+ f.close();
+ if (!globals.debuglog) {
+ boost::system::error_code ec;
+ boost::filesystem::remove(tszDecPath, ec);
+ if (ec) {
+ //TODO: handle error
+ }
+ }
+ }
+
+ if (str.empty()) {
+ if (globals.debuglog)
+ globals.debuglog << "info: Failed to decrypt GPG encrypted message.";
+
+ string szMsg = param->msg;
+ szMsg.insert(0, TranslateU("Failed to decrypt GPG encrypted message.\nMessage body for manual decryption:\n"));
+
+ HistoryLog(hContact, param->msg.c_str(), param->timestamp);
+ SendErrorMessage(hContact);
+ delete param;
+ return;
+ }
+
+ fix_line_term(str);
+ if (g_plugin.bAppendTags) {
+ str.insert(0, toUTF8(globals.wszInopentag.c_str()));
+ str.append(toUTF8(globals.wszInclosetag.c_str()));
+ }
+
+ HistoryLog(hContact, str.c_str(), param->timestamp);
+ delete param;
+ return;
+ }
+ }
+
+ if (g_plugin.getByte(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "GPGEncryption"))
+ HistoryLog(hContact, param->msg.c_str(), param->timestamp, DBEF_READ);
+ else
+ HistoryLog(hContact, param->msg.c_str(), param->timestamp);
+
+ delete param;
+}
+
+INT_PTR RecvMsgSvc(WPARAM w, LPARAM l)
+{
+ CCSDATA *ccs = (CCSDATA*)l;
+ if (!ccs)
+ return Proto_ChainRecv(w, ccs);
+
+ PROTORECVEVENT *pre = (PROTORECVEVENT*)(ccs->lParam);
+ if (!pre)
+ return Proto_ChainRecv(w, ccs);
+
+ char *msg = pre->szMessage;
+ if (!msg)
+ return Proto_ChainRecv(w, ccs);
+
+ if (db_mc_isMeta(ccs->hContact)) {
+ if (!strstr(msg, "-----BEGIN PGP MESSAGE-----"))
+ return Proto_ChainRecv(w, ccs);
+ else {
+ if (globals.debuglog)
+ globals.debuglog << "info: blocked pgp message to metacontact:" + toUTF8(Clist_GetContactDisplayName(ccs->hContact));
+ return 0;
+ }
+ }
+
+ wstring str = toUTF16(msg);
+ size_t s1, s2;
+ if (g_plugin.bAutoExchange && (str.find(L"-----PGP KEY RESPONSE-----") != wstring::npos)) {
+ if (globals.debuglog)
+ globals.debuglog << "info(autoexchange): parsing key response:" + toUTF8(Clist_GetContactDisplayName(ccs->hContact));
+ s2 = str.find(L"-----END PGP PUBLIC KEY BLOCK-----");
+ s1 = str.find(L"-----BEGIN PGP PUBLIC KEY BLOCK-----");
+ if (s1 != wstring::npos && s2 != wstring::npos) {
+ if (globals.debuglog)
+ globals.debuglog << "info(autoexchange): found pubkey block:" + toUTF8(Clist_GetContactDisplayName(ccs->hContact));
+ s2 += mir_wstrlen(L"-----END PGP PUBLIC KEY BLOCK-----");
+ g_plugin.setWString(ccs->hContact, "GPGPubKey", str.substr(s1, s2 - s1).c_str());
+ {
+ // gpg execute block
+ CMStringW tmp2(g_plugin.getMStringW("szHomePath"));
+ tmp2 += L"\\";
+ tmp2 += get_random(5).c_str();
+ tmp2 += L".asc";
+
+ if (!globals.debuglog) {
+ boost::system::error_code e;
+ boost::filesystem::remove(tmp2.c_str(), e);
+ }
+ wfstream f(tmp2, std::ios::out);
+ {
+ const int timeout = 5000, step = 100;
+ int count = 0;
+ while (!f.is_open()) {
+ ::Sleep(step);
+ count += step;
+ if (count >= timeout) {
+ g_plugin.setByte(ccs->hContact, "GPGEncryption", 0);
+ setSrmmIcon(ccs->hContact);
+ globals.debuglog << "info: failed to create temporary file for decryption, disabling gpg for contact to avoid deadlock";
+ return 1;
+ }
+ f.open(tmp2, std::ios::out);
+ }
+ }
+ f << g_plugin.getMStringW(ccs->hContact, "GPGPubKey").c_str();
+ f.close();
+
+ gpg_execution_params params;
+ params.addParam(L"--batch");
+ params.addParam(L"--import");
+ params.addParam(tmp2.c_str());
+ if (!gpg_launcher(params))
+ return 1;
+
+ if (!globals.debuglog) {
+ boost::system::error_code e;
+ boost::filesystem::remove(tmp2.c_str(), e);
+ }
+ if (params.result == pxNotFound)
+ return 1;
+
+ string output(params.out);
+ s1 = output.find("gpg: key ") + mir_strlen("gpg: key ");
+ s2 = output.find(":", s1);
+ g_plugin.setString(ccs->hContact, "KeyID", output.substr(s1, s2 - s1).c_str());
+ s2 += 2;
+ s1 = output.find(RUS_QUOTE, s2);
+ if (s1 == string::npos) {
+ s1 = output.find("\"", s2);
+ s1 += 1;
+ }
+ else s1 += sizeof(RUS_QUOTE) - 1;
+
+ if ((s2 = output.find("(", s1)) == string::npos)
+ s2 = output.find("<", s1);
+ else if (s2 > output.find("<", s1))
+ s2 = output.find("<", s1);
+
+ char *tmp = (char*)mir_alloc(output.substr(s1, s2 - s1 - 1).length() + 1);
+ mir_strcpy(tmp, output.substr(s1, s2 - s1 - 1).c_str());
+ mir_utf8decode(tmp, nullptr);
+ g_plugin.setString(ccs->hContact, "KeyMainName", tmp);
+ mir_free(tmp);
+ if ((s1 = output.find(")", s2)) == string::npos)
+ s1 = output.find(">", s2);
+ else if (s1 > output.find(">", s2))
+ s1 = output.find(">", s2);
+ s2++;
+ if (output[s1] == ')') {
+ tmp = (char*)mir_alloc(output.substr(s2, s1 - s2).length() + 1);
+ mir_strcpy(tmp, output.substr(s2, s1 - s2).c_str());
+ mir_utf8decode(tmp, nullptr);
+ g_plugin.setString(ccs->hContact, "KeyComment", tmp);
+ mir_free(tmp);
+ s1 += 3;
+ s2 = output.find(">", s1);
+ tmp = (char*)mir_alloc(output.substr(s1, s2 - s1).length() + 1);
+ mir_strcpy(tmp, output.substr(s1, s2 - s1).c_str());
+ mir_utf8decode(tmp, nullptr);
+ g_plugin.setString(ccs->hContact, "KeyMainEmail", tmp);
+ mir_free(tmp);
+ }
+ else {
+ tmp = (char*)mir_alloc(output.substr(s2, s1 - s2).length() + 1);
+ mir_strcpy(tmp, output.substr(s2, s1 - s2).c_str());
+ mir_utf8decode(tmp, nullptr);
+ g_plugin.setString(ccs->hContact, "KeyMainEmail", output.substr(s2, s1 - s2).c_str());
+ mir_free(tmp);
+ }
+ g_plugin.setByte(ccs->hContact, "GPGEncryption", 1);
+ g_plugin.setByte(ccs->hContact, "bAlwatsTrust", 1);
+ setSrmmIcon(ccs->hContact);
+ if (db_mc_isSub(ccs->hContact))
+ setSrmmIcon(db_mc_getMeta(ccs->hContact));
+
+ HistoryLog(ccs->hContact, "PGP Encryption turned on by key autoexchange feature");
+ }
+ return 1;
+ }
+ }
+ if (((s2 = str.find(L"-----END PGP PUBLIC KEY BLOCK-----")) == wstring::npos) || ((s1 = str.find(L"-----BEGIN PGP PUBLIC KEY BLOCK-----")) == wstring::npos)) {
+ s2 = str.find(L"-----END PGP PRIVATE KEY BLOCK-----");
+ s1 = str.find(L"-----BEGIN PGP PRIVATE KEY BLOCK-----");
+ }
+ if ((s2 != wstring::npos) && (s1 != wstring::npos)) { //this is public key
+ if (globals.debuglog)
+ globals.debuglog << "info: received key from: " + toUTF8(Clist_GetContactDisplayName(ccs->hContact));
+ s1 = 0;
+ while ((s1 = str.find(L"\r", s1)) != wstring::npos)
+ str.erase(s1, 1);
+ if (((s2 = str.find(L"-----END PGP PUBLIC KEY BLOCK-----")) != wstring::npos) && ((s1 = str.find(L"-----BEGIN PGP PUBLIC KEY BLOCK-----")) != wstring::npos))
+ s2 += mir_wstrlen(L"-----END PGP PUBLIC KEY BLOCK-----");
+ else if (((s2 = str.find(L"-----BEGIN PGP PRIVATE KEY BLOCK-----")) != wstring::npos) && ((s1 = str.find(L"-----END PGP PRIVATE KEY BLOCK-----")) != wstring::npos))
+ s2 += mir_wstrlen(L"-----END PGP PRIVATE KEY BLOCK-----");
+ CDlgNewKey *d = new CDlgNewKey(ccs->hContact, str.substr(s1, s2 - s1));
+ d->Show();
+ HistoryLog(ccs->hContact, msg);
+ return 0;
+ }
+
+ if (g_plugin.bAutoExchange && strstr(msg, "-----PGP KEY REQUEST-----") && globals.gpg_valid && globals.gpg_keyexist) {
+ if (globals.debuglog)
+ globals.debuglog << "info(autoexchange): received key request from: " + toUTF8(Clist_GetContactDisplayName(ccs->hContact));
+
+ CMStringA tmp(g_plugin.getMStringA("GPGPubKey"));
+ if (!tmp.IsEmpty()) {
+ int enc_state = g_plugin.getByte(ccs->hContact, "GPGEncryption");
+ if (enc_state)
+ g_plugin.setByte(ccs->hContact, "GPGEncryption", 0);
+
+ string str1 = "-----PGP KEY RESPONSE-----";
+ str1.append(tmp);
+ ProtoChainSend(ccs->hContact, PSS_MESSAGE, 0, (LPARAM)str1.c_str());
+ if (enc_state)
+ g_plugin.setByte(ccs->hContact, "GPGEncryption", 1);
+ }
+ return 0;
+ }
+ else if (!isContactHaveKey(ccs->hContact) && g_plugin.bAutoExchange && globals.gpg_valid && globals.gpg_keyexist) {
+ char *proto = Proto_GetBaseAccountName(ccs->hContact);
+ ptrA jid(db_get_utfa(ccs->hContact, proto, "jid", ""));
+ if (jid[0]) {
+ for (auto p : globals.Accounts) {
+ ptrA caps(p->getJabberInterface()->GetResourceFeatures(jid));
+ if (caps) {
+ string str1;
+ for (int i = 0;; i++) {
+ str1.push_back(caps[i]);
+ if (caps[i] == '\0')
+ if (caps[i + 1] == '\0')
+ break;
+ }
+
+ if (str1.find("GPG_Key_Auto_Exchange:0") != string::npos) {
+ ProtoChainSend(ccs->hContact, PSS_MESSAGE, 0, (LPARAM)"-----PGP KEY REQUEST-----");
+ return 0;
+ }
+ }
+ }
+ }
+ }
+
+ if (!strstr(msg, "-----BEGIN PGP MESSAGE-----"))
+ return Proto_ChainRecv(w, ccs);
+
+ mir_forkThread<RecvParams>(RecvMsgSvc_func, new RecvParams(ccs->hContact, str, msg, pre->timestamp));
+ return 0;
+}
+
+void SendMsgSvc_func(MCONTACT hContact, char *msg, uint32_t flags)
+{
+ string str = msg;
+ if (g_plugin.bStripTags && g_plugin.bAppendTags) {
+ if (globals.debuglog)
+ globals.debuglog << "info: stripping tags in outgoing message, name: " + toUTF8(Clist_GetContactDisplayName(hContact));
+ strip_tags(str);
+ }
+
+LBL_Relaunch:
+ wstring file = toUTF16(get_random(10));
+ gpg_execution_params params;
+ {
+ CMStringA tmp(g_plugin.getMStringA(hContact, "KeyID"));
+ if (tmp.IsEmpty()) {
+ HistoryLog(hContact, "Failed to encrypt message with GPG (not found key for encryption in db", DBEF_SENT);
+ ProtoChainSend(hContact, PSS_MESSAGE, flags, (LPARAM)msg);
+ return;
+ }
+
+ if (g_plugin.getByte(hContact, "bAlwaysTrust", 0)) {
+ params.addParam(L"--trust-model");
+ params.addParam(L"always");
+ }
+ params.addParam(L"--batch");
+ params.addParam(L"--yes");
+ params.addParam(L"-eatr");
+ params.addParam(_A2T(tmp).get());
+ }
+
+ CMStringW path(g_plugin.getMStringW("szHomePath"));
+ path += L"\\tmp\\";
+ path += file.c_str();
+ params.addParam(path.c_str());
+
+ const int timeout = 5000, step = 100;
+ int count = 0;
+ {
+ fstream f(path.c_str(), std::ios::out);
+ while (!f.is_open()) {
+ ::Sleep(step);
+ count += step;
+ if (count >= timeout) {
+ g_plugin.setByte(hContact, "GPGEncryption", 0); //disable encryption
+ setSrmmIcon(hContact);
+ globals.debuglog << "info: failed to create temporary file for encryption, disabling encryption to avoid deadlock";
+ break;
+ }
+ f.open(path.c_str(), std::ios::out);
+ }
+ if (count < timeout) {
+ f.write(str.c_str(), str.size());
+ f.close();
+ }
+ }
+
+ if (!gpg_launcher(params)) {
+ ProtoChainSend(hContact, PSS_MESSAGE, flags, (LPARAM)msg);
+ return;
+ }
+
+ if (params.result == pxNotFound) {
+ ProtoChainSend(hContact, PSS_MESSAGE, flags, (LPARAM)msg);
+ return;
+ }
+
+ if (params.out.Find("There is no assurance this key belongs to the named user") != -1) {
+ if (IDYES != MessageBox(nullptr, TranslateT("We're trying to encrypt with untrusted key. Do you want to trust this key permanently?"), TranslateT("Warning"), MB_YESNO))
+ return;
+
+ g_plugin.setByte(hContact, "bAlwaysTrust", 1);
+ params.aargv.clear();
+ goto LBL_Relaunch;
+ }
+
+ if (params.out.Find("usage: ") != -1) {
+ MessageBox(nullptr, TranslateT("Something is wrong, GPG does not understand us, aborting encryption."), TranslateT("Warning"), MB_OK);
+ //mir_free(msg);
+ ProtoChainSend(hContact, PSS_MESSAGE, flags, (LPARAM)msg);
+ if (!globals.debuglog) {
+ boost::system::error_code e;
+ boost::filesystem::remove(path.c_str(), e);
+ }
+ return;
+ }
+
+ if (!globals.debuglog) {
+ boost::system::error_code e;
+ boost::filesystem::remove(path.c_str(), e);
+ }
+
+ path += L".asc";
+ fstream f(path.c_str(), std::ios::in | std::ios::ate | std::ios::binary);
+ count = 0;
+ while (!f.is_open()) {
+ ::Sleep(step);
+ f.open(path.c_str(), std::ios::in | std::ios::ate | std::ios::binary);
+ count += step;
+ if (count >= timeout) {
+ g_plugin.setByte(hContact, "GPGEncryption", 0); //disable encryption
+ setSrmmIcon(hContact);
+ globals.debuglog << "info: gpg failed to encrypt message, disabling encryption to avoid deadlock";
+ break;
+ }
+ }
+
+ str.clear();
+ if (f.is_open()) {
+ size_t size = f.tellg();
+ char *tmp = new char[size + 1];
+ f.seekg(0, std::ios::beg);
+ f.read(tmp, size);
+ tmp[size] = '\0';
+ str.append(tmp);
+ delete[] tmp;
+ f.close();
+ if (!globals.debuglog) {
+ boost::system::error_code e;
+ boost::filesystem::remove(path.c_str(), e);
+ }
+ }
+
+ if (str.empty()) {
+ HistoryLog(hContact, "Failed to encrypt message with GPG", DBEF_SENT);
+ if (globals.debuglog)
+ globals.debuglog << "info: Failed to encrypt message with GPG";
+ ProtoChainSend(hContact, PSS_MESSAGE, flags, (LPARAM)msg);
+ return;
+ }
+
+ string str_event = msg;
+ if (g_plugin.bAppendTags) {
+ str_event.insert(0, toUTF8(globals.wszOutopentag.c_str()));
+ str_event.append(toUTF8(globals.wszOutclosetag.c_str()));
+ }
+
+ if (globals.debuglog)
+ globals.debuglog << "adding event to contact: " + toUTF8(Clist_GetContactDisplayName(hContact)) + " on send message.";
+
+ fix_line_term(str);
+ sent_msgs.push_back((HANDLE)ProtoChainSend(hContact, PSS_MESSAGE, flags, (LPARAM)str.c_str()));
+}
+
+INT_PTR SendMsgSvc(WPARAM w, LPARAM l)
+{
+ CCSDATA *ccs = (CCSDATA*)l;
+ if (!ccs)
+ return Proto_ChainSend(w, ccs);
+
+ if (!ccs->lParam)
+ return Proto_ChainSend(w, ccs);
+
+ std::string szScreenName(toUTF8(Clist_GetContactDisplayName(ccs->hContact)));
+ char *msg = (char*)ccs->lParam;
+ if (!msg) {
+ if (globals.debuglog)
+ globals.debuglog << "info: failed to get message data, name: " + szScreenName;
+ return Proto_ChainSend(w, ccs);
+ }
+
+ if (strstr(msg, "-----BEGIN PGP MESSAGE-----")) {
+ if (globals.debuglog)
+ globals.debuglog << "info: encrypted message, let it go, name: " + szScreenName;
+ return Proto_ChainSend(w, ccs);
+ }
+
+ if (globals.debuglog)
+ globals.debuglog << "info: contact have key, name: " + szScreenName;
+
+ if (globals.debuglog && db_mc_isMeta(ccs->hContact))
+ globals.debuglog << "info: protocol is metacontacts, name: " + szScreenName;
+
+ if (!isContactSecured(ccs->hContact) || db_mc_isMeta(ccs->hContact)) {
+ if (globals.debuglog)
+ globals.debuglog << "info: contact not secured, name: " + szScreenName;
+ return Proto_ChainSend(w, ccs);
+ }
+
+ ProtoBroadcastAsync(Proto_GetBaseAccountName(ccs->hContact), ccs->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)777);
+ return 777;
+}
+
+int HookSendMsg(WPARAM w, LPARAM l)
+{
+ if (!l)
+ return 0;
+
+ DBEVENTINFO *dbei = (DBEVENTINFO*)l;
+ if (dbei->eventType != EVENTTYPE_MESSAGE || (dbei->flags & DBEF_READ))
+ return 0;
+
+ MCONTACT hContact = (MCONTACT)w;
+ std::string szScreenName(toUTF8(Clist_GetContactDisplayName(hContact)));
+
+ if (dbei->flags & DBEF_SENT) {
+ if (isContactSecured(hContact) && strstr((char*)dbei->pBlob, "-----BEGIN PGP MESSAGE-----")) //our service data, can be double added by metacontacts e.w.c.
+ {
+ if (globals.debuglog)
+ globals.debuglog << "info(send handler): block pgp message event, name: " + szScreenName;
+ return 1;
+ }
+ if (g_plugin.bAutoExchange && (strstr((char*)dbei->pBlob, "-----PGP KEY RESPONSE-----") || strstr((char*)dbei->pBlob, "-----PGP KEY REQUEST-----"))) ///do not show service data in history
+ {
+ if (globals.debuglog)
+ globals.debuglog << "info(send handler): block pgp key request/response event, name: " + szScreenName;
+ return 1;
+ }
+ }
+
+ if (db_mc_isMeta(hContact))
+ return 0;
+
+ if (!isContactHaveKey(hContact)) {
+ if (globals.debuglog)
+ globals.debuglog << "info: contact have not key, name: " + szScreenName;
+
+ if (g_plugin.bAutoExchange && !strstr((char*)dbei->pBlob, "-----PGP KEY REQUEST-----") && !strstr((char*)dbei->pBlob, "-----BEGIN PGP PUBLIC KEY BLOCK-----") && globals.gpg_valid) {
+ if (globals.debuglog)
+ globals.debuglog << "info: checking for autoexchange possibility, name: " + szScreenName;
+
+ LPSTR proto = Proto_GetBaseAccountName(hContact);
+ ptrA jid(db_get_utfa(hContact, proto, "jid", ""));
+ if (jid[0]) {
+ if (globals.debuglog)
+ globals.debuglog << "info(autoexchange): protocol looks like jabber, name: " + szScreenName;
+ for (auto p : globals.Accounts) {
+ ptrA caps(p->getJabberInterface()->GetResourceFeatures(jid));
+ if (caps) {
+ string str;
+ for (int i = 0;; i++) {
+ str.push_back(caps[i]);
+ if (caps[i] == '\0')
+ if (caps[i + 1] == '\0')
+ break;
+ }
+
+ if (str.find("GPG_Key_Auto_Exchange:0") != string::npos) {
+ if (globals.debuglog)
+ globals.debuglog << "info(autoexchange, jabber): autoexchange capability found, sending key request, name: " + szScreenName;
+ ProtoChainSend(hContact, PSS_MESSAGE, 0, (LPARAM)"-----PGP KEY REQUEST-----");
+ globals.hcontact_data[hContact].msgs_to_send.push_back((char*)dbei->pBlob);
+ mir_forkthread(send_encrypted_msgs_thread, (void*)hContact);
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ else return 0;
+ }
+
+ if (isContactSecured(hContact) && (dbei->flags & DBEF_SENT)) //aggressive outgoing events filtering
+ {
+ SendMsgSvc_func(hContact, (char*)dbei->pBlob, 0);
+ //TODO: handle errors somehow ...
+ if (g_plugin.bAppendTags) {
+ string str_event = (char*)dbei->pBlob;
+ //mir_free(dbei->pBlob);
+ str_event.insert(0, toUTF8(globals.wszOutopentag.c_str()));
+ str_event.append(toUTF8(globals.wszOutclosetag.c_str()));
+ dbei->pBlob = (uint8_t*)mir_strdup(str_event.c_str());
+ dbei->cbBlob = (uint32_t)str_event.length() + 1;
+ }
+
+ return 0;
+ }
+
+ if (!isContactSecured(hContact)) {
+ if (globals.debuglog)
+ globals.debuglog << "event message: \"" + string((char*)dbei->pBlob) + "\" passed event filter, contact " + szScreenName + " is unsecured";
+ return 0;
+ }
+
+ if (!(dbei->flags & DBEF_SENT) && db_mc_isMeta((MCONTACT)w)) {
+ char tmp[29];
+ strncpy(tmp, (char*)dbei->pBlob, 27);
+ tmp[28] = '\0';
+ if (strstr(tmp, "-----BEGIN PGP MESSAGE-----")) {
+ if (globals.debuglog)
+ globals.debuglog << "info(send handler): block pgp message event, name: " + szScreenName;
+ return 1;
+ }
+ }
+ return 0;
+}
|
