diff options
Diffstat (limited to 'plugins/New_GPG/src')
-rwxr-xr-x | plugins/New_GPG/src/main.cpp | 209 | ||||
-rwxr-xr-x | plugins/New_GPG/src/messages.cpp | 435 | ||||
-rwxr-xr-x | plugins/New_GPG/src/options.cpp | 201 | ||||
-rwxr-xr-x | plugins/New_GPG/src/ui.cpp | 1643 | ||||
-rwxr-xr-x | plugins/New_GPG/src/ui.h | 109 | ||||
-rwxr-xr-x | plugins/New_GPG/src/utilities.cpp | 16 |
6 files changed, 1260 insertions, 1353 deletions
diff --git a/plugins/New_GPG/src/main.cpp b/plugins/New_GPG/src/main.cpp index db51945fa5..cdd38bebf7 100755 --- a/plugins/New_GPG/src/main.cpp +++ b/plugins/New_GPG/src/main.cpp @@ -18,6 +18,179 @@ #pragma comment(lib, "shlwapi.lib") +///////////////////////////////////////////////////////////////////////////////////////// +// GPG binaries options + +class CDlgGpgBinOpts : public CDlgBase +{ + CCtrlButton btn_SET_BIN_PATH, btn_SET_HOME_DIR, btn_OK, btn_GENERATE_RANDOM; + CCtrlEdit edit_BIN_PATH, edit_HOME_DIR; + CCtrlCheck chk_AUTO_EXCHANGE; + +public: + CDlgGpgBinOpts() : + CDlgBase(g_plugin, IDD_BIN_PATH), + btn_SET_BIN_PATH(this, IDC_SET_BIN_PATH), + btn_SET_HOME_DIR(this, IDC_SET_HOME_DIR), + btn_OK(this, ID_OK), + btn_GENERATE_RANDOM(this, IDC_GENERATE_RANDOM), + edit_BIN_PATH(this, IDC_BIN_PATH), + edit_HOME_DIR(this, IDC_HOME_DIR), + chk_AUTO_EXCHANGE(this, IDC_AUTO_EXCHANGE) + { + btn_SET_BIN_PATH.OnClick = Callback(this, &CDlgGpgBinOpts::onClick_SET_BIN_PATH); + btn_SET_HOME_DIR.OnClick = Callback(this, &CDlgGpgBinOpts::onClick_SET_HOME_DIR); + btn_OK.OnClick = Callback(this, &CDlgGpgBinOpts::onClick_OK); + btn_GENERATE_RANDOM.OnClick = Callback(this, &CDlgGpgBinOpts::onClick_GENERATE_RANDOM); + } + + bool OnInitDialog() override + { + CMStringW path; + bool gpg_exists = false, lang_exists = false; + + wchar_t mir_path[MAX_PATH]; + PathToAbsoluteW(L"\\", mir_path); + SetCurrentDirectoryW(mir_path); + + CMStringW gpg_path(mir_path); gpg_path.Append(L"\\GnuPG\\gpg.exe"); + CMStringW gpg_lang_path(mir_path); gpg_lang_path.Append(L"\\GnuPG\\gnupg.nls\\en@quot.mo"); + + if (boost::filesystem::exists(gpg_path.c_str())) { + gpg_exists = true; + path = L"GnuPG\\gpg.exe"; + } + else path = gpg_path; + + if (boost::filesystem::exists(gpg_lang_path.c_str())) + lang_exists = true; + if (gpg_exists && !lang_exists) + MessageBox(nullptr, TranslateT("GPG binary found in Miranda folder, but English locale does not exist.\nIt's highly recommended that you place \\gnupg.nls\\en@quot.mo in GnuPG folder under Miranda root.\nWithout this file you may experience many problems with GPG output on non-English systems\nand plugin may completely not work.\nYou have been warned."), TranslateT("Warning"), MB_OK); + + DWORD len = MAX_PATH; + bool bad_version = false; + { + ptrW tmp; + if (!gpg_exists) { + tmp = g_plugin.getWStringA("szGpgBinPath", (SHGetValueW(HKEY_CURRENT_USER, L"Software\\GNU\\GnuPG", L"gpgProgram", 0, (void *)path.c_str(), &len) == ERROR_SUCCESS) ? path.c_str() : L""); + if (tmp[0]) + if (!boost::filesystem::exists((wchar_t *)tmp)) + MessageBoxW(nullptr, TranslateT("Wrong GPG binary location found in system.\nPlease choose another location"), TranslateT("Warning"), MB_OK); + } + else tmp = mir_wstrdup(path.c_str()); + + edit_BIN_PATH.SetText(tmp); + if (gpg_exists/* && lang_exists*/) { + g_plugin.setWString("szGpgBinPath", tmp); + + gpg_execution_params params; + params.addParam(L"--version"); + bool _gpg_valid = globals.gpg_valid; + globals.gpg_valid = true; + gpg_launcher(params); + globals.gpg_valid = _gpg_valid; //TODO: check this + g_plugin.delSetting("szGpgBinPath"); + int p1 = params.out.Find("(GnuPG) "); + if (p1 != -1) { + p1 += mir_strlen("(GnuPG) "); + if (params.out[p1] != '1') + bad_version = true; + } + else { + bad_version = false; + MessageBox(nullptr, TranslateT("This is not GnuPG binary!\nIt is recommended that you use GnuPG v1.x.x with this plugin."), TranslateT("Error"), MB_OK); + } + if (bad_version) + MessageBox(nullptr, TranslateT("Unsupported GnuPG version found, use at you own risk!\nIt is recommended that you use GnuPG v1.x.x with this plugin."), TranslateT("Warning"), MB_OK); + } + } + + CMStringW tmp(g_plugin.getMStringW("szHomePath")); + if (tmp.IsEmpty()) { + mir_wstrcat(mir_path, L"\\gpg"); + if (_waccess(mir_path, 0) != -1) { + tmp = mir_path; + MessageBoxW(nullptr, TranslateT("\"GPG\" directory found in Miranda root.\nAssuming it's GPG home directory.\nGPG home directory set."), TranslateT("Info"), MB_OK); + } + else { + wstring path_ = _wgetenv(L"APPDATA"); + path_ += L"\\GnuPG"; + tmp = path_.c_str(); + } + } + edit_HOME_DIR.SetText(!gpg_exists ? tmp : L"gpg"); + + // TODO: additional check for write access + if (gpg_exists && lang_exists && !bad_version) + MessageBox(nullptr, TranslateT("Your GPG version is supported. The language file was found.\nGPG plugin should work fine.\nPress OK to continue."), TranslateT("Info"), MB_OK); + chk_AUTO_EXCHANGE.Enable(); + return true; + } + + void OnDestroy() override + { + void InitCheck(); + InitCheck(); + } + + void onClick_SET_BIN_PATH(CCtrlButton *) + { + GetFilePath(L"Choose gpg.exe", "szGpgBinPath", L"*.exe", L"EXE Executables"); + CMStringW tmp(g_plugin.getMStringW("szGpgBinPath", L"gpg.exe")); + edit_BIN_PATH.SetText(tmp); + + wchar_t mir_path[MAX_PATH]; + PathToAbsoluteW(L"\\", mir_path); + if (tmp.Find(mir_path, 0) == 0) { + CMStringW path = tmp.Mid(mir_wstrlen(mir_path)); + edit_BIN_PATH.SetText(path); + } + } + + void onClick_SET_HOME_DIR(CCtrlButton *) + { + GetFolderPath(L"Set home directory"); + CMStringW tmp(g_plugin.getMStringW("szHomePath")); + edit_HOME_DIR.SetText(tmp); + + wchar_t mir_path[MAX_PATH]; + PathToAbsoluteW(L"\\", mir_path); + PathToAbsoluteW(L"\\", mir_path); + if (tmp.Find(mir_path, 0) == 0) { + CMStringW path = tmp.Mid(mir_wstrlen(mir_path)); + edit_HOME_DIR.SetText(path); + } + } + + void onClick_OK(CCtrlButton *) + { + if (gpg_validate_paths(edit_BIN_PATH.GetText(), edit_HOME_DIR.GetText())) { + gpg_save_paths(edit_BIN_PATH.GetText(), edit_HOME_DIR.GetText()); + globals.gpg_valid = true; + g_plugin.setByte("FirstRun", 0); + this->Hide(); + this->Close(); + ShowFirstRunDialog(); + } + } + + void onClick_GENERATE_RANDOM(CCtrlButton *) + { + if (gpg_validate_paths(edit_BIN_PATH.GetText(), edit_HOME_DIR.GetText())) { + gpg_save_paths(edit_BIN_PATH.GetText(), edit_HOME_DIR.GetText()); + globals.gpg_valid = true; + if (gpg_use_new_random_key(nullptr)) { + g_plugin.bAutoExchange = chk_AUTO_EXCHANGE.GetState(); + globals.gpg_valid = true; + g_plugin.setByte("FirstRun", 0); + this->Close(); + } + } + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// + static int EnumProc(const char *szSetting, void *param) { auto *list = (OBJLIST<CMStringA> *)param; @@ -49,10 +222,8 @@ void FirstRun() g_plugin.setByte("CompatLevel", 1); } - if (!g_plugin.getByte("FirstRun", 1)) - return; - CDlgGpgBinOpts *d = new CDlgGpgBinOpts; - d->Show(); + if (g_plugin.getByte("FirstRun", 1)) + (new CDlgGpgBinOpts())->Show(); } void InitCheck() @@ -134,10 +305,8 @@ void InitCheck() wszQuestion += TranslateT(" for account "); wszQuestion += pa->tszAccountName; wszQuestion += TranslateT(" deleted from GPG secret keyring.\nDo you want to set another key?"); - if (MessageBoxW(nullptr, wszQuestion, TranslateT("Own secret key warning"), MB_YESNO) == IDYES) { - CDlgFirstRun *d = new CDlgFirstRun; - d->DoModal(); - } + if (MessageBoxW(nullptr, wszQuestion, TranslateT("Own secret key warning"), MB_YESNO) == IDYES) + ShowFirstRunDialog(); } p2 = p; p = out.find("[", p); @@ -174,10 +343,8 @@ void InitCheck() wszQuestion += TranslateT(" for account "); wszQuestion += pa->tszAccountName; wszQuestion += TranslateT(" expired and will not work.\nDo you want to set another key?"); - if (MessageBoxW(nullptr, wszQuestion.c_str(), TranslateT("Own secret key warning"), MB_YESNO) == IDYES) { - CDlgFirstRun *d = new CDlgFirstRun; - d->DoModal(); - } + if (MessageBoxW(nullptr, wszQuestion.c_str(), TranslateT("Own secret key warning"), MB_YESNO) == IDYES) + ShowFirstRunDialog(); } mir_free(expire_date); } @@ -189,18 +356,14 @@ void InitCheck() CMStringA key(g_plugin.getMStringA("GPGPubKey")); if (!g_plugin.getByte("FirstRun", 1) && (keyid.IsEmpty() || key.IsEmpty())) { wszQuestion = TranslateT("You didn't set a private key.\nWould you like to set it now?"); - if (MessageBoxW(nullptr, wszQuestion, TranslateT("Own private key warning"), MB_YESNO) == IDYES) { - CDlgFirstRun *d = new CDlgFirstRun; - d->DoModal(); - } + if (MessageBoxW(nullptr, wszQuestion, TranslateT("Own private key warning"), MB_YESNO) == IDYES) + ShowFirstRunDialog(); } if ((p = out.find(keyid)) == string::npos) { wszQuestion += keyid; wszQuestion += TranslateT(" deleted from GPG secret keyring.\nDo you want to set another key?"); - if (MessageBoxW(nullptr, wszQuestion, TranslateT("Own secret key warning"), MB_YESNO) == IDYES) { - CDlgFirstRun *d = new CDlgFirstRun; - d->DoModal(); - } + if (MessageBoxW(nullptr, wszQuestion, TranslateT("Own secret key warning"), MB_YESNO) == IDYES) + ShowFirstRunDialog(); } p2 = p; p = out.find("[", p); @@ -235,10 +398,8 @@ void InitCheck() if (expired) { wszQuestion += keyid; wszQuestion += TranslateT(" expired and will not work.\nDo you want to set another key?"); - if (MessageBoxW(nullptr, wszQuestion, TranslateT("Own secret key warning"), MB_YESNO) == IDYES) { - CDlgFirstRun *d = new CDlgFirstRun; - d->DoModal(); - } + if (MessageBoxW(nullptr, wszQuestion, TranslateT("Own secret key warning"), MB_YESNO) == IDYES) + ShowFirstRunDialog(); } mir_free(expire_date); } diff --git a/plugins/New_GPG/src/messages.cpp b/plugins/New_GPG/src/messages.cpp index f5deedd289..f446f5907e 100755 --- a/plugins/New_GPG/src/messages.cpp +++ b/plugins/New_GPG/src/messages.cpp @@ -37,287 +37,259 @@ static void RecvMsgSvc_func(RecvParams *param) { MCONTACT hContact = param->hContact; std::string szScreenName(toUTF8(Clist_GetContactDisplayName(hContact))); - { - // check for gpg related data - wstring::size_type s1 = param->str.find(L"-----BEGIN PGP MESSAGE-----"); - wstring::size_type s2 = param->str.find(L"-----END PGP MESSAGE-----"); - if (s2 != wstring::npos && s1 != wstring::npos) { //this is generic encrypted data block - if (!isContactSecured(hContact)) { - if (globals.debuglog) - globals.debuglog << "info: received encrypted message from: " + szScreenName + " with turned off encryption"; - if (MessageBox(nullptr, TranslateT("We received encrypted message from contact with encryption turned off.\nDo you want to turn on encryption for this contact?"), TranslateT("Warning"), MB_YESNO) == IDYES) { - if (!isContactHaveKey(hContact)) - ShowLoadPublicKeyDialog(hContact, true); - else { - g_plugin.setByte(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "GPGEncryption", 1); - setSrmmIcon(hContact); - } - if (isContactHaveKey(hContact)) { - g_plugin.setByte(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "GPGEncryption", 1); - setSrmmIcon(hContact); - } + // check for gpg related data + wstring::size_type s1 = param->str.find(L"-----BEGIN PGP MESSAGE-----"); + wstring::size_type s2 = param->str.find(L"-----END PGP MESSAGE-----"); + if (s2 != wstring::npos && s1 != wstring::npos) { //this is generic encrypted data block + if (!isContactSecured(hContact)) { + if (globals.debuglog) + globals.debuglog << "info: received encrypted message from: " + szScreenName + " with turned off encryption"; + if (MessageBox(nullptr, TranslateT("We received encrypted message from contact with encryption turned off.\nDo you want to turn on encryption for this contact?"), TranslateT("Warning"), MB_YESNO) == IDYES) { + if (!isContactHaveKey(hContact)) + ShowLoadPublicKeyDialog(hContact, true); + else { + g_plugin.setByte(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "GPGEncryption", 1); + setSrmmIcon(hContact); } - else if (MessageBox(nullptr, TranslateT("Do you want to try to decrypt encrypted message?"), TranslateT("Warning"), MB_YESNO) == IDNO) { - HistoryLog(hContact, param->msg.c_str(), param->timestamp); - delete param; - return; + + if (isContactHaveKey(hContact)) { + g_plugin.setByte(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "GPGEncryption", 1); + setSrmmIcon(hContact); } } - else if (globals.debuglog) - globals.debuglog << "info: received encrypted message from: " + szScreenName; - boost::algorithm::erase_all(param->str, "\r"); - s2 += mir_wstrlen(L"-----END PGP MESSAGE-----"); - - ptrW ptszHomePath(g_plugin.getWStringA("szHomePath", L"")); - wstring encfile = toUTF16(get_random(10)); - wstring decfile = toUTF16(get_random(10)); - { - wstring path = wstring(ptszHomePath) + L"\\tmp\\" + encfile; - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(path, e); - } - - { - const int timeout = 5000, step = 100; - int count = 0; + else if (MessageBox(nullptr, TranslateT("Do you want to try to decrypt encrypted message?"), TranslateT("Warning"), MB_YESNO) == IDNO) { + HistoryLog(hContact, param->msg.c_str(), param->timestamp); + delete param; + return; + } + } + else if (globals.debuglog) + globals.debuglog << "info: received encrypted message from: " + szScreenName; + boost::algorithm::erase_all(param->str, "\r"); + s2 += mir_wstrlen(L"-----END PGP MESSAGE-----"); + + ptrW ptszHomePath(g_plugin.getWStringA("szHomePath", L"")); + wstring encfile = toUTF16(get_random(10)); + wstring decfile = toUTF16(get_random(10)); + { + wstring path = wstring(ptszHomePath) + L"\\tmp\\" + encfile; + if (!globals.debuglog) { + boost::system::error_code e; + boost::filesystem::remove(path, e); + } - fstream f(path.c_str(), std::ios::out); - while (!f.is_open()) { - ::Sleep(step); - count += step; - if (count >= timeout) { - g_plugin.setByte(hContact, "GPGEncryption", 0); - setSrmmIcon(hContact); - globals.debuglog << "info: failed to create temporary file for decryption, disabling gpg for contact to avoid deadlock"; - delete param; - return; - } - f.open(path.c_str(), std::ios::out); + { + const int timeout = 5000, step = 100; + int count = 0; + + fstream f(path.c_str(), std::ios::out); + while (!f.is_open()) { + ::Sleep(step); + count += step; + if (count >= timeout) { + g_plugin.setByte(hContact, "GPGEncryption", 0); + setSrmmIcon(hContact); + globals.debuglog << "info: failed to create temporary file for decryption, disabling gpg for contact to avoid deadlock"; + delete param; + return; } - char *tmp = mir_u2a(param->str.substr(s1, s2 - s1).c_str()); - f << tmp; - mir_free(tmp); - f.close(); + f.open(path.c_str(), std::ios::out); } + char *tmp = mir_u2a(param->str.substr(s1, s2 - s1).c_str()); + f << tmp; + mir_free(tmp); + f.close(); + } - gpg_execution_params params; - params.addParam(L"--batch"); - { - CMStringA inkeyid = g_plugin.getMStringA(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "InKeyID"); - CMStringW pass; - if (!inkeyid.IsEmpty()) { - string dbsetting = "szKey_"; - dbsetting += inkeyid; - dbsetting += "_Password"; - pass = g_plugin.getMStringW(dbsetting.c_str()); - if (!pass.IsEmpty() && globals.debuglog) - globals.debuglog << "info: found password in database for key ID: " + string(inkeyid.c_str()) + ", trying to decrypt message from " + szScreenName + " with password"; - } - else { - pass = g_plugin.getMStringW("szKeyPassword"); - if (!pass.IsEmpty() && globals.debuglog) - globals.debuglog << "info: found password for all keys in database, trying to decrypt message from " + szScreenName + " with password"; - } - if (!pass.IsEmpty()) { - params.addParam(L"--passphrase"); - params.addParam(pass.c_str()); - } - else if (!globals.wszPassword.IsEmpty()) { - if (globals.debuglog) - globals.debuglog << "info: found password in memory, trying to decrypt message from " + szScreenName + " with password"; - params.addParam(L"--passphrase"); - params.addParam(globals.wszPassword.c_str()); - } - else if (globals.debuglog) - globals.debuglog << "info: passwords not found in database or memory, trying to decrypt message from " + szScreenName + " without password"; + gpg_execution_params params; + params.addParam(L"--batch"); + { + CMStringA inkeyid = g_plugin.getMStringA(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "InKeyID"); + CMStringW pass; + if (!inkeyid.IsEmpty()) { + string dbsetting = "szKey_"; + dbsetting += inkeyid; + dbsetting += "_Password"; + pass = g_plugin.getMStringW(dbsetting.c_str()); + if (!pass.IsEmpty() && globals.debuglog) + globals.debuglog << "info: found password in database for key ID: " + string(inkeyid.c_str()) + ", trying to decrypt message from " + szScreenName + " with password"; + } + else { + pass = g_plugin.getMStringW("szKeyPassword"); + if (!pass.IsEmpty() && globals.debuglog) + globals.debuglog << "info: found password for all keys in database, trying to decrypt message from " + szScreenName + " with password"; } + if (!pass.IsEmpty()) { + params.addParam(L"--passphrase"); + params.addParam(pass.c_str()); + } + else if (!globals.wszPassword.IsEmpty()) { + if (globals.debuglog) + globals.debuglog << "info: found password in memory, trying to decrypt message from " + szScreenName + " with password"; + params.addParam(L"--passphrase"); + params.addParam(globals.wszPassword.c_str()); + } + else if (globals.debuglog) + globals.debuglog << "info: passwords not found in database or memory, trying to decrypt message from " + szScreenName + " without password"; + } + + if (!globals.debuglog) { + boost::system::error_code e; + boost::filesystem::remove(wstring(ptszHomePath) + L"\\tmp\\" + decfile, e); + } + params.addParam(L"--output"); + params.addParam(std::wstring(ptszHomePath) + L"\\tmp\\" + decfile); + params.addParam(L"-d"); + params.addParam(L"-a"); + params.addParam(path); + + bool bRes = gpg_launcher(params); + if (!bRes || params.result == pxNotFound) { if (!globals.debuglog) { boost::system::error_code e; - boost::filesystem::remove(wstring(ptszHomePath) + L"\\tmp\\" + decfile, e); + boost::filesystem::remove(path, e); } - params.addParam(L"--output"); - params.addParam(std::wstring(ptszHomePath) + L"\\tmp\\" + decfile); - params.addParam(L"-d"); - params.addParam(L"-a"); - params.addParam(path); - - if (!gpg_launcher(params)) { - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(path, e); - } - HistoryLog(hContact, param->msg.c_str(), param->timestamp); + SendErrorMessage(hContact); + HistoryLog(hContact, TranslateU("GPG cannot decrypt imcoming message"), param->timestamp); + delete param; + return; + } + + // TODO: check gpg output for errors + globals._terminate = false; + + string out(params.out); + while (out.find("public key decryption failed: bad passphrase") != string::npos) { + if (globals.debuglog) + globals.debuglog << "info: failed to decrypt messaage from " + szScreenName + " password needed, trying to get one"; + if (globals._terminate) { SendErrorMessage(hContact); - delete param; - return; + break; } - if (params.result == pxNotFound) { - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(path, e); - } - - HistoryLog(hContact, param->msg.c_str(), param->timestamp); - delete param; - return; + { + // save inkey id + string::size_type s = out.find(" encrypted with "); + s = out.find(" ID ", s); + s += mir_strlen(" ID "); + g_plugin.setString(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "InKeyID", out.substr(s, out.find(",", s) - s).c_str()); } - // TODO: check gpg output for errors - globals._terminate = false; + CDlgKeyPasswordMsgBox(hContact).DoModal(); - string out(params.out); - while (out.find("public key decryption failed: bad passphrase") != string::npos) { + gpg_execution_params params2; + params2.aargv = params.aargv; + if (!globals.wszPassword.IsEmpty()) { if (globals.debuglog) - globals.debuglog << "info: failed to decrypt messaage from " + szScreenName + " password needed, trying to get one"; - if (globals._terminate) { - SendErrorMessage(hContact); - break; - } - { //save inkey id - string::size_type s = out.find(" encrypted with "); - s = out.find(" ID ", s); - s += mir_strlen(" ID "); - g_plugin.setString(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "InKeyID", out.substr(s, out.find(",", s) - s).c_str()); - } - - CDlgKeyPasswordMsgBox *d = new CDlgKeyPasswordMsgBox(hContact); - d->DoModal(); + globals.debuglog << "info: found password in memory, trying to decrypt message from " + szScreenName; - gpg_execution_params params2; - params2.aargv = params.aargv; - if (!globals.wszPassword.IsEmpty()) { - if (globals.debuglog) - globals.debuglog << "info: found password in memory, trying to decrypt message from " + szScreenName; - - params2.addParam(L"--passphrase"); - params2.addParam(globals.wszPassword.c_str()); - } - - if (!gpg_launcher(params2)) { - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(path, e); - } - - HistoryLog(hContact, param->msg.c_str(), param->timestamp); - SendErrorMessage(hContact); - delete param; - return; - } - if (params2.result == pxNotFound) { - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(path, e); - } - - HistoryLog(hContact, param->msg.c_str(), param->timestamp); - delete param; - return; - } + params2.addParam(L"--passphrase"); + params2.addParam(globals.wszPassword.c_str()); } - out.clear(); - if (!gpg_launcher(params)) { + + bRes = gpg_launcher(params2); + if (!bRes || params2.result == pxNotFound) { if (!globals.debuglog) { boost::system::error_code e; boost::filesystem::remove(path, e); } - HistoryLog(hContact, param->msg.c_str(), param->timestamp); + HistoryLog(hContact, TranslateU("GPG cannot decrypt imcoming message"), param->timestamp); SendErrorMessage(hContact); delete param; return; } - - if (params.result == pxNotFound) { - if (!globals.debuglog) { - boost::system::error_code e; - boost::filesystem::remove(path, e); - } - - HistoryLog(hContact, param->msg.c_str(), param->timestamp); - } - + } + + out.clear(); + bRes = gpg_launcher(params); + if (!bRes || params.result == pxNotFound) { if (!globals.debuglog) { boost::system::error_code e; - boost::filesystem::remove(wstring(ptszHomePath) + L"\\tmp\\" + encfile, e); + boost::filesystem::remove(path, e); } - if (!boost::filesystem::exists(wstring(ptszHomePath) + L"\\tmp\\" + decfile)) { - string str1 = param->msg; - str1.insert(0, "Received unencrypted message:\n"); - if (globals.debuglog) - globals.debuglog << "info: Failed to decrypt GPG encrypted message."; + HistoryLog(hContact, TranslateU("GPG cannot decrypt imcoming message"), param->timestamp); + SendErrorMessage(hContact); + delete param; + return; + } - ptrA tmp4((char*)mir_alloc(sizeof(char)*(str1.length() + 1))); - mir_strcpy(tmp4, str1.c_str()); - HistoryLog(hContact, param->msg.c_str(), param->timestamp); - SendErrorMessage(hContact); - delete param; - return; - } + if (!globals.debuglog) { + boost::system::error_code e; + boost::filesystem::remove(wstring(ptszHomePath) + L"\\tmp\\" + encfile, e); + } - param->str.clear(); + if (!boost::filesystem::exists(wstring(ptszHomePath) + L"\\tmp\\" + decfile)) { + if (globals.debuglog) + globals.debuglog << "info: Failed to decrypt GPG encrypted message."; - wstring tszDecPath = wstring(ptszHomePath) + L"\\tmp\\" + decfile; - { - fstream f(tszDecPath.c_str(), std::ios::in | std::ios::ate | std::ios::binary); - if (f.is_open()) { - size_t size = f.tellg(); - char *tmp = new char[size + 1]; - f.seekg(0, std::ios::beg); - f.read(tmp, size); - tmp[size] = '\0'; - toUTF16(tmp); - param->str.append(toUTF16(tmp)); - delete[] tmp; - f.close(); - if (!globals.debuglog) { - boost::system::error_code ec; - boost::filesystem::remove(tszDecPath, ec); - if (ec) { - //TODO: handle error - } - } + string str1 = param->msg; + str1.insert(0, "\n"); + str1.insert(0, TranslateU("Received unencrypted message:")); + + HistoryLog(hContact, str1.c_str(), param->timestamp); + SendErrorMessage(hContact); + delete param; + return; + } + + param->str.clear(); + + wstring tszDecPath = wstring(ptszHomePath) + L"\\tmp\\" + decfile; + + fstream f(tszDecPath.c_str(), std::ios::in | std::ios::ate | std::ios::binary); + if (f.is_open()) { + size_t size = f.tellg(); + char *tmp = new char[size + 1]; + f.seekg(0, std::ios::beg); + f.read(tmp, size); + tmp[size] = '\0'; + + param->str.append(toUTF16(tmp)); + delete[] tmp; + f.close(); + if (!globals.debuglog) { + boost::system::error_code ec; + boost::filesystem::remove(tszDecPath, ec); + if (ec) { + //TODO: handle error } } - if (param->str.empty()) { - string szMsg = param->msg; - szMsg.insert(0, "Failed to decrypt GPG encrypted message.\nMessage body for manual decryption:\n"); - if (globals.debuglog) - globals.debuglog << "info: Failed to decrypt GPG encrypted message."; + } - HistoryLog(hContact, param->msg.c_str(), param->timestamp); - SendErrorMessage(hContact); - delete param; - return; - } + if (param->str.empty()) { + if (globals.debuglog) + globals.debuglog << "info: Failed to decrypt GPG encrypted message."; - fix_line_term(param->str); - if (g_plugin.bAppendTags) { - param->str.insert(0, globals.wszInopentag); - param->str.append(globals.wszInclosetag); - } + string szMsg = param->msg; + szMsg.insert(0, TranslateU("Failed to decrypt GPG encrypted message.\nMessage body for manual decryption:\n")); - char *tmp = mir_strdup(toUTF8(param->str).c_str()); - HistoryLog(hContact, tmp, param->timestamp); - mir_free(tmp); + HistoryLog(hContact, param->msg.c_str(), param->timestamp); + SendErrorMessage(hContact); delete param; return; } + + fix_line_term(param->str); + if (g_plugin.bAppendTags) { + param->str.insert(0, globals.wszInopentag); + param->str.append(globals.wszInclosetag); + } + + HistoryLog(hContact, toUTF8(param->str).c_str(), param->timestamp); + delete param; + return; } } - if (g_plugin.getByte(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "GPGEncryption")) { + if (g_plugin.getByte(db_mc_isMeta(hContact) ? metaGetMostOnline(hContact) : hContact, "GPGEncryption")) HistoryLog(hContact, param->msg.c_str(), param->timestamp, DBEF_READ); - delete param; - return; - } + else + HistoryLog(hContact, param->msg.c_str(), param->timestamp); - HistoryLog(hContact, param->msg.c_str(), param->timestamp); delete param; } @@ -326,9 +298,11 @@ INT_PTR RecvMsgSvc(WPARAM w, LPARAM l) CCSDATA *ccs = (CCSDATA*)l; if (!ccs) return Proto_ChainRecv(w, ccs); + PROTORECVEVENT *pre = (PROTORECVEVENT*)(ccs->lParam); if (!pre) return Proto_ChainRecv(w, ccs); + char *msg = pre->szMessage; if (!msg) return Proto_ChainRecv(w, ccs); @@ -342,6 +316,7 @@ INT_PTR RecvMsgSvc(WPARAM w, LPARAM l) return 0; } } + wstring str = toUTF16(msg); size_t s1, s2; if (g_plugin.bAutoExchange && (str.find(L"-----PGP KEY RESPONSE-----") != wstring::npos)) { diff --git a/plugins/New_GPG/src/options.cpp b/plugins/New_GPG/src/options.cpp index 2f2b61d5ea..485c7b431c 100755 --- a/plugins/New_GPG/src/options.cpp +++ b/plugins/New_GPG/src/options.cpp @@ -21,6 +21,201 @@ globals_s globals; HWND hwndCurKey_p = nullptr; ///////////////////////////////////////////////////////////////////////////////////////// +// Load existing key dialog + +class CDlgLoadExistingKey : public CDlgBase +{ + wchar_t id[16]; + CCtrlListView list_EXISTING_KEY_LIST; + +public: + CDlgLoadExistingKey() : + CDlgBase(g_plugin, IDD_LOAD_EXISTING_KEY), + list_EXISTING_KEY_LIST(this, IDC_EXISTING_KEY_LIST) + { + id[0] = 0; + } + + bool OnInitDialog() override + { + Utils_RestoreWindowPosition(m_hwnd, 0, MODULENAME, "LoadKeyWindow"); + + list_EXISTING_KEY_LIST.AddColumn(0, TranslateT("Key ID"), 50); + list_EXISTING_KEY_LIST.AddColumn(1, TranslateT("Email"), 30); + list_EXISTING_KEY_LIST.AddColumn(2, TranslateT("Name"), 250); + list_EXISTING_KEY_LIST.AddColumn(3, TranslateT("Creation date"), 30); + list_EXISTING_KEY_LIST.AddColumn(4, TranslateT("Expiration date"), 30); + list_EXISTING_KEY_LIST.AddColumn(5, TranslateT("Key length"), 30); + list_EXISTING_KEY_LIST.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_SINGLEROW); + int i = 1; + + // parse gpg output + gpg_execution_params params; + params.addParam(L"--batch"); + params.addParam(L"--list-keys"); + if (!gpg_launcher(params)) + return false; + if (params.result == pxNotFound) + return false; + + string out(params.out); + string::size_type p = 0, p2 = 0, stop = 0; + while (p != string::npos) { + if ((p = out.find("pub ", p)) == string::npos) + break; + p += 5; + if (p < stop) + break; + stop = p; + p2 = out.find("/", p) - 1; + + int row = list_EXISTING_KEY_LIST.AddItem(L"", 0); + list_EXISTING_KEY_LIST.SetItemText(row, 5, toUTF16(out.substr(p, p2 - p)).c_str()); + + p2 += 2; + p = out.find(" ", p2); + list_EXISTING_KEY_LIST.SetItemText(row, 0, toUTF16(out.substr(p2, p - p2)).c_str()); + + p++; + p2 = out.find("\n", p); + string::size_type p3 = out.substr(p, p2 - p).find("["); + if (p3 != string::npos) { + p3 += p; + p2 = p3; + p2--; + p3++; + p3 += mir_strlen("expires: "); + string::size_type p4 = out.find("]", p3); + list_EXISTING_KEY_LIST.SetItemText(row, 4, toUTF16(out.substr(p3, p4 - p3)).c_str()); + } + else p2--; + + list_EXISTING_KEY_LIST.SetItemText(row, 3, toUTF16(out.substr(p, p2 - p)).c_str()); + + p = out.find("uid ", p); + p += mir_strlen("uid "); + p2 = out.find("\n", p); + p3 = out.substr(p, p2 - p).find("<"); + if (p3 != string::npos) { + p3 += p; + p2 = p3; + p2--; + p3++; + string::size_type p4 = out.find(">", p3); + list_EXISTING_KEY_LIST.SetItemText(row, 1, toUTF16(out.substr(p3, p4 - p3)).c_str()); + } + else p2--; + + p = out.find_first_not_of(" ", p); + list_EXISTING_KEY_LIST.SetItemText(row, 2, toUTF16(out.substr(p, p2 - p)).c_str()); + + list_EXISTING_KEY_LIST.SetColumnWidth(0, LVSCW_AUTOSIZE);// not sure about this + list_EXISTING_KEY_LIST.SetColumnWidth(1, LVSCW_AUTOSIZE); + list_EXISTING_KEY_LIST.SetColumnWidth(2, LVSCW_AUTOSIZE); + list_EXISTING_KEY_LIST.SetColumnWidth(3, LVSCW_AUTOSIZE); + list_EXISTING_KEY_LIST.SetColumnWidth(4, LVSCW_AUTOSIZE); + list_EXISTING_KEY_LIST.SetColumnWidth(5, LVSCW_AUTOSIZE); + i++; + } + + list_EXISTING_KEY_LIST.OnClick = Callback(this, &CDlgLoadExistingKey::onChange_EXISTING_KEY_LIST); + return true; + } + + bool OnApply() override + { + int i = list_EXISTING_KEY_LIST.GetSelectionMark(); + if (i == -1) + return false; //TODO: error message + + list_EXISTING_KEY_LIST.GetItemText(i, 0, id, _countof(id)); + extern CCtrlEdit *edit_p_PubKeyEdit; + + gpg_execution_params params; + params.addParam(L"--batch"); + params.addParam(L"-a"); + params.addParam(L"--export"); + params.addParam(id); + if (!gpg_launcher(params)) + return false; + if (params.result == pxNotFound) + return false; + + string out(params.out); + size_t p1 = out.find("-----BEGIN PGP PUBLIC KEY BLOCK-----"); + if (p1 != std::string::npos) { + size_t p2 = out.find("-----END PGP PUBLIC KEY BLOCK-----", p1); + if (p2 != std::string::npos) { + p2 += mir_strlen("-----END PGP PUBLIC KEY BLOCK-----"); + out = out.substr(p1, p2 - p1); + if (edit_p_PubKeyEdit) + edit_p_PubKeyEdit->SetText(_A2T(out.c_str())); + } + else MessageBox(nullptr, TranslateT("Failed to export public key."), TranslateT("Error"), MB_OK); + } + else MessageBox(nullptr, TranslateT("Failed to export public key."), TranslateT("Error"), MB_OK); + + return true; + } + + void OnDestroy() override + { + Utils_SaveWindowPosition(m_hwnd, 0, MODULENAME, "LoadKeyWindow"); + } + + void onChange_EXISTING_KEY_LIST(CCtrlListView::TEventInfo *) + { + EnableWindow(GetDlgItem(m_hwnd, IDOK), TRUE); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// Import key dialog + +class CDlgImportKey : public CDlgBase +{ + MCONTACT hContact; + CCtrlCombo combo_KEYSERVER; + CCtrlButton btn_IMPORT; + +public: + CDlgImportKey(MCONTACT _hContact) : + CDlgBase(g_plugin, IDD_IMPORT_KEY), + combo_KEYSERVER(this, IDC_KEYSERVER), + btn_IMPORT(this, IDC_IMPORT) + { + hContact = _hContact; + btn_IMPORT.OnClick = Callback(this, &CDlgImportKey::onClick_IMPORT); + } + + bool OnInitDialog() override + { + Utils_RestoreWindowPosition(m_hwnd, 0, MODULENAME, "ImportKeyWindow"); + + combo_KEYSERVER.AddString(L"subkeys.pgp.net"); + combo_KEYSERVER.AddString(L"keys.gnupg.net"); + return true; + } + + void OnDestroy() override + { + Utils_SaveWindowPosition(m_hwnd, 0, MODULENAME, "ImportKeyWindow"); + } + + void onClick_IMPORT(CCtrlButton *) + { + gpg_execution_params params; + params.addParam(L"--keyserver"); + params.addParam(combo_KEYSERVER.GetText()); + params.addParam(L"--recv-keys"); + params.addParam(toUTF16(globals.hcontact_data[hContact].key_in_prescense)); + gpg_launcher(params); + + MessageBoxA(nullptr, params.out.c_str(), "GPG output", MB_OK); + } +}; + +///////////////////////////////////////////////////////////////////////////////////////// // COptGpgMainDlg class static class COptGpgMainDlg *g_pMainDlg; @@ -232,8 +427,7 @@ public: void onClick_SELECT_KEY(CCtrlButton*) { - CDlgFirstRun *d = new CDlgFirstRun; - d->Show(); + ShowFirstRunDialog(); } void onClick_SAVE_KEY_BUTTON(CCtrlButton*) @@ -626,8 +820,7 @@ public: void onClick_SELECT_EXISTING(CCtrlButton*) { - CDlgLoadExistingKey *d = new CDlgLoadExistingKey; - d->Show(); + (new CDlgLoadExistingKey())->Show(); } void onClick_OK(CCtrlButton*) diff --git a/plugins/New_GPG/src/ui.cpp b/plugins/New_GPG/src/ui.cpp index afd9c00def..8f0d9e8950 100755 --- a/plugins/New_GPG/src/ui.cpp +++ b/plugins/New_GPG/src/ui.cpp @@ -54,741 +54,774 @@ void CDlgEncryptedFileMsgBox::onClick_DECRYPT(CCtrlButton*) ///////////////////////////////////////////////////////////////////////////////////////// -CDlgExportKeysMsgBox::CDlgExportKeysMsgBox() : - CDlgBase(g_plugin, IDD_EXPORT_TYPE), - chk_PUBLIC(this, IDC_PUBLIC), - chk_PRIVATE(this, IDC_PRIVATE), - chk_ALL(this, IDC_ALL) +class CDlgExportKeysMsgBox : public CDlgBase { -} + CCtrlCheck chk_PUBLIC, chk_PRIVATE, chk_ALL; -bool CDlgExportKeysMsgBox::OnInitDialog() -{ - chk_PUBLIC.SetState(1); - return true; -} +public: + CDlgExportKeysMsgBox() : + CDlgBase(g_plugin, IDD_EXPORT_TYPE), + chk_PUBLIC(this, IDC_PUBLIC), + chk_PRIVATE(this, IDC_PRIVATE), + chk_ALL(this, IDC_ALL) + { + } -bool CDlgExportKeysMsgBox::OnApply() + bool OnInitDialog() override + { + chk_PUBLIC.SetState(true); + return true; + } + + bool OnApply() override + { + if (chk_PUBLIC.GetState()) + ExportGpGKeysFunc(0); + else if (chk_PRIVATE.GetState()) + ExportGpGKeysFunc(1); + else if (chk_ALL.GetState()) + ExportGpGKeysFunc(2); + return true; + } +}; + +INT_PTR ExportGpGKeys(WPARAM, LPARAM) { - if (chk_PUBLIC.GetState()) - ExportGpGKeysFunc(0); - else if (chk_PRIVATE.GetState()) - ExportGpGKeysFunc(1); - else if (chk_ALL.GetState()) - ExportGpGKeysFunc(2); - return true; + (new CDlgExportKeysMsgBox())->Show(); + return 0; } ///////////////////////////////////////////////////////////////////////////////////////// -CDlgChangePasswdMsgBox::CDlgChangePasswdMsgBox() : - CDlgBase(g_plugin, IDD_CHANGE_PASSWD), - edit_NEW_PASSWD1(this, IDC_NEW_PASSWD1), - edit_NEW_PASSWD2(this, IDC_NEW_PASSWD2), - edit_OLD_PASSWD(this, IDC_OLD_PASSWD) +class CDlgChangePasswdMsgBox : public CDlgBase //always modal { -} + CCtrlEdit edit_NEW_PASSWD1, edit_NEW_PASSWD2, edit_OLD_PASSWD; -bool CDlgChangePasswdMsgBox::OnApply() -{ - //TODO: show some prgress - if (mir_wstrcmp(edit_NEW_PASSWD1.GetText(), edit_NEW_PASSWD2.GetText())) { - MessageBox(m_hwnd, TranslateT("New passwords do not match"), TranslateT("Error"), MB_OK); - return false; +public: + CDlgChangePasswdMsgBox() : + CDlgBase(g_plugin, IDD_CHANGE_PASSWD), + edit_NEW_PASSWD1(this, IDC_NEW_PASSWD1), + edit_NEW_PASSWD2(this, IDC_NEW_PASSWD2), + edit_OLD_PASSWD(this, IDC_OLD_PASSWD) + { } - std::string old_pass, new_pass; - new_pass = toUTF8(ptrW(edit_NEW_PASSWD1.GetText()).get()); - old_pass = toUTF8(ptrW(edit_OLD_PASSWD.GetText()).get()); - - bool old_pass_match = false; - if (!mir_strcmp(ptrA(g_plugin.getUStringA("szKeyPassword")), old_pass.c_str())) - old_pass_match = true; + bool OnApply() override + { + //TODO: show some prgress + if (mir_wstrcmp(edit_NEW_PASSWD1.GetText(), edit_NEW_PASSWD2.GetText())) { + MessageBox(m_hwnd, TranslateT("New passwords do not match"), TranslateT("Error"), MB_OK); + return false; + } - if (!old_pass_match) { - if (globals.key_id_global[0]) { - string dbsetting = "szKey_"; - dbsetting += toUTF8(globals.key_id_global); - dbsetting += "_Password"; - ptrA pass(g_plugin.getUStringA(dbsetting.c_str())); - if (!mir_strcmp(pass, old_pass.c_str())) - old_pass_match = true; + std::string old_pass, new_pass; + new_pass = toUTF8(ptrW(edit_NEW_PASSWD1.GetText()).get()); + old_pass = toUTF8(ptrW(edit_OLD_PASSWD.GetText()).get()); + + bool old_pass_match = false; + if (!mir_strcmp(ptrA(g_plugin.getUStringA("szKeyPassword")), old_pass.c_str())) + old_pass_match = true; + + if (!old_pass_match) { + if (globals.key_id_global[0]) { + string dbsetting = "szKey_"; + dbsetting += toUTF8(globals.key_id_global); + dbsetting += "_Password"; + ptrA pass(g_plugin.getUStringA(dbsetting.c_str())); + if (!mir_strcmp(pass, old_pass.c_str())) + old_pass_match = true; + } } - } - if (!old_pass_match) - if (MessageBox(m_hwnd, TranslateT("Old password does not match, you can continue, but GPG will reject wrong password.\nDo you want to continue?"), TranslateT("Error"), MB_YESNO) == IDNO) - return false; + if (!old_pass_match) + if (MessageBox(m_hwnd, TranslateT("Old password does not match, you can continue, but GPG will reject wrong password.\nDo you want to continue?"), TranslateT("Error"), MB_YESNO) == IDNO) + return false; + + gpg_execution_params_pass params(old_pass, new_pass); + params.addParam(L"--edit-key"); + params.addParam(globals.key_id_global); + params.addParam(L"passwd"); + + HANDLE hThread = mir_forkThread<gpg_execution_params_pass>(&pxEexcute_passwd_change_thread, ¶ms); + if (WaitForSingleObject(hThread, 600000) != WAIT_OBJECT_0) { + if (params.child) + params.child->terminate(); + if (globals.debuglog) + globals.debuglog << "GPG execution timed out, aborted"; + return true; + } - gpg_execution_params_pass params(old_pass, new_pass); - params.addParam(L"--edit-key"); - params.addParam(globals.key_id_global); - params.addParam(L"passwd"); - - HANDLE hThread = mir_forkThread<gpg_execution_params_pass>(&pxEexcute_passwd_change_thread, ¶ms); - if (WaitForSingleObject(hThread, 600000) != WAIT_OBJECT_0) { - if (params.child) - params.child->terminate(); - if (globals.debuglog) - globals.debuglog << "GPG execution timed out, aborted"; - return true; + return params.result != pxNotFound; } - - return params.result != pxNotFound; +}; + +void ShowChangePasswdDlg() +{ + CDlgChangePasswdMsgBox *d = new CDlgChangePasswdMsgBox; + d->DoModal(); } ///////////////////////////////////////////////////////////////////////////////////////// +// New key generation dialog + +class CDlgKeyGen : public CDlgBase +{ + CCtrlCombo combo_KEY_TYPE; + CCtrlEdit edit_KEY_LENGTH, edit_KEY_PASSWD, edit_KEY_REAL_NAME, edit_KEY_EMAIL, edit_KEY_COMMENT, edit_KEY_EXPIRE_DATE; + CCtrlData lbl_GENERATING_TEXT; + +public: + CDlgKeyGen() : + CDlgBase(g_plugin, IDD_KEY_GEN), + combo_KEY_TYPE(this, IDC_KEY_TYPE), + edit_KEY_LENGTH(this, IDC_KEY_LENGTH), + edit_KEY_PASSWD(this, IDC_KEY_PASSWD), + edit_KEY_REAL_NAME(this, IDC_KEY_REAL_NAME), + edit_KEY_EMAIL(this, IDC_KEY_EMAIL), + edit_KEY_COMMENT(this, IDC_KEY_COMMENT), + edit_KEY_EXPIRE_DATE(this, IDC_KEY_EXPIRE_DATE), + lbl_GENERATING_TEXT(this, IDC_GENERATING_TEXT) + { + } -CDlgFirstRun::CDlgFirstRun() : - CDlgBase(g_plugin, IDD_FIRST_RUN), - list_KEY_LIST(this, IDC_KEY_LIST), - btn_COPY_PUBKEY(this, IDC_COPY_PUBKEY), - btn_EXPORT_PRIVATE(this, IDC_EXPORT_PRIVATE), - btn_CHANGE_PASSWD(this, IDC_CHANGE_PASSWD), - btn_GENERATE_RANDOM(this, IDC_GENERATE_RANDOM), - btn_GENERATE_KEY(this, IDC_GENERATE_KEY), - btn_OTHER(this, IDC_OTHER), - btn_DELETE_KEY(this, IDC_DELETE_KEY), - btn_OK(this, ID_OK), - edit_KEY_PASSWORD(this, IDC_KEY_PASSWORD), - combo_ACCOUNT(this, IDC_ACCOUNT), - lbl_KEY_ID(this, IDC_KEY_ID), - lbl_GENERATING_KEY(this, IDC_GENERATING_KEY) -{ - fp[0] = 0; + bool OnInitDialog() override + { + Utils_RestoreWindowPosition(m_hwnd, 0, MODULENAME, "KeygenWindow"); + SetCaption(TranslateT("Key Generation dialog")); + + combo_KEY_TYPE.AddString(L"RSA"); + combo_KEY_TYPE.AddString(L"DSA"); + combo_KEY_TYPE.SelectString(L"RSA"); + edit_KEY_EXPIRE_DATE.SetText(L"0"); + edit_KEY_LENGTH.SetText(L"4096"); + return true; + } - btn_COPY_PUBKEY.OnClick = Callback(this, &CDlgFirstRun::onClick_COPY_PUBKEY); - btn_EXPORT_PRIVATE.OnClick = Callback(this, &CDlgFirstRun::onClick_EXPORT_PRIVATE); - btn_CHANGE_PASSWD.OnClick = Callback(this, &CDlgFirstRun::onClick_CHANGE_PASSWD); - btn_GENERATE_RANDOM.OnClick = Callback(this, &CDlgFirstRun::onClick_GENERATE_RANDOM); - btn_GENERATE_KEY.OnClick = Callback(this, &CDlgFirstRun::onClick_GENERATE_KEY); - btn_OTHER.OnClick = Callback(this, &CDlgFirstRun::onClick_OTHER); - btn_DELETE_KEY.OnClick = Callback(this, &CDlgFirstRun::onClick_DELETE_KEY); - btn_OK.OnClick = Callback(this, &CDlgFirstRun::onClick_OK); + bool OnApply() override + { + // data sanity checks + ptrW tmp(combo_KEY_TYPE.GetText()); + if (mir_wstrlen(tmp) < 3) { + MessageBox(nullptr, TranslateT("You must set encryption algorithm first"), TranslateT("Error"), MB_OK); + return false; + } - combo_ACCOUNT.OnChange = Callback(this, &CDlgFirstRun::onChange_ACCOUNT); + tmp = edit_KEY_LENGTH.GetText(); + int length = _wtoi(tmp); + if (length < 1024 || length > 4096) { + MessageBox(nullptr, TranslateT("Key length must be of length from 1024 to 4096 bits"), TranslateT("Error"), MB_OK); + return false; + } - list_KEY_LIST.OnClick = Callback(this, &CDlgFirstRun::onChange_KEY_LIST); -} + tmp = edit_KEY_EXPIRE_DATE.GetText(); + if (mir_wstrlen(tmp) != 10 && tmp[0] != '0') { + MessageBox(nullptr, TranslateT("Invalid date"), TranslateT("Error"), MB_OK); + return false; + } -bool CDlgFirstRun::OnInitDialog() -{ - Utils_RestoreWindowPosition(m_hwnd, 0, MODULENAME, "FirstrunWindow"); - SetCaption(TranslateT("Bind own keys to accounts")); - btn_COPY_PUBKEY.Disable(); - btn_EXPORT_PRIVATE.Disable(); - btn_CHANGE_PASSWD.Disable(); - - list_KEY_LIST.AddColumn(0, TranslateT("Key ID"), 50); - list_KEY_LIST.AddColumn(1, TranslateT("Email"), 30); - list_KEY_LIST.AddColumn(2, TranslateT("Name"), 250); - list_KEY_LIST.AddColumn(3, TranslateT("Creation date"), 30); - list_KEY_LIST.AddColumn(4, TranslateT("Expire date"), 30); - list_KEY_LIST.AddColumn(5, TranslateT("Key length"), 30); - list_KEY_LIST.AddColumn(6, TranslateT("Accounts"), 30); - list_KEY_LIST.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_SINGLEROW); - - refresh_key_list(); - - combo_ACCOUNT.AddString(TranslateT("Default")); - - for (auto &pa : Accounts()) { - if (StriStr(pa->szModuleName, "metacontacts")) - continue; - if (StriStr(pa->szModuleName, "weather")) - continue; - - combo_ACCOUNT.AddString(pa->tszAccountName, (LPARAM)pa->szModuleName); - } - combo_ACCOUNT.SetCurSel(0); + tmp = edit_KEY_REAL_NAME.GetText(); + if (mir_wstrlen(tmp) < 5) { + MessageBox(nullptr, TranslateT("Name must contain at least 5 characters"), TranslateT("Error"), MB_OK); + return false; + } + if (wcschr(tmp, '(') || wcschr(tmp, ')')) { + MessageBox(nullptr, TranslateT("Name cannot contain '(' or ')'"), TranslateT("Error"), MB_OK); + return false; + } - CMStringW keyinfo = TranslateT("key ID"); - keyinfo += L": "; - keyinfo += g_plugin.getMStringW("KeyID", TranslateT("not set")); - lbl_KEY_ID.SetText(keyinfo); - return true; -} + tmp = edit_KEY_EMAIL.GetText(); + if ((mir_wstrlen(tmp)) < 5 || (!wcschr(tmp, '@')) || (!wcschr(tmp, '.'))) { + MessageBox(nullptr, TranslateT("Invalid Email"), TranslateT("Error"), MB_OK); + return false; + } -void CDlgFirstRun::onClick_COPY_PUBKEY(CCtrlButton*) -{ - int i = list_KEY_LIST.GetSelectionMark(); - if (i == -1) - return; - - if (!OpenClipboard(m_hwnd)) - return; - - list_KEY_LIST.GetItemText(i, 0, fp, _countof(fp)); - - gpg_execution_params params; - params.addParam(L"--batch"); - params.addParam(L"-a"); - params.addParam(L"--export"); - params.addParam(fp); - if (!gpg_launcher(params)) - return; - if (params.result == pxNotFound) - return; - - params.out.Remove('\r'); - HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, params.out.GetLength() + 1); - if (!hMem) { - MessageBox(nullptr, TranslateT("Failed to allocate memory"), TranslateT("Error"), MB_OK); - return; - } - char *szKey = (char*)GlobalLock(hMem); - if (!szKey) { - wchar_t msg[64]; - mir_snwprintf(msg, TranslateT("Failed to lock memory with error %d"), GetLastError()); - MessageBox(nullptr, msg, TranslateT("Error"), MB_OK); - GlobalFree(hMem); - } - - memcpy(szKey, params.out.c_str(), params.out.GetLength()); - szKey[params.out.GetLength()] = '\0'; - - EmptyClipboard(); - GlobalUnlock(hMem); - if (!SetClipboardData(CF_OEMTEXT, hMem)) { - GlobalFree(hMem); - wchar_t msg[64]; - mir_snwprintf(msg, TranslateT("Failed write to clipboard with error %d"), GetLastError()); - MessageBox(nullptr, msg, TranslateT("Error"), MB_OK); - } - CloseClipboard(); -} + // generating key file + CMStringW path = g_plugin.getMStringW("szHomePath"); + path += L"\\new_key"; + wfstream f(path.c_str(), std::ios::out); + if (!f.is_open()) { + MessageBox(nullptr, TranslateT("Failed to open file"), TranslateT("Error"), MB_OK); + return false; + } -void CDlgFirstRun::onClick_EXPORT_PRIVATE(CCtrlButton*) -{ - int i = list_KEY_LIST.GetSelectionMark(); - if (i == -1) - return; - - ptrW p(GetFilePath(L"Choose file to export key", L"*", L"Any file", true)); - if (!p || !p[0]) - return; - - std::ofstream file; - file.open(p, std::ios::trunc | std::ios::out); - if (!file.is_open()) - return; //TODO: handle error - - list_KEY_LIST.GetItemText(i, 0, fp, _countof(fp)); - - gpg_execution_params params; - params.addParam(L"--batch"); - params.addParam(L"-a"); - params.addParam(L"--export-secret-keys"); - params.addParam(fp); - if (!gpg_launcher(params)) - return; - if (params.result == pxNotFound) - return; - - params.out.Remove('\r'); - file << params.out.c_str(); - if (file.is_open()) - file.close(); -} + f << "Key-Type: "; + char *tmp2 = mir_u2a(combo_KEY_TYPE.GetText()); + char *subkeytype = (char *)mir_alloc(6); + if (strstr(tmp2, "RSA")) + mir_strcpy(subkeytype, "RSA"); + else if (strstr(tmp2, "DSA")) //this is useless check for now, but it will be required if someone add another key types support + mir_strcpy(subkeytype, "ELG-E"); + f << tmp2; + mir_free(tmp2); + f << "\n"; + f << "Key-Length: "; + f << _wtoi(edit_KEY_LENGTH.GetText()); + f << "\n"; + f << "Subkey-Length: "; + f << _wtoi(edit_KEY_LENGTH.GetText()); + f << "\n"; + f << "Subkey-Type: "; + f << subkeytype; + mir_free(subkeytype); + f << "\n"; + if (edit_KEY_PASSWD.GetText()[0]) { + f << "Passphrase: "; + f << toUTF8(edit_KEY_PASSWD.GetText()).c_str(); + f << "\n"; + } + f << "Name-Real: "; + f << toUTF8(edit_KEY_REAL_NAME.GetText()).c_str(); + f << "\n"; + if (edit_KEY_COMMENT.GetText()[0]) { + f << "Name-Comment: "; + f << toUTF8(edit_KEY_COMMENT.GetText()).c_str(); + f << "\n"; + } + f << "Name-Email: "; + f << toUTF8(edit_KEY_EMAIL.GetText()).c_str(); + f << "\n"; + f << "Expire-Date: "; + f << toUTF8(edit_KEY_EXPIRE_DATE.GetText()).c_str(); + f << "\n"; + f.close(); + + lbl_GENERATING_TEXT.SendMsg(WM_SETFONT, (WPARAM)globals.bold_font, TRUE); + lbl_GENERATING_TEXT.SetText(TranslateT("Generating new key, please wait...")); + combo_KEY_TYPE.Disable(); + edit_KEY_LENGTH.Disable(); + edit_KEY_PASSWD.Disable(); + edit_KEY_REAL_NAME.Disable(); + edit_KEY_EMAIL.Disable(); + edit_KEY_COMMENT.Disable(); + edit_KEY_EXPIRE_DATE.Disable(); + + // gpg execution + gpg_execution_params params; + params.addParam(L"--batch"); + params.addParam(L"--yes"); + params.addParam(L"--gen-key"); + params.addParam(path.c_str()); + params.bNoOutput = true; + if (!gpg_launcher(params, boost::posix_time::minutes(10))) + return false; + if (params.result == pxNotFound) + return false; -void CDlgFirstRun::onClick_CHANGE_PASSWD(CCtrlButton*) -{ - int i = list_KEY_LIST.GetSelectionMark(); - if (i == -1) - return; - - list_KEY_LIST.GetItemText(i, 0, globals.key_id_global, _countof(globals.key_id_global)); - - // temporary code follows - std::string old_pass, new_pass; - - gpg_execution_params_pass params(old_pass, new_pass); - params.addParam(L"--edit-key"); - params.addParam(globals.key_id_global); - params.addParam(L"passwd"); - - HANDLE hThread = mir_forkThread<gpg_execution_params_pass>(pxEexcute_passwd_change_thread, ¶ms); - if (WaitForSingleObject(hThread, 600000) != WAIT_OBJECT_0) { - if (params.child) - params.child->terminate(); - if (globals.debuglog) - globals.debuglog << "GPG execution timed out, aborted"; - this->Close(); + boost::filesystem::remove(path.c_str()); + return true; } -} -void CDlgFirstRun::onClick_GENERATE_RANDOM(CCtrlButton*) -{ - lbl_GENERATING_KEY.SendMsg(WM_SETFONT, (WPARAM)globals.bold_font, TRUE); - lbl_GENERATING_KEY.SetText(TranslateT("Generating new random key, please wait")); - btn_GENERATE_KEY.Disable(); - btn_OTHER.Disable(); - btn_DELETE_KEY.Disable(); - list_KEY_LIST.Disable(); - btn_GENERATE_RANDOM.Disable(); - gpg_use_new_random_key(m_szCurrAcc); - this->Close(); -} - -void CDlgFirstRun::onClick_GENERATE_KEY(CCtrlButton*) -{ - CDlgKeyGen *d = new CDlgKeyGen; - d->DoModal(); - refresh_key_list(); -} + void OnDestroy() override + { + Utils_SaveWindowPosition(m_hwnd, 0, MODULENAME, "KeygenWindow"); + } +}; -void CDlgFirstRun::onClick_OTHER(CCtrlButton*) -{ - ShowLoadPublicKeyDialog(0, true); - refresh_key_list(); -} +///////////////////////////////////////////////////////////////////////////////////////// +// First run dialog -void CDlgFirstRun::onClick_DELETE_KEY(CCtrlButton*) +class CDlgFirstRun : public CDlgBase { - int i = list_KEY_LIST.GetSelectionMark(); - if (i == -1) - return; - - list_KEY_LIST.GetItemText(i, 0, fp, _countof(fp)); + void refresh_key_list() { + list_KEY_LIST.DeleteAllItems(); + int i = 1; + + // parse gpg output gpg_execution_params params; params.addParam(L"--batch"); - params.addParam(L"--fingerprint"); - params.addParam(fp); + params.addParam(L"--list-secret-keys"); if (!gpg_launcher(params)) return; if (params.result == pxNotFound) return; - int s = params.out.Find("Key fingerprint = "); - s += mir_strlen("Key fingerprint = "); - int s2 = params.out.Find("\n", s); + wstring::size_type p = 0, p2 = 0, stop = 0; + string out(params.out); + while (p != string::npos) { + if ((p = out.find("sec ", p)) == string::npos) + break; + p += 5; + if (p < stop) + break; + stop = p; + p2 = out.find("/", p) - 1; + wchar_t *key_len = mir_wstrdup(toUTF16(out.substr(p, p2 - p)).c_str()), *creation_date = nullptr, *expire_date = nullptr; + p2 += 2; + p = out.find(" ", p2); + std::wstring key_id = toUTF16(out.substr(p2, p - p2)); + p += 1; + p2 = out.find(" ", p); + std::string::size_type p3 = out.find("\n", p); + if ((p2 != std::string::npos) && (p3 < p2)) { + p2 = p3; + creation_date = mir_wstrdup(toUTF16(out.substr(p, p2 - p - 1)).c_str()); + } + else { + creation_date = mir_wstrdup(toUTF16(out.substr(p, p2 - p)).c_str()); + p2 = out.find("[", p2); + p2 = out.find("expires:", p2); + p2 += mir_strlen("expires:"); + if (p2 != std::string::npos) { + p2++; + p = p2; + p2 = out.find("]", p); + expire_date = mir_wstrdup(toUTF16(out.substr(p, p2 - p)).c_str()); + //check expiration + bool expired = false; + { + boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); + wchar_t buf[5]; + wcsncpy_s(buf, expire_date, _TRUNCATE); + int year = _wtoi(buf); + if (year < now.date().year()) + expired = true; + else if (year == now.date().year()) { + wcsncpy_s(buf, (expire_date + 5), _TRUNCATE); + int month = _wtoi(buf); + if (month < now.date().month()) + expired = true; + else if (month == now.date().month()) { + wcsncpy_s(buf, (expire_date + 8), _TRUNCATE); + unsigned day = _wtoi(buf); + if (day <= now.date().day_number()) + expired = true; + } + } + } + if (expired) { + mir_free(key_len); + mir_free(creation_date); + mir_free(expire_date); + //mimic normal behaviour + p = out.find("uid ", p); + p2 = out.find_first_not_of(" ", p + 5); + p = out.find("<", p2); + p++; + //p2 = out.find(">", p); + // + continue; //does not add to key list + } + } + } + int row = list_KEY_LIST.AddItem(L"", 0); + list_KEY_LIST.SetItemText(row, 3, creation_date); + mir_free(creation_date); + if (expire_date) { + list_KEY_LIST.SetItemText(row, 4, expire_date); + mir_free(expire_date); + } + list_KEY_LIST.SetItemText(row, 5, key_len); + mir_free(key_len); + list_KEY_LIST.SetItemText(row, 0, (wchar_t *)key_id.c_str()); + p = out.find("uid ", p); + p2 = out.find_first_not_of(" ", p + 5); + p = out.find("<", p2); + + wstring tmp = toUTF16(out.substr(p2, p - p2)); + list_KEY_LIST.SetItemText(row, 2, (wchar_t *)tmp.c_str()); - CMStringW tmp = params.out.Mid(s, s2 - s); - tmp.Remove(' '); + p++; + p2 = out.find(">", p); + + tmp = toUTF16(out.substr(p, p2 - p)); + list_KEY_LIST.SetItemText(row, 1, (wchar_t *)tmp.c_str()); + + // get accounts + std::wstring accs; + for (auto &pa : Accounts()) { + std::string setting = pa->szModuleName; + setting += "_KeyID"; + ptrW str(g_plugin.getWStringA(setting.c_str(), L"")); + if (key_id == str.get()) { + if (!accs.empty()) + accs += L","; + accs += pa->tszAccountName; + } + } + list_KEY_LIST.SetItemText(row, 6, accs.c_str()); + } + i++; + list_KEY_LIST.SetColumnWidth(0, LVSCW_AUTOSIZE); + list_KEY_LIST.SetColumnWidth(1, LVSCW_AUTOSIZE); + list_KEY_LIST.SetColumnWidth(2, LVSCW_AUTOSIZE); + list_KEY_LIST.SetColumnWidth(3, LVSCW_AUTOSIZE); + list_KEY_LIST.SetColumnWidth(4, LVSCW_AUTOSIZE); + list_KEY_LIST.SetColumnWidth(5, LVSCW_AUTOSIZE); + list_KEY_LIST.SetColumnWidth(6, LVSCW_AUTOSIZE); + } + + CCtrlListView list_KEY_LIST; + CCtrlButton btn_COPY_PUBKEY, btn_EXPORT_PRIVATE, btn_CHANGE_PASSWD, btn_GENERATE_RANDOM, btn_GENERATE_KEY, btn_OTHER, btn_DELETE_KEY, btn_OK; + CCtrlEdit edit_KEY_PASSWORD; + CCtrlCombo combo_ACCOUNT; + CCtrlData lbl_KEY_ID, lbl_GENERATING_KEY; + wchar_t fp[16]; + const char *m_szCurrAcc = nullptr; + +public: + CDlgFirstRun() : + CDlgBase(g_plugin, IDD_FIRST_RUN), + list_KEY_LIST(this, IDC_KEY_LIST), + btn_COPY_PUBKEY(this, IDC_COPY_PUBKEY), + btn_EXPORT_PRIVATE(this, IDC_EXPORT_PRIVATE), + btn_CHANGE_PASSWD(this, IDC_CHANGE_PASSWD), + btn_GENERATE_RANDOM(this, IDC_GENERATE_RANDOM), + btn_GENERATE_KEY(this, IDC_GENERATE_KEY), + btn_OTHER(this, IDC_OTHER), + btn_DELETE_KEY(this, IDC_DELETE_KEY), + btn_OK(this, ID_OK), + edit_KEY_PASSWORD(this, IDC_KEY_PASSWORD), + combo_ACCOUNT(this, IDC_ACCOUNT), + lbl_KEY_ID(this, IDC_KEY_ID), + lbl_GENERATING_KEY(this, IDC_GENERATING_KEY) + { + fp[0] = 0; - gpg_execution_params params2; - params2.addParam(L"--batch"); - params2.addParam(L"--delete-secret-and-public-key"); - params2.addParam(L"--fingerprint"); - params2.addParam(tmp.c_str()); + btn_COPY_PUBKEY.OnClick = Callback(this, &CDlgFirstRun::onClick_COPY_PUBKEY); + btn_EXPORT_PRIVATE.OnClick = Callback(this, &CDlgFirstRun::onClick_EXPORT_PRIVATE); + btn_CHANGE_PASSWD.OnClick = Callback(this, &CDlgFirstRun::onClick_CHANGE_PASSWD); + btn_GENERATE_RANDOM.OnClick = Callback(this, &CDlgFirstRun::onClick_GENERATE_RANDOM); + btn_GENERATE_KEY.OnClick = Callback(this, &CDlgFirstRun::onClick_GENERATE_KEY); + btn_OTHER.OnClick = Callback(this, &CDlgFirstRun::onClick_OTHER); + btn_DELETE_KEY.OnClick = Callback(this, &CDlgFirstRun::onClick_DELETE_KEY); + btn_OK.OnClick = Callback(this, &CDlgFirstRun::onClick_OK); - if (!gpg_launcher(params2)) - return; - if (params2.result == pxNotFound) - return; - } + combo_ACCOUNT.OnChange = Callback(this, &CDlgFirstRun::onChange_ACCOUNT); - if (m_szCurrAcc == nullptr) { - g_plugin.delSetting("GPGPubKey"); - g_plugin.delSetting("KeyID"); - g_plugin.delSetting("KeyComment"); - g_plugin.delSetting("KeyMainName"); - g_plugin.delSetting("KeyMainEmail"); - g_plugin.delSetting("KeyType"); - } - else { - CMStringA acc_str = m_szCurrAcc; - g_plugin.delSetting(acc_str + "_GPGPubKey"); - g_plugin.delSetting(acc_str + "_KeyMainName"); - g_plugin.delSetting(acc_str + "_KeyID"); - g_plugin.delSetting(acc_str + "_KeyComment"); - g_plugin.delSetting(acc_str + "_KeyMainEmail"); - g_plugin.delSetting(acc_str + "_KeyType"); + list_KEY_LIST.OnClick = Callback(this, &CDlgFirstRun::onChange_KEY_LIST); } - list_KEY_LIST.DeleteItem(i); -} + bool OnInitDialog() override + { + Utils_RestoreWindowPosition(m_hwnd, 0, MODULENAME, "FirstrunWindow"); + SetCaption(TranslateT("Bind own keys to accounts")); + btn_COPY_PUBKEY.Disable(); + btn_EXPORT_PRIVATE.Disable(); + btn_CHANGE_PASSWD.Disable(); -void CDlgFirstRun::onClick_OK(CCtrlButton*) -{ - int i = list_KEY_LIST.GetSelectionMark(); - if (i == -1) - return; + list_KEY_LIST.AddColumn(0, TranslateT("Key ID"), 50); + list_KEY_LIST.AddColumn(1, TranslateT("Email"), 30); + list_KEY_LIST.AddColumn(2, TranslateT("Name"), 250); + list_KEY_LIST.AddColumn(3, TranslateT("Creation date"), 30); + list_KEY_LIST.AddColumn(4, TranslateT("Expire date"), 30); + list_KEY_LIST.AddColumn(5, TranslateT("Key length"), 30); + list_KEY_LIST.AddColumn(6, TranslateT("Accounts"), 30); + list_KEY_LIST.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_SINGLEROW); - list_KEY_LIST.GetItemText(i, 0, fp, _countof(fp)); - wchar_t name[65]; - list_KEY_LIST.GetItemText(i, 2, name, 64); - { - if (wcschr(name, '(')) { - wstring str = name; - wstring::size_type p = str.find(L"(") - 1; - mir_wstrcpy(name, str.substr(0, p).c_str()); - } - } + refresh_key_list(); - gpg_execution_params params; - params.addParam(L"--batch"); - params.addParam(L"-a"); - params.addParam(L"--export"); - params.addParam(fp); - if (!gpg_launcher(params)) - return; - if (params.result == pxNotFound) - return; + combo_ACCOUNT.AddString(TranslateT("Default")); - params.out.Remove('\r'); + for (auto &pa : Accounts()) { + if (StriStr(pa->szModuleName, "metacontacts")) + continue; + if (StriStr(pa->szModuleName, "weather")) + continue; - if (m_szCurrAcc == nullptr) { - g_plugin.setString("GPGPubKey", params.out.c_str()); - g_plugin.setWString("KeyMainName", name); - g_plugin.setWString("KeyID", fp); + combo_ACCOUNT.AddString(pa->tszAccountName, (LPARAM)pa->szModuleName); + } + combo_ACCOUNT.SetCurSel(0); - wstring keyinfo = TranslateT("Default private key ID"); + CMStringW keyinfo = TranslateT("key ID"); keyinfo += L": "; - keyinfo += (fp[0]) ? fp : L"not set"; - extern HWND hwndCurKey_p; - SetWindowText(hwndCurKey_p, keyinfo.c_str()); - } - else { - CMStringA acc_str = m_szCurrAcc; - g_plugin.setString(acc_str + "_GPGPubKey", params.out.c_str()); - g_plugin.setWString(acc_str + "_KeyMainName", name); - g_plugin.setWString(acc_str + "_KeyID", fp); + keyinfo += g_plugin.getMStringW("KeyID", TranslateT("not set")); + lbl_KEY_ID.SetText(keyinfo); + return true; } - ptrW passwd(edit_KEY_PASSWORD.GetText()); - if (mir_wstrlen(passwd)) { - string dbsetting = "szKey_"; - dbsetting += _T2A(fp); - dbsetting += "_Password"; - g_plugin.setWString(dbsetting.c_str(), passwd); + void OnDestroy() override + { + Utils_SaveWindowPosition(m_hwnd, 0, MODULENAME, "FirstrunWindow"); } - //bAutoExchange = CheckStateStoreDB(hwndDlg, IDC_AUTO_EXCHANGE, "bAutoExchange") != 0; //TODO: check is it just typo, or doing something - globals.gpg_valid = isGPGValid(); - globals.gpg_keyexist = isGPGKeyExist(); - DestroyWindow(m_hwnd); -} - -void CDlgFirstRun::onChange_ACCOUNT(CCtrlCombo *pCombo) -{ - CMStringW keyinfo = TranslateT("key ID"); - keyinfo += ": "; + void onClick_COPY_PUBKEY(CCtrlButton *) + { + int i = list_KEY_LIST.GetSelectionMark(); + if (i == -1) + return; - m_szCurrAcc = (const char *)pCombo->GetItemData(pCombo->GetCurSel()); - if (m_szCurrAcc == nullptr) { - keyinfo += g_plugin.getMStringW("KeyID", TranslateT("not set")); - } - else { - std::string acc_str = m_szCurrAcc; - acc_str += "_KeyID"; - keyinfo += g_plugin.getMStringW(acc_str.c_str(), TranslateT("not set")); - } - lbl_KEY_ID.SetText(keyinfo); -} + if (!OpenClipboard(m_hwnd)) + return; -void CDlgFirstRun::onChange_KEY_LIST(CCtrlListView::TEventInfo *ev) //TODO: check if this work -{ - if (ev->nmlv) { - NMLISTVIEW *hdr = ev->nmlv; - - if (hdr->hdr.code == NM_CLICK) { - btn_OK.Enable(); - btn_COPY_PUBKEY.Enable(); - btn_EXPORT_PRIVATE.Enable(); - btn_CHANGE_PASSWD.Enable(); - } - } -} + list_KEY_LIST.GetItemText(i, 0, fp, _countof(fp)); -void CDlgFirstRun::OnDestroy() -{ - Utils_SaveWindowPosition(m_hwnd, 0, MODULENAME, "FirstrunWindow"); -} + gpg_execution_params params; + params.addParam(L"--batch"); + params.addParam(L"-a"); + params.addParam(L"--export"); + params.addParam(fp); + if (!gpg_launcher(params)) + return; + if (params.result == pxNotFound) + return; -void CDlgFirstRun::refresh_key_list() -{ - list_KEY_LIST.DeleteAllItems(); - int i = 1; - - // parse gpg output - gpg_execution_params params; - params.addParam(L"--batch"); - params.addParam(L"--list-secret-keys"); - if (!gpg_launcher(params)) - return; - if (params.result == pxNotFound) - return; - - wstring::size_type p = 0, p2 = 0, stop = 0; - string out(params.out); - while (p != string::npos) { - if ((p = out.find("sec ", p)) == string::npos) - break; - p += 5; - if (p < stop) - break; - stop = p; - p2 = out.find("/", p) - 1; - wchar_t *key_len = mir_wstrdup(toUTF16(out.substr(p, p2 - p)).c_str()), *creation_date = nullptr, *expire_date = nullptr; - p2 += 2; - p = out.find(" ", p2); - std::wstring key_id = toUTF16(out.substr(p2, p - p2)); - p += 1; - p2 = out.find(" ", p); - std::string::size_type p3 = out.find("\n", p); - if ((p2 != std::string::npos) && (p3 < p2)) { - p2 = p3; - creation_date = mir_wstrdup(toUTF16(out.substr(p, p2 - p - 1)).c_str()); + params.out.Remove('\r'); + HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, params.out.GetLength() + 1); + if (!hMem) { + MessageBox(nullptr, TranslateT("Failed to allocate memory"), TranslateT("Error"), MB_OK); + return; } - else { - creation_date = mir_wstrdup(toUTF16(out.substr(p, p2 - p)).c_str()); - p2 = out.find("[", p2); - p2 = out.find("expires:", p2); - p2 += mir_strlen("expires:"); - if (p2 != std::string::npos) { - p2++; - p = p2; - p2 = out.find("]", p); - expire_date = mir_wstrdup(toUTF16(out.substr(p, p2 - p)).c_str()); - //check expiration - bool expired = false; - { - boost::posix_time::ptime now = boost::posix_time::second_clock::local_time(); - wchar_t buf[5]; - wcsncpy_s(buf, expire_date, _TRUNCATE); - int year = _wtoi(buf); - if (year < now.date().year()) - expired = true; - else if (year == now.date().year()) { - wcsncpy_s(buf, (expire_date + 5), _TRUNCATE); - int month = _wtoi(buf); - if (month < now.date().month()) - expired = true; - else if (month == now.date().month()) { - wcsncpy_s(buf, (expire_date + 8), _TRUNCATE); - unsigned day = _wtoi(buf); - if (day <= now.date().day_number()) - expired = true; - } - } - } - if (expired) { - mir_free(key_len); - mir_free(creation_date); - mir_free(expire_date); - //mimic normal behaviour - p = out.find("uid ", p); - p2 = out.find_first_not_of(" ", p + 5); - p = out.find("<", p2); - p++; - //p2 = out.find(">", p); - // - continue; //does not add to key list - } - } + + char *szKey = (char *)GlobalLock(hMem); + if (!szKey) { + wchar_t msg[64]; + mir_snwprintf(msg, TranslateT("Failed to lock memory with error %d"), GetLastError()); + MessageBox(nullptr, msg, TranslateT("Error"), MB_OK); + GlobalFree(hMem); } - int row = list_KEY_LIST.AddItem(L"", 0); - list_KEY_LIST.SetItemText(row, 3, creation_date); - mir_free(creation_date); - if (expire_date) { - list_KEY_LIST.SetItemText(row, 4, expire_date); - mir_free(expire_date); + + memcpy(szKey, params.out.c_str(), params.out.GetLength()); + szKey[params.out.GetLength()] = '\0'; + + EmptyClipboard(); + GlobalUnlock(hMem); + if (!SetClipboardData(CF_OEMTEXT, hMem)) { + GlobalFree(hMem); + wchar_t msg[64]; + mir_snwprintf(msg, TranslateT("Failed write to clipboard with error %d"), GetLastError()); + MessageBox(nullptr, msg, TranslateT("Error"), MB_OK); } - list_KEY_LIST.SetItemText(row, 5, key_len); - mir_free(key_len); - list_KEY_LIST.SetItemText(row, 0, (wchar_t *)key_id.c_str()); - p = out.find("uid ", p); - p2 = out.find_first_not_of(" ", p + 5); - p = out.find("<", p2); + CloseClipboard(); + } + + void onClick_EXPORT_PRIVATE(CCtrlButton *) + { + int i = list_KEY_LIST.GetSelectionMark(); + if (i == -1) + return; - wstring tmp = toUTF16(out.substr(p2, p - p2)); - list_KEY_LIST.SetItemText(row, 2, (wchar_t *)tmp.c_str()); + ptrW p(GetFilePath(L"Choose file to export key", L"*", L"Any file", true)); + if (!p || !p[0]) + return; - p++; - p2 = out.find(">", p); + std::ofstream file; + file.open(p, std::ios::trunc | std::ios::out); + if (!file.is_open()) + return; //TODO: handle error - tmp = toUTF16(out.substr(p, p2 - p)); - list_KEY_LIST.SetItemText(row, 1, (wchar_t *)tmp.c_str()); + list_KEY_LIST.GetItemText(i, 0, fp, _countof(fp)); - // get accounts - std::wstring accs; - for (auto &pa : Accounts()) { - std::string setting = pa->szModuleName; - setting += "_KeyID"; - ptrW str(g_plugin.getWStringA(setting.c_str(), L"")); - if (key_id == str.get()) { - if (!accs.empty()) - accs += L","; - accs += pa->tszAccountName; - } - } - list_KEY_LIST.SetItemText(row, 6, accs.c_str()); + gpg_execution_params params; + params.addParam(L"--batch"); + params.addParam(L"-a"); + params.addParam(L"--export-secret-keys"); + params.addParam(fp); + if (!gpg_launcher(params)) + return; + if (params.result == pxNotFound) + return; + + params.out.Remove('\r'); + file << params.out.c_str(); + if (file.is_open()) + file.close(); } - i++; - list_KEY_LIST.SetColumnWidth(0, LVSCW_AUTOSIZE); - list_KEY_LIST.SetColumnWidth(1, LVSCW_AUTOSIZE); - list_KEY_LIST.SetColumnWidth(2, LVSCW_AUTOSIZE); - list_KEY_LIST.SetColumnWidth(3, LVSCW_AUTOSIZE); - list_KEY_LIST.SetColumnWidth(4, LVSCW_AUTOSIZE); - list_KEY_LIST.SetColumnWidth(5, LVSCW_AUTOSIZE); - list_KEY_LIST.SetColumnWidth(6, LVSCW_AUTOSIZE); -} -///////////////////////////////////////////////////////////////////////////////////////// + void onClick_CHANGE_PASSWD(CCtrlButton *) + { + int i = list_KEY_LIST.GetSelectionMark(); + if (i == -1) + return; -CDlgGpgBinOpts::CDlgGpgBinOpts() : - CDlgBase(g_plugin, IDD_BIN_PATH), - btn_SET_BIN_PATH(this, IDC_SET_BIN_PATH), - btn_SET_HOME_DIR(this, IDC_SET_HOME_DIR), - btn_OK(this, ID_OK), - btn_GENERATE_RANDOM(this, IDC_GENERATE_RANDOM), - edit_BIN_PATH(this, IDC_BIN_PATH), - edit_HOME_DIR(this, IDC_HOME_DIR), - chk_AUTO_EXCHANGE(this, IDC_AUTO_EXCHANGE) -{ - btn_SET_BIN_PATH.OnClick = Callback(this, &CDlgGpgBinOpts::onClick_SET_BIN_PATH); - btn_SET_HOME_DIR.OnClick = Callback(this, &CDlgGpgBinOpts::onClick_SET_HOME_DIR); - btn_OK.OnClick = Callback(this, &CDlgGpgBinOpts::onClick_OK); - btn_GENERATE_RANDOM.OnClick = Callback(this, &CDlgGpgBinOpts::onClick_GENERATE_RANDOM); -} + list_KEY_LIST.GetItemText(i, 0, globals.key_id_global, _countof(globals.key_id_global)); -bool CDlgGpgBinOpts::OnInitDialog() -{ - CMStringW path; - bool gpg_exists = false, lang_exists = false; - { - wchar_t mir_path[MAX_PATH]; - PathToAbsoluteW(L"\\", mir_path); - SetCurrentDirectoryW(mir_path); + // temporary code follows + std::string old_pass, new_pass; - CMStringW gpg_path(mir_path); gpg_path.Append(L"\\GnuPG\\gpg.exe"); - CMStringW gpg_lang_path(mir_path); gpg_lang_path.Append(L"\\GnuPG\\gnupg.nls\\en@quot.mo"); + gpg_execution_params_pass params(old_pass, new_pass); + params.addParam(L"--edit-key"); + params.addParam(globals.key_id_global); + params.addParam(L"passwd"); - if (boost::filesystem::exists(gpg_path.c_str())) { - gpg_exists = true; - path = L"GnuPG\\gpg.exe"; + HANDLE hThread = mir_forkThread<gpg_execution_params_pass>(pxEexcute_passwd_change_thread, ¶ms); + if (WaitForSingleObject(hThread, 600000) != WAIT_OBJECT_0) { + if (params.child) + params.child->terminate(); + if (globals.debuglog) + globals.debuglog << "GPG execution timed out, aborted"; + this->Close(); } - else path = gpg_path; + } - if (boost::filesystem::exists(gpg_lang_path.c_str())) - lang_exists = true; - if (gpg_exists && !lang_exists) - MessageBox(nullptr, TranslateT("GPG binary found in Miranda folder, but English locale does not exist.\nIt's highly recommended that you place \\gnupg.nls\\en@quot.mo in GnuPG folder under Miranda root.\nWithout this file you may experience many problems with GPG output on non-English systems\nand plugin may completely not work.\nYou have been warned."), TranslateT("Warning"), MB_OK); + void onClick_GENERATE_RANDOM(CCtrlButton *) + { + lbl_GENERATING_KEY.SendMsg(WM_SETFONT, (WPARAM)globals.bold_font, TRUE); + lbl_GENERATING_KEY.SetText(TranslateT("Generating new random key, please wait")); + btn_GENERATE_KEY.Disable(); + btn_OTHER.Disable(); + btn_DELETE_KEY.Disable(); + list_KEY_LIST.Disable(); + btn_GENERATE_RANDOM.Disable(); + gpg_use_new_random_key(m_szCurrAcc); + this->Close(); } - DWORD len = MAX_PATH; - bool bad_version = false; + + void onClick_GENERATE_KEY(CCtrlButton *) { - ptrW tmp; - if (!gpg_exists) { - tmp = g_plugin.getWStringA("szGpgBinPath", (SHGetValueW(HKEY_CURRENT_USER, L"Software\\GNU\\GnuPG", L"gpgProgram", 0, (void *)path.c_str(), &len) == ERROR_SUCCESS) ? path.c_str() : L""); - if (tmp[0]) - if (!boost::filesystem::exists((wchar_t *)tmp)) - MessageBoxW(nullptr, TranslateT("Wrong GPG binary location found in system.\nPlease choose another location"), TranslateT("Warning"), MB_OK); - } - else tmp = mir_wstrdup(path.c_str()); + CDlgKeyGen().DoModal(); + refresh_key_list(); + } - edit_BIN_PATH.SetText(tmp); - if (gpg_exists/* && lang_exists*/) { - g_plugin.setWString("szGpgBinPath", tmp); + void onClick_OTHER(CCtrlButton *) + { + ShowLoadPublicKeyDialog(0, true); + refresh_key_list(); + } + + void onClick_DELETE_KEY(CCtrlButton *) + { + int i = list_KEY_LIST.GetSelectionMark(); + if (i == -1) + return; + list_KEY_LIST.GetItemText(i, 0, fp, _countof(fp)); + { gpg_execution_params params; - params.addParam(L"--version"); - bool _gpg_valid = globals.gpg_valid; - globals.gpg_valid = true; - gpg_launcher(params); - globals.gpg_valid = _gpg_valid; //TODO: check this - g_plugin.delSetting("szGpgBinPath"); - int p1 = params.out.Find("(GnuPG) "); - if (p1 != -1) { - p1 += mir_strlen("(GnuPG) "); - if (params.out[p1] != '1') - bad_version = true; - } - else { - bad_version = false; - MessageBox(nullptr, TranslateT("This is not GnuPG binary!\nIt is recommended that you use GnuPG v1.x.x with this plugin."), TranslateT("Error"), MB_OK); - } - if (bad_version) - MessageBox(nullptr, TranslateT("Unsupported GnuPG version found, use at you own risk!\nIt is recommended that you use GnuPG v1.x.x with this plugin."), TranslateT("Warning"), MB_OK); + params.addParam(L"--batch"); + params.addParam(L"--fingerprint"); + params.addParam(fp); + if (!gpg_launcher(params)) + return; + if (params.result == pxNotFound) + return; + + int s = params.out.Find("Key fingerprint = "); + s += mir_strlen("Key fingerprint = "); + int s2 = params.out.Find("\n", s); + + CMStringW tmp = params.out.Mid(s, s2 - s); + tmp.Remove(' '); + + gpg_execution_params params2; + params2.addParam(L"--batch"); + params2.addParam(L"--delete-secret-and-public-key"); + params2.addParam(L"--fingerprint"); + params2.addParam(tmp.c_str()); + + if (!gpg_launcher(params2)) + return; + if (params2.result == pxNotFound) + return; + } + + if (m_szCurrAcc == nullptr) { + g_plugin.delSetting("GPGPubKey"); + g_plugin.delSetting("KeyID"); + g_plugin.delSetting("KeyComment"); + g_plugin.delSetting("KeyMainName"); + g_plugin.delSetting("KeyMainEmail"); + g_plugin.delSetting("KeyType"); + } + else { + CMStringA acc_str = m_szCurrAcc; + g_plugin.delSetting(acc_str + "_GPGPubKey"); + g_plugin.delSetting(acc_str + "_KeyMainName"); + g_plugin.delSetting(acc_str + "_KeyID"); + g_plugin.delSetting(acc_str + "_KeyComment"); + g_plugin.delSetting(acc_str + "_KeyMainEmail"); + g_plugin.delSetting(acc_str + "_KeyType"); } + + list_KEY_LIST.DeleteItem(i); } + + void onClick_OK(CCtrlButton *) { - CMStringW tmp(g_plugin.getMStringW("szHomePath")); - if (tmp.IsEmpty()) { - wchar_t mir_path[MAX_PATH]; - PathToAbsoluteW(L"\\", mir_path); - mir_wstrcat(mir_path, L"\\gpg"); - if (_waccess(mir_path, 0) != -1) { - tmp = mir_path; - MessageBoxW(nullptr, TranslateT("\"GPG\" directory found in Miranda root.\nAssuming it's GPG home directory.\nGPG home directory set."), TranslateT("Info"), MB_OK); - } - else { - wstring path_ = _wgetenv(L"APPDATA"); - path_ += L"\\GnuPG"; - tmp = path_.c_str(); + int i = list_KEY_LIST.GetSelectionMark(); + if (i == -1) + return; + + list_KEY_LIST.GetItemText(i, 0, fp, _countof(fp)); + wchar_t name[65]; + list_KEY_LIST.GetItemText(i, 2, name, 64); + { + if (wcschr(name, '(')) { + wstring str = name; + wstring::size_type p = str.find(L"(") - 1; + mir_wstrcpy(name, str.substr(0, p).c_str()); } } - edit_HOME_DIR.SetText(!gpg_exists ? tmp : L"gpg"); - } - //TODO: additional check for write access - if (gpg_exists && lang_exists && !bad_version) - MessageBox(nullptr, TranslateT("Your GPG version is supported. The language file was found.\nGPG plugin should work fine.\nPress OK to continue."), TranslateT("Info"), MB_OK); - chk_AUTO_EXCHANGE.Enable(); - return true; -} -void CDlgGpgBinOpts::onClick_SET_BIN_PATH(CCtrlButton*) -{ - GetFilePath(L"Choose gpg.exe", "szGpgBinPath", L"*.exe", L"EXE Executables"); - CMStringW tmp(g_plugin.getMStringW("szGpgBinPath", L"gpg.exe")); - edit_BIN_PATH.SetText(tmp); - - wchar_t mir_path[MAX_PATH]; - PathToAbsoluteW(L"\\", mir_path); - if (tmp.Find(mir_path, 0) == 0) { - CMStringW path = tmp.Mid(mir_wstrlen(mir_path)); - edit_BIN_PATH.SetText(path); - } -} + gpg_execution_params params; + params.addParam(L"--batch"); + params.addParam(L"-a"); + params.addParam(L"--export"); + params.addParam(fp); + if (!gpg_launcher(params)) + return; + if (params.result == pxNotFound) + return; -void CDlgGpgBinOpts::onClick_SET_HOME_DIR(CCtrlButton*) -{ - GetFolderPath(L"Set home directory"); - CMStringW tmp(g_plugin.getMStringW("szHomePath")); - edit_HOME_DIR.SetText(tmp); - - wchar_t mir_path[MAX_PATH]; - PathToAbsoluteW(L"\\", mir_path); - PathToAbsoluteW(L"\\", mir_path); - if (tmp.Find(mir_path, 0) == 0) { - CMStringW path = tmp.Mid(mir_wstrlen(mir_path)); - edit_HOME_DIR.SetText(path); + params.out.Remove('\r'); + + if (m_szCurrAcc == nullptr) { + g_plugin.setString("GPGPubKey", params.out.c_str()); + g_plugin.setWString("KeyMainName", name); + g_plugin.setWString("KeyID", fp); + + wstring keyinfo = TranslateT("Default private key ID"); + keyinfo += L": "; + keyinfo += (fp[0]) ? fp : L"not set"; + extern HWND hwndCurKey_p; + SetWindowText(hwndCurKey_p, keyinfo.c_str()); + } + else { + CMStringA acc_str = m_szCurrAcc; + g_plugin.setString(acc_str + "_GPGPubKey", params.out.c_str()); + g_plugin.setWString(acc_str + "_KeyMainName", name); + g_plugin.setWString(acc_str + "_KeyID", fp); + } + + ptrW passwd(edit_KEY_PASSWORD.GetText()); + if (mir_wstrlen(passwd)) { + string dbsetting = "szKey_"; + dbsetting += _T2A(fp); + dbsetting += "_Password"; + g_plugin.setWString(dbsetting.c_str(), passwd); + } + + //bAutoExchange = CheckStateStoreDB(hwndDlg, IDC_AUTO_EXCHANGE, "bAutoExchange") != 0; //TODO: check is it just typo, or doing something + globals.gpg_valid = isGPGValid(); + globals.gpg_keyexist = isGPGKeyExist(); + DestroyWindow(m_hwnd); } -} -void CDlgGpgBinOpts::onClick_OK(CCtrlButton*) -{ - if (gpg_validate_paths(edit_BIN_PATH.GetText(), edit_HOME_DIR.GetText())) { - gpg_save_paths(edit_BIN_PATH.GetText(), edit_HOME_DIR.GetText()); - globals.gpg_valid = true; - g_plugin.setByte("FirstRun", 0); - this->Hide(); - CDlgFirstRun *d = new CDlgFirstRun; - d->Show(); - this->Close(); + void onChange_ACCOUNT(CCtrlCombo *pCombo) + { + CMStringW keyinfo = TranslateT("key ID"); + keyinfo += ": "; + + m_szCurrAcc = (const char *)pCombo->GetItemData(pCombo->GetCurSel()); + if (m_szCurrAcc == nullptr) { + keyinfo += g_plugin.getMStringW("KeyID", TranslateT("not set")); + } + else { + std::string acc_str = m_szCurrAcc; + acc_str += "_KeyID"; + keyinfo += g_plugin.getMStringW(acc_str.c_str(), TranslateT("not set")); + } + lbl_KEY_ID.SetText(keyinfo); } -} -void CDlgGpgBinOpts::onClick_GENERATE_RANDOM(CCtrlButton*) -{ - if (gpg_validate_paths(edit_BIN_PATH.GetText(), edit_HOME_DIR.GetText())) { - gpg_save_paths(edit_BIN_PATH.GetText(), edit_HOME_DIR.GetText()); - globals.gpg_valid = true; - if (gpg_use_new_random_key(nullptr)) { - g_plugin.bAutoExchange = chk_AUTO_EXCHANGE.GetState(); - globals.gpg_valid = true; - g_plugin.setByte("FirstRun", 0); - this->Close(); + void onChange_KEY_LIST(CCtrlListView::TEventInfo *ev) + { + if (ev->nmlv) { + NMLISTVIEW *hdr = ev->nmlv; + + if (hdr->hdr.code == NM_CLICK) { + btn_OK.Enable(); + btn_COPY_PUBKEY.Enable(); + btn_EXPORT_PRIVATE.Enable(); + btn_CHANGE_PASSWD.Enable(); + } } } -} +}; -void CDlgGpgBinOpts::OnDestroy() +void ShowFirstRunDialog() { - void InitCheck(); - InitCheck(); + CDlgFirstRun().DoModal(); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -848,342 +881,6 @@ void CDlgNewKey::onClick_IGNORE_KEY(CCtrlButton*) ///////////////////////////////////////////////////////////////////////////////////////// -CDlgKeyGen::CDlgKeyGen() : - CDlgBase(g_plugin, IDD_KEY_GEN), - combo_KEY_TYPE(this, IDC_KEY_TYPE), - edit_KEY_LENGTH(this, IDC_KEY_LENGTH), - edit_KEY_PASSWD(this, IDC_KEY_PASSWD), - edit_KEY_REAL_NAME(this, IDC_KEY_REAL_NAME), - edit_KEY_EMAIL(this, IDC_KEY_EMAIL), - edit_KEY_COMMENT(this, IDC_KEY_COMMENT), - edit_KEY_EXPIRE_DATE(this, IDC_KEY_EXPIRE_DATE), - lbl_GENERATING_TEXT(this, IDC_GENERATING_TEXT) -{ -} - -bool CDlgKeyGen::OnInitDialog() -{ - Utils_RestoreWindowPosition(m_hwnd, 0, MODULENAME, "KeygenWindow"); - SetCaption(TranslateT("Key Generation dialog")); - - combo_KEY_TYPE.AddString(L"RSA"); - combo_KEY_TYPE.AddString(L"DSA"); - combo_KEY_TYPE.SelectString(L"RSA"); - edit_KEY_EXPIRE_DATE.SetText(L"0"); - edit_KEY_LENGTH.SetText(L"4096"); - return true; -} - -bool CDlgKeyGen::OnApply() -{ - // data sanity checks - ptrW tmp(combo_KEY_TYPE.GetText()); - if (mir_wstrlen(tmp) < 3) { - MessageBox(nullptr, TranslateT("You must set encryption algorithm first"), TranslateT("Error"), MB_OK); - return false; - } - - tmp = edit_KEY_LENGTH.GetText(); - int length = _wtoi(tmp); - if (length < 1024 || length > 4096) { - MessageBox(nullptr, TranslateT("Key length must be of length from 1024 to 4096 bits"), TranslateT("Error"), MB_OK); - return false; - } - - tmp = edit_KEY_EXPIRE_DATE.GetText(); - if (mir_wstrlen(tmp) != 10 && tmp[0] != '0') { - MessageBox(nullptr, TranslateT("Invalid date"), TranslateT("Error"), MB_OK); - return false; - } - - tmp = edit_KEY_REAL_NAME.GetText(); - if (mir_wstrlen(tmp) < 5) { - MessageBox(nullptr, TranslateT("Name must contain at least 5 characters"), TranslateT("Error"), MB_OK); - return false; - } - if (wcschr(tmp, '(') || wcschr(tmp, ')')) { - MessageBox(nullptr, TranslateT("Name cannot contain '(' or ')'"), TranslateT("Error"), MB_OK); - return false; - } - - tmp = edit_KEY_EMAIL.GetText(); - if ((mir_wstrlen(tmp)) < 5 || (!wcschr(tmp, '@')) || (!wcschr(tmp, '.'))) { - MessageBox(nullptr, TranslateT("Invalid Email"), TranslateT("Error"), MB_OK); - return false; - } - - // generating key file - CMStringW path = g_plugin.getMStringW("szHomePath"); - path += L"\\new_key"; - wfstream f(path.c_str(), std::ios::out); - if (!f.is_open()) { - MessageBox(nullptr, TranslateT("Failed to open file"), TranslateT("Error"), MB_OK); - return false; - } - - f << "Key-Type: "; - char *tmp2 = mir_u2a(combo_KEY_TYPE.GetText()); - char *subkeytype = (char *)mir_alloc(6); - if (strstr(tmp2, "RSA")) - mir_strcpy(subkeytype, "RSA"); - else if (strstr(tmp2, "DSA")) //this is useless check for now, but it will be required if someone add another key types support - mir_strcpy(subkeytype, "ELG-E"); - f << tmp2; - mir_free(tmp2); - f << "\n"; - f << "Key-Length: "; - f << _wtoi(edit_KEY_LENGTH.GetText()); - f << "\n"; - f << "Subkey-Length: "; - f << _wtoi(edit_KEY_LENGTH.GetText()); - f << "\n"; - f << "Subkey-Type: "; - f << subkeytype; - mir_free(subkeytype); - f << "\n"; - if (edit_KEY_PASSWD.GetText()[0]) { - f << "Passphrase: "; - f << toUTF8(edit_KEY_PASSWD.GetText()).c_str(); - f << "\n"; - } - f << "Name-Real: "; - f << toUTF8(edit_KEY_REAL_NAME.GetText()).c_str(); - f << "\n"; - if (edit_KEY_COMMENT.GetText()[0]) { - f << "Name-Comment: "; - f << toUTF8(edit_KEY_COMMENT.GetText()).c_str(); - f << "\n"; - } - f << "Name-Email: "; - f << toUTF8(edit_KEY_EMAIL.GetText()).c_str(); - f << "\n"; - f << "Expire-Date: "; - f << toUTF8(edit_KEY_EXPIRE_DATE.GetText()).c_str(); - f << "\n"; - f.close(); - - lbl_GENERATING_TEXT.SendMsg(WM_SETFONT, (WPARAM)globals.bold_font, TRUE); - lbl_GENERATING_TEXT.SetText(TranslateT("Generating new key, please wait...")); - combo_KEY_TYPE.Disable(); - edit_KEY_LENGTH.Disable(); - edit_KEY_PASSWD.Disable(); - edit_KEY_REAL_NAME.Disable(); - edit_KEY_EMAIL.Disable(); - edit_KEY_COMMENT.Disable(); - edit_KEY_EXPIRE_DATE.Disable(); - - // gpg execution - gpg_execution_params params; - params.addParam(L"--batch"); - params.addParam(L"--yes"); - params.addParam(L"--gen-key"); - params.addParam(path.c_str()); - params.bNoOutput = true; - if (!gpg_launcher(params, boost::posix_time::minutes(10))) - return false; - if (params.result == pxNotFound) - return false; - - boost::filesystem::remove(path.c_str()); - return true; -} - -void CDlgKeyGen::OnDestroy() -{ - Utils_SaveWindowPosition(m_hwnd, 0, MODULENAME, "KeygenWindow"); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -CDlgLoadExistingKey::CDlgLoadExistingKey() : - CDlgBase(g_plugin, IDD_LOAD_EXISTING_KEY), - list_EXISTING_KEY_LIST(this, IDC_EXISTING_KEY_LIST) -{ - id[0] = 0; -} - -bool CDlgLoadExistingKey::OnInitDialog() -{ - Utils_RestoreWindowPosition(m_hwnd, 0, MODULENAME, "LoadKeyWindow"); - - list_EXISTING_KEY_LIST.AddColumn(0, TranslateT("Key ID"), 50); - list_EXISTING_KEY_LIST.AddColumn(1, TranslateT("Email"), 30); - list_EXISTING_KEY_LIST.AddColumn(2, TranslateT("Name"), 250); - list_EXISTING_KEY_LIST.AddColumn(3, TranslateT("Creation date"), 30); - list_EXISTING_KEY_LIST.AddColumn(4, TranslateT("Expiration date"), 30); - list_EXISTING_KEY_LIST.AddColumn(5, TranslateT("Key length"), 30); - list_EXISTING_KEY_LIST.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT | LVS_EX_SINGLEROW); - int i = 1; - { - // parse gpg output - gpg_execution_params params; - params.addParam(L"--batch"); - params.addParam(L"--list-keys"); - if (!gpg_launcher(params)) - return false; - if (params.result == pxNotFound) - return false; - - string out(params.out); - string::size_type p = 0, p2 = 0, stop = 0; - while (p != string::npos) { - if ((p = out.find("pub ", p)) == string::npos) - break; - p += 5; - if (p < stop) - break; - stop = p; - p2 = out.find("/", p) - 1; - wchar_t *tmp = mir_wstrdup(toUTF16(out.substr(p, p2 - p)).c_str()); - int row = list_EXISTING_KEY_LIST.AddItem(L"", 0); - list_EXISTING_KEY_LIST.SetItemText(row, 5, tmp); - mir_free(tmp); - p2 += 2; - p = out.find(" ", p2); - tmp = mir_wstrdup(toUTF16(out.substr(p2, p - p2)).c_str()); - list_EXISTING_KEY_LIST.SetItemText(row, 0, tmp); - mir_free(tmp); - p++; - p2 = out.find("\n", p); - string::size_type p3 = out.substr(p, p2 - p).find("["); - if (p3 != string::npos) { - p3 += p; - p2 = p3; - p2--; - p3++; - p3 += mir_strlen("expires: "); - string::size_type p4 = out.find("]", p3); - tmp = mir_wstrdup(toUTF16(out.substr(p3, p4 - p3)).c_str()); - list_EXISTING_KEY_LIST.SetItemText(row, 4, tmp); - mir_free(tmp); - } - else - p2--; - tmp = mir_wstrdup(toUTF16(out.substr(p, p2 - p)).c_str()); - list_EXISTING_KEY_LIST.SetItemText(row, 3, tmp); - mir_free(tmp); - p = out.find("uid ", p); - p += mir_strlen("uid "); - p2 = out.find("\n", p); - p3 = out.substr(p, p2 - p).find("<"); - if (p3 != string::npos) { - p3 += p; - p2 = p3; - p2--; - p3++; - string::size_type p4 = out.find(">", p3); - tmp = mir_wstrdup(toUTF16(out.substr(p3, p4 - p3)).c_str()); - list_EXISTING_KEY_LIST.SetItemText(row, 1, tmp); - mir_free(tmp); - } - else - p2--; - p = out.find_first_not_of(" ", p); - tmp = mir_wstrdup(toUTF16(out.substr(p, p2 - p)).c_str()); - list_EXISTING_KEY_LIST.SetItemText(row, 2, tmp); - mir_free(tmp); - - list_EXISTING_KEY_LIST.SetColumnWidth(0, LVSCW_AUTOSIZE);// not sure about this - list_EXISTING_KEY_LIST.SetColumnWidth(1, LVSCW_AUTOSIZE); - list_EXISTING_KEY_LIST.SetColumnWidth(2, LVSCW_AUTOSIZE); - list_EXISTING_KEY_LIST.SetColumnWidth(3, LVSCW_AUTOSIZE); - list_EXISTING_KEY_LIST.SetColumnWidth(4, LVSCW_AUTOSIZE); - list_EXISTING_KEY_LIST.SetColumnWidth(5, LVSCW_AUTOSIZE); - i++; - } - } - list_EXISTING_KEY_LIST.OnClick = Callback(this, &CDlgLoadExistingKey::onChange_EXISTING_KEY_LIST); - return true; -} - -void CDlgLoadExistingKey::OnDestroy() -{ - Utils_SaveWindowPosition(m_hwnd, 0, MODULENAME, "LoadKeyWindow"); -} - -bool CDlgLoadExistingKey::OnApply() -{ - int i = list_EXISTING_KEY_LIST.GetSelectionMark(); - if (i == -1) - return false; //TODO: error message - - list_EXISTING_KEY_LIST.GetItemText(i, 0, id, _countof(id)); - extern CCtrlEdit *edit_p_PubKeyEdit; - - gpg_execution_params params; - params.addParam(L"--batch"); - params.addParam(L"-a"); - params.addParam(L"--export"); - params.addParam(id); - if (!gpg_launcher(params)) - return false; - if (params.result == pxNotFound) - return false; - - string out(params.out); - std::string::size_type p1 = 0, p2 = 0; - p1 = out.find("-----BEGIN PGP PUBLIC KEY BLOCK-----"); - if (p1 != std::string::npos) { - p2 = out.find("-----END PGP PUBLIC KEY BLOCK-----", p1); - if (p2 != std::string::npos) { - p2 += mir_strlen("-----END PGP PUBLIC KEY BLOCK-----"); - out = out.substr(p1, p2 - p1); - wchar_t *tmp = mir_a2u(out.c_str()); - if (edit_p_PubKeyEdit) - edit_p_PubKeyEdit->SetText(tmp); - mir_free(tmp); - } - else MessageBox(nullptr, TranslateT("Failed to export public key."), TranslateT("Error"), MB_OK); - } - else MessageBox(nullptr, TranslateT("Failed to export public key."), TranslateT("Error"), MB_OK); - - return true; -} - -void CDlgLoadExistingKey::onChange_EXISTING_KEY_LIST(CCtrlListView::TEventInfo*) -{ - EnableWindow(GetDlgItem(m_hwnd, IDOK), TRUE); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -CDlgImportKey::CDlgImportKey(MCONTACT _hContact) : - CDlgBase(g_plugin, IDD_IMPORT_KEY), - combo_KEYSERVER(this, IDC_KEYSERVER), - btn_IMPORT(this, IDC_IMPORT) -{ - hContact = _hContact; - btn_IMPORT.OnClick = Callback(this, &CDlgImportKey::onClick_IMPORT); -} - -bool CDlgImportKey::OnInitDialog() -{ - Utils_RestoreWindowPosition(m_hwnd, 0, MODULENAME, "ImportKeyWindow"); - - combo_KEYSERVER.AddString(L"subkeys.pgp.net"); - combo_KEYSERVER.AddString(L"keys.gnupg.net"); - return true; -} - -void CDlgImportKey::OnDestroy() -{ - Utils_SaveWindowPosition(m_hwnd, 0, MODULENAME, "ImportKeyWindow"); -} - -void CDlgImportKey::onClick_IMPORT(CCtrlButton*) -{ - gpg_execution_params params; - params.addParam(L"--keyserver"); - params.addParam(combo_KEYSERVER.GetText()); - params.addParam(L"--recv-keys"); - params.addParam(toUTF16(globals.hcontact_data[hContact].key_in_prescense)); - gpg_launcher(params); - - MessageBoxA(nullptr, params.out.c_str(), "GPG output", MB_OK); -} - -///////////////////////////////////////////////////////////////////////////////////////// - CDlgKeyPasswordMsgBox::CDlgKeyPasswordMsgBox(MCONTACT _hContact) : CDlgBase(g_plugin, IDD_KEY_PASSWD), lbl_KEYID(this, IDC_KEYID), diff --git a/plugins/New_GPG/src/ui.h b/plugins/New_GPG/src/ui.h index e5c0c2c5ad..d97c7e09e5 100755 --- a/plugins/New_GPG/src/ui.h +++ b/plugins/New_GPG/src/ui.h @@ -18,6 +18,7 @@ #define UI_H void ShowLoadPublicKeyDialog(MCONTACT hContact, bool bModal); +void ShowFirstRunDialog(); class CDlgEncryptedFileMsgBox : public CDlgBase { @@ -32,72 +33,6 @@ public: void onClick_DECRYPT(CCtrlButton*); }; -class CDlgExportKeysMsgBox : public CDlgBase -{ - CCtrlCheck chk_PUBLIC, chk_PRIVATE, chk_ALL; - -public: - CDlgExportKeysMsgBox(); - - bool OnInitDialog() override; - bool OnApply() override; -}; - -class CDlgChangePasswdMsgBox : public CDlgBase //always modal -{ - CCtrlEdit edit_NEW_PASSWD1, edit_NEW_PASSWD2, edit_OLD_PASSWD; - -public: - CDlgChangePasswdMsgBox(); - - bool OnApply() override; -}; - -class CDlgFirstRun : public CDlgBase -{ - void refresh_key_list(); - CCtrlListView list_KEY_LIST; - CCtrlButton btn_COPY_PUBKEY, btn_EXPORT_PRIVATE, btn_CHANGE_PASSWD, btn_GENERATE_RANDOM, btn_GENERATE_KEY, btn_OTHER, btn_DELETE_KEY, btn_OK; - CCtrlEdit edit_KEY_PASSWORD; - CCtrlCombo combo_ACCOUNT; - CCtrlData lbl_KEY_ID, lbl_GENERATING_KEY; - wchar_t fp[16]; - const char *m_szCurrAcc = nullptr; - -public: - CDlgFirstRun(); - bool OnInitDialog() override; - void OnDestroy() override; - - void onClick_COPY_PUBKEY(CCtrlButton*); - void onClick_EXPORT_PRIVATE(CCtrlButton*); - void onClick_CHANGE_PASSWD(CCtrlButton*); - void onClick_GENERATE_RANDOM(CCtrlButton*); - void onClick_GENERATE_KEY(CCtrlButton*); - void onClick_OTHER(CCtrlButton*); - void onClick_DELETE_KEY(CCtrlButton*); - void onClick_OK(CCtrlButton*); - void onChange_ACCOUNT(CCtrlCombo*); - void onChange_KEY_LIST(CCtrlListView::TEventInfo *ev); -}; - -class CDlgGpgBinOpts : public CDlgBase -{ - CCtrlButton btn_SET_BIN_PATH, btn_SET_HOME_DIR, btn_OK, btn_GENERATE_RANDOM; - CCtrlEdit edit_BIN_PATH, edit_HOME_DIR; - CCtrlCheck chk_AUTO_EXCHANGE; - -public: - CDlgGpgBinOpts(); - bool OnInitDialog() override; - void OnDestroy() override; - - void onClick_SET_BIN_PATH(CCtrlButton*); - void onClick_SET_HOME_DIR(CCtrlButton*); - void onClick_OK(CCtrlButton*); - void onClick_GENERATE_RANDOM(CCtrlButton*); -}; - class CDlgNewKey : public CDlgBase { wstring new_key; @@ -115,48 +50,6 @@ public: void onClick_IGNORE_KEY(CCtrlButton*); }; -class CDlgKeyGen : public CDlgBase //TODO: in modal mode window destroying on any button press even without direct "Close" call -{ - CCtrlCombo combo_KEY_TYPE; - CCtrlEdit edit_KEY_LENGTH, edit_KEY_PASSWD, edit_KEY_REAL_NAME, edit_KEY_EMAIL, edit_KEY_COMMENT, edit_KEY_EXPIRE_DATE; - CCtrlData lbl_GENERATING_TEXT; - -public: - CDlgKeyGen(); - - bool OnInitDialog() override; - bool OnApply() override; - void OnDestroy() override; -}; - -class CDlgLoadExistingKey : public CDlgBase -{ - wchar_t id[16]; - CCtrlListView list_EXISTING_KEY_LIST; - -public: - CDlgLoadExistingKey(); - bool OnInitDialog() override; - bool OnApply() override; - void OnDestroy() override; - - void onChange_EXISTING_KEY_LIST(CCtrlListView::TEventInfo * /*ev*/); -}; - -class CDlgImportKey : public CDlgBase -{ - MCONTACT hContact; - CCtrlCombo combo_KEYSERVER; - CCtrlButton btn_IMPORT; - -public: - CDlgImportKey(MCONTACT hContact); - bool OnInitDialog() override; - void OnDestroy() override; - - void onClick_IMPORT(CCtrlButton*); -}; - class CDlgKeyPasswordMsgBox : public CDlgBase //always modal { char *inkeyid = nullptr; diff --git a/plugins/New_GPG/src/utilities.cpp b/plugins/New_GPG/src/utilities.cpp index 3bbcbc2162..bcfd9205ef 100755 --- a/plugins/New_GPG/src/utilities.cpp +++ b/plugins/New_GPG/src/utilities.cpp @@ -303,8 +303,8 @@ int onProtoAck(WPARAM, LPARAM l) else g_plugin.setString(ack->hContact, "InKeyID", out.substr(s, s2 - s).c_str()); } - CDlgKeyPasswordMsgBox *d = new CDlgKeyPasswordMsgBox(ack->hContact); - d->DoModal(); + + CDlgKeyPasswordMsgBox(ack->hContact).DoModal(); if (!globals.wszPassword.IsEmpty()) { if (globals.debuglog) @@ -1015,12 +1015,6 @@ void ExportGpGKeysFunc(int type) MessageBox(nullptr, msg, TranslateT("Keys export result"), MB_OK); } -INT_PTR ExportGpGKeys(WPARAM, LPARAM) -{ - (new CDlgExportKeysMsgBox())->Show(); - return 0; -} - INT_PTR ImportGpGKeys(WPARAM, LPARAM) { ptrW p(GetFilePath(L"Choose file to import keys from", L"*", L"Any file")); @@ -1272,12 +1266,6 @@ void ShowEncryptedFileMsgBox() d->DoModal(); } -void ShowChangePasswdDlg() -{ - CDlgChangePasswdMsgBox *d = new CDlgChangePasswdMsgBox; - d->DoModal(); -} - void clean_temp_dir() { using namespace boost::filesystem; |