/*

Jabber Protocol Plugin for Miranda IM
Copyright ( C ) 2002-04  Santithorn Bunchua
Copyright ( C ) 2005-11  George Hazan
Copyright ( C ) 2007     Artem Shpynov

Module implements an XMPP protocol extension for reporting and executing ad-hoc, 
human-oriented commands according to XEP-0050: Ad-Hoc Commands
http://www.xmpp.org/extensions/xep-0050.html

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.

Revision       : $Revision: 13898 $
Last change on : $Date: 2011-11-02 05:38:43 +0200 (Ср, 02 ноя 2011) $
Last change by : $Author: borkra $

*/

#include "jabber.h"
#include <CommCtrl.h>
#include "jabber_iq.h"
#include "m_clui.h"
#include "jabber_caps.h"


#define ShowDlgItem( a, b, c )	 ShowWindow( GetDlgItem( a, b ), c )
#define EnableDlgItem( a, b, c ) EnableWindow( GetDlgItem( a, b ), c )

enum 
{
	JAHM_COMMANDLISTRESULT = WM_USER+1,
	JAHM_PROCESSRESULT
};

//Declarations
static INT_PTR CALLBACK JabberAdHoc_CommandDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam );

//implementations

// convert iqID to dialog hwnd
HWND CJabberProto::GetWindowFromIq( HXML iqNode )
{
	const TCHAR* id = xmlGetAttrValue( iqNode, _T( "id" ));
	if (_tcslen(id)>4)
		return (HWND)_tcstol(id+4,NULL,10);
	return m_hwndCommandWindow;

}
// Callback to clear form content
static BOOL CALLBACK sttDeleteChildWindowsProc( HWND hwnd, LPARAM )
{
	DestroyWindow( hwnd );
	return TRUE;
}

static void sttEnableControls( HWND hwndDlg, BOOL bEnable, const int * controlsID )
{
	int i=0;
	while ( controlsID[i]!=0 ) 
		EnableDlgItem( hwndDlg, controlsID[i++], bEnable );
}

static void sttShowControls( HWND hwndDlg, BOOL bShow, int * controlsID )
{
	int i=0;
	while ( controlsID[i]!=0 )
		ShowDlgItem( hwndDlg, controlsID[i++], (bShow) ? SW_SHOW : SW_HIDE );
}

static void JabberAdHoc_RefreshFrameScroll(HWND hwndDlg, JabberAdHocData * dat)
{
	HWND hFrame = GetDlgItem( hwndDlg, IDC_FRAME );
	HWND hwndScroll = GetDlgItem( hwndDlg, IDC_VSCROLL );
	RECT rc;
	RECT rcScrollRc;
	GetClientRect( hFrame, &rc );
	GetClientRect( hFrame, &dat->frameRect );
	GetWindowRect( hwndScroll, &rcScrollRc );
	dat->frameRect.right-=(rcScrollRc.right-rcScrollRc.left);
	dat->frameHeight = rc.bottom-rc.top;
	if ( dat->frameHeight < dat->CurrentHeight) {
		ShowWindow( hwndScroll, SW_SHOW );
		EnableWindow( hwndScroll, TRUE );
	}
	else ShowWindow( hwndScroll, SW_HIDE );

	SetScrollRange( hwndScroll, SB_CTL, 0, dat->CurrentHeight-dat->frameHeight, FALSE );

}

//////////////////////////////////////////////////////////////////////////
// Iq handlers
// Forwards to dialog window procedure

void CJabberProto::OnIqResult_ListOfCommands( HXML iqNode )
{
	SendMessage( GetWindowFromIq( iqNode ), JAHM_COMMANDLISTRESULT, 0, (LPARAM)xi.copyNode( iqNode ));
}

void CJabberProto::OnIqResult_CommandExecution( HXML iqNode )
{
	SendMessage( GetWindowFromIq( iqNode ), JAHM_PROCESSRESULT, (WPARAM)xi.copyNode( iqNode ), 0 );
}

