Source code of Windows XP (NT5)
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.

2926 lines
81 KiB

  1. /************************************************************************
  2. Copyright (c) 2000-2000 Microsoft Corporation
  3. Module Name :
  4. client.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. #define MAKE_UNICODE(x) L ## x
  19. #include <windows.h>
  20. #include <sddl.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <malloc.h>
  24. #include <bits.h>
  25. #include <bits1_5.h>
  26. #include <ntverp.h>
  27. #include <locale.h>
  28. #include <strsafe.h>
  29. #include <memory>
  30. using namespace std;
  31. typedef auto_ptr<WCHAR> CAutoString;
  32. const UINT MAX_GUID_CHARS=40;
  33. typedef OLECHAR GUIDSTR[MAX_GUID_CHARS];
  34. void __declspec(noreturn) AppExit( int val );
  35. bool g_Shutdown = false;
  36. HANDLE g_MainThreadHandle = NULL;
  37. void PollShutdown();
  38. void SignalShutdown( DWORD MilliTimeout );
  39. template<class T> class SmartRefPointer
  40. {
  41. private:
  42. T * m_Interface;
  43. void ReleaseIt()
  44. {
  45. if ( m_Interface )
  46. m_Interface->Release();
  47. m_Interface = NULL;
  48. }
  49. void RefIt()
  50. {
  51. if ( m_Interface )
  52. m_Interface->AddRef();
  53. }
  54. public:
  55. SmartRefPointer()
  56. {
  57. m_Interface = NULL;
  58. }
  59. SmartRefPointer( T * RawInterface )
  60. {
  61. m_Interface = RawInterface;
  62. RefIt();
  63. }
  64. SmartRefPointer( SmartRefPointer & Other )
  65. {
  66. m_Interface = Other.m_Interface;
  67. RefIt();
  68. }
  69. ~SmartRefPointer()
  70. {
  71. ReleaseIt();
  72. }
  73. T * Get() const
  74. {
  75. return m_Interface;
  76. }
  77. T * Release()
  78. {
  79. T * temp = m_Interface;
  80. m_Interface = NULL;
  81. return temp;
  82. }
  83. void Clear()
  84. {
  85. ReleaseIt();
  86. }
  87. T** GetRecvPointer()
  88. {
  89. ReleaseIt();
  90. return &m_Interface;
  91. }
  92. SmartRefPointer & operator=( SmartRefPointer & Other )
  93. {
  94. ReleaseIt();
  95. m_Interface = Other.m_Interface;
  96. RefIt();
  97. return *this;
  98. }
  99. T* operator->() const
  100. {
  101. return m_Interface;
  102. }
  103. operator const T*() const
  104. {
  105. return m_Interface;
  106. }
  107. };
  108. typedef SmartRefPointer<IUnknown> SmartIUnknownPointer;
  109. typedef SmartRefPointer<IBackgroundCopyManager> SmartManagerPointer;
  110. typedef SmartRefPointer<IBackgroundCopyJob> SmartJobPointer;
  111. typedef SmartRefPointer<IBackgroundCopyJob2> SmartJob2Pointer;
  112. typedef SmartRefPointer<IBackgroundCopyError> SmartJobErrorPointer;
  113. typedef SmartRefPointer<IBackgroundCopyFile> SmartFilePointer;
  114. typedef SmartRefPointer<IEnumBackgroundCopyFiles> SmartEnumFilesPointer;
  115. typedef SmartRefPointer<IEnumBackgroundCopyJobs> SmartEnumJobsPointer;
  116. class AutoStringPointer
  117. {
  118. private:
  119. WCHAR * m_String;
  120. public:
  121. AutoStringPointer( WCHAR *pString = NULL )
  122. {
  123. m_String = pString;
  124. }
  125. ~AutoStringPointer()
  126. {
  127. delete m_String;
  128. m_String = NULL;
  129. }
  130. WCHAR *Get()
  131. {
  132. return m_String;
  133. }
  134. WCHAR ** GetRecvPointer()
  135. {
  136. delete m_String;
  137. m_String = NULL;
  138. return &m_String;
  139. }
  140. void Clear()
  141. {
  142. delete m_String;
  143. m_String = NULL;
  144. }
  145. operator WCHAR *() const
  146. {
  147. return m_String;
  148. }
  149. AutoStringPointer & operator=( WCHAR *pString )
  150. {
  151. delete m_String;
  152. m_String = pString;
  153. return *this;
  154. }
  155. };
  156. WCHAR* pComputerName;
  157. SmartManagerPointer g_Manager;
  158. bool bRawReturn = false;
  159. bool bWrap = false;
  160. typedef void (* PSET_THREAD_UI)( DWORD );
  161. void BITSADMINSetThreadUILanguage()
  162. {
  163. HINSTANCE hInstance = LoadLibrary( L"kernel32.dll" ); // SEC-REVIEWED: 2002-03-21
  164. if ( !hInstance )
  165. return;
  166. PSET_THREAD_UI SetUI = (PSET_THREAD_UI)GetProcAddress( hInstance, "SetThreadUILanguage" );
  167. if ( !SetUI )
  168. {
  169. FreeLibrary( hInstance );
  170. return;
  171. }
  172. (*SetUI)(0);
  173. FreeLibrary( hInstance );
  174. return;
  175. }
  176. HRESULT
  177. Job2FromJob(
  178. SmartJobPointer & Job,
  179. SmartJob2Pointer & Job2
  180. )
  181. {
  182. return Job->QueryInterface( __uuidof(IBackgroundCopyJob2), (void **) Job2.GetRecvPointer() );
  183. }
  184. //
  185. // Generic print operators and input functions
  186. //
  187. class BITSOUTStream
  188. {
  189. HANDLE Handle;
  190. char MBBuffer[ 4096 * 8 ];
  191. WCHAR Buffer[ 4096 ];
  192. DWORD BufferUsed;
  193. public:
  194. BITSOUTStream( DWORD StdHandle );
  195. void FlushBuffer( bool HasNewLine=false );
  196. void OutputString( const WCHAR *RawString );
  197. HANDLE GetHandle() { return Handle; }
  198. };
  199. BITSOUTStream bcout( STD_OUTPUT_HANDLE );
  200. BITSOUTStream bcerr( STD_ERROR_HANDLE );
  201. BITSOUTStream::BITSOUTStream( DWORD StdHandle ) :
  202. BufferUsed( 0 ),
  203. Handle( GetStdHandle( StdHandle ) )
  204. {
  205. }
  206. void
  207. BITSOUTStream::OutputString( const WCHAR *RawString )
  208. {
  209. SIZE_T CurrentPos = 0;
  210. PollShutdown();
  211. while( RawString[ CurrentPos ] != '\0' )
  212. {
  213. if ( L'\n' == RawString[ CurrentPos ] )
  214. {
  215. Buffer[ BufferUsed++ ] = L'\x000D';
  216. Buffer[ BufferUsed++ ] = L'\x000A';
  217. CurrentPos++;
  218. FlushBuffer( true );
  219. }
  220. else if ( L'\t' == RawString[ CurrentPos ] )
  221. {
  222. // Tabs complicate things, flush them
  223. FlushBuffer();
  224. Buffer[ BufferUsed++ ] = RawString[ CurrentPos++ ];
  225. FlushBuffer();
  226. }
  227. else
  228. {
  229. Buffer[ BufferUsed++ ] = RawString[ CurrentPos++ ];
  230. if ( BufferUsed >= ( 4096 - 10 ) ) // keep a pad of 10 chars
  231. FlushBuffer();
  232. }
  233. }
  234. }
  235. void
  236. BITSOUTStream::FlushBuffer( bool HasNewLine )
  237. {
  238. if (!BufferUsed)
  239. return;
  240. if( GetFileType(Handle) == FILE_TYPE_CHAR )
  241. {
  242. DWORD CharsWritten;
  243. if ( bWrap )
  244. WriteConsoleW( Handle, Buffer, BufferUsed, &CharsWritten, 0);
  245. else
  246. {
  247. // The console code has what appears to be a bug in that it doesn't
  248. // handle the case were line wrapping is disabled and WriteConsoleW
  249. // is called. Need to manually handle the truncation.
  250. CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo;
  251. GetConsoleScreenBufferInfo( Handle, &ConsoleScreenBufferInfo );
  252. SHORT Columns = ( ConsoleScreenBufferInfo.dwSize.X - 1 ) -
  253. ( ConsoleScreenBufferInfo.dwCursorPosition.X );
  254. DWORD ActualChars = HasNewLine ? ( BufferUsed - 2 ) : BufferUsed;
  255. if ( Columns >= (INT32)ActualChars )
  256. WriteConsoleW( Handle, Buffer, BufferUsed, &CharsWritten, 0 );
  257. else
  258. {
  259. WriteConsoleW( Handle, Buffer, Columns, &CharsWritten, 0 );
  260. if ( HasNewLine )
  261. WriteConsoleW( Handle, Buffer + ActualChars, 2, &CharsWritten, 0 );
  262. }
  263. }
  264. }
  265. else
  266. {
  267. DWORD BytesWritten;
  268. int CharCount = WideCharToMultiByte( GetConsoleOutputCP(), 0, Buffer, BufferUsed, MBBuffer, sizeof(MBBuffer), 0, 0); // SEC-REVIEWED: 2002-03-21
  269. if ( CharCount )
  270. {
  271. if ( MBBuffer[CharCount-1] == '\0' )
  272. CharCount--;
  273. WriteFile(Handle, MBBuffer, CharCount, &BytesWritten, 0); // SEC-REVIEWED: 2002-03-21
  274. }
  275. }
  276. BufferUsed = 0;
  277. }
  278. BITSOUTStream& operator<< (BITSOUTStream &s, const WCHAR * String )
  279. {
  280. s.OutputString( String );
  281. return s;
  282. }
  283. BITSOUTStream& operator<< (BITSOUTStream &s, UINT64 Number )
  284. {
  285. static WCHAR Buffer[256];
  286. StringCbPrintf( Buffer, sizeof(Buffer), L"%I64u", Number );
  287. return ( s << Buffer );
  288. }
  289. WCHAR * HRESULTToString( HRESULT Hr )
  290. {
  291. static WCHAR ErrorCode[12];
  292. StringCbPrintf( ErrorCode, sizeof(ErrorCode), L"0x%8.8x", Hr );
  293. return ErrorCode;
  294. }
  295. BITSOUTStream& operator<< ( BITSOUTStream &s, AutoStringPointer & String )
  296. {
  297. return ( s << String.Get() );
  298. }
  299. BITSOUTStream& operator<< ( BITSOUTStream &s, GUID & guid )
  300. {
  301. WCHAR GUIDSTR[40];
  302. if (!StringFromGUID2( guid, GUIDSTR, 40 ))
  303. {
  304. bcout << L"Internal error converting guid to string.\n";
  305. AppExit(1);
  306. }
  307. return ( s << GUIDSTR );
  308. }
  309. BITSOUTStream& operator<< ( BITSOUTStream &s, FILETIME & filetime )
  310. {
  311. // Convert the time and date into a localized string.
  312. // If an error occures, ignore it and print ERROR instead
  313. if ( !filetime.dwLowDateTime && !filetime.dwHighDateTime )
  314. return ( s << L"UNKNOWN" );
  315. FILETIME localtime;
  316. FileTimeToLocalFileTime( &filetime, &localtime );
  317. SYSTEMTIME systemtime;
  318. FileTimeToSystemTime( &localtime, &systemtime );
  319. // Get the required date size
  320. int RequiredDateSize =
  321. GetDateFormatW(
  322. LOCALE_USER_DEFAULT,
  323. 0,
  324. &systemtime,
  325. NULL,
  326. NULL,
  327. 0 );
  328. if (!RequiredDateSize)
  329. return ( s << L"ERROR" );
  330. CAutoString DateBuffer( new WCHAR[ RequiredDateSize + 1 ]);
  331. // Actually retrieve the date
  332. int DateSize =
  333. GetDateFormatW( LOCALE_USER_DEFAULT,
  334. 0,
  335. &systemtime,
  336. NULL,
  337. DateBuffer.get(),
  338. RequiredDateSize );
  339. if (!DateSize)
  340. return ( s << L"ERROR" );
  341. // Get the required time size
  342. int RequiredTimeSize =
  343. GetTimeFormatW( LOCALE_USER_DEFAULT,
  344. 0,
  345. &systemtime,
  346. NULL,
  347. NULL,
  348. 0 );
  349. if (!RequiredTimeSize)
  350. return ( s << L"ERROR" );
  351. CAutoString TimeBuffer( new WCHAR[ RequiredTimeSize + 1 ]);
  352. int TimeSize =
  353. GetTimeFormatW( LOCALE_USER_DEFAULT,
  354. 0,
  355. &systemtime,
  356. NULL,
  357. TimeBuffer.get(),
  358. RequiredTimeSize );
  359. if (!TimeSize)
  360. return ( s << L"ERROR" );
  361. return ( s << DateBuffer.get() << L" " << TimeBuffer.get() );
  362. }
  363. BITSOUTStream& operator<< ( BITSOUTStream &s, BG_JOB_PROXY_USAGE ProxyUsage )
  364. {
  365. switch( ProxyUsage )
  366. {
  367. case BG_JOB_PROXY_USAGE_PRECONFIG:
  368. return (s << L"PRECONFIG");
  369. case BG_JOB_PROXY_USAGE_NO_PROXY:
  370. return (s << L"NO_PROXY");
  371. case BG_JOB_PROXY_USAGE_OVERRIDE:
  372. return (s << L"OVERRIDE");
  373. default:
  374. return (s << L"UNKNOWN");
  375. }
  376. }
  377. ULONG InputULONG( WCHAR *pText )
  378. {
  379. ULONG number;
  380. if ( 1 != swscanf( pText, L"%u", &number ) )
  381. {
  382. bcout << L"Invalid number.\n";
  383. AppExit(1);
  384. }
  385. return number;
  386. }
  387. class PrintSidString
  388. {
  389. public:
  390. WCHAR *m_SidString;
  391. PrintSidString( WCHAR * SidString ) :
  392. m_SidString( SidString )
  393. {
  394. }
  395. };
  396. BOOL
  397. LocalConvertStringSidToSid (
  398. IN PWSTR StringSid,
  399. OUT PSID *Sid,
  400. OUT PWSTR *End
  401. )
  402. /*++
  403. Routine Description:
  404. This routine will convert a string representation of a SID back into
  405. a sid. The expected format of the string is:
  406. "S-1-5-32-549"
  407. If a string in a different format or an incorrect or incomplete string
  408. is given, the operation is failed.
  409. The returned sid must be free via a call to LocalFree
  410. Arguments:
  411. StringSid - The string to be converted
  412. Sid - Where the created SID is to be returned
  413. End - Where in the string we stopped processing
  414. Return Value:
  415. TRUE - Success.
  416. FALSE - Failure. Additional information returned from GetLastError(). Errors set are:
  417. ERROR_SUCCESS indicates success
  418. ERROR_NOT_ENOUGH_MEMORY indicates a memory allocation for the ouput sid
  419. failed
  420. ERROR_INVALID_SID indicates that the given string did not represent a sid
  421. --*/
  422. {
  423. DWORD Err = ERROR_SUCCESS;
  424. UCHAR Revision, Subs;
  425. SID_IDENTIFIER_AUTHORITY IDAuth;
  426. PULONG SubAuth = NULL;
  427. PWSTR CurrEnd, Curr, Next;
  428. WCHAR Stub, *StubPtr = NULL;
  429. ULONG Index;
  430. INT gBase=10;
  431. INT lBase=10;
  432. ULONG Auto;
  433. if ( NULL == StringSid || NULL == Sid || NULL == End ) {
  434. SetLastError( ERROR_INVALID_PARAMETER );
  435. return( FALSE );
  436. }
  437. // if ( wcslen( StringSid ) < 2 || ( *StringSid != L'S' && *( StringSid + 1 ) != L'-' ) ) {
  438. //
  439. // no need to check length because StringSid is NULL
  440. // and if the first char is NULL, it won't access the second char
  441. //
  442. if ( (*StringSid != L'S' && *StringSid != L's') ||
  443. *( StringSid + 1 ) != L'-' ) {
  444. //
  445. // string sid should always start with S-
  446. //
  447. SetLastError( ERROR_INVALID_SID );
  448. return( FALSE );
  449. }
  450. Curr = StringSid + 2;
  451. if ( (*Curr == L'0') &&
  452. ( *(Curr+1) == L'x' ||
  453. *(Curr+1) == L'X' ) ) {
  454. gBase = 16;
  455. }
  456. Revision = ( UCHAR )wcstol( Curr, &CurrEnd, gBase );
  457. if ( CurrEnd == Curr || *CurrEnd != L'-' || *(CurrEnd+1) == L'\0' ) {
  458. //
  459. // no revision is provided, or invalid delimeter
  460. //
  461. SetLastError( ERROR_INVALID_SID );
  462. return( FALSE );
  463. }
  464. Curr = CurrEnd + 1;
  465. //
  466. // Count the number of characters in the indentifer authority...
  467. //
  468. Next = wcschr( Curr, L'-' );
  469. /*
  470. Length = 6 doesn't mean each digit is a id authority value, could be 0x...
  471. if ( Next != NULL && (Next - Curr == 6) ) {
  472. for ( Index = 0; Index < 6; Index++ ) {
  473. // IDAuth.Value[Index] = (UCHAR)Next[Index]; what is this ???
  474. IDAuth.Value[Index] = (BYTE) (Curr[Index]-L'0');
  475. }
  476. Curr +=6;
  477. } else {
  478. */
  479. if ( (*Curr == L'0') &&
  480. ( *(Curr+1) == L'x' ||
  481. *(Curr+1) == L'X' ) ) {
  482. lBase = 16;
  483. } else {
  484. lBase = gBase;
  485. }
  486. Auto = wcstoul( Curr, &CurrEnd, lBase );
  487. if ( CurrEnd == Curr || *CurrEnd != L'-' || *(CurrEnd+1) == L'\0' ) {
  488. //
  489. // no revision is provided, or invalid delimeter
  490. //
  491. SetLastError( ERROR_INVALID_SID );
  492. return( FALSE );
  493. }
  494. IDAuth.Value[0] = IDAuth.Value[1] = 0;
  495. IDAuth.Value[5] = ( UCHAR )Auto & 0xFF;
  496. IDAuth.Value[4] = ( UCHAR )(( Auto >> 8 ) & 0xFF );
  497. IDAuth.Value[3] = ( UCHAR )(( Auto >> 16 ) & 0xFF );
  498. IDAuth.Value[2] = ( UCHAR )(( Auto >> 24 ) & 0xFF );
  499. Curr = CurrEnd;
  500. // }
  501. //
  502. // Now, count the number of sub auths, at least one sub auth is required
  503. //
  504. Subs = 0;
  505. Next = Curr;
  506. //
  507. // We'll have to count our sub authoritys one character at a time,
  508. // since there are several deliminators that we can have...
  509. //
  510. while ( Next ) {
  511. if ( *Next == L'-' && *(Next-1) != L'-') {
  512. //
  513. // do not allow two continuous '-'s
  514. // We've found one!
  515. //
  516. Subs++;
  517. if ( (*(Next+1) == L'0') &&
  518. ( *(Next+2) == L'x' ||
  519. *(Next+2) == L'X' ) ) {
  520. //
  521. // this is hex indicator
  522. //
  523. Next += 2;
  524. }
  525. } else if ( *Next == SDDL_SEPERATORC || *Next == L'\0' ||
  526. *Next == SDDL_ACE_ENDC || *Next == L' ' ||
  527. ( *(Next+1) == SDDL_DELIMINATORC &&
  528. (*Next == L'G' || *Next == L'O' || *Next == L'S')) ) {
  529. //
  530. // space is a terminator too
  531. //
  532. if ( *( Next - 1 ) == L'-' ) {
  533. //
  534. // shouldn't allow a SID terminated with '-'
  535. //
  536. Err = ERROR_INVALID_SID;
  537. Next--;
  538. } else {
  539. Subs++;
  540. }
  541. *End = Next;
  542. break;
  543. } else if ( !iswxdigit( *Next ) ) {
  544. Err = ERROR_INVALID_SID;
  545. *End = Next;
  546. // Subs++;
  547. break;
  548. } else {
  549. //
  550. // Note: SID is also used as a owner or group
  551. //
  552. // Some of the tags (namely 'D' for Dacl) fall under the category of iswxdigit, so
  553. // if the current character is a character we care about and the next one is a
  554. // delminiator, we'll quit
  555. //
  556. if ( *Next == L'D' && *( Next + 1 ) == SDDL_DELIMINATORC ) {
  557. //
  558. // We'll also need to temporarily truncate the string to this length so
  559. // we don't accidentally include the character in one of the conversions
  560. //
  561. Stub = *Next;
  562. StubPtr = Next;
  563. *StubPtr = UNICODE_NULL;
  564. *End = Next;
  565. Subs++;
  566. break;
  567. }
  568. }
  569. Next++;
  570. }
  571. if ( Err == ERROR_SUCCESS ) {
  572. if ( Subs != 0 ) Subs--;
  573. if ( Subs != 0 ) {
  574. Curr++;
  575. SubAuth = ( PULONG )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, Subs * sizeof( ULONG ) );
  576. if ( SubAuth == NULL ) {
  577. Err = ERROR_NOT_ENOUGH_MEMORY;
  578. } else {
  579. for ( Index = 0; Index < Subs; Index++ ) {
  580. if ( (*Curr == L'0') &&
  581. ( *(Curr+1) == L'x' ||
  582. *(Curr+1) == L'X' ) ) {
  583. lBase = 16;
  584. } else {
  585. lBase = gBase;
  586. }
  587. SubAuth[Index] = wcstoul( Curr, &CurrEnd, lBase );
  588. Curr = CurrEnd + 1;
  589. }
  590. }
  591. } else {
  592. Err = ERROR_INVALID_SID;
  593. }
  594. }
  595. //
  596. // Now, create the SID
  597. //
  598. if ( Err == ERROR_SUCCESS ) {
  599. *Sid = ( PSID )LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
  600. sizeof( SID ) + Subs * sizeof( ULONG ) );
  601. if ( *Sid == NULL ) {
  602. Err = ERROR_NOT_ENOUGH_MEMORY;
  603. } else {
  604. PISID ISid = ( PISID )*Sid;
  605. ISid->Revision = Revision;
  606. ISid->SubAuthorityCount = Subs;
  607. ISid->IdentifierAuthority = IDAuth;
  608. RtlCopyMemory( ISid->SubAuthority, SubAuth, Subs * sizeof( ULONG ) ); // SEC-REVIEWED: 2002-03-21
  609. }
  610. }
  611. LocalFree( SubAuth );
  612. //
  613. // Restore any character we may have stubbed out
  614. //
  615. if ( StubPtr ) {
  616. *StubPtr = Stub;
  617. }
  618. SetLastError( Err );
  619. return( Err == ERROR_SUCCESS );
  620. }
  621. BOOL
  622. AltConvertStringSidToSid(
  623. IN LPCWSTR StringSid,
  624. OUT PSID *Sid
  625. )
  626. /*++
  627. Routine Description:
  628. This routine converts a stringized SID into a valid, functional SID
  629. Arguments:
  630. StringSid - SID to be converted.
  631. Sid - Where the converted SID is returned. Buffer is allocated via LocalAlloc and should
  632. be free via LocalFree.
  633. Return Value:
  634. TRUE - Success
  635. FALSE - Failure
  636. Extended error status is available using GetLastError.
  637. ERROR_INVALID_PARAMETER - A NULL name was given
  638. ERROR_INVALID_SID - The format of the given sid was incorrect
  639. --*/
  640. {
  641. PWSTR End = NULL;
  642. BOOL ReturnValue = FALSE;
  643. PSID pSASid=NULL;
  644. ULONG Len=0;
  645. DWORD SaveCode=0;
  646. DWORD Err=0;
  647. if ( StringSid == NULL || Sid == NULL )
  648. {
  649. SetLastError( ERROR_INVALID_PARAMETER );
  650. return ReturnValue;
  651. }
  652. ReturnValue = LocalConvertStringSidToSid( ( PWSTR )StringSid, Sid, &End );
  653. if ( !ReturnValue )
  654. {
  655. SetLastError( ERROR_INVALID_PARAMETER );
  656. return ReturnValue;
  657. }
  658. if ( ( ULONG )( End - StringSid ) != wcslen( StringSid ) ) {
  659. SetLastError( ERROR_INVALID_SID );
  660. LocalFree( *Sid );
  661. *Sid = FALSE;
  662. ReturnValue = FALSE;
  663. } else {
  664. SetLastError(ERROR_SUCCESS);
  665. }
  666. return ReturnValue;
  667. }
  668. BITSOUTStream& operator<< ( BITSOUTStream &s, PrintSidString SidString )
  669. {
  670. // Convert the SID string into the user name
  671. // in domain\account format.
  672. // If an error occures, just return the SID string
  673. PSID pSid = NULL;
  674. BOOL bResult =
  675. AltConvertStringSidToSid(
  676. SidString.m_SidString,
  677. &pSid );
  678. if ( !bResult )
  679. {
  680. return ( s << SidString.m_SidString );
  681. }
  682. SID_NAME_USE NameUse;
  683. DWORD dwNameSize = 0;
  684. DWORD dwDomainSize = 0;
  685. bResult = LookupAccountSid(
  686. NULL,
  687. pSid,
  688. NULL,
  689. &dwNameSize,
  690. NULL,
  691. &dwDomainSize,
  692. &NameUse);
  693. if ( bResult ||
  694. ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) )
  695. {
  696. LocalFree( pSid );
  697. return ( s << SidString.m_SidString );
  698. }
  699. CAutoString pName( new WCHAR[ dwNameSize ] );
  700. CAutoString pDomain( new WCHAR[ dwDomainSize ] );
  701. bResult = LookupAccountSid(
  702. NULL,
  703. pSid,
  704. pName.get(),
  705. &dwNameSize,
  706. pDomain.get(),
  707. &dwDomainSize,
  708. &NameUse);
  709. if (!bResult)
  710. {
  711. LocalFree( pSid );
  712. return ( s << SidString.m_SidString );
  713. }
  714. LocalFree( pSid );
  715. return ( s << pDomain.get() << L"\\" << pName.get() );
  716. }
  717. void * _cdecl operator new( size_t Size )
  718. {
  719. void *Memory = CoTaskMemAlloc( Size );
  720. if ( !Memory )
  721. {
  722. bcout << L"Out of memory while allocating " << Size << L" bytes.\n";
  723. AppExit( (int)E_OUTOFMEMORY );
  724. }
  725. return Memory;
  726. }
  727. void _cdecl operator delete( void *Mem )
  728. {
  729. CoTaskMemFree( Mem );
  730. }
  731. void RestoreConsole();
  732. void __declspec(noreturn) AppExit( int val )
  733. {
  734. bcout.FlushBuffer();
  735. RestoreConsole();
  736. exit( val );
  737. }
  738. void PollShutdown()
  739. {
  740. if ( g_Shutdown )
  741. AppExit( (DWORD)CONTROL_C_EXIT );
  742. }
  743. void ShutdownAPC( ULONG_PTR )
  744. {
  745. return;
  746. }
  747. void SignalShutdown( DWORD MilliTimeout )
  748. {
  749. g_Shutdown = true;
  750. // Queue a shutdown APC
  751. if ( g_MainThreadHandle )
  752. {
  753. QueueUserAPC( ShutdownAPC, g_MainThreadHandle, NULL );
  754. }
  755. Sleep( MilliTimeout );
  756. RestoreConsole();
  757. TerminateProcess( GetCurrentProcess(), (DWORD)CONTROL_C_EXIT );
  758. }
  759. void CheckHR( const WCHAR *pFailTxt, HRESULT Hr )
  760. {
  761. // Check error code for success, and exit
  762. // with a failure message if unsuccessfull.
  763. if ( !SUCCEEDED(Hr) ) {
  764. WCHAR ErrorCode[12];
  765. StringCbPrintf( ErrorCode, sizeof(ErrorCode), L"0x%8.8x", Hr );
  766. bcout << pFailTxt << L" - " << ErrorCode << L"\n";
  767. WCHAR *pMessage = NULL;
  768. if ( FormatMessage(
  769. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  770. NULL,
  771. (DWORD)Hr,
  772. GetThreadLocale(),
  773. (WCHAR*)&pMessage,
  774. 0,
  775. NULL ) )
  776. {
  777. bcout << pMessage << L"\n";
  778. LocalFree( pMessage );
  779. }
  780. AppExit( Hr );
  781. }
  782. }
  783. //
  784. // Code to handle console pretty printing mode changes
  785. //
  786. bool bConsoleInfoRetrieved = false;
  787. HANDLE hConsole;
  788. CRITICAL_SECTION CritSection;
  789. CONSOLE_SCREEN_BUFFER_INFO StartConsoleInfo;
  790. DWORD StartConsoleMode;
  791. void SetupConsole()
  792. {
  793. if (!( GetFileType( bcout.GetHandle() ) == FILE_TYPE_CHAR ) )
  794. return;
  795. hConsole = bcout.GetHandle();
  796. if ( INVALID_HANDLE_VALUE == hConsole )
  797. CheckHR( L"Unable to get console handle", HRESULT_FROM_WIN32( GetLastError() ) );
  798. if (!GetConsoleScreenBufferInfo( hConsole, &StartConsoleInfo ) )
  799. CheckHR( L"Unable get setup console information", HRESULT_FROM_WIN32( GetLastError() ) );
  800. if (!GetConsoleMode( hConsole, &StartConsoleMode ) )
  801. CheckHR( L"Unable get setup console information", HRESULT_FROM_WIN32( GetLastError() ) );
  802. InitializeCriticalSection( &CritSection );
  803. bConsoleInfoRetrieved = true;
  804. EnterCriticalSection( &CritSection );
  805. DWORD NewConsoleMode = ( bWrap ) ?
  806. ( StartConsoleMode | ENABLE_WRAP_AT_EOL_OUTPUT ) :
  807. ( StartConsoleMode & ~ENABLE_WRAP_AT_EOL_OUTPUT );
  808. if (!SetConsoleMode( hConsole, NewConsoleMode ) )
  809. CheckHR( L"Unable set console mode", HRESULT_FROM_WIN32( GetLastError() ) );
  810. LeaveCriticalSection( &CritSection );
  811. }
  812. void RestoreConsole()
  813. {
  814. if ( bConsoleInfoRetrieved )
  815. {
  816. EnterCriticalSection( &CritSection );
  817. SetConsoleTextAttribute( hConsole, StartConsoleInfo.wAttributes );
  818. SetConsoleMode( hConsole, StartConsoleMode );
  819. // Do not unlock, since we shouldn't allow any more console attribute changes
  820. }
  821. }
  822. void ClearScreen()
  823. {
  824. COORD coordScreen = { 0, 0 };
  825. BOOL bSuccess;
  826. DWORD cCharsWritten;
  827. CONSOLE_SCREEN_BUFFER_INFO csbi;
  828. DWORD dwConSize;
  829. EnterCriticalSection( &CritSection );
  830. if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
  831. goto error;
  832. dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
  833. if (!FillConsoleOutputCharacter(hConsole, (WCHAR) ' ',
  834. dwConSize, coordScreen, &cCharsWritten))
  835. goto error;
  836. if (!GetConsoleScreenBufferInfo(hConsole, &csbi))
  837. goto error;
  838. if (!FillConsoleOutputAttribute(hConsole, csbi.wAttributes,
  839. dwConSize, coordScreen, &cCharsWritten))
  840. goto error;
  841. if (!SetConsoleCursorPosition(hConsole, coordScreen))
  842. goto error;
  843. LeaveCriticalSection( &CritSection );
  844. return;
  845. error:
  846. DWORD dwError = GetLastError();
  847. LeaveCriticalSection( &CritSection );
  848. CheckHR( L"Unable to clear the console window", HRESULT_FROM_WIN32( dwError ) );
  849. AppExit( dwError );
  850. }
  851. //
  852. // Classes set the intensity mode for the text. Use as follows
  853. // bcout << L"Some normal text " << AddIntensity();
  854. // bcout << L"Intense text" << ResetIntensity() << L"Normal";
  855. //
  856. class AddIntensity
  857. {
  858. };
  859. BITSOUTStream & operator<<( BITSOUTStream & s, AddIntensity )
  860. {
  861. if ( GetFileType( s.GetHandle() ) == FILE_TYPE_CHAR )
  862. {
  863. s.FlushBuffer();
  864. EnterCriticalSection( &CritSection );
  865. SetConsoleTextAttribute( hConsole, StartConsoleInfo.wAttributes | FOREGROUND_INTENSITY );
  866. LeaveCriticalSection( &CritSection );
  867. }
  868. return s;
  869. }
  870. class ResetIntensity
  871. {
  872. };
  873. BITSOUTStream & operator<<( BITSOUTStream & s, ResetIntensity )
  874. {
  875. if ( GetFileType( s.GetHandle() ) == FILE_TYPE_CHAR )
  876. {
  877. s.FlushBuffer();
  878. EnterCriticalSection( &CritSection );
  879. SetConsoleTextAttribute( hConsole, StartConsoleInfo.wAttributes );
  880. LeaveCriticalSection( &CritSection );
  881. }
  882. return s;
  883. }
  884. void CheckBITSHR( const WCHAR *pFailTxt, HRESULT Hr )
  885. {
  886. // Check on error code returned from BITS,
  887. // and exit with a printed error messeage on an error
  888. if ( !SUCCEEDED(Hr) )
  889. {
  890. WCHAR ErrorCode[12];
  891. StringCbPrintf( ErrorCode, sizeof(ErrorCode), L"0x%8.8x", Hr );
  892. bcout << pFailTxt << L" - " << ErrorCode << L"\n";
  893. AutoStringPointer Message;
  894. if ( SUCCEEDED( g_Manager->GetErrorDescription(
  895. Hr,
  896. GetThreadLocale(),
  897. Message.GetRecvPointer() ) ) )
  898. {
  899. bcout << Message << L"\n";
  900. }
  901. AppExit( Hr );
  902. }
  903. }
  904. void ConnectToBITS()
  905. {
  906. // Connects to the BITS service
  907. if ( g_Manager.Get() )
  908. return;
  909. if ( !pComputerName )
  910. {
  911. CheckHR( L"Unable to connect to BITS",
  912. CoCreateInstance( CLSID_BackgroundCopyManager,
  913. NULL,
  914. CLSCTX_LOCAL_SERVER,
  915. IID_IBackgroundCopyManager,
  916. (void**)g_Manager.GetRecvPointer() ) );
  917. }
  918. else
  919. {
  920. COSERVERINFO ServerInfo;
  921. memset( &ServerInfo, 0 , sizeof( ServerInfo ) );
  922. ServerInfo.pwszName = pComputerName;
  923. IClassFactory *pFactory = NULL;
  924. CheckHR( L"Unable to connect to BITS",
  925. CoGetClassObject(
  926. CLSID_BackgroundCopyManager,
  927. CLSCTX_REMOTE_SERVER,
  928. &ServerInfo,
  929. IID_IClassFactory,
  930. (void**) &pFactory ) );
  931. CheckHR( L"Unable to connect to BITS",
  932. pFactory->CreateInstance(
  933. NULL,
  934. IID_IBackgroundCopyManager,
  935. (void**)g_Manager.GetRecvPointer() ));
  936. pFactory->Release();
  937. }
  938. }
  939. //
  940. // Generic commandline parsing structures and functions
  941. //
  942. typedef void (*PCMDPARSEFUNC)(int, WCHAR** );
  943. typedef struct _PARSEENTRY
  944. {
  945. const WCHAR * pCommand;
  946. PCMDPARSEFUNC pParseFunc;
  947. } PARSEENTRY;
  948. typedef struct _PARSETABLE
  949. {
  950. const PARSEENTRY *pEntries;
  951. PCMDPARSEFUNC pErrorFunc;
  952. void * pErrorContext;
  953. } PARSETABLE;
  954. void ParseCmd( int argc, WCHAR **argv, const PARSETABLE *pParseTable )
  955. {
  956. if ( !argc) goto InvalidCommand;
  957. for( const PARSEENTRY *pEntry = pParseTable->pEntries;
  958. pEntry->pCommand; pEntry++ )
  959. {
  960. if (!_wcsicmp( *argv, pEntry->pCommand ))
  961. {
  962. argc--;
  963. argv++;
  964. (*pEntry->pParseFunc)( argc, argv );
  965. return;
  966. }
  967. }
  968. InvalidCommand:
  969. // Couldn't find a match, so complain
  970. bcout << L"Invalid command\n";
  971. (*pParseTable->pErrorFunc)( argc, argv );
  972. AppExit( 1 );
  973. }
  974. //
  975. // BITS specific input and output
  976. //
  977. BITSOUTStream & operator<<( BITSOUTStream &s, SmartJobPointer Job )
  978. {
  979. GUID guid;
  980. CheckBITSHR( L"Unable to get guid to job", Job->GetId( &guid ) );
  981. return (s << guid );
  982. }
  983. BITSOUTStream& operator<<( BITSOUTStream &s, SmartJobErrorPointer Error )
  984. {
  985. SmartFilePointer pFile;
  986. AutoStringPointer LocalName;
  987. AutoStringPointer URL;
  988. CheckBITSHR( L"Unable to get error file", Error->GetFile( pFile.GetRecvPointer() ) );
  989. CheckBITSHR( L"Unable to get error URL", pFile->GetRemoteName( URL.GetRecvPointer() ) );
  990. CheckBITSHR( L"Unable to get error file name", pFile->GetLocalName( LocalName.GetRecvPointer() ) );
  991. bcout << AddIntensity() << L"ERROR FILE: " << ResetIntensity() << URL << L" -> " << LocalName << L"\n";
  992. BG_ERROR_CONTEXT Context;
  993. HRESULT Code;
  994. AutoStringPointer ErrorDescription;
  995. AutoStringPointer ContextDescription;
  996. CheckBITSHR( L"Unable to get error code", Error->GetError( &Context, &Code ) );
  997. CheckBITSHR( L"Unable to get error description",
  998. Error->GetErrorDescription( (DWORD)GetThreadLocale(), ErrorDescription.GetRecvPointer() ) );
  999. CheckBITSHR( L"Unable to get context description",
  1000. Error->GetErrorContextDescription( (DWORD)GetThreadLocale(), ContextDescription.GetRecvPointer() ) );
  1001. bcout << AddIntensity() << L"ERROR CODE: " << ResetIntensity() <<
  1002. HRESULTToString(Code) << L" - " << ErrorDescription;
  1003. bcout << AddIntensity() << L"ERROR CONTEXT: " << ResetIntensity() <<
  1004. HRESULTToString((HRESULT)Context) << L" - " << ContextDescription;
  1005. return s;
  1006. }
  1007. BITSOUTStream & operator<<( BITSOUTStream &s, BG_JOB_TYPE type )
  1008. {
  1009. if ( BG_JOB_TYPE_DOWNLOAD == type )
  1010. return ( s << L"DOWNLOAD" );
  1011. else if ( BG_JOB_TYPE_UPLOAD == type )
  1012. return ( s << L"UPLOAD" );
  1013. else if ( BG_JOB_TYPE_UPLOAD_REPLY == type )
  1014. return ( s << L"UPLOAD-REPLY" );
  1015. else
  1016. return ( s << L"UNKNOWN" );
  1017. }
  1018. BITSOUTStream & operator<<( BITSOUTStream &s, BG_JOB_STATE state )
  1019. {
  1020. switch(state)
  1021. {
  1022. case BG_JOB_STATE_QUEUED:
  1023. return ( s << L"QUEUED" );
  1024. case BG_JOB_STATE_CONNECTING:
  1025. return ( s << L"CONNECTING" );
  1026. case BG_JOB_STATE_TRANSFERRING:
  1027. return ( s << L"TRANSFERRING" );
  1028. case BG_JOB_STATE_SUSPENDED:
  1029. return ( s << L"SUSPENDED" );
  1030. case BG_JOB_STATE_ERROR:
  1031. return ( s << L"ERROR" );
  1032. case BG_JOB_STATE_TRANSIENT_ERROR:
  1033. return ( s << L"TRANSIENT_ERROR" );
  1034. case BG_JOB_STATE_TRANSFERRED:
  1035. return ( s << L"TRANSFERRED" );
  1036. case BG_JOB_STATE_ACKNOWLEDGED:
  1037. return ( s << L"ACKNOWLEDGED" );
  1038. case BG_JOB_STATE_CANCELLED:
  1039. return ( s << L"CANCELLED" );
  1040. default:
  1041. return ( s << L"UNKNOWN" );
  1042. }
  1043. }
  1044. BITSOUTStream & operator<<( BITSOUTStream &s, BG_JOB_PRIORITY priority )
  1045. {
  1046. switch(priority)
  1047. {
  1048. case BG_JOB_PRIORITY_FOREGROUND:
  1049. return ( s << L"FOREGROUND" );
  1050. case BG_JOB_PRIORITY_HIGH:
  1051. return ( s << L"HIGH" );
  1052. case BG_JOB_PRIORITY_NORMAL:
  1053. return ( s << L"NORMAL" );
  1054. case BG_JOB_PRIORITY_LOW:
  1055. return ( s << L"LOW" );
  1056. default:
  1057. return ( s << L"UNKNOWN" );
  1058. }
  1059. }
  1060. BG_JOB_PRIORITY JobInputPriority( WCHAR *pText )
  1061. {
  1062. if ( _wcsicmp( pText, L"FOREGROUND" ) == 0 )
  1063. return BG_JOB_PRIORITY_FOREGROUND;
  1064. if ( _wcsicmp( pText, L"HIGH" ) == 0 )
  1065. return BG_JOB_PRIORITY_HIGH;
  1066. if ( _wcsicmp( pText, L"NORMAL" ) == 0 )
  1067. return BG_JOB_PRIORITY_NORMAL;
  1068. if ( _wcsicmp( pText, L"LOW" ) == 0 )
  1069. return BG_JOB_PRIORITY_LOW;
  1070. bcout << L"Invalid priority.\n";
  1071. AppExit(1);
  1072. }
  1073. SmartJobPointer
  1074. JobLookupViaDisplayName( const WCHAR * JobName )
  1075. {
  1076. SmartEnumJobsPointer Enum;
  1077. CheckBITSHR( L"Unable to lookup job", g_Manager->EnumJobs( 0, Enum.GetRecvPointer() ) );
  1078. size_t FoundJobs = 0;
  1079. SmartJobPointer FoundJob;
  1080. SmartJobPointer Job;
  1081. while( Enum->Next( 1, Job.GetRecvPointer(), NULL ) == S_OK )
  1082. {
  1083. PollShutdown();
  1084. AutoStringPointer DisplayName;
  1085. CheckBITSHR( L"Unable to lookup job", Job->GetDisplayName( DisplayName.GetRecvPointer() ) );
  1086. if ( wcscmp( DisplayName, JobName) == 0 )
  1087. {
  1088. FoundJobs++;
  1089. FoundJob = Job;
  1090. }
  1091. }
  1092. if ( 1 == FoundJobs )
  1093. {
  1094. return FoundJob;
  1095. }
  1096. if ( !FoundJobs )
  1097. {
  1098. bcout << L"Unable to find job named \"" << JobName << L"\".\n";
  1099. AppExit( 1 );
  1100. }
  1101. bcout << L"Found " << FoundJobs << L" jobs named \"" << JobName << L"\".\n";
  1102. bcout << L"Use the job identifier instead of the job name.\n";
  1103. AppExit( 1 );
  1104. }
  1105. SmartJobPointer
  1106. JobLookup( WCHAR * JobName )
  1107. {
  1108. ConnectToBITS();
  1109. GUID JobGuid;
  1110. SmartJobPointer Job;
  1111. if ( FAILED( CLSIDFromString( JobName, &JobGuid) ) )
  1112. return JobLookupViaDisplayName( JobName );
  1113. if ( FAILED( g_Manager->GetJob( JobGuid, Job.GetRecvPointer() ) ) )
  1114. return JobLookupViaDisplayName( JobName );
  1115. return Job;
  1116. }
  1117. SmartJobPointer
  1118. JobLookupForNoArg( int argc, WCHAR **argv )
  1119. {
  1120. if (1 != argc)
  1121. {
  1122. bcout << L"Invalid number of arguments.\n";
  1123. AppExit(1);
  1124. }
  1125. return JobLookup( argv[0] );
  1126. }
  1127. void JobValidateArgs( int argc, WCHAR**argv, int required )
  1128. {
  1129. if ( argc != required )
  1130. {
  1131. bcout << L"Invalid number of arguments.\n";
  1132. AppExit(1);
  1133. }
  1134. }
  1135. //
  1136. // Actual command functions
  1137. //
  1138. void JobCreate( int argc, WCHAR **argv )
  1139. {
  1140. GUID guid;
  1141. SmartJobPointer Job;
  1142. BG_JOB_TYPE type = BG_JOB_TYPE_DOWNLOAD;
  1143. while (argc > 0)
  1144. {
  1145. if (argv[0][0] != '/')
  1146. {
  1147. break;
  1148. }
  1149. if ( !_wcsicmp( argv[0], L"/UPLOAD" ) )
  1150. {
  1151. type = BG_JOB_TYPE_UPLOAD;
  1152. }
  1153. else if ( !_wcsicmp( argv[0], L"/UPLOAD-REPLY" ) )
  1154. {
  1155. type = BG_JOB_TYPE_UPLOAD_REPLY;
  1156. }
  1157. else if ( !_wcsicmp( argv[0], L"/DOWNLOAD" ) )
  1158. {
  1159. type = BG_JOB_TYPE_DOWNLOAD;
  1160. }
  1161. else
  1162. {
  1163. bcout << L"Invalid argument.\n";
  1164. AppExit(1);
  1165. }
  1166. --argc;
  1167. ++argv;
  1168. }
  1169. JobValidateArgs( argc, argv, 1 );
  1170. ConnectToBITS();
  1171. CheckBITSHR( L"Unable to create group",
  1172. g_Manager->CreateJob( argv[0],
  1173. type,
  1174. &guid,
  1175. Job.GetRecvPointer() ) );
  1176. if (bRawReturn)
  1177. bcout << Job;
  1178. else
  1179. bcout << L"Created job " << Job << L".\n";
  1180. }
  1181. void JobAddFile( int argc, WCHAR **argv )
  1182. {
  1183. JobValidateArgs( argc, argv, 3 );
  1184. SmartJobPointer Job = JobLookup( argv[0] );
  1185. CheckBITSHR( L"Unable to add file to job", Job->AddFile( argv[1], argv[2] ) );
  1186. bcout << L"Added " << argv[1] << L" -> " << argv[2] << L" to job.\n";
  1187. }
  1188. size_t JobListFiles( SmartJobPointer Job, bool bDoIndent )
  1189. {
  1190. SmartEnumFilesPointer Enum;
  1191. CheckBITSHR( L"Unable to enum files in job", Job->EnumFiles( Enum.GetRecvPointer() ) );
  1192. SmartFilePointer pFile;
  1193. size_t FilesListed = 0;
  1194. while( Enum->Next( 1, pFile.GetRecvPointer(), NULL ) == S_OK )
  1195. {
  1196. BG_FILE_PROGRESS progress;
  1197. AutoStringPointer URL;
  1198. AutoStringPointer Local;
  1199. CheckBITSHR( L"Unable to get file progress", pFile->GetProgress( &progress ) );
  1200. CheckBITSHR( L"Unable to get file URL", pFile->GetRemoteName( URL.GetRecvPointer() ) );
  1201. CheckBITSHR( L"Unable to get local file name", pFile->GetLocalName( Local.GetRecvPointer() ) );
  1202. if ( bDoIndent )
  1203. bcout << L"\t";
  1204. WCHAR *pCompleteText = progress.Completed ? L"COMPLETED" : L"WORKING";
  1205. bcout << progress.BytesTransferred << L" / ";
  1206. if ( progress.BytesTotal != (UINT64)-1 )
  1207. {
  1208. bcout << progress.BytesTotal;
  1209. }
  1210. else
  1211. {
  1212. bcout << L"UNKNOWN";
  1213. }
  1214. bcout << L" " << pCompleteText << L" " << URL << L" -> " << Local << L"\n";
  1215. // Example output:
  1216. // 10 / 1000 INCOMPLETE http://www.microsoft.com -> c:\temp\microsoft.htm
  1217. FilesListed++;
  1218. }
  1219. return FilesListed;
  1220. }
  1221. void JobListFiles( int argc, WCHAR **argv )
  1222. {
  1223. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1224. size_t FilesListed = JobListFiles( Job, false );
  1225. if (!bRawReturn)
  1226. bcout << L"Listed " << FilesListed << L" file(s).\n";
  1227. }
  1228. void JobSuspend( int argc, WCHAR **argv )
  1229. {
  1230. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1231. CheckBITSHR( L"Unable to suspend job", Job->Suspend() );
  1232. bcout << L"Job suspended.\n";
  1233. }
  1234. void JobResume( int argc, WCHAR **argv )
  1235. {
  1236. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1237. CheckBITSHR( L"Unable to resume job", Job->Resume() );
  1238. bcout << L"Job resumed.\n";
  1239. }
  1240. void JobCancel( int argc, WCHAR **argv )
  1241. {
  1242. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1243. CheckBITSHR( L"Unable to cancel job", Job->Cancel() );
  1244. bcout << L"Job canceled.\n";
  1245. }
  1246. void JobComplete( int argc, WCHAR **argv )
  1247. {
  1248. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1249. CheckBITSHR( L"Unable to complete job", Job->Complete() );
  1250. bcout << L"Job completed.\n";
  1251. }
  1252. void JobGetType( int argc, WCHAR **argv )
  1253. {
  1254. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1255. BG_JOB_TYPE type;
  1256. CheckBITSHR( L"Unable to get job type", Job->GetType(&type) );
  1257. bcout << type;
  1258. if (!bRawReturn) bcout << L"\n";
  1259. }
  1260. void JobGetBytesTotal( int argc, WCHAR **argv )
  1261. {
  1262. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1263. BG_JOB_PROGRESS progress;
  1264. CheckBITSHR( L"Unable to get total bytes in job", Job->GetProgress( &progress ) );
  1265. bcout << progress.BytesTotal;
  1266. if (!bRawReturn) bcout << L"\n";
  1267. }
  1268. void JobGetBytesTransferred( int argc, WCHAR **argv )
  1269. {
  1270. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1271. BG_JOB_PROGRESS progress;
  1272. CheckBITSHR( L"Unable to get bytes transferred in job", Job->GetProgress( &progress ) );
  1273. bcout << progress.BytesTransferred;
  1274. if (!bRawReturn) bcout << L"\n";
  1275. }
  1276. void JobGetFilesTotal( int argc, WCHAR **argv )
  1277. {
  1278. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1279. BG_JOB_PROGRESS progress;
  1280. CheckBITSHR( L"Unable to get number of files in job", Job->GetProgress( &progress ) );
  1281. bcout << progress.FilesTotal;
  1282. if (!bRawReturn) bcout << L"\n";
  1283. }
  1284. void JobGetFilesTransferred( int argc, WCHAR **argv )
  1285. {
  1286. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1287. BG_JOB_PROGRESS progress;
  1288. CheckBITSHR( L"Unable to get numeber of transferred files in job", Job->GetProgress( &progress ) );
  1289. bcout << progress.FilesTransferred;
  1290. if (!bRawReturn) bcout << L"\n";
  1291. }
  1292. void JobGetCreationTime( int argc, WCHAR **argv )
  1293. {
  1294. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1295. BG_JOB_TIMES times;
  1296. CheckBITSHR( L"Unable to get job creation time", Job->GetTimes( &times ) );
  1297. bcout << times.CreationTime;
  1298. if (!bRawReturn) bcout << L"\n";
  1299. }
  1300. void JobGetModificationTime( int argc, WCHAR **argv )
  1301. {
  1302. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1303. BG_JOB_TIMES times;
  1304. CheckBITSHR( L"Unable to get job modification time", Job->GetTimes( &times ) );
  1305. bcout << times.ModificationTime;
  1306. if (!bRawReturn) bcout << L"\n";
  1307. }
  1308. void JobGetCompletionTime( int argc, WCHAR **argv )
  1309. {
  1310. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1311. BG_JOB_TIMES times;
  1312. CheckBITSHR( L"Unable to get job completion time", Job->GetTimes( &times ) );
  1313. if ( !times.TransferCompletionTime.dwLowDateTime && !times.TransferCompletionTime.dwHighDateTime )
  1314. bcout << L"WORKING";
  1315. else
  1316. bcout << times.TransferCompletionTime;
  1317. if (!bRawReturn) bcout << L"\n";
  1318. }
  1319. void JobGetError( int argc, WCHAR **argv )
  1320. {
  1321. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1322. SmartJobErrorPointer Error;
  1323. CheckBITSHR( L"Unable to get error", Job->GetError( Error.GetRecvPointer() ) );
  1324. bcout << Error;
  1325. }
  1326. void JobGetState( int argc, WCHAR **argv )
  1327. {
  1328. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1329. BG_JOB_STATE state;
  1330. CheckBITSHR( L"Unable to get job state", Job->GetState( &state ) );
  1331. bcout << state;
  1332. if (!bRawReturn) bcout << L"\n";
  1333. }
  1334. void JobGetOwner( int argc, WCHAR **argv )
  1335. {
  1336. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1337. AutoStringPointer Owner;
  1338. CheckBITSHR( L"Unable to get job owner", Job->GetOwner( Owner.GetRecvPointer() ) );
  1339. bcout << PrintSidString( Owner );
  1340. if (!bRawReturn) bcout << L"\n";
  1341. }
  1342. void JobGetDisplayName( int argc, WCHAR **argv )
  1343. {
  1344. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1345. AutoStringPointer DisplayName;
  1346. CheckBITSHR( L"Unable to get job displayname", Job->GetDisplayName( DisplayName.GetRecvPointer() ) );
  1347. bcout << DisplayName;
  1348. if (!bRawReturn) bcout << L"\n";
  1349. }
  1350. void JobSetDisplayName( int argc, WCHAR **argv )
  1351. {
  1352. JobValidateArgs( argc, argv, 2 );
  1353. SmartJobPointer Job = JobLookup( argv[0] );
  1354. CheckBITSHR( L"Unable to set display name", Job->SetDisplayName( argv[1] ) );
  1355. bcout << L"Display name set to " << argv[1] << L".\n";
  1356. }
  1357. void JobGetDescription( int argc, WCHAR **argv )
  1358. {
  1359. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1360. AutoStringPointer Description;
  1361. CheckBITSHR( L"Unable to get job displayname", Job->GetDescription( Description.GetRecvPointer() ) );
  1362. bcout << Description;
  1363. if (!bRawReturn) bcout << L"\n";
  1364. }
  1365. void JobSetDescription( int argc, WCHAR **argv )
  1366. {
  1367. JobValidateArgs( argc, argv, 2 );
  1368. SmartJobPointer Job = JobLookup( argv[0] );
  1369. CheckBITSHR( L"Unable to set description", Job->SetDescription( argv[1] ) );
  1370. bcout << L"Description set to " << argv[1] << L".\n";
  1371. }
  1372. void JobGetReplyFileName( int argc, WCHAR **argv )
  1373. {
  1374. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1375. SmartJob2Pointer Job2;
  1376. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  1377. AutoStringPointer ReplyFileName;
  1378. CheckBITSHR( L"Unable to get reply file name", Job2->GetReplyFileName( ReplyFileName.GetRecvPointer() ) );
  1379. if (ReplyFileName)
  1380. {
  1381. bcout << L"'" << ReplyFileName << L"'";
  1382. }
  1383. else
  1384. {
  1385. bcout << L"(null)";
  1386. }
  1387. if (!bRawReturn) bcout << L"\n";
  1388. }
  1389. void JobSetReplyFileName( int argc, WCHAR **argv )
  1390. {
  1391. JobValidateArgs( argc, argv, 2 );
  1392. SmartJobPointer Job = JobLookup( argv[0] );
  1393. SmartJob2Pointer Job2;
  1394. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  1395. CheckBITSHR( L"Unable to set reply file name", Job2->SetReplyFileName( argv[1] ) );
  1396. bcout << L"reply file name set to " << argv[1] << L".\n";
  1397. }
  1398. void JobGetReplyProgress( int argc, WCHAR **argv )
  1399. {
  1400. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1401. SmartJob2Pointer Job2;
  1402. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  1403. BG_JOB_REPLY_PROGRESS Progress;
  1404. CheckBITSHR( L"Unable to get reply progress", Job2->GetReplyProgress( &Progress ) );
  1405. bcout << L"progress: " << ULONG(Progress.BytesTransferred) << L" / ";
  1406. if (Progress.BytesTotal == BG_SIZE_UNKNOWN)
  1407. bcout << L"(unknown)";
  1408. else
  1409. bcout << ULONG(Progress.BytesTotal);
  1410. bcout << L".\n";
  1411. if (!bRawReturn) bcout << L"\n";
  1412. }
  1413. bool
  1414. printable( char c )
  1415. {
  1416. if ( c < 32 )
  1417. {
  1418. return false;
  1419. }
  1420. if ( c > 126 )
  1421. {
  1422. return false;
  1423. }
  1424. return true;
  1425. }
  1426. void
  1427. DumpBuffer(
  1428. void * Buffer,
  1429. unsigned Length
  1430. )
  1431. {
  1432. const BYTES_PER_LINE = 16;
  1433. unsigned char FAR *p = (unsigned char FAR *) Buffer;
  1434. //
  1435. // 3 chars per byte for hex display, plus an extra space every 4 bytes,
  1436. // plus a byte for the printable representation, plus the \0.
  1437. //
  1438. const buflen = BYTES_PER_LINE*3+BYTES_PER_LINE/4+BYTES_PER_LINE;
  1439. wchar_t Outbuf[buflen+1];
  1440. Outbuf[0] = 0;
  1441. Outbuf[buflen] = 0;
  1442. wchar_t * HexDigits = L"0123456789abcdef";
  1443. unsigned Index;
  1444. for ( unsigned Offset=0; Offset < Length; Offset++ )
  1445. {
  1446. Index = Offset % BYTES_PER_LINE;
  1447. if ( Index == 0 )
  1448. {
  1449. bcout << L" " << Outbuf << L"\n";
  1450. for (int i=0; i < buflen; ++i)
  1451. {
  1452. Outbuf[i] = L' ';
  1453. }
  1454. }
  1455. Outbuf[Index*3+Index/4 ] = HexDigits[p[Offset] / 16];
  1456. Outbuf[Index*3+Index/4+1] = HexDigits[p[Offset] % 16];
  1457. Outbuf[BYTES_PER_LINE*3+BYTES_PER_LINE/4+Index] = printable(p[Offset]) ? p[Offset] : L'.';
  1458. }
  1459. bcout << L" " << Outbuf << L"\n";
  1460. }
  1461. void JobGetReplyData( int argc, WCHAR **argv )
  1462. {
  1463. byte * Buffer = 0;
  1464. ULONG Length = 0;
  1465. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1466. SmartJob2Pointer Job2;
  1467. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  1468. CheckBITSHR( L"Unable to get reply data", Job2->GetReplyData( &Buffer, &Length ) );
  1469. bcout << L"data length is " << Length;
  1470. DumpBuffer( Buffer, Length );
  1471. }
  1472. void JobGetNotifyCmdLine( int argc, WCHAR **argv )
  1473. {
  1474. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1475. SmartJob2Pointer Job2;
  1476. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  1477. LPWSTR CmdLine = 0;
  1478. CheckBITSHR( L"Unable to get command line", Job2->GetNotifyCmdLine( &CmdLine ) );
  1479. bcout << L"the notification command line is '" << CmdLine << L"'";
  1480. if (!bRawReturn) bcout << L"\n";
  1481. }
  1482. void JobSetNotifyCmdLine( int argc, WCHAR **argv )
  1483. {
  1484. JobValidateArgs( argc, argv, 2 );
  1485. SmartJobPointer Job = JobLookup( argv[0] );
  1486. SmartJob2Pointer Job2;
  1487. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  1488. CheckBITSHR( L"Unable to set the notification command line", Job2->SetNotifyCmdLine( argv[1] ) );
  1489. bcout << L"notification command line set to '" << argv[1] << L"'.\n";
  1490. }
  1491. BG_AUTH_TARGET TargetFromString( LPCWSTR s )
  1492. {
  1493. if (0 == _wcsicmp(s, L"server"))
  1494. {
  1495. return BG_AUTH_TARGET_SERVER;
  1496. }
  1497. else if (0 == _wcsicmp(s, L"proxy"))
  1498. {
  1499. return BG_AUTH_TARGET_PROXY;
  1500. }
  1501. bcout << L"'" << s << L"' is not a valid credential target. It must be 'proxy' or 'server'.\n";
  1502. AppExit( 1 );
  1503. }
  1504. struct
  1505. {
  1506. LPCWSTR Name;
  1507. BG_AUTH_SCHEME Scheme;
  1508. }
  1509. SchemeNames[] =
  1510. {
  1511. { L"basic", BG_AUTH_SCHEME_BASIC },
  1512. { L"digest", BG_AUTH_SCHEME_DIGEST },
  1513. { L"ntlm", BG_AUTH_SCHEME_NTLM },
  1514. { L"negotiate", BG_AUTH_SCHEME_NEGOTIATE },
  1515. { L"passport", BG_AUTH_SCHEME_PASSPORT },
  1516. { NULL, BG_AUTH_SCHEME_BASIC }
  1517. };
  1518. BG_AUTH_SCHEME SchemeFromString( LPCWSTR s )
  1519. {
  1520. int i;
  1521. i = 0;
  1522. while (SchemeNames[i].Name != NULL)
  1523. {
  1524. if (0 == _wcsicmp( s, SchemeNames[i].Name ))
  1525. {
  1526. return SchemeNames[i].Scheme;
  1527. }
  1528. ++i;
  1529. }
  1530. bcout << L"'" << s << L"is not a valid credential scheme.\n"
  1531. L"It must be one of the following:\n"
  1532. L" basic\n"
  1533. L" digest\n"
  1534. L" ntlm\n"
  1535. L" negotiate\n"
  1536. L" passport\n";
  1537. AppExit( 1 );
  1538. }
  1539. void JobSetCredentials( int argc, WCHAR **argv )
  1540. /*
  1541. args:
  1542. 0: job ID
  1543. 1: "proxy" | "server"
  1544. 2: "basic" | "digest" | "ntlm" | "negotiate" | "passport"
  1545. 3: user name
  1546. 4: password
  1547. */
  1548. {
  1549. JobValidateArgs( argc, argv, 5 );
  1550. SmartJobPointer Job = JobLookup( argv[0] );
  1551. SmartJob2Pointer Job2;
  1552. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  1553. BG_AUTH_CREDENTIALS cred;
  1554. cred.Target = TargetFromString( argv[1] );
  1555. cred.Scheme = SchemeFromString( argv[2] );
  1556. cred.Credentials.Basic.UserName = argv[3];
  1557. cred.Credentials.Basic.Password = argv[4];
  1558. CheckBITSHR( L"Unable to add credentials", Job2->SetCredentials( &cred ));
  1559. bcout << L"OK" << L".\n";
  1560. }
  1561. void JobRemoveCredentials( int argc, WCHAR **argv )
  1562. /*
  1563. args:
  1564. 0: job ID
  1565. 1: "proxy" | "server"
  1566. 2: "basic" | "digest" | "ntlm" | "negotiate" | "passport"
  1567. */
  1568. {
  1569. JobValidateArgs( argc, argv, 3 );
  1570. SmartJobPointer Job = JobLookup( argv[0] );
  1571. SmartJob2Pointer Job2;
  1572. CheckBITSHR( L"Unable to get the IBackgroundCopyJob2 interface. Version 1.5 is required", Job2FromJob( Job, Job2 ));
  1573. HRESULT hr;
  1574. BG_AUTH_TARGET Target;
  1575. BG_AUTH_SCHEME Scheme;
  1576. Target = TargetFromString( argv[1] );
  1577. Scheme = SchemeFromString( argv[2] );
  1578. hr = Job2->RemoveCredentials( Target, Scheme );
  1579. CheckBITSHR( L"Unable to remove credentials", hr);
  1580. if (hr == S_FALSE)
  1581. {
  1582. bcout << L"no matching credential was found.\n";
  1583. }
  1584. else
  1585. {
  1586. bcout << L"OK" << L".\n";
  1587. }
  1588. }
  1589. void JobGetPriority( int argc, WCHAR **argv )
  1590. {
  1591. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1592. BG_JOB_PRIORITY priority;
  1593. CheckBITSHR( L"Unable to get job displayname", Job->GetPriority( &priority ) );
  1594. bcout << priority;
  1595. if (!bRawReturn) bcout << L"\n";
  1596. }
  1597. void JobSetPriority( int argc, WCHAR **argv )
  1598. {
  1599. JobValidateArgs( argc, argv, 2 );
  1600. SmartJobPointer Job = JobLookup( argv[0] );
  1601. BG_JOB_PRIORITY priority = JobInputPriority( argv[1] );
  1602. CheckBITSHR( L"Unable to set description", Job->SetPriority( priority ) );
  1603. bcout << L"Priority set to " << priority << L".\n";
  1604. }
  1605. void JobGetNotifyFlags( int argc, WCHAR **argv )
  1606. {
  1607. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1608. ULONG flags;
  1609. CheckBITSHR( L"Unable to get notify flags", Job->GetNotifyFlags( &flags ) );
  1610. bcout << flags;
  1611. if (!bRawReturn) bcout << L"\n";
  1612. }
  1613. void JobSetNotifyFlags( int argc, WCHAR **argv )
  1614. {
  1615. JobValidateArgs( argc, argv, 2 );
  1616. SmartJobPointer Job = JobLookup( argv[0] );
  1617. ULONG NewFlags = InputULONG( argv[1] );
  1618. CheckBITSHR( L"Unable to set description", Job->SetNotifyFlags( NewFlags ) );
  1619. bcout << L"Notification flags set to " << NewFlags << L".\n";
  1620. }
  1621. void JobGetNotifyInterface( int argc, WCHAR **argv )
  1622. {
  1623. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1624. SmartIUnknownPointer pUnknown;
  1625. CheckBITSHR( L"Unable to get notify interface", Job->GetNotifyInterface( pUnknown.GetRecvPointer() ) );
  1626. if ( pUnknown.Get() )
  1627. bcout << L"REGISTERED";
  1628. else
  1629. bcout << L"UNREGISTERED";
  1630. if (!bRawReturn) bcout << L"\n";
  1631. }
  1632. void JobSetMinimumRetryDelay( int argc, WCHAR **argv )
  1633. {
  1634. JobValidateArgs( argc, argv, 2 );
  1635. SmartJobPointer Job = JobLookup( argv[0] );
  1636. ULONG NewDelay = InputULONG( argv[1] );
  1637. CheckBITSHR( L"Unable to set new minimum retry delay", Job->SetMinimumRetryDelay( NewDelay ) );
  1638. bcout << L"Minimum retry delay set to " << NewDelay << L".\n";
  1639. }
  1640. void JobGetMinimumRetryDelay( int argc, WCHAR **argv )
  1641. {
  1642. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1643. ULONG delay;
  1644. CheckBITSHR( L"Unable to get minimum retry delay", Job->GetMinimumRetryDelay( &delay ) );
  1645. bcout << delay;
  1646. if (!bRawReturn) bcout << L"\n";
  1647. }
  1648. void JobGetNoProgressTimeout( int argc, WCHAR **argv )
  1649. {
  1650. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1651. ULONG timeout;
  1652. CheckBITSHR( L"Unable to get no progress timeout", Job->GetNoProgressTimeout( &timeout ) );
  1653. bcout << timeout;
  1654. if (!bRawReturn) bcout << L"\n";
  1655. }
  1656. void JobSetNoProgressTimeout( int argc, WCHAR **argv )
  1657. {
  1658. JobValidateArgs( argc, argv, 2 );
  1659. SmartJobPointer Job = JobLookup( argv[0] );
  1660. ULONG NewTimeout = InputULONG( argv[1] );
  1661. CheckBITSHR( L"Unable to set new no progress timeout", Job->SetNoProgressTimeout( NewTimeout ) );
  1662. bcout << L"No progress timeout set to " << NewTimeout << L".\n";
  1663. }
  1664. void JobGetErrorCount( int argc, WCHAR **argv )
  1665. {
  1666. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1667. ULONG errors;
  1668. CheckBITSHR( L"Unable to get no progress timeout", Job->GetErrorCount( &errors ) );
  1669. bcout << errors;
  1670. if (!bRawReturn) bcout << L"\n";
  1671. }
  1672. void JobInfo( SmartJobPointer Job )
  1673. {
  1674. GUID id;
  1675. BG_JOB_STATE state;
  1676. BG_JOB_PROGRESS progress;
  1677. AutoStringPointer DisplayName;
  1678. CheckBITSHR( L"Unable to get job ID", Job->GetId( &id ));
  1679. CheckBITSHR( L"Unable to get job state", Job->GetState( &state ));
  1680. CheckBITSHR( L"Unable to get job progress", Job->GetProgress( &progress ));
  1681. CheckBITSHR( L"Unable to get display name", Job->GetDisplayName( DisplayName.GetRecvPointer() ) );
  1682. bcout << id << L" " << DisplayName << L" " << state;
  1683. bcout << L" " << progress.FilesTransferred << L" / " << progress.FilesTotal;
  1684. bcout << L" " << progress.BytesTransferred << L" / ";
  1685. if ( (UINT64)-1 == progress.BytesTotal )
  1686. bcout << L"UNKNOWN";
  1687. else
  1688. bcout << progress.BytesTotal;
  1689. bcout << L"\n";
  1690. }
  1691. void JobVerboseInfo( SmartJobPointer Job )
  1692. {
  1693. GUID id;
  1694. AutoStringPointer Display;
  1695. BG_JOB_TYPE type;
  1696. BG_JOB_STATE state;
  1697. AutoStringPointer Owner;
  1698. BG_JOB_PRIORITY priority;
  1699. BG_JOB_PROGRESS progress;
  1700. BG_JOB_TIMES times;
  1701. SmartIUnknownPointer Notify;
  1702. ULONG NotifyFlags;
  1703. ULONG retrydelay;
  1704. ULONG noprogresstimeout;
  1705. ULONG ErrorCount;
  1706. AutoStringPointer Description;
  1707. SmartJobErrorPointer Error;
  1708. BG_JOB_PROXY_USAGE ProxyUsage;
  1709. AutoStringPointer ProxyList;
  1710. AutoStringPointer ProxyBypassList;
  1711. bool fShow15Fields;
  1712. SmartJob2Pointer Job2;
  1713. BG_JOB_REPLY_PROGRESS ReplyProgress;
  1714. AutoStringPointer ReplyFileName;
  1715. AutoStringPointer CmdLine;
  1716. CheckBITSHR( L"Unable to get job ID", Job->GetId( &id) );
  1717. CheckBITSHR( L"Unable to get job display name", Job->GetDisplayName(Display.GetRecvPointer()) );
  1718. CheckBITSHR( L"Unable to get job type", Job->GetType( &type ) );
  1719. CheckBITSHR( L"Unable to get job state", Job->GetState( &state ) );
  1720. CheckBITSHR( L"Unable to get job owner", Job->GetOwner( Owner.GetRecvPointer() ) );
  1721. CheckBITSHR( L"Unable to get job priority", Job->GetPriority( &priority ) );
  1722. CheckBITSHR( L"Unable to get job progress", Job->GetProgress( &progress ) );
  1723. CheckBITSHR( L"Unable to get job times", Job->GetTimes( &times ) );
  1724. bool NotifyAvailable = SUCCEEDED( Job->GetNotifyInterface( Notify.GetRecvPointer() ) );
  1725. CheckBITSHR( L"Unable to get job notification flags", Job->GetNotifyFlags( &NotifyFlags ) );
  1726. CheckBITSHR( L"Unable to get job retry delay", Job->GetMinimumRetryDelay( &retrydelay ) );
  1727. CheckBITSHR( L"Unable to get job no progress timeout", Job->GetNoProgressTimeout( &noprogresstimeout ) );
  1728. CheckBITSHR( L"Unable to get job error count", Job->GetErrorCount( &ErrorCount ) );
  1729. CheckBITSHR( L"Unable to get job description", Job->GetDescription( Description.GetRecvPointer() ) );
  1730. CheckBITSHR( L"Unable to get proxy settings", Job->GetProxySettings( &ProxyUsage,
  1731. ProxyList.GetRecvPointer(),
  1732. ProxyBypassList.GetRecvPointer() ) );
  1733. if (FAILED(Job->GetError( Error.GetRecvPointer() )) )
  1734. Error.Clear();
  1735. if (SUCCEEDED(Job2FromJob( Job, Job2 )))
  1736. {
  1737. fShow15Fields = true;
  1738. CheckBITSHR( L"unable to get notification command line", Job2->GetNotifyCmdLine( CmdLine.GetRecvPointer() ));
  1739. if (type == BG_JOB_TYPE_UPLOAD_REPLY )
  1740. {
  1741. CheckBITSHR( L"unable to get reply progress", Job2->GetReplyProgress( &ReplyProgress ));
  1742. CheckBITSHR( L"unable to get reply file name", Job2->GetReplyFileName( ReplyFileName.GetRecvPointer() ));
  1743. }
  1744. }
  1745. else
  1746. {
  1747. fShow15Fields = false;
  1748. }
  1749. // Example output
  1750. // GUID: {F196178C-0C00-4E92-A8AD-1F44E30C2485} DISPLAY: Test Job
  1751. // TYPE: DOWNLOAD STATE: SUSPENDED OWNER: ntdev\somedev
  1752. // PRIORITY: NORMAL FILES: 0 / 0 BYTES: 0 / 0
  1753. // CREATION TIME: 5:29:35 PM 11/9/2000 MODIFICATION TIME: 5:29:35 PM 11/9/2000
  1754. // COMPLETION TIME: 5:29:35 PM 11/9/2000
  1755. // NOTIFY INTERFACE: 00000000 NOTIFICATION FLAGS: 3
  1756. // RETRY DELAY: 300 NO PROGRESS TIMEOUT: 1209600 ERROR COUNT: 0
  1757. // PROXY USAGE: PRECONFIG PROXY LIST: NULL PROXY BYPASS LIST: NULL
  1758. // [ error info ]
  1759. // DESCRIPTION:
  1760. // [ file list ]
  1761. //
  1762. // Additional output for BITS 1.5:
  1763. // NOTIFICATION COMMAND LINE: NULL
  1764. // REPLY FILE: 10 / 1000 'C:\foo\replyfile'
  1765. //
  1766. bcout << AddIntensity() << L"GUID: " << ResetIntensity() << id << AddIntensity() << L" DISPLAY: " << ResetIntensity() << Display << L"\n";
  1767. bcout << AddIntensity() << L"TYPE: " << ResetIntensity() << type;
  1768. bcout << AddIntensity() << L" STATE: " << ResetIntensity() << state;
  1769. bcout << AddIntensity() << L" OWNER: " << ResetIntensity() << PrintSidString( Owner ) << L"\n";
  1770. bcout << AddIntensity() << L"PRIORITY: " << ResetIntensity() << priority;
  1771. bcout << AddIntensity() << L" FILES: " << ResetIntensity() << progress.FilesTransferred << L" / " << progress.FilesTotal;
  1772. bcout << AddIntensity() << L" BYTES: " << ResetIntensity() << progress.BytesTransferred << L" / ";
  1773. if ( (UINT64)-1 == progress.BytesTotal )
  1774. bcout << L"UNKNOWN";
  1775. else
  1776. bcout << progress.BytesTotal;
  1777. bcout << L"\n";
  1778. bcout << AddIntensity() << L"CREATION TIME: " << ResetIntensity() << times.CreationTime;
  1779. bcout << AddIntensity() << L" MODIFICATION TIME: " << ResetIntensity() << times.ModificationTime << L"\n";
  1780. bcout << AddIntensity() << L"COMPLETION TIME: " << ResetIntensity() << times.TransferCompletionTime << L"\n";
  1781. bcout << AddIntensity() << L"NOTIFY INTERFACE: " << ResetIntensity();
  1782. if ( NotifyAvailable )
  1783. {
  1784. if ( Notify.Get() )
  1785. bcout << L"REGISTERED";
  1786. else
  1787. bcout << L"UNREGISTERED";
  1788. }
  1789. else
  1790. bcout << L"UNAVAILABLE";
  1791. bcout << AddIntensity() << L" NOTIFICATION FLAGS: " << ResetIntensity() << NotifyFlags << L"\n";
  1792. bcout << AddIntensity() << L"RETRY DELAY: " << ResetIntensity() << retrydelay;
  1793. bcout << AddIntensity() << L" NO PROGRESS TIMEOUT: " << ResetIntensity() << noprogresstimeout;
  1794. bcout << AddIntensity() << L" ERROR COUNT: " << ResetIntensity() << ErrorCount << L"\n";
  1795. bcout << AddIntensity() << L"PROXY USAGE: " << ResetIntensity() << ProxyUsage;
  1796. bcout << AddIntensity() << L" PROXY LIST: " << ResetIntensity() << ( (WCHAR*)ProxyList ? (WCHAR*)ProxyList : L"NULL" );
  1797. bcout << AddIntensity() << L" PROXY BYPASS LIST: " << ResetIntensity() << ((WCHAR*)ProxyBypassList ? (WCHAR*)ProxyBypassList : L"NULL" );
  1798. bcout << L"\n";
  1799. if ( Error.Get() )
  1800. bcout << Error;
  1801. bcout << AddIntensity() << L"DESCRIPTION: " << ResetIntensity() << Description << L"\n";
  1802. bcout << AddIntensity() << L"JOB FILES: \n" << ResetIntensity();
  1803. JobListFiles( Job, true );
  1804. if (fShow15Fields)
  1805. {
  1806. bcout << AddIntensity() << L"NOTIFICATION COMMAND LINE: " << ResetIntensity();
  1807. if (wcslen( CmdLine ) > 0)
  1808. {
  1809. bcout << L"'" << CmdLine << L"'\n";
  1810. }
  1811. else
  1812. {
  1813. bcout << L"NULL\n";
  1814. }
  1815. if (type == BG_JOB_TYPE_UPLOAD_REPLY )
  1816. {
  1817. bcout << AddIntensity() << L"REPLY FILE: " << ResetIntensity() << ReplyProgress.BytesTransferred << L" / ";
  1818. if ( (UINT64)-1 == ReplyProgress.BytesTotal )
  1819. bcout << L"UNKNOWN";
  1820. else
  1821. bcout << ReplyProgress.BytesTotal;
  1822. bcout << L" '" << ReplyFileName << L"'\n";
  1823. }
  1824. }
  1825. }
  1826. void JobInfo( int argc, WCHAR **argv )
  1827. {
  1828. if ( ( argc != 1 ) && (argc != 2 ) )
  1829. {
  1830. bcout << L"Invalid argument.\n";
  1831. AppExit(1);
  1832. }
  1833. bool Verbose = false;
  1834. if ( 2 == argc )
  1835. {
  1836. if ( !_wcsicmp( argv[1], L"/VERBOSE" ) )
  1837. Verbose = true;
  1838. else
  1839. {
  1840. bcout << L"Invalid argument.\n";
  1841. AppExit(1);
  1842. }
  1843. }
  1844. SmartJobPointer Job = JobLookup( argv[0] );
  1845. if ( Verbose )
  1846. JobVerboseInfo( Job );
  1847. else
  1848. JobInfo( Job );
  1849. }
  1850. size_t JobList( bool Verbose, bool AllUsers )
  1851. {
  1852. DWORD dwFlags = 0;
  1853. if ( AllUsers )
  1854. dwFlags |= BG_JOB_ENUM_ALL_USERS;
  1855. size_t JobsListed = 0;
  1856. SmartEnumJobsPointer Enum;
  1857. CheckBITSHR( L"Unable to enum jobs", g_Manager->EnumJobs( dwFlags, Enum.GetRecvPointer() ) );
  1858. SmartJobPointer Job;
  1859. while( Enum->Next( 1, Job.GetRecvPointer(), NULL ) == S_OK )
  1860. {
  1861. if ( Verbose )
  1862. {
  1863. JobVerboseInfo( Job );
  1864. bcout << L"\n";
  1865. }
  1866. else
  1867. JobInfo( Job );
  1868. JobsListed++;
  1869. }
  1870. return JobsListed;
  1871. }
  1872. void JobList( int argc, WCHAR **argv )
  1873. {
  1874. if ( argc > 2 )
  1875. {
  1876. bcout << L"Invalid number of arguments.\n";
  1877. AppExit(1);
  1878. }
  1879. bool Verbose = false;
  1880. bool AllUsers = false;
  1881. for( int i = 0; i < argc; i++)
  1882. {
  1883. if ( !_wcsicmp( argv[i], L"/VERBOSE" ) )
  1884. {
  1885. Verbose = true;
  1886. }
  1887. else if ( !_wcsicmp( argv[i], L"/ALLUSERS" ) )
  1888. {
  1889. AllUsers = true;
  1890. }
  1891. else
  1892. {
  1893. bcout << L"Invalid argument.\n";
  1894. AppExit(1);
  1895. }
  1896. }
  1897. ConnectToBITS();
  1898. size_t JobsListed = JobList( Verbose, AllUsers );
  1899. if (!bRawReturn)
  1900. bcout << L"Listed " << JobsListed << L" job(s).\n";
  1901. }
  1902. void JobMonitor( int argc, WCHAR**argv )
  1903. {
  1904. DWORD dwSleepSeconds = 5;
  1905. bool AllUsers = false;
  1906. if ( argc > 3 )
  1907. {
  1908. bcout << L"Invalid number of arguments.\n";
  1909. AppExit( 1 );
  1910. }
  1911. for( int i=0; i < argc; i++ )
  1912. {
  1913. if ( !_wcsicmp( argv[i], L"/ALLUSERS" ) )
  1914. {
  1915. AllUsers = true;
  1916. }
  1917. else if ( !_wcsicmp( argv[i], L"/REFRESH" ) )
  1918. {
  1919. i++;
  1920. if ( i >= argc )
  1921. {
  1922. bcout << L"/REFRESH is missing the refresh rate.";
  1923. AppExit(1);
  1924. }
  1925. dwSleepSeconds = InputULONG( argv[i] );
  1926. }
  1927. else
  1928. {
  1929. bcout << L"Invalid argument.\n";
  1930. AppExit(1);
  1931. }
  1932. }
  1933. if ( GetFileType( bcout.GetHandle() ) != FILE_TYPE_CHAR )
  1934. {
  1935. bcerr << L"/MONITOR will not work with a redirected stdout.\n";
  1936. AppExit(1);
  1937. }
  1938. ConnectToBITS();
  1939. for(;;)
  1940. {
  1941. ClearScreen();
  1942. bcout << L"MONITORING BACKGROUND COPY MANAGER(" << dwSleepSeconds << L" second refresh)\n";
  1943. JobList( false, AllUsers );
  1944. SleepEx( dwSleepSeconds * 1000, TRUE );
  1945. PollShutdown();
  1946. }
  1947. }
  1948. void JobReset( int argc, WCHAR **argv )
  1949. {
  1950. JobValidateArgs( argc, argv, 0 );
  1951. ConnectToBITS();
  1952. ULONG JobsFound = 0;
  1953. ULONG JobsCanceled = 0;
  1954. SmartEnumJobsPointer Enum;
  1955. CheckBITSHR( L"Unable to enum jobs", g_Manager->EnumJobs( 0, Enum.GetRecvPointer() ) );
  1956. SmartJobPointer Job;
  1957. while( Enum->Next( 1, Job.GetRecvPointer(), NULL ) == S_OK )
  1958. {
  1959. JobsFound++;
  1960. if (SUCCEEDED( Job->Cancel() ) )
  1961. {
  1962. bcout << Job << L" canceled.\n";
  1963. JobsCanceled++;
  1964. }
  1965. }
  1966. bcout << JobsCanceled << L" out of " << JobsFound << L" jobs canceled.\n";
  1967. }
  1968. void JobGetProxyUsage( int argc, WCHAR **argv )
  1969. {
  1970. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1971. BG_JOB_PROXY_USAGE ProxyUsage;
  1972. AutoStringPointer ProxyList;
  1973. AutoStringPointer ProxyBypassList;
  1974. CheckBITSHR( L"Unable to get proxy usage",
  1975. Job->GetProxySettings( &ProxyUsage, ProxyList.GetRecvPointer(), ProxyBypassList.GetRecvPointer() ) );
  1976. bcout << ProxyUsage;
  1977. if (!bRawReturn) bcout << L"\n";
  1978. }
  1979. void JobGetProxyList( int argc, WCHAR **argv )
  1980. {
  1981. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1982. BG_JOB_PROXY_USAGE ProxyUsage;
  1983. AutoStringPointer ProxyList;
  1984. AutoStringPointer ProxyBypassList;
  1985. CheckBITSHR( L"Unable to get proxy list",
  1986. Job->GetProxySettings( &ProxyUsage, ProxyList.GetRecvPointer(), ProxyBypassList.GetRecvPointer() ) );
  1987. bcout << ( (WCHAR*)ProxyList ? (WCHAR*)ProxyList : L"NULL");
  1988. if (!bRawReturn) bcout << L"\n";
  1989. }
  1990. void JobGetProxyBypassList( int argc, WCHAR **argv )
  1991. {
  1992. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  1993. BG_JOB_PROXY_USAGE ProxyUsage;
  1994. AutoStringPointer ProxyList;
  1995. AutoStringPointer ProxyBypassList;
  1996. CheckBITSHR( L"Unable to get proxy bypass list",
  1997. Job->GetProxySettings( &ProxyUsage, ProxyList.GetRecvPointer(), ProxyBypassList.GetRecvPointer() ) );
  1998. bcout << ( (WCHAR*)ProxyBypassList ? (WCHAR*)ProxyBypassList : L"NULL");
  1999. if (!bRawReturn) bcout << L"\n";
  2000. }
  2001. WCHAR *
  2002. FindMatching( WCHAR *pStr, WCHAR start, WCHAR finish, ULONG CurrentLevel )
  2003. {
  2004. while( *pStr != L'\0' )
  2005. {
  2006. if ( start == *pStr )
  2007. CurrentLevel++;
  2008. else if ( finish == *pStr )
  2009. CurrentLevel--;
  2010. if ( !CurrentLevel )
  2011. return pStr;
  2012. pStr++;
  2013. }
  2014. return NULL;
  2015. }
  2016. void JobSetProxySettings( int argc, WCHAR **argv )
  2017. {
  2018. JobValidateArgs( argc, argv, 2 );
  2019. SmartJobPointer Job = JobLookup( argv[0] );
  2020. WCHAR *pSettings = argv[1];
  2021. // The format of the settings is usage,<ProxyList>,<ProxyBypassList>
  2022. WCHAR *pEndUsage = wcsstr( pSettings, L"," );
  2023. if ( !pEndUsage )
  2024. pEndUsage = pSettings + wcslen( pSettings );
  2025. size_t UsageSize = ((char*)pEndUsage - (char*)pSettings)/sizeof(WCHAR);
  2026. AutoStringPointer Usage( new WCHAR[UsageSize + 1] );
  2027. memcpy( Usage.Get(), pSettings, UsageSize * sizeof(WCHAR) );
  2028. Usage.Get()[UsageSize] = L'\0';
  2029. BG_JOB_PROXY_USAGE ProxyUsage;
  2030. if ( _wcsicmp( Usage, L"PRECONFIG" ) == 0 )
  2031. {
  2032. ProxyUsage = BG_JOB_PROXY_USAGE_PRECONFIG;
  2033. }
  2034. else if ( _wcsicmp( Usage, L"NO_PROXY" ) == 0 )
  2035. {
  2036. ProxyUsage = BG_JOB_PROXY_USAGE_NO_PROXY;
  2037. }
  2038. else if ( _wcsicmp( Usage, L"OVERRIDE" ) == 0 )
  2039. {
  2040. ProxyUsage = BG_JOB_PROXY_USAGE_OVERRIDE;
  2041. }
  2042. else
  2043. {
  2044. bcout << L"Unknown proxy usage\n";
  2045. AppExit(0);
  2046. }
  2047. if ( BG_JOB_PROXY_USAGE_PRECONFIG == ProxyUsage ||
  2048. BG_JOB_PROXY_USAGE_NO_PROXY == ProxyUsage )
  2049. {
  2050. CheckBITSHR( L"Unable to set proxy settings", Job->SetProxySettings( ProxyUsage, NULL, NULL ) );
  2051. bcout << L"Proxy usage set to " << ProxyUsage << L".\n";
  2052. return;
  2053. }
  2054. if ( L',' != *pEndUsage )
  2055. {
  2056. bcout << L"Missing a , after the proxy usage setting";
  2057. AppExit(1);
  2058. }
  2059. WCHAR *pProxyListStart = pEndUsage + 1; // skip ,
  2060. if ( *pProxyListStart != L'<' )
  2061. {
  2062. bcout << L"Missing a < before the proxy list.\n";
  2063. AppExit(0);
  2064. }
  2065. pProxyListStart++; // skip the <
  2066. WCHAR *pEndProxyList = FindMatching( pProxyListStart, L'<', L'>', 1 );
  2067. if ( !pEndProxyList )
  2068. {
  2069. bcout << L"Missing a matching > after the proxy list.\n";
  2070. AppExit(0);
  2071. }
  2072. size_t ProxyListSize = ((char*)pEndProxyList - (char*)pProxyListStart)/sizeof(WCHAR);
  2073. AutoStringPointer ProxyList( new WCHAR[ ProxyListSize + 1 ] );
  2074. memcpy( ProxyList.Get(), pProxyListStart, ProxyListSize * sizeof(WCHAR) );
  2075. ProxyList.Get()[ ProxyListSize ] = L'\0';
  2076. WCHAR *pProxyBypassListStart = pEndProxyList + 1; // skip >
  2077. if ( *pProxyBypassListStart != L',' )
  2078. {
  2079. bcout << L"Missing a , after the proxy list.\n";
  2080. AppExit(0);
  2081. }
  2082. pProxyBypassListStart += 1; // skip the ,
  2083. if ( *pProxyBypassListStart != L'<' )
  2084. {
  2085. bcout << L"Missing a < before the proxy bypass list.";
  2086. AppExit(0);
  2087. }
  2088. pProxyBypassListStart += 1; // skip the <
  2089. WCHAR *pEndProxyBypassList = FindMatching( pProxyBypassListStart, L'<', L'>', 1 );
  2090. if ( !pEndProxyBypassList )
  2091. {
  2092. bcout << L"Missing a > after the proxy bypass list.";
  2093. AppExit(0);
  2094. }
  2095. size_t ProxyBypassListSize = ((char*)pEndProxyBypassList - (char*)pProxyBypassListStart)/sizeof(WCHAR);
  2096. AutoStringPointer ProxyBypassList( new WCHAR[ ProxyBypassListSize + 1 ] );
  2097. memcpy( ProxyBypassList.Get(), pProxyBypassListStart, ProxyBypassListSize * sizeof(WCHAR) );
  2098. ProxyBypassList.Get()[ ProxyBypassListSize ] = L'\0';
  2099. if ( _wcsicmp( ProxyList, L"NULL" ) == 0 )
  2100. {
  2101. ProxyList.Clear();
  2102. }
  2103. if ( _wcsicmp( ProxyBypassList, L"NULL" ) == 0 )
  2104. {
  2105. ProxyBypassList.Clear();
  2106. }
  2107. CheckBITSHR( L"Unable to set proxy settings", Job->SetProxySettings( ProxyUsage, ProxyList, ProxyBypassList ) );
  2108. bcout << L"Proxy usage set to " << ProxyUsage << L".\n";
  2109. bcout << L"Proxy list set to " << ( (WCHAR*)ProxyList ? (WCHAR*)ProxyList : L"NULL" )<< L".\n";
  2110. bcout << L"Proxy bypass list set to " << ( (WCHAR*)ProxyBypassList ? (WCHAR*)ProxyBypassList : L"NULL" ) << L".\n";
  2111. }
  2112. void JobTakeOwnership( int argc, WCHAR **argv )
  2113. {
  2114. SmartJobPointer Job = JobLookupForNoArg( argc, argv );
  2115. CheckBITSHR( L"Unable to take ownership", Job->TakeOwnership() );
  2116. bcout << L"Took ownership of " << Job << L".\n";
  2117. }
  2118. void PrintBanner()
  2119. {
  2120. const char ProductVer[] = VER_PRODUCTVERSION_STR;
  2121. // double for extra protection
  2122. wchar_t WProductVer[ sizeof(ProductVer) * 2];
  2123. memset( WProductVer, 0, sizeof(WProductVer) );
  2124. mbstowcs( WProductVer, ProductVer, sizeof(ProductVer) );
  2125. bcout <<
  2126. L"\n" <<
  2127. L"BITSADMIN version 1.5 [ " << WProductVer << L" ]\n" <<
  2128. L"BITS administration utility.\n" <<
  2129. L"(C) Copyright 2000-2002 Microsoft Corp.\n" <<
  2130. L"\n";
  2131. }
  2132. const wchar_t UsageLine[] = L"USAGE: BITSADMIN [/RAWRETURN] [/WRAP] command\n";
  2133. void JobHelp()
  2134. {
  2135. bcout << UsageLine;
  2136. bcout <<
  2137. L"The following commands are available:\n"
  2138. L"\n"
  2139. L"/HELP Prints this help \n"
  2140. L"/? Prints this help \n"
  2141. L"/LIST [/ALLUSERS] [/VERBOSE] List the jobs\n"
  2142. L"/MONITOR [/ALLUSERS] [/REFRESH sec] Monitors the copy manager\n"
  2143. L"/RESET Deletes all jobs in the manager\n"
  2144. L"/CREATE display_name Create job\n"
  2145. L"/INFO job [/VERBOSE] Display information about the job\n"
  2146. L"/ADDFILE job remote_url local_name Adds a file to the job\n"
  2147. L"/LISTFILES job Lists the files in the job\n"
  2148. L"/SUSPEND job Suspends the job\n"
  2149. L"/RESUME job Resumes the job\n"
  2150. L"/CANCEL job Cancels the job\n"
  2151. L"/COMPLETE job Completes the job\n"
  2152. L"\n"
  2153. L"/GETTYPE job Retrieves the job type\n"
  2154. L"/GETBYTESTOTAL job Retrieves the size of the job\n"
  2155. L"/GETBYTESTRANSFERRED job Retrieves the number of bytes transferred\n"
  2156. L"/GETFILESTOTAL job Retrieves the number of files in the job\n"
  2157. L"/GETFILESTRANSFERRED job Retrieves the number of files transferred\n"
  2158. L"/GETCREATIONTIME job Retrieves the job creation time\n"
  2159. L"/GETMODIFICATIONTIME job Retrieves the job modification time\n"
  2160. L"/GETCOMPLETIONTIME job Retrieves the job completion time\n"
  2161. L"/GETSTATE job Retrieves the job state\n"
  2162. L"/GETERROR job Retrieves detailed error information\n"
  2163. L"/GETOWNER job Retrieves the job owner\n"
  2164. L"/GETDISPLAYNAME job Retrieves the job display name.\n"
  2165. L"/SETDISPLAYNAME job displayname Sets the job display name.\n"
  2166. L"/GETDESCRIPTION job Retrieves the job description\n"
  2167. L"/SETDESCRIPTION job description Sets the job description\n"
  2168. L"/GETPRIORITY job Retrieves the job priority\n"
  2169. L"/SETPRIORITY job priority Sets the job priority\n"
  2170. L"/GETNOTIFYFLAGS job Retrieves the notify flags\n"
  2171. L"/SETNOTIFYFLAGS job notify_flags Sets the notify flags\n"
  2172. L"/GETNOTIFYINTERFACE job Determines if notify interface is registered\n"
  2173. L"/GETMINRETRYDELAY job Retrieves the retry delay in seconds\n"
  2174. L"/SETMINRETRYDELAY job retry_delay Sets the retry delay in seconds\n"
  2175. L"/GETNOPROGRESSTIMEOUT job Retrieves the no progress timeout in seconds\n"
  2176. L"/SETNOPROGRESSTIMEOUT job timeout Sets the no progress timeout in seconds\n"
  2177. L"/GETERRORCOUNT job Retrieves an error count for the job\n"
  2178. L"/GETPROXYUSAGE job Retries the proxy usage setting\n"
  2179. L"/GETPROXYLIST job Retries the proxy list\n"
  2180. L"/GETPROXYBYPASSLIST job Retries the proxy bypass list\n"
  2181. L"/SETPROXYSETTINGS job use,<List>,<Bypass>Sets the proxy Settings\n"
  2182. L"/TAKEOWNERSHIP job Take ownership of the job\n"
  2183. L"\n"
  2184. L"/SETNOTIFYCMDLINE job connamd-line Sets a command line for job notification\n"
  2185. L"/GETNOTIFYCMDLINE job returns the job's notification command line\n"
  2186. L"\n"
  2187. L"/SetCredentials job {proxy|server} {basic|digest|ntlm|negotiate|passport} username password\n"
  2188. L" adds credentials to a job\n"
  2189. L"/RemoveCredentials job {proxy|server} {basic|digest|ntlm|negotiate|passport} \n"
  2190. L" removes credentials from a job\n"
  2191. L"\n"
  2192. L"the following options are valid for UPLOAD-REPLY jobs only:\n"
  2193. L"\n"
  2194. L"/GETREPLYFILENAME job gets the name of the file containing the server reply\n"
  2195. L"/SETREPLYFILENAME job filespec sets the name of the file containing the server reply\n"
  2196. L"/GETREPLYPROGRESS job gets the number of bytes and progress of the server reply\n"
  2197. L"/GETREPLYDATA job dumps the server's reply data in hex format\n"
  2198. L"\n"
  2199. L"The Following options can be placed before the command:\n"
  2200. L"/RAWRETURN Return data more suitable for parsing\n"
  2201. L"/WRAP Wrap output around console\n"
  2202. L"The /RAWRETURN option strips new line characters and formatting.\nIt is recognized by the "
  2203. L"/CREATE and /GET* commands.\n"
  2204. L"\n";
  2205. }
  2206. void JobHelpAdapter( int, WCHAR ** )
  2207. {
  2208. JobHelp();
  2209. }
  2210. void JobNotImplemented( int, WCHAR ** )
  2211. {
  2212. bcout << L"Not implemented.\n";
  2213. AppExit(1);
  2214. }
  2215. const PARSEENTRY JobParseTableEntries[] =
  2216. {
  2217. {L"/HELP", JobHelpAdapter },
  2218. {L"/?", JobHelpAdapter },
  2219. {L"/LIST", JobList },
  2220. {L"/MONITOR", JobMonitor },
  2221. {L"/RESET", JobReset },
  2222. {L"/CREATE", JobCreate },
  2223. {L"/INFO", JobInfo },
  2224. {L"/ADDFILE", JobAddFile },
  2225. {L"/LISTFILES", JobListFiles },
  2226. {L"/SUSPEND", JobSuspend },
  2227. {L"/RESUME", JobResume },
  2228. {L"/CANCEL", JobCancel },
  2229. {L"/COMPLETE", JobComplete },
  2230. {L"/GETTYPE", JobGetType },
  2231. {L"/GETBYTESTOTAL", JobGetBytesTotal },
  2232. {L"/GETBYTESTRANSFERRED", JobGetBytesTransferred },
  2233. {L"/GETFILESTOTAL", JobGetFilesTotal },
  2234. {L"/GETFILESTRANSFERRED", JobGetFilesTransferred },
  2235. {L"/GETCREATIONTIME", JobGetCreationTime },
  2236. {L"/GETMODIFICATIONTIME", JobGetModificationTime },
  2237. {L"/GETCOMPLETIONTIME", JobGetCompletionTime },
  2238. {L"/GETSTATE", JobGetState },
  2239. {L"/GETERROR", JobGetError },
  2240. {L"/GETOWNER", JobGetOwner },
  2241. {L"/GETDISPLAYNAME", JobGetDisplayName },
  2242. {L"/SETDISPLAYNAME", JobSetDisplayName },
  2243. {L"/GETDESCRIPTION", JobGetDescription },
  2244. {L"/SETDESCRIPTION", JobSetDescription },
  2245. {L"/GETPRIORITY", JobGetPriority },
  2246. {L"/SETPRIORITY", JobSetPriority },
  2247. {L"/GETNOTIFYFLAGS", JobGetNotifyFlags },
  2248. {L"/SETNOTIFYFLAGS", JobSetNotifyFlags },
  2249. {L"/GETNOTIFYINTERFACE", JobGetNotifyInterface },
  2250. {L"/GETMINRETRYDELAY", JobGetMinimumRetryDelay },
  2251. {L"/SETMINRETRYDELAY", JobSetMinimumRetryDelay },
  2252. {L"/GETNOPROGRESSTIMEOUT", JobGetNoProgressTimeout },
  2253. {L"/SETNOPROGRESSTIMEOUT", JobSetNoProgressTimeout },
  2254. {L"/GETERRORCOUNT", JobGetErrorCount },
  2255. {L"/GETPROXYUSAGE", JobGetProxyUsage },
  2256. {L"/GETPROXYLIST", JobGetProxyList },
  2257. {L"/GETPROXYBYPASSLIST", JobGetProxyBypassList },
  2258. {L"/SETPROXYSETTINGS", JobSetProxySettings },
  2259. {L"/TAKEOWNERSHIP", JobTakeOwnership },
  2260. {L"/GETREPLYFILENAME", JobGetReplyFileName },
  2261. {L"/SETREPLYFILENAME", JobSetReplyFileName },
  2262. {L"/GETREPLYPROGRESS", JobGetReplyProgress },
  2263. {L"/GETREPLYDATA", JobGetReplyData },
  2264. {L"/GETNOTIFYCMDLINE", JobGetNotifyCmdLine },
  2265. {L"/SETNOTIFYCMDLINE", JobSetNotifyCmdLine },
  2266. {L"/SETCREDENTIALS", JobSetCredentials },
  2267. {L"/REMOVECREDENTIALS", JobRemoveCredentials },
  2268. {NULL, NULL }
  2269. };
  2270. const PARSETABLE JobParseTable =
  2271. {
  2272. JobParseTableEntries,
  2273. JobHelpAdapter,
  2274. NULL
  2275. };
  2276. void ParseCmdAdapter( int argc, WCHAR **argv, void *pContext )
  2277. {
  2278. ParseCmd( argc, argv, (const PARSETABLE *) pContext );
  2279. }
  2280. BOOL ControlHandler( DWORD Event )
  2281. {
  2282. switch( Event )
  2283. {
  2284. case CTRL_C_EVENT:
  2285. case CTRL_CLOSE_EVENT:
  2286. SignalShutdown( 5000 );
  2287. return TRUE;
  2288. case CTRL_BREAK_EVENT:
  2289. SignalShutdown( 500 );
  2290. return TRUE;
  2291. default:
  2292. return FALSE;
  2293. }
  2294. }
  2295. int _cdecl wmain(int argc, WCHAR **argv )
  2296. {
  2297. DuplicateHandle(
  2298. GetCurrentProcess(), // handle to source process
  2299. GetCurrentThread(), // handle to duplicate
  2300. GetCurrentProcess(), // handle to target process
  2301. &g_MainThreadHandle, // duplicate handle
  2302. 0, // requested access
  2303. TRUE, // handle inheritance option
  2304. DUPLICATE_SAME_ACCESS // optional actions
  2305. );
  2306. SetConsoleCtrlHandler( ControlHandler, TRUE );
  2307. BITSADMINSetThreadUILanguage();
  2308. _wsetlocale (LC_COLLATE, L".OCP" ); // sets the sort order
  2309. _wsetlocale (LC_MONETARY, L".OCP" ); // sets the currency formatting rules
  2310. _wsetlocale (LC_NUMERIC, L".OCP" ); // sets the formatting of numerals
  2311. _wsetlocale (LC_TIME, L".OCP" ); // defines the date/time formatting
  2312. // skip command name
  2313. argc--;
  2314. argv++;
  2315. if ( 0 == argc )
  2316. {
  2317. PrintBanner();
  2318. bcout << UsageLine;
  2319. return 0;
  2320. }
  2321. // parse /RAWRETURN
  2322. if ( argc >= 1 && ( _wcsicmp( argv[0], L"/RAWRETURN" ) == 0 ))
  2323. {
  2324. bRawReturn = true;
  2325. // skip /RAWRETURN
  2326. argc--;
  2327. argv++;
  2328. }
  2329. // parse /WRAP
  2330. if ( argc >= 1 && ( _wcsicmp( argv[0], L"/WRAP" ) == 0 ))
  2331. {
  2332. bWrap = true;
  2333. // skip /WRAP
  2334. argc--;
  2335. argv++;
  2336. }
  2337. if ( !bRawReturn )
  2338. PrintBanner();
  2339. #ifdef DBG
  2340. // parse /COMPUTERNAME
  2341. if ( argc >= 1 && ( _wcsicmp( argv[0], L"/COMPUTERNAME" ) == 0 ))
  2342. {
  2343. argc--;
  2344. argv++;
  2345. if (argc < 1)
  2346. {
  2347. bcout << L"/COMPUTERNAME option is missing the computer name.\n";
  2348. AppExit(1);
  2349. }
  2350. pComputerName = argv[0];
  2351. argc--;
  2352. argv++;
  2353. }
  2354. #endif
  2355. CheckHR( L"Unable to initialize COM", CoInitializeEx(NULL, COINIT_MULTITHREADED ) );
  2356. SetupConsole();
  2357. ParseCmd( argc, argv, &JobParseTable );
  2358. g_Manager.Clear();
  2359. CoUninitialize();
  2360. bcout.FlushBuffer();
  2361. RestoreConsole();
  2362. if ( g_MainThreadHandle )
  2363. CloseHandle( g_MainThreadHandle );
  2364. return 0;
  2365. }