/* Jabber Protocol Plugin for Miranda IM Copyright ( C ) 2002-04 Santithorn Bunchua Copyright ( C ) 2005-12 George Hazan 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" ); }