int CJabberProto::AdHoc_RequestListOfCommands( TCHAR * szResponder, HWND hwndDlg )
{
	int iqId = (int)hwndDlg;
	IqAdd( iqId, IQ_PROC_DISCOCOMMANDS, &CJabberProto::OnIqResult_ListOfCommands );
	m_ThreadInfo->send( XmlNodeIq( _T("get"), iqId, szResponder ) << XQUERY( _T(JABBER_FEAT_DISCO_ITEMS)) 
		<< XATTR( _T("node"), _T(JABBER_FEAT_COMMANDS)));
	return iqId;
}

int CJabberProto::AdHoc_ExecuteCommand( HWND hwndDlg, TCHAR*, JabberAdHocData* dat )
{
	for ( int i = 1; ; i++ ) {
		HXML itemNode = xmlGetNthChild( dat->CommandsNode, _T("item"), i );
		if ( !itemNode)
			break;
		if ( !IsDlgButtonChecked( GetDlgItem( hwndDlg, IDC_FRAME ), i ))
			continue;
		const TCHAR* node = xmlGetAttrValue( itemNode, _T("node"));
		if ( node ) {
			const TCHAR *jid2 = xmlGetAttrValue( itemNode, _T("jid"));

			int iqId = (int)hwndDlg;
			IqAdd( iqId, IQ_PROC_EXECCOMMANDS, &CJabberProto::OnIqResult_CommandExecution );
			m_ThreadInfo->send(
				XmlNodeIq( _T("set"), iqId, jid2 )
					<< XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) << XATTR( _T("node"), node ) << XATTR( _T("action"), _T("execute")));

			EnableDlgItem( hwndDlg, IDC_SUBMIT, FALSE );
			SetDlgItemText( hwndDlg, IDC_SUBMIT, TranslateT( "OK" ) );
	}	}

	xi.destroyNode( dat->CommandsNode ); dat->CommandsNode = NULL;
	return TRUE;
}

//Messages handlers
int CJabberProto::AdHoc_OnJAHMCommandListResult( HWND hwndDlg, HXML iqNode, JabberAdHocData* dat )
{
	int nodeIdx = 0;
	const TCHAR * type = xmlGetAttrValue( iqNode, _T("type"));
	if ( !type || !_tcscmp( type, _T( "error" ) ) ) {
		// error occurred here
		TCHAR buff[255];
		const TCHAR* code		= NULL;
		const TCHAR* description = NULL;
		
		HXML errorNode = xmlGetChild( iqNode, "error" );
		if ( errorNode ) {
			code = xmlGetAttrValue( errorNode, _T("code"));
			description = xmlGetText( errorNode );
		}
		_sntprintf( buff, SIZEOF(buff), TranslateT( "Error %s %s" ), (code) ? code : _T(""), (description) ? description : _T("") );	
		JabberFormSetInstruction( hwndDlg, buff );
	} 
	else if ( !_tcscmp( type, _T("result") ) ) {	
		BOOL validResponse = FALSE;
		EnumChildWindows( GetDlgItem( hwndDlg, IDC_FRAME ), sttDeleteChildWindowsProc, 0 );
		dat->CurrentHeight = 0;
		dat->curPos = 0;
		SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, 0, FALSE );
		HXML queryNode = xmlGetChild( iqNode , "query" );
		if ( queryNode ) {
			const TCHAR* xmlns = xmlGetAttrValue( queryNode, _T( "xmlns" ));
			const TCHAR* node  = xmlGetAttrValue( queryNode, _T( "node" ));
			if ( xmlns && node
					&& !_tcscmp( xmlns, _T( JABBER_FEAT_DISCO_ITEMS ) )
					&& !_tcscmp( node,  _T( JABBER_FEAT_COMMANDS ) ) )
				validResponse = TRUE;
		}
		if ( queryNode && xmlGetChild( queryNode ,0) && validResponse ) {
			dat->CommandsNode = xi.copyNode( queryNode );

			nodeIdx = 1;
			int ypos = 20;
			for (nodeIdx = 1; ; nodeIdx++ ) {
				HXML itemNode = xmlGetNthChild( queryNode, _T("item"), nodeIdx );
				if ( itemNode ) {
					const TCHAR *name = xmlGetAttrValue( itemNode, _T("name"));
					if (!name) name = xmlGetAttrValue( itemNode, _T("node"));
					ypos = AdHoc_AddCommandRadio( GetDlgItem( hwndDlg,IDC_FRAME ), TranslateTS(name), nodeIdx, ypos, (nodeIdx==1) ? 1 : 0);
					dat->CurrentHeight = ypos;
				}
				else break;
		}	}

		if (nodeIdx>1) {
			JabberFormSetInstruction( hwndDlg, TranslateT("Select Command") );				
			ShowDlgItem( hwndDlg, IDC_FRAME, SW_SHOW);
			ShowDlgItem( hwndDlg, IDC_VSCROLL, SW_SHOW);
			EnableDlgItem( hwndDlg, IDC_SUBMIT, TRUE);
		} else {
			JabberFormSetInstruction(hwndDlg, TranslateT("Not supported") );
	}	}

	JabberAdHoc_RefreshFrameScroll( hwndDlg, dat );
	return (TRUE);
}

