// 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" 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 _tcsdup(szDef); if(dbv.pszVal) szRes = _tcsdup(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 _strdup(szDef); if(dbv.pszVal) szRes = _strdup(dbv.pszVal); DBFreeVariant(&dbv); return szRes; } char *date() { setlocale( LC_ALL, "C" ); static char d[11]; char *tmp = __DATE__, m[4], mn[3] = "01"; m[0]=tmp[0]; m[1]=tmp[1]; m[2]=tmp[2]; if(strstr(m,"Jan")) strcpy(mn,"01"); else if(strstr(m,"Feb")) strcpy(mn,"02"); else if(strstr(m,"Mar")) strcpy(mn,"03"); else if(strstr(m,"Apr")) strcpy(mn,"04"); else if(strstr(m,"May")) strcpy(mn,"05"); else if(strstr(m,"Jun")) strcpy(mn,"06"); else if(strstr(m,"Jul")) strcpy(mn,"07"); else if(strstr(m,"Aug")) strcpy(mn,"08"); else if(strstr(m,"Sep")) strcpy(mn,"09"); else if(strstr(m,"Oct")) strcpy(mn,"10"); else if(strstr(m,"Nov")) strcpy(mn,"11"); else if(strstr(m,"Dec")) strcpy(mn,"12"); d[0]=tmp[7]; d[1]=tmp[8]; d[2]=tmp[9]; d[3]=tmp[10]; d[4]='.'; d[5]=mn[0]; d[6]=mn[1]; d[7]='.'; if (tmp[4] == ' ') d[8] = '0'; else d[8]=tmp[4]; d[9]=tmp[5]; return d; } 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 LoadKey(WPARAM w, LPARAM l) { void ShowLoadPublicKeyDialog(); extern map user_data; extern int item_num; item_num = 0; //black magic here user_data[1] = (HANDLE)w; ShowLoadPublicKeyDialog(); return 0; } int SendKey(WPARAM w, LPARAM l) { HANDLE hContact = (HANDLE)w; if(isProtoMetaContacts(hContact)) hContact = metaGetMostOnline(hContact); char *szMessage = UniGetContactSettingUtf(NULL, szGPGModuleName, "GPGPubKey", ""); if(strlen(szMessage) > 1) { BYTE enc = DBGetContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 0); DBWriteContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 0); CallContactService(hContact, PSS_MESSAGE, (WPARAM)PREF_UTF, (LPARAM)szMessage); HistoryLog(hContact, "Public key sent", EVENTTYPE_MESSAGE, DBEF_SENT); DBWriteContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", enc); } mir_free(szMessage); return 0; } extern HANDLE hLoadPublicKey, hToggleEncryption; int ToggleEncryption(WPARAM w, LPARAM l) { HANDLE hContact = (HANDLE)w; BYTE enc = 0; if(isProtoMetaContacts(hContact)) enc = DBGetContactSettingByte(metaGetMostOnline(hContact), szGPGModuleName, "GPGEncryption", 0); else enc = DBGetContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 0); { if(isProtoMetaContacts(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); } } } 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(isProtoMetaContacts(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; } int onProtoAck(WPARAM w, LPARAM l) { extern bool bFileTransfers; bool isContactHaveKey(HANDLE); ACKDATA *ack=(ACKDATA*)l; if (ack->type!=ACKTYPE_FILE) return 0; if(!isContactHaveKey(ack->hContact)) return 0; PROTOFILETRANSFERSTATUS *f = (PROTOFILETRANSFERSTATUS*) ack->lParam; if (f && (f->flags & PFTS_SENDING) && !bFileTransfers) return 0; if(!f) f = (PROTOFILETRANSFERSTATUS*) ack->hProcess; switch(ack->result) { case ACKRESULT_DENIED: case ACKRESULT_FAILED: { if(!f->tszWorkingDir) return 0; if(_tcsstr(f->tszCurrentFile, _T(".gpg"))) ; } break; case ACKRESULT_NEXTFILE: case ACKRESULT_FILERESUME: //works only on receiving (than it useless ...) { wstring str = _T("Next:\n"); str.append(f->tszCurrentFile).append(_T("\n")); MessageBox(0, str.c_str(), _T(""), MB_OK); } break; case ACKRESULT_SUCCESS: { if(!f->tszWorkingDir) return 0; if(_tcsstr(f->tszCurrentFile, _T(".gpg"))) { //process encrypted file if(f->flags & PFTS_SENDING) DeleteFile(f->tszCurrentFile); if(f->flags & PFTS_RECEIVING) ; } } break; } return 0; } void storeOutput(HANDLE ahandle, string *output) { BOOL success; char readbuffer[4096] = {0}; unsigned long transfered, available; do { PeekNamedPipe(ahandle,NULL,0,NULL,&available,NULL); if (!available) continue; success=ReadFile(ahandle,readbuffer,sizeof(readbuffer),&transfered,NULL); if (success && transfered) output->append(readbuffer, 4096); } while (available>0); } void HistoryLog(HANDLE hContact, char *data, int event_type, int flags) { DBEVENTINFO Event = {0}; Event.cbSize = sizeof(Event); Event.szModule = szGPGModuleName; Event.eventType = event_type; Event.flags = flags, DBEF_UTF; Event.timestamp = (DWORD)time(NULL); Event.cbBlob = strlen(data)+1; Event.pBlob = (PBYTE)_strdup(data); 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 Accounts; void AddHandlers(); int count = 0; PROTOACCOUNT **accounts; ProtoEnumAccounts(&count, &accounts); list ::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); 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-----")); HXML encrypted_data = xi.addChild(node, _T("x"), data.substr(p1, p2-p1).c_str()); xi.addAttr(encrypted_data, _T("xmlns"), _T("jabber:x:encrypted")); return FALSE; } } if(nodename) { if(_tcsstr(nodename, _T("status"))) { TCHAR *path_c = UniGetContactSettingUtf(NULL, szGPGModuleName, "szHomePath", _T("")); wstring path_out = path_c; mir_free(path_c); path_out += _T("\\prescense_text"); DeleteFile(path_out.c_str()); wfstream f(path_out.c_str(), std::ios::out); char *tmp = mir_utf8encodeW(str); 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 encrypt message from self 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 encrypt message from self with password\n"; cmd += _T("--passphrase \""); cmd += password; cmd += _T("\" "); } else debuglog<<"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("--default-key "); path_c = UniGetContactSettingUtf(NULL, szGPGModuleName, "KeyID", _T("")); 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(10))) { gpg_thread.~thread(); 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_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<<"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"); 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("\\sign.asc"); sign_file_mutex.lock(); DeleteFile(path_out.c_str()); wfstream f(path_out.c_str(), std::ios::out); char *tmp = mir_utf8encodeW(sign.c_str()); f< Accounts; list ::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) DBWriteContactSettingString(hContact, szGPGModuleName, "KeyID_Prescense", out.substr(p1, p2-p1-1).c_str()); } } } } } return FALSE; } } } } local_node = xi.getChild(node, n); } return FALSE; } void AddHandlers() { extern list Accounts; list ::iterator p = Accounts.begin(); for(unsigned int i = 0; i < Accounts.size(); i++, 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)); } } } bool isContactSecured(HANDLE hContact) { TCHAR *key = UniGetContactSettingUtf(hContact, szGPGModuleName, "GPGPubKey", _T("")); if(DBGetContactSettingByte(hContact, szGPGModuleName, "GPGEncryption", 0) && (_tcslen(key) > 0)) { mir_free(key); return true; } mir_free(key); return false; } 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; } #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; } void SecureIM_cleanup() { for (HANDLE hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); hContact; hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0)) { if(CallService(MS_PROTO_ISPROTOONCONTACT, (WPARAM)hContact, (LPARAM)"SecureIM")) CallService(MS_PROTO_REMOVEFROMCONTACT, (WPARAM)hContact, (LPARAM)"SecureIM"); if(CallService(MS_PROTO_ISPROTOONCONTACT, (WPARAM)hContact, (LPARAM)"OTR")) CallService(MS_PROTO_REMOVEFROMCONTACT, (WPARAM)hContact, (LPARAM)"OTR"); if(CallService(MS_PROTO_ISPROTOONCONTACT, (WPARAM)hContact, (LPARAM)"GnuPGPlugin")) CallService(MS_PROTO_REMOVEFROMCONTACT, (WPARAM)hContact, (LPARAM)"GnuPGPlugin"); } }