Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1953 lines
62 KiB

  1. /************************************************************************
  2. Copyright (c) 2000-2000 Microsoft Corporation
  3. Module Name :
  4. bitsadmin.cpp
  5. Abstract :
  6. This file contains a very simple commandline utility for controlling
  7. the BITS service.
  8. Author :
  9. Mike Zoran mzoran July 2000.
  10. Revision History :
  11. Notes:
  12. This tools does not do all the necessary Release and memory
  13. free calls that a long lived program would need to do. Since
  14. this tool is generally short lived, or only a small section of code
  15. is used when it isn't, the system can be relied on for resource
  16. cleanup.
  17. ***********************************************************************/
  18. #include "bitsadmin.h"
  19. void CheckBITSHR( const WCHAR *pFailTxt, HRESULT Hr )
  20. {
  21. // Check on error code returned from BITS,
  22. // and exit with a printed error messeage on an error
  23. if ( !SUCCEEDED(Hr) )
  24. {
  25. WCHAR ErrorCode[12];
  26. if ( SUCCEEDED( StringCbPrintf( ErrorCode, sizeof(ErrorCode), L"0x%8.8x", Hr ) ) )
  27. {
  28. bcout << pFailTxt << L" - " << ErrorCode << L"\n";
  29. AutoStringPointer Message;
  30. HRESULT LookupHr = HRESULT_FROM_WIN32( ERROR_RESOURCE_LANG_NOT_FOUND );
  31. LCID LcidsToTry[] =
  32. {
  33. GetThreadLocale(),
  34. GetUserDefaultLCID(),
  35. GetSystemDefaultLCID(),
  36. MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ), 0 )
  37. };
  38. SIZE_T NumberOfLCIDs = sizeof( LcidsToTry ) / sizeof( *LcidsToTry );
  39. for( int i = 0;
  40. ( HRESULT_FROM_WIN32( ERROR_RESOURCE_LANG_NOT_FOUND ) == LookupHr ||
  41. HRESULT_FROM_WIN32( ERROR_MR_MID_NOT_FOUND ) == LookupHr ) &&
  42. i < NumberOfLCIDs;
  43. i++ )
  44. {
  45. LookupHr =
  46. g_Manager->GetErrorDescription(
  47. Hr,
  48. LcidsToTry[ i ],
  49. Message.GetRecvPointer() );
  50. if ( SUCCEEDED( LookupHr ) )
  51. {
  52. bcout << Message << L"\n";
  53. break;
  54. }
  55. }
  56. throw AbortException( Hr );
  57. }
  58. }
  59. }
  60. void ConnectToBITS()
  61. {
  62. // Connects to the BITS service
  63. if ( g_Manager.Get() )
  64. return;
  65. if ( !pComputerName )
  66. {
  67. CheckHR( L"Unable to connect to BITS",
  68. CoCreateInstance( CLSID_BackgroundCopyManager,
  69. NULL,
  70. CLSCTX_LOCAL_SERVER,
  71. IID_IBackgroundCopyManager,
  72. (void**)g_Manager.GetRecvPointer() ) );
  73. }
  74. else
  75. {
  76. COSERVERINFO ServerInfo;
  77. memset( &ServerInfo, 0 , sizeof( ServerInfo ) );
  78. ServerInfo.pwszName = pComputerName;
  79. IClassFactory *pFactory = NULL;
  80. CheckHR( L"Unable to connect to BITS",
  81. CoGetClassObject(
  82. CLSID_BackgroundCopyManager,
  83. CLSCTX_REMOTE_SERVER,
  84. &ServerInfo,
  85. IID_IClassFactory,
  86. (void**) &pFactory ) );
  87. CheckHR( L"Unable to connect to BITS",
  88. pFactory->CreateInstance(
  89. NULL,
  90. IID_IBackgroundCopyManager,
  91. (void**)g_Manager.GetRecvPointer() ));
  92. pFactory->Release();
  93. }
  94. }
  95. //
  96. // Generic commandline parsing structures and functions
  97. //
  98. typedef void (*PCMDPARSEFUNC)(int, WCHAR** );
  99. typedef struct _PARSEENTRY
  100. {
  101. const WCHAR * pCommand;
  102. PCMDPARSEFUNC pParseFunc;
  103. } PARSEENTRY;
  104. typedef struct _PARSETABLE
  105. {
  106. const PARSEENTRY *pEntries;
  107. PCMDPARSEFUNC pErrorFunc;
  108. void * pErrorContext;
  109. } PARSETABLE;
  110. void ParseCmd( int argc, WCHAR **argv, const PARSETABLE *pParseTable )
  111. {
  112. if ( !argc) goto InvalidCommand;
  113. for( const PARSEENTRY *pEntry = pParseTable->pEntries;
  114. pEntry->pCommand; pEntry++ )
  115. {
  116. if (!_wcsicmp( *argv, pEntry->pCommand ))
  117. {
  118. argc--;
  119. argv++;
  120. (*pEntry->pParseFunc)( argc, argv );
  121. return;
  122. }
  123. }
  124. InvalidCommand:
  125. // Couldn't find a match, so complain
  126. bcout << L"Invalid command\n";
  127. (*pParseTable->pErrorFunc)( argc, argv );
  128. throw AbortException( 1 );
  129. }
  130. //
  131. // BITS specific input and output
  132. //
  133. BITSOUTStream & operator<<( BITSOUTStream &s, SmartJobPointer Job )
  134. {
  135. GUID guid;
  136. CheckBITSHR( L"Unable to get guid to job", Job->GetId( &guid ) );
  137. return (s << guid );
  138. }
  139. BITSOUTStream& operator<<( BITSOUTStream &s, SmartJobErrorPointer Error )
  140. {
  141. SmartFilePointer pFile;
  142. AutoStringPointer LocalName;
  143. AutoStringPointer URL;
  144. CheckBITSHR( L"Unable to get error file", Error->GetFile( pFile.GetRecvPointer() ) );
  145. CheckBITSHR( L"Unable to get error URL", pFile->GetRemoteName( URL.GetRecvPointer() ) );
  146. CheckBITSHR( L"Unable to get error file name", pFile->GetLocalName( LocalName.GetRecvPointer() ) );
  147. bcout << AddIntensity() << L"ERROR FILE: " << ResetIntensity() << URL << L" -> " << LocalName << L"\n";
  148. BG_ERROR_CONTEXT Context;
  149. HRESULT Code;
  150. AutoStringPointer ErrorDescription;
  151. AutoStringPointer ContextDescription;
  152. CheckBITSHR( L"Unable to get error code", Error->GetError( &Context, &Code ) );
  153. HRESULT LookupHr = HRESULT_FROM_WIN32( ERROR_RESOURCE_LANG_NOT_FOUND );
  154. LCID LcidsToTry[] =
  155. {
  156. GetThreadLocale(),
  157. GetUserDefaultLCID(),
  158. GetSystemDefaultLCID(),
  159. MAKELCID( MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ), 0 )
  160. };
  161. SIZE_T NumberOfLCIDs = sizeof( LcidsToTry ) / sizeof( *LcidsToTry );
  162. for( int i = 0;
  163. ( HRESULT_FROM_WIN32( ERROR_RESOURCE_LANG_NOT_FOUND ) == LookupHr ||
  164. HRESULT_FROM_WIN32( ERROR_MR_MID_NOT_FOUND ) == LookupHr ) &&
  165. i < NumberOfLCIDs;
  166. i++ )
  167. {
  168. LookupHr =
  169. Error->GetErrorDescription(
  170. LcidsToTry[ i ],
  171. ErrorDescription.GetRecvPointer() );
  172. if ( SUCCEEDED( LookupHr ) )
  173. {
  174. break;
  175. }
  176. }
  177. CheckBITSHR( L"Unable to get error description", LookupHr );
  178. LookupHr = HRESULT_FROM_WIN32( ERROR_RESOURCE_LANG_NOT_FOUND );
  179. for( int i = 0;
  180. ( HRESULT_FROM_WIN32( ERROR_RESOURCE_LANG_NOT_FOUND ) == LookupHr ||
  181. HRESULT_FROM_WIN32( ERROR_MR_MID_NOT_FOUND ) == LookupHr ) &&
  182. i < NumberOfLCIDs;
  183. i++ )
  184. {
  185. LookupHr =
  186. Error->GetErrorContextDescription(
  187. LcidsToTry[ i ],
  188. ContextDescription.GetRecvPointer() );
  189. if ( SUCCEEDED( LookupHr ) )
  190. {
  191. break;
  192. }
  193. }
  194. CheckBITSHR( L"Unable to get context description", LookupHr );
  195. bcout << AddIntensity() << L"ERROR CODE: " << ResetIntensity() <<
  196. HRESULTToString(Code) << L" - " << ErrorDescription;
  197. bcout << AddIntensity() << L"ERROR CONTEXT: " << ResetIntensity() <<
  198. HRESULTToString((HRESULT)Context) << L" - " << ContextDescription;
  199. return s;
  200. }
  201. BITSOUTStream & operator<<( BITSOUTStream &s, BG_JOB_TYPE type )
  202. {
  203. if ( BG_JOB_TYPE_DOWNLOAD == type )
  204. return ( s << L"DOWNLOAD" );
  205. else if ( BG_JOB_TYPE_UPLOAD == type )
  206. return ( s << L"UPLOAD" );
  207. else if ( BG_JOB_TYPE_UPLOAD_REPLY == type )
  208. return ( s << L"UPLOAD-REPLY" );
  209. else
  210. return ( s << L"UNKNOWN" );
  211. }
  212. BITSOUTStream & operator<<( BITSOUTStream &s, BG_JOB_STATE state )
  213. {
  214. switch(state)
  215. {
  216. case BG_JOB_STATE_QUEUED:
  217. return ( s << L"QUEUED" );
  218. case BG_JOB_STATE_CONNECTING:
  219. return ( s << L"CONNECTING" );
  220. case BG_JOB_STATE_TRANSFERRING:
  221. return ( s << L"TRANSFERRING" );
  222. case BG_JOB_STATE_SUSPENDED:
  223. return ( s << L"SUSPENDED" );
  224. case BG_JOB_STATE_ERROR:
  225. return ( s << L"ERROR" );
  226. case BG_JOB_STATE_TRANSIENT_ERROR:
  227. return ( s << L"TRANSIENT_ERROR" );
  228. case BG_JOB_STATE_TRANSFERRED:
  229. return ( s << L"TRANSFERRED" );
  230. case BG_JOB_STATE_ACKNOWLEDGED:
  231. return ( s << L"ACKNOWLEDGED" );
  232. case BG_JOB_STATE_CANCELLED:
  233. return ( s << L"CANCELLED" );
  234. default:
  235. return ( s << L"UNKNOWN" );
  236. }
  237. }
  238. BITSOUTStream & operator<<( BITSOUTStream &s, BG_JOB_PRIORITY priority )
  239. {
  240. switch(priority)
  241. {
  242. case BG_JOB_PRIORITY_FOREGROUND:
  243. return ( s << L"FOREGROUND" );
  244. case BG_JOB_PRIORITY_HIGH:
  245. return ( s << L"HIGH" );
  246. case BG_JOB_PRIORITY_NORMAL:
  247. return ( s << L"NORMAL" );
  248. case BG_JOB_PRIORITY_LOW:
  249. return ( s << L"LOW" );
  250. default:
  251. return ( s << L"UNKNOWN" );
  252. }
  253. }
  254. BG_JOB_PRIORITY JobInputPriority( WCHAR *pText )
  255. {
  256. if ( _wcsicmp( pText, L"FOREGROUND" ) == 0 )
  257. return BG_JOB_PRIORITY_FOREGROUND;
  258. if ( _wcsicmp( pText, L"HIGH" ) == 0 )
  259. return BG_JOB_PRIORITY_HIGH;
  260. if ( _wcsicmp( pText, L"NORMAL" ) == 0 )
  261. return BG_JOB_PRIORITY_NORMAL;
  262. if ( _wcsicmp( pText, L"LOW" ) == 0 )
  263. return BG_JOB_PRIORITY_LOW;
  264. bcout << L"Invalid priority.\n";
  265. throw AbortException(1);
  266. }
  267. SmartJobPointer
  268. JobLookupViaDisplayName( const WCHAR * JobName )
  269. {
  270. SmartEnumJobsPointer Enum;
  271. CheckBITSHR( L"Unable to lookup job", g_Manager->EnumJobs( 0, Enum.GetRecvPointer() ) );
  272. size_t FoundJobs = 0;
  273. SmartJobPointer FoundJob;
  274. SmartJobPointer Job;
  275. while( Enum->Next( 1, Job.GetRecvPointer(), NULL ) == S_OK )
  276. {
  277. PollShutdown();
  278. AutoStringPointer DisplayName;
  279. CheckBITSHR( L"Unable to lookup job", Job->GetDisplayName( DisplayName.GetRecvPointer() ) );
  280. if ( wcscmp( DisplayName, JobName) == 0 )
  281. {
  282. FoundJobs++;
  283. FoundJob = Job;
  284. }
  285. }
  286. if ( 1 == FoundJobs )
  287. {
  288. return FoundJob;
  289. }
  290. if ( !FoundJobs )
  291. {
  292. bcout << L"Unable to find job named \"" << JobName << L"\".\n";
  293. throw AbortException( 1 );
  294. }
  295. bcout << L"Found " << FoundJobs << L" jobs named \"" << JobName << L"\".\n";
  296. bcout << L"Use the job identifier instead of the job name.\n";
  297. throw AbortException( 1 );
  298. }
  299. SmartJobPointer
  300. JobLookup( WCHAR * JobName )
  301. {
  302. ConnectToBITS();
  303. GUID JobGuid;
  304. SmartJobPointer Job;
  305. if ( FAILED( CLSIDFromString( JobName, &JobGuid) ) )
  306. return JobLookupViaDisplayName( JobName );
  307. if ( FAILED( g_Manager->GetJob( JobGuid, Job.GetRecvPointer() ) ) )
  308. return JobLookupViaDisplayName( JobName );
  309. return Job;
  310. }
  311. SmartJobPointer
  312. JobLookupForNoArg( int argc, WCHAR **argv )
  313. {
  314. if (1 != argc)
  315. {
  316. bcout << L"Invalid number of arguments.\n";
  317. throw AbortException(1);
  318. }
  319. return JobLookup( argv[0] );
  320. }
  321. void JobValidateArgs( int argc, WCHAR**argv, int required )
  322. {
  323. if ( argc != required )
  324. {
  325. bcout << L"Invalid number of arguments.\n";
  326. throw AbortException(1);
  327. }
  328. }
  329. //
  330. // Actual command functions
  331. //
  332. void JobCreate( int argc, WCHAR **argv )
  333. {
  334. GUID guid;
  335. SmartJobPointer Job;
  336. BG_JOB_TYPE type = BG_JOB_TYPE_DOWNLOAD;
  337. while (argc > 0)
  338. {
  339. if (argv[0][0] != '/')
  340. {
  341. break;
  342. }
  343. if ( !_wcsicmp( argv[0], L"/UPLOAD" ) )
  344. {
  345. type = BG_JOB_TYPE_UPLOAD;
  346. }
  347. else if ( !_wcsicmp( argv[0], L"/UPLOAD-REPLY" ) )
  348. {
  349. type = BG_JOB_TYPE_UPLOAD_REPLY;
  350. }
  351. else if ( !_wcsicmp( argv[0], L"/DOWNLOAD" ) )
  352. {
  353. type = BG_JOB_TYPE_DOWNLOAD;
  354. }
  355. else
  356. {
  357. bcout << L"Invalid argument.\n";
  358. throw AbortException(1);
  359. }
  360. --argc;
  361. ++argv;
  362. }
  363. JobValidateArgs( argc, argv, 1 );
  364. ConnectToBITS();
  365. CheckBITSHR( L"Unable to create group",
  366. g_Manager->CreateJob( argv[0],
  367. type,
  368. &guid,
  369. Job.GetRecvPointer() ) );
  370. if (bRawReturn)
  371. bcout << Job;
  372. else
  373. bcout << L"Created job " << Job << L".\n";
  374. }
  375. void JobAddFile( int argc, WCHAR **argv )
  376. {
  377. JobValidateArgs( argc, argv, 3 );
  378. SmartJobPointer Job = JobLookup( argv[0] );
  379. CheckBITSHR( L"Unable to add file to job", Job->AddFile( argv[1], argv[2] ) );
  380. bcout << L"Added " << argv[1] << L" -> " << argv[2] << L" to job.\n";
  381. }
  382. size_t JobListFiles( SmartJobPointer Job, bool bDoIndent )
  383. {
  384. SmartEnumFilesPointer Enum;
  385. CheckBITSHR( L"Unable to enum files in job", Job->EnumFiles( Enum.GetRecvPointer() ) );
  386. SmartFilePointer pFile;
  387. size_t FilesListed = 0;
  388. while( Enum->Next( 1, pFile.GetRecvPointer(), NULL ) == S_OK )
  389. {
  390. BG_FILE_PROGRESS progress;
  391. AutoStringPointer URL;
  392. AutoStringPointer Local;
  393. CheckBITSHR( L"Unable to get file progress", pFile->GetProgress( &progress ) );
  394. CheckBITSHR( L"Unable to get file URL", pFile->GetRemoteName( URL.GetRecvPointer() ) );
  395. CheckBITSHR( L"Unable to get local file name", pFile->GetLocalName( Local.GetRecvPointer() ) );
  396. if ( bDoIndent )
  397. bcout << L"\t";
  398. WCHAR *pCompleteText = progress.Completed ? L"COMPLETED" : L"WORKING";
  399. bcout << progress.BytesTransferred << L" / ";
  400. if ( progress.BytesTotal != (UINT64)-1 )
  401. {
  402. bcout << progress.BytesTotal;
  403. }
  404. else
  405. {
  406. bcout << L"UNKNOWN";
  407. }
  408. bcout << L" " << pCompleteText << L" " << URL << L" -> " << Local << L"\n";
  409. // Example output:
  410. // 10 / 1000 INCOMPLETE http://www.microsoft.com -> c:\temp\microsoft.htm
  411. FilesListed++;
  412. }
  413. return FilesListed;
  414. }
  415. void JobListFiles( int argc, WCHAR **argv )
  416. {
  417. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  418. size_t FilesListed = JobListFiles( Job, false );
  419. if (!bRawReturn)
  420. bcout << L"Listed " << FilesListed << L" file(s).\n";
  421. }
  422. void JobSuspend( int argc, WCHAR **argv )
  423. {
  424. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  425. CheckBITSHR( L"Unable to suspend job", Job->Suspend() );
  426. bcout << L"Job suspended.\n";
  427. }
  428. void JobResume( int argc, WCHAR **argv )
  429. {
  430. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  431. CheckBITSHR( L"Unable to resume job", Job->Resume() );
  432. bcout << L"Job resumed.\n";
  433. }
  434. void JobCancel( int argc, WCHAR **argv )
  435. {
  436. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  437. CheckBITSHR( L"Unable to cancel job", Job->Cancel() );
  438. bcout << L"Job canceled.\n";
  439. }
  440. void JobComplete( int argc, WCHAR **argv )
  441. {
  442. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  443. CheckBITSHR( L"Unable to complete job", Job->Complete() );
  444. bcout << L"Job completed.\n";
  445. }
  446. void JobGetType( int argc, WCHAR **argv )
  447. {
  448. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  449. BG_JOB_TYPE type;
  450. CheckBITSHR( L"Unable to get job type", Job->GetType(&type) );
  451. bcout << type;
  452. if (!bRawReturn) bcout << L"\n";
  453. }
  454. void JobGetBytesTotal( int argc, WCHAR **argv )
  455. {
  456. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  457. BG_JOB_PROGRESS progress;
  458. CheckBITSHR( L"Unable to get total bytes in job", Job->GetProgress( &progress ) );
  459. bcout << progress.BytesTotal;
  460. if (!bRawReturn) bcout << L"\n";
  461. }
  462. void JobGetBytesTransferred( int argc, WCHAR **argv )
  463. {
  464. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  465. BG_JOB_PROGRESS progress;
  466. CheckBITSHR( L"Unable to get bytes transferred in job", Job->GetProgress( &progress ) );
  467. bcout << progress.BytesTransferred;
  468. if (!bRawReturn) bcout << L"\n";
  469. }
  470. void JobGetFilesTotal( int argc, WCHAR **argv )
  471. {
  472. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  473. BG_JOB_PROGRESS progress;
  474. CheckBITSHR( L"Unable to get number of files in job", Job->GetProgress( &progress ) );
  475. bcout << progress.FilesTotal;
  476. if (!bRawReturn) bcout << L"\n";
  477. }
  478. void JobGetFilesTransferred( int argc, WCHAR **argv )
  479. {
  480. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  481. BG_JOB_PROGRESS progress;
  482. CheckBITSHR( L"Unable to get numeber of transferred files in job", Job->GetProgress( &progress ) );
  483. bcout << progress.FilesTransferred;
  484. if (!bRawReturn) bcout << L"\n";
  485. }
  486. void JobGetCreationTime( int argc, WCHAR **argv )
  487. {
  488. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  489. BG_JOB_TIMES times;
  490. CheckBITSHR( L"Unable to get job creation time", Job->GetTimes( &times ) );
  491. bcout << times.CreationTime;
  492. if (!bRawReturn) bcout << L"\n";
  493. }
  494. void JobGetModificationTime( int argc, WCHAR **argv )
  495. {
  496. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  497. BG_JOB_TIMES times;
  498. CheckBITSHR( L"Unable to get job modification time", Job->GetTimes( &times ) );
  499. bcout << times.ModificationTime;
  500. if (!bRawReturn) bcout << L"\n";
  501. }
  502. void JobGetCompletionTime( int argc, WCHAR **argv )
  503. {
  504. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  505. BG_JOB_TIMES times;
  506. CheckBITSHR( L"Unable to get job completion time", Job->GetTimes( &times ) );
  507. if ( !times.TransferCompletionTime.dwLowDateTime && !times.TransferCompletionTime.dwHighDateTime )
  508. bcout << L"WORKING";
  509. else
  510. bcout << times.TransferCompletionTime;
  511. if (!bRawReturn) bcout << L"\n";
  512. }
  513. void JobGetError( int argc, WCHAR **argv )
  514. {
  515. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  516. SmartJobErrorPointer Error;
  517. CheckBITSHR( L"Unable to get error", Job->GetError( Error.GetRecvPointer() ) );
  518. bcout << Error;
  519. }
  520. void JobGetState( int argc, WCHAR **argv )
  521. {
  522. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  523. BG_JOB_STATE state;
  524. CheckBITSHR( L"Unable to get job state", Job->GetState( &state ) );
  525. bcout << state;
  526. if (!bRawReturn) bcout << L"\n";
  527. }
  528. void JobGetOwner( int argc, WCHAR **argv )
  529. {
  530. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  531. AutoStringPointer Owner;
  532. CheckBITSHR( L"Unable to get job owner", Job->GetOwner( Owner.GetRecvPointer() ) );
  533. bcout << PrintSidString( Owner );
  534. if (!bRawReturn) bcout << L"\n";
  535. }
  536. void JobGetDisplayName( int argc, WCHAR **argv )
  537. {
  538. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  539. AutoStringPointer DisplayName;
  540. CheckBITSHR( L"Unable to get job displayname", Job->GetDisplayName( DisplayName.GetRecvPointer() ) );
  541. bcout << DisplayName;
  542. if (!bRawReturn) bcout << L"\n";
  543. }
  544. void JobSetDisplayName( int argc, WCHAR **argv )
  545. {
  546. JobValidateArgs( argc, argv, 2 );
  547. SmartJobPointer Job = JobLookup( argv[0] );
  548. CheckBITSHR( L"Unable to set display name", Job->SetDisplayName( argv[1] ) );
  549. bcout << L"Display name set to " << argv[1] << L".\n";
  550. }
  551. void JobGetDescription( int argc, WCHAR **argv )
  552. {
  553. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  554. AutoStringPointer Description;
  555. CheckBITSHR( L"Unable to get job displayname", Job->GetDescription( Description.GetRecvPointer() ) );
  556. bcout << Description;
  557. if (!bRawReturn) bcout << L"\n";
  558. }
  559. void JobSetDescription( int argc, WCHAR **argv )
  560. {
  561. JobValidateArgs( argc, argv, 2 );
  562. SmartJobPointer Job = JobLookup( argv[0] );
  563. CheckBITSHR( L"Unable to set description", Job->SetDescription( argv[1] ) );
  564. bcout << L"Description set to " << argv[1] << L".\n";
  565. }
  566. void JobGetReplyFileName( int argc, WCHAR **argv )
  567. {
  568. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  569. SmartJob2Pointer Job2;
  570. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  571. AutoStringPointer ReplyFileName;
  572. CheckBITSHR( L"Unable to get reply file name", Job2->GetReplyFileName( ReplyFileName.GetRecvPointer() ) );
  573. if (ReplyFileName)
  574. {
  575. bcout << L"'" << ReplyFileName << L"'";
  576. }
  577. else
  578. {
  579. bcout << L"(null)";
  580. }
  581. if (!bRawReturn) bcout << L"\n";
  582. }
  583. void JobSetReplyFileName( int argc, WCHAR **argv )
  584. {
  585. JobValidateArgs( argc, argv, 2 );
  586. SmartJobPointer Job = JobLookup( argv[0] );
  587. SmartJob2Pointer Job2;
  588. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  589. CheckBITSHR( L"Unable to set reply file name", Job2->SetReplyFileName( argv[1] ) );
  590. bcout << L"reply file name set to " << argv[1] << L".\n";
  591. }
  592. void JobGetReplyProgress( int argc, WCHAR **argv )
  593. {
  594. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  595. SmartJob2Pointer Job2;
  596. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  597. BG_JOB_REPLY_PROGRESS Progress;
  598. CheckBITSHR( L"Unable to get reply progress", Job2->GetReplyProgress( &Progress ) );
  599. bcout << L"progress: " << ULONG(Progress.BytesTransferred) << L" / ";
  600. if (Progress.BytesTotal == BG_SIZE_UNKNOWN)
  601. bcout << L"(unknown)";
  602. else
  603. bcout << ULONG(Progress.BytesTotal);
  604. bcout << L".\n";
  605. if (!bRawReturn) bcout << L"\n";
  606. }
  607. bool
  608. printable( char c )
  609. {
  610. if ( c < 32 )
  611. {
  612. return false;
  613. }
  614. if ( c > 126 )
  615. {
  616. return false;
  617. }
  618. return true;
  619. }
  620. void
  621. DumpBuffer(
  622. void * Buffer,
  623. unsigned Length
  624. )
  625. {
  626. const BYTES_PER_LINE = 16;
  627. unsigned char FAR *p = (unsigned char FAR *) Buffer;
  628. //
  629. // 3 chars per byte for hex display, plus an extra space every 4 bytes,
  630. // plus a byte for the printable representation, plus the \0.
  631. //
  632. const buflen = BYTES_PER_LINE*3+BYTES_PER_LINE/4+BYTES_PER_LINE;
  633. wchar_t Outbuf[buflen+1];
  634. Outbuf[0] = 0;
  635. Outbuf[buflen] = 0;
  636. wchar_t * HexDigits = L"0123456789abcdef";
  637. unsigned Index;
  638. for ( unsigned Offset=0; Offset < Length; Offset++ )
  639. {
  640. Index = Offset % BYTES_PER_LINE;
  641. if ( Index == 0 )
  642. {
  643. bcout << L" " << Outbuf << L"\n";
  644. for (int i=0; i < buflen; ++i)
  645. {
  646. Outbuf[i] = L' ';
  647. }
  648. }
  649. Outbuf[Index*3+Index/4 ] = HexDigits[p[Offset] / 16];
  650. Outbuf[Index*3+Index/4+1] = HexDigits[p[Offset] % 16];
  651. Outbuf[BYTES_PER_LINE*3+BYTES_PER_LINE/4+Index] = printable(p[Offset]) ? p[Offset] : L'.';
  652. }
  653. bcout << L" " << Outbuf << L"\n";
  654. }
  655. void JobGetReplyData( int argc, WCHAR **argv )
  656. {
  657. byte * Buffer = 0;
  658. UINT64 Length = 0;
  659. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  660. SmartJob2Pointer Job2;
  661. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  662. CheckBITSHR( L"Unable to get reply data", Job2->GetReplyData( &Buffer, &Length ) );
  663. bcout << L"data length is " << Length;
  664. DumpBuffer( Buffer, ULONG(Length) );
  665. }
  666. void JobGetNotifyCmdLine( int argc, WCHAR **argv )
  667. {
  668. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  669. SmartJob2Pointer Job2;
  670. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  671. LPWSTR Program = 0;
  672. LPWSTR Parms = 0;
  673. CheckBITSHR( L"Unable to get callback command line", Job2->GetNotifyCmdLine( &Program, &Parms ) );
  674. bcout << L"the notification command line is '" << Program << L"' '" << Program << L"'";
  675. if (!bRawReturn) bcout << L"\n";
  676. }
  677. void JobSetNotifyCmdLine( int argc, WCHAR **argv )
  678. {
  679. JobValidateArgs( argc, argv, 3 );
  680. SmartJobPointer Job = JobLookup( argv[0] );
  681. SmartJob2Pointer Job2;
  682. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  683. WCHAR * Program;
  684. WCHAR * Parameters;
  685. if (_wcsicmp( argv[1], L"NULL") == 0)
  686. {
  687. Program = NULL;
  688. }
  689. else
  690. {
  691. Program = argv[1];
  692. if (!GetFileType( Program ))
  693. {
  694. }
  695. }
  696. if (_wcsicmp( argv[2], L"NULL") == 0)
  697. {
  698. Parameters = NULL;
  699. }
  700. else
  701. {
  702. Parameters = argv[2];
  703. }
  704. CheckBITSHR( L"Unable to set the notification command line", Job2->SetNotifyCmdLine( Program, Parameters ) );
  705. bcout << L"notification command line set to '" << argv[1] << L"' '" << argv[2] << L"'.\n";
  706. }
  707. BG_AUTH_TARGET TargetFromString( LPCWSTR s )
  708. {
  709. if (0 == _wcsicmp(s, L"server"))
  710. {
  711. return BG_AUTH_TARGET_SERVER;
  712. }
  713. else if (0 == _wcsicmp(s, L"proxy"))
  714. {
  715. return BG_AUTH_TARGET_PROXY;
  716. }
  717. bcout << L"'" << s << L"' is not a valid credential target. It must be 'proxy' or 'server'.\n";
  718. throw AbortException( 1 );
  719. }
  720. struct
  721. {
  722. LPCWSTR Name;
  723. BG_AUTH_SCHEME Scheme;
  724. }
  725. SchemeNames[] =
  726. {
  727. { L"basic", BG_AUTH_SCHEME_BASIC },
  728. { L"digest", BG_AUTH_SCHEME_DIGEST },
  729. { L"ntlm", BG_AUTH_SCHEME_NTLM },
  730. { L"negotiate", BG_AUTH_SCHEME_NEGOTIATE },
  731. { L"passport", BG_AUTH_SCHEME_PASSPORT },
  732. { NULL, BG_AUTH_SCHEME_BASIC }
  733. };
  734. BG_AUTH_SCHEME SchemeFromString( LPCWSTR s )
  735. {
  736. int i;
  737. i = 0;
  738. while (SchemeNames[i].Name != NULL)
  739. {
  740. if (0 == _wcsicmp( s, SchemeNames[i].Name ))
  741. {
  742. return SchemeNames[i].Scheme;
  743. }
  744. ++i;
  745. }
  746. bcout << L"'" << s << L"is not a valid credential scheme.\n"
  747. L"It must be one of the following:\n"
  748. L" basic\n"
  749. L" digest\n"
  750. L" ntlm\n"
  751. L" negotiate\n"
  752. L" passport\n";
  753. throw AbortException( 1 );
  754. }
  755. void JobSetCredentials( int argc, WCHAR **argv )
  756. /*
  757. args:
  758. 0: job ID
  759. 1: "proxy" | "server"
  760. 2: "basic" | "digest" | "ntlm" | "negotiate" | "passport"
  761. 3: user name
  762. 4: password
  763. */
  764. {
  765. JobValidateArgs( argc, argv, 5 );
  766. SmartJobPointer Job = JobLookup( argv[0] );
  767. SmartJob2Pointer Job2;
  768. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  769. BG_AUTH_CREDENTIALS cred;
  770. cred.Target = TargetFromString( argv[1] );
  771. cred.Scheme = SchemeFromString( argv[2] );
  772. cred.Credentials.Basic.UserName = argv[3];
  773. cred.Credentials.Basic.Password = argv[4];
  774. CheckBITSHR( L"Unable to add credentials", Job2->SetCredentials( &cred ));
  775. bcout << L"OK" << L".\n";
  776. }
  777. void JobRemoveCredentials( int argc, WCHAR **argv )
  778. /*
  779. args:
  780. 0: job ID
  781. 1: "proxy" | "server"
  782. 2: "basic" | "digest" | "ntlm" | "negotiate" | "passport"
  783. */
  784. {
  785. JobValidateArgs( argc, argv, 3 );
  786. SmartJobPointer Job = JobLookup( argv[0] );
  787. SmartJob2Pointer Job2;
  788. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  789. HRESULT hr;
  790. BG_AUTH_TARGET Target;
  791. BG_AUTH_SCHEME Scheme;
  792. Target = TargetFromString( argv[1] );
  793. Scheme = SchemeFromString( argv[2] );
  794. hr = Job2->RemoveCredentials( Target, Scheme );
  795. CheckBITSHR( L"Unable to remove credentials", hr);
  796. if (hr == S_FALSE)
  797. {
  798. bcout << L"no matching credential was found.\n";
  799. }
  800. else
  801. {
  802. bcout << L"OK" << L".\n";
  803. }
  804. }
  805. void JobGetPriority( int argc, WCHAR **argv )
  806. {
  807. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  808. BG_JOB_PRIORITY priority;
  809. CheckBITSHR( L"Unable to get job displayname", Job->GetPriority( &priority ) );
  810. bcout << priority;
  811. if (!bRawReturn) bcout << L"\n";
  812. }
  813. void JobSetPriority( int argc, WCHAR **argv )
  814. {
  815. JobValidateArgs( argc, argv, 2 );
  816. SmartJobPointer Job = JobLookup( argv[0] );
  817. BG_JOB_PRIORITY priority = JobInputPriority( argv[1] );
  818. CheckBITSHR( L"Unable to set description", Job->SetPriority( priority ) );
  819. bcout << L"Priority set to " << priority << L".\n";
  820. }
  821. void JobGetNotifyFlags( int argc, WCHAR **argv )
  822. {
  823. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  824. ULONG flags;
  825. CheckBITSHR( L"Unable to get notify flags", Job->GetNotifyFlags( &flags ) );
  826. bcout << flags;
  827. if (!bRawReturn) bcout << L"\n";
  828. }
  829. void JobSetNotifyFlags( int argc, WCHAR **argv )
  830. {
  831. JobValidateArgs( argc, argv, 2 );
  832. SmartJobPointer Job = JobLookup( argv[0] );
  833. ULONG NewFlags = InputULONG( argv[1] );
  834. CheckBITSHR( L"Unable to set description", Job->SetNotifyFlags( NewFlags ) );
  835. bcout << L"Notification flags set to " << NewFlags << L".\n";
  836. }
  837. void JobGetNotifyInterface( int argc, WCHAR **argv )
  838. {
  839. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  840. SmartIUnknownPointer pUnknown;
  841. CheckBITSHR( L"Unable to get notify interface", Job->GetNotifyInterface( pUnknown.GetRecvPointer() ) );
  842. if ( pUnknown.Get() )
  843. bcout << L"REGISTERED";
  844. else
  845. bcout << L"UNREGISTERED";
  846. if (!bRawReturn) bcout << L"\n";
  847. }
  848. void JobSetMinimumRetryDelay( int argc, WCHAR **argv )
  849. {
  850. JobValidateArgs( argc, argv, 2 );
  851. SmartJobPointer Job = JobLookup( argv[0] );
  852. ULONG NewDelay = InputULONG( argv[1] );
  853. CheckBITSHR( L"Unable to set new minimum retry delay", Job->SetMinimumRetryDelay( NewDelay ) );
  854. bcout << L"Minimum retry delay set to " << NewDelay << L".\n";
  855. }
  856. void JobGetMinimumRetryDelay( int argc, WCHAR **argv )
  857. {
  858. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  859. ULONG delay;
  860. CheckBITSHR( L"Unable to get minimum retry delay", Job->GetMinimumRetryDelay( &delay ) );
  861. bcout << delay;
  862. if (!bRawReturn) bcout << L"\n";
  863. }
  864. void JobGetNoProgressTimeout( int argc, WCHAR **argv )
  865. {
  866. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  867. ULONG timeout;
  868. CheckBITSHR( L"Unable to get no progress timeout", Job->GetNoProgressTimeout( &timeout ) );
  869. bcout << timeout;
  870. if (!bRawReturn) bcout << L"\n";
  871. }
  872. void JobSetNoProgressTimeout( int argc, WCHAR **argv )
  873. {
  874. JobValidateArgs( argc, argv, 2 );
  875. SmartJobPointer Job = JobLookup( argv[0] );
  876. ULONG NewTimeout = InputULONG( argv[1] );
  877. CheckBITSHR( L"Unable to set new no progress timeout", Job->SetNoProgressTimeout( NewTimeout ) );
  878. bcout << L"No progress timeout set to " << NewTimeout << L".\n";
  879. }
  880. void JobGetErrorCount( int argc, WCHAR **argv )
  881. {
  882. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  883. ULONG errors;
  884. CheckBITSHR( L"Unable to get no progress timeout", Job->GetErrorCount( &errors ) );
  885. bcout << errors;
  886. if (!bRawReturn) bcout << L"\n";
  887. }
  888. void JobInfo( SmartJobPointer Job )
  889. {
  890. GUID id;
  891. BG_JOB_STATE state;
  892. BG_JOB_PROGRESS progress;
  893. AutoStringPointer DisplayName;
  894. CheckBITSHR( L"Unable to get job ID", Job->GetId( &id ));
  895. CheckBITSHR( L"Unable to get job state", Job->GetState( &state ));
  896. CheckBITSHR( L"Unable to get job progress", Job->GetProgress( &progress ));
  897. CheckBITSHR( L"Unable to get display name", Job->GetDisplayName( DisplayName.GetRecvPointer() ) );
  898. bcout << id << L" " << DisplayName << L" " << state;
  899. bcout << L" " << progress.FilesTransferred << L" / " << progress.FilesTotal;
  900. bcout << L" " << progress.BytesTransferred << L" / ";
  901. if ( (UINT64)-1 == progress.BytesTotal )
  902. bcout << L"UNKNOWN";
  903. else
  904. bcout << progress.BytesTotal;
  905. bcout << L"\n";
  906. }
  907. void JobVerboseInfo( SmartJobPointer Job )
  908. {
  909. GUID id;
  910. AutoStringPointer Display;
  911. BG_JOB_TYPE type;
  912. BG_JOB_STATE state;
  913. AutoStringPointer Owner;
  914. BG_JOB_PRIORITY priority;
  915. BG_JOB_PROGRESS progress;
  916. BG_JOB_TIMES times;
  917. SmartIUnknownPointer Notify;
  918. ULONG NotifyFlags;
  919. ULONG retrydelay;
  920. ULONG noprogresstimeout;
  921. ULONG ErrorCount;
  922. AutoStringPointer Description;
  923. SmartJobErrorPointer Error;
  924. BG_JOB_PROXY_USAGE ProxyUsage;
  925. AutoStringPointer ProxyList;
  926. AutoStringPointer ProxyBypassList;
  927. bool fShow15Fields;
  928. SmartJob2Pointer Job2;
  929. BG_JOB_REPLY_PROGRESS ReplyProgress;
  930. AutoStringPointer ReplyFileName;
  931. AutoStringPointer NotifyProgram;
  932. AutoStringPointer NotifyParms;
  933. CheckBITSHR( L"Unable to get job ID", Job->GetId( &id) );
  934. CheckBITSHR( L"Unable to get job display name", Job->GetDisplayName(Display.GetRecvPointer()) );
  935. CheckBITSHR( L"Unable to get job type", Job->GetType( &type ) );
  936. CheckBITSHR( L"Unable to get job state", Job->GetState( &state ) );
  937. CheckBITSHR( L"Unable to get job owner", Job->GetOwner( Owner.GetRecvPointer() ) );
  938. CheckBITSHR( L"Unable to get job priority", Job->GetPriority( &priority ) );
  939. CheckBITSHR( L"Unable to get job progress", Job->GetProgress( &progress ) );
  940. CheckBITSHR( L"Unable to get job times", Job->GetTimes( &times ) );
  941. bool NotifyAvailable = SUCCEEDED( Job->GetNotifyInterface( Notify.GetRecvPointer() ) );
  942. CheckBITSHR( L"Unable to get job notification flags", Job->GetNotifyFlags( &NotifyFlags ) );
  943. CheckBITSHR( L"Unable to get job retry delay", Job->GetMinimumRetryDelay( &retrydelay ) );
  944. CheckBITSHR( L"Unable to get job no progress timeout", Job->GetNoProgressTimeout( &noprogresstimeout ) );
  945. CheckBITSHR( L"Unable to get job error count", Job->GetErrorCount( &ErrorCount ) );
  946. CheckBITSHR( L"Unable to get job description", Job->GetDescription( Description.GetRecvPointer() ) );
  947. CheckBITSHR( L"Unable to get proxy settings", Job->GetProxySettings( &ProxyUsage,
  948. ProxyList.GetRecvPointer(),
  949. ProxyBypassList.GetRecvPointer() ) );
  950. if (FAILED(Job->GetError( Error.GetRecvPointer() )) )
  951. Error.Clear();
  952. if (SUCCEEDED(Job2FromJob( Job, Job2 )))
  953. {
  954. fShow15Fields = true;
  955. CheckBITSHR( L"unable to get notification command line",
  956. Job2->GetNotifyCmdLine( NotifyProgram.GetRecvPointer(), NotifyParms.GetRecvPointer() ));
  957. if (type == BG_JOB_TYPE_UPLOAD_REPLY )
  958. {
  959. CheckBITSHR( L"unable to get reply progress", Job2->GetReplyProgress( &ReplyProgress ));
  960. CheckBITSHR( L"unable to get reply file name", Job2->GetReplyFileName( ReplyFileName.GetRecvPointer() ));
  961. }
  962. }
  963. else
  964. {
  965. fShow15Fields = false;
  966. }
  967. // Example output
  968. // GUID: {F196178C-0C00-4E92-A8AD-1F44E30C2485} DISPLAY: Test Job
  969. // TYPE: DOWNLOAD STATE: SUSPENDED OWNER: ntdev\somedev
  970. // PRIORITY: NORMAL FILES: 0 / 0 BYTES: 0 / 0
  971. // CREATION TIME: 5:29:35 PM 11/9/2000 MODIFICATION TIME: 5:29:35 PM 11/9/2000
  972. // COMPLETION TIME: 5:29:35 PM 11/9/2000
  973. // NOTIFY INTERFACE: 00000000 NOTIFICATION FLAGS: 3
  974. // RETRY DELAY: 300 NO PROGRESS TIMEOUT: 1209600 ERROR COUNT: 0
  975. // PROXY USAGE: PRECONFIG PROXY LIST: NULL PROXY BYPASS LIST: NULL
  976. // [ error info ]
  977. // DESCRIPTION:
  978. // [ file list ]
  979. //
  980. // Additional output for BITS 1.5:
  981. // NOTIFICATION COMMAND LINE: NULL
  982. // REPLY FILE: 'C:\foo\replyfile' 10 / 1000
  983. //
  984. bcout << AddIntensity() << L"GUID: " << ResetIntensity() << id << AddIntensity() << L" DISPLAY: " << ResetIntensity() << Display << L"\n";
  985. bcout << AddIntensity() << L"TYPE: " << ResetIntensity() << type;
  986. bcout << AddIntensity() << L" STATE: " << ResetIntensity() << state;
  987. bcout << AddIntensity() << L" OWNER: " << ResetIntensity() << PrintSidString( Owner ) << L"\n";
  988. bcout << AddIntensity() << L"PRIORITY: " << ResetIntensity() << priority;
  989. bcout << AddIntensity() << L" FILES: " << ResetIntensity() << progress.FilesTransferred << L" / " << progress.FilesTotal;
  990. bcout << AddIntensity() << L" BYTES: " << ResetIntensity() << progress.BytesTransferred << L" / ";
  991. if ( (UINT64)-1 == progress.BytesTotal )
  992. bcout << L"UNKNOWN";
  993. else
  994. bcout << progress.BytesTotal;
  995. bcout << L"\n";
  996. bcout << AddIntensity() << L"CREATION TIME: " << ResetIntensity() << times.CreationTime;
  997. bcout << AddIntensity() << L" MODIFICATION TIME: " << ResetIntensity() << times.ModificationTime << L"\n";
  998. bcout << AddIntensity() << L"COMPLETION TIME: " << ResetIntensity() << times.TransferCompletionTime << L"\n";
  999. bcout << AddIntensity() << L"NOTIFY INTERFACE: " << ResetIntensity();
  1000. if ( NotifyAvailable )
  1001. {
  1002. if ( Notify.Get() )
  1003. bcout << L"REGISTERED";
  1004. else
  1005. bcout << L"UNREGISTERED";
  1006. }
  1007. else
  1008. bcout << L"UNAVAILABLE";
  1009. bcout << AddIntensity() << L" NOTIFICATION FLAGS: " << ResetIntensity() << NotifyFlags << L"\n";
  1010. bcout << AddIntensity() << L"RETRY DELAY: " << ResetIntensity() << retrydelay;
  1011. bcout << AddIntensity() << L" NO PROGRESS TIMEOUT: " << ResetIntensity() << noprogresstimeout;
  1012. bcout << AddIntensity() << L" ERROR COUNT: " << ResetIntensity() << ErrorCount << L"\n";
  1013. bcout << AddIntensity() << L"PROXY USAGE: " << ResetIntensity() << ProxyUsage;
  1014. bcout << AddIntensity() << L" PROXY LIST: " << ResetIntensity() << ( (WCHAR*)ProxyList ? (WCHAR*)ProxyList : L"NULL" );
  1015. bcout << AddIntensity() << L" PROXY BYPASS LIST: " << ResetIntensity() << ((WCHAR*)ProxyBypassList ? (WCHAR*)ProxyBypassList : L"NULL" );
  1016. bcout << L"\n";
  1017. if ( Error.Get() )
  1018. bcout << Error;
  1019. bcout << AddIntensity() << L"DESCRIPTION: " << ResetIntensity() << Description << L"\n";
  1020. bcout << AddIntensity() << L"JOB FILES: \n" << ResetIntensity();
  1021. JobListFiles( Job, true );
  1022. if (fShow15Fields)
  1023. {
  1024. bcout << AddIntensity() << L"NOTIFICATION COMMAND LINE: " << ResetIntensity();
  1025. if (NotifyProgram)
  1026. {
  1027. bcout << L"'" << NotifyProgram << L"'";
  1028. if (NotifyParms)
  1029. {
  1030. bcout << L" '" << NotifyParms << L"'";
  1031. }
  1032. }
  1033. else
  1034. {
  1035. bcout << L"none";
  1036. }
  1037. bcout << L"\n";
  1038. if (type == BG_JOB_TYPE_UPLOAD_REPLY )
  1039. {
  1040. bcout << AddIntensity() << L"REPLY FILE: " << ResetIntensity();
  1041. if (LPCWSTR(ReplyFileName) == NULL)
  1042. {
  1043. bcout << L"none\n";
  1044. }
  1045. else
  1046. {
  1047. bcout << L"'" << ReplyFileName << L"' ";
  1048. bcout << ReplyProgress.BytesTransferred << L" / ";
  1049. if ( (UINT64)-1 == ReplyProgress.BytesTotal )
  1050. bcout << L"UNKNOWN";
  1051. else
  1052. bcout << ReplyProgress.BytesTotal;
  1053. bcout << L"\n";
  1054. }
  1055. }
  1056. }
  1057. }
  1058. void JobInfo( int argc, WCHAR **argv )
  1059. {
  1060. if ( ( argc != 1 ) && (argc != 2 ) )
  1061. {
  1062. bcout << L"Invalid argument.\n";
  1063. throw AbortException(1);
  1064. }
  1065. bool Verbose = false;
  1066. if ( 2 == argc )
  1067. {
  1068. if ( !_wcsicmp( argv[1], L"/VERBOSE" ) )
  1069. Verbose = true;
  1070. else
  1071. {
  1072. bcout << L"Invalid argument.\n";
  1073. throw AbortException(1);
  1074. }
  1075. }
  1076. SmartJobPointer Job = JobLookup( argv[0] );
  1077. if ( Verbose )
  1078. JobVerboseInfo( Job );
  1079. else
  1080. JobInfo( Job );
  1081. }
  1082. size_t JobList( bool Verbose, bool AllUsers )
  1083. {
  1084. DWORD dwFlags = 0;
  1085. if ( AllUsers )
  1086. dwFlags |= BG_JOB_ENUM_ALL_USERS;
  1087. size_t JobsListed = 0;
  1088. SmartEnumJobsPointer Enum;
  1089. CheckBITSHR( L"Unable to enum jobs", g_Manager->EnumJobs( dwFlags, Enum.GetRecvPointer() ) );
  1090. SmartJobPointer Job;
  1091. while( Enum->Next( 1, Job.GetRecvPointer(), NULL ) == S_OK )
  1092. {
  1093. if ( Verbose )
  1094. {
  1095. JobVerboseInfo( Job );
  1096. bcout << L"\n";
  1097. }
  1098. else
  1099. JobInfo( Job );
  1100. JobsListed++;
  1101. }
  1102. Enum.Release();
  1103. Job.Release();
  1104. return JobsListed;
  1105. }
  1106. void JobList( int argc, WCHAR **argv )
  1107. {
  1108. if ( argc > 2 )
  1109. {
  1110. bcout << L"Invalid number of arguments.\n";
  1111. throw AbortException(1);
  1112. }
  1113. bool Verbose = false;
  1114. bool AllUsers = false;
  1115. for( int i = 0; i < argc; i++)
  1116. {
  1117. if ( !_wcsicmp( argv[i], L"/VERBOSE" ) )
  1118. {
  1119. Verbose = true;
  1120. }
  1121. else if ( !_wcsicmp( argv[i], L"/ALLUSERS" ) )
  1122. {
  1123. AllUsers = true;
  1124. }
  1125. else
  1126. {
  1127. bcout << L"Invalid argument.\n";
  1128. throw AbortException(1);
  1129. }
  1130. }
  1131. ConnectToBITS();
  1132. size_t JobsListed = JobList( Verbose, AllUsers );
  1133. if (!bRawReturn)
  1134. bcout << L"Listed " << JobsListed << L" job(s).\n";
  1135. }
  1136. void JobMonitor( int argc, WCHAR**argv )
  1137. {
  1138. DWORD dwSleepSeconds = 5;
  1139. bool AllUsers = false;
  1140. // the default wrap is different for the /monitor command
  1141. if ( !bExplicitWrap )
  1142. {
  1143. bWrap = false;
  1144. ChangeConsoleMode();
  1145. }
  1146. if ( argc > 3 )
  1147. {
  1148. bcout << L"Invalid number of arguments.\n";
  1149. throw AbortException( 1 );
  1150. }
  1151. for( int i=0; i < argc; i++ )
  1152. {
  1153. if ( !_wcsicmp( argv[i], L"/ALLUSERS" ) )
  1154. {
  1155. AllUsers = true;
  1156. }
  1157. else if ( !_wcsicmp( argv[i], L"/REFRESH" ) )
  1158. {
  1159. i++;
  1160. if ( i >= argc )
  1161. {
  1162. bcout << L"/REFRESH is missing the refresh rate.";
  1163. throw AbortException(1);
  1164. }
  1165. dwSleepSeconds = InputULONG( argv[i] );
  1166. }
  1167. else
  1168. {
  1169. bcout << L"Invalid argument.\n";
  1170. throw AbortException(1);
  1171. }
  1172. }
  1173. if ( GetFileType( bcout.GetHandle() ) != FILE_TYPE_CHAR )
  1174. {
  1175. bcerr << L"/MONITOR will not work with a redirected stdout.\n";
  1176. throw AbortException(1);
  1177. }
  1178. ConnectToBITS();
  1179. for(;;)
  1180. {
  1181. ClearScreen();
  1182. bcout << L"MONITORING BACKGROUND COPY MANAGER(" << dwSleepSeconds << L" second refresh)\n";
  1183. JobList( false, AllUsers );
  1184. SleepEx( dwSleepSeconds * 1000, TRUE );
  1185. PollShutdown();
  1186. }
  1187. }
  1188. void JobReset( int argc, WCHAR **argv )
  1189. {
  1190. JobValidateArgs( argc, argv, 0 );
  1191. ConnectToBITS();
  1192. ULONG JobsFound = 0;
  1193. ULONG JobsCanceled = 0;
  1194. SmartEnumJobsPointer Enum;
  1195. CheckBITSHR( L"Unable to enum jobs", g_Manager->EnumJobs( 0, Enum.GetRecvPointer() ) );
  1196. SmartJobPointer Job;
  1197. while( Enum->Next( 1, Job.GetRecvPointer(), NULL ) == S_OK )
  1198. {
  1199. JobsFound++;
  1200. if (SUCCEEDED( Job->Cancel() ) )
  1201. {
  1202. bcout << Job << L" canceled.\n";
  1203. JobsCanceled++;
  1204. }
  1205. }
  1206. bcout << JobsCanceled << L" out of " << JobsFound << L" jobs canceled.\n";
  1207. }
  1208. void JobGetProxyUsage( int argc, WCHAR **argv )
  1209. {
  1210. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1211. BG_JOB_PROXY_USAGE ProxyUsage;
  1212. AutoStringPointer ProxyList;
  1213. AutoStringPointer ProxyBypassList;
  1214. CheckBITSHR( L"Unable to get proxy usage",
  1215. Job->GetProxySettings( &ProxyUsage, ProxyList.GetRecvPointer(), ProxyBypassList.GetRecvPointer() ) );
  1216. bcout << ProxyUsage;
  1217. if (!bRawReturn) bcout << L"\n";
  1218. }
  1219. void JobGetProxyList( int argc, WCHAR **argv )
  1220. {
  1221. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1222. BG_JOB_PROXY_USAGE ProxyUsage;
  1223. AutoStringPointer ProxyList;
  1224. AutoStringPointer ProxyBypassList;
  1225. CheckBITSHR( L"Unable to get proxy list",
  1226. Job->GetProxySettings( &ProxyUsage, ProxyList.GetRecvPointer(), ProxyBypassList.GetRecvPointer() ) );
  1227. bcout << ( (WCHAR*)ProxyList ? (WCHAR*)ProxyList : L"NULL");
  1228. if (!bRawReturn) bcout << L"\n";
  1229. }
  1230. void JobGetProxyBypassList( int argc, WCHAR **argv )
  1231. {
  1232. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1233. BG_JOB_PROXY_USAGE ProxyUsage;
  1234. AutoStringPointer ProxyList;
  1235. AutoStringPointer ProxyBypassList;
  1236. CheckBITSHR( L"Unable to get proxy bypass list",
  1237. Job->GetProxySettings( &ProxyUsage, ProxyList.GetRecvPointer(), ProxyBypassList.GetRecvPointer() ) );
  1238. bcout << ( (WCHAR*)ProxyBypassList ? (WCHAR*)ProxyBypassList : L"NULL");
  1239. if (!bRawReturn) bcout << L"\n";
  1240. }
  1241. WCHAR *
  1242. FindMatching( WCHAR *pStr, WCHAR start, WCHAR finish, ULONG CurrentLevel )
  1243. {
  1244. while( *pStr != L'\0' )
  1245. {
  1246. if ( start == *pStr )
  1247. CurrentLevel++;
  1248. else if ( finish == *pStr )
  1249. CurrentLevel--;
  1250. if ( !CurrentLevel )
  1251. return pStr;
  1252. pStr++;
  1253. }
  1254. return NULL;
  1255. }
  1256. void JobSetProxySettings( int argc, WCHAR **argv )
  1257. {
  1258. if (argc < 2)
  1259. {
  1260. bcout << L"/SetProxySettings must be followed by a job name or guid, then a proxy usage name\n";
  1261. throw AbortException(1);
  1262. }
  1263. SmartJobPointer Job = JobLookup( argv[0] );
  1264. WCHAR *pSettings = argv[1];
  1265. // The format of the settings is usage,<ProxyList>,<ProxyBypassList>
  1266. WCHAR *pEndUsage = wcsstr( pSettings, L"," );
  1267. if ( !pEndUsage )
  1268. pEndUsage = pSettings + wcslen( pSettings );
  1269. size_t UsageSize = ((char*)pEndUsage - (char*)pSettings)/sizeof(WCHAR);
  1270. AutoStringPointer Usage( new WCHAR[UsageSize + 1] );
  1271. memcpy( Usage.Get(), pSettings, UsageSize * sizeof(WCHAR) );
  1272. Usage.Get()[UsageSize] = L'\0';
  1273. BG_JOB_PROXY_USAGE ProxyUsage;
  1274. if ( _wcsicmp( Usage, L"PRECONFIG" ) == 0 )
  1275. {
  1276. ProxyUsage = BG_JOB_PROXY_USAGE_PRECONFIG;
  1277. CheckBITSHR( L"Unable to set proxy settings", Job->SetProxySettings( ProxyUsage, NULL, NULL ) );
  1278. bcout << L"Proxy usage set to " << ProxyUsage << L".\n";
  1279. return;
  1280. }
  1281. else if ( _wcsicmp( Usage, L"NO_PROXY" ) == 0 )
  1282. {
  1283. ProxyUsage = BG_JOB_PROXY_USAGE_NO_PROXY;
  1284. CheckBITSHR( L"Unable to set proxy settings", Job->SetProxySettings( ProxyUsage, NULL, NULL ) );
  1285. bcout << L"Proxy usage set to " << ProxyUsage << L".\n";
  1286. return;
  1287. }
  1288. else if ( _wcsicmp( Usage, L"OVERRIDE" ) == 0 )
  1289. {
  1290. if (argc != 4)
  1291. {
  1292. bcout << L"OVERRIDE must be followed by a proxy list and a proxy bypass list\n";
  1293. throw AbortException(1);
  1294. }
  1295. ProxyUsage = BG_JOB_PROXY_USAGE_OVERRIDE;
  1296. }
  1297. else
  1298. {
  1299. bcout << L"proxy usage must be one of OVERRIDE, NO_PROXY, or PRECONFIG\n";
  1300. throw AbortException(0);
  1301. }
  1302. WCHAR * ProxyList = argv[2];
  1303. WCHAR * ProxyBypassList = argv[3];
  1304. if ( _wcsicmp( ProxyList, L"NULL" ) == 0 )
  1305. {
  1306. ProxyList = NULL;
  1307. }
  1308. if ( _wcsicmp( ProxyBypassList, L"NULL" ) == 0 )
  1309. {
  1310. ProxyBypassList = NULL;
  1311. }
  1312. CheckBITSHR( L"Unable to set proxy settings", Job->SetProxySettings( ProxyUsage, ProxyList, ProxyBypassList ) );
  1313. bcout << L"Proxy usage set to " << ProxyUsage << L".\n";
  1314. bcout << L"Proxy list set to " << ( ProxyList ? ProxyList : L"NULL" )<< L".\n";
  1315. bcout << L"Proxy bypass list set to " << ( ProxyBypassList ? ProxyBypassList : L"NULL" ) << L".\n";
  1316. }
  1317. void JobTakeOwnership( int argc, WCHAR **argv )
  1318. {
  1319. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1320. CheckBITSHR( L"Unable to take ownership", Job->TakeOwnership() );
  1321. bcout << L"Took ownership of " << Job << L".\n";
  1322. }
  1323. void PrintBanner()
  1324. {
  1325. const char ProductVer[] = VER_PRODUCTVERSION_STR;
  1326. // double for extra protection
  1327. wchar_t WProductVer[ sizeof(ProductVer) * 2];
  1328. memset( WProductVer, 0, sizeof(WProductVer) );
  1329. mbstowcs( WProductVer, ProductVer, sizeof(ProductVer) );
  1330. bcout <<
  1331. L"\n" <<
  1332. L"BITSADMIN version 1.5 [ " << WProductVer << L" ]\n" <<
  1333. L"BITS administration utility.\n" <<
  1334. L"(C) Copyright 2000-2002 Microsoft Corp.\n" <<
  1335. L"\n";
  1336. }
  1337. const wchar_t UsageLine[] = L"USAGE: BITSADMIN [/RAWRETURN] [/WRAP | /NOWRAP] command\n";
  1338. void JobHelp()
  1339. {
  1340. bcout << UsageLine;
  1341. bcout <<
  1342. L"The following commands are available:\n"
  1343. L"\n"
  1344. L"/HELP Prints this help \n"
  1345. L"/? Prints this help \n"
  1346. L"/LIST [/ALLUSERS] [/VERBOSE] List the jobs\n"
  1347. L"/MONITOR [/ALLUSERS] [/REFRESH sec] Monitors the copy manager\n"
  1348. L"/RESET Deletes all jobs in the manager\n"
  1349. L"/CREATE [type] display_name Creates a job\n"
  1350. L" [type] may be /DOWNLOAD, /UPLOAD, or /UPLOAD-REPLY; default is download\n"
  1351. L"\n"
  1352. L"/INFO job [/VERBOSE] Displays information about the job\n"
  1353. L"/ADDFILE job remote_url local_name Adds a file to the job\n"
  1354. L"/LISTFILES job Lists the files in the job\n"
  1355. L"/SUSPEND job Suspends the job\n"
  1356. L"/RESUME job Resumes the job\n"
  1357. L"/CANCEL job Cancels the job\n"
  1358. L"/COMPLETE job Completes the job\n"
  1359. L"\n"
  1360. L"/GETTYPE job Retrieves the job type\n"
  1361. L"/GETBYTESTOTAL job Retrieves the size of the job\n"
  1362. L"/GETBYTESTRANSFERRED job Retrieves the number of bytes transferred\n"
  1363. L"/GETFILESTOTAL job Retrieves the number of files in the job\n"
  1364. L"/GETFILESTRANSFERRED job Retrieves the number of files transferred\n"
  1365. L"/GETCREATIONTIME job Retrieves the job creation time\n"
  1366. L"/GETMODIFICATIONTIME job Retrieves the job modification time\n"
  1367. L"/GETCOMPLETIONTIME job Retrieves the job completion time\n"
  1368. L"/GETSTATE job Retrieves the job state\n"
  1369. L"/GETERROR job Retrieves detailed error information\n"
  1370. L"/GETOWNER job Retrieves the job owner\n"
  1371. L"/GETDISPLAYNAME job Retrieves the job display name\n"
  1372. L"/SETDISPLAYNAME job display_name Sets the job display name\n"
  1373. L"/GETDESCRIPTION job Retrieves the job description\n"
  1374. L"/SETDESCRIPTION job description Sets the job description\n"
  1375. L"/GETPRIORITY job Retrieves the job priority\n"
  1376. L"/SETPRIORITY job priority Sets the job priority\n"
  1377. L"/GETNOTIFYFLAGS job Retrieves the notify flags\n"
  1378. L"/SETNOTIFYFLAGS job notify_flags Sets the notify flags\n"
  1379. L"/GETNOTIFYINTERFACE job Determines if notify interface is registered\n"
  1380. L"/GETMINRETRYDELAY job Retrieves the retry delay in seconds\n"
  1381. L"/SETMINRETRYDELAY job retry_delay Sets the retry delay in seconds\n"
  1382. L"/GETNOPROGRESSTIMEOUT job Retrieves the no progress timeout in seconds\n"
  1383. L"/SETNOPROGRESSTIMEOUT job timeout Sets the no progress timeout in seconds\n"
  1384. L"/GETERRORCOUNT job Retrieves an error count for the job\n"
  1385. L"\n"
  1386. L"/SETPROXYSETTINGS job <usage> Sets the proxy usage\n"
  1387. L" usage choices:\n"
  1388. L" PRECONFIG - Use the owner's IE defaults.\n"
  1389. L" NO_PROXY - Do not use a proxy server.\n"
  1390. L" OVERRIDE - Use an explicit proxy list and bypass list. \n"
  1391. L" Must be followed by a proxy list and a proxy bypass list.\n"
  1392. L" NULL or \"\" may be used for an empty proxy bypass list.\n"
  1393. L" Examples:\n"
  1394. L" bitsadmin /setproxysettings MyJob PRECONFIG\n"
  1395. L" bitsadmin /setproxysettings MyJob NO_PROXY\n"
  1396. L" bitsadmin /setproxysettings MyJob OVERRIDE proxy1:80 \"<local>\" \n"
  1397. L" bitsadmin /setproxysettings MyJob OVERRIDE proxy1,proxy2,proxy3 NULL \n"
  1398. L"\n"
  1399. L"/GETPROXYUSAGE job Retrieves the proxy usage setting\n"
  1400. L"/GETPROXYLIST job Retrieves the proxy list\n"
  1401. L"/GETPROXYBYPASSLIST job Retrieves the proxy bypass list\n"
  1402. L"\n"
  1403. L"/TAKEOWNERSHIP job Take ownership of the job\n"
  1404. L"\n"
  1405. L"/SETNOTIFYCMDLINE job program_name [program_parameters] \n"
  1406. L" Sets a program to execute for notification, and optionally parameters.\n"
  1407. L" The program name and parameters can be NULL.\n"
  1408. L"\n"
  1409. L" Examples:\n"
  1410. L" bitsadmin /SetNotifyCmdLine MyJob c:\\winnt\\system32\\notepad.exe NULL\n"
  1411. L" bitsadmin /SetNotifyCmdLine MyJob c:\\handler.exe \"parm1 parm2 parm3\" \n"
  1412. L" bitsadmin /SetNotifyCmdLine MyJob NULL NULL\n"
  1413. L"\n"
  1414. L"/GETNOTIFYCMDLINE job returns the job's notification command line\n"
  1415. L"\n"
  1416. L"/SETCREDENTIALS job <target> <scheme> <username> <password>\n"
  1417. L" Adds credentials to a job.\n"
  1418. L" <target> may be either SERVER or PROXY\n"
  1419. L" <scheme> may be BASIC, DIGEST, NTLM, NEGOTIATE, or PASSPORT. \n"
  1420. L"\n"
  1421. L"/REMOVECREDENTIALS job <target> <scheme> \n"
  1422. L" Removes credentials from a job.\n"
  1423. L"\n"
  1424. L"The following options are valid for UPLOAD-REPLY jobs only:\n"
  1425. L"\n"
  1426. L"/GETREPLYFILENAME job Gets the path of the file containing the server reply\n"
  1427. L"/SETREPLYFILENAME job path Sets the path of the file containing the server reply\n"
  1428. L"/GETREPLYPROGRESS job Gets the size and progress of the server reply\n"
  1429. L"/GETREPLYDATA job Dumps the server's reply data in hex format\n"
  1430. L"\n"
  1431. L"The following options can be placed before the command:\n"
  1432. L"/RAWRETURN Return data more suitable for parsing\n"
  1433. L"/WRAP Wrap output around console (default)\n"
  1434. L"/NOWRAP Don't wrap output around console\n"
  1435. L"\n"
  1436. L"The /RAWRETURN option strips new line characters and formatting.\n"
  1437. L"It is recognized by the /CREATE and /GET* commands.\n"
  1438. L"\n"
  1439. L"Commands that take a job parameter will accept either a job name or a job-ID\n"
  1440. L"GUID inside braces. BITSADMIN reports an error if a name is ambiguous.\n";
  1441. }
  1442. void JobHelpAdapter( int, WCHAR ** )
  1443. {
  1444. JobHelp();
  1445. }
  1446. void JobNotImplemented( int, WCHAR ** )
  1447. {
  1448. bcout << L"Not implemented.\n";
  1449. throw AbortException(1);
  1450. }
  1451. const PARSEENTRY JobParseTableEntries[] =
  1452. {
  1453. {L"/HELP", JobHelpAdapter },
  1454. {L"/?", JobHelpAdapter },
  1455. {L"/LIST", JobList },
  1456. {L"/MONITOR", JobMonitor },
  1457. {L"/RESET", JobReset },
  1458. {L"/CREATE", JobCreate },
  1459. {L"/INFO", JobInfo },
  1460. {L"/ADDFILE", JobAddFile },
  1461. {L"/LISTFILES", JobListFiles },
  1462. {L"/SUSPEND", JobSuspend },
  1463. {L"/RESUME", JobResume },
  1464. {L"/CANCEL", JobCancel },
  1465. {L"/COMPLETE", JobComplete },
  1466. {L"/GETTYPE", JobGetType },
  1467. {L"/GETBYTESTOTAL", JobGetBytesTotal },
  1468. {L"/GETBYTESTRANSFERRED", JobGetBytesTransferred },
  1469. {L"/GETFILESTOTAL", JobGetFilesTotal },
  1470. {L"/GETFILESTRANSFERRED", JobGetFilesTransferred },
  1471. {L"/GETCREATIONTIME", JobGetCreationTime },
  1472. {L"/GETMODIFICATIONTIME", JobGetModificationTime },
  1473. {L"/GETCOMPLETIONTIME", JobGetCompletionTime },
  1474. {L"/GETSTATE", JobGetState },
  1475. {L"/GETERROR", JobGetError },
  1476. {L"/GETOWNER", JobGetOwner },
  1477. {L"/GETDISPLAYNAME", JobGetDisplayName },
  1478. {L"/SETDISPLAYNAME", JobSetDisplayName },
  1479. {L"/GETDESCRIPTION", JobGetDescription },
  1480. {L"/SETDESCRIPTION", JobSetDescription },
  1481. {L"/GETPRIORITY", JobGetPriority },
  1482. {L"/SETPRIORITY", JobSetPriority },
  1483. {L"/GETNOTIFYFLAGS", JobGetNotifyFlags },
  1484. {L"/SETNOTIFYFLAGS", JobSetNotifyFlags },
  1485. {L"/GETNOTIFYINTERFACE", JobGetNotifyInterface },
  1486. {L"/GETMINRETRYDELAY", JobGetMinimumRetryDelay },
  1487. {L"/SETMINRETRYDELAY", JobSetMinimumRetryDelay },
  1488. {L"/GETNOPROGRESSTIMEOUT", JobGetNoProgressTimeout },
  1489. {L"/SETNOPROGRESSTIMEOUT", JobSetNoProgressTimeout },
  1490. {L"/GETERRORCOUNT", JobGetErrorCount },
  1491. {L"/GETPROXYUSAGE", JobGetProxyUsage },
  1492. {L"/GETPROXYLIST", JobGetProxyList },
  1493. {L"/GETPROXYBYPASSLIST", JobGetProxyBypassList },
  1494. {L"/SETPROXYSETTINGS", JobSetProxySettings },
  1495. {L"/TAKEOWNERSHIP", JobTakeOwnership },
  1496. {L"/GETREPLYFILENAME", JobGetReplyFileName },
  1497. {L"/SETREPLYFILENAME", JobSetReplyFileName },
  1498. {L"/GETREPLYPROGRESS", JobGetReplyProgress },
  1499. {L"/GETREPLYDATA", JobGetReplyData },
  1500. {L"/GETNOTIFYCMDLINE", JobGetNotifyCmdLine },
  1501. {L"/SETNOTIFYCMDLINE", JobSetNotifyCmdLine },
  1502. {L"/SETCREDENTIALS", JobSetCredentials },
  1503. {L"/REMOVECREDENTIALS", JobRemoveCredentials },
  1504. {NULL, NULL }
  1505. };
  1506. const PARSETABLE JobParseTable =
  1507. {
  1508. JobParseTableEntries,
  1509. JobHelpAdapter,
  1510. NULL
  1511. };
  1512. void ParseCmdAdapter( int argc, WCHAR **argv, void *pContext )
  1513. {
  1514. ParseCmd( argc, argv, (const PARSETABLE *) pContext );
  1515. }
  1516. BOOL ControlHandler( DWORD Event )
  1517. {
  1518. switch( Event )
  1519. {
  1520. case CTRL_C_EVENT:
  1521. case CTRL_CLOSE_EVENT:
  1522. SignalShutdown( 5000 );
  1523. return TRUE;
  1524. case CTRL_BREAK_EVENT:
  1525. SignalShutdown( 500 );
  1526. return TRUE;
  1527. default:
  1528. return FALSE;
  1529. }
  1530. }
  1531. int _cdecl wmain(int argc, WCHAR **argv )
  1532. {
  1533. //
  1534. // Wrap long lines by default. /NOWRAP overrides this.
  1535. //
  1536. bWrap = true;
  1537. try
  1538. {
  1539. DuplicateHandle(
  1540. GetCurrentProcess(), // handle to source process
  1541. GetCurrentThread(), // handle to duplicate
  1542. GetCurrentProcess(), // handle to target process
  1543. &g_MainThreadHandle, // duplicate handle
  1544. 0, // requested access
  1545. TRUE, // handle inheritance option
  1546. DUPLICATE_SAME_ACCESS // optional actions
  1547. );
  1548. SetConsoleCtrlHandler( ControlHandler, TRUE );
  1549. BITSADMINSetThreadUILanguage();
  1550. _wsetlocale (LC_COLLATE, L".OCP" ); // sets the sort order
  1551. _wsetlocale (LC_MONETARY, L".OCP" ); // sets the currency formatting rules
  1552. _wsetlocale (LC_NUMERIC, L".OCP" ); // sets the formatting of numerals
  1553. _wsetlocale (LC_TIME, L".OCP" ); // defines the date/time formatting
  1554. // skip command name
  1555. argc--;
  1556. argv++;
  1557. if ( 0 == argc )
  1558. {
  1559. PrintBanner();
  1560. bcout << UsageLine;
  1561. return 0;
  1562. }
  1563. // parse /RAWRETURN
  1564. if ( argc >= 1 && ( _wcsicmp( argv[0], L"/RAWRETURN" ) == 0 ))
  1565. {
  1566. bRawReturn = true;
  1567. // skip /RAWRETURN
  1568. argc--;
  1569. argv++;
  1570. }
  1571. // parse /WRAP
  1572. if ( argc >= 1 && ( _wcsicmp( argv[0], L"/WRAP" ) == 0 ))
  1573. {
  1574. bWrap = true;
  1575. bExplicitWrap = true;
  1576. // skip /WRAP
  1577. argc--;
  1578. argv++;
  1579. }
  1580. // parse /NOWRAP
  1581. if ( argc >= 1 && ( _wcsicmp( argv[0], L"/NOWRAP" ) == 0 ))
  1582. {
  1583. bWrap = false;
  1584. bExplicitWrap = true;
  1585. // skip /NOWRAP
  1586. argc--;
  1587. argv++;
  1588. }
  1589. if ( !bRawReturn )
  1590. PrintBanner();
  1591. #ifdef DBG
  1592. // parse /COMPUTERNAME
  1593. if ( argc >= 1 && ( _wcsicmp( argv[0], L"/COMPUTERNAME" ) == 0 ))
  1594. {
  1595. argc--;
  1596. argv++;
  1597. if (argc < 1)
  1598. {
  1599. bcout << L"/COMPUTERNAME option is missing the computer name.\n";
  1600. throw AbortException(1);
  1601. }
  1602. pComputerName = argv[0];
  1603. argc--;
  1604. argv++;
  1605. }
  1606. #endif
  1607. CheckHR( L"Unable to initialize COM", CoInitializeEx(NULL, COINIT_MULTITHREADED ) );
  1608. SetupConsole();
  1609. ParseCmd( argc, argv, &JobParseTable );
  1610. g_Manager.Clear();
  1611. CoUninitialize();
  1612. bcout.FlushBuffer();
  1613. RestoreConsole();
  1614. if ( g_MainThreadHandle )
  1615. CloseHandle( g_MainThreadHandle );
  1616. }
  1617. catch( AbortException & Exception )
  1618. {
  1619. bcout.FlushBuffer();
  1620. RestoreConsole();
  1621. exit( Exception.Code );
  1622. }
  1623. return 0;
  1624. }