int CJabberProto::AdHoc_OnJAHMProcessResult(HWND hwndDlg, HXML workNode, JabberAdHocData* dat)
{
	EnumChildWindows( GetDlgItem( hwndDlg, IDC_FRAME ), sttDeleteChildWindowsProc, 0 );
	dat->CurrentHeight = 0;
	dat->curPos = 0;
	SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, 0, FALSE );

	if ( workNode == NULL )
		return TRUE;

	dat->AdHocNode = xi.copyNode( workNode );

	const TCHAR *type;
	if (( type = xmlGetAttrValue( workNode, _T("type"))) == NULL ) return TRUE;
	if ( !lstrcmp( type, _T("result") ) ) { 
		// wParam = <iq/> node from responder as a result of command execution
		HXML commandNode, xNode, n;
		if (( commandNode = xmlGetChild( dat->AdHocNode, _T("command"))) == NULL )
			return TRUE;

		const TCHAR * status = xmlGetAttrValue( commandNode, _T("status"));
		if (!status) status = _T("completed");

		if (( xNode = xmlGetChild( commandNode , "x" ))) {
			// use jabber:x:data form
			HWND hFrame = GetDlgItem( hwndDlg, IDC_FRAME );
			ShowWindow( GetDlgItem( hwndDlg, IDC_FRAME_TEXT ), SW_HIDE );
			if (( n = xmlGetChild( xNode , "instructions" )) != NULL && xmlGetText( n )!=NULL )
				JabberFormSetInstruction( hwndDlg, xmlGetText( n ) );
			else if (( n = xmlGetChild( xNode , "title" )) != NULL && xmlGetText( n )!=NULL )
				JabberFormSetInstruction( hwndDlg, xmlGetText( n ) );
			else
				JabberFormSetInstruction(hwndDlg, TranslateTS(status) );
			JabberFormCreateUI( hFrame, xNode, &dat->CurrentHeight );
			ShowDlgItem(  hwndDlg, IDC_FRAME , SW_SHOW);
		} 
		else {
			//NO X FORM
			int toHide[]={ IDC_FRAME_TEXT, IDC_FRAME, IDC_VSCROLL,   0}; 
			sttShowControls(hwndDlg, FALSE, toHide );

			const TCHAR * noteText=NULL;
			HXML noteNode = xmlGetChild( commandNode , "note");
			if (noteNode)
				noteText = xmlGetText( noteNode );

			JabberFormSetInstruction(hwndDlg, noteText ? noteText : TranslateTS(status) );
		}

		//check actions
		HXML actionsNode = xmlGetChild( commandNode , "actions");
		if ( actionsNode != NULL ) {
			ShowDlgItem( hwndDlg, IDC_PREV, ( xmlGetChild( actionsNode , "prev")!=NULL) ? SW_SHOW : SW_HIDE);
			ShowDlgItem( hwndDlg, IDC_NEXT, ( xmlGetChild( actionsNode , "next")!=NULL) ? SW_SHOW : SW_HIDE);
			ShowDlgItem( hwndDlg, IDC_COMPLETE, ( xmlGetChild( actionsNode , "complete")!=NULL) ? SW_SHOW : SW_HIDE);
			ShowDlgItem( hwndDlg, IDC_SUBMIT, SW_HIDE);
			
			int toEnable[]={ IDC_PREV, IDC_NEXT, IDC_COMPLETE,   0}; 
			sttEnableControls( hwndDlg, TRUE, toEnable );
		} else 	{
			int toHide[]={ IDC_PREV, IDC_NEXT, IDC_COMPLETE,   0}; 
 			sttShowControls(hwndDlg, FALSE, toHide );

			ShowDlgItem(hwndDlg,IDC_SUBMIT,	SW_SHOW);
			EnableDlgItem(hwndDlg,IDC_SUBMIT, TRUE);
		}

		if (!status || _tcscmp(status,_T("executing"))) {
			ShowDlgItem( hwndDlg, IDC_SUBMIT, SW_HIDE);
			SetWindowText(GetDlgItem(hwndDlg,IDCANCEL), TranslateT("Done"));
	} 	} 
	else if ( !lstrcmp( type, _T("error"))) {	
		// error occurred here
		int toHide[]={ IDC_FRAME, IDC_FRAME_TEXT, IDC_VSCROLL,
						IDC_PREV, IDC_NEXT, IDC_COMPLETE, IDC_SUBMIT,  0}; 
		
		sttShowControls(hwndDlg, FALSE, toHide );
		
		const TCHAR* code=NULL;
		const TCHAR* description=NULL;
		TCHAR buff[255];
		HXML errorNode = xmlGetChild( workNode , "error");
		if ( errorNode ) {
			code = xmlGetAttrValue( errorNode, _T("code"));
			description = xmlGetText( errorNode );
		}
		_sntprintf(buff,SIZEOF(buff),TranslateT("Error %s %s"),code ? code : _T(""),description?description:_T(""));	
		JabberFormSetInstruction(hwndDlg,buff);
	}
	JabberAdHoc_RefreshFrameScroll( hwndDlg, dat );
	return TRUE;
}

