// Copyright � 2010-2012 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" TCHAR* __stdcall UniGetContactSettingUtf(HANDLE hContact, const char *szModule,const char* szSetting, TCHAR* szDef) { DBVARIANT dbv = {DBVT_DELETED}; TCHAR* szRes; if (DBGetContactSettingTString(hContact, szModule, szSetting, &dbv)) return mir_tstrdup(szDef); if(dbv.pszVal) szRes = mir_tstrdup(dbv.ptszVal); DBFreeVariant(&dbv); return szRes; } char* __stdcall UniGetContactSettingUtf(HANDLE hContact, const char *szModule,const char* szSetting, char* szDef) { DBVARIANT dbv = {DBVT_DELETED}; char* szRes; if (DBGetContactSettingString(hContact, szModule, szSetting, &dbv)) return mir_strdup(szDef); if(dbv.pszVal) szRes = mir_strdup(dbv.pszVal); DBFreeVariant(&dbv); return szRes; } void GetFilePath(TCHAR *WindowTittle, char *szSetting, TCHAR *szExt, TCHAR *szExtDesc) { TCHAR str[MAX_PATH+2] = {0}, *tmp; OPENFILENAME ofn={0}; TCHAR filter[512], *pfilter; ofn.lStructSize=CDSIZEOF_STRUCT(OPENFILENAME,lpTemplateName); ofn.Flags=OFN_EXPLORER; ofn.lpstrTitle=TranslateW(WindowTittle); _tcscpy(filter,TranslateW(szExtDesc)); pfilter=filter+_tcslen(filter)+1; _tcscpy(pfilter, szExt); pfilter[_tcslen(pfilter)+1] = '\0'; pfilter[_tcslen(pfilter)+2] = '\0'; ofn.lpstrFilter=filter; tmp = UniGetContactSettingUtf(0, szGPGModuleName, szSetting, _T("")); _tcscpy(str, tmp); mir_free(tmp); if(_tcslen(str)< 2) str[0] = '\0'; ofn.lpstrFile=str; ofn.nMaxFile=_MAX_PATH; ofn.nMaxFileTitle=MAX_PATH; if(!GetOpenFileName(&ofn)) return; DBWriteContactSettingTString(0, szGPGModuleName, szSetting, str); } TCHAR *GetFilePath(TCHAR *WindowTittle, TCHAR *szExt, TCHAR *szExtDesc, bool save_file) { TCHAR *str = new TCHAR [MAX_PATH+2]; OPENFILENAME ofn={0}; TCHAR filter[512], *pfilter; ofn.lStructSize=CDSIZEOF_STRUCT(OPENFILENAME,lpTemplateName); ofn.Flags=OFN_EXPLORER; ofn.lpstrTitle=TranslateW(WindowTittle); _tcscpy(filter,TranslateW(szExtDesc)); pfilter=filter+_tcslen(filter)+1; _tcscpy(pfilter, szExt); pfilter[_tcslen(pfilter)+1] = '\0'; pfilter[_tcslen(pfilter)+2] = '\0'; ofn.lpstrFilter=filter; _tcscpy(str, _T("")); if(_tcslen(str)< 2) str[0] = '\0'; ofn.lpstrFile=str; ofn.nMaxFile=_MAX_PATH; ofn.nMaxFileTitle=MAX_PATH; if(!save_file) { if(!GetOpenFileName(&ofn)) { delete [] str; return NULL; } } else { if(!GetSaveFileName(&ofn)) { delete [] str; return NULL; } } return str; } void GetFolderPath(TCHAR *WindowTittle, char *szSetting) { BROWSEINFO pbi = {0}; pbi.lpszTitle = WindowTittle; pbi.ulFlags = BIF_EDITBOX|BIF_NEWDIALOGSTYLE|BIF_SHAREABLE; LPITEMIDLIST pidl = SHBrowseForFolder(&pbi); if (pidl != 0) { TCHAR path[MAX_PATH]; if (SHGetPathFromIDList(pidl, path)) { DBWriteContactSettingTString(NULL, szGPGModuleName, "szHomePath", path); } IMalloc * imalloc = 0; if (SUCCEEDED(SHGetMalloc(&imalloc))) { imalloc->Free(pidl); imalloc->Release(); } } } INT_PTR LoadKey(WPARAM w, LPARAM l) { void ShowLoadPublicKeyDialog(); extern map<int, HANDLE> user_data; user_data[1] = (HANDLE)w; ShowLoadPublicKeyDialog(); return 0; } INT_PTR SendKey(WPARAM w, LPARAM l) { HANDLE hContact = (HANDLE)w; if(metaIsProtoMetaContacts(hContact)) hContact = metaGetMostOnline(hContact); char *szMessage; { LPSTR proto = (LPSTR)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); PROTOACCOUNT *acc = (PROTOACCOUNT*)CallService(MS_PROTO_GETACCOUNT, 0, (LPARAM)proto); std::string acc_str; if(acc) { acc_str = toUTF8(acc->tszAccountName); acc_str += "("; acc_str += acc->szModuleName; acc_str += ")" ; acc_str += "_GPGPubKey"; } szMessage = UniGetContactSettingUtf(NULL, szGPGModuleName, acc_str.empty()?"GPGPubKey":acc_str.c_str(), ""); if(!szMessage[0]) { mir_free(szMessage); szMessage = UniGetContactSettingUtf(NULL, szGPGModuleName, "GPGPubKey", ""); //try to get default key as fallback in any way } } if(szMessage[0]) { BYTE enc = DBGetContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 0); DBWriteContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 0); CallContactService(hContact, PSS_MESSAGE, (WPARAM)PREF_UTF, (LPARAM)szMessage); HistoryLog(hContact, db_event("Public key sent", 0, 0, DBEF_SENT)); DBWriteContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", enc); } mir_free(szMessage); return 0; } extern HANDLE hLoadPublicKey, hToggleEncryption; INT_PTR ToggleEncryption(WPARAM w, LPARAM l) { HANDLE hContact = (HANDLE)w; BYTE enc = 0; if(metaIsProtoMetaContacts(hContact)) enc = DBGetContactSettingByte(metaGetMostOnline(hContact), szGPGModuleName, "GPGEncryption", 0); else enc = DBGetContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 0); if(metaIsProtoMetaContacts(hContact)) { HANDLE hcnt = NULL; if(MessageBox(0, _T("Do you want to toggle encryption for all subcontacts ?"), _T("Metacontact detected"), MB_YESNO) == IDYES) { int count = metaGetContactsNum(hContact); for(int i = 0; i < count; i++) { hcnt = metaGetSubcontact(hContact, i); if(hcnt) DBWriteContactSettingByte(hcnt, szGPGModuleName, "GPGEncryption", enc?0:1); } DBWriteContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", enc?0:1); } } else DBWriteContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", enc?0:1); void setSrmmIcon(HANDLE hContact); void setClistIcon(HANDLE hContact); setSrmmIcon(hContact); setClistIcon(hContact); enc = enc?0:1; CLISTMENUITEM mi = {0}; mi.cbSize=sizeof(mi); mi.flags = CMIM_NAME; enc?mi.pszName="Turn off GPG encryption":mi.pszName="Turn on GPG encryption"; CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hToggleEncryption, (LPARAM)&mi); return 0; } int OnPreBuildContactMenu(WPARAM w, LPARAM l) { HANDLE hContact = (HANDLE)w; if(metaIsProtoMetaContacts(hContact)) hContact = metaGetMostOnline(hContact); CLISTMENUITEM mi = {0}; mi.cbSize=sizeof(mi); mi.flags = CMIM_NAME; TCHAR *tmp = UniGetContactSettingUtf(hContact, szGPGModuleName, "GPGPubKey", _T("")); if(_tcslen(tmp) < 1) { DBDeleteContactSetting(hContact, szGPGModuleName, "GPGEncryption"); mi.flags += CMIM_FLAGS | CMIF_GRAYED; } else mi.flags = CMIM_NAME | CMIM_FLAGS; mi.pszName = DBGetContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 0)?"Turn off GPG encryption":"Turn on GPG encryption"; CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hToggleEncryption, (LPARAM)&mi); return 0; } list<wstring> transfers; extern bool bFileTransfers; int onProtoAck(WPARAM w, LPARAM l) { ACKDATA *ack=(ACKDATA*)l; CCSDATA *ccs=(CCSDATA*)ack->lParam; if(ack->type == ACKTYPE_FILE && bFileTransfers) { switch(ack->result) { case ACKRESULT_DENIED: case ACKRESULT_FAILED: break; case ACKRESULT_SUCCESS: { PROTOFILETRANSFERSTATUS *f = (PROTOFILETRANSFERSTATUS*) ack->hProcess; TCHAR *filename = NULL; if(f->flags & PFTS_UNICODE) { if(f->tszCurrentFile && f->tszCurrentFile[0]) filename = mir_wstrdup(f->tszCurrentFile); if(!filename) return 0; } else { if(f->szCurrentFile && f->szCurrentFile[0]) filename = mir_utf8decodeT(f->szCurrentFile); if(!filename) return 0; } if(_tcsstr(filename, _T(".gpg"))) //decrypt it { //process encrypted file if(_waccess(f->tszCurrentFile, 0) == -1) { if(errno == ENOENT) return 0; } string out; DWORD code; pxResult result; wstring cmd = _T(" -o "); wstring file = filename; wstring::size_type p1 = file.rfind(_T(".gpg")); file.erase(p1, _tcslen(_T(".gpg"))); if(_waccess(file.c_str(), 0) != -1) { if(MessageBox(0, _T("Target file exists, do you want to replace it ?"), _T("Warning"), MB_YESNO) == IDNO) return 0; } DeleteFile(file.c_str()); file.insert(0, _T("\"")); file.insert(file.length(), _T("\" ")); cmd += file; extern TCHAR *password; { // password TCHAR *pass = NULL; char *keyid = UniGetContactSettingUtf(ack->hContact, szGPGModuleName, "KeyID", ""); if(strlen(keyid) > 0) { string dbsetting = "szKey_"; dbsetting += keyid; dbsetting += "_Password"; pass = UniGetContactSettingUtf(NULL, szGPGModuleName, dbsetting.c_str(), _T("")); if(_tcslen(pass) > 0) debuglog<<time_str()<<": info: found password in database for key id: "<<keyid<<", trying to decrypt message from "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)ack->hContact, GCDNF_TCHAR)<<" with password\n"; } else { pass = UniGetContactSettingUtf(NULL, szGPGModuleName, "szKeyPassword", _T("")); if(_tcslen(pass) > 0) debuglog<<time_str()<<": info: found password for all keys in database, trying to decrypt message from "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)ack->hContact, GCDNF_TCHAR)<<" with password\n"; } if(_tcslen(pass) > 0) { cmd += _T("--passphrase \""); cmd += pass; cmd += _T("\" "); } else if(password) { debuglog<<time_str()<<": info: found password in memory, trying to decrypt message from "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)ack->hContact, GCDNF_TCHAR)<<" with password\n"; cmd += _T("--passphrase \""); cmd += password; cmd += _T("\" "); } else debuglog<<time_str()<<": info: passwords not found in database or memory, trying to decrypt message from "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)ack->hContact, GCDNF_TCHAR)<<" with out password\n"; mir_free(pass); mir_free(keyid); } cmd += _T(" -d \""); cmd += filename; cmd += _T("\""); gpg_execution_params params; params.cmd = &cmd; params.useless = ""; params.out = &out; params.code = &code; params.result = &result; boost::thread *gpg_thread = new boost::thread(boost::bind(&pxEexcute_thread, ¶ms)); if(!gpg_thread->timed_join(boost::posix_time::minutes(15))) { delete gpg_thread; TerminateProcess(params.hProcess, 1); params.hProcess = NULL; debuglog<<time_str()<<": GPG execution timed out, aborted\n"; return 0; } while(out.find("public key decryption failed: bad passphrase") != string::npos) { extern bool _terminate; extern HANDLE new_key_hcnt; extern boost::mutex new_key_hcnt_mutex; debuglog<<time_str()<<": info: failed to decrypt messaage from "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)ack->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); if(metaIsProtoMetaContacts(ack->hContact)) DBWriteContactSettingString(metaGetMostOnline(ack->hContact), szGPGModuleName, "InKeyID", out.substr(s, s2-s).c_str()); else DBWriteContactSettingString(ack->hContact, szGPGModuleName, "InKeyID", out.substr(s, s2-s).c_str()); } void ShowLoadKeyPasswordWindow(); new_key_hcnt_mutex.lock(); new_key_hcnt = ack->hContact; ShowLoadKeyPasswordWindow(); wstring cmd2 = cmd; if(password) { debuglog<<time_str()<<": info: found password in memory, trying to decrypt message from "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)ack->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; gpg_thread = gpg_thread = new boost::thread(boost::bind(&pxEexcute_thread, ¶ms)); if(!gpg_thread->timed_join(boost::posix_time::seconds(15))) { delete gpg_thread; TerminateProcess(params.hProcess, 1); params.hProcess = NULL; debuglog<<time_str()<<": GPG execution timed out, aborted\n"; DeleteFile(filename); return 0; } if(result == pxNotFound) { DeleteFile(filename); return 0; } } DeleteFile(filename); mir_free(filename); } } break; } } else if(ack->type == ACKTYPE_MESSAGE) { extern std::list<HANDLE> sent_msgs; if(!sent_msgs.empty()) { if(ack->result == ACKRESULT_FAILED) { std::list<HANDLE>::iterator it = std::find(sent_msgs.begin(), sent_msgs.end(), ack->hProcess); if(it != sent_msgs.end()) { HistoryLog(ack->hContact, db_event("Failed to send encrypted message", 0,0, 0)); } } else if(ack->result == ACKRESULT_SUCCESS) { std::list<HANDLE>::iterator it = std::find(sent_msgs.begin(), sent_msgs.end(), ack->hProcess); if(it != sent_msgs.end()) sent_msgs.erase(it); } } } return 0; } std::wstring encrypt_file(HANDLE hContact, TCHAR *filename) { string out; DWORD code; pxResult result; HANDLE hcnt = metaIsProtoMetaContacts(hContact)?metaGetMostOnline(hContact):hContact; wstring cmd = _T("--batch --yes -r "); char *keyid = UniGetContactSettingUtf(hcnt, szGPGModuleName, "KeyID", ""); TCHAR *szKeyid = mir_a2t(keyid); TCHAR *name = _tcsrchr(filename,_T('\\')); if( !name ) name = filename; else name++; TCHAR *file_out = new TCHAR [_tcslen(filename)+4]; mir_sntprintf(file_out, _tcslen(name)+7, _T("%s.gpg"), name); cmd += szKeyid; if(DBGetContactSettingByte(hcnt, szGPGModuleName, "bAlwaysTrust", 0)) cmd += _T(" --trust-model always "); mir_free(szKeyid); mir_free(keyid); cmd += _T(" -o \""); TCHAR *temp = _tgetenv(_T("TEMP")); cmd += temp; cmd += _T("\\"); cmd += file_out; wstring path_out = temp; path_out += _T("\\"); path_out += file_out; DeleteFile(path_out.c_str()); cmd += _T("\" "); mir_free(temp); cmd += _T(" -e \""); cmd += filename; cmd += _T("\" "); gpg_execution_params params; params.cmd = &cmd; params.useless = ""; params.out = &out; params.code = &code; params.result = &result; mir_free(keyid); delete [] file_out; boost::thread *gpg_thread = new boost::thread(boost::bind(&pxEexcute_thread, ¶ms)); if(!gpg_thread->timed_join(boost::posix_time::seconds(180))) { delete gpg_thread; TerminateProcess(params.hProcess, 1); params.hProcess = NULL; debuglog<<time_str()<<": GPG execution timed out, aborted\n"; return 0; } if(out.find("There is no assurance this key belongs to the named user") != string::npos) { out.clear(); if(MessageBox(0, _T("We trying to encrypt with untrusted key, do you want to trust this key permanently ?"), _T("Warning"), MB_YESNO) == IDYES) { DBWriteContactSettingByte(hcnt, szGPGModuleName, "bAlwaysTrust", 1); cmd.insert(0, _T("--trust-model always ")); gpg_thread = new boost::thread(boost::bind(&pxEexcute_thread, ¶ms)); if(!gpg_thread->timed_join(boost::posix_time::seconds(180))) { delete gpg_thread; TerminateProcess(params.hProcess, 1); params.hProcess = NULL; debuglog<<time_str()<<": GPG execution timed out, aborted\n"; return 0; } } else return 0; } return path_out; } //from secureim partially int onSendFile(WPARAM w, LPARAM l) { if(!bFileTransfers) return CallService(MS_PROTO_CHAINSEND, w, l); CCSDATA *ccs=(CCSDATA*)l; if(isContactSecured(ccs->hContact)) { DWORD flags = (DWORD)ccs->wParam; //check for PFTS_UNICODE here int i; // if(flags & PFTS_UNICODE) //this does not work .... if(StriStr(ccs->szProtoService, "/sendfilew")) { TCHAR **file=(TCHAR **)ccs->lParam; for(i = 0; file[i]; i++) { if(_waccess(file[i], 0) == -1) if(errno == ENOENT) return 0; //we do not want to send file unencrypted (sometimes ack have wrong info) if (_tcsstr(file[i],_T(".gpg"))) continue; std::wstring path_out = encrypt_file(ccs->hContact, file[i]); mir_free(file[i]); file[i] = mir_tstrdup(path_out.c_str()); transfers.push_back(path_out); } } else { char **file = (char**) ccs->lParam; for(i = 0; file[i]; i++) { if(_access(file[i], 0) == -1) if(errno == ENOENT) return 0; //we do not want to send file unencrypted (sometimes ack have wrong info) if (strstr(file[i],".gpg")) continue; TCHAR *tmp = mir_utf8decodeT(file[i]); std::wstring path_out = encrypt_file(ccs->hContact, tmp); mir_free(tmp); char* tmp2 = mir_utf8encodeW(path_out.c_str()); mir_free(file[i]); file[i] = tmp2; transfers.push_back(path_out); } } } return CallService(MS_PROTO_CHAINSEND, w, l); } void storeOutput(HANDLE ahandle, string *output) { BOOL success; char *readbuffer = NULL; unsigned long transfered, available; do { PeekNamedPipe(ahandle,NULL,0,NULL,&available,NULL); if (!available) continue; readbuffer = (char*)mir_alloc(available); success=ReadFile(ahandle,readbuffer,available,&transfered,NULL); if (success && transfered) output->append(readbuffer, available); mir_free(readbuffer); } while (available>0); } void HistoryLog(HANDLE hContact, db_event evt) { DBEVENTINFO Event = {0}; Event.cbSize = sizeof(Event); Event.szModule = szGPGModuleName; Event.eventType = evt.eventType; Event.flags = evt.flags; if(!evt.timestamp) Event.timestamp = (DWORD)time(NULL); else Event.timestamp = evt.timestamp; Event.cbBlob = strlen((char*)evt.pBlob)+1; Event.pBlob = (PBYTE)_strdup((char*)evt.pBlob); CallService(MS_DB_EVENT_ADD, (WPARAM)(HANDLE)hContact,(LPARAM)&Event); } static int ControlAddStringUtf(HWND ctrl, DWORD msg, const TCHAR *szString) { int item = -1; item = SendMessage(ctrl, msg, 0, (LPARAM)szString); return item; } int ComboBoxAddStringUtf(HWND hCombo, const TCHAR *szString, DWORD data) { int item = ControlAddStringUtf(hCombo, CB_ADDSTRING, szString); SendMessage(hCombo, CB_SETITEMDATA, item, data); return item; } int GetJabberInterface(WPARAM w, LPARAM l) //get interface for all jabber accounts, options later { extern list <JabberAccount*> Accounts; void AddHandlers(); int count = 0; PROTOACCOUNT **accounts; ProtoEnumAccounts(&count, &accounts); list <JabberAccount*>::iterator p; Accounts.clear(); Accounts.push_back(new JabberAccount); p = Accounts.begin(); (*p)->setAccountNumber(0); for(int i = 0; i < count; i++) //get only jabber accounts from all accounts { IJabberInterface *JIftmp = getJabberApi(accounts[i]->szModuleName); int a = 0; if(JIftmp) { (*p)->setJabberInterface(JIftmp); if(accounts[i]->tszAccountName) { TCHAR* tmp = mir_tstrdup(accounts[i]->tszAccountName); (*p)->setAccountName(tmp); } else { TCHAR *tmp = mir_a2t(accounts[i]->szModuleName); (*p)->setAccountName(tmp); } (*p)->setAccountNumber(a); a++; Accounts.push_back(new JabberAccount); p++; } } Accounts.pop_back(); AddHandlers(); return 0; } static JABBER_HANDLER_FUNC SendHandler(IJabberInterface *ji, HXML node, void *pUserData) { HXML local_node = node; for(int n = 0; n <= xi.getChildCount(node); n++) { LPCTSTR str = xi.getText(local_node); LPCTSTR nodename = xi.getName(local_node); LPCTSTR attr = xi.getAttrValue(local_node, _T("to")); if(attr) { HANDLE hContact = ji->Sys()->ContactFromJID(attr); if(hContact) if(!isContactSecured(hContact)) return FALSE; } if(str) { if(_tcsstr(str, _T("-----BEGIN PGP MESSAGE-----")) && _tcsstr(str, _T("-----END PGP MESSAGE-----"))) { wstring data = str; xi.setText(local_node, _T("This message is encrypted.")); wstring::size_type p1 = data.find(_T("-----BEGIN PGP MESSAGE-----")) + _tcslen(_T("-----BEGIN PGP MESSAGE-----")); while(data.find(_T("Version: "), p1) != wstring::npos) { p1 = data.find(_T("Version: "), p1); p1 = data.find(_T("\n"), p1); } while(data.find(_T("Comment: "), p1) != wstring::npos) { p1 = data.find(_T("Comment: "), p1); p1 = data.find(_T("\n"), p1); } while(data.find(_T("Encoding: "), p1) != wstring::npos) { p1 = data.find(_T("Encoding: "), p1); p1 = data.find(_T("\n"), p1); } p1+=2; wstring::size_type p2 = data.find(_T("-----END PGP MESSAGE-----")); wstring data2 = data.substr(p1, p2-p1); for(std::wstring::size_type i = data2.find(_T("\r")); i != std::wstring::npos; i = data2.find(_T("\r"), i+1)) data2.erase(i, 1); for(std::wstring::size_type i = data2.find(_T("\n")); i != std::wstring::npos; i = data2.find(_T("\n"), i+1)) data2.erase(i, 1); HXML encrypted_data = xi.addChild(node, _T("x"), data2.c_str()); xi.addAttr(encrypted_data, _T("xmlns"), _T("jabber:x:encrypted")); return FALSE; } } if(bPresenceSigning && nodename) { if(_tcsstr(nodename, _T("status"))) { TCHAR *path_c = UniGetContactSettingUtf(NULL, szGPGModuleName, "szHomePath", _T("")); wstring path_out = path_c; wstring file = toUTF16(get_random(10)); mir_free(path_c); path_out += _T("\\tmp\\"); path_out += file; DeleteFile(path_out.c_str()); wfstream f(path_out.c_str(), std::ios::out); f<<toUTF8(str).c_str(); f.close(); if(_waccess(path_out.c_str(), 0) == -1) { if(errno == ENOENT) { debuglog<<time_str()<<": info: Failed to write prescense in file\n"; return FALSE; } } { extern TCHAR *password; string out; DWORD code; wstring cmd; { char *inkeyid; { char *proto = ji->Sys()->GetModuleName(); char setting[64]; strcpy(setting, proto); strcat(setting, "_KeyID"); inkeyid = UniGetContactSettingUtf(NULL, szGPGModuleName, setting, ""); if(!inkeyid[0]) { mir_free(inkeyid); inkeyid = UniGetContactSettingUtf(NULL, szGPGModuleName, "KeyID", ""); } } TCHAR *pass = NULL; if(inkeyid[0]) { string dbsetting = "szKey_"; dbsetting += inkeyid; dbsetting += "_Password"; pass = UniGetContactSettingUtf(NULL, szGPGModuleName, dbsetting.c_str(), _T("")); if(pass[0]) debuglog<<time_str()<<": info: found password in database for key id: "<<inkeyid<<", trying to encrypt message from self with password\n"; } else { pass = UniGetContactSettingUtf(NULL, szGPGModuleName, "szKeyPassword", _T("")); if(pass[0]) debuglog<<time_str()<<": info: found password for all keys in database, trying to encrypt message from self with password\n"; } if(pass[0]) { cmd += _T("--passphrase \""); cmd += pass; cmd += _T("\" "); } else if(password) { debuglog<<time_str()<<": info: found password in memory, trying to encrypt message from self with password\n"; cmd += _T("--passphrase \""); cmd += password; cmd += _T("\" "); } else debuglog<<time_str()<<": info: passwords not found in database or memory, trying to encrypt message from self with out password\n"; mir_free(pass); mir_free(inkeyid); } cmd += _T("--local-user "); path_c = UniGetContactSettingUtf(NULL, szGPGModuleName, "KeyID", _T("")); cmd += path_c; cmd += _T(" --default-key "); cmd += path_c; mir_free(path_c); cmd += _T(" --batch --yes -a -s \""); cmd += path_out; cmd += _T("\" "); gpg_execution_params params; pxResult result; params.cmd = &cmd; params.useless = ""; params.out = &out; params.code = &code; params.result = &result; boost::thread gpg_thread(boost::bind(&pxEexcute_thread, ¶ms)); if(!gpg_thread.timed_join(boost::posix_time::seconds(15))) { gpg_thread.~thread(); TerminateProcess(params.hProcess, 1); params.hProcess = NULL; debuglog<<time_str()<<"GPG execution timed out, aborted\n"; } DeleteFile(path_out.c_str()); path_out += _T(".asc"); f.open(path_out.c_str(), std::ios::in | std::ios::ate | std::ios::binary); wstring data; if(f.is_open()) { std::wifstream::pos_type size = f.tellg(); TCHAR *tmp = new TCHAR [(std::ifstream::pos_type)size+(std::ifstream::pos_type)1]; f.seekg(0, std::ios::beg); f.read(tmp, size); tmp[size]= '\0'; data.append(tmp); delete [] tmp; f.close(); DeleteFile(path_out.c_str()); } if(data.empty()) { debuglog<<time_str()<<": info: Failed to read prescense sign from file\n"; return FALSE; } if(data.find(_T("-----BEGIN PGP MESSAGE-----")) != wstring::npos && data.find(_T("-----END PGP MESSAGE-----")) != wstring::npos) { wstring::size_type p1 = data.find(_T("-----BEGIN PGP MESSAGE-----")) + _tcslen(_T("-----BEGIN PGP MESSAGE-----")); if(data.find(_T("Version: "), p1) != wstring::npos) { p1 = data.find(_T("Version: "), p1); p1 = data.find(_T("\n"), p1); if(data.find(_T("Version: "), p1) != wstring::npos) { p1 = data.find(_T("Version: "), p1); p1 = data.find(_T("\n"), p1)+1; } else p1 += 1; } if(data.find(_T("Comment: "), p1) != wstring::npos) { p1 = data.find(_T("Comment: "), p1); p1 = data.find(_T("\n"), p1); if(data.find(_T("Comment: "), p1) != wstring::npos) { p1 = data.find(_T("Comment: "), p1); p1 = data.find(_T("\n"), p1)+1; } else p1 += 1; } else p1+=1; wstring::size_type p2 = data.find(_T("-----END PGP MESSAGE-----")); HXML encrypted_data = xi.addChild(node, _T("x"), data.substr(p1, p2-p1).c_str()); xi.addAttr(encrypted_data, _T("xmlns"), _T("jabber:x:signed")); } return FALSE; } } } local_node = xi.getChild(node, n); } return FALSE; } //boost::mutex sign_file_mutex; static JABBER_HANDLER_FUNC PrescenseHandler(IJabberInterface *ji, HXML node, void *pUserData) { HXML local_node = node; for(int n = 0; n <= xi.getChildCount(node); n++) { LPCTSTR str = xi.getText(local_node); LPCTSTR nodename = xi.getName(local_node); if(nodename) { if(_tcsstr(nodename, _T("x"))) { for(int n = 0; n < xi.getAttrCount(local_node); n++) { LPCTSTR name = xi.getAttrName(local_node, n); LPCTSTR value = xi.getAttrValue(local_node, name); if(_tcsstr(value, _T("jabber:x:signed"))) { LPCTSTR data = xi.getText(local_node); wstring sign = _T("-----BEGIN PGP MESSAGE-----\n\n"); wstring file = toUTF16(get_random(10)); sign += data; sign += _T("\n-----END PGP MESSAGE-----\n"); TCHAR *path_c = UniGetContactSettingUtf(NULL, szGPGModuleName, "szHomePath", _T("")); wstring path_out = path_c; mir_free(path_c); path_out += _T("\\tmp\\"); path_out += file; // sign_file_mutex.lock(); DeleteFile(path_out.c_str()); wfstream f(path_out.c_str(), std::ios::out); while(!f.is_open()) f.open(path_out.c_str(), std::ios::out); f<<toUTF8(sign).c_str(); f.close(); if(_waccess(path_out.c_str(), 0) == -1) { if(errno == ENOENT) { // sign_file_mutex.unlock(); debuglog<<time_str()<<": info: Failed to write sign in file\n"; return FALSE; } } { //gpg string out; DWORD code; wstring cmd = _T(" --verify -a \""); cmd += path_out; cmd += _T("\""); gpg_execution_params params; pxResult result; params.cmd = &cmd; params.useless = ""; params.out = &out; params.code = &code; params.result = &result; boost::thread gpg_thread(boost::bind(&pxEexcute_thread, ¶ms)); if(!gpg_thread.timed_join(boost::posix_time::seconds(15))) { gpg_thread.~thread(); TerminateProcess(params.hProcess, 1); params.hProcess = NULL; debuglog<<time_str()<<": GPG execution timed out, aborted\n"; return FALSE; } if(result == pxNotFound) { return FALSE; } DeleteFile(path_out.c_str()); if(out.find("key ID ") != string::npos) { //need to get hcontact here, i can get jid from hxml, and get handle from jid, maybe exists better way ? string::size_type p1 = out.find("key ID ") + strlen("key ID "); string::size_type p2 = out.find("\n", p1); if(p1 != string::npos && p2 != string::npos) { HANDLE hContact = NULL; { extern list <JabberAccount*> Accounts; list <JabberAccount*>::iterator p = Accounts.begin(); for(unsigned int i = 0; i < Accounts.size(); i++, p++) { if(!(*p)) break; hContact = (*p)->getJabberInterface()->Sys()->ContactFromJID(xi.getAttrValue(node, _T("from"))); if(hContact) hcontact_data[hContact].key_in_prescense = out.substr(p1, p2-p1-1).c_str(); } } } } } return FALSE; } } } } local_node = xi.getChild(node, n); } return FALSE; } static JABBER_HANDLER_FUNC MessageHandler(IJabberInterface *ji, HXML node, void *pUserData) { return FALSE; } void AddHandlers() { extern list<JabberAccount*> Accounts; list<JabberAccount*>::iterator end = Accounts.end(); for(list<JabberAccount*>::iterator p = Accounts.begin(); p != end; p++) { if(!(*p)) break; if((*p)->getSendHandler() == INVALID_HANDLE_VALUE) (*p)->setSendHandler((*p)->getJabberInterface()->Net()->AddSendHandler((JABBER_HANDLER_FUNC)SendHandler)); if((*p)->getPrescenseHandler() == INVALID_HANDLE_VALUE) (*p)->setPrescenseHandler((*p)->getJabberInterface()->Net()->AddPresenceHandler((JABBER_HANDLER_FUNC)PrescenseHandler)); // if((*p)->getMessageHandler() == INVALID_HANDLE_VALUE) // (*p)->setMessageHandler((*p)->getJabberInterface()->Net()->AddMessageHandler((JABBER_HANDLER_FUNC)MessageHandler, JABBER_MESSAGE_TYPE_ANY ,NULL,NULL)); if(bAutoExchange) { (*p)->getJabberInterface()->Net()->RegisterFeature(_T("GPG_Key_Auto_Exchange:0"), _T("Indicates that gpg installed and configured to public key auto exchange (currently implemented in new_gpg Miranda IM plugin)")); (*p)->getJabberInterface()->Net()->AddFeatures(_T("GPG_Key_Auto_Exchange:0\0\0")); } } } bool isContactSecured(HANDLE hContact) { BYTE gpg_enc = DBGetContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 0); if(!gpg_enc) { debuglog<<time_str()<<": encryption is turned off for "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)<<"\n"; return false; } if(!metaIsProtoMetaContacts(hContact)) { TCHAR *key = UniGetContactSettingUtf(hContact, szGPGModuleName, "GPGPubKey", _T("")); if(!key[0]) { mir_free(key); debuglog<<time_str()<<": encryption is turned off for "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)<<"\n"; return false; } mir_free(key); } debuglog<<time_str()<<": encryption is turned on for "<<(TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, GCDNF_TCHAR)<<"\n"; return true; } bool isContactHaveKey(HANDLE hContact) { TCHAR *key = UniGetContactSettingUtf(hContact, szGPGModuleName, "GPGPubKey", _T("")); if(_tcslen(key) > 0) { mir_free(key); return true; } mir_free(key); return false; } bool isGPGKeyExist() { TCHAR *id = UniGetContactSettingUtf(NULL, szGPGModuleName, "KeyID", _T("")); char *key = UniGetContactSettingUtf(NULL, szGPGModuleName, "GPGPubKey", ""); if(id[0] && key[0]) { mir_free(id); mir_free(key); return true; } mir_free(id); mir_free(key); return false; } bool isGPGValid() { TCHAR *tmp; bool gpg_exists = false, is_valid = true; tmp = UniGetContactSettingUtf(NULL, szGPGModuleName, "szGpgBinPath", _T("")); if(_waccess(tmp, 0) != -1) gpg_exists = true; else { mir_free(tmp); TCHAR *path = (TCHAR*)mir_alloc(sizeof(TCHAR)*MAX_PATH); char *mir_path = (char*)mir_alloc(MAX_PATH); CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)"\\", (LPARAM)mir_path); SetCurrentDirectoryA(mir_path); tmp = mir_a2t(mir_path); mir_free(mir_path); //mir_realloc(path, (_tcslen(path)+64)*sizeof(TCHAR)); TCHAR *gpg_path = (TCHAR*)mir_alloc(sizeof(TCHAR)*MAX_PATH); _tcscpy(gpg_path, tmp); _tcscat(gpg_path, _T("\\GnuPG\\gpg.exe")); mir_free(tmp); if(_waccess(gpg_path, 0) != -1) { gpg_exists = true; _tcscpy(path, _T("GnuPG\\gpg.exe")); } mir_free(gpg_path); tmp = mir_tstrdup(path); mir_free(path); } DWORD len = MAX_PATH; if(gpg_exists) { DBWriteContactSettingTString(NULL, szGPGModuleName, "szGpgBinPath", tmp); string out; DWORD code; wstring cmd = _T("--version"); gpg_execution_params params; pxResult result; params.cmd = &cmd; params.useless = ""; params.out = &out; params.code = &code; params.result = &result; gpg_valid = true; boost::thread gpg_thread(boost::bind(&pxEexcute_thread, ¶ms)); if(!gpg_thread.timed_join(boost::posix_time::seconds(10))) { gpg_thread.~thread(); TerminateProcess(params.hProcess, 1); params.hProcess = NULL; debuglog<<time_str()<<": GPG execution timed out, aborted\n"; } gpg_valid = false; string::size_type p1 = out.find("(GnuPG) "); if(p1 == string::npos) is_valid = false; } mir_free(tmp); tmp = NULL; if(!gpg_exists) { wstring path_ = _wgetenv(_T("APPDATA")); path_ += _T("\\GnuPG"); tmp = UniGetContactSettingUtf(NULL, szGPGModuleName, "szHomePath", (TCHAR*)path_.c_str()); } if(tmp) mir_free(tmp); return is_valid; } #define NEWTSTR_MALLOC(A) (A==NULL)?NULL:strcpy((char*)mir_alloc(sizeof(char)*(strlen(A)+1)),A) const bool StriStr(const char *str, const char *substr) { bool i = false; char *str_up = NEWTSTR_MALLOC(str); char *substr_up = NEWTSTR_MALLOC(substr); CharUpperBuffA(str_up, strlen(str_up)); CharUpperBuffA(substr_up, strlen(substr_up)); if(strstr (str_up, substr_up)) i = true; mir_free(str_up); mir_free(substr_up); return i; } bool IsOnline(HANDLE hContact) { if(DBGetContactSettingByte(hContact, szGPGModuleName, "Status", 0) == ID_STATUS_OFFLINE) return false; return true; } //from secureim #include <process.h> struct TFakeAckParams { inline TFakeAckParams( HANDLE p1, HANDLE p2, LONG p3, LPCSTR p4 ) : hEvent( p1 ), hContact( p2 ), id( p3 ), msg( p4 ) {} HANDLE hEvent; HANDLE hContact; LONG id; LPCSTR msg; }; int SendBroadcast( HANDLE hContact, int type, int result, HANDLE hProcess, LPARAM lParam ) { ACKDATA ack; memset(&ack,0,sizeof(ack)); ack.cbSize = sizeof( ACKDATA ); ack.szModule = szGPGModuleName;// (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); ack.hContact = hContact; ack.type = type; ack.result = result; ack.hProcess = hProcess; ack.lParam = lParam; return CallService( MS_PROTO_BROADCASTACK, 0, ( LPARAM )&ack ); } unsigned __stdcall sttFakeAck( LPVOID param ) { TFakeAckParams* tParam = ( TFakeAckParams* )param; WaitForSingleObject( tParam->hEvent, INFINITE ); Sleep( 100 ); if ( tParam->msg == NULL ) SendBroadcast( tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, ( HANDLE )tParam->id, 0 ); else SendBroadcast( tParam->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, ( HANDLE )tParam->id, LPARAM( tParam->msg )); CloseHandle( tParam->hEvent ); delete tParam; return 0; } int returnNoError(HANDLE hContact) { HANDLE hEvent = CreateEvent( NULL, TRUE, FALSE, NULL ); unsigned int tID; CloseHandle( (HANDLE) _beginthreadex(NULL, 0, sttFakeAck, new TFakeAckParams(hEvent,hContact,777,0), 0, &tID) ); SetEvent( hEvent ); return 777; } // end from secureim string toUTF8(wstring str) { string ustr; try{ utf8::utf16to8(str.begin(), str.end(), back_inserter(ustr)); } catch(const utf8::exception& e) { debuglog<<std::string("utf8cpp encoding exception: ")+(char*)e.what(); //TODO } return ustr; } wstring toUTF16(string str) //convert as much as possible { wstring ustr; string tmpstr; try{ utf8::replace_invalid(str.begin(), str.end(), back_inserter(tmpstr)); utf8::utf8to16(tmpstr.begin(), tmpstr.end(), back_inserter(ustr)); } catch(const utf8::exception& e) { debuglog<<std::string("utf8cpp decoding exception: ")+(char*)e.what(); //TODO } return ustr; } string get_random(int length) { string chars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"); string data; boost::random_device rng; boost::variate_generator<boost::random_device&, boost::uniform_int<>> gen(rng, boost::uniform_int<>(0, chars.length()-1)); for(int i = 0; i < length; ++i) data += chars[gen()]; return data; } void send_encrypted_msgs_thread(HANDLE hContact) { while(true) { char *key = UniGetContactSettingUtf(hContact, szGPGModuleName, "GPGPubKey", ""); while(!isContactSecured(hContact)) boost::this_thread::sleep(boost::posix_time::seconds(1)); if(!hcontact_data[hContact].msgs_to_send.empty()) { boost::this_thread::sleep(boost::posix_time::seconds(1)); list<string>::iterator end = hcontact_data[hContact].msgs_to_send.end(); extern std::list<HANDLE> sent_msgs; for(list<string>::iterator p = hcontact_data[hContact].msgs_to_send.begin(); p != end; ++p) { sent_msgs.push_back((HANDLE)CallContactService(hContact, PSS_MESSAGE, (WPARAM)PREF_UTF, (LPARAM)p->c_str())); HistoryLog(hContact, db_event((char*)p->c_str(),0,0, DBEF_SENT)); boost::this_thread::sleep(boost::posix_time::seconds(1)); } hcontact_data[hContact].msgs_to_send.clear(); return; } else return; } } string time_str() { boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); return (string)boost::posix_time::to_simple_string(now); } int handleEnum(const char *szSetting, LPARAM lParam) { if(!*(bool*)lParam && szSetting[0] && StriStr(szSetting, "tabsrmm")) { bool f = false, *found = (bool*)lParam; f = !DBGetContactSettingByte(NULL, "PluginDisable", szSetting, 0); if(f) *found = f; } return 0; } bool isTabsrmmUsed() { DBCONTACTENUMSETTINGS enm = {0}; bool found = false; enm.lParam = (LPARAM)&found; enm.pfnEnumProc = (DBSETTINGENUMPROC)&handleEnum; enm.szModule = "PluginDisable"; if(CallService(MS_DB_CONTACT_ENUMSETTINGS, (WPARAM)NULL, (LPARAM)&enm) == -1) return false; return found; } INT_PTR ExportGpGKeys(WPARAM w, LPARAM l) { TCHAR *p = GetFilePath(_T("Choose file to export public keys"), _T("*"), _T("Any file"), true); if(!p || !p[0]) { delete [] p; //TODO: handle error return 1; } char *path = mir_t2a(p); delete [] p; std::ofstream file; file.open(path, std::ios::trunc | std::ios::out); mir_free(path); int exported_keys = 0; if(!file.is_open()) return 1; //TODO: handle error for(HANDLE hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { char *k = UniGetContactSettingUtf(hContact, szGPGModuleName, "GPGPubKey", ""); if(!k[0]) { mir_free(k); continue; } std::string key = k; mir_free(k); const char* proto = (const char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); std::string id = "Comment: login "; const char * uid = (const char*)CallProtoService(proto, PS_GETCAPS, (WPARAM)PFLAG_UNIQUEIDSETTING, 0); DBVARIANT dbv = {0}; DBCONTACTGETSETTING dbcgs = {0}; dbcgs.pValue = &dbv; dbcgs.szModule = proto; dbcgs.szSetting = uid; CallService(MS_DB_CONTACT_GETSETTING, 0, (LPARAM)&dbcgs); switch(dbcgs.pValue->type) { case DBVT_DELETED: continue; break; case DBVT_BYTE: { char _id[64]; mir_snprintf(_id, 63, "%d", dbcgs.pValue->bVal); id += _id; } break; case DBVT_WORD: { char _id[64]; mir_snprintf(_id, 63, "%d", dbcgs.pValue->wVal); id += _id; } break; case DBVT_DWORD: { char _id[64]; mir_snprintf(_id, 63, "%d", dbcgs.pValue->dVal); id += _id; } break; case DBVT_ASCIIZ: { id += dbcgs.pValue->pszVal; CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); } break; case DBVT_UTF8: { char *tmp = mir_utf8decodeA(dbcgs.pValue->pszVal); if(tmp[0]) id += tmp; mir_free(tmp); CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); } break; case DBVT_BLOB: //TODO CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); break; case DBVT_WCHAR: //TODO CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); break; } id += " contact_id "; ZeroMemory(&dbv, sizeof(dbv)); ZeroMemory(&dbcgs, sizeof(dbcgs)); dbcgs.pValue = &dbv; dbcgs.szModule = proto; dbcgs.szSetting = uid; CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&dbcgs); switch(dbcgs.pValue->type) { case DBVT_DELETED: continue; break; case DBVT_BYTE: { char _id[64]; mir_snprintf(_id, 63, "%d", dbcgs.pValue->bVal); id += _id; } break; case DBVT_WORD: { char _id[64]; mir_snprintf(_id, 63, "%d", dbcgs.pValue->wVal); id += _id; } break; case DBVT_DWORD: { char _id[64]; mir_snprintf(_id, 63, "%d", dbcgs.pValue->dVal); id += _id; } break; case DBVT_ASCIIZ: { id += dbcgs.pValue->pszVal; CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); } break; case DBVT_UTF8: { char *tmp = mir_utf8decodeA(dbcgs.pValue->pszVal); if(tmp[0]) id += tmp; mir_free(tmp); CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); } break; case DBVT_BLOB: //TODO CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); break; case DBVT_WCHAR: //TODO CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); break; } std::string::size_type p1 = key.find("-----BEGIN PGP PUBLIC KEY BLOCK-----"); if(p1 == std::string::npos) continue; p1 += strlen("-----BEGIN PGP PUBLIC KEY BLOCK-----"); p1 ++; id += '\n'; key.insert(p1, id); file<<key; file<<std::endl; exported_keys++; } if(file.is_open()) file.close(); char msg[512]; mir_snprintf(msg, 511, "we have succesfully exported %d keys", exported_keys); MessageBoxA(NULL, msg, Translate("Keys export result"), MB_OK); return 0; } INT_PTR ImportGpGKeys(WPARAM w, LPARAM l) { TCHAR *p = GetFilePath(_T("Choose file to import keys from"), _T("*"), _T("Any file")); if(!p || !p[0]) { delete [] p; //TODO: handle error return 1; } char *path = mir_t2a(p); delete [] p; std::ifstream file; file.open(path, std::ios::in); mir_free(path); if(!file.is_open()) return 1; //TODO: handle error PROTOACCOUNT **accs; int acc_count = 0, processed_keys = 0; ProtoEnumAccounts(&acc_count, &accs); char line[256]; file.getline(line, 255); if(!strstr(line, "-----BEGIN PGP PUBLIC KEY BLOCK-----")) return 1; //TODO: handle error std::string key, login, contact_id; key += line; key += '\n'; while(file.is_open() && !file.eof()) { file.getline(line, 255); key += line; key += '\n'; if(strstr(line, "-----END PGP PUBLIC KEY BLOCK-----")) { //TODO: parse key std::string::size_type p1 = 0, p2 = 0; p1 = key.find("Comment: login "); p1 += strlen("Comment: login "); p2 = key.find(" contact_id "); login = key.substr(p1, p2-p1); p2 += strlen(" contact_id "); p1 = key.find("\n", p2); contact_id = key.substr(p2, p1-p2); p1 = key.find("Comment: login "); p2 = key.find("\n", p1); p2++; key.erase(p1, p2-p1); std::string acc; for(int i = 0; i < acc_count; i++) { if(acc.length()) break; const char * uid = (const char*)CallProtoService(accs[i]->szModuleName, PS_GETCAPS, (WPARAM)PFLAG_UNIQUEIDSETTING, 0); DBVARIANT dbv = {0}; DBCONTACTGETSETTING dbcgs = {0}; dbcgs.pValue = &dbv; dbcgs.szModule = accs[i]->szModuleName; dbcgs.szSetting = uid; CallService(MS_DB_CONTACT_GETSETTING, 0, (LPARAM)&dbcgs); std::string id; switch(dbcgs.pValue->type) { case DBVT_DELETED: continue; break; case DBVT_BYTE: { char _id[64]; mir_snprintf(_id, 63, "%d", dbcgs.pValue->bVal); id += _id; if(id == login) acc = accs[i]->szModuleName; } break; case DBVT_WORD: { char _id[64]; mir_snprintf(_id, 63, "%d", dbcgs.pValue->wVal); id += _id; if(id == login) acc = accs[i]->szModuleName; } break; case DBVT_DWORD: { char _id[64]; mir_snprintf(_id, 63, "%d", dbcgs.pValue->dVal); id += _id; if(id == login) acc = accs[i]->szModuleName; } break; case DBVT_ASCIIZ: { id += dbcgs.pValue->pszVal; CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); if(id == login) acc = accs[i]->szModuleName; } break; case DBVT_UTF8: { char *tmp = mir_utf8decodeA(dbcgs.pValue->pszVal); if(tmp[0]) id += tmp; mir_free(tmp); CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); if(id == login) acc = accs[i]->szModuleName; } break; case DBVT_BLOB: //TODO CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); break; case DBVT_WCHAR: //TODO CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); break; } } if(acc.length()) { const char * uid = (const char*)CallProtoService(acc.c_str(), PS_GETCAPS, (WPARAM)PFLAG_UNIQUEIDSETTING, 0); for(HANDLE hContact = db_find_first(acc.c_str()); hContact; hContact = db_find_next(hContact, acc.c_str())) { DBVARIANT dbv = {0}; DBCONTACTGETSETTING dbcgs = {0}; dbcgs.pValue = &dbv; dbcgs.szModule = acc.c_str(); dbcgs.szSetting = uid; CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&dbcgs); std::string id; bool found = false; switch(dbcgs.pValue->type) { case DBVT_DELETED: continue; break; case DBVT_BYTE: { char _id[64]; mir_snprintf(_id, 63, "%d", dbcgs.pValue->bVal); id += _id; if(id == contact_id) found = true; } break; case DBVT_WORD: { char _id[64]; mir_snprintf(_id, 63, "%d", dbcgs.pValue->wVal); id += _id; if(id == contact_id) found = true; } break; case DBVT_DWORD: { char _id[64]; mir_snprintf(_id, 63, "%d", dbcgs.pValue->dVal); id += _id; if(id == contact_id) found = true; } break; case DBVT_ASCIIZ: { id += dbcgs.pValue->pszVal; CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); if(id == contact_id) found = true; } break; case DBVT_UTF8: { char *tmp = mir_utf8decodeA(dbcgs.pValue->pszVal); if(tmp[0]) id += tmp; mir_free(tmp); CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); if(id == contact_id) found = true; } break; case DBVT_BLOB: //TODO CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); break; case DBVT_WCHAR: //TODO CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv); break; } if(found) { wstring cmd; TCHAR tmp2[MAX_PATH] = {0}; TCHAR *ptmp; string output; DWORD exitcode; { HANDLE hcnt = hContact; 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); f<<toUTF16(key).c_str(); f.close(); cmd += _T(" --batch "); cmd += _T(" --import \""); cmd += tmp2; cmd += _T("\""); } gpg_execution_params params; pxResult result; params.cmd = &cmd; params.useless = ""; params.out = &output; params.code = &exitcode; params.result = &result; boost::thread gpg_thread(boost::bind(&pxEexcute_thread, ¶ms)); if(!gpg_thread.timed_join(boost::posix_time::seconds(10))) { gpg_thread.~thread(); TerminateProcess(params.hProcess, 1); params.hProcess = NULL; debuglog<<time_str()<<": GPG execution timed out, aborted\n"; break; } if(result == pxNotFound) break; if(result == pxSuccess) processed_keys++; { if(output.find("already in secret keyring") != string::npos) { MessageBox(0, _T("Key already in scret key ring."), _T("Info"), MB_OK); DeleteFile(tmp2); break; } char *tmp2; string::size_type s = output.find("gpg: key ") + strlen("gpg: key "); string::size_type s2 = output.find(":", s); tmp2 = new char [output.substr(s,s2-s).length()+1]; strcpy(tmp2, output.substr(s,s2-s).c_str()); mir_utf8decode(tmp2, 0); DBWriteContactSettingString(hContact, szGPGModuleName, "KeyID", tmp2); mir_free(tmp2); s = output.find("“", s2); if(s == string::npos) { s = output.find("\"", s2); s += 1; } else s += 3; if((s2 = output.find("(", s)) == string::npos) s2 = output.find("<", s); else if(s2 > output.find("<", s)) s2 = output.find("<", s); if(s2 != string::npos) { tmp2 = new char [output.substr(s,s2-s-1).length()+1]; strcpy(tmp2, output.substr(s,s2-s-1).c_str()); mir_utf8decode(tmp2, 0); if(hContact) { DBWriteContactSettingString(hContact, szGPGModuleName, "KeyMainName", output.substr(s,s2-s-1).c_str()); } mir_free(tmp2); 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] == ')') { tmp2 = new char [output.substr(s2,s-s2).length()+1]; strcpy(tmp2, output.substr(s2,s-s2).c_str()); mir_utf8decode(tmp2, 0); if(hContact) DBWriteContactSettingString(hContact, szGPGModuleName, "KeyComment", output.substr(s2,s-s2).c_str()); mir_free(tmp2); s+=3; s2 = output.find(">", s); tmp2 = new char [output.substr(s,s2-s).length()+1]; strcpy(tmp2, output.substr(s,s2-s).c_str()); mir_utf8decode(tmp2, 0); if(hContact) DBWriteContactSettingString(hContact, szGPGModuleName, "KeyMainEmail", output.substr(s,s2-s).c_str()); mir_free(tmp2); } else { tmp2 = new char [output.substr(s2,s-s2).length()+1]; strcpy(tmp2, output.substr(s2,s-s2).c_str()); mir_utf8decode(tmp2, 0); if(hContact) DBWriteContactSettingString(hContact, szGPGModuleName, "KeyMainEmail", output.substr(s2,s-s2).c_str()); mir_free(tmp2); } } DBWriteContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 1); DBWriteContactSettingTString(hContact, szGPGModuleName, "GPGPubKey", toUTF16(key).c_str()); } DeleteFile(tmp2); break; } } } key.clear(); } } if(file.is_open()) file.close(); char msg[512]; mir_snprintf(msg, 511, "we have succesfully processed %d keys", processed_keys); MessageBoxA(NULL, msg, Translate("Keys import result"), MB_OK); return 0; }