// 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; boost::mutex new_key_hcnt_mutex; bool _terminate = false; int returnNoError(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; { //check for gpg related data wstring str = toUTF16(msg); wstring::size_type s1 = wstring::npos, s2 = wstring::npos; if((str.find(_T("-----PGP KEY RESPONSE-----")) != wstring::npos) && !metaIsProtoMetaContacts(ccs->hContact)) { s2 = str.find(_T("-----END PGP PUBLIC KEY BLOCK-----")); s1 = str.find(_T("-----BEGIN PGP PUBLIC KEY BLOCK-----")); if(s1 != wstring::npos && s2 != wstring::npos) { s2 += _tcslen(_T("-----END PGP PUBLIC KEY BLOCK-----")); DBWriteContactSettingTString(hContact, szGPGModuleName, "GPGPubKey", str.substr(s1,s2-s1).c_str()); DBWriteContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 1); { //gpg execute block wstring cmd; TCHAR tmp2[MAX_PATH] = {0}; TCHAR *ptmp; string output; DWORD exitcode; { ptmp = UniGetContactSettingUtf(NULL, szGPGModuleName, "szHomePath", _T("")); _tcscpy(tmp2, ptmp); mir_free(ptmp); _tcscat(tmp2, _T("\\")); _tcscat(tmp2, _T("temporary_exported.asc")); DeleteFile(tmp2); wfstream f(tmp2, std::ios::out); ptmp = UniGetContactSettingUtf(hContact, szGPGModuleName, "GPGPubKey", _T("")); wstring new_key = ptmp; mir_free(ptmp); f< output.find("<", s)) s2 = output.find("<", s); tmp = new char [output.substr(s,s2-s-1).length()+1]; strcpy(tmp, output.substr(s,s2-s-1).c_str()); mir_utf8decode(tmp, 0); DBWriteContactSettingString(hContact, szGPGModuleName, "KeyMainName", tmp); mir_free(tmp); if((s = output.find(")", s2)) == string::npos) s = output.find(">", s2); else if(s > output.find(">", s2)) s = output.find(">", s2); s2++; if(output[s] == ')') { tmp = new char [output.substr(s2,s-s2).length()+1]; strcpy(tmp, output.substr(s2,s-s2).c_str()); mir_utf8decode(tmp, 0); DBWriteContactSettingString(hContact, szGPGModuleName, "KeyComment", tmp); mir_free(tmp); s+=3; s2 = output.find(">", s); tmp = new char [output.substr(s,s2-s).length()+1]; strcpy(tmp, output.substr(s,s2-s).c_str()); mir_utf8decode(tmp, 0); DBWriteContactSettingString(hContact, szGPGModuleName, "KeyMainEmail", tmp); mir_free(tmp); } else { tmp = new char [output.substr(s2,s-s2).length()+1]; strcpy(tmp, output.substr(s2,s-s2).c_str()); mir_utf8decode(tmp, 0); DBWriteContactSettingString(hContact, szGPGModuleName, "KeyMainEmail", output.substr(s2,s-s2).c_str()); mir_free(tmp); } DBWriteContactSettingByte(hContact, szGPGModuleName, "bAlwatsTrust", 1); void setSrmmIcon(HANDLE); void setClistIcon(HANDLE); setSrmmIcon(hContact); setClistIcon(hContact); if(metaIsSubcontact(hContact)) { setSrmmIcon(metaGetContact(hContact)); setClistIcon(metaGetContact(hContact)); HistoryLog(metaGetContact(hContact), "PGP Encryption turned on by key autoexchange feature", EVENTTYPE_MESSAGE, DBEF_READ); } HistoryLog(hContact, "PGP Encryption turned on by key autoexchange feature", EVENTTYPE_MESSAGE, 0); } } hcontact_data[hContact].msgs_to_ignore.push_back(msg); return 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-----")); } 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 if(metaIsSubcontact(hContact)) return CallService(MS_PROTO_CHAINRECV, w, l); //yet another metacontacts problem debuglog< Accounts; list::iterator end = Accounts.end(); for(list::iterator p = Accounts.begin(); p != end; p++) { TCHAR *caps = (*p)->getJabberInterface()->Net()->GetResourceFeatures(jid); if(caps) { wstring str; for(int i =0;;i++) { str.push_back(caps[i]); if(caps[i] == '\0') if(caps[i+1] == '\0') break; } mir_free(caps); if(str.find(_T("GPG_Key_Auto_Exchange:0")) != string::npos) CallContactService(hContact, PSS_MESSAGE, (WPARAM)PREF_UTF, (LPARAM)"-----PGP KEY REQUEST-----"); } } } } } return 1; } 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(metaGetCurrent(hContact), szGPGModuleName, "GPGEncryption", 0)) { debuglog< user_data; extern int item_num; item_num = 0; //black magic here user_data[1] = hContact; ShowLoadPublicKeyDialog(); } else { DBWriteContactSettingByte(metaGetCurrent(hContact), szGPGModuleName, "GPGEncryption", 1); setSrmmIcon(hContact); setClistIcon(hContact); } if(isContactHaveKey(hContact)) { DBWriteContactSettingByte(metaGetCurrent(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< 0) debuglog< 0) { cmd += _T("--passphrase \""); cmd += pass; cmd += _T("\" "); } else if(password) { debuglog<timed_join(boost::posix_time::seconds(10))) { delete gpg_thread; debuglog<timed_join(boost::posix_time::seconds(10))) { delete gpg_thread; debuglog<timed_join(boost::posix_time::seconds(10))) { delete gpg_thread; debuglog<szMessage; mir_free((void**)pre->szMessage); str.insert(0, "Received unencrypted message:\n"); debuglog<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'; toUTF16(tmp); str.append(toUTF16(tmp)); delete [] tmp; 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.\nReceived unencrypted message:\n"); debuglog<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_strdup(toUTF8(str).c_str()); if(metaIsSubcontact(hContact)) { char *msg = mir_strdup(toUTF8(str).c_str()); HistoryLog(hContact, msg, EVENTTYPE_MESSAGE, DBEF_UTF); HistoryLog(metaGetContact(hContact), msg, EVENTTYPE_MESSAGE, DBEF_UTF); mir_free(msg); return 1; } return CallService(MS_PROTO_CHAINRECV, w, (LPARAM)ccs); } } } } } if(DBGetContactSettingByte(metaGetCurrent(hContact), szGPGModuleName, "GPGEncryption", 0)) { if(metaIsSubcontact(hContact)) { HistoryLog(hContact, msg, EVENTTYPE_MESSAGE, DBEF_UTF); HistoryLog(metaGetContact(hContact), msg, EVENTTYPE_MESSAGE, DBEF_UTF); mir_free(msg); return 1; } string str = msg; mir_free((void**)pre->szMessage); str.insert(0, "Received unencrypted message:\n"); pre->szMessage = mir_strdup(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); if(strstr(msg,"-----BEGIN PGP MESSAGE-----")) //metecontacts .... %) return CallService(MS_PROTO_CHAINSEND, w, l); HANDLE hContact = ccs->hContact; if(metaIsProtoMetaContacts(hContact)) { hcontact_data[ccs->hContact].msgs_to_ignore.push_back((char*)ccs->lParam); return CallService(MS_PROTO_CHAINSEND, w, l); } if(!isContactHaveKey(hContact) && bAutoExchange && !strstr(msg, "-----PGP KEY REQUEST-----") && !strstr(msg, "-----BEGIN PGP PUBLIC KEY BLOCK-----") && isGPGConfigured()) //TODO: add all mesages to list, and send after key exchange done, encrypted { void send_encrypted_msgs_thread(HANDLE hContact); LPSTR proto = (LPSTR)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); DWORD uin = DBGetContactSettingDword(hContact, proto, "UIN", 0); if(uin) { if(ServiceExists("ICQ"PS_ICQ_CHECKCAPABILITY)) { ICQ_CUSTOMCAP cap = {0}; strcpy(cap.caps, "GPG AutoExchange"); if(CallService("ICQ"PS_ICQ_CHECKCAPABILITY, (WPARAM)hContact, (LPARAM)&cap)) { CallContactService(hContact, PSS_MESSAGE, (WPARAM)PREF_UTF, (LPARAM)"-----PGP KEY REQUEST-----"); hcontact_data[hContact].msgs_to_ignore.push_back(msg); hcontact_data[hContact].msgs_to_send.push_back(msg); boost::thread *thr = new boost::thread(boost::bind(send_encrypted_msgs_thread, hContact)); return returnNoError(hContact); } } } else { TCHAR *jid = UniGetContactSettingUtf(hContact, proto, "jid", _T("")); if(jid[0]) { extern list Accounts; list::iterator end = Accounts.end(); for(list::iterator p = Accounts.begin(); p != end; p++) { TCHAR *caps = (*p)->getJabberInterface()->Net()->GetResourceFeatures(jid); if(caps) { wstring str; for(int i =0;;i++) { str.push_back(caps[i]); if(caps[i] == '\0') if(caps[i+1] == '\0') break; } mir_free(caps); if(str.find(_T("GPG_Key_Auto_Exchange:0")) != string::npos) { CallContactService(hContact, PSS_MESSAGE, (WPARAM)PREF_UTF, (LPARAM)"-----PGP KEY REQUEST-----"); hcontact_data[hContact].msgs_to_ignore.push_back(msg); hcontact_data[hContact].msgs_to_send.push_back(msg); boost::thread *thr = new boost::thread(boost::bind(send_encrypted_msgs_thread, hContact)); return returnNoError(hContact); } } } } } } if(!isContactSecured(hContact)) return CallService(MS_PROTO_CHAINSEND, w, l); { //encrypt data here wstring str = toUTF16(msg); { //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(!tmp[0]) { 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) //force jabber to handle encrypted message by itself 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_strdup(toUTF8(str).c_str()); fstream f(path.c_str(), std::ios::out); f<lParam; if(bAppendTags) { str_event.insert(0, toUTF8(outopentag)); str_event.append(toUTF8(outclosetag)); } HistoryLog(hContact, (char*)str_event.c_str(), EVENTTYPE_MESSAGE, DBEF_SENT | DBEF_UTF); HistoryLog(metaGetContact(hContact), (char*)str_event.c_str(), EVENTTYPE_MESSAGE, DBEF_SENT | DBEF_UTF); hcontact_data[hContact].msgs_to_ignore.push_back((char*)ccs->lParam); hcontact_data[metaGetContact(hContact)].msgs_to_ignore.push_back((char*)ccs->lParam); //hmm, twice ? metacontacts !! %) CallContactService(hContact, PSS_MESSAGE, (WPARAM)PREF_UTF, (LPARAM)toUTF8(str).c_str()); return returnNoError(hContact); } if(bAppendTags) hcontact_data[hContact].msgs_to_tag.push_back((char*)ccs->lParam); ccs->lParam = (LPARAM)mir_strdup(toUTF8(str).c_str()); } } return CallService(MS_PROTO_CHAINSEND, w, l); } int HookSendMsg(WPARAM w, LPARAM l) { //TODO: implement additional filtering for metacontacts data... if(!l) return 0; DBEVENTINFO * dbei = (DBEVENTINFO*)l; if((dbei->eventType == EVENTTYPE_MESSAGE) && (dbei->flags & DBEF_SENT)) { if(strstr((char*)dbei->pBlob, "-----BEGIN PGP MESSAGE-----") || strstr((char*)dbei->pBlob, "-----PGP KEY RESPONSE-----") || strstr((char*)dbei->pBlob, "-----PGP KEY REQUEST-----") || strstr((char*)dbei->pBlob, "-----PGP KEY RESPONSE-----")) //grrrr! return 1; HANDLE hContact = NULL; if(!hcontact_data[(HANDLE)w].msgs_to_ignore.empty()) hContact = (HANDLE)w; else if(!hcontact_data[metaGetContact((HANDLE)w)].msgs_to_ignore.empty()) hContact = metaGetContact((HANDLE)w); if(hContact) { list::iterator end = hcontact_data[hContact].msgs_to_ignore.end(); for(list::iterator p = hcontact_data[hContact].msgs_to_ignore.begin(); p != end; p++) { if(*p == (char*)dbei->pBlob) { hcontact_data[hContact].msgs_to_ignore.erase(p); return 1; } } } } HANDLE hContact = (HANDLE)w; if(metaIsProtoMetaContacts(hContact)) hContact = metaGetCurrent(hContact); if(!DBGetContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 0)) return 0; if(bAppendTags) { if((dbei->eventType == EVENTTYPE_MESSAGE) && (dbei->flags & DBEF_SENT)) { if(!hcontact_data[hContact].msgs_to_tag.empty()) { std::list::iterator end = hcontact_data[hContact].msgs_to_tag.end(); for(std::list::iterator i = hcontact_data[hContact].msgs_to_tag.begin(); i != end; ++i) { if(*i == (char*)dbei->pBlob) { char *msg = (char*)dbei->pBlob; wstring str = toUTF16(msg); str.insert(0, outopentag); str.append(outclosetag); char *msg2 = mir_strdup(toUTF8(str).c_str()); mir_free(dbei->pBlob); dbei->pBlob = (PBYTE)msg2; dbei->cbBlob = strlen(msg2)+1; hcontact_data[hContact].msgs_to_tag.erase(i); break; } } } } } if((dbei->eventType == EVENTTYPE_MESSAGE) && !(dbei->flags & DBEF_SENT) && metaIsProtoMetaContacts((HANDLE)w)) { char tmp[29]; strncpy(tmp, (char*)dbei->pBlob, 27); tmp[28] = '\0'; if(strstr(tmp, "-----BEGIN PGP MESSAGE-----")) return 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", ""); new_key_hcnt_mutex.unlock(); 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, (DLGPROC)DlgProcKeyPassword); }