int CJabberProto::AdHoc_SubmitCommandForm(HWND hwndDlg, JabberAdHocData* dat, TCHAR* action)
{
	HXML commandNode = xmlGetChild( dat->AdHocNode, "command" );
	HXML xNode		  = xmlGetChild( commandNode , "x" );
	HXML dataNode    = JabberFormGetData( GetDlgItem( hwndDlg, IDC_FRAME ), xNode);

	int iqId = (int)hwndDlg;
	XmlNodeIq iq( _T("set"), iqId, xmlGetAttrValue( dat->AdHocNode, _T("from")));
	HXML command = iq << XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS));
	
	const TCHAR* sessionId = xmlGetAttrValue( commandNode, _T("sessionid"));
	if ( sessionId ) 
		command << XATTR( _T("sessionid"), sessionId );
	
	const TCHAR* node = xmlGetAttrValue( commandNode, _T("node"));
	if ( node ) 
		command << XATTR( _T("node"), node );
	
	if ( action ) 
		command << XATTR( _T("action"), action );
	
	xmlAddChild( command, dataNode );
	IqAdd( iqId, IQ_PROC_EXECCOMMANDS, &CJabberProto::OnIqResult_CommandExecution );
	m_ThreadInfo->send( iq );
	
	xi.destroyNode( dataNode );

	JabberFormSetInstruction(hwndDlg,TranslateT("In progress. Please Wait..."));
	
	static const int toDisable[]={IDC_SUBMIT, IDC_PREV, IDC_NEXT, IDC_COMPLETE, 0};
	sttEnableControls( hwndDlg, FALSE, toDisable);
	
	return TRUE;
}


