/* Jabber Protocol Plugin for Miranda NG Copyright (c) 2002-04 Santithorn Bunchua Copyright (c) 2005-12 George Hazan Copyright (c) 2007 Maxim Mluhov Copyright (c) 2012-18 Miranda NG team 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 "stdafx.h" #include "jabber_list.h" #include "jabber_caps.h" #include "jabber_opttree.h" static BOOL(WINAPI *pfnEnableThemeDialogTexture)(HANDLE, DWORD) = nullptr; ///////////////////////////////////////////////////////////////////////////////////////// // JabberRegisterDlgProc - the dialog proc for registering new account #define STR_FORMAT L"%s %s@%S:%d?" struct { wchar_t *szCode; wchar_t *szDescription; } g_LanguageCodes[] = { { L"aa", LPGENW("Afar") }, { L"ab", LPGENW("Abkhazian") }, { L"af", LPGENW("Afrikaans") }, { L"ak", LPGENW("Akan") }, { L"sq", LPGENW("Albanian") }, { L"am", LPGENW("Amharic") }, { L"ar", LPGENW("Arabic") }, { L"an", LPGENW("Aragonese") }, { L"hy", LPGENW("Armenian") }, { L"as", LPGENW("Assamese") }, { L"av", LPGENW("Avaric") }, { L"ae", LPGENW("Avestan") }, { L"ay", LPGENW("Aymara") }, { L"az", LPGENW("Azerbaijani") }, { L"ba", LPGENW("Bashkir") }, { L"bm", LPGENW("Bambara") }, { L"eu", LPGENW("Basque") }, { L"be", LPGENW("Belarusian") }, { L"bn", LPGENW("Bengali") }, { L"bh", LPGENW("Bihari") }, { L"bi", LPGENW("Bislama") }, { L"bs", LPGENW("Bosnian") }, { L"br", LPGENW("Breton") }, { L"bg", LPGENW("Bulgarian") }, { L"my", LPGENW("Burmese") }, { L"ca", LPGENW("Catalan; Valencian") }, { L"ch", LPGENW("Chamorro") }, { L"ce", LPGENW("Chechen") }, { L"zh", LPGENW("Chinese") }, { L"cu", LPGENW("Church Slavic; Old Slavonic") }, { L"cv", LPGENW("Chuvash") }, { L"kw", LPGENW("Cornish") }, { L"co", LPGENW("Corsican") }, { L"cr", LPGENW("Cree") }, { L"cs", LPGENW("Czech") }, { L"da", LPGENW("Danish") }, { L"dv", LPGENW("Divehi; Dhivehi; Maldivian") }, { L"nl", LPGENW("Dutch; Flemish") }, { L"dz", LPGENW("Dzongkha") }, { L"en", LPGENW("English") }, { L"eo", LPGENW("Esperanto") }, { L"et", LPGENW("Estonian") }, { L"ee", LPGENW("Ewe") }, { L"fo", LPGENW("Faroese") }, { L"fj", LPGENW("Fijian") }, { L"fi", LPGENW("Finnish") }, { L"fr", LPGENW("French") }, { L"fy", LPGENW("Western Frisian") }, { L"ff", LPGENW("Fulah") }, { L"ka", LPGENW("Georgian") }, { L"de", LPGENW("German") }, { L"gd", LPGENW("Gaelic; Scottish Gaelic") }, { L"ga", LPGENW("Irish") }, { L"gl", LPGENW("Galician") }, { L"gv", LPGENW("Manx") }, { L"el", LPGENW("Greek, Modern (1453-)") }, { L"gn", LPGENW("Guarani") }, { L"gu", LPGENW("Gujarati") }, { L"ht", LPGENW("Haitian; Haitian Creole") }, { L"ha", LPGENW("Hausa") }, { L"he", LPGENW("Hebrew") }, { L"hz", LPGENW("Herero") }, { L"hi", LPGENW("Hindi") }, { L"ho", LPGENW("Hiri Motu") }, { L"hu", LPGENW("Hungarian") }, { L"ig", LPGENW("Igbo") }, { L"is", LPGENW("Icelandic") }, { L"io", LPGENW("Ido") }, { L"ii", LPGENW("Sichuan Yi") }, { L"iu", LPGENW("Inuktitut") }, { L"ie", LPGENW("Interlingue") }, { L"ia", LPGENW("Interlingua (International Auxiliary Language Association)") }, { L"id", LPGENW("Indonesian") }, { L"ik", LPGENW("Inupiaq") }, { L"it", LPGENW("Italian") }, { L"jv", LPGENW("Javanese") }, { L"ja", LPGENW("Japanese") }, { L"kl", LPGENW("Kalaallisut; Greenlandic") }, { L"kn", LPGENW("Kannada") }, { L"ks", LPGENW("Kashmiri") }, { L"kr", LPGENW("Kanuri") }, { L"kk", LPGENW("Kazakh") }, { L"km", LPGENW("Central Khmer") }, { L"ki", LPGENW("Kikuyu; Gikuyu") }, { L"rw", LPGENW("Kinyarwanda") }, { L"ky", LPGENW("Kirghiz; Kyrgyz") }, { L"kv", LPGENW("Komi") }, { L"kg", LPGENW("Kongo") }, { L"ko", LPGENW("Korean") }, { L"kj", LPGENW("Kuanyama; Kwanyama") }, { L"ku", LPGENW("Kurdish") }, { L"lo", LPGENW("Lao") }, { L"la", LPGENW("Latin") }, { L"lv", LPGENW("Latvian") }, { L"li", LPGENW("Limburgan; Limburger; Limburgish") }, { L"ln", LPGENW("Lingala") }, { L"lt", LPGENW("Lithuanian") }, { L"lb", LPGENW("Luxembourgish; Letzeburgesch") }, { L"lu", LPGENW("Luba-Katanga") }, { L"lg", LPGENW("Ganda") }, { L"mk", LPGENW("Macedonian") }, { L"mh", LPGENW("Marshallese") }, { L"ml", LPGENW("Malayalam") }, { L"mi", LPGENW("Maori") }, { L"mr", LPGENW("Marathi") }, { L"ms", LPGENW("Malay") }, { L"mg", LPGENW("Malagasy") }, { L"mt", LPGENW("Maltese") }, { L"mo", LPGENW("Moldavian") }, { L"mn", LPGENW("Mongolian") }, { L"na", LPGENW("Nauru") }, { L"nv", LPGENW("Navajo; Navaho") }, { L"nr", LPGENW("Ndebele, South; South Ndebele") }, { L"nd", LPGENW("Ndebele, North; North Ndebele") }, { L"ng", LPGENW("Ndonga") }, { L"ne", LPGENW("Nepali") }, { L"nn", LPGENW("Norwegian Nynorsk; Nynorsk, Norwegian") }, { L"nb", LPGENW("Bokmaal, Norwegian; Norwegian Bokmaal") }, { L"no", LPGENW("Norwegian") }, { L"ny", LPGENW("Chichewa; Chewa; Nyanja") }, { L"oc", LPGENW("Occitan (post 1500); Provencal") }, { L"oj", LPGENW("Ojibwa") }, { L"or", LPGENW("Oriya") }, { L"om", LPGENW("Oromo") }, { L"os", LPGENW("Ossetian; Ossetic") }, { L"pa", LPGENW("Panjabi; Punjabi") }, { L"fa", LPGENW("Persian") }, { L"pi", LPGENW("Pali") }, { L"pl", LPGENW("Polish") }, { L"pt", LPGENW("Portuguese") }, { L"ps", LPGENW("Pushto") }, { L"qu", LPGENW("Quechua") }, { L"rm", LPGENW("Romansh") }, { L"ro", LPGENW("Romanian") }, { L"rn", LPGENW("Rundi") }, { L"ru", LPGENW("Russian") }, { L"sg", LPGENW("Sango") }, { L"sa", LPGENW("Sanskrit") }, { L"sr", LPGENW("Serbian") }, { L"hr", LPGENW("Croatian") }, { L"si", LPGENW("Sinhala; Sinhalese") }, { L"sk", LPGENW("Slovak") }, { L"sl", LPGENW("Slovenian") }, { L"se", LPGENW("Northern Sami") }, { L"sm", LPGENW("Samoan") }, { L"sn", LPGENW("Shona") }, { L"sd", LPGENW("Sindhi") }, { L"so", LPGENW("Somali") }, { L"st", LPGENW("Sotho, Southern") }, { L"es", LPGENW("Spanish; Castilian") }, { L"sc", LPGENW("Sardinian") }, { L"ss", LPGENW("Swati") }, { L"su", LPGENW("Sundanese") }, { L"sw", LPGENW("Swahili") }, { L"sv", LPGENW("Swedish") }, { L"ty", LPGENW("Tahitian") }, { L"ta", LPGENW("Tamil") }, { L"tt", LPGENW("Tatar") }, { L"te", LPGENW("Telugu") }, { L"tg", LPGENW("Tajik") }, { L"tl", LPGENW("Tagalog") }, { L"th", LPGENW("Thai") }, { L"bo", LPGENW("Tibetan") }, { L"ti", LPGENW("Tigrinya") }, { L"to", LPGENW("Tonga (Tonga Islands)") }, { L"tn", LPGENW("Tswana") }, { L"ts", LPGENW("Tsonga") }, { L"tk", LPGENW("Turkmen") }, { L"tr", LPGENW("Turkish") }, { L"tw", LPGENW("Twi") }, { L"ug", LPGENW("Uighur; Uyghur") }, { L"uk", LPGENW("Ukrainian") }, { L"ur", LPGENW("Urdu") }, { L"uz", LPGENW("Uzbek") }, { L"ve", LPGENW("Venda") }, { L"vi", LPGENW("Vietnamese") }, { L"vo", LPGENW("Volapuk") }, { L"cy", LPGENW("Welsh") }, { L"wa", LPGENW("Walloon") }, { L"wo", LPGENW("Wolof") }, { L"xh", LPGENW("Xhosa") }, { L"yi", LPGENW("Yiddish") }, { L"yo", LPGENW("Yoruba") }, { L"za", LPGENW("Zhuang; Chuang") }, { L"zu", LPGENW("Zulu") }, { nullptr, nullptr } }; class CJabberDlgRegister : public CJabberDlgBase { typedef CJabberDlgBase CSuper; public: CJabberDlgRegister(CJabberProto *proto, HWND hwndParent, JABBER_CONN_DATA *regInfo) : CJabberDlgBase(proto, IDD_OPT_REGISTER), m_bProcessStarted(false), m_regInfo(regInfo), m_btnOk(this, IDOK) { SetParent(hwndParent); m_autoClose = CLOSE_ON_CANCEL; m_btnOk.OnClick = Callback(this, &CJabberDlgRegister::btnOk_OnClick); } protected: bool OnInitDialog() override { wchar_t text[256]; mir_snwprintf(text, STR_FORMAT, TranslateT("Register"), m_regInfo->username, m_regInfo->server, m_regInfo->port); SetDlgItemText(m_hwnd, IDC_REG_STATUS, text); return true; } INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override { switch (msg) { case WM_JABBER_REGDLG_UPDATE: // wParam=progress (0-100), lparam=status string if ((wchar_t*)lParam == nullptr) SetDlgItemText(m_hwnd, IDC_REG_STATUS, TranslateT("No message")); else SetDlgItemText(m_hwnd, IDC_REG_STATUS, (wchar_t*)lParam); SendDlgItemMessage(m_hwnd, IDC_PROGRESS_REG, PBM_SETPOS, wParam, 0); if (wParam >= 100) m_btnOk.SetText(TranslateT("Close")); else SetFocus(GetDlgItem(m_hwnd, IDC_PROGRESS_REG)); return TRUE; } return CSuper::DlgProc(msg, wParam, lParam); } private: bool m_bProcessStarted; JABBER_CONN_DATA *m_regInfo; CCtrlButton m_btnOk; void btnOk_OnClick(CCtrlButton*) { if (m_bProcessStarted) { Close(); return; } ShowWindow(GetDlgItem(m_hwnd, IDC_PROGRESS_REG), SW_SHOW); m_regInfo->reg_hwndDlg = m_hwnd; m_proto->ForkThread((CJabberProto::MyThreadFunc)&CJabberProto::ServerThread, m_regInfo); m_btnOk.SetText(TranslateT("Cancel")); m_bProcessStarted = true; } }; ///////////////////////////////////////////////////////////////////////////////////////// // JabberOptDlgProc - main options dialog procedure class CCtrlEditJid : public CCtrlEdit { typedef CCtrlEdit CSuper; public: CCtrlEditJid(CDlgBase *dlg, int ctrlId); void OnInit() { CCtrlEdit::OnInit(); Subclass(); } protected: virtual LRESULT CustomWndProc(UINT msg, WPARAM wParam, LPARAM lParam) { if (msg == WM_CHAR) { switch (wParam) { case '\"': case '&': case '\'': case '/': case ':': case '<': case '>': case '@': MessageBeep(MB_ICONASTERISK); return 0; } } return CCtrlEdit::CustomWndProc(msg, wParam, lParam); } }; CCtrlEditJid::CCtrlEditJid(CDlgBase* dlg, int ctrlId): CCtrlEdit(dlg, ctrlId) { } static void sttStoreJidFromUI(CJabberProto *ppro, CCtrlEdit &txtUsername, CCtrlCombo &cbServer) { ppro->setWString("jid", CMStringW(FORMAT, L"%s@%s", ptrW(txtUsername.GetText()), ptrW(cbServer.GetText()))); } class CDlgOptAccount : public CJabberDlgBase { typedef CJabberDlgBase CSuper; CCtrlEditJid m_txtUsername; CCtrlEdit m_txtPassword; CCtrlEdit m_txtPriority; CCtrlCheck m_chkSavePassword; CCtrlCombo m_cbResource; CCtrlCheck m_chkUseHostnameAsResource; CCtrlCheck m_chkUseDomainLogin; CCtrlCombo m_cbServer; CCtrlEdit m_txtPort; CCtrlCheck m_chkUseSsl; CCtrlCheck m_chkUseTls; CCtrlCheck m_chkManualHost; CCtrlEdit m_txtManualHost; CCtrlEdit m_txtManualPort; CCtrlCheck m_chkKeepAlive; CCtrlCheck m_chkAutoDeleteContacts; CCtrlEdit m_txtUserDirectory; CCtrlCombo m_cbLocale; CCtrlButton m_btnRegister; CCtrlButton m_btnUnregister; CCtrlButton m_btnChangePassword; CCtrlHyperlink m_lnkServers; public: CDlgOptAccount(CJabberProto *proto) : CJabberDlgBase(proto, IDD_OPT_JABBER), m_txtUsername(this, IDC_EDIT_USERNAME), m_txtPassword(this, IDC_EDIT_PASSWORD), m_txtPriority(this, IDC_PRIORITY), m_chkSavePassword(this, IDC_SAVEPASSWORD), m_cbResource(this, IDC_COMBO_RESOURCE), m_chkUseHostnameAsResource(this, IDC_HOSTNAME_AS_RESOURCE), m_chkUseDomainLogin(this, IDC_USEDOMAINLOGIN), m_cbServer(this, IDC_EDIT_LOGIN_SERVER), m_txtPort(this, IDC_PORT), m_chkUseSsl(this, IDC_USE_SSL), m_chkUseTls(this, IDC_USE_TLS), m_chkManualHost(this, IDC_MANUAL), m_txtManualHost(this, IDC_HOST), m_txtManualPort(this, IDC_HOSTPORT), m_chkKeepAlive(this, IDC_KEEPALIVE), m_chkAutoDeleteContacts(this, IDC_ROSTER_SYNC), m_txtUserDirectory(this, IDC_JUD), m_cbLocale(this, IDC_MSGLANG), m_btnRegister(this, IDC_BUTTON_REGISTER), m_btnUnregister(this, IDC_UNREGISTER), m_btnChangePassword(this, IDC_BUTTON_CHANGE_PASSWORD), m_gotservers(false), m_lnkServers(this, IDC_LINK_PUBLIC_SERVER, "https://xmpp.net/directory.php") { CreateLink(m_txtUsername, "LoginName", L""); CreateLink(m_txtPriority, "Priority", DBVT_DWORD, 0); CreateLink(m_chkSavePassword, proto->m_bSavePassword); CreateLink(m_cbResource, "Resource", L"Miranda"); CreateLink(m_chkUseHostnameAsResource, proto->m_bHostNameAsResource); CreateLink(m_chkUseDomainLogin, proto->m_bUseDomainLogin); CreateLink(m_cbServer, "LoginServer", L"jabber.org"); CreateLink(m_txtPort, "Port", DBVT_WORD, 5222); CreateLink(m_chkUseSsl, proto->m_bUseSSL); CreateLink(m_chkUseTls, proto->m_bUseTLS); CreateLink(m_chkManualHost, proto->m_bManualConnect); CreateLink(m_txtManualHost, "ManualHost", L""); CreateLink(m_txtManualPort, "ManualPort", DBVT_WORD, 0); CreateLink(m_chkKeepAlive, proto->m_bKeepAlive); CreateLink(m_chkAutoDeleteContacts, proto->m_bRosterSync); CreateLink(m_txtUserDirectory, "Jud", L""); // Bind events m_cbServer.OnDropdown = Callback(this, &CDlgOptAccount::cbServer_OnDropdown); m_chkManualHost.OnChange = Callback(this, &CDlgOptAccount::chkManualHost_OnChange); m_chkUseHostnameAsResource.OnChange = Callback(this, &CDlgOptAccount::chkUseHostnameAsResource_OnChange); m_chkUseDomainLogin.OnChange = Callback(this, &CDlgOptAccount::chkUseDomainLogin_OnChange); m_chkUseSsl.OnChange = Callback(this, &CDlgOptAccount::chkUseSsl_OnChange); m_chkUseTls.OnChange = Callback(this, &CDlgOptAccount::chkUseTls_OnChange); m_btnRegister.OnClick = Callback(this, &CDlgOptAccount::btnRegister_OnClick); m_btnUnregister.OnClick = Callback(this, &CDlgOptAccount::btnUnregister_OnClick); m_btnChangePassword.OnClick = Callback(this, &CDlgOptAccount::btnChangePassword_OnClick); } protected: bool OnInitDialog() override { CSuper::OnInitDialog(); SendDlgItemMessage(m_hwnd, IDC_PRIORITY_SPIN, UDM_SETRANGE, 0, (LPARAM)MAKELONG(127, -128)); wchar_t *passw = m_proto->getWStringA(0, "Password"); if (passw) { m_txtPassword.SetText(passw); mir_free(passw); } m_cbServer.AddString(TranslateT("Loading...")); // fill predefined resources wchar_t *szResources[] = { L"Home", L"Work", L"Office", L"Miranda" }; for (auto &it : szResources) m_cbResource.AddString(it); // append computer name to the resource list wchar_t szCompName[MAX_COMPUTERNAME_LENGTH + 1]; DWORD dwCompNameLength = MAX_COMPUTERNAME_LENGTH; if (GetComputerName(szCompName, &dwCompNameLength)) m_cbResource.AddString(szCompName); ptrW tszResource(m_proto->getWStringA("Resource")); if (tszResource != nullptr) { if (CB_ERR == m_cbResource.FindString(tszResource, -1, true)) m_cbResource.AddString(tszResource); m_cbResource.SetText(tszResource); } else m_cbResource.SetText(L"Miranda"); for (int i = 0; g_LanguageCodes[i].szCode; i++) { int iItem = m_cbLocale.AddString(TranslateW(g_LanguageCodes[i].szDescription), (LPARAM)g_LanguageCodes[i].szCode); if (!mir_wstrcmp(m_proto->m_tszSelectedLang, g_LanguageCodes[i].szCode)) m_cbLocale.SetCurSel(iItem); } EnableWindow(GetDlgItem(m_hwnd, IDC_COMBO_RESOURCE), m_chkUseHostnameAsResource.GetState() != BST_CHECKED); EnableWindow(GetDlgItem(m_hwnd, IDC_UNREGISTER), m_proto->m_bJabberOnline); m_chkUseTls.Enable(!m_proto->m_bDisable3920auth && (m_proto->m_bUseSSL ? false : true)); if (m_proto->m_bDisable3920auth) m_chkUseTls.SetState(BST_UNCHECKED); m_chkUseSsl.Enable(m_proto->m_bDisable3920auth || (m_proto->m_bUseTLS ? false : true)); if (m_proto->m_bManualConnect) { m_txtManualHost.Enable(); m_txtManualPort.Enable(); m_txtPort.Disable(); } if (m_proto->m_bUseDomainLogin) chkUseDomainLogin_OnChange(&m_chkUseDomainLogin); CheckRegistration(); return true; } bool OnApply() override { // clear saved password m_proto->m_savedPassword = nullptr; if (m_chkSavePassword.GetState() == BST_CHECKED) m_proto->setWString("Password", ptrW(m_txtPassword.GetText())); else m_proto->delSetting("Password"); int index = m_cbLocale.GetCurSel(); if (index >= 0) { wchar_t *szLanguageCode = (wchar_t *)m_cbLocale.GetItemData(index); if (szLanguageCode) { m_proto->setWString("XmlLang", szLanguageCode); mir_free(m_proto->m_tszSelectedLang); m_proto->m_tszSelectedLang = mir_wstrdup(szLanguageCode); } } sttStoreJidFromUI(m_proto, m_txtUsername, m_cbServer); if (m_proto->m_bJabberOnline) { if (m_txtUsername.IsChanged() || m_txtPassword.IsChanged() || m_cbResource.IsChanged() || m_cbServer.IsChanged() || m_chkUseHostnameAsResource.IsChanged() || m_txtPort.IsChanged() || m_txtManualHost.IsChanged() || m_txtManualPort.IsChanged() || m_cbLocale.IsChanged()) { MessageBox(m_hwnd, TranslateT("These changes will take effect the next time you connect to the Jabber network."), TranslateT("Jabber Protocol Option"), MB_OK | MB_SETFOREGROUND); } m_proto->SendPresence(m_proto->m_iStatus, true); } return true; } void OnChange(CCtrlBase*) { if (m_initialized) CheckRegistration(); } INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override { switch (msg) { case WM_ACTIVATE: m_chkUseTls.Enable(!m_proto->m_bDisable3920auth && (m_proto->m_bUseSSL ? false : true)); if (m_proto->m_bDisable3920auth) m_chkUseTls.SetState(BST_UNCHECKED); break; case WM_JABBER_REFRESH: RefreshServers((HXML)lParam); break; } return CSuper::DlgProc(msg, wParam, lParam); } private: bool m_gotservers; void btnRegister_OnClick(CCtrlButton *) { PSHNOTIFY pshn = {}; pshn.hdr.code = PSN_APPLY; pshn.hdr.hwndFrom = m_hwnd; SendMessage(m_hwnd, WM_NOTIFY, 0, (LPARAM)&pshn); JABBER_CONN_DATA regInfo; m_txtUsername.GetText(regInfo.username, _countof(regInfo.username)); m_txtPassword.GetText(regInfo.password, _countof(regInfo.password)); m_cbServer.GetTextA(regInfo.server, _countof(regInfo.server)); if (m_chkManualHost.GetState() == BST_CHECKED) { regInfo.port = (WORD)m_txtManualPort.GetInt(); m_txtManualHost.GetTextA(regInfo.manualHost, _countof(regInfo.manualHost)); } else { regInfo.port = (WORD)m_txtPort.GetInt(); regInfo.manualHost[0] = '\0'; } if (regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port > 0 && ((m_chkManualHost.GetState() != BST_CHECKED) || regInfo.manualHost[0])) { CJabberDlgRegister dlg(m_proto, m_hwnd, ®Info); dlg.DoModal(); } } void btnUnregister_OnClick(CCtrlButton *) { int res = MessageBox(nullptr, TranslateT("This operation will kill your account, roster and all other information stored at the server. Are you ready to do that?"), TranslateT("Account removal warning"), MB_YESNOCANCEL); if (res == IDYES) m_proto->m_ThreadInfo->send( XmlNodeIq(L"set", m_proto->SerialNext(), m_proto->m_szJabberJID) << XQUERY(JABBER_FEAT_REGISTER) << XCHILD(L"remove")); } void btnChangePassword_OnClick(CCtrlButton *) { if (!m_proto->m_bJabberOnline) { MessageBox(nullptr, TranslateT("You can change your password only when you are online"), TranslateT("You must be online"), MB_OK | MB_ICONSTOP); return; } m_proto->OnMenuHandleChangePassword(0, 0); } void cbServer_OnDropdown(CCtrlCombo*) { if (!m_gotservers) mir_forkThread(QueryServerListThread, this); } void chkManualHost_OnChange(CCtrlData *sender) { CCtrlCheck *chk = (CCtrlCheck *)sender; if (chk->GetState() == BST_CHECKED) { m_txtManualHost.Enable(); m_txtManualPort.Enable(); m_txtPort.Disable(); } else { m_txtManualHost.Disable(); m_txtManualPort.Disable(); m_txtPort.Enable(); } } void chkUseHostnameAsResource_OnChange(CCtrlData *sender) { CCtrlCheck *chk = (CCtrlCheck *)sender; m_cbResource.Enable(chk->GetState() != BST_CHECKED); if (chk->GetState() == BST_CHECKED) { wchar_t szCompName[MAX_COMPUTERNAME_LENGTH + 1]; DWORD dwCompNameLength = MAX_COMPUTERNAME_LENGTH; if (GetComputerName(szCompName, &dwCompNameLength)) m_cbResource.SetText(szCompName); } } void chkUseDomainLogin_OnChange(CCtrlData *sender) { CCtrlCheck *chk = (CCtrlCheck *)sender; BOOL checked = chk->GetState() == BST_CHECKED; m_txtPassword.Enable(!checked); m_txtUsername.Enable(!checked); m_chkSavePassword.Enable(!checked); if (checked) { m_txtPassword.SetText(L""); m_txtUsername.SetText(L""); m_chkSavePassword.SetState(BST_CHECKED); } } void chkUseSsl_OnChange(CCtrlData*) { BOOL bManualHost = m_chkManualHost.GetState() == BST_CHECKED; if (m_chkUseSsl.GetState() == BST_CHECKED) { m_chkUseTls.Disable(); if (!bManualHost) m_txtPort.SetInt(5223); } else { if (!m_proto->m_bDisable3920auth) m_chkUseTls.Enable(); if (!bManualHost) m_txtPort.SetInt(5222); } } void chkUseTls_OnChange(CCtrlData*) { if (m_chkUseTls.GetState() == BST_CHECKED) m_chkUseSsl.Disable(); else m_chkUseSsl.Enable(); } void CheckRegistration() { JABBER_CONN_DATA regInfo; m_txtUsername.GetText(regInfo.username, _countof(regInfo.username)); m_txtPassword.GetText(regInfo.password, _countof(regInfo.password)); m_cbServer.GetTextA(regInfo.server, _countof(regInfo.server)); if (m_chkManualHost.GetState() == BST_CHECKED) { regInfo.port = (WORD)m_txtManualPort.GetInt(); m_txtManualHost.GetTextA(regInfo.manualHost, _countof(regInfo.manualHost)); } else { regInfo.port = (WORD)m_txtPort.GetInt(); regInfo.manualHost[0] = '\0'; } if (regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port > 0 && ((m_chkManualHost.GetState() != BST_CHECKED) || regInfo.manualHost[0])) EnableWindow(GetDlgItem(m_hwnd, IDC_BUTTON_REGISTER), TRUE); else EnableWindow(GetDlgItem(m_hwnd, IDC_BUTTON_REGISTER), FALSE); } void RefreshServers(HXML node) { m_gotservers = node != nullptr; wchar_t *server = m_cbServer.GetText(); bool bDropdown = m_cbServer.GetDroppedState(); if (bDropdown) m_cbServer.ShowDropdown(false); m_cbServer.ResetContent(); if (node) { for (int i = 0;; i++) { HXML n = XmlGetChild(node, i); if (!n) break; if (!mir_wstrcmp(XmlGetName(n), L"item")) if (const wchar_t *jid = XmlGetAttrValue(n, L"jid")) if (m_cbServer.FindString(jid, -1, true) == CB_ERR) m_cbServer.AddString(jid); } } m_cbServer.SetText(server); if (bDropdown) m_cbServer.ShowDropdown(); mir_free(server); } static void __cdecl QueryServerListThread(CDlgOptAccount *wnd) { Thread_SetName("Jabber: QueryServerListThread"); HWND hwnd = wnd->GetHwnd(); bool bIsError = true; if (!IsWindow(hwnd)) return; NETLIBHTTPREQUEST request = { 0 }; request.cbSize = sizeof(request); request.requestType = REQUEST_GET; request.flags = NLHRF_REDIRECT | NLHRF_HTTP11; request.szUrl = JABBER_SERVER_URL; NETLIBHTTPREQUEST *result = Netlib_HttpTransaction(wnd->GetProto()->m_hNetlibUser, &request); if (result) { if (result->resultCode == 200 && result->dataLength && result->pData) { wchar_t *buf = mir_a2u(result->pData); XmlNode node(buf, nullptr, nullptr); if (node) { HXML queryNode = XmlGetChild(node, L"query"); SendMessage(hwnd, WM_JABBER_REFRESH, 0, (LPARAM)queryNode); bIsError = false; } mir_free(buf); } Netlib_FreeHttpRequest(result); } if (bIsError) SendMessage(hwnd, WM_JABBER_REFRESH, 0, 0); } }; ///////////////////////////////////////////////////////////////////////////////////////// // JabberAdvOptDlgProc - advanced options dialog procedure class CDlgOptAdvanced : public CJabberDlgBase { typedef CJabberDlgBase CSuper; CCtrlCheck m_chkDirect; CCtrlCheck m_chkDirectManual; CCtrlCheck m_chkProxy; CCtrlEdit m_txtDirect; CCtrlEdit m_txtProxy; CCtrlTreeOpts m_otvOptions; BYTE m_oldFrameValue; public: CDlgOptAdvanced(CJabberProto *proto) : CJabberDlgBase(proto, IDD_OPT_JABBER2), m_chkDirect(this, IDC_DIRECT), m_chkDirectManual(this, IDC_DIRECT_MANUAL), m_chkProxy(this, IDC_PROXY_MANUAL), m_txtDirect(this, IDC_DIRECT_ADDR), m_txtProxy(this, IDC_PROXY_ADDR), m_otvOptions(this, IDC_OPTTREE), m_oldFrameValue(proto->m_bDisableFrame) { CreateLink(m_chkDirect, proto->m_bBsDirect); CreateLink(m_chkDirectManual, proto->m_bBsDirectManual); CreateLink(m_chkProxy, proto->m_bBsProxyManual); CreateLink(m_txtDirect, "BsDirectAddr", L""); CreateLink(m_txtProxy, "BsProxyServer", L""); m_chkDirect.OnChange = m_chkDirectManual.OnChange = Callback(this, &CDlgOptAdvanced::chkDirect_OnChange); m_chkProxy.OnChange = Callback(this, &CDlgOptAdvanced::chkProxy_OnChange); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Send messages slower, but with full acknowledgment"), m_proto->m_bMsgAck); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Enable avatars"), m_proto->m_bEnableAvatars); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Log chat state changes"), m_proto->m_bLogChatstates); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Log presence subscription state changes"), m_proto->m_bLogPresence); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Log presence errors"), m_proto->m_bLogPresenceErrors); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Enable user moods receiving"), m_proto->m_bEnableUserMood); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Enable user tunes receiving"), m_proto->m_bEnableUserTune); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Enable user activity receiving"), m_proto->m_bEnableUserActivity); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Receive notes"), m_proto->m_bAcceptNotes); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Automatically save received notes"), m_proto->m_bAutosaveNotes); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Enable server-side history (XEP-0136)"), m_proto->m_bEnableMsgArchive); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Receive conversations from other devices (XEP-0280)"), m_proto->m_bEnableCarbons); m_otvOptions.AddOption(LPGENW("Messaging") L"/" LPGENW("Use Stream Management (XEP-0198) if possible (Testing)"), m_proto->m_bEnableStreamMgmt); m_otvOptions.AddOption(LPGENW("Server options") L"/" LPGENW("Disable SASL authentication (for old servers)"), m_proto->m_bDisable3920auth); m_otvOptions.AddOption(LPGENW("Server options") L"/" LPGENW("Enable stream compression (if possible)"), m_proto->m_bEnableZlib); m_otvOptions.AddOption(LPGENW("Other") L"/" LPGENW("Enable remote controlling (from another resource of same JID only)"), m_proto->m_bEnableRemoteControl); m_otvOptions.AddOption(LPGENW("Other") L"/" LPGENW("Show transport agents on contact list"), m_proto->m_bShowTransport); m_otvOptions.AddOption(LPGENW("Other") L"/" LPGENW("Automatically add contact when accept authorization"), m_proto->m_bAutoAdd); m_otvOptions.AddOption(LPGENW("Other") L"/" LPGENW("Automatically accept authorization requests"), m_proto->m_bAutoAcceptAuthorization); m_otvOptions.AddOption(LPGENW("Other") L"/" LPGENW("Fix incorrect timestamps in incoming messages"), m_proto->m_bFixIncorrectTimestamps); m_otvOptions.AddOption(LPGENW("Other") L"/" LPGENW("Disable frame"), m_proto->m_bDisableFrame); m_otvOptions.AddOption(LPGENW("Other") L"/" LPGENW("Enable XMPP link processing (requires AssocMgr)"), m_proto->m_bProcessXMPPLinks); m_otvOptions.AddOption(LPGENW("Other") L"/" LPGENW("Keep contacts assigned to local groups (ignore roster group)"), m_proto->m_bIgnoreRosterGroups); m_otvOptions.AddOption(LPGENW("Security") L"/" LPGENW("Allow servers to request version (XEP-0092)"), m_proto->m_bAllowVersionRequests); m_otvOptions.AddOption(LPGENW("Security") L"/" LPGENW("Show information about operating system in version replies"), m_proto->m_bShowOSVersion); m_otvOptions.AddOption(LPGENW("Security") L"/" LPGENW("Accept only in band incoming filetransfers (don't disclose own IP)"), m_proto->m_bBsOnlyIBB); m_otvOptions.AddOption(LPGENW("Security") L"/" LPGENW("Accept HTTP Authentication requests (XEP-0070)"), m_proto->m_bAcceptHttpAuth); m_otvOptions.AddOption(LPGENW("Security") L"/" LPGENW("Use OMEMO encryption for messages if possible (XEP-0384) (Basic support without GUI)"), m_proto->m_bUseOMEMO); } bool OnInitDialog() override { CSuper::OnInitDialog(); chkDirect_OnChange(&m_chkDirect); chkProxy_OnChange(&m_chkProxy); return true; } bool OnApply() override { if (m_proto->m_bDisableFrame != m_oldFrameValue) { m_proto->InitInfoFrame(); // create or destroy a frame m_oldFrameValue = m_proto->m_bDisableFrame; } BOOL bChecked = m_proto->m_bShowTransport; LISTFOREACH(index, m_proto, LIST_ROSTER) { JABBER_LIST_ITEM *item = m_proto->ListGetItemPtrFromIndex(index); if (item != nullptr) { if (wcschr(item->jid, '@') == nullptr) { MCONTACT hContact = m_proto->HContactFromJID(item->jid); if (hContact != 0) { if (bChecked) { if (item->getTemp()->m_iStatus != m_proto->getWord(hContact, "Status", ID_STATUS_OFFLINE)) { m_proto->setWord(hContact, "Status", (WORD)item->getTemp()->m_iStatus); } } else if (m_proto->getWord(hContact, "Status", ID_STATUS_OFFLINE) != ID_STATUS_OFFLINE) m_proto->setWord(hContact, "Status", ID_STATUS_OFFLINE); } } } } if (m_proto->m_bUseOMEMO) m_proto->m_omemo.init(); else m_proto->m_omemo.deinit(); m_proto->m_clientCapsManager.UpdateFeatHash(); m_proto->SendPresence(m_proto->m_iStatus, true); return true; } void chkDirect_OnChange(CCtrlData *) { if (m_chkDirect.GetState() == BST_CHECKED) { if (m_chkDirectManual.GetState() == BST_CHECKED) m_txtDirect.Enable(); else m_txtDirect.Disable(); m_chkDirectManual.Enable(); } else { m_txtDirect.Disable(); m_chkDirectManual.Disable(); } } void chkProxy_OnChange(CCtrlData *) { if (m_chkProxy.GetState() == BST_CHECKED) m_txtProxy.Enable(); else m_txtProxy.Disable(); } }; ///////////////////////////////////////////////////////////////////////////////////////// // JabberGcOptDlgProc - chat options dialog procedure class CDlgOptGc : public CJabberDlgBase { typedef CJabberDlgBase CSuper; CCtrlEdit m_txtAltNick; CCtrlEdit m_txtSlap; CCtrlEdit m_txtQuit; CCtrlTreeOpts m_otvOptions; public: CDlgOptGc(CJabberProto *proto) : CJabberDlgBase(proto, IDD_OPT_JABBER4), m_txtAltNick(this, IDC_TXT_ALTNICK), m_txtSlap(this, IDC_TXT_SLAP), m_txtQuit(this, IDC_TXT_QUIT), m_otvOptions(this, IDC_OPTTREE) { CreateLink(m_txtAltNick, "GcAltNick", L""); CreateLink(m_txtSlap, "GcMsgSlap", TranslateW(JABBER_GC_MSG_SLAP)); CreateLink(m_txtQuit, "GcMsgQuit", TranslateW(JABBER_GC_MSG_QUIT)); m_otvOptions.AddOption(LPGENW("General") L"/" LPGENW("Autoaccept multiuser chat invitations"), m_proto->m_bAutoAcceptMUC); m_otvOptions.AddOption(LPGENW("General") L"/" LPGENW("Automatically join bookmarks on login"), m_proto->m_bAutoJoinBookmarks); m_otvOptions.AddOption(LPGENW("General") L"/" LPGENW("Automatically join conferences on login"), m_proto->m_bAutoJoinConferences); m_otvOptions.AddOption(LPGENW("General") L"/" LPGENW("Hide conference windows at startup"), m_proto->m_bAutoJoinHidden); m_otvOptions.AddOption(LPGENW("General") L"/" LPGENW("Do not show multiuser chat invitations"), m_proto->m_bIgnoreMUCInvites); m_otvOptions.AddOption(LPGENW("Log events") L"/" LPGENW("Ban notifications"), m_proto->m_bGcLogBans); m_otvOptions.AddOption(LPGENW("Log events") L"/" LPGENW("Room configuration changes"), m_proto->m_bGcLogConfig); m_otvOptions.AddOption(LPGENW("Log events") L"/" LPGENW("Affiliation changes"), m_proto->m_bGcLogAffiliations); m_otvOptions.AddOption(LPGENW("Log events") L"/" LPGENW("Role changes"), m_proto->m_bGcLogRoles); m_otvOptions.AddOption(LPGENW("Log events") L"/" LPGENW("Status changes"), m_proto->m_bGcLogStatuses); m_otvOptions.AddOption(LPGENW("Log events") L"/" LPGENW("Don't notify history messages"), m_proto->m_bGcLogChatHistory); } }; ////////////////////////////////////////////////////////////////////////// // roster editor // #include #define JM_STATUSCHANGED WM_USER+0x0001 #define fopent(name, mode) _wfopen(name, mode) enum { RRA_FILLLIST = 0, RRA_SYNCROSTER, RRA_SYNCDONE }; struct ROSTEREDITDAT { HWND hList; int index; int subindex; }; static int _RosterInsertListItem(HWND hList, const wchar_t *jid, const wchar_t *nick, const wchar_t *group, const wchar_t *subscr, BOOL bChecked) { LVITEM item = { 0 }; item.mask = LVIF_TEXT | LVIF_STATE; item.iItem = ListView_GetItemCount(hList); item.pszText = (wchar_t*)jid; int index = ListView_InsertItem(hList, &item); if (index < 0) return index; ListView_SetCheckState(hList, index, bChecked); ListView_SetItemText(hList, index, 0, (wchar_t*)jid); ListView_SetItemText(hList, index, 1, (wchar_t*)nick); ListView_SetItemText(hList, index, 2, (wchar_t*)group); ListView_SetItemText(hList, index, 3, TranslateW(subscr)); return index; } static void _RosterListClear(HWND hwndDlg) { HWND hList = GetDlgItem(hwndDlg, IDC_ROSTER); if (!hList) return; ListView_DeleteAllItems(hList); while (ListView_DeleteColumn(hList, 0)); LV_COLUMN column = { 0 }; column.mask = LVCF_TEXT; column.cx = 500; column.pszText = TranslateT("JID"); ListView_InsertColumn(hList, 1, &column); column.pszText = TranslateT("Nickname"); ListView_InsertColumn(hList, 2, &column); column.pszText = TranslateT("Group"); ListView_InsertColumn(hList, 3, &column); column.pszText = TranslateT("Subscription"); ListView_InsertColumn(hList, 4, &column); RECT rc; GetClientRect(hList, &rc); int width = rc.right - rc.left; ListView_SetColumnWidth(hList, 0, width * 40 / 100); ListView_SetColumnWidth(hList, 1, width * 25 / 100); ListView_SetColumnWidth(hList, 2, width * 20 / 100); ListView_SetColumnWidth(hList, 3, width * 10 / 100); } void CJabberProto::_RosterHandleGetRequest(HXML node, CJabberIqInfo*) { HWND hList = GetDlgItem(rrud.hwndDlg, IDC_ROSTER); if (rrud.bRRAction == RRA_FILLLIST) { _RosterListClear(rrud.hwndDlg); HXML query = XmlGetChild(node, "query"); if (query == nullptr) return; int i = 1; while (TRUE) { HXML item = XmlGetNthChild(query, L"item", i++); if (item == nullptr) break; const wchar_t *jid = XmlGetAttrValue(item, L"jid"); if (jid == nullptr) continue; const wchar_t *name = XmlGetAttrValue(item, L"name"); const wchar_t *subscription = XmlGetAttrValue(item, L"subscription"); const wchar_t *group = XmlGetText(XmlGetChild(item, "group")); _RosterInsertListItem(hList, jid, name, group, subscription, TRUE); } // now it is require to process whole contact list to add not in roster contacts for (auto &hContact : AccContacts()) { ptrW tszJid(getWStringA(hContact, "jid")); if (tszJid == nullptr) continue; LVFINDINFO lvfi = { 0 }; lvfi.flags = LVFI_STRING; lvfi.psz = tszJid; wchar_t *p = wcschr(tszJid, '@'); if (p) { p = wcschr(tszJid, '/'); if (p) *p = 0; } if (ListView_FindItem(hList, -1, &lvfi) == -1) { ptrW tszName(db_get_wsa(hContact, "CList", "MyHandle")); ptrW tszGroup(db_get_wsa(hContact, "CList", "Group")); _RosterInsertListItem(hList, tszJid, tszName, tszGroup, nullptr, FALSE); } } rrud.bReadyToDownload = FALSE; rrud.bReadyToUpload = TRUE; SetDlgItemText(rrud.hwndDlg, IDC_DOWNLOAD, TranslateT("Download")); SetDlgItemText(rrud.hwndDlg, IDC_UPLOAD, TranslateT("Upload")); SendMessage(rrud.hwndDlg, JM_STATUSCHANGED, 0, 0); return; } if (rrud.bRRAction == RRA_SYNCROSTER) { SetDlgItemText(rrud.hwndDlg, IDC_UPLOAD, TranslateT("Uploading...")); HXML queryRoster = XmlGetChild(node, "query"); if (!queryRoster) return; XmlNodeIq iq(AddIQ(&CJabberProto::_RosterHandleGetRequest, JABBER_IQ_TYPE_SET)); HXML query = iq << XCHILDNS(L"query", JABBER_FEAT_IQ_ROSTER); int itemCount = 0; int ListItemCount = ListView_GetItemCount(hList); for (int index = 0; index < ListItemCount; index++) { wchar_t jid[JABBER_MAX_JID_LEN] = L""; wchar_t name[260] = L""; wchar_t group[260] = L""; wchar_t subscr[260] = L""; ListView_GetItemText(hList, index, 0, jid, _countof(jid)); ListView_GetItemText(hList, index, 1, name, _countof(name)); ListView_GetItemText(hList, index, 2, group, _countof(group)); ListView_GetItemText(hList, index, 3, subscr, _countof(subscr)); HXML itemRoster = XmlGetChildByTag(queryRoster, "item", "jid", jid); BOOL bRemove = !ListView_GetCheckState(hList, index); if (itemRoster && bRemove) { //delete item query << XCHILD(L"item") << XATTR(L"jid", jid) << XATTR(L"subscription", L"remove"); itemCount++; } else if (!bRemove) { BOOL bPushed = itemRoster ? TRUE : FALSE; if (!bPushed) { const wchar_t *rosterName = XmlGetAttrValue(itemRoster, L"name"); if ((rosterName != nullptr || name[0] != 0) && mir_wstrcmpi(rosterName, name)) bPushed = TRUE; if (!bPushed) { rosterName = XmlGetAttrValue(itemRoster, L"subscription"); if ((rosterName != nullptr || subscr[0] != 0) && mir_wstrcmpi(rosterName, subscr)) bPushed = TRUE; } if (!bPushed) { const wchar_t *rosterGroup = XmlGetText(XmlGetChild(itemRoster, "group")); if ((rosterGroup != nullptr || group[0] != 0) && mir_wstrcmpi(rosterGroup, group)) bPushed = TRUE; } } if (bPushed) { HXML item = query << XCHILD(L"item"); if (mir_wstrlen(group)) item << XCHILD(L"group", group); if (mir_wstrlen(name)) item << XATTR(L"name", name); item << XATTR(L"jid", jid) << XATTR(L"subscription", subscr[0] ? subscr : L"none"); itemCount++; } } } rrud.bRRAction = RRA_SYNCDONE; if (itemCount) m_ThreadInfo->send(iq); else _RosterSendRequest(rrud.hwndDlg, RRA_FILLLIST); } else { SetDlgItemText(rrud.hwndDlg, IDC_UPLOAD, TranslateT("Upload")); rrud.bReadyToUpload = rrud.bReadyToDownload = FALSE; SendMessage(rrud.hwndDlg, JM_STATUSCHANGED, 0, 0); SetDlgItemText(rrud.hwndDlg, IDC_DOWNLOAD, TranslateT("Downloading...")); _RosterSendRequest(rrud.hwndDlg, RRA_FILLLIST); } } void CJabberProto::_RosterSendRequest(HWND hwndDlg, BYTE rrAction) { rrud.bRRAction = rrAction; rrud.hwndDlg = hwndDlg; m_ThreadInfo->send( XmlNodeIq(AddIQ(&CJabberProto::_RosterHandleGetRequest, JABBER_IQ_TYPE_GET)) << XCHILDNS(L"query", JABBER_FEAT_IQ_ROSTER)); } static void _RosterItemEditEnd(HWND hEditor, ROSTEREDITDAT * edat, BOOL bCancel) { if (!bCancel) { int len = GetWindowTextLength(hEditor) + 1; wchar_t *buff = (wchar_t*)mir_alloc(len*sizeof(wchar_t)); if (buff) { GetWindowText(hEditor, buff, len); ListView_SetItemText(edat->hList, edat->index, edat->subindex, buff); } mir_free(buff); } DestroyWindow(hEditor); } static LRESULT CALLBACK _RosterItemNewEditProc(HWND hEditor, UINT msg, WPARAM wParam, LPARAM lParam) { ROSTEREDITDAT * edat = (ROSTEREDITDAT *)GetWindowLongPtr(hEditor, GWLP_USERDATA); if (!edat) return 0; switch (msg) { case WM_KEYDOWN: switch (wParam) { case VK_RETURN: _RosterItemEditEnd(hEditor, edat, FALSE); return 0; case VK_ESCAPE: _RosterItemEditEnd(hEditor, edat, TRUE); return 0; } break; case WM_GETDLGCODE: if (lParam) { MSG *msg2 = (MSG*)lParam; if (msg2->message == WM_KEYDOWN && msg2->wParam == VK_TAB) return 0; if (msg2->message == WM_CHAR && msg2->wParam == '\t') return 0; } return DLGC_WANTMESSAGE; case WM_KILLFOCUS: _RosterItemEditEnd(hEditor, edat, FALSE); return 0; case WM_DESTROY: SetWindowLongPtr(hEditor, GWLP_USERDATA, (LONG_PTR)0); free(edat); return 0; } return mir_callNextSubclass(hEditor, _RosterItemNewEditProc, msg, wParam, lParam); } void CJabberProto::_RosterExportToFile(HWND hwndDlg) { wchar_t filename[MAX_PATH] = { 0 }; wchar_t filter[MAX_PATH]; mir_snwprintf(filter, L"%s (*.xml)%c*.xml%c%c", TranslateT("XML for MS Excel (UTF-8 encoded)"), 0, 0, 0); OPENFILENAME ofn = { 0 }; ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; ofn.hwndOwner = hwndDlg; ofn.hInstance = nullptr; ofn.lpstrFilter = filter; ofn.lpstrFile = filename; ofn.Flags = OFN_HIDEREADONLY; ofn.nMaxFile = _countof(filename); ofn.nMaxFileTitle = MAX_PATH; ofn.lpstrDefExt = L"xml"; if (!GetSaveFileName(&ofn)) return; FILE * fp = fopent(filename, L"w"); if (!fp) return; HWND hList = GetDlgItem(hwndDlg, IDC_ROSTER); int ListItemCount = ListView_GetItemCount(hList); XmlNode root(L"Workbook"); root << XATTR(L"xmlns", L"urn:schemas-microsoft-com:office:spreadsheet") << XATTR(L"xmlns:o", L"urn:schemas-microsoft-com:office:office") << XATTR(L"xmlns:x", L"urn:schemas-microsoft-com:office:excel") << XATTR(L"xmlns:ss", L"urn:schemas-microsoft-com:office:spreadsheet") << XATTR(L"xmlns:html", L"http://www.w3.org/TR/REC-html40"); root << XCHILD(L"ExcelWorkbook") << XATTR(L"xmlns", L"urn:schemas-microsoft-com:office:excel"); HXML table = root << XCHILD(L"Worksheet") << XATTR(L"ss:Name", L"Exported roster") << XCHILD(L"Table"); for (int index = 0; index < ListItemCount; index++) { wchar_t jid[JABBER_MAX_JID_LEN] = L""; wchar_t name[260] = L""; wchar_t group[260] = L""; wchar_t subscr[260] = L""; ListView_GetItemText(hList, index, 0, jid, _countof(jid)); ListView_GetItemText(hList, index, 1, name, _countof(name)); ListView_GetItemText(hList, index, 2, group, _countof(group)); ListView_GetItemText(hList, index, 3, subscr, _countof(subscr)); HXML node = table << XCHILD(L"Row"); node << XCHILD(L"Cell") << XCHILD(L"Data", L"+") << XATTR(L"ss:Type", L"String"); node << XCHILD(L"Cell") << XCHILD(L"Data", jid) << XATTR(L"ss:Type", L"String"); node << XCHILD(L"Cell") << XCHILD(L"Data", name) << XATTR(L"ss:Type", L"String"); node << XCHILD(L"Cell") << XCHILD(L"Data", group) << XATTR(L"ss:Type", L"String"); node << XCHILD(L"Cell") << XCHILD(L"Data", subscr) << XATTR(L"ss:Type", L"String"); } char header[] = "\n\n"; fwrite(header, 1, sizeof(header) - 1 /* for zero terminator */, fp); wchar_t *xtmp = xmlToString(root, nullptr); fputs(T2Utf(xtmp), fp); xmlFree(xtmp); fclose(fp); } void CJabberProto::_RosterImportFromFile(HWND hwndDlg) { char filename[MAX_PATH] = { 0 }; char *filter = "XML for MS Excel (UTF-8 encoded)(*.xml)\0*.xml\0\0"; OPENFILENAMEA ofn = { 0 }; ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; ofn.hwndOwner = hwndDlg; ofn.hInstance = nullptr; ofn.lpstrFilter = filter; ofn.lpstrFile = filename; ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.nMaxFile = _countof(filename); ofn.nMaxFileTitle = MAX_PATH; ofn.lpstrDefExt = "xml"; if (!GetOpenFileNameA(&ofn)) return; FILE * fp = fopen(filename, "r"); if (!fp) return; DWORD bufsize = _filelength(_fileno(fp)); if (bufsize <= 0) { fclose(fp); return; } char* buffer = (char*)mir_calloc(bufsize + 1); // zero-terminate it fread(buffer, 1, bufsize, fp); fclose(fp); _RosterListClear(hwndDlg); wchar_t *newBuf = mir_utf8decodeW(buffer); mir_free(buffer); int nBytesProcessed = 0; XmlNode node(newBuf, &nBytesProcessed, nullptr); if (node) { HXML Workbook = XmlGetChild(node, L"Workbook"); if (Workbook) { HXML Worksheet = XmlGetChild(Workbook, "Worksheet"); if (Worksheet) { HXML Table = XmlGetChild(Worksheet, "Table"); if (Table) { int index = 1; HWND hList = GetDlgItem(hwndDlg, IDC_ROSTER); while (TRUE) { HXML Row = XmlGetNthChild(Table, L"Row", index++); if (!Row) break; BOOL bAdd = FALSE; const wchar_t *jid = nullptr; const wchar_t *name = nullptr; const wchar_t *group = nullptr; const wchar_t *subscr = nullptr; HXML Cell = XmlGetNthChild(Row, L"Cell", 1); HXML Data = (Cell) ? XmlGetChild(Cell, "Data") : XmlNode(); if (Data) { if (!mir_wstrcmpi(XmlGetText(Data), L"+")) bAdd = TRUE; else if (mir_wstrcmpi(XmlGetText(Data), L"-")) continue; Cell = XmlGetNthChild(Row, L"Cell", 2); if (Cell) Data = XmlGetChild(Cell, "Data"); else Data = nullptr; if (Data) { jid = XmlGetText(Data); if (!jid || mir_wstrlen(jid) == 0) continue; } Cell = XmlGetNthChild(Row, L"Cell", 3); if (Cell) Data = XmlGetChild(Cell, "Data"); else Data = nullptr; if (Data) name = XmlGetText(Data); Cell = XmlGetNthChild(Row, L"Cell", 4); if (Cell) Data = XmlGetChild(Cell, "Data"); else Data = nullptr; if (Data) group = XmlGetText(Data); Cell = XmlGetNthChild(Row, L"Cell", 5); if (Cell) Data = XmlGetChild(Cell, "Data"); else Data = nullptr; if (Data) subscr = XmlGetText(Data); } _RosterInsertListItem(hList, jid, name, group, subscr, bAdd); } } } } } mir_free(newBuf); SendMessage(hwndDlg, JM_STATUSCHANGED, 0, 0); } static LRESULT CALLBACK _RosterNewListProc(HWND hList, UINT msg, WPARAM wParam, LPARAM lParam) { if (msg == WM_MOUSEWHEEL || msg == WM_NCLBUTTONDOWN || msg == WM_NCRBUTTONDOWN) SetFocus(hList); if (msg == WM_LBUTTONDOWN) { POINT pt; GetCursorPos(&pt); ScreenToClient(hList, &pt); LVHITTESTINFO lvhti = { 0 }; lvhti.pt = pt; ListView_SubItemHitTest(hList, &lvhti); if (lvhti.flags&LVHT_ONITEM && lvhti.iSubItem != 0) { RECT rc; wchar_t buff[260]; ListView_GetSubItemRect(hList, lvhti.iItem, lvhti.iSubItem, LVIR_BOUNDS, &rc); ListView_GetItemText(hList, lvhti.iItem, lvhti.iSubItem, buff, _countof(buff)); HWND hEditor = CreateWindow(TEXT("EDIT"), buff, WS_CHILD | ES_AUTOHSCROLL, rc.left + 3, rc.top + 2, rc.right - rc.left - 3, rc.bottom - rc.top - 3, hList, nullptr, g_plugin.getInst(), nullptr); SendMessage(hEditor, WM_SETFONT, (WPARAM)SendMessage(hList, WM_GETFONT, 0, 0), 0); ShowWindow(hEditor, SW_SHOW); SetWindowText(hEditor, buff); ClientToScreen(hList, &pt); ScreenToClient(hEditor, &pt); mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0); mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); ROSTEREDITDAT * edat = (ROSTEREDITDAT *)malloc(sizeof(ROSTEREDITDAT)); mir_subclassWindow(hEditor, _RosterItemNewEditProc); edat->hList = hList; edat->index = lvhti.iItem; edat->subindex = lvhti.iSubItem; SetWindowLongPtr(hEditor, GWLP_USERDATA, (LONG_PTR)edat); } } return mir_callNextSubclass(hList, _RosterNewListProc, msg, wParam, lParam); } ///////////////////////////////////////////////////////////////////////////////////////// // JabberRosterOptDlgProc - advanced options dialog procedure static int sttRosterEditorResizer(HWND /*hwndDlg*/, LPARAM, UTILRESIZECONTROL *urc) { switch (urc->wId) { case IDC_HEADERBAR: return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORX_WIDTH; case IDC_ROSTER: return RD_ANCHORX_LEFT | RD_ANCHORY_TOP | RD_ANCHORY_HEIGHT | RD_ANCHORX_WIDTH; case IDC_DOWNLOAD: case IDC_UPLOAD: return RD_ANCHORX_LEFT | RD_ANCHORY_BOTTOM; case IDC_EXPORT: case IDC_IMPORT: return RD_ANCHORX_RIGHT | RD_ANCHORY_BOTTOM; } return RD_ANCHORX_LEFT | RD_ANCHORY_TOP; } static INT_PTR CALLBACK JabberRosterOptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { CJabberProto *ppro = (CJabberProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); switch (msg) { case WM_INITDIALOG: ppro = (CJabberProto*)lParam; SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); TranslateDialogDefault(hwndDlg); Window_SetIcon_IcoLib(hwndDlg, g_GetIconHandle(IDI_AGENTS)); Utils_RestoreWindowPosition(hwndDlg, 0, ppro->m_szModuleName, "rosterCtrlWnd_"); ListView_SetExtendedListViewStyle(GetDlgItem(hwndDlg, IDC_ROSTER), LVS_EX_CHECKBOXES | LVS_EX_BORDERSELECT /*| LVS_EX_FULLROWSELECT*/ | LVS_EX_GRIDLINES /*| LVS_EX_HEADERDRAGDROP*/); mir_subclassWindow(GetDlgItem(hwndDlg, IDC_ROSTER), _RosterNewListProc); _RosterListClear(hwndDlg); ppro->rrud.hwndDlg = hwndDlg; ppro->rrud.bReadyToDownload = TRUE; ppro->rrud.bReadyToUpload = FALSE; SendMessage(hwndDlg, JM_STATUSCHANGED, 0, 0); return TRUE; case JM_STATUSCHANGED: { int count = ListView_GetItemCount(GetDlgItem(hwndDlg, IDC_ROSTER)); EnableWindow(GetDlgItem(hwndDlg, IDC_DOWNLOAD), ppro->m_bJabberOnline); EnableWindow(GetDlgItem(hwndDlg, IDC_UPLOAD), count && ppro->m_bJabberOnline); EnableWindow(GetDlgItem(hwndDlg, IDC_EXPORT), count > 0); } break; case WM_CLOSE: DestroyWindow(hwndDlg); break; case WM_DESTROY: Utils_SaveWindowPosition(hwndDlg, 0, ppro->m_szModuleName, "rosterCtrlWnd_"); ppro->rrud.hwndDlg = nullptr; Window_FreeIcon_IcoLib(hwndDlg); break; case WM_GETMINMAXINFO: { LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam; lpmmi->ptMinTrackSize.x = 550; lpmmi->ptMinTrackSize.y = 390; return 0; } case WM_SIZE: Utils_ResizeDialog(hwndDlg, g_plugin.getInst(), MAKEINTRESOURCEA(IDD_OPT_JABBER3), sttRosterEditorResizer); break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_DOWNLOAD: ppro->rrud.bReadyToUpload = FALSE; ppro->rrud.bReadyToDownload = FALSE; SendMessage(ppro->rrud.hwndDlg, JM_STATUSCHANGED, 0, 0); SetDlgItemText(ppro->rrud.hwndDlg, IDC_DOWNLOAD, TranslateT("Downloading...")); ppro->_RosterSendRequest(hwndDlg, RRA_FILLLIST); break; case IDC_UPLOAD: ppro->rrud.bReadyToUpload = FALSE; SendMessage(ppro->rrud.hwndDlg, JM_STATUSCHANGED, 0, 0); SetDlgItemText(ppro->rrud.hwndDlg, IDC_UPLOAD, TranslateT("Connecting...")); ppro->_RosterSendRequest(hwndDlg, RRA_SYNCROSTER); break; case IDC_EXPORT: ppro->_RosterExportToFile(hwndDlg); break; case IDC_IMPORT: ppro->_RosterImportFromFile(hwndDlg); break; } break; } return FALSE; } INT_PTR __cdecl CJabberProto::OnMenuHandleRosterControl(WPARAM, LPARAM) { if (rrud.hwndDlg && IsWindow(rrud.hwndDlg)) SetForegroundWindow(rrud.hwndDlg); else CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_OPT_JABBER3), nullptr, JabberRosterOptDlgProc, (LPARAM)this); return 0; } ///////////////////////////////////////////////////////////////////////////////////////// // JabberOptInit - initializes all options dialogs int CJabberProto::OnOptionsInit(WPARAM wParam, LPARAM) { OPTIONSDIALOGPAGE odp = {}; odp.szGroup.w = LPGENW("Network"); odp.szTitle.w = m_tszUserName; odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE | ODPF_DONTTRANSLATE; odp.szTab.w = LPGENW("Account"); odp.pDialog = new CDlgOptAccount(this); g_plugin.addOptions(wParam, &odp); odp.szTab.w = LPGENW("Conferences"); odp.pDialog = new CDlgOptGc(this); g_plugin.addOptions(wParam, &odp); odp.szTab.w = LPGENW("Advanced"); odp.pDialog = new CDlgOptAdvanced(this); g_plugin.addOptions(wParam, &odp); //TODO: add omemo options return 0; } /////////////////////////////////////////////////////////////////////////////// // Account manager UI class CJabberDlgAccMgrUI : public CJabberDlgBase { typedef CJabberDlgBase CSuper; CCtrlCombo m_cbType; CCtrlEditJid m_txtUsername; CCtrlCombo m_cbServer; CCtrlEdit m_txtPassword; CCtrlCheck m_chkSavePassword; CCtrlCheck m_chkUseDomainLogin; CCtrlCombo m_cbResource; CCtrlCheck m_chkManualHost; CCtrlEdit m_txtManualHost; CCtrlEdit m_txtPort; CCtrlButton m_btnRegister; public: CJabberDlgAccMgrUI(CJabberProto *proto, HWND hwndParent) : CJabberDlgBase(proto, IDD_ACCMGRUI), m_cbType(this, IDC_CB_TYPE), m_txtUsername(this, IDC_EDIT_USERNAME), m_txtPassword(this, IDC_EDIT_PASSWORD), m_chkUseDomainLogin(this, IDC_USEDOMAINLOGIN), m_chkSavePassword(this, IDC_SAVEPASSWORD), m_cbResource(this, IDC_COMBO_RESOURCE), m_cbServer(this, IDC_EDIT_LOGIN_SERVER), m_txtPort(this, IDC_PORT), m_chkManualHost(this, IDC_MANUAL), m_txtManualHost(this, IDC_HOST), m_btnRegister(this, IDC_BUTTON_REGISTER) { SetParent(hwndParent); CreateLink(m_txtUsername, "LoginName", L""); CreateLink(m_chkSavePassword, proto->m_bSavePassword); CreateLink(m_cbResource, "Resource", L"Miranda"); CreateLink(m_cbServer, "LoginServer", L"jabber.org"); CreateLink(m_txtPort, "Port", DBVT_WORD, 5222); CreateLink(m_chkUseDomainLogin, proto->m_bUseDomainLogin); // Bind events m_cbType.OnChange = Callback(this, &CJabberDlgAccMgrUI::cbType_OnChange); m_cbServer.OnDropdown = Callback(this, &CJabberDlgAccMgrUI::cbServer_OnDropdown); m_chkManualHost.OnChange = Callback(this, &CJabberDlgAccMgrUI::chkManualHost_OnChange); m_chkUseDomainLogin.OnChange = Callback(this, &CJabberDlgAccMgrUI::chkUseDomainLogin_OnChange); m_btnRegister.OnClick = Callback(this, &CJabberDlgAccMgrUI::btnRegister_OnClick); } protected: enum { ACC_PUBLIC, ACC_TLS, ACC_SSL, ACC_GTALK, ACC_HIPCHAT, ACC_LJTALK, ACC_LOL_EN, ACC_LOL_EW, ACC_LOL_OC, ACC_LOL_US, ACC_OK, ACC_SMS }; bool OnInitDialog() override { CSuper::OnInitDialog(); m_gotservers = false; wchar_t *passw = m_proto->getWStringA(0, "Password"); if (passw) { m_txtPassword.SetText(passw); mir_free(passw); } m_cbServer.AddString(TranslateT("Loading...")); // fill predefined resources wchar_t *szResources[] = { L"Home", L"Work", L"Office", L"Miranda" }; for (auto &it : szResources) m_cbResource.AddString(it); // append computer name to the resource list wchar_t szCompName[MAX_COMPUTERNAME_LENGTH + 1]; DWORD dwCompNameLength = MAX_COMPUTERNAME_LENGTH; if (GetComputerName(szCompName, &dwCompNameLength)) m_cbResource.AddString(szCompName); ptrW tszResource(m_proto->getWStringA("Resource")); if (tszResource != nullptr) { if (CB_ERR == m_cbResource.FindString(tszResource, -1, true)) m_cbResource.AddString(tszResource); m_cbResource.SetText(tszResource); } else m_cbResource.SetText(L"Miranda"); m_cbType.AddString(TranslateT("Public XMPP Network"), ACC_PUBLIC); m_cbType.AddString(TranslateT("Secure XMPP Network"), ACC_TLS); m_cbType.AddString(TranslateT("Secure XMPP Network (old style)"), ACC_SSL); m_cbType.AddString(TranslateT("Google Talk!"), ACC_GTALK); m_cbType.AddString(TranslateT("Hipchat"), ACC_HIPCHAT); m_cbType.AddString(TranslateT("LiveJournal Talk"), ACC_LJTALK); m_cbType.AddString(TranslateT("League Of Legends (EU Nordic)"), ACC_LOL_EN); m_cbType.AddString(TranslateT("League Of Legends (EU West)"), ACC_LOL_EW); m_cbType.AddString(TranslateT("League Of Legends (Oceania)"), ACC_LOL_OC); m_cbType.AddString(TranslateT("League Of Legends (US)"), ACC_LOL_US); m_cbType.AddString(TranslateT("Odnoklassniki"), ACC_OK); m_cbType.AddString(TranslateT("S.ms"), ACC_SMS); char server[256], manualServer[256] = { 0 }; m_cbServer.GetTextA(server, _countof(server)); ptrA dbManualServer(db_get_sa(0, m_proto->m_szModuleName, "ManualHost")); if (dbManualServer != nullptr) mir_strncpy(manualServer, dbManualServer, _countof(manualServer)); m_canregister = true; if (!mir_strcmp(manualServer, "talk.google.com")) { m_cbType.SetCurSel(ACC_GTALK); m_canregister = false; } else if (!mir_strcmp(server, "chat.hipchat.com")) { m_cbType.SetCurSel(ACC_HIPCHAT); m_canregister = false; } else if (!mir_strcmp(server, "livejournal.com")) { m_cbType.SetCurSel(ACC_LJTALK); m_canregister = false; } else if (!mir_strcmp(server, "chat.eun1.lol.riotgames.com")) { m_cbType.SetCurSel(ACC_LOL_EN); m_canregister = false; } else if (!mir_strcmp(server, "chat.euw1.lol.riotgames.com")) { m_cbType.SetCurSel(ACC_LOL_EW); m_canregister = false; } else if (!mir_strcmp(server, "chat.oc1.lol.riotgames.com")) { m_cbType.SetCurSel(ACC_LOL_OC); m_canregister = false; } else if (!mir_strcmp(server, "chat.na2.lol.riotgames.com")) { m_cbType.SetCurSel(ACC_LOL_US); m_canregister = false; } else if (!mir_strcmp(server, "xmpp.odnoklassniki.ru")) { m_cbType.SetCurSel(ACC_OK); m_canregister = false; } else if (!mir_strcmp(server, "S.ms")) { m_cbType.SetCurSel(ACC_SMS); m_canregister = false; } else if (m_proto->m_bUseSSL) m_cbType.SetCurSel(ACC_SSL); else if (m_proto->m_bUseTLS) { m_cbType.SetCurSel(ACC_TLS); m_txtPort.SetInt(5222); } else m_cbType.SetCurSel(ACC_PUBLIC); if (m_chkManualHost.Enabled()) { if (m_proto->m_bManualConnect) { m_chkManualHost.SetState(BST_CHECKED); m_txtManualHost.Enable(); m_txtPort.Enable(); ptrW dbManualHost(m_proto->getWStringA("ManualHost")); if (dbManualHost != nullptr) m_txtManualHost.SetText(dbManualHost); m_txtPort.SetInt(m_proto->getWord("ManualPort", m_txtPort.GetInt())); } else { int defPort = m_txtPort.GetInt(); int port = m_proto->getWord("Port", defPort); if (port != defPort) { m_chkManualHost.SetState(BST_CHECKED); m_txtManualHost.Enable(); m_txtPort.Enable(); m_txtManualHost.SetTextA(server); m_txtPort.SetInt(port); } else { m_chkManualHost.SetState(BST_UNCHECKED); m_txtManualHost.Disable(); m_txtPort.Disable(); } } } if (m_proto->m_bUseDomainLogin) chkUseDomainLogin_OnChange(&m_chkUseDomainLogin); CheckRegistration(); return true; } bool OnApply() override { // clear saved password m_proto->m_savedPassword = nullptr; BOOL bUseHostnameAsResource = FALSE; wchar_t szCompName[MAX_COMPUTERNAME_LENGTH + 1], szResource[MAX_COMPUTERNAME_LENGTH + 1]; DWORD dwCompNameLength = MAX_COMPUTERNAME_LENGTH; if (GetComputerName(szCompName, &dwCompNameLength)) { m_cbResource.GetText(szResource, _countof(szResource)); if (!mir_wstrcmp(szCompName, szResource)) bUseHostnameAsResource = TRUE; } m_proto->m_bHostNameAsResource = bUseHostnameAsResource; if (m_chkSavePassword.GetState() == BST_CHECKED) { wchar_t *text = m_txtPassword.GetText(); m_proto->setWString("Password", text); mir_free(text); } else m_proto->delSetting("Password"); switch (m_cbType.GetItemData(m_cbType.GetCurSel())) { case ACC_PUBLIC: m_proto->m_bUseSSL = m_proto->m_bUseTLS = FALSE; break; case ACC_GTALK: m_proto->setDword("Priority", 24); { int port = m_txtPort.GetInt(); if (port == 443 || port == 5223) { m_proto->m_bUseSSL = TRUE; m_proto->m_bUseTLS = FALSE; } else if (port == 5222) { m_proto->m_bUseSSL = FALSE; m_proto->m_bUseTLS = TRUE; } } break; case ACC_OK: m_proto->m_bIgnoreRosterGroups = TRUE; m_proto->m_bUseSSL = FALSE; m_proto->m_bUseTLS = TRUE; case ACC_TLS: case ACC_HIPCHAT: case ACC_LJTALK: case ACC_SMS: m_proto->m_bUseSSL = FALSE; m_proto->m_bUseTLS = TRUE; break; case ACC_LOL_EN: case ACC_LOL_EW: case ACC_LOL_OC: case ACC_LOL_US: m_proto->setDword("Priority", -2); m_proto->m_bUseSSL = TRUE; m_proto->m_bUseTLS = FALSE; break; case ACC_SSL: m_proto->m_bUseSSL = TRUE; m_proto->m_bUseTLS = FALSE; break; } char server[256]; char manualServer[256]; m_cbServer.GetTextA(server, _countof(server)); m_txtManualHost.GetTextA(manualServer, _countof(manualServer)); if ((m_chkManualHost.GetState() == BST_CHECKED) && mir_strcmp(server, manualServer)) { m_proto->m_bManualConnect = TRUE; m_proto->setString("ManualHost", manualServer); m_proto->setWord("ManualPort", m_txtPort.GetInt()); m_proto->setWord("Port", m_txtPort.GetInt()); } else { m_proto->m_bManualConnect = FALSE; m_proto->delSetting("ManualHost"); m_proto->delSetting("ManualPort"); m_proto->setWord("Port", m_txtPort.GetInt()); } sttStoreJidFromUI(m_proto, m_txtUsername, m_cbServer); if (m_proto->m_bJabberOnline) { if (m_cbType.IsChanged() || m_txtPassword.IsChanged() || m_cbResource.IsChanged() || m_cbServer.IsChanged() || m_txtPort.IsChanged() || m_txtManualHost.IsChanged()) { MessageBox(m_hwnd, TranslateT("Some changes will take effect the next time you connect to the Jabber network."), TranslateT("Jabber Protocol Option"), MB_OK | MB_SETFOREGROUND); } m_proto->SendPresence(m_proto->m_iStatus, true); } return true; } void OnChange(CCtrlBase*) { if (m_initialized) CheckRegistration(); } INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override { switch (msg) { case WM_JABBER_REFRESH: RefreshServers((HXML)lParam); break; } return CSuper::DlgProc(msg, wParam, lParam); } private: bool m_gotservers; bool m_canregister; void btnRegister_OnClick(CCtrlButton *) { PSHNOTIFY pshn = {}; pshn.hdr.code = PSN_APPLY; pshn.hdr.hwndFrom = m_hwnd; SendMessage(m_hwnd, WM_NOTIFY, 0, (LPARAM)&pshn); JABBER_CONN_DATA regInfo; m_txtUsername.GetText(regInfo.username, _countof(regInfo.username)); m_txtPassword.GetText(regInfo.password, _countof(regInfo.password)); m_cbServer.GetTextA(regInfo.server, _countof(regInfo.server)); regInfo.port = (WORD)m_txtPort.GetInt(); if (m_chkManualHost.GetState() == BST_CHECKED) m_txtManualHost.GetTextA(regInfo.manualHost, _countof(regInfo.manualHost)); else regInfo.manualHost[0] = '\0'; if (regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port > 0 && ((m_chkManualHost.GetState() != BST_CHECKED) || regInfo.manualHost[0])) CJabberDlgRegister(m_proto, m_hwnd, ®Info).DoModal(); } void cbServer_OnDropdown(CCtrlCombo*) { if (!m_gotservers) mir_forkThread(QueryServerListThread, this); } void cbType_OnChange(CCtrlData *sender) { CCtrlCombo *chk = (CCtrlCombo *)sender; setupConnection(chk->GetItemData(chk->GetCurSel())); CheckRegistration(); } void chkUseDomainLogin_OnChange(CCtrlData *sender) { CCtrlCheck *chk = (CCtrlCheck *)sender; BOOL checked = chk->GetState() == BST_CHECKED; m_txtPassword.Enable(!checked); m_txtUsername.Enable(!checked); m_chkSavePassword.Enable(!checked); if (checked) { m_txtPassword.SetText(L""); m_txtUsername.SetText(L""); m_chkSavePassword.SetState(BST_CHECKED); } } void chkManualHost_OnChange(CCtrlData *sender) { CCtrlCheck *chk = (CCtrlCheck *)sender; if (chk->GetState() == BST_CHECKED) { char buf[256]; m_cbServer.GetTextA(buf, _countof(buf)); m_txtManualHost.SetTextA(buf); m_txtPort.SetInt(5222); m_txtManualHost.Enable(); m_txtPort.Enable(); } else { m_txtManualHost.Disable(); m_txtPort.Disable(); } } void CheckRegistration() { if (!m_canregister) { m_btnRegister.Disable(); return; } JABBER_CONN_DATA regInfo; m_txtUsername.GetText(regInfo.username, _countof(regInfo.username)); m_txtPassword.GetText(regInfo.password, _countof(regInfo.password)); m_cbServer.GetTextA(regInfo.server, _countof(regInfo.server)); regInfo.port = m_txtPort.GetInt(); if (m_chkManualHost.GetState() == BST_CHECKED) m_txtManualHost.GetTextA(regInfo.manualHost, _countof(regInfo.manualHost)); else regInfo.manualHost[0] = '\0'; if (regInfo.username[0] && regInfo.password[0] && regInfo.server[0] && regInfo.port > 0 && ((m_chkManualHost.GetState() != BST_CHECKED) || regInfo.manualHost[0])) m_btnRegister.Enable(); else m_btnRegister.Disable(); } void setupConnection(int type) { switch (type) { case ACC_PUBLIC: setupPublic(); break; case ACC_TLS: setupSecure(); break; case ACC_SSL: setupSecureSSL(); break; case ACC_GTALK: setupGoogle(); break; case ACC_HIPCHAT: setupHipchat(); break; case ACC_LJTALK: setupLJ(); break; case ACC_LOL_EN: setupLOLEN(); break; case ACC_LOL_EW: setupLOLEW(); break; case ACC_LOL_OC: setupLOLOC(); break; case ACC_LOL_US: setupLOLUS(); break; case ACC_OK: setupOK(); break; case ACC_SMS: setupSMS(); break; } } void setupPublic() { m_canregister = true; m_gotservers = false; m_chkManualHost.SetState(BST_UNCHECKED); m_txtManualHost.SetTextA(""); m_txtPort.SetInt(5222); m_cbServer.Enable(); m_chkManualHost.Enable(); m_txtManualHost.Disable(); m_txtPort.Disable(); m_btnRegister.Enable(); } void setupSecure() { m_canregister = true; m_gotservers = false; m_chkManualHost.SetState(BST_UNCHECKED); m_txtManualHost.SetTextA(""); m_txtPort.SetInt(5222); m_cbServer.Enable(); m_chkManualHost.Enable(); m_txtManualHost.Disable(); m_txtPort.Disable(); m_btnRegister.Enable(); } void setupSecureSSL() { m_canregister = true; m_gotservers = false; m_chkManualHost.SetState(BST_UNCHECKED); m_txtManualHost.SetTextA(""); m_txtPort.SetInt(5223); m_cbServer.Enable(); m_chkManualHost.Enable(); m_txtManualHost.Disable(); m_txtPort.Disable(); m_btnRegister.Enable(); } void setupGoogle() { m_canregister = false; m_gotservers = true; m_cbServer.ResetContent(); m_cbServer.AddStringA("gmail.com"); m_cbServer.AddStringA("googlemail.com"); m_cbServer.SetTextA("gmail.com"); m_chkManualHost.SetState(BST_CHECKED); m_txtManualHost.SetTextA("talk.google.com"); m_txtPort.SetInt(443); m_cbServer.Enable(); m_chkManualHost.Disable(); m_txtManualHost.Disable(); m_btnRegister.Disable(); } void setupHipchat() { m_canregister = false; m_gotservers = true; m_cbServer.ResetContent(); m_cbServer.SetTextA("chat.hipchat.com"); m_cbServer.AddStringA("chat.hipchat.com"); m_chkManualHost.SetState(BST_UNCHECKED); m_txtManualHost.SetTextA(""); m_txtPort.SetInt(5222); m_cbServer.Disable(); m_chkManualHost.Disable(); m_txtManualHost.Disable(); m_txtPort.Disable(); m_btnRegister.Disable(); } void setupLJ() { m_canregister = false; m_gotservers = true; m_cbServer.ResetContent(); m_cbServer.SetTextA("livejournal.com"); m_cbServer.AddStringA("livejournal.com"); m_chkManualHost.SetState(BST_UNCHECKED); m_txtManualHost.SetTextA(""); m_txtPort.SetInt(5222); m_cbServer.Disable(); m_chkManualHost.Disable(); m_txtManualHost.Disable(); m_txtPort.Disable(); m_btnRegister.Disable(); } void setupLOLEN() { m_canregister = false; m_gotservers = true; m_cbServer.ResetContent(); m_cbServer.SetTextA("pvp.net"); m_cbServer.AddStringA("pvp.net"); m_chkManualHost.SetState(BST_UNCHECKED); m_txtManualHost.SetTextA("chat.eun1.lol.riotgames.com"); m_txtPort.SetInt(5223); m_cbServer.Disable(); m_chkManualHost.Disable(); m_txtManualHost.Disable(); m_txtPort.Disable(); m_btnRegister.Disable(); } void setupLOLEW() { m_canregister = false; m_gotservers = true; m_cbServer.ResetContent(); m_cbServer.SetTextA("pvp.net"); m_cbServer.AddStringA("pvp.net"); m_chkManualHost.SetState(BST_UNCHECKED); m_txtManualHost.SetTextA("chat.euw1.lol.riotgames.com"); m_txtPort.SetInt(5223); m_cbServer.Disable(); m_chkManualHost.Disable(); m_txtManualHost.Disable(); m_txtPort.Disable(); m_btnRegister.Disable(); } void setupLOLOC() { m_canregister = false; m_gotservers = true; m_cbServer.ResetContent(); m_cbServer.SetTextA("pvp.net"); m_cbServer.AddStringA("pvp.net"); m_chkManualHost.SetState(BST_UNCHECKED); m_txtManualHost.SetTextA("chat.oc1.lol.riotgames.com"); m_txtPort.SetInt(5223); m_cbServer.Disable(); m_chkManualHost.Disable(); m_txtManualHost.Disable(); m_txtPort.Disable(); m_btnRegister.Disable(); } void setupLOLUS() { m_canregister = false; m_gotservers = true; m_cbServer.ResetContent(); m_cbServer.SetTextA("pvp.net"); m_cbServer.AddStringA("pvp.net"); m_chkManualHost.SetState(BST_UNCHECKED); m_txtManualHost.SetTextA("chat.na2.lol.riotgames.com"); m_txtPort.SetInt(5223); m_cbServer.Disable(); m_chkManualHost.Disable(); m_txtManualHost.Disable(); m_txtPort.Disable(); m_btnRegister.Disable(); } void setupOK() { m_canregister = false; m_gotservers = true; m_cbServer.ResetContent(); m_cbServer.SetTextA("xmpp.odnoklassniki.ru"); m_cbServer.AddStringA("xmpp.odnoklassniki.ru"); m_chkManualHost.SetState(BST_UNCHECKED); m_txtManualHost.SetTextA(""); m_txtPort.SetInt(5222); m_cbServer.Disable(); m_chkManualHost.Disable(); m_txtManualHost.Disable(); m_txtPort.Disable(); m_btnRegister.Disable(); } void setupSMS() { m_canregister = false; m_gotservers = true; m_cbServer.ResetContent(); m_cbServer.SetTextA("S.ms"); m_cbServer.AddStringA("S.ms"); m_chkManualHost.SetState(BST_UNCHECKED); m_txtManualHost.SetTextA(""); m_txtPort.SetInt(5222); m_cbServer.Disable(); m_chkManualHost.Disable(); m_txtManualHost.Disable(); m_txtPort.Disable(); m_btnRegister.Disable(); } void RefreshServers(HXML node) { m_gotservers = node != nullptr; wchar_t *server = m_cbServer.GetText(); bool bDropdown = m_cbServer.GetDroppedState(); if (bDropdown) m_cbServer.ShowDropdown(false); m_cbServer.ResetContent(); if (node) { for (int i = 0;; i++) { HXML n = XmlGetChild(node, i); if (!n) break; if (!mir_wstrcmp(XmlGetName(n), L"item")) if (const wchar_t *jid = XmlGetAttrValue(n, L"jid")) if (m_cbServer.FindString(jid, -1, true) == CB_ERR) m_cbServer.AddString(jid); } } m_cbServer.SetText(server); if (bDropdown) m_cbServer.ShowDropdown(); mir_free(server); } static void __cdecl QueryServerListThread(CJabberDlgAccMgrUI *wnd) { HWND hwnd = wnd->GetHwnd(); bool bIsError = true; NETLIBHTTPREQUEST request = { 0 }; request.cbSize = sizeof(request); request.requestType = REQUEST_GET; request.flags = NLHRF_HTTP11; request.szUrl = JABBER_SERVER_URL; NETLIBHTTPREQUEST *result = Netlib_HttpTransaction(wnd->GetProto()->m_hNetlibUser, &request); if (result && IsWindow(hwnd)) { if ((result->resultCode == 200) && result->dataLength && result->pData) { wchar_t *ptszText = mir_a2u(result->pData); XmlNode node(ptszText, nullptr, nullptr); if (node) { HXML queryNode = XmlGetChild(node, L"query"); if (queryNode && IsWindow(hwnd)) { SendMessage(hwnd, WM_JABBER_REFRESH, 0, (LPARAM)queryNode); bIsError = false; } } mir_free(ptszText); } } if (result) Netlib_FreeHttpRequest(result); if (bIsError) SendMessage(hwnd, WM_JABBER_REFRESH, 0, 0); } }; INT_PTR CJabberProto::SvcCreateAccMgrUI(WPARAM, LPARAM lParam) { CJabberDlgAccMgrUI *dlg = new CJabberDlgAccMgrUI(this, (HWND)lParam); dlg->Show(); return (INT_PTR)dlg->GetHwnd(); } void CJabberProto::JabberUpdateDialogs(BOOL) { if (rrud.hwndDlg) SendMessage(rrud.hwndDlg, JM_STATUSCHANGED, 0, 0); } INT_PTR __cdecl CJabberProto::OnMenuOptions(WPARAM, LPARAM) { g_plugin.openOptions(L"Network", m_tszUserName, L"Account"); return 0; }