845 lines
24 KiB
C++
845 lines
24 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1997.
|
|
//
|
|
// File: U P D I A G . C P P
|
|
//
|
|
// Contents: UPnP Diagnostic App and CD and UCP emulator
|
|
//
|
|
// Notes:
|
|
//
|
|
// Author: danielwe 28 Oct 1999
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
|
|
#include "ncbase.h"
|
|
#include "updiagp.h"
|
|
#include "ncinet.h"
|
|
|
|
UPDIAG_PARAMS g_params = {0};
|
|
UPDIAG_CONTEXT g_ctx;
|
|
SHARED_DATA * g_pdata = NULL;
|
|
HANDLE g_hMapFile = NULL;
|
|
HANDLE g_hEvent = NULL;
|
|
HANDLE g_hEventRet = NULL;
|
|
HANDLE g_hEventCleanup = NULL;
|
|
HANDLE g_hMutex = NULL;
|
|
HANDLE g_hThreadTime = NULL;
|
|
FILE * g_pInputFile = NULL;
|
|
|
|
static const COMMAND c_rgCommands[] =
|
|
{
|
|
// Generic commands (some depend on context)
|
|
//
|
|
{TEXT("?"), TEXT("Help!"), CTX_ANY, TRUE, DoHelp, TEXT("[command]")},
|
|
{TEXT("\\"), TEXT("Go to Root context"), CTX_ANY, TRUE, DoRoot, TEXT("")},
|
|
{TEXT(".."), TEXT("Go To Previous Context"), CTX_ANY & ~CTX_ROOT, TRUE, DoBack, TEXT("")},
|
|
{TEXT("exit"), TEXT("Exit UPDIAG"), CTX_ANY, TRUE, DoExit, TEXT("")},
|
|
{TEXT("info"), TEXT("List Information"), CTX_ANY, TRUE, DoInfo, TEXT("")},
|
|
{TEXT("script"), TEXT("Run Script"), CTX_ANY, TRUE, DoScript, TEXT("<file name>")},
|
|
|
|
// Automation specific commands (wont appear in menus)
|
|
//
|
|
{TEXT("sleep"), TEXT("Sleep for time period"), CTX_AUTO, TRUE, DoSleep, TEXT("<seconds>")},
|
|
{TEXT("prompt"), TEXT("Prompt (for user input)"), CTX_AUTO, TRUE, DoPrompt, TEXT("")},
|
|
|
|
// Listing commands
|
|
//
|
|
{TEXT("ls"), TEXT("List Services"), CTX_CD | CTX_DEVICE, TRUE, DoListServices, TEXT("")},
|
|
{TEXT("ld"), TEXT("List Devices"), CTX_ROOT | CTX_DEVICE | CTX_CD, TRUE, DoListDevices, TEXT("")},
|
|
{TEXT("lucp"), TEXT("List Control Points"), CTX_ROOT, TRUE, DoListUcp, TEXT("")},
|
|
{TEXT("les"), TEXT("List Event Sources"), CTX_CD, FALSE, DoListEventSources, TEXT("")},
|
|
{TEXT("lsubs"), TEXT("List Subscriptions"), CTX_UCP, TRUE, DoListUpnpResults, TEXT("")},
|
|
{TEXT("lsres"), TEXT("List Results"), CTX_RESULT, TRUE, DoListUpnpResultMsgs, TEXT("")},
|
|
{TEXT("lsrch"), TEXT("List Searches"), CTX_UCP, TRUE, DoListUpnpResults, TEXT("")},
|
|
|
|
// Context switching commands
|
|
//
|
|
{TEXT("ucp"), TEXT("Switch To UCP Context"), CTX_ROOT, TRUE, DoSwitchUcp, TEXT("<ucp #>")},
|
|
{TEXT("srch"), TEXT("Switch To Search Context"), CTX_UCP, TRUE, DoSwitchResult, TEXT("<search #>")},
|
|
{TEXT("dev"), TEXT("Switch To Device Context"), CTX_DEVICE, TRUE, DoNothing, TEXT("")},
|
|
{TEXT("svc"), TEXT("Switch To Service Context"), CTX_DEVICE | CTX_CD, TRUE, DoSwitchSvc, TEXT("<service #>")},
|
|
{TEXT("es"), TEXT("Switch To Event Source Context"), CTX_CD, FALSE, DoSwitchEs, TEXT("<event source #>")},
|
|
{TEXT("gsubs"), TEXT("Switch To Subscription Context"), CTX_UCP, TRUE, DoSwitchResult, TEXT("<subscription #>")},
|
|
|
|
// UCP commands
|
|
//
|
|
{TEXT("newucp"), TEXT("Create New Control Point"), CTX_ROOT, TRUE, DoNewUcp, TEXT("<ucp name>")},
|
|
{TEXT("delucp"), TEXT("Delete Control Point"), CTX_ROOT, TRUE, DoDelUcp, TEXT("<ucp #>")},
|
|
|
|
// These test RegisterNotification()
|
|
{TEXT("alive"), TEXT("Register For Alive Notification"), CTX_UCP, TRUE, DoAlive, TEXT("<notif type>")},
|
|
{TEXT("subs"), TEXT("Subscribe To Service"), CTX_UCP, TRUE, DoSubscribe, TEXT("<event source URL>")},
|
|
|
|
// These test DeregisterNotification()
|
|
{TEXT("unsubs"), TEXT("Unsubscribe To Service"), CTX_UCP, TRUE, DoDelResult, TEXT("<subscription #>")},
|
|
{TEXT("unalive"),TEXT("Stop Listening For Alive"), CTX_UCP, TRUE, DoNothing, TEXT("")},
|
|
|
|
// These test FindServicesCallback()
|
|
{TEXT("newf"), TEXT("Create New Search"), CTX_UCP, TRUE, DoFindServices, TEXT("<search type>")},
|
|
{TEXT("delf"), TEXT("Delete Search"), CTX_UCP, TRUE, DoDelResult, TEXT("<search #>")},
|
|
|
|
// These test FindServices()
|
|
// --- nothing yet ---
|
|
//
|
|
|
|
// These test UPnP COM interfaces
|
|
{TEXT("doc"), TEXT("List Description Document"), CTX_DEVICE, TRUE, DoNothing, TEXT("")},
|
|
{TEXT("cmd"), TEXT("Send Command To Service"), CTX_UCP_SVC, TRUE, DoNothing, TEXT("")},
|
|
|
|
// CD commands
|
|
//
|
|
|
|
// These test RegisterService() and RegisterEventSource()
|
|
{TEXT("newcd"), TEXT("Create New CD"), CTX_ROOT, FALSE, DoNewCd, TEXT("<URL to description doc>, <Device INF file>")},
|
|
{TEXT("cd"), TEXT("Switch To CD Context"), CTX_ROOT | CTX_CD, FALSE, DoSwitchCd, TEXT("<cd #>")},
|
|
{TEXT("delcd"), TEXT("Delete CD"), CTX_ROOT, FALSE, DoDelCd, TEXT("<cd #>")},
|
|
|
|
// This tests SubmitUpnpPropertyEvent()
|
|
{TEXT("evt"), TEXT("Submit An Event"), CTX_EVTSRC, FALSE, DoSubmitEvent, TEXT("{property#:newValue} [...]")},
|
|
{TEXT("props"), TEXT("List Event Source Properties"), CTX_EVTSRC, FALSE, DoListProps, TEXT("")},
|
|
|
|
// Dump StateTable and action set of a service
|
|
{TEXT("sst"), TEXT("Print the service state table"), CTX_CD_SVC, FALSE, DoPrintSST, TEXT("")},
|
|
{TEXT("actions"), TEXT("Print the service action set"), CTX_CD_SVC, FALSE, DoPrintActionSet, TEXT("")},
|
|
};
|
|
|
|
static const DWORD c_cCmd = celems(c_rgCommands);
|
|
|
|
BOOL FIsMillenium()
|
|
{
|
|
OSVERSIONINFO osvi = {0};
|
|
|
|
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
|
|
GetVersionEx(&osvi);
|
|
|
|
return (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
|
|
}
|
|
|
|
VOID Usage(DWORD iCmd)
|
|
{
|
|
_tprintf(TEXT("%s - %s\nUsage: \n %s %s\n\n"), c_rgCommands[iCmd].szCommand,
|
|
c_rgCommands[iCmd].szCmdDesc, c_rgCommands[iCmd].szCommand,
|
|
c_rgCommands[iCmd].szUsage);
|
|
}
|
|
|
|
BOOL FCmdFromName(LPCTSTR szName, DWORD *piCmd)
|
|
{
|
|
DWORD iCmd;
|
|
|
|
*piCmd = 0xFFFFFFFF;
|
|
|
|
for (iCmd = 0; iCmd < c_cCmd; iCmd++)
|
|
{
|
|
if (!_tcsicmp(szName, c_rgCommands[iCmd].szCommand))
|
|
{
|
|
*piCmd = iCmd;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL DoHelp(DWORD iCmd, DWORD cArgs, LPTSTR *rgArgs)
|
|
{
|
|
LPTSTR szName;
|
|
|
|
if (cArgs == 2)
|
|
{
|
|
if (FCmdFromName(rgArgs[1], &iCmd))
|
|
{
|
|
Usage(iCmd);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
_tprintf(TEXT("Available commands:\n"));
|
|
_tprintf(TEXT("-------------------\n"));
|
|
for (iCmd = 0; iCmd < c_cCmd; iCmd++)
|
|
{
|
|
if ((c_rgCommands[iCmd].dwCtx & g_ctx.ectx) &&
|
|
(((FIsMillenium() && c_rgCommands[iCmd].fValidOnMillen)) ||
|
|
(!FIsMillenium())))
|
|
|
|
{
|
|
_tprintf(TEXT("%-7s - %s\n"), c_rgCommands[iCmd].szCommand,
|
|
c_rgCommands[iCmd].szCmdDesc);
|
|
}
|
|
}
|
|
|
|
_tprintf(TEXT("-------------------\n\n"));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL DoInfo(DWORD iCmd, DWORD cArgs, LPTSTR *rgArgs)
|
|
{
|
|
if (cArgs == 1)
|
|
{
|
|
switch (g_ctx.ectx)
|
|
{
|
|
case CTX_EVTSRC:
|
|
DoEvtSrcInfo();
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Usage(iCmd);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL DoSleep(DWORD iCmd, DWORD cArgs, LPTSTR *rgArgs)
|
|
{
|
|
if (cArgs == 2)
|
|
{
|
|
DWORD iSeconds = _tcstoul(rgArgs[1], NULL, 10);
|
|
|
|
_tprintf(TEXT("Sleeping for %d second(s).\n\n"), iSeconds);
|
|
Sleep(iSeconds * 1000);
|
|
}
|
|
else
|
|
{
|
|
Usage(iCmd);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL DoPrompt(DWORD iCmd, DWORD cArgs, LPTSTR *rgArgs)
|
|
{
|
|
TCHAR szBuf[10]; // Size doesn't matter (uh, not here anyway)
|
|
|
|
_tprintf(TEXT("Press [Enter] to continue\n"));
|
|
|
|
_fgetts(szBuf, sizeof(szBuf), stdin);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL DoScript(DWORD iCmd, DWORD cArgs, LPTSTR *rgArgs)
|
|
{
|
|
if (cArgs == 2)
|
|
{
|
|
if (g_pInputFile)
|
|
{
|
|
_tprintf(TEXT("Error. Already in script. Go away.\n\n"));
|
|
}
|
|
else
|
|
{
|
|
g_pInputFile = _tfopen(rgArgs[1], TEXT("r"));
|
|
if (!g_pInputFile)
|
|
{
|
|
_tprintf(TEXT("Failed to open input file. Reverting to user-input.\n\n"));
|
|
}
|
|
else
|
|
{
|
|
_tprintf(TEXT("Running in scripted mode with file: %S\n\n"), rgArgs[1]);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Usage(iCmd);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL DoNothing(DWORD iCmd, DWORD cArgs, LPTSTR *rgArgs)
|
|
{
|
|
_tprintf(TEXT("Not yet implemented.\n\n"));
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL DoRoot(DWORD iCmd, DWORD cArgs, LPTSTR *rgArgs)
|
|
{
|
|
g_ctx.ectx = CTX_ROOT;
|
|
g_ctx.idevStackIndex = 0;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL DoBack(DWORD iCmd, DWORD cArgs, LPTSTR *rgArgs)
|
|
{
|
|
switch (g_ctx.ectx)
|
|
{
|
|
case CTX_UCP:
|
|
g_ctx.ectx = CTX_ROOT;
|
|
break;
|
|
|
|
case CTX_CD:
|
|
PopDev();
|
|
if (!g_ctx.idevStackIndex)
|
|
{
|
|
// Go back to root context if no more devs on stack
|
|
g_ctx.ectx = CTX_ROOT;
|
|
}
|
|
break;
|
|
|
|
case CTX_RESULT:
|
|
g_ctx.ectx = CTX_UCP;
|
|
break;
|
|
|
|
case CTX_CD_SVC:
|
|
case CTX_EVTSRC:
|
|
g_ctx.ectx = CTX_CD;
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
VOID Cleanup()
|
|
{
|
|
DWORD i;
|
|
|
|
SetEvent(g_hEventCleanup);
|
|
TraceTag(ttidUpdiag, "Waiting for time thread to exit");
|
|
WaitForSingleObject(g_hThreadTime, INFINITE);
|
|
|
|
for (i = 0; i < g_params.cCd; i++)
|
|
{
|
|
CleanupCd(g_params.rgCd[i]);
|
|
}
|
|
|
|
for (i = 0; i < g_params.cUcp; i++)
|
|
{
|
|
CleanupUcp(g_params.rgUcp[i]);
|
|
}
|
|
|
|
UnmapViewOfFile((LPVOID)g_pdata);
|
|
CloseHandle(g_hMapFile);
|
|
CloseHandle(g_hEvent);
|
|
CloseHandle(g_hEventRet);
|
|
CloseHandle(g_hEventCleanup);
|
|
CloseHandle(g_hMutex);
|
|
|
|
CoUninitialize();
|
|
UnInitializeNcInet();
|
|
SsdpCleanup();
|
|
}
|
|
|
|
BOOL DoExit(DWORD iCmd, DWORD cArgs, LPTSTR *rgArgs)
|
|
{
|
|
if (cArgs == 1)
|
|
{
|
|
Cleanup();
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL ParseCommand(LPTSTR szCommand)
|
|
{
|
|
DWORD iCmd;
|
|
LPTSTR szTemp;
|
|
|
|
// eat leading spaces
|
|
while (*szCommand == ' ')
|
|
{
|
|
szCommand++;
|
|
}
|
|
|
|
szTemp = _tcstok(szCommand, c_szSeps);
|
|
if (szTemp && *szTemp && (*szTemp != ';'))
|
|
{
|
|
for (iCmd = 0; iCmd < c_cCmd; iCmd++)
|
|
{
|
|
if (!lstrcmpi(szCommand, c_rgCommands[iCmd].szCommand) &&
|
|
(((FIsMillenium() && c_rgCommands[iCmd].fValidOnMillen)) ||
|
|
(!FIsMillenium())))
|
|
{
|
|
if (c_rgCommands[iCmd].dwCtx & (g_ctx.ectx | CTX_AUTO))
|
|
{
|
|
DWORD iArg = 0;
|
|
LPTSTR argv[MAX_ARGS];
|
|
|
|
ZeroMemory(&argv, sizeof(argv));
|
|
while (szTemp && iArg < MAX_ARGS)
|
|
{
|
|
argv[iArg++] = szTemp;
|
|
szTemp = _tcstok(NULL, c_szSeps);
|
|
}
|
|
|
|
return c_rgCommands[iCmd].pfnCommand(iCmd, iArg, argv);
|
|
}
|
|
else
|
|
{
|
|
_tprintf(TEXT("'%s' is not valid in this context.\n\n"),
|
|
_tcstok(szCommand, TEXT(" \r\n\t")));
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
_tprintf(TEXT("Unknown command: '%s'.\n\n"), _tcstok(szCommand, TEXT(" \r\n\t")));
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL FInit()
|
|
{
|
|
HANDLE hThread;
|
|
SECURITY_ATTRIBUTES sa = {0};
|
|
SECURITY_DESCRIPTOR sd = {0};
|
|
HRESULT hr = S_OK;
|
|
|
|
hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
if (FAILED(hr))
|
|
{
|
|
TraceError("FInit", hr);
|
|
return FALSE;
|
|
}
|
|
|
|
InitializeDebugging();
|
|
if (!SsdpStartup())
|
|
{
|
|
TraceTag(ttidUpdiag, "SsdpStartup failed! Error %d.",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
InitializeNcInet();
|
|
|
|
if (FIsMillenium())
|
|
{
|
|
// Don't need to do any more
|
|
return TRUE;
|
|
}
|
|
|
|
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
|
|
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
|
|
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
|
|
sa.bInheritHandle = FALSE;
|
|
sa.lpSecurityDescriptor = &sd;
|
|
|
|
g_hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE,
|
|
0, sizeof(SHARED_DATA), c_szSharedData);
|
|
|
|
if (!g_hMapFile)
|
|
{
|
|
TraceTag(ttidUpdiag, "Could not create shared memory! Error %d.",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
TraceTag(ttidUpdiag, "Created file mapping '%s'.", c_szSharedData);
|
|
|
|
g_pdata = (SHARED_DATA *)MapViewOfFile(g_hMapFile, FILE_MAP_ALL_ACCESS,
|
|
0, 0, 0);
|
|
if (!g_pdata)
|
|
{
|
|
TraceTag(ttidUpdiag, "Could not map shared memory! Error %d.", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
ZeroMemory(g_pdata, sizeof(SHARED_DATA));
|
|
|
|
g_hEvent = CreateEvent(&sa, FALSE, FALSE, c_szSharedEvent);
|
|
if (!g_hEvent)
|
|
{
|
|
TraceTag(ttidUpdiag, "Could not create %s! Error %d.",
|
|
c_szSharedEvent, GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
TraceTag(ttidUpdiag, "Created %s event.", c_szSharedEvent);
|
|
|
|
g_hEventRet = CreateEvent(&sa, FALSE, FALSE, c_szSharedEventRet);
|
|
if (!g_hEventRet)
|
|
{
|
|
TraceTag(ttidUpdiag, "Could not create %s! Error %d.",
|
|
c_szSharedEventRet, GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
TraceTag(ttidUpdiag, "Created %s event.", c_szSharedEventRet);
|
|
|
|
g_hEventCleanup = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (!g_hEventCleanup)
|
|
{
|
|
TraceTag(ttidUpdiag, "Could not create cleanup event! Error %d.",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
TraceTag(ttidUpdiag, "Created %s event.", c_szSharedEventRet);
|
|
|
|
DWORD dwThreadId;
|
|
hThread = CreateThread(NULL, 0, RequestHandlerThreadStart, NULL, 0,
|
|
&dwThreadId);
|
|
if (!hThread)
|
|
{
|
|
TraceTag(ttidUpdiag, "Could not create request handler thread! Error %d.",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
TraceTag(ttidUpdiag, "Created shared thread.");
|
|
|
|
g_hMutex = CreateMutex(&sa, FALSE, c_szSharedMutex);
|
|
if (!g_hMutex)
|
|
{
|
|
TraceTag(ttidUpdiag, "Could not create shared mutex! Error %d.",
|
|
GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
TraceTag(ttidUpdiag, "Created mutex.");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID Prompt(LPTSTR szRoot, LPTSTR szParam)
|
|
{
|
|
const DWORD c_cchMax = 60;
|
|
TCHAR szPrompt[81];
|
|
|
|
if (szParam && *szParam)
|
|
{
|
|
if (_tcslen(szParam) >= c_cchMax)
|
|
{
|
|
TCHAR szTemp[c_cchMax + 1] = {0};
|
|
|
|
lstrcpyn(szTemp, szParam, c_cchMax);
|
|
|
|
wsprintf(szPrompt, TEXT("%s: %s...>"), szRoot, szTemp);
|
|
}
|
|
else
|
|
{
|
|
wsprintf(szPrompt, TEXT("%s: %s>"), szRoot, szParam);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wsprintf(szPrompt, TEXT("%s>"), szRoot);
|
|
}
|
|
|
|
_fputts(szPrompt, stdout);
|
|
}
|
|
|
|
BOOL FIsLineAllWhitespace(LPTSTR szBuf)
|
|
{
|
|
INT iLen = _tcslen(szBuf);
|
|
|
|
for (INT iLoop = 0; iLoop < iLen; iLoop++)
|
|
{
|
|
if (!_istspace(szBuf[iLoop]))
|
|
{
|
|
return FALSE;
|
|
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID PrintCommandPrompt()
|
|
{
|
|
switch (g_ctx.ectx)
|
|
{
|
|
case CTX_ROOT:
|
|
Prompt(TEXT("UPDIAG"), NULL);
|
|
break;
|
|
case CTX_CD:
|
|
Prompt(TEXT("CD"), PDevCur()->szFriendlyName);
|
|
break;
|
|
case CTX_RESULT:
|
|
switch (g_ctx.presCur->resType)
|
|
{
|
|
case RES_FIND:
|
|
Prompt(TEXT("SRCH"), g_ctx.presCur->szType);
|
|
break;
|
|
case RES_NOTIFY:
|
|
Prompt(TEXT("NOTIFY"), g_ctx.presCur->szType);
|
|
break;
|
|
case RES_SUBS:
|
|
Prompt(TEXT("SUBS"), g_ctx.presCur->szType);
|
|
break;
|
|
default:
|
|
Prompt(TEXT("BUG!"), g_ctx.presCur->szType);
|
|
break;
|
|
}
|
|
break;
|
|
case CTX_CD_SVC:
|
|
Prompt(TEXT("CDSVC"), g_ctx.psvcCur->szSti);
|
|
break;
|
|
case CTX_EVTSRC:
|
|
Prompt(TEXT("ES"), g_ctx.psvcCur->szEvtUrl);
|
|
break;
|
|
case CTX_UCP:
|
|
Prompt(TEXT("UCP"), g_ctx.pucpCur->szName);
|
|
break;
|
|
default:
|
|
Prompt(TEXT("UNKNOWN"), NULL);
|
|
break;
|
|
}
|
|
}
|
|
|
|
EXTERN_C
|
|
VOID
|
|
__cdecl
|
|
wmain (
|
|
IN INT argc,
|
|
IN PCWSTR argv[])
|
|
{
|
|
TCHAR szBuf[MAX_PATH];
|
|
BOOL fDone = FALSE;
|
|
|
|
if (!FInit())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Check for presence of input file arg. If there, init file input.
|
|
//
|
|
if (argc > 1)
|
|
{
|
|
CHAR szFileName[MAX_PATH];
|
|
|
|
WszToSzBuf(szFileName, argv[1], MAX_PATH);
|
|
g_pInputFile = fopen(szFileName, "r");
|
|
if (!g_pInputFile)
|
|
{
|
|
_tprintf(TEXT("Failed to open input file. Reverting to user-input.\n\n"));
|
|
}
|
|
else
|
|
{
|
|
_tprintf(TEXT("Running in scripted mode with file: %S\n\n"), argv[1]);
|
|
}
|
|
}
|
|
|
|
g_ctx.ectx = CTX_ROOT;
|
|
|
|
while (!fDone)
|
|
{
|
|
// If we're running from an input file, continue.
|
|
//
|
|
if (g_pInputFile)
|
|
{
|
|
// If there was an error reading the file
|
|
//
|
|
if (!_fgetts(szBuf, sizeof(szBuf), g_pInputFile))
|
|
{
|
|
// If it wasn't eof, print an error
|
|
//
|
|
if (!feof(g_pInputFile))
|
|
{
|
|
_tprintf(TEXT("\nFailure reading script file\n\n"));
|
|
}
|
|
else
|
|
{
|
|
_tprintf(TEXT("\n[Script complete]\n\n"));
|
|
}
|
|
|
|
// regardless, close the file and NULL the handle
|
|
//
|
|
fclose(g_pInputFile);
|
|
g_pInputFile = NULL;
|
|
}
|
|
else
|
|
{
|
|
if (!FIsLineAllWhitespace(szBuf))
|
|
{
|
|
PrintCommandPrompt();
|
|
_tprintf(TEXT("%s\n"), szBuf);
|
|
fDone = ParseCommand(szBuf);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PrintCommandPrompt();
|
|
_fgetts(szBuf, sizeof(szBuf), stdin);
|
|
|
|
// Print nice separator so we can distinguish between commands and output
|
|
//
|
|
_tprintf(TEXT("\n"));
|
|
|
|
fDone = ParseCommand(szBuf);
|
|
}
|
|
}
|
|
|
|
// Print nice terminating separator
|
|
//
|
|
_tprintf(TEXT("\n"));
|
|
|
|
if (g_pInputFile)
|
|
{
|
|
fclose(g_pInputFile);
|
|
}
|
|
|
|
SsdpCleanup();
|
|
}
|
|
|
|
|
|
// Copy this from the SSDP implemenation so that BoundsChecker doesn't get
|
|
// upset about mismatching new with free.
|
|
//
|
|
VOID LocalFreeSsdpMessage(PSSDP_MESSAGE pSsdpMessage)
|
|
{
|
|
delete pSsdpMessage->szAltHeaders;
|
|
delete pSsdpMessage->szContent;
|
|
delete pSsdpMessage->szLocHeader;
|
|
delete pSsdpMessage->szType;
|
|
delete pSsdpMessage->szUSN;
|
|
delete pSsdpMessage->szSid;
|
|
delete pSsdpMessage;
|
|
}
|
|
|
|
// stolen from ssdp\client\message.cpp
|
|
BOOL CopySsdpMessage(PSSDP_MESSAGE pDestination, CONST SSDP_MESSAGE * pSource)
|
|
{
|
|
pDestination->szLocHeader = NULL;
|
|
pDestination->szAltHeaders = NULL;
|
|
pDestination->szType = NULL;
|
|
pDestination->szUSN = NULL;
|
|
pDestination->szSid = NULL;
|
|
pDestination->szContent = NULL;
|
|
pDestination->iLifeTime = 0;
|
|
|
|
if (pSource->szType != NULL)
|
|
{
|
|
pDestination->szType = new CHAR [strlen(pSource->szType) + 1];
|
|
if (pDestination->szType == NULL)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
else
|
|
{
|
|
strcpy(pDestination->szType, pSource->szType);
|
|
}
|
|
}
|
|
|
|
if (pSource->szLocHeader != NULL)
|
|
{
|
|
pDestination->szLocHeader = new CHAR [strlen(pSource->szLocHeader) + 1];
|
|
if (pDestination->szLocHeader == NULL)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
else
|
|
{
|
|
strcpy(pDestination->szLocHeader, pSource->szLocHeader);
|
|
}
|
|
}
|
|
|
|
if (pSource->szAltHeaders != NULL)
|
|
{
|
|
pDestination->szAltHeaders = new CHAR [strlen(pSource->szAltHeaders) + 1];
|
|
if (pDestination->szAltHeaders == NULL)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
else
|
|
{
|
|
strcpy(pDestination->szAltHeaders, pSource->szAltHeaders);
|
|
}
|
|
}
|
|
|
|
if (pSource->szUSN != NULL)
|
|
{
|
|
pDestination->szUSN = new CHAR [strlen(pSource->szUSN) + 1];
|
|
if (pDestination->szUSN == NULL)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
else
|
|
{
|
|
strcpy(pDestination->szUSN, pSource->szUSN);
|
|
}
|
|
}
|
|
|
|
if (pSource->szSid != NULL)
|
|
{
|
|
pDestination->szSid = new CHAR [strlen(pSource->szSid) + 1];
|
|
if (pDestination->szSid == NULL)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
else
|
|
{
|
|
strcpy(pDestination->szSid, pSource->szSid);
|
|
}
|
|
}
|
|
|
|
pDestination->iLifeTime = pSource->iLifeTime;
|
|
pDestination->iSeq = pSource->iSeq;
|
|
|
|
return TRUE;
|
|
|
|
cleanup:
|
|
LocalFreeSsdpMessage(pDestination);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
VOID NotifyCallback(SSDP_CALLBACK_TYPE ct,
|
|
CONST SSDP_MESSAGE *pSsdpService,
|
|
LPVOID pContext)
|
|
{
|
|
UPNPRESULT * pres = (UPNPRESULT *)pContext;
|
|
|
|
Assert(pres);
|
|
|
|
switch (ct)
|
|
{
|
|
case SSDP_DONE:
|
|
break;
|
|
|
|
case SSDP_BYEBYE:
|
|
case SSDP_ALIVE:
|
|
case SSDP_FOUND:
|
|
case SSDP_EVENT:
|
|
if (pres->cResult < MAX_RESULT_MSGS)
|
|
{
|
|
SSDP_MESSAGE * pSsdpMsgCopy;
|
|
|
|
pSsdpMsgCopy = new SSDP_MESSAGE;
|
|
if (pSsdpMsgCopy)
|
|
{
|
|
BOOL fResult;
|
|
|
|
fResult = CopySsdpMessage(pSsdpMsgCopy, pSsdpService);
|
|
if (fResult)
|
|
{
|
|
// Overload iSeq in the case of alive or byebye so we know
|
|
// which is which
|
|
if (ct == SSDP_BYEBYE)
|
|
{
|
|
pSsdpMsgCopy->iSeq = 1;
|
|
}
|
|
else if (ct == SSDP_ALIVE)
|
|
{
|
|
pSsdpMsgCopy->iSeq = 2;
|
|
}
|
|
else if (ct == SSDP_FOUND)
|
|
{
|
|
pSsdpMsgCopy->iSeq = 0;
|
|
}
|
|
|
|
pres->rgmsgResult[pres->cResult++] = pSsdpMsgCopy;
|
|
}
|
|
// else, CopySsdpMessage frees pSsdpMsgCopy
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
TraceTag(ttidUpdiag, "Unknown callback type %d!", ct);
|
|
break;
|
|
}
|
|
}
|