int CJabberProto::AdHoc_AddCommandRadio(HWND hFrame, TCHAR * labelStr, int id, int ypos, int value)
{
	int labelHeight;
	RECT strRect={0};

	int verticalStep=4;
	int ctrlMinHeight=18;
	HWND hCtrl=NULL;

	RECT rcFrame;
	GetClientRect(hFrame,&rcFrame);

	int ctrlOffset=20;
	int ctrlWidth=rcFrame.right-ctrlOffset;

	HDC hdc = GetDC( hFrame );
	labelHeight = max(ctrlMinHeight, DrawText( hdc , labelStr, -1, &strRect, DT_CALCRECT ));
	ctrlWidth=min( ctrlWidth, strRect.right-strRect.left+20 );
	ReleaseDC( hFrame, hdc );

	hCtrl = CreateWindowEx( 0, _T("button"), labelStr, WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_AUTORADIOBUTTON, ctrlOffset, ypos, ctrlWidth, labelHeight, hFrame, ( HMENU ) id, hInst, NULL );
	SendMessage( hCtrl, WM_SETFONT, ( WPARAM ) SendMessage( GetParent(hFrame), WM_GETFONT, 0, 0 ), 0 );
	SendMessage( hCtrl, BM_SETCHECK, value, 0 );
	return (ypos + labelHeight + verticalStep);

}

