/* Jabber Protocol Plugin for Miranda IM Copyright (C) 2002-04 Santithorn Bunchua Copyright (C) 2005-12 George Hazan Copyright (C) 2007 Artem Shpynov Copyright (C) 2012-13 Miranda NG Project 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. */ #include "jabber.h" #include "jabber_iq.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(JABBER_FEAT_DISCO_ITEMS) << XATTR(_T("node"), 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"), 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, JABBER_FEAT_DISCO_ITEMS) && !_tcscmp(node, JABBER_FEAT_COMMANDS)) validResponse = TRUE; } if (queryNode && xmlGetChild(queryNode ,0) && validResponse) { dat->CommandsNode = xi.copyNode(queryNode); int ypos = 20; for (nodeIdx = 1; ; nodeIdx++) { HXML itemNode = xmlGetNthChild(queryNode, _T("item"), nodeIdx); if (!itemNode) break; 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; } } 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 = node from responder as a result of command execution HXML commandNode, xNode; 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 (LPCTSTR ptszInstr = xmlGetText( xmlGetChild(xNode , "instructions"))) JabberFormSetInstruction(hwndDlg, ptszInstr); else if (LPCTSTR ptszTitle = xmlGetText( xmlGetChild(xNode , "title"))) JabberFormSetInstruction(hwndDlg, ptszTitle); 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); LPCTSTR noteText = xmlGetText( xmlGetChild(commandNode, "note")); 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"), 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_calloc(sizeof(JabberAdHocData)); 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"), 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 = (HANDLE)wParam; int res = -1; if ((hContact != NULL || lParam != 0) && m_bJabberOnline) { DBVARIANT dbv; if (wParam && !getTString(hContact, "jid", &dbv)) { JABBER_LIST_ITEM *item = NULL; int selected = 0; TCHAR jid[JABBER_MAX_JID_LEN]; _tcsncpy(jid, dbv.ptszVal, SIZEOF(jid)); { mir_cslock lck(m_csLists); 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->pResources[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->pResources) { _tcsncat(jid,_T("/"),SIZEOF(jid)); _tcsncat(jid,item->pResources[selected].resourceName,SIZEOF(jid)); } selected = 1; } } } if ( !item || selected) { CJabberAdhocStartupParams* pStartupParams = new CJabberAdhocStartupParams(this, jid, NULL); CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_FORM), NULL, JabberAdHoc_CommandDlgProc, (LPARAM)(pStartupParams)); } db_free(&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); }