// Copyright © 2010 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 "commonheaders.h" wstring new_key; HANDLE new_key_hcnt = NULL; HANDLE new_key_hcnt_mutex = NULL; bool _terminate = false; BOOL isProtoMetaContacts(HANDLE hContact); int RecvMsgSvc(WPARAM w, LPARAM l) { CCSDATA *ccs = (CCSDATA*)l; if (!ccs) return CallService(MS_PROTO_CHAINRECV, w, l); PROTORECVEVENT *pre = (PROTORECVEVENT*)(ccs->lParam); if (!pre) return CallService(MS_PROTO_CHAINRECV, w, l); char *msg = pre->szMessage; if (!msg) return CallService(MS_PROTO_CHAINRECV, w, l); HANDLE hContact = ccs->hContact; if(isProtoMetaContacts(hContact)) hContact = metaGetMostOnline(hContact); { //check for gpg related data wchar_t *tmp = mir_utf8decodeW(msg); if(!tmp) tmp = mir_a2t(msg); wstring str = tmp; mir_free(tmp); wstring::size_type s1 = wstring::npos, s2 = wstring::npos; if((str.find(_T("-----END PGP PUBLIC KEY BLOCK-----")) != wstring::npos) && (str.find(_T("-----BEGIN PGP PUBLIC KEY BLOCK-----")) != wstring::npos)) { s2 = str.find(_T("-----END PGP PUBLIC KEY BLOCK-----")); s1 = str.find(_T("-----BEGIN PGP PUBLIC KEY BLOCK-----")); } else if((str.find(_T("-----BEGIN PGP PRIVATE KEY BLOCK-----")) != wstring::npos) && (str.find(_T("-----END PGP PRIVATE KEY BLOCK-----")) != wstring::npos)) { s2 = str.find(_T("-----END PGP PRIVATE KEY BLOCK-----")); s1 = str.find(_T("-----BEGIN PGP PRIVATE KEY BLOCK-----")); } if((s2 != wstring::npos) && (s1 != wstring::npos)) { //this is public key debuglog<<"info: "<<"received key from: "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)<<"\n"; void ShowNewKeyDialog(); s1 = 0; while((s1 = str.find(_T("\r"), s1)) != wstring::npos) { str.erase(s1, 1); } if((str.find(_T("-----END PGP PUBLIC KEY BLOCK-----")) != wstring::npos) && (str.find(_T("-----BEGIN PGP PUBLIC KEY BLOCK-----")) != wstring::npos)) { s2 = str.find(_T("-----END PGP PUBLIC KEY BLOCK-----")); s1 = str.find(_T("-----BEGIN PGP PUBLIC KEY BLOCK-----")); s2 += _tcslen(_T("-----END PGP PUBLIC KEY BLOCK-----")); } else if((str.find(_T("-----BEGIN PGP PRIVATE KEY BLOCK-----")) != wstring::npos) && (str.find(_T("-----END PGP PRIVATE KEY BLOCK-----")) != wstring::npos)) { s2 = str.find(_T("-----END PGP PRIVATE KEY BLOCK-----")); s1 = str.find(_T("-----BEGIN PGP PRIVATE KEY BLOCK-----")); s2 += _tcslen(_T("-----END PGP PRIVATE KEY BLOCK-----")); } new_key.append(str.substr(s1,s2-s1)); WaitForSingleObject(new_key_hcnt_mutex, INFINITE); new_key_hcnt_mutex = CreateMutex(NULL, FALSE, NULL); new_key_hcnt = hContact; ShowNewKeyDialog(); return CallService(MS_PROTO_CHAINRECV, w, l); } s1 = str.find(_T("-----BEGIN PGP MESSAGE-----")); s2 = str.find(_T("-----END PGP MESSAGE-----")); if((s2 != wstring::npos) && (s1 != wstring::npos)) { //this is generic encrypted data block void setSrmmIcon(HANDLE); void setClistIcon(HANDLE); bool isContactHaveKey(HANDLE hContact); if(!DBGetContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 0)) { debuglog<<"info: "<<"received message from: "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)<<" whith tyrned off encryption\n"; if(MessageBox(0, _T("We received encrypted message from contact with encryption turned off.\nDo you want turn on encryption for this contact ?"), _T("Warning"), MB_YESNO) == IDYES) { if(!isContactHaveKey(hContact)) { void ShowLoadPublicKeyDialog(); extern map user_data; extern int item_num; item_num = 0; //black magic here user_data[1] = hContact; ShowLoadPublicKeyDialog(); } else { DBWriteContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 1); setSrmmIcon(hContact); setClistIcon(hContact); } if(isContactHaveKey(hContact)) { DBWriteContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 1); setSrmmIcon(hContact); setClistIcon(hContact); } } else if(MessageBox(0, _T("Do you want try to decrypt encrypted message ?"), _T("Warning"), MB_YESNO) == IDNO) return CallService(MS_PROTO_CHAINRECV, w, l); } { wstring::size_type p = 0; while((p = str.find(_T("\r"), p)) != wstring::npos) str.erase(p, 1); } s2 += _tcslen(_T("-----END PGP MESSAGE-----")); char *tmp = mir_t2a(str.substr(s1,s2-s1).c_str()); TCHAR *tmp2 = UniGetContactSettingUtf(NULL, szGPGModuleName, "szHomePath", _T("")); wstring path = tmp2; path.append(_T("\\encrypted_data.asc")); DeleteFile(path.c_str()); fstream f(path.c_str(), std::ios::out); f< 0) { string dbsetting = "szKey_"; dbsetting += inkeyid; dbsetting += "_Password"; pass = UniGetContactSettingUtf(NULL, szGPGModuleName, dbsetting.c_str(), _T("")); if(_tcslen(pass) > 0) debuglog<<"info: found password in database for key id: "< 0) debuglog<<"info: found password for all keys in database, trying to decrypt message from "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)<<" with password\n"; } if(_tcslen(pass) > 0) { cmd += _T("--passphrase \""); cmd += pass; cmd += _T("\" "); } else if(password) { debuglog<<"info: found password in memory, trying to decrypt message from "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)<<" with password\n"; cmd += _T("--passphrase \""); cmd += password; cmd += _T("\" "); } else debuglog<<"info: passwords not found in database or memory, trying to decrypt message from "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)<<" with out password\n"; mir_free(pass); mir_free(inkeyid); } { wstring path = tmp2; path += _T("\\decrypted_data"); DeleteFile(path.c_str()); } cmd += _T("--output \""); cmd += tmp2; cmd += _T("\\decrypted_data\""); cmd += _T(" -d -a \""); cmd += path; cmd += _T("\""); gpg_execution_params params; pxResult result; params.cmd = &cmd; params.useless = ""; params.out = &out; params.code = &code; params.result = &result; HANDLE gpg_thread = mir_forkthread(pxEexcute_thread, (void*)¶ms); if(WaitForSingleObject(gpg_thread, 10000) == WAIT_TIMEOUT) { TerminateThread(gpg_thread, 0); MessageBox(0, _T("GPG execution timed out, aborted"), _T(""), MB_OK); } if(result == pxNotFound) { MessageBox(0, _T("Set path to gpg.exe first!"), _T("Warning"), MB_OK); DeleteFile(path.c_str()); return CallService(MS_PROTO_CHAINRECV, w, l); } _terminate = false; while(out.find("public key decryption failed: bad passphrase") != string::npos) { debuglog<<"info: failed to decrypt messaage from "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)<<" password needed, trying to get one\n"; if(_terminate) break; { //save inkey id string::size_type s = out.find(" encrypted with "); s = out.find(" ID ", s); s += strlen(" ID "); string::size_type s2 = out.find(",",s); DBWriteContactSettingString(hContact, szGPGModuleName, "InKeyID", out.substr(s, s2-s).c_str()); } void ShowLoadKeyPasswordWindow(); WaitForSingleObject(new_key_hcnt_mutex, INFINITE); new_key_hcnt_mutex = CreateMutex(NULL, FALSE, NULL); new_key_hcnt = hContact; ShowLoadKeyPasswordWindow(); wstring cmd2 = cmd; if(password) { debuglog<<"info: found password in memory, trying to decrypt message from "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)<<"\n"; wstring tmp = _T("--passphrase \""); tmp += password; tmp += _T("\" "); cmd2.insert(0, tmp); } out.clear(); gpg_execution_params params; pxResult result; params.cmd = &cmd2; params.useless = ""; params.out = &out; params.code = &code; params.result = &result; HANDLE gpg_thread = mir_forkthread(pxEexcute_thread, (void*)¶ms); if(WaitForSingleObject(gpg_thread, 10000) == WAIT_TIMEOUT) { TerminateThread(gpg_thread, 0); MessageBox(0, _T("GPG execution timed out, aborted"), _T(""), MB_OK); } if(result == pxNotFound) { MessageBox(0, _T("Set path to gpg.exe first!"), _T("Warning"), MB_OK); DeleteFile(path.c_str()); return CallService(MS_PROTO_CHAINRECV, w, l); } } out.clear(); gpg_thread = mir_forkthread(pxEexcute_thread, (void*)¶ms); if(WaitForSingleObject(gpg_thread, 10000) == WAIT_TIMEOUT) { TerminateThread(gpg_thread, 0); MessageBox(0, _T("GPG execution timed out, aborted"), _T(""), MB_OK); } if(result == pxNotFound) { MessageBox(0, _T("Set path to gpg.exe first!"), _T("Warning"), MB_OK); DeleteFile(path.c_str()); return CallService(MS_PROTO_CHAINRECV, w, l); } { wstring tmp = tmp2; tmp += _T("\\encrypted_data.asc"); DeleteFile(tmp.c_str()); } { wstring tmp = tmp2; tmp += _T("\\decrypted_data"); if(_waccess(tmp.c_str(), 0) == -1) { if(errno == ENOENT) { string str = pre->szMessage; mir_free((void**)pre->szMessage); str.insert(0, "Failed to decrypt GPG encrypted message:\n"); char *tmp = new char [str.length()+1]; strcpy(tmp, str.c_str()); pre->szMessage = tmp; return CallService(MS_PROTO_CHAINRECV, w, (LPARAM)ccs); } } } str.clear(); { wstring path = tmp2; mir_free(tmp2); path += _T("\\decrypted_data"); fstream f(path.c_str(), std::ios::in | std::ios::ate | std::ios::binary); if(f.is_open()) { std::wifstream::pos_type size = f.tellg(); char *tmp = new char [(std::ifstream::pos_type)size+(std::ifstream::pos_type)1]; f.seekg(0, std::ios::beg); f.read(tmp, size); tmp[size] = '\0'; TCHAR *tmp2 = mir_utf8decodeW(tmp); if(!tmp2) { str.append(_T("Miranda failed to decode this utf8 message, showing it as is:\n")); tmp2 = mir_a2t(tmp); str.append(tmp2); } delete [] tmp; str.append(tmp2); mir_free(tmp2); f.close(); DeleteFile(path.c_str()); } if(str.empty()) { string str = pre->szMessage; mir_free((void**)pre->szMessage); str.insert(0, "Failed to decrypt GPG encrypted message:\n"); debuglog<<"info: Failed to decrypt GPG encrypted message.\n"; pre->szMessage = mir_strdup(str.c_str()); return CallService(MS_PROTO_CHAINRECV, w, (LPARAM)ccs); } else { mir_free((void**)pre->szMessage); if(bAppendTags) { str.insert(0, inopentag); str.append(inclosetag); } pre->szMessage = mir_utf8encodeW(str.c_str()); return CallService(MS_PROTO_CHAINRECV, w, (LPARAM)ccs); } } } } } if(DBGetContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 0)) { wchar_t *tmp = mir_utf8decodeW(msg); wstring str = tmp; mir_free(tmp); mir_free((void**)pre->szMessage); str.insert(0, _T("Received unencrypted message:\n")); pre->szMessage = mir_utf8encodeW(str.c_str()); return CallService(MS_PROTO_CHAINRECV, w, (LPARAM)ccs); } return CallService(MS_PROTO_CHAINRECV, w, l); } int SendMsgSvc(WPARAM w, LPARAM l) { CCSDATA *ccs = (CCSDATA*)l; if (!ccs) return CallService(MS_PROTO_CHAINSEND, w, l); char *msg = (char*)(ccs->lParam); if (!msg) return CallService(MS_PROTO_CHAINSEND, w, l); HANDLE hContact = ccs->hContact; if(isProtoMetaContacts(hContact)) hContact = metaGetMostOnline(hContact); if(!DBGetContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 0)) return CallService(MS_PROTO_CHAINSEND, w, l); { //encrypt data here wchar_t *tmp = mir_utf8decodeW(msg); wstring str = tmp; mir_free(tmp); { //not xmpp, just replace whole message string out; DWORD code; wstring cmd; wstring path; extern bool bJabberAPI, bIsMiranda09; char *tmp = UniGetContactSettingUtf(hContact, szGPGModuleName, "KeyID", ""); if(strlen(tmp) < 2) { mir_free(tmp); HistoryLog(hContact, "Failed to encrypt message with GPG", EVENTTYPE_MESSAGE, DBEF_SENT); return CallService(MS_PROTO_CHAINSEND, w, l); } if(!bJabberAPI || !bIsMiranda09) cmd += _T("--comment \"\" --no-version "); if(DBGetContactSettingByte(hContact, szGPGModuleName, "bAlwaysTrust", 0)) cmd += _T("--trust-model always "); cmd += _T("--batch --yes -e -a -r "); TCHAR *tmp2 = mir_a2t(tmp); mir_free(tmp); cmd += tmp2; mir_free(tmp2); cmd += _T(" \""); tmp2 = UniGetContactSettingUtf(NULL, szGPGModuleName, "szHomePath", _T("")); path.append(tmp2); cmd += tmp2; mir_free(tmp2); cmd += _T("\\exported_data"); path.append(_T("\\exported_data")); cmd += _T("\""); { char *tmp; tmp = mir_utf8encodeW(str.c_str()); fstream f(path.c_str(), std::ios::out); f<lParam = (LPARAM)mir_utf8encodeW(str.c_str()); if(bAppendTags) DBWriteContactSettingByte(hContact, szGPGModuleName, "MsgsForTagging", DBGetContactSettingByte(ccs->hContact, szGPGModuleName, "MsgsForTagging", 0) + 1); } } return CallService(MS_PROTO_CHAINSEND, w, l); } int HookSendMsg(WPARAM w, LPARAM l) { HANDLE hContact = (HANDLE)w; if(isProtoMetaContacts(hContact)) hContact = metaGetMostOnline(hContact); if(!DBGetContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 0)) return 0; if(bAppendTags) { if(!l) return 0; BYTE Msgs = DBGetContactSettingByte(hContact, szGPGModuleName, "MsgsForTagging", 0); if(!Msgs) return 0; DBEVENTINFO * dbei = (DBEVENTINFO*)l; if((dbei->eventType == EVENTTYPE_MESSAGE) && (dbei->flags & DBEF_SENT)) { char *msg = (char*)dbei->pBlob; TCHAR *tmp = mir_utf8decodeW(msg); wstring str = tmp; mir_free(tmp); str.insert(0, outopentag); str.append(outclosetag); char *msg2 = mir_utf8encodeW(str.c_str()); mir_free(dbei->pBlob); dbei->pBlob = (PBYTE)msg2; dbei->cbBlob = strlen(msg2)+1; DBWriteContactSettingByte(hContact, szGPGModuleName, "MsgsForTagging", Msgs - 1); } } return 0; } int TestHook(WPARAM w, LPARAM l) { return 0; } static BOOL CALLBACK DlgProcKeyPassword(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { char *inkeyid = UniGetContactSettingUtf(new_key_hcnt, szGPGModuleName, "InKeyID", ""); ReleaseMutex(new_key_hcnt_mutex); TCHAR *tmp = NULL; switch (msg) { case WM_INITDIALOG: { TranslateDialogDefault(hwndDlg); string questionstr = "Please enter password for key with ID: "; questionstr += inkeyid; SetDlgItemTextA(hwndDlg, IDC_KEYID, questionstr.c_str()); EnableWindow(GetDlgItem(hwndDlg, IDC_DEFAULT_PASSWORD), 0); return TRUE; } case WM_COMMAND: { switch (LOWORD(wParam)) { case IDOK: { TCHAR tmp[64]; GetDlgItemText(hwndDlg, IDC_KEY_PASSWORD, tmp, 64); if(_tcslen(tmp) > 0) { extern TCHAR *password; if(IsDlgButtonChecked(hwndDlg, IDC_SAVE_PASSWORD)) { if((strlen(inkeyid) > 0) && !IsDlgButtonChecked(hwndDlg, IDC_DEFAULT_PASSWORD)) { string dbsetting = "szKey_"; dbsetting += inkeyid; dbsetting += "_Password"; DBWriteContactSettingTString(NULL, szGPGModuleName, dbsetting.c_str(), tmp); } else DBWriteContactSettingTString(NULL, szGPGModuleName, "szKeyPassword", tmp); } if(password) delete [] password; password = new TCHAR [_tcslen(tmp)+1]; _tcscpy(password, tmp); } mir_free(tmp); mir_free(inkeyid); DestroyWindow(hwndDlg); break; } case IDCANCEL: mir_free(inkeyid); _terminate = true; DestroyWindow(hwndDlg); break; default: break; } break; } case WM_NOTIFY: { /* switch (((LPNMHDR)lParam)->code) { default: EnableWindow(GetDlgItem(hwndDlg, IDC_DEFAULT_PASSWORD), IsDlgButtonChecked(hwndDlg, IDC_SAVE_PASSWORD)?1:0); break; }*/ } break; case WM_CLOSE: mir_free(inkeyid); DestroyWindow(hwndDlg); break; case WM_DESTROY: break; } return FALSE; } void ShowLoadKeyPasswordWindow() { extern HINSTANCE hInst; DialogBox(hInst, MAKEINTRESOURCE(IDD_KEY_PASSWD), NULL, DlgProcKeyPassword); }