static INT_PTR CALLBACK JabberAdHoc_CommandDlgProc( HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam )
{
	JabberAdHocData* dat = ( JabberAdHocData* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA );
	switch (msg)
	{
	case WM_INITDIALOG:
		{
			CJabberAdhocStartupParams* pStartupParams = (CJabberAdhocStartupParams *)lParam;
			dat=(JabberAdHocData *)mir_alloc(sizeof(JabberAdHocData));
			memset(dat,0,sizeof(JabberAdHocData));
			
			//hmmm, useless code? if (dat->ResponderJID) mir_free(dat->ResponderJID);
			dat->ResponderJID = mir_tstrdup(pStartupParams->m_szJid);
			dat->proto = pStartupParams->m_pProto;

			SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)dat);
			WindowSetIcon( hwndDlg, dat->proto, "adhoc" );
			dat->proto->m_hwndCommandWindow = hwndDlg;
			TranslateDialogDefault( hwndDlg );

			//Firstly hide frame
			LONG frameExStyle = GetWindowLongPtr( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE );
			frameExStyle |= WS_EX_CONTROLPARENT;

			SetWindowLongPtr( GetDlgItem( hwndDlg, IDC_FRAME ), GWL_EXSTYLE, frameExStyle );
	
			int toHide[]={ IDC_FRAME, IDC_VSCROLL, IDC_PREV, IDC_NEXT, IDC_COMPLETE, IDC_FRAME_TEXT, 0}; 
			sttShowControls(hwndDlg, FALSE, toHide );
		
			int toShow[]={ IDC_INSTRUCTION, IDC_SUBMIT, IDCANCEL, 0}; 
			sttShowControls(hwndDlg, TRUE, toShow );

			EnableDlgItem(hwndDlg,IDC_VSCROLL,TRUE);
	
			SetWindowPos(GetDlgItem(hwndDlg,IDC_VSCROLL),HWND_BOTTOM,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);

			SetDlgItemText(hwndDlg,IDC_SUBMIT, TranslateT("Execute"));
			JabberFormSetInstruction(hwndDlg,TranslateT("Requesting command list. Please wait..."));

			if ( !pStartupParams->m_szNode ) {
				dat->proto->AdHoc_RequestListOfCommands(pStartupParams->m_szJid, hwndDlg);

				TCHAR Caption[ 512 ];
				_sntprintf(Caption, SIZEOF(Caption), _T("%s %s"), TranslateT("Jabber Ad-Hoc commands at"), dat->ResponderJID );
				SetWindowText(hwndDlg, Caption);
			}
			else
			{
				int iqId = (int)hwndDlg;
				dat->proto->IqAdd( iqId, IQ_PROC_EXECCOMMANDS, &CJabberProto::OnIqResult_CommandExecution );
				dat->proto->m_ThreadInfo->send(
					XmlNodeIq( _T("set"), iqId, pStartupParams->m_szJid )
						<< XCHILDNS( _T("command"), _T(JABBER_FEAT_COMMANDS)) 
							<< XATTR( _T("node"), pStartupParams->m_szNode ) << XATTR( _T("action"), _T("execute")));

				EnableDlgItem( hwndDlg, IDC_SUBMIT, FALSE );
				SetDlgItemText( hwndDlg, IDC_SUBMIT, TranslateT( "OK" ) );

				TCHAR Caption[ 512 ];
				_sntprintf(Caption, SIZEOF(Caption), _T("%s %s"), TranslateT("Sending Ad-Hoc command to"), dat->ResponderJID );
				SetWindowText(hwndDlg, Caption);
			}

			delete pStartupParams;

			return TRUE;
		}
	case WM_CTLCOLORSTATIC:
		if ((GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_WHITERECT) ||
			(GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_INSTRUCTION) ||
			(GetWindowLongPtr((HWND)lParam, GWL_ID) == IDC_TITLE))
		{
			return (INT_PTR)GetStockObject(WHITE_BRUSH);
		} else
		{
			return NULL;
		}
	case WM_COMMAND:
		{	
			switch ( LOWORD( wParam )) 
			{

			case IDC_PREV:
				return dat->proto->AdHoc_SubmitCommandForm(hwndDlg,dat,_T("prev"));
			case IDC_NEXT:
				return dat->proto->AdHoc_SubmitCommandForm(hwndDlg,dat,_T("next"));
			case IDC_COMPLETE:
				return dat->proto->AdHoc_SubmitCommandForm(hwndDlg,dat,_T("complete"));
			case IDC_SUBMIT:
				if (!dat->AdHocNode && dat->CommandsNode && LOWORD( wParam )==IDC_SUBMIT) 
					return dat->proto->AdHoc_ExecuteCommand(hwndDlg,dat->ResponderJID, dat);
				else
					return dat->proto->AdHoc_SubmitCommandForm(hwndDlg,dat, NULL);
			case IDCLOSE:
			case IDCANCEL:
				xi.destroyNode( dat->AdHocNode ); dat->AdHocNode = NULL;
				DestroyWindow( hwndDlg );
				return TRUE;
			}
			break;
		}
	case JAHM_COMMANDLISTRESULT:
		return dat->proto->AdHoc_OnJAHMCommandListResult(hwndDlg,(HXML)lParam,dat);
	case JAHM_PROCESSRESULT:
		return dat->proto->AdHoc_OnJAHMProcessResult(hwndDlg, (HXML)wParam,dat);

	case WM_MOUSEWHEEL:
		{
			int zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
			if ( zDelta ) {
				int nScrollLines=0;
				SystemParametersInfo(SPI_GETWHEELSCROLLLINES,0,(void*)&nScrollLines,0);
				for (int i=0; i<(nScrollLines+1)/2; i++)
					SendMessage(hwndDlg,WM_VSCROLL, (zDelta<0)?SB_LINEDOWN:SB_LINEUP,0);
			}	}
		return TRUE;

	case WM_VSCROLL:
		{
			int pos;
			if ( dat != NULL ) {
				pos = dat->curPos;
				switch ( LOWORD( wParam ))
				{
				case SB_LINEDOWN:
					pos += 10;
					break;
				case SB_LINEUP:
					pos -= 10;
					break;
				case SB_PAGEDOWN:
					pos += ( dat->CurrentHeight - 10 );
					break;
				case SB_PAGEUP:
					pos -= ( dat->CurrentHeight - 10 );
					break;
				case SB_THUMBTRACK:
					pos = HIWORD( wParam );
					break;
				}
				if ( pos > ( dat->CurrentHeight - dat->frameHeight ))
					pos = dat->CurrentHeight - dat->frameHeight;
				if ( pos < 0 )
					pos = 0;
				if ( dat->curPos != pos ) {
					ScrollWindow( GetDlgItem( hwndDlg, IDC_FRAME ), 0, dat->curPos - pos, NULL ,  &( dat->frameRect ));
					SetScrollPos( GetDlgItem( hwndDlg, IDC_VSCROLL ), SB_CTL, pos, TRUE );
					RECT Invalid=dat->frameRect;
					if (dat->curPos - pos >0)
						Invalid.bottom=Invalid.top+(dat->curPos - pos);
					else
						Invalid.top=Invalid.bottom+(dat->curPos - pos);

					RedrawWindow(GetDlgItem( hwndDlg, IDC_FRAME ), NULL, NULL, RDW_UPDATENOW |RDW_ALLCHILDREN);
					dat->curPos = pos;
			}	}
			break;
		}
	case WM_DESTROY:
		{
			JabberFormDestroyUI(GetDlgItem(hwndDlg, IDC_FRAME));
			WindowFreeIcon(hwndDlg);

			dat->proto->m_hwndCommandWindow = NULL;
			mir_free( dat->ResponderJID );
			xi.destroyNode( dat->CommandsNode );
			xi.destroyNode( dat->AdHocNode );
			mir_free(dat);
			dat=NULL;
			SetWindowLongPtr(hwndDlg, GWLP_USERDATA, 0);
			break;
		}
	}
	return FALSE;
}

