/* Jabber Protocol Plugin for Miranda IM Copyright (C) 2002-04 Santithorn Bunchua Copyright (C) 2005-12 George Hazan Copyright (C) 2012-13 Miranda NG Project 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 "jabber.h" #include "jabber_list.h" #include "jabber_iq.h" #include "jabber_caps.h" void CJabberProto::SetMucConfig(HXML node, void *from) { if (m_ThreadInfo && from) { XmlNodeIq iq(_T("set"), SerialNext(), (TCHAR*)from); HXML query = iq << XQUERY(xmlnsOwner); xmlAddChild(query, node); m_ThreadInfo->send(iq); } } void LaunchForm(HXML node); void CJabberProto::OnIqResultGetMuc(HXML iqNode) { HXML queryNode, xNode; const TCHAR *type, *from, *str; // RECVED: room config form // ACTION: show the form Log(" iqIdGetMuc"); if ((type = xmlGetAttrValue(iqNode, _T("type"))) == NULL) return; if ((from = xmlGetAttrValue(iqNode, _T("from"))) == NULL) return; if ( !_tcscmp(type, _T("result"))) { if ((queryNode = xmlGetChild(iqNode , "query")) != NULL) { str = xmlGetAttrValue(queryNode, _T("xmlns")); if ( !lstrcmp(str, _T("http://jabber.org/protocol/muc#owner"))) { if ((xNode = xmlGetChild(queryNode , "x")) != NULL) { str = xmlGetAttrValue(xNode, _T("xmlns")); if ( !lstrcmp(str, _T(JABBER_FEAT_DATA_FORMS))) //LaunchForm(xNode); FormCreateDialog(xNode, _T("Jabber Conference Room Configuration"), &CJabberProto::SetMucConfig, mir_tstrdup(from)); } } } } } static void sttFillJidList(HWND hwndDlg) { JABBER_MUC_JIDLIST_INFO *jidListInfo; HXML iqNode, queryNode; const TCHAR *from, *jid, *reason, *nick; LVITEM lvi; HWND hwndList; int count, i; TCHAR *filter = NULL; if (GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_USERDATA)) { int filterLength = GetWindowTextLength(GetDlgItem(hwndDlg, IDC_FILTER)) + 1; filter = (TCHAR *)_alloca(filterLength * sizeof(TCHAR)); GetDlgItemText(hwndDlg, IDC_FILTER, filter, filterLength); } jidListInfo = (JABBER_MUC_JIDLIST_INFO *) GetWindowLongPtr(hwndDlg, GWLP_USERDATA); if ( !jidListInfo) return; hwndList = GetDlgItem(hwndDlg, IDC_LIST); SendMessage(hwndList, WM_SETREDRAW, FALSE, 0); count = ListView_GetItemCount(hwndList); lvi.mask = LVIF_PARAM; lvi.iSubItem = 0; for (i=0; iiqNode) != NULL) { if ((from = xmlGetAttrValue(iqNode, _T("from"))) != NULL) { if ((queryNode = xmlGetChild(iqNode , "query")) != NULL) { lvi.mask = LVIF_TEXT | LVIF_PARAM; lvi.iSubItem = 0; lvi.iItem = 0; for (i=0; ; i++) { HXML itemNode = xmlGetChild(queryNode ,i); if ( !itemNode) break; if ((jid = xmlGetAttrValue(itemNode, _T("jid"))) != NULL) { lvi.pszText = (TCHAR*)jid; if (jidListInfo->type == MUC_BANLIST) { if ((reason = xmlGetText(xmlGetChild(itemNode , "reason"))) != NULL) { TCHAR jidreason[ JABBER_MAX_JID_LEN + 256 ]; mir_sntprintf(jidreason, SIZEOF(jidreason), _T("%s (%s)") , jid, reason); lvi.pszText = jidreason; } } if (jidListInfo->type == MUC_VOICELIST || jidListInfo->type == MUC_MODERATORLIST) { if ((nick = xmlGetAttrValue(itemNode, _T("nick"))) != NULL) { TCHAR nickjid[ JABBER_MAX_JID_LEN + 256 ]; mir_sntprintf(nickjid, SIZEOF(nickjid), _T("%s (%s)") , nick, jid); lvi.pszText = nickjid; } } if (filter && *filter && !JabberStrIStr(lvi.pszText, filter)) continue; lvi.lParam = (LPARAM)mir_tstrdup(jid); ListView_InsertItem(hwndList, &lvi); lvi.iItem++; } } } } } lvi.mask = LVIF_PARAM; lvi.lParam = (LPARAM)(-1); ListView_InsertItem(hwndList, &lvi); SendMessage(hwndList, WM_SETREDRAW, TRUE, 0); RedrawWindow(hwndList, NULL, NULL, RDW_INVALIDATE); } static int sttJidListResizer(HWND, LPARAM, UTILRESIZECONTROL *urc) { switch (urc->wId) { case IDC_LIST: return RD_ANCHORX_LEFT|RD_ANCHORY_TOP|RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; case IDC_FILTER: return RD_ANCHORX_LEFT|RD_ANCHORY_BOTTOM|RD_ANCHORX_WIDTH; case IDC_BTN_FILTERRESET: case IDC_BTN_FILTERAPPLY: return RD_ANCHORX_RIGHT|RD_ANCHORY_BOTTOM; } return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; } static INT_PTR CALLBACK JabberMucJidListDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { JABBER_MUC_JIDLIST_INFO* dat = (JABBER_MUC_JIDLIST_INFO*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); switch(msg) { case WM_INITDIALOG: { LVCOLUMN lvc; RECT rc; HWND hwndList; TranslateDialogDefault(hwndDlg); hwndList = GetDlgItem(hwndDlg, IDC_LIST); ListView_SetExtendedListViewStyle(hwndList, LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES); GetClientRect(hwndList, &rc); //rc.right -= GetSystemMetrics(SM_CXVSCROLL); lvc.mask = LVCF_WIDTH; lvc.cx = rc.right - 20; ListView_InsertColumn(hwndList, 0, &lvc); lvc.cx = 20; ListView_InsertColumn(hwndList, 1, &lvc); SendMessage(hwndDlg, WM_JABBER_REFRESH, 0, lParam); dat = (JABBER_MUC_JIDLIST_INFO*)lParam; static struct { int idc; char *title; char *icon; bool push; } buttons[] = { {IDC_BTN_FILTERAPPLY, "Apply filter", "sd_filter_apply", false}, {IDC_BTN_FILTERRESET, "Reset filter", "sd_filter_reset", false}, }; for (int i = 0; i < SIZEOF(buttons); i++) { SendDlgItemMessage(hwndDlg, buttons[i].idc, BM_SETIMAGE, IMAGE_ICON, (LPARAM)dat->ppro->LoadIconEx(buttons[i].icon)); SendDlgItemMessage(hwndDlg, buttons[i].idc, BUTTONSETASFLATBTN, TRUE, 0); SendDlgItemMessage(hwndDlg, buttons[i].idc, BUTTONADDTOOLTIP, (WPARAM)buttons[i].title, 0); if (buttons[i].push) SendDlgItemMessage(hwndDlg, buttons[i].idc, BUTTONSETASPUSHBTN, TRUE, 0); } Utils_RestoreWindowPosition(hwndDlg, NULL, dat->ppro->m_szModuleName, "jidListWnd_"); } return TRUE; case WM_SIZE: { UTILRESIZEDIALOG urd = {0}; urd.cbSize = sizeof(urd); urd.hInstance = hInst; urd.hwndDlg = hwndDlg; urd.lpTemplate = MAKEINTRESOURCEA(IDD_JIDLIST); urd.pfnResizer = sttJidListResizer; CallService(MS_UTILS_RESIZEDIALOG, 0, (LPARAM)&urd); RECT listrc; LVCOLUMN lvc; HWND hwndList = GetDlgItem(hwndDlg, IDC_LIST); GetClientRect(hwndList, &listrc); lvc.mask = LVCF_WIDTH; //listrc.right -= GetSystemMetrics(SM_CXVSCROLL); lvc.cx = listrc.right - 20; SendMessage(hwndList, LVM_SETCOLUMN, 0, (LPARAM)&lvc); break; } break; case WM_JABBER_REFRESH: { // lParam is (JABBER_MUC_JIDLIST_INFO *) HXML iqNode, queryNode; const TCHAR *from; TCHAR title[256]; // Clear current GWL_USERDATA, if any if (dat != NULL) delete dat; // Set new GWL_USERDATA dat = (JABBER_MUC_JIDLIST_INFO *) lParam; SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR) dat); // Populate displayed list from iqNode lstrcpyn(title, TranslateT("JID List"), SIZEOF(title)); if ((dat=(JABBER_MUC_JIDLIST_INFO *) lParam) != NULL) { if ((iqNode = dat->iqNode) != NULL) { if ((from = xmlGetAttrValue(iqNode, _T("from"))) != NULL) { dat->roomJid = mir_tstrdup(from); if ((queryNode = xmlGetChild(iqNode , "query")) != NULL) { TCHAR* localFrom = mir_tstrdup(from); mir_sntprintf(title, SIZEOF(title), TranslateT("%s, %d items (%s)"), (dat->type == MUC_VOICELIST) ? TranslateT("Voice List") : (dat->type == MUC_MEMBERLIST) ? TranslateT("Member List") : (dat->type == MUC_MODERATORLIST) ? TranslateT("Moderator List") : (dat->type == MUC_BANLIST) ? TranslateT("Ban List") : (dat->type == MUC_ADMINLIST) ? TranslateT("Admin List") : (dat->type == MUC_OWNERLIST) ? TranslateT("Owner List") : TranslateT("JID List"), xmlGetChildCount(queryNode), localFrom); mir_free(localFrom); } } } } SetWindowText(hwndDlg, title); SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_USERDATA, 0); sttFillJidList(hwndDlg); } break; case WM_NOTIFY: if (((LPNMHDR)lParam)->idFrom == IDC_LIST) { switch (((LPNMHDR)lParam)->code) { case NM_CUSTOMDRAW: { NMLVCUSTOMDRAW *nm = (NMLVCUSTOMDRAW *) lParam; switch (nm->nmcd.dwDrawStage) { case CDDS_PREPAINT: case CDDS_ITEMPREPAINT: SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, CDRF_NOTIFYSUBITEMDRAW); return TRUE; case CDDS_SUBITEM|CDDS_ITEMPREPAINT: { RECT rc; HICON hIcon; ListView_GetSubItemRect(nm->nmcd.hdr.hwndFrom, nm->nmcd.dwItemSpec, nm->iSubItem, LVIR_LABEL, &rc); if (nm->iSubItem == 1) { if (nm->nmcd.lItemlParam == (LPARAM)(-1)) hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_ADDCONTACT), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); else hIcon = (HICON)LoadImage(hInst, MAKEINTRESOURCE(IDI_DELETE), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0); DrawIconEx(nm->nmcd.hdc, (rc.left+rc.right-GetSystemMetrics(SM_CXSMICON))/2, (rc.top+rc.bottom-GetSystemMetrics(SM_CYSMICON))/2,hIcon, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0, GetSysColorBrush(COLOR_WINDOW), DI_NORMAL); DestroyIcon(hIcon); SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, CDRF_SKIPDEFAULT); return TRUE; } } } } break; case NM_CLICK: { NMLISTVIEW *nm = (NMLISTVIEW *) lParam; LVITEM lvi; LVHITTESTINFO hti; TCHAR text[128]; if (nm->iSubItem < 1) break; hti.pt.x = (short) LOWORD(GetMessagePos()); hti.pt.y = (short) HIWORD(GetMessagePos()); ScreenToClient(nm->hdr.hwndFrom, &hti.pt); if (ListView_SubItemHitTest(nm->hdr.hwndFrom, &hti) == -1) break; if (hti.iSubItem != 1) break; lvi.mask = LVIF_PARAM | LVIF_TEXT; lvi.iItem = hti.iItem; lvi.iSubItem = 0; lvi.pszText = text; lvi.cchTextMax = sizeof(text); ListView_GetItem(nm->hdr.hwndFrom, &lvi); if (lvi.lParam == (LPARAM)(-1)) { TCHAR szBuffer[ 1024 ]; _tcscpy(szBuffer, dat->type2str()); if ( !dat->ppro->EnterString(szBuffer, SIZEOF(szBuffer), NULL, JES_COMBO, "gcAddNick_")) break; // Trim leading and trailing whitespaces TCHAR *p = szBuffer, *q; for (p = szBuffer; *p!='\0' && isspace(BYTE(*p)); p++); for (q = p; *q!='\0' && !isspace(BYTE(*q)); q++); if (*q != '\0') *q = '\0'; if (*p == '\0') break; TCHAR rsn[ 1024 ]; _tcscpy(rsn, dat->type2str()); if (dat->type == MUC_BANLIST) { dat->ppro->EnterString(rsn, SIZEOF(rsn), TranslateT("Reason to ban") , JES_COMBO, "gcAddReason_"); if (szBuffer) dat->ppro->AddMucListItem(dat, p , rsn); else dat->ppro->AddMucListItem(dat, p); } else dat->ppro->AddMucListItem(dat, p); } else { //delete TCHAR msgText[128]; mir_sntprintf(msgText, SIZEOF(msgText), _T("%s %s?"), TranslateT("Removing"), text); if (MessageBox(hwndDlg, msgText, dat->type2str(), MB_YESNO|MB_SETFOREGROUND) == IDYES) { dat->ppro->DeleteMucListItem(dat, (TCHAR*)lvi.lParam); mir_free((void *)lvi.lParam); ListView_DeleteItem(nm->hdr.hwndFrom, hti.iItem); } } } break; } break; } break; case WM_COMMAND: if ((LOWORD(wParam) == IDC_BTN_FILTERAPPLY) || ((LOWORD(wParam) == IDOK) && (GetFocus() == GetDlgItem(hwndDlg, IDC_FILTER)))) { SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_USERDATA, 1); sttFillJidList(hwndDlg); } else if ((LOWORD(wParam) == IDC_BTN_FILTERRESET) || ((LOWORD(wParam) == IDCANCEL) && (GetFocus() == GetDlgItem(hwndDlg, IDC_FILTER)))) { SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_FILTER), GWLP_USERDATA, 0); sttFillJidList(hwndDlg); } break; /* case WM_SETCURSOR: if (LOWORD(LPARAM)!= HTCLIENT) break; if (GetForegroundWindow() == GetParent(hwndDlg)) { POINT pt; GetCursorPos(&pt); ScreenToClient(hwndDlg,&pt); SetFocus(ChildWindowFromPoint(hwndDlg,pt)); //ugly hack because listviews ignore their first click } break; */ case WM_CLOSE: { HWND hwndList; int count, i; LVITEM lvi; // Free lParam of the displayed list items hwndList = GetDlgItem(hwndDlg, IDC_LIST); count = ListView_GetItemCount(hwndList); lvi.mask = LVIF_PARAM; lvi.iSubItem = 0; for (i=0; ippro; switch (dat->type) { case MUC_VOICELIST: ppro->m_hwndMucVoiceList = NULL; break; case MUC_MEMBERLIST: ppro->m_hwndMucMemberList = NULL; break; case MUC_MODERATORLIST: ppro->m_hwndMucModeratorList = NULL; break; case MUC_BANLIST: ppro->m_hwndMucBanList = NULL; break; case MUC_ADMINLIST: ppro->m_hwndMucAdminList = NULL; break; case MUC_OWNERLIST: ppro->m_hwndMucOwnerList = NULL; break; } DestroyWindow(hwndDlg); } break; case WM_DESTROY: // Clear GWL_USERDATA if (dat != NULL) { Utils_SaveWindowPosition(hwndDlg, NULL, dat->ppro->m_szModuleName, "jidListWnd_"); delete dat; } break; } return FALSE; } static void CALLBACK JabberMucJidListCreateDialogApcProc(void* param) { HXML iqNode, queryNode; const TCHAR *from; HWND *pHwndJidList; JABBER_MUC_JIDLIST_INFO *jidListInfo = (JABBER_MUC_JIDLIST_INFO *)param; if (jidListInfo == NULL) return; if ((iqNode = jidListInfo->iqNode) == NULL) return; if ((from = xmlGetAttrValue(iqNode, _T("from"))) == NULL) return; if ((queryNode = xmlGetChild(iqNode , "query")) == NULL) return; CJabberProto* ppro = jidListInfo->ppro; switch (jidListInfo->type) { case MUC_VOICELIST: pHwndJidList = &ppro->m_hwndMucVoiceList; break; case MUC_MEMBERLIST: pHwndJidList = &ppro->m_hwndMucMemberList; break; case MUC_MODERATORLIST: pHwndJidList = &ppro->m_hwndMucModeratorList; break; case MUC_BANLIST: pHwndJidList = &ppro->m_hwndMucBanList; break; case MUC_ADMINLIST: pHwndJidList = &ppro->m_hwndMucAdminList; break; case MUC_OWNERLIST: pHwndJidList = &ppro->m_hwndMucOwnerList; break; default: mir_free(jidListInfo); return; } if (*pHwndJidList!=NULL && IsWindow(*pHwndJidList)) { SetForegroundWindow(*pHwndJidList); SendMessage(*pHwndJidList, WM_JABBER_REFRESH, 0, (LPARAM)jidListInfo); } else *pHwndJidList = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_JIDLIST), GetForegroundWindow(), JabberMucJidListDlgProc, (LPARAM)jidListInfo); } void CJabberProto::OnIqResultMucGetJidList(HXML iqNode, JABBER_MUC_JIDLIST_TYPE listType) { const TCHAR *type; JABBER_MUC_JIDLIST_INFO *jidListInfo; if ((type = xmlGetAttrValue(iqNode, _T("type"))) == NULL) return; if ( !lstrcmp(type, _T("result"))) { if ((jidListInfo = new JABBER_MUC_JIDLIST_INFO) != NULL) { jidListInfo->type = listType; jidListInfo->ppro = this; jidListInfo->roomJid = NULL; // Set in the dialog procedure if ((jidListInfo->iqNode = xi.copyNode(iqNode)) != NULL) CallFunctionAsync(JabberMucJidListCreateDialogApcProc, jidListInfo); else mir_free(jidListInfo); } } } void CJabberProto::OnIqResultMucGetVoiceList(HXML iqNode) { Log(" iqResultMucGetVoiceList"); OnIqResultMucGetJidList(iqNode, MUC_VOICELIST); } void CJabberProto::OnIqResultMucGetMemberList(HXML iqNode) { Log(" iqResultMucGetMemberList"); OnIqResultMucGetJidList(iqNode, MUC_MEMBERLIST); } void CJabberProto::OnIqResultMucGetModeratorList(HXML iqNode) { Log(" iqResultMucGetModeratorList"); OnIqResultMucGetJidList(iqNode, MUC_MODERATORLIST); } void CJabberProto::OnIqResultMucGetBanList(HXML iqNode) { Log(" iqResultMucGetBanList"); OnIqResultMucGetJidList(iqNode, MUC_BANLIST); } void CJabberProto::OnIqResultMucGetAdminList(HXML iqNode) { Log(" iqResultMucGetAdminList"); OnIqResultMucGetJidList(iqNode, MUC_ADMINLIST); } void CJabberProto::OnIqResultMucGetOwnerList(HXML iqNode) { Log(" iqResultMucGetOwnerList"); OnIqResultMucGetJidList(iqNode, MUC_OWNERLIST); } ///////////////////////////////////////////////////////////////////////////////////////// JABBER_MUC_JIDLIST_INFO::~JABBER_MUC_JIDLIST_INFO() { xi.destroyNode(iqNode); mir_free(roomJid); } TCHAR* JABBER_MUC_JIDLIST_INFO::type2str() const { switch(type) { case MUC_VOICELIST: return TranslateT("Voice List"); case MUC_MEMBERLIST: return TranslateT("Member List"); case MUC_MODERATORLIST: return TranslateT("Moderator List"); case MUC_BANLIST: return TranslateT("Ban List"); case MUC_ADMINLIST: return TranslateT("Admin List"); case MUC_OWNERLIST: return TranslateT("Owner List"); } return TranslateT("JID List"); }