int __cdecl CJabberProto::ContactMenuRunCommands(WPARAM wParam, LPARAM lParam )
{
	HANDLE hContact;
	DBVARIANT dbv;
	int res = -1;
	JABBER_LIST_ITEM * item=NULL;
	
	if ((( hContact=( HANDLE ) wParam )!=NULL || (lParam!=0)) && m_bJabberOnline ) {
		if ( wParam && !JGetStringT( hContact, "jid", &dbv )) {
			TCHAR jid[ JABBER_MAX_JID_LEN ];
			int selected = 0;
			_tcsncpy(jid, dbv.ptszVal, SIZEOF(jid));

			ListLock();
			{
				item = ListGetItemPtr( LIST_ROSTER, jid);
				if (item)
				{
					if (item->resourceCount>1)
					{
						HMENU hMenu=CreatePopupMenu();
						for (int i=0; i<item->resourceCount; i++)
							AppendMenu(hMenu,MF_STRING,i+1, item->resource[i].resourceName);
						HWND hwndTemp=CreateWindowEx(WS_EX_TOOLWINDOW,_T("button"),_T("PopupMenuHost"),0,0,0,10,10,NULL,NULL,hInst,NULL);
						SetForegroundWindow(hwndTemp);
						POINT pt;
						GetCursorPos(&pt);
						RECT rc;
						selected=TrackPopupMenu(hMenu,TPM_RETURNCMD,pt.x,pt.y,0,hwndTemp,&rc);
						DestroyMenu(hMenu);
						DestroyWindow(hwndTemp);
					}
					else selected=1;

					if (selected>0) 
					{
						selected--;
						if (item->resource)
						{
							_tcsncat(jid,_T("/"),SIZEOF(jid));
							_tcsncat(jid,item->resource[selected].resourceName,SIZEOF(jid));
						}
						selected=1;
					}
				}
			}
			ListUnlock();

			if (!item || selected) {
				CJabberAdhocStartupParams* pStartupParams = new CJabberAdhocStartupParams( this, jid, NULL );
				CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), NULL, JabberAdHoc_CommandDlgProc, ( LPARAM )(pStartupParams) );
			}
			JFreeVariant( &dbv );
			
		}
		else if (lParam!=0)
			CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), NULL, JabberAdHoc_CommandDlgProc, lParam );
	}
	return res;
}

void CJabberProto::ContactMenuAdhocCommands( CJabberAdhocStartupParams* param )
{
	if ( param )
		CreateDialogParam( hInst, MAKEINTRESOURCE( IDD_FORM ), NULL, JabberAdHoc_CommandDlgProc, (LPARAM)param );
}