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.

2408 lines
64 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. cliparse.cpp
  5. Abstract:
  6. Implements CLI parsing engine
  7. Author:
  8. Ravisankar Pudipeddi [ravisp] 3-March-2000
  9. Revision History:
  10. --*/
  11. //
  12. // Throughout this parse module, we return E_NOINTERFACE
  13. // to indicate invalid command line syntax/parameters.
  14. // This is to explicitly distinguish from E_INVALIDARG that may
  15. // be returned by the CLI dll: we wish to distinguish a syntax error
  16. // detected by the parser from a syntax error detected by the CLI dll
  17. // because in the latter case we do not print the usage for the interface.
  18. // Whereas for errors detected by the parser, we *do* print the usage.
  19. // This rule needs to be strictly adhered to
  20. //
  21. #include "stdafx.h"
  22. #include "stdlib.h"
  23. #include "cliparse.h"
  24. #include "string.h"
  25. #include "locale.h"
  26. #pragma warning( disable : 4100 )
  27. CComModule _Module;
  28. CComPtr<IWsbTrace> g_pTrace;
  29. #define MAX_ARGS 40
  30. #define MAX_SWITCHES 20
  31. //
  32. // List of all CLI keywords
  33. // TBD: Sort them!
  34. //
  35. RSS_KEYWORD RssInterfaceStrings[] = {
  36. {L"ADMIN", L"AD", ADMIN_IF},
  37. {L"VOLUME", L"VL", VOLUME_IF},
  38. {L"MEDIA", L"MD", MEDIA_IF},
  39. {L"FILE", L"FL", FILE_IF},
  40. {L"SHOW", L"SH", SHOW_IF},
  41. {L"SET", L"ST", SET_IF},
  42. {L"MANAGE", L"MG", MANAGE_IF},
  43. {L"UNMANAGE", L"UM", UNMANAGE_IF},
  44. {L"DELETE", L"DL", DELETE_IF},
  45. {L"JOB", L"JB", JOB_IF},
  46. {L"RECALL", L"RC", RECALL_IF},
  47. {L"SYNCHRONIZE", L"SN", SYNCHRONIZE_IF},
  48. {L"RECREATEMASTER", L"RM", RECREATEMASTER_IF},
  49. {L"HELP", L"/?", HELP_IF},
  50. //
  51. // Duplicate entry for HELP to recognize -? also as a help
  52. // interface
  53. //
  54. {L"HELP", L"-?", HELP_IF},
  55. {NULL, NULL, UNKNOWN_IF}
  56. };
  57. //
  58. // Rss option strings - listed here without the preceding
  59. // '/' or '-' (or whatever that distinguishes a switch from
  60. // an argument)
  61. // TBD: Sort them!
  62. //
  63. RSS_SWITCH_DEFINITION RssSwitchStrings[] = {
  64. {L"RECALLLIMIT", L"LM", RECALLLIMIT_SW, RSS_ARG_DWORD},
  65. {L"MEDIACOPIES", L"MC", MEDIACOPIES_SW, RSS_ARG_DWORD},
  66. {L"SCHEDULE", L"SC", SCHEDULE_SW, RSS_ARG_STRING},
  67. {L"CONCURRENCY", L"CN", CONCURRENCY_SW, RSS_ARG_DWORD},
  68. {L"ADMINEXEMPT", L"AE", ADMINEXEMPT_SW, RSS_ARG_DWORD},
  69. {L"GENERAL", L"GN", GENERAL_SW, RSS_NO_ARG},
  70. {L"MANAGEABLES", L"MS", MANAGEABLES_SW, RSS_NO_ARG},
  71. {L"MANAGED", L"MN", MANAGED_SW, RSS_NO_ARG},
  72. {L"MEDIA", L"MD", MEDIA_SW, RSS_NO_ARG},
  73. {L"DFS", L"DF", DFS_SW, RSS_ARG_DWORD},
  74. {L"SIZE", L"SZ", SIZE_SW, RSS_ARG_DWORD},
  75. {L"ACCESS", L"AC", ACCESS_SW, RSS_ARG_DWORD},
  76. {L"INCLUDE", L"IN", INCLUDE_SW, RSS_ARG_STRING},
  77. {L"EXCLUDE", L"EX", EXCLUDE_SW, RSS_ARG_STRING},
  78. {L"RECURSIVE", L"RC", RECURSIVE_SW, RSS_NO_ARG},
  79. {L"QUICK", L"QK", QUICK_SW, RSS_NO_ARG},
  80. {L"FULL", L"FL", FULL_SW, RSS_NO_ARG},
  81. {L"RULE", L"RL", RULE_SW, RSS_ARG_STRING},
  82. {L"STATISTICS", L"ST", STATISTICS_SW, RSS_NO_ARG},
  83. {L"TYPE", L"TY", TYPE_SW, RSS_ARG_STRING},
  84. {L"RUN", L"RN", RUN_SW, RSS_NO_ARG},
  85. {L"CANCEL", L"CX", CANCEL_SW, RSS_NO_ARG},
  86. {L"WAIT", L"WT", WAIT_SW, RSS_NO_ARG},
  87. {L"COPYSET", L"CS", COPYSET_SW, RSS_ARG_DWORD},
  88. {L"NAME", L"NM", NAME_SW, RSS_ARG_STRING},
  89. {L"STATUS", L"SS", STATUS_SW, RSS_NO_ARG},
  90. {L"CAPACITY", L"CP", CAPACITY_SW, RSS_NO_ARG},
  91. {L"FREESPACE", L"FS", FREESPACE_SW, RSS_NO_ARG},
  92. {L"VERSION", L"VR", VERSION_SW, RSS_NO_ARG},
  93. {L"COPIES", L"CP", COPIES_SW, RSS_NO_ARG},
  94. {L"HELP", L"?", HELP_SW, RSS_NO_ARG},
  95. {NULL, NULL, UNKNOWN_SW, RSS_NO_ARG}
  96. };
  97. RSS_JOB_DEFINITION RssJobTypeStrings[] = {
  98. {L"CREATEFREESPACE", L"F", CreateFreeSpace},
  99. {L"COPYFILES", L"C", CopyFiles},
  100. {L"VALIDATE", L"V", Validate},
  101. {NULL, NULL, InvalidJobType}
  102. };
  103. //
  104. // Global arrays of arguments and switches
  105. // These will be used as 'known' entities by all
  106. // the interface implementations instead of passing
  107. // them around as parameters
  108. //
  109. LPWSTR Args[MAX_ARGS];
  110. RSS_SWITCHES Switches[MAX_SWITCHES];
  111. DWORD NumberOfArguments = 0;
  112. DWORD NumberOfSwitches = 0;
  113. //
  114. // Useful macros
  115. //
  116. #define CLIP_ARGS_REQUIRED() { \
  117. if (NumberOfArguments <= 0) { \
  118. WsbThrow(E_NOINTERFACE); \
  119. } \
  120. }
  121. #define CLIP_ARGS_NOT_REQUIRED() { \
  122. if (NumberOfArguments > 0) { \
  123. WsbThrow(E_NOINTERFACE); \
  124. } \
  125. }
  126. #define CLIP_SWITCHES_REQUIRED() { \
  127. if (NumberOfSwitches <= 0) { \
  128. WsbThrow(E_NOINTERFACE); \
  129. } \
  130. }
  131. #define CLIP_SWITCHES_NOT_REQUIRED() { \
  132. if (NumberOfSwitches > 0) { \
  133. WsbThrow(E_NOINTERFACE); \
  134. } \
  135. }
  136. #define CLIP_TRANSLATE_HR_AND_RETURN(__HR) { \
  137. if (__HR == S_OK) { \
  138. return CLIP_ERROR_SUCCESS; \
  139. } else if ((__HR == E_NOINTERFACE) || \
  140. (__HR == E_INVALIDARG)) { \
  141. return CLIP_ERROR_INVALID_PARAMETER; \
  142. } else if (__HR == E_OUTOFMEMORY) { \
  143. return CLIP_ERROR_INSUFFICIENT_MEMORY; \
  144. } else { \
  145. return CLIP_ERROR_UNKNOWN; \
  146. } \
  147. }
  148. #define CLIP_GET_DWORD_ARG(__VAL, __STRING, __STOPSTRING) { \
  149. __VAL = wcstol(__STRING, &(__STOPSTRING), 10); \
  150. if (*(__STOPSTRING) != L'\0') { \
  151. WsbThrow(E_NOINTERFACE); \
  152. } \
  153. }
  154. #define CLIP_VALIDATE_DUPLICATE_DWORD_ARG(__ARG) { \
  155. if ((__ARG) != INVALID_DWORD_ARG) { \
  156. WsbThrow(E_NOINTERFACE); \
  157. } \
  158. }
  159. #define CLIP_VALIDATE_DUPLICATE_POINTER_ARG(__ARG) { \
  160. if ((__ARG) != INVALID_POINTER_ARG) { \
  161. WsbThrow(E_NOINTERFACE); \
  162. } \
  163. }
  164. //
  165. // Local function prototypes
  166. //
  167. RSS_INTERFACE
  168. ClipGetInterface(
  169. IN LPWSTR InterfaceString
  170. );
  171. DWORD
  172. ClipGetSwitchTypeIndex(
  173. IN LPWSTR SwitchString
  174. );
  175. HSM_JOB_TYPE
  176. ClipGetJobType(
  177. IN LPWSTR JobTypeString
  178. );
  179. HRESULT
  180. ClipCompileSwitchesAndArgs(
  181. IN LPWSTR CommandLine,
  182. IN RSS_INTERFACE Interface,
  183. IN RSS_INTERFACE SubInterface
  184. );
  185. VOID
  186. ClipCleanup(
  187. VOID
  188. );
  189. HRESULT
  190. ClipAdminShow(
  191. VOID
  192. );
  193. HRESULT
  194. ClipAdminSet(
  195. VOID
  196. );
  197. HRESULT
  198. ClipVolumeShow(
  199. VOID
  200. );
  201. HRESULT
  202. ClipVolumeUnmanage(
  203. VOID
  204. );
  205. HRESULT
  206. ClipVolumeSetManage(
  207. IN BOOL Set
  208. );
  209. HRESULT
  210. ClipVolumeDelete(
  211. VOID
  212. );
  213. HRESULT
  214. ClipVolumeJob(
  215. VOID
  216. );
  217. HRESULT
  218. ClipMediaShow(
  219. VOID
  220. );
  221. HRESULT
  222. ClipMediaSynchronize(
  223. VOID
  224. );
  225. HRESULT
  226. ClipMediaRecreateMaster(
  227. VOID
  228. );
  229. HRESULT
  230. ClipMediaDelete(
  231. VOID
  232. );
  233. HRESULT
  234. ClipFileRecall(
  235. VOID
  236. );
  237. VOID
  238. ClipHelp(
  239. IN RSS_INTERFACE Interface,
  240. IN RSS_INTERFACE SubInterface
  241. );
  242. HRESULT
  243. ClipParseTime(
  244. IN LPWSTR TimeString,
  245. OUT PSYSTEMTIME ScheduledTime
  246. );
  247. HRESULT
  248. ClipParseSchedule(
  249. IN LPWSTR ScheduleString,
  250. OUT PHSM_JOB_SCHEDULE Schedule
  251. );
  252. BOOL
  253. ClipInitializeTrace(
  254. VOID
  255. );
  256. VOID
  257. ClipUninitializeTrace(
  258. VOID
  259. );
  260. VOID
  261. ClipHandleErrors(
  262. IN HRESULT RetCode,
  263. IN RSS_INTERFACE Interface,
  264. IN RSS_INTERFACE SubInterface
  265. );
  266. //
  267. // Function bodies start here
  268. //
  269. RSS_INTERFACE
  270. ClipGetInterface(
  271. IN LPWSTR InterfaceString
  272. )
  273. /*++
  274. Routine Description:
  275. Maps the interface string that is supplied to an enum
  276. Arguments
  277. InterfaceString - Pointer to the interface string
  278. TBD: implement a binary search
  279. Return Value
  280. UNKNOWN_IF - if the interface string is not recognized
  281. An RSS_INTERFACE value if it is.
  282. --*/
  283. {
  284. DWORD i;
  285. RSS_INTERFACE ret = UNKNOWN_IF;
  286. WsbTraceIn(OLESTR("ClipHandleErrors"), OLESTR(""));
  287. for (i=0 ; TRUE ; i++) {
  288. if (RssInterfaceStrings[i].Long == NULL) {
  289. //
  290. // Reached end of table.
  291. //
  292. break;
  293. } else if ((_wcsicmp(RssInterfaceStrings[i].Short,
  294. InterfaceString) == 0) ||
  295. (_wcsicmp(RssInterfaceStrings[i].Long,
  296. InterfaceString) == 0)) {
  297. ret = RssInterfaceStrings[i].Interface;
  298. break;
  299. }
  300. }
  301. WsbTraceOut(OLESTR("ClipGetInterface"), OLESTR("Interface = <%ls>"), WsbLongAsString((LONG) ret));
  302. return ret;
  303. }
  304. DWORD
  305. ClipGetSwitchTypeIndex(
  306. IN LPWSTR SwitchString
  307. )
  308. /*++
  309. Routine Description
  310. Maps the Switch to an entry in the global list of switches
  311. and returns the index
  312. Arguments
  313. SwitchString - Pointer to switch string
  314. TBD: implement a binary search
  315. Return Value
  316. -1 - If the switch is not recognized
  317. A positive value (index to the entry) if it is
  318. --*/
  319. {
  320. DWORD i;
  321. WsbTraceIn(OLESTR("ClipGetSwitchTypeIndex"), OLESTR(""));
  322. for (i = 0; TRUE; i++) {
  323. if (RssSwitchStrings[i].Long == NULL) {
  324. //
  325. // Reached end of table.
  326. //
  327. i = -1;
  328. break;
  329. } else if ((_wcsicmp(RssSwitchStrings[i].Short,
  330. SwitchString) == 0) ||
  331. (_wcsicmp(RssSwitchStrings[i].Long,
  332. SwitchString) == 0)) {
  333. break;
  334. }
  335. }
  336. WsbTraceOut(OLESTR("ClipGetSwitchTypeIndex"), OLESTR("index = <%ls>"), WsbLongAsString((LONG) i));
  337. return i;
  338. }
  339. HSM_JOB_TYPE
  340. ClipGetJobType(
  341. IN LPWSTR JobTypeString
  342. )
  343. /*++
  344. Routine Description
  345. Maps the job string to an enum
  346. Arguments
  347. JobTypeString - Pointer to JobType string
  348. TBD: implement a binary search
  349. Return Value
  350. InvalidJobType - If the job type is not recognized
  351. HSM_JOB_TYPE value if it is
  352. --*/
  353. {
  354. DWORD i;
  355. HSM_JOB_TYPE jobType = InvalidJobType;
  356. WsbTraceIn(OLESTR("ClipGetJobType"), OLESTR(""));
  357. for (i = 0; TRUE; i++) {
  358. if (RssJobTypeStrings[i].Long == NULL) {
  359. //
  360. // Reached end of table.
  361. //
  362. break;
  363. }
  364. if ((_wcsicmp(RssJobTypeStrings[i].Short,
  365. JobTypeString) == 0) ||
  366. (_wcsicmp(RssJobTypeStrings[i].Long,
  367. JobTypeString) == 0)) {
  368. jobType = RssJobTypeStrings[i].JobType;
  369. break;
  370. }
  371. }
  372. WsbTraceOut(OLESTR("ClipGetJobType"), OLESTR("JobType = <%ls>"), WsbLongAsString((LONG) jobType));
  373. return jobType;
  374. }
  375. HRESULT
  376. ClipCompileSwitchesAndArgs(
  377. IN LPWSTR CommandLine,
  378. IN RSS_INTERFACE Interface,
  379. IN RSS_INTERFACE SubInterface
  380. )
  381. /*++
  382. Routine Description
  383. Parses the passed in string and compiles all switches
  384. (a switch is identified by an appropriate delimiter preceding
  385. it, such as a '/') into a global switches array (along with
  386. the arguments to the switch) and the rest of the parameters
  387. into an Args array
  388. Arguments
  389. CommandLine - String to be parsed
  390. Return Value
  391. S_OK if success
  392. --*/
  393. {
  394. HRESULT hr = S_OK;
  395. WCHAR token[MAX_PATH];
  396. LPWSTR p = CommandLine, pToken = token, switchArg, switchString;
  397. RSS_SWITCH_TYPE switchType;
  398. DWORD index;
  399. BOOL isSwitch, skipSpace;
  400. WsbTraceIn(OLESTR("ClipCompileSwitchesAndArgs"), OLESTR(""));
  401. try {
  402. if (p == NULL) {
  403. WsbThrow(S_OK);
  404. }
  405. while (*p != L'\0') {
  406. if (wcschr(SEPARATORS, *p) != NULL) {
  407. //
  408. // Skip white space
  409. //
  410. p++;
  411. continue;
  412. }
  413. if (wcschr(SWITCH_DELIMITERS, *p) != NULL) {
  414. isSwitch = TRUE;
  415. p++;
  416. if (*p == L'\0') {
  417. //
  418. // Badly formed - a SWITCH_DELIMITER with no switch
  419. //
  420. WsbThrow(E_NOINTERFACE);
  421. }
  422. } else {
  423. isSwitch = FALSE;
  424. }
  425. //
  426. // Get the rest of the word
  427. //
  428. skipSpace = FALSE;
  429. while (*p != L'\0' && *p != L'\n') {
  430. //
  431. // We wish to consider stuff enclosed entirely in
  432. // quotes as a single token. As a result
  433. // we won't consider white space to be a delimiter
  434. // for tokens when they are in quotes.
  435. //
  436. if (*p == QUOTE) {
  437. if (skipSpace) {
  438. //
  439. // A quote was encountered previously.
  440. // This signifies - hence - the end of the token
  441. //
  442. p++;
  443. break;
  444. } else {
  445. //
  446. // Start of quoted string..don't treat whitespace
  447. // as a delimiter anymore, only a quote will end the token
  448. //
  449. skipSpace = TRUE;
  450. p++;
  451. continue;
  452. }
  453. }
  454. if (!skipSpace && (wcschr(SEPARATORS, *p) != NULL)) {
  455. //
  456. // This is not quoted and white space was encountered..
  457. //
  458. break;
  459. }
  460. *pToken++ = *p++;
  461. }
  462. *pToken = L'\0';
  463. if (isSwitch) {
  464. //
  465. // For a switch, we will have to further split it into
  466. // the switch part and the argument part
  467. //
  468. switchString = wcstok(token, SWITCH_ARG_DELIMITERS);
  469. index = ClipGetSwitchTypeIndex(switchString);
  470. if (index == -1) {
  471. //
  472. // Invalid switch. Get out.
  473. //
  474. WsbThrow(E_NOINTERFACE);
  475. }
  476. switchType = RssSwitchStrings[index].SwitchType;
  477. switchArg = wcstok(NULL, L"");
  478. //
  479. // Validation - badly formed commandline if either:
  480. // 1. An argument was supplied and the switch definition indicated
  481. // no argument was required
  482. // OR
  483. // 2. This is a non-SHOW interface (by default show interface
  484. // don't require arguments for options), and an argument was not
  485. // supplied even though the switch definition indicated one is
  486. // required.
  487. //
  488. // 3. This is a SHOW interface and an argument was supplied
  489. //
  490. if ( ((switchArg != NULL) &&
  491. (RssSwitchStrings[index].ArgRequired == RSS_NO_ARG)) ||
  492. ((SubInterface != SHOW_IF) && (switchArg == NULL) &&
  493. (RssSwitchStrings[index].ArgRequired != RSS_NO_ARG)) ||
  494. ((SubInterface == SHOW_IF) && (switchArg != NULL))) {
  495. WsbThrow(E_NOINTERFACE);
  496. }
  497. Switches[NumberOfSwitches].SwitchType = switchType;
  498. if (switchArg != NULL) {
  499. Switches[NumberOfSwitches].Arg = new WCHAR [wcslen(switchArg)+1];
  500. if (Switches[NumberOfSwitches].Arg == NULL) {
  501. WsbThrow(E_OUTOFMEMORY);
  502. }
  503. wcscpy(Switches[NumberOfSwitches].Arg, switchArg);
  504. } else {
  505. //
  506. // No arg for this switch
  507. //
  508. Switches[NumberOfSwitches].Arg = NULL;
  509. }
  510. NumberOfSwitches++;
  511. } else {
  512. //
  513. // This is an argument..
  514. //
  515. Args[NumberOfArguments] = new WCHAR [wcslen(token)+1];
  516. if (Args[NumberOfArguments] == NULL) {
  517. WsbThrow(E_OUTOFMEMORY);
  518. }
  519. wcscpy(Args[NumberOfArguments],
  520. token);
  521. NumberOfArguments++;
  522. }
  523. pToken = token;
  524. }
  525. }WsbCatch(hr);
  526. WsbTraceOut(OLESTR("ClipCompileSwitchesAndArgs"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  527. return hr;
  528. }
  529. VOID
  530. ClipCleanup(VOID)
  531. /*++
  532. Routine Description
  533. Performs global cleanup for CLI parse module.
  534. Mainly - frees up all allocated arguments and switches
  535. Arguments
  536. None
  537. Return Value
  538. None
  539. --*/
  540. {
  541. DWORD i;
  542. WsbTraceIn(OLESTR("ClipCleanup"), OLESTR(""));
  543. for (i = 0; i < NumberOfArguments; i++) {
  544. delete [] Args[i];
  545. }
  546. for (i = 0; i < NumberOfSwitches; i++) {
  547. if (Switches[i].Arg != NULL) {
  548. delete [] Switches[i].Arg;
  549. }
  550. }
  551. WsbTraceOut(OLESTR("ClipCleanup"), OLESTR(""));
  552. }
  553. HRESULT
  554. ClipAdminShow(VOID)
  555. /*++
  556. Routine Description
  557. Implements RSS ADMIN SHOW interface.
  558. Arguments are in global arrays:
  559. Args - containing list of arguments
  560. Switches - containing list of switches
  561. Arguments
  562. None
  563. Return Value
  564. S_OK if everything's ok
  565. E_NOINTERFACE if args/switches are bad
  566. --*/
  567. {
  568. DWORD i;
  569. HRESULT hr;
  570. BOOL recallLimit = FALSE;
  571. BOOL adminExempt = FALSE;
  572. BOOL mediaCopies = FALSE;
  573. BOOL concurrency = FALSE;
  574. BOOL schedule = FALSE;
  575. BOOL general = FALSE;
  576. BOOL manageables = FALSE;
  577. BOOL managed = FALSE;
  578. BOOL media = FALSE;
  579. WsbTraceIn(OLESTR("ClipAdminShow"), OLESTR(""));
  580. try {
  581. //
  582. // No arguments needed for this interface
  583. //
  584. CLIP_ARGS_NOT_REQUIRED();
  585. if (NumberOfSwitches) {
  586. for (i = 0; i < NumberOfSwitches; i++) {
  587. switch (Switches[i].SwitchType) {
  588. case RECALLLIMIT_SW: {
  589. recallLimit = TRUE;
  590. break;
  591. }
  592. case ADMINEXEMPT_SW: {
  593. adminExempt = TRUE;
  594. break;
  595. }
  596. case MEDIACOPIES_SW: {
  597. mediaCopies = TRUE;
  598. break;
  599. }
  600. case CONCURRENCY_SW: {
  601. concurrency = TRUE;
  602. break;
  603. }
  604. case SCHEDULE_SW: {
  605. schedule = TRUE;
  606. break;
  607. }
  608. case GENERAL_SW: {
  609. general = TRUE;
  610. break;
  611. }
  612. case MANAGEABLES_SW: {
  613. manageables = TRUE;
  614. break;
  615. }
  616. case MANAGED_SW: {
  617. managed = TRUE;
  618. break;
  619. }
  620. case MEDIA_SW: {
  621. media = TRUE;
  622. break;
  623. }
  624. default: {
  625. // Unknown switch - get out
  626. WsbThrow(E_NOINTERFACE);
  627. }
  628. }
  629. }
  630. hr = AdminShow(recallLimit,
  631. adminExempt,
  632. mediaCopies,
  633. concurrency,
  634. schedule,
  635. general,
  636. manageables,
  637. managed,
  638. media);
  639. } else {
  640. hr = AdminShow(TRUE,
  641. TRUE,
  642. TRUE,
  643. TRUE,
  644. TRUE,
  645. TRUE,
  646. TRUE,
  647. TRUE,
  648. TRUE);
  649. }
  650. }WsbCatch(hr);
  651. WsbTraceOut(OLESTR("ClipAdminShow"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  652. return hr;
  653. }
  654. HRESULT
  655. ClipAdminSet(VOID)
  656. /*++
  657. Routine Description
  658. Implements RSS ADMIN SET interface.
  659. Arguments are in global arrays:
  660. Args - containing list of arguments
  661. Switches - containing list of switches
  662. Arguments
  663. None
  664. Return Value
  665. S_OK if everything's ok
  666. E_NOINTERFACE if arguments are invalid
  667. --*/
  668. {
  669. DWORD i;
  670. HRESULT hr;
  671. LPWSTR stopString = NULL;
  672. DWORD recallLimit = INVALID_DWORD_ARG;
  673. DWORD adminExempt = INVALID_DWORD_ARG;
  674. DWORD mediaCopies = INVALID_DWORD_ARG;
  675. DWORD concurrency = INVALID_DWORD_ARG;
  676. PHSM_JOB_SCHEDULE schedule = INVALID_POINTER_ARG;
  677. HSM_JOB_SCHEDULE schedAllocated;
  678. WsbTraceIn(OLESTR("ClipAdminSet"), OLESTR(""));
  679. try {
  680. //
  681. // No arguments needed for this interface
  682. //
  683. CLIP_ARGS_NOT_REQUIRED();
  684. if (NumberOfSwitches) {
  685. for (i = 0; i < NumberOfSwitches; i++) {
  686. switch (Switches[i].SwitchType) {
  687. case RECALLLIMIT_SW: {
  688. CLIP_VALIDATE_DUPLICATE_DWORD_ARG(recallLimit);
  689. CLIP_GET_DWORD_ARG(recallLimit,
  690. Switches[i].Arg,
  691. stopString);
  692. break;
  693. }
  694. case ADMINEXEMPT_SW: {
  695. CLIP_VALIDATE_DUPLICATE_DWORD_ARG(adminExempt);
  696. CLIP_GET_DWORD_ARG(adminExempt,
  697. Switches[i].Arg,
  698. stopString);
  699. break;
  700. }
  701. case MEDIACOPIES_SW: {
  702. CLIP_VALIDATE_DUPLICATE_DWORD_ARG(mediaCopies);
  703. CLIP_GET_DWORD_ARG(mediaCopies,
  704. Switches[i].Arg,
  705. stopString);
  706. break;
  707. }
  708. case CONCURRENCY_SW: {
  709. CLIP_VALIDATE_DUPLICATE_DWORD_ARG(concurrency);
  710. CLIP_GET_DWORD_ARG(concurrency,
  711. Switches[i].Arg,
  712. stopString);
  713. break;
  714. }
  715. case SCHEDULE_SW: {
  716. CLIP_VALIDATE_DUPLICATE_POINTER_ARG(schedule);
  717. hr = ClipParseSchedule(Switches[i].Arg,
  718. &schedAllocated);
  719. if (!SUCCEEDED(hr)) {
  720. WsbThrow(E_NOINTERFACE);
  721. } else {
  722. //
  723. // schedAllocated has the schedule
  724. //
  725. schedule = &schedAllocated;
  726. }
  727. break;
  728. }
  729. default: {
  730. // Unknown switch - get out
  731. WsbThrow(E_NOINTERFACE);
  732. }
  733. }
  734. }
  735. }
  736. hr = AdminSet(recallLimit,
  737. adminExempt,
  738. mediaCopies,
  739. concurrency,
  740. schedule);
  741. }WsbCatch(hr);
  742. WsbTraceOut(OLESTR("ClipAdminSet"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  743. return hr;
  744. }
  745. HRESULT
  746. ClipVolumeShow(VOID)
  747. /*++
  748. Routine Description
  749. Implements RSS VOLUME SHOW interface.
  750. Arguments are in global arrays:
  751. Args - containing list of arguments
  752. Switches - containing list of switches
  753. Arguments
  754. None
  755. Return Value
  756. S_OK if everything's ok
  757. E_NOINTERFACE if arguments are invalid
  758. --*/
  759. {
  760. DWORD i;
  761. HRESULT hr;
  762. LPWSTR stopString = NULL;
  763. BOOL dfs = FALSE;
  764. BOOL size = FALSE;
  765. BOOL access = FALSE;
  766. BOOL rules = FALSE;
  767. BOOL statistics = FALSE;
  768. WsbTraceIn(OLESTR("ClipVolumeShow"), OLESTR(""));
  769. try {
  770. //
  771. // Atleast one arg. required for this interface
  772. //
  773. CLIP_ARGS_REQUIRED();
  774. if (NumberOfSwitches == 0) {
  775. dfs = size = access = rules = statistics = TRUE;
  776. } else {
  777. for (i = 0; i < NumberOfSwitches; i++) {
  778. switch (Switches[i].SwitchType) {
  779. case DFS_SW: {
  780. dfs = TRUE;
  781. break;
  782. }
  783. case SIZE_SW: {
  784. size = TRUE;
  785. break;
  786. }
  787. case ACCESS_SW: {
  788. access = TRUE;
  789. break;
  790. }
  791. case RULE_SW: {
  792. rules = TRUE;
  793. break;
  794. }
  795. case STATISTICS_SW: {
  796. statistics = TRUE;
  797. break;
  798. }
  799. default: {
  800. //
  801. // Invalid option
  802. //
  803. WsbThrow(E_NOINTERFACE);
  804. }
  805. }
  806. }
  807. }
  808. hr = VolumeShow(Args,
  809. NumberOfArguments,
  810. dfs,
  811. size,
  812. access,
  813. rules,
  814. statistics);
  815. }WsbCatch(hr);
  816. WsbTraceOut(OLESTR("ClipVolumeShow"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  817. return hr;
  818. }
  819. HRESULT
  820. ClipVolumeUnmanage(VOID)
  821. /*++
  822. Routine Description
  823. Implements RSS VOLUME UNMANAGE interface.
  824. Arguments are in global arrays:
  825. Args - containing list of arguments
  826. Switches - containing list of switches
  827. Arguments
  828. None
  829. Return Value
  830. S_OK if everything's ok
  831. E_NOINTERFACE if arguments are invalid
  832. --*/
  833. {
  834. DWORD i = 0;
  835. HRESULT hr;
  836. #define QUICK_UNMANAGE 0
  837. #define FULL_UNMANAGE 1
  838. DWORD fullOrQuick = INVALID_DWORD_ARG;
  839. WsbTraceIn(OLESTR("ClipVolumeUnmanage"), OLESTR(""));
  840. try {
  841. //
  842. // Atleast one arg. required for this interface
  843. //
  844. CLIP_ARGS_REQUIRED();
  845. if (NumberOfSwitches) {
  846. for (i = 0; i < NumberOfSwitches; i++) {
  847. switch (Switches[i].SwitchType) {
  848. case FULL_SW: {
  849. CLIP_VALIDATE_DUPLICATE_DWORD_ARG(fullOrQuick);
  850. fullOrQuick = FULL_UNMANAGE;
  851. break;
  852. }
  853. case QUICK_SW: {
  854. CLIP_VALIDATE_DUPLICATE_DWORD_ARG(fullOrQuick);
  855. fullOrQuick = QUICK_UNMANAGE;
  856. break;
  857. }
  858. default: {
  859. //
  860. // Invalid option
  861. //
  862. WsbThrow(E_NOINTERFACE);
  863. }
  864. }
  865. }
  866. }
  867. //
  868. // The default for UNMANAGE is quick. So if fullOrQuick is either
  869. // QUICK_UNMANAGE or INVALID_DWORD_ARG, we call unmanage of the quick
  870. // variety
  871. //
  872. hr = VolumeUnmanage(Args,
  873. NumberOfArguments,
  874. (fullOrQuick == FULL_UNMANAGE)? TRUE : FALSE);
  875. }WsbCatch(hr);
  876. WsbTraceOut(OLESTR("ClipVolumeUnmanage"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  877. return hr;
  878. }
  879. HRESULT
  880. ClipVolumeSetManage(IN BOOL Set)
  881. /*++
  882. Routine Description
  883. Implements RSS VOLUME MANAGE & RSS VOLUME SET interfaces.
  884. Arguments are in global arrays:
  885. Args - containing list of arguments
  886. Switches - containing list of switches
  887. Arguments
  888. None
  889. Return Value
  890. CLIP_ERROR_SUCCESS if everything's ok
  891. CLIP_ERROR_INVALID_PARAMETER if args/switches are bad
  892. CLIP_ERROR_UNKNOWN any other error
  893. --*/
  894. {
  895. DWORD i = 0;
  896. HRESULT hr;
  897. LPWSTR stopString = NULL;
  898. DWORD dfs = INVALID_DWORD_ARG;
  899. DWORD size = INVALID_DWORD_ARG;
  900. DWORD access = INVALID_DWORD_ARG;
  901. LPWSTR rulePath = INVALID_POINTER_ARG;
  902. LPWSTR ruleFileSpec = INVALID_POINTER_ARG;
  903. BOOL include = FALSE;
  904. BOOL recursive = FALSE;
  905. WsbTraceIn(OLESTR("ClipVolumeSetManage"), OLESTR(""));
  906. try {
  907. //
  908. // Atleast one arg. required for this interface
  909. //
  910. CLIP_ARGS_REQUIRED();
  911. if (NumberOfSwitches) {
  912. for (i = 0; i < NumberOfSwitches; i++) {
  913. switch (Switches[i].SwitchType) {
  914. case DFS_SW: {
  915. CLIP_VALIDATE_DUPLICATE_DWORD_ARG(dfs);
  916. CLIP_GET_DWORD_ARG(dfs, Switches[i].Arg, stopString);
  917. break;
  918. }
  919. case SIZE_SW: {
  920. CLIP_VALIDATE_DUPLICATE_DWORD_ARG(size);
  921. CLIP_GET_DWORD_ARG(size, Switches[i].Arg, stopString);
  922. break;
  923. }
  924. case ACCESS_SW: {
  925. CLIP_VALIDATE_DUPLICATE_DWORD_ARG(access);
  926. CLIP_GET_DWORD_ARG(access, Switches[i].Arg, stopString);
  927. break;
  928. }
  929. case INCLUDE_SW: {
  930. include = TRUE;
  931. //
  932. // Deliberately fall down to the EXCLUDE case
  933. // (break intentionally omitted)
  934. //
  935. }
  936. case EXCLUDE_SW: {
  937. CLIP_VALIDATE_DUPLICATE_POINTER_ARG(rulePath);
  938. rulePath = wcstok(Switches[i].Arg, RULE_DELIMITERS);
  939. ruleFileSpec = wcstok(NULL, L"");
  940. if (ruleFileSpec == NULL) {
  941. //
  942. // Omission of this indicates all files
  943. //
  944. ruleFileSpec = CLI_ALL_STR;
  945. }
  946. break;
  947. }
  948. case RECURSIVE_SW: {
  949. recursive = TRUE;
  950. break;
  951. }
  952. default: {
  953. WsbThrow(E_NOINTERFACE);
  954. }
  955. }
  956. }
  957. }
  958. //
  959. // Validate the rule arguments
  960. //
  961. if ((rulePath == INVALID_POINTER_ARG) && recursive) {
  962. //
  963. // The recursive flag is valid only if a rule was specified
  964. //
  965. WsbThrow(E_NOINTERFACE);
  966. }
  967. if (Set) {
  968. hr = VolumeSet(Args,
  969. NumberOfArguments,
  970. dfs,
  971. size,
  972. access,
  973. rulePath,
  974. ruleFileSpec,
  975. include,
  976. recursive);
  977. } else {
  978. hr = VolumeManage(Args,
  979. NumberOfArguments,
  980. dfs,
  981. size,
  982. access,
  983. rulePath,
  984. ruleFileSpec,
  985. include,
  986. recursive);
  987. }
  988. }WsbCatch(hr);
  989. WsbTraceOut(OLESTR("ClipVolumeSetManage"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  990. return hr;
  991. }
  992. HRESULT
  993. ClipVolumeDelete(VOID)
  994. /*++
  995. Routine Description
  996. Implements RSS VOLUME DELETE interface.
  997. Arguments are in global arrays:
  998. Args - containing list of arguments
  999. Switches - containing list of switches
  1000. Arguments
  1001. None
  1002. Return Value
  1003. S_OK if everything's ok
  1004. E_NOINTERFACE if arguments are invalid
  1005. --*/
  1006. {
  1007. DWORD i;
  1008. HRESULT hr;
  1009. BOOL rule = FALSE;
  1010. LPWSTR rulePath = INVALID_POINTER_ARG;
  1011. LPWSTR ruleFileSpec = INVALID_POINTER_ARG;
  1012. WsbTraceIn(OLESTR("ClipVolumeDelete"), OLESTR(""));
  1013. try {
  1014. //
  1015. // Atleast one arg. required for this interface
  1016. //
  1017. CLIP_ARGS_REQUIRED();
  1018. for (i = 0; i < NumberOfSwitches; i++) {
  1019. switch (Switches[i].SwitchType) {
  1020. case RULE_SW: {
  1021. CLIP_VALIDATE_DUPLICATE_POINTER_ARG(rulePath);
  1022. rule = TRUE;
  1023. rulePath = wcstok(Switches[i].Arg, RULE_DELIMITERS);
  1024. ruleFileSpec = wcstok(NULL, L"");
  1025. if (ruleFileSpec == NULL) {
  1026. //
  1027. // Omission of this indicates all files
  1028. //
  1029. ruleFileSpec = CLI_ALL_STR;
  1030. }
  1031. break;
  1032. }
  1033. default: {
  1034. //
  1035. // Invalid option
  1036. //
  1037. WsbThrow(E_NOINTERFACE);
  1038. }
  1039. }
  1040. }
  1041. //
  1042. // Only deleting rules is supported now
  1043. //
  1044. if (rule) {
  1045. hr = VolumeDeleteRule(Args,
  1046. NumberOfArguments,
  1047. rulePath,
  1048. ruleFileSpec);
  1049. } else {
  1050. hr = E_NOINTERFACE;
  1051. }
  1052. }WsbCatch(hr);
  1053. WsbTraceOut(OLESTR("ClipVolumeDelete"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1054. return hr;
  1055. }
  1056. HRESULT
  1057. ClipVolumeJob(VOID)
  1058. /*++
  1059. Routine Description
  1060. Implements RSS VOLUME JOB interface.
  1061. Arguments are in global arrays:
  1062. Args - containing list of arguments
  1063. Switches - containing list of switches
  1064. Arguments
  1065. None
  1066. Return Value
  1067. S_OK if everything's ok
  1068. E_NOINTERFACE if arguments are invalid
  1069. --*/
  1070. {
  1071. DWORD i;
  1072. HRESULT hr;
  1073. HSM_JOB_TYPE jobType = InvalidJobType;
  1074. #define CANCEL_JOB 0
  1075. #define RUN_JOB 1
  1076. DWORD runOrCancel = INVALID_DWORD_ARG;
  1077. BOOL synchronous = FALSE;
  1078. WsbTraceIn(OLESTR("ClipVolumeJob"), OLESTR(""));
  1079. try {
  1080. //
  1081. // Atleast one arg. required for this interface
  1082. //
  1083. CLIP_ARGS_REQUIRED();
  1084. for (i = 0; i < NumberOfSwitches; i++) {
  1085. switch (Switches[i].SwitchType) {
  1086. case RUN_SW: {
  1087. CLIP_VALIDATE_DUPLICATE_DWORD_ARG(runOrCancel);
  1088. runOrCancel = RUN_JOB;
  1089. break;
  1090. }
  1091. case CANCEL_SW: {
  1092. CLIP_VALIDATE_DUPLICATE_DWORD_ARG(runOrCancel);
  1093. runOrCancel = CANCEL_JOB;
  1094. break;
  1095. }
  1096. case WAIT_SW: {
  1097. synchronous = TRUE;
  1098. break;
  1099. }
  1100. case TYPE_SW: {
  1101. if (jobType != InvalidJobType) {
  1102. //
  1103. // Duplicate switch. Bail
  1104. //
  1105. WsbThrow(E_NOINTERFACE);
  1106. }
  1107. jobType = ClipGetJobType(Switches[i].Arg);
  1108. if (jobType == InvalidJobType) {
  1109. //
  1110. // Invalid job type supplied..
  1111. //
  1112. WsbThrow(E_NOINTERFACE);
  1113. }
  1114. break;
  1115. }
  1116. default: {
  1117. WsbThrow(E_NOINTERFACE);
  1118. }
  1119. }
  1120. }
  1121. //
  1122. // More validation:
  1123. // job type should be valid i.e., specified
  1124. //
  1125. if (jobType == InvalidJobType) {
  1126. WsbThrow(E_NOINTERFACE);
  1127. }
  1128. //
  1129. // Run is the default.. (i.e. TRUE). So if runOrCancel is either
  1130. // INVALID_DWORD_ARG or RUN_JOB, we pass TRUE
  1131. //
  1132. hr = VolumeJob(Args,
  1133. NumberOfArguments,
  1134. jobType,
  1135. (runOrCancel == CANCEL_JOB)? FALSE: TRUE,
  1136. synchronous);
  1137. }WsbCatch(hr);
  1138. WsbTraceOut(OLESTR("ClipVolumeJob"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1139. return hr;
  1140. }
  1141. HRESULT
  1142. ClipMediaShow(VOID)
  1143. /*++
  1144. Routine Description
  1145. Implements RSS MEDIA SHOW interface.
  1146. Arguments are in global arrays:
  1147. Args - containing list of arguments
  1148. Switches - containing list of switches
  1149. Arguments
  1150. None
  1151. Return Value
  1152. S_OK if everything's ok
  1153. E_NOINTERFACE if arguments are invalid
  1154. --*/
  1155. {
  1156. DWORD i;
  1157. HRESULT hr;
  1158. BOOL name = FALSE;
  1159. BOOL status = FALSE;
  1160. BOOL capacity = FALSE;
  1161. BOOL freeSpace = FALSE;
  1162. BOOL version = FALSE;
  1163. BOOL copies = FALSE;
  1164. WsbTraceIn(OLESTR("ClipMediaShow"), OLESTR(""));
  1165. try {
  1166. //
  1167. // Atleast one arg. required for this interface
  1168. //
  1169. CLIP_ARGS_REQUIRED();
  1170. if (NumberOfSwitches == 0) {
  1171. name = status = capacity = freeSpace = version = copies = TRUE;
  1172. } else {
  1173. for (i = 0; i < NumberOfSwitches; i++) {
  1174. switch (Switches[i].SwitchType) {
  1175. case NAME_SW: {
  1176. name = TRUE;
  1177. break;
  1178. }
  1179. case STATUS_SW: {
  1180. status = TRUE;
  1181. break;
  1182. }
  1183. case CAPACITY_SW: {
  1184. capacity = TRUE;
  1185. break;
  1186. }
  1187. case FREESPACE_SW: {
  1188. freeSpace = TRUE;
  1189. break;
  1190. }
  1191. case VERSION_SW: {
  1192. version = TRUE;
  1193. break;
  1194. }
  1195. case COPIES_SW: {
  1196. copies = TRUE;
  1197. break;
  1198. }
  1199. default: {
  1200. //
  1201. // Invalid option
  1202. //
  1203. WsbThrow(E_NOINTERFACE);
  1204. }
  1205. }
  1206. }
  1207. }
  1208. hr = MediaShow(Args,
  1209. NumberOfArguments,
  1210. name,
  1211. status,
  1212. capacity,
  1213. freeSpace,
  1214. version,
  1215. copies);
  1216. }WsbCatch(hr);
  1217. WsbTraceOut(OLESTR("ClipMediaShow"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1218. return hr;
  1219. }
  1220. HRESULT
  1221. ClipMediaSynchronize(VOID)
  1222. /*++
  1223. Routine Description
  1224. Implements RSS MEDIA SYNCHRONIZE interface.
  1225. Arguments are in global arrays:
  1226. Args - containing list of arguments
  1227. Switches - containing list of switches
  1228. Arguments
  1229. None
  1230. Return Value
  1231. S_OK if everything's ok
  1232. E_NOINTERFACE if arguments are invalid
  1233. --*/
  1234. {
  1235. DWORD i;
  1236. HRESULT hr;
  1237. DWORD copySetNumber = INVALID_DWORD_ARG;
  1238. BOOL synchronous = FALSE;
  1239. LPWSTR stopString = NULL;
  1240. WsbTraceIn(OLESTR("ClipMediaSynchronize"), OLESTR(""));
  1241. try {
  1242. //
  1243. // No arguments needed
  1244. //
  1245. CLIP_ARGS_NOT_REQUIRED();
  1246. for (i = 0; i < NumberOfSwitches; i++) {
  1247. switch (Switches[i].SwitchType) {
  1248. case COPYSET_SW: {
  1249. CLIP_VALIDATE_DUPLICATE_DWORD_ARG(copySetNumber);
  1250. CLIP_GET_DWORD_ARG(copySetNumber, Switches[i].Arg, stopString);
  1251. break;
  1252. }
  1253. case WAIT_SW: {
  1254. synchronous = TRUE;
  1255. break;
  1256. }
  1257. default: {
  1258. //
  1259. // Invalid option
  1260. //
  1261. WsbThrow(E_NOINTERFACE);
  1262. }
  1263. }
  1264. }
  1265. //
  1266. // Need copy set number..
  1267. //
  1268. if (copySetNumber == INVALID_DWORD_ARG) {
  1269. //
  1270. // None was specified
  1271. //
  1272. WsbThrow(E_NOINTERFACE);
  1273. }
  1274. hr = MediaSynchronize(copySetNumber, synchronous);
  1275. }WsbCatch(hr);
  1276. WsbTraceOut(OLESTR("ClipMediaRecreateMaster"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1277. return hr;
  1278. }
  1279. HRESULT
  1280. ClipMediaRecreateMaster(VOID)
  1281. /*++
  1282. Routine Description
  1283. Implements RSS MEDIA RECREATEMASTER interface.
  1284. Arguments are in global arrays:
  1285. Args - containing list of arguments
  1286. Switches - containing list of switches
  1287. Arguments
  1288. None
  1289. Return Value
  1290. S_OK if everything's ok
  1291. E_NOINTERFACE if arguments are invalid
  1292. --*/
  1293. {
  1294. DWORD i;
  1295. HRESULT hr;
  1296. DWORD copySetNumber = INVALID_DWORD_ARG;
  1297. LPWSTR stopString = NULL;
  1298. BOOL synchronous = FALSE;
  1299. WsbTraceIn(OLESTR("ClipMediaRecreateMaster"), OLESTR(""));
  1300. try {
  1301. //
  1302. // Atleast one arg required
  1303. //
  1304. CLIP_ARGS_REQUIRED();
  1305. if (NumberOfArguments > 1) {
  1306. //
  1307. // Only one argument supported...
  1308. //
  1309. WsbThrow(E_NOINTERFACE);
  1310. }
  1311. for (i = 0; i < NumberOfSwitches; i++) {
  1312. switch (Switches[i].SwitchType) {
  1313. case COPYSET_SW: {
  1314. CLIP_VALIDATE_DUPLICATE_DWORD_ARG(copySetNumber);
  1315. CLIP_GET_DWORD_ARG(copySetNumber, Switches[i].Arg, stopString);
  1316. break;
  1317. }
  1318. case WAIT_SW: {
  1319. synchronous = TRUE;
  1320. break;
  1321. }
  1322. default: {
  1323. //
  1324. // Invalid option
  1325. //
  1326. WsbThrow(E_NOINTERFACE);
  1327. }
  1328. }
  1329. }
  1330. //
  1331. // Need copy set number..
  1332. //
  1333. if (copySetNumber == INVALID_DWORD_ARG) {
  1334. //
  1335. // None was specified
  1336. //
  1337. WsbThrow(E_NOINTERFACE);
  1338. }
  1339. hr = MediaRecreateMaster(Args[0],
  1340. copySetNumber,
  1341. synchronous);
  1342. }WsbCatch(hr);
  1343. WsbTraceOut(OLESTR("ClipRecreateMaster"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1344. return hr;
  1345. }
  1346. HRESULT
  1347. ClipMediaDelete(VOID)
  1348. /*++
  1349. Routine Description
  1350. Implements RSS MEDIA DELETE interface.
  1351. Arguments are in global arrays:
  1352. Args - containing list of arguments
  1353. Switches - containing list of switches
  1354. Arguments
  1355. None
  1356. Return Value
  1357. S_OK if everything's ok
  1358. E_NOINTERFACE if arguments are invalid
  1359. --*/
  1360. {
  1361. DWORD i;
  1362. HRESULT hr;
  1363. DWORD copySetNumber = INVALID_DWORD_ARG;
  1364. LPWSTR stopString = NULL;
  1365. WsbTraceIn(OLESTR("ClipMediaDelete"), OLESTR(""));
  1366. try {
  1367. //
  1368. // Atleast one arg required
  1369. //
  1370. CLIP_ARGS_REQUIRED();
  1371. for (i = 0; i < NumberOfSwitches; i++) {
  1372. switch (Switches[i].SwitchType) {
  1373. case COPYSET_SW: {
  1374. CLIP_VALIDATE_DUPLICATE_DWORD_ARG(copySetNumber);
  1375. CLIP_GET_DWORD_ARG(copySetNumber, Switches[i].Arg, stopString);
  1376. break;
  1377. }
  1378. default: {
  1379. //
  1380. // Invalid option
  1381. //
  1382. WsbThrow(E_NOINTERFACE);
  1383. }
  1384. }
  1385. }
  1386. //
  1387. // Need copy set number..
  1388. //
  1389. if (copySetNumber == INVALID_DWORD_ARG) {
  1390. //
  1391. // None was specified
  1392. //
  1393. WsbThrow(E_NOINTERFACE);
  1394. }
  1395. hr = MediaDelete(Args,
  1396. NumberOfArguments,
  1397. copySetNumber);
  1398. }WsbCatch(hr);
  1399. WsbTraceOut(OLESTR("ClipMediaDelete"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1400. return hr;
  1401. }
  1402. HRESULT
  1403. ClipFileRecall(VOID)
  1404. /*++
  1405. Routine Description
  1406. Implements RSS FILE RECALL interface.
  1407. Arguments are in global arrays:
  1408. Args - containing list of arguments
  1409. Switches - containing list of switches
  1410. Arguments
  1411. None
  1412. Return Value
  1413. S_OK if everything's ok
  1414. E_NOINTERFACE if arguments are invalid
  1415. --*/
  1416. {
  1417. HRESULT hr;
  1418. WsbTraceIn(OLESTR("ClipFileRecall"), OLESTR(""));
  1419. try {
  1420. //
  1421. // Atleast one arg. required for this interface
  1422. //
  1423. CLIP_ARGS_REQUIRED();
  1424. //
  1425. // No switches supported
  1426. //
  1427. CLIP_SWITCHES_NOT_REQUIRED();
  1428. hr = FileRecall(Args,
  1429. NumberOfArguments);
  1430. }WsbCatch(hr);
  1431. WsbTraceOut(OLESTR("ClipFileRecall"), OLESTR("hr = <%ls>"), WsbHrAsString(hr));
  1432. return hr;
  1433. }
  1434. VOID
  1435. ClipHelp(
  1436. IN RSS_INTERFACE Interface,
  1437. IN RSS_INTERFACE SubInterface
  1438. )
  1439. /*++
  1440. Routine Description
  1441. Prints appropriate help message depending on the interface
  1442. Arguments
  1443. Interface - Specifies interface for which help has to be
  1444. displayed
  1445. SubInterface - Specifies sub-interface for which help has to be
  1446. displayed
  1447. Return Value:
  1448. NONE
  1449. --*/
  1450. {
  1451. #define BREAK_IF_NOT_UNKNOWN_IF(__INTERFACE) { \
  1452. if (((__INTERFACE) != UNKNOWN_IF) && \
  1453. ((__INTERFACE) != HELP_IF)) { \
  1454. break; \
  1455. } \
  1456. }
  1457. WsbTraceIn(OLESTR("ClipHelp"), OLESTR(""));
  1458. switch (Interface) {
  1459. case HELP_IF:
  1460. case UNKNOWN_IF: {
  1461. WsbTraceAndPrint(CLI_MESSAGE_MAIN_HELP, NULL);
  1462. BREAK_IF_NOT_UNKNOWN_IF(SubInterface);
  1463. }
  1464. case ADMIN_IF: {
  1465. switch (SubInterface) {
  1466. case HELP_IF:
  1467. case UNKNOWN_IF:
  1468. case SHOW_IF: {
  1469. WsbTraceAndPrint(CLI_MESSAGE_ADMIN_SHOW_HELP, NULL);
  1470. BREAK_IF_NOT_UNKNOWN_IF(SubInterface);
  1471. }
  1472. case SET_IF: {
  1473. WsbTraceAndPrint(CLI_MESSAGE_ADMIN_SET_HELP, NULL);
  1474. BREAK_IF_NOT_UNKNOWN_IF(SubInterface);
  1475. }
  1476. }
  1477. BREAK_IF_NOT_UNKNOWN_IF(Interface);
  1478. }
  1479. case VOLUME_IF: {
  1480. switch (SubInterface) {
  1481. case HELP_IF:
  1482. case UNKNOWN_IF:
  1483. case SHOW_IF: {
  1484. WsbTraceAndPrint(CLI_MESSAGE_VOLUME_SHOW_HELP, NULL);
  1485. BREAK_IF_NOT_UNKNOWN_IF(SubInterface);
  1486. }
  1487. case SET_IF: {
  1488. WsbTraceAndPrint(CLI_MESSAGE_VOLUME_SET_HELP, NULL);
  1489. BREAK_IF_NOT_UNKNOWN_IF(SubInterface);
  1490. }
  1491. case MANAGE_IF: {
  1492. WsbTraceAndPrint(CLI_MESSAGE_VOLUME_MANAGE_HELP, NULL);
  1493. BREAK_IF_NOT_UNKNOWN_IF(SubInterface);
  1494. }
  1495. case UNMANAGE_IF: {
  1496. WsbTraceAndPrint(CLI_MESSAGE_VOLUME_UNMANAGE_HELP, NULL);
  1497. BREAK_IF_NOT_UNKNOWN_IF(SubInterface);
  1498. }
  1499. case JOB_IF: {
  1500. WsbTraceAndPrint(CLI_MESSAGE_VOLUME_JOB_HELP, NULL);
  1501. BREAK_IF_NOT_UNKNOWN_IF(SubInterface);
  1502. }
  1503. case DELETE_IF: {
  1504. WsbTraceAndPrint(CLI_MESSAGE_VOLUME_DELETE_HELP, NULL);
  1505. BREAK_IF_NOT_UNKNOWN_IF(SubInterface);
  1506. }
  1507. }
  1508. BREAK_IF_NOT_UNKNOWN_IF(Interface);
  1509. }
  1510. case MEDIA_IF: {
  1511. switch (SubInterface) {
  1512. case HELP_IF:
  1513. case UNKNOWN_IF:
  1514. case SHOW_IF: {
  1515. WsbTraceAndPrint(CLI_MESSAGE_MEDIA_SHOW_HELP, NULL);
  1516. BREAK_IF_NOT_UNKNOWN_IF(SubInterface);
  1517. }
  1518. case DELETE_IF: {
  1519. WsbTraceAndPrint(CLI_MESSAGE_MEDIA_DELETE_HELP, NULL);
  1520. BREAK_IF_NOT_UNKNOWN_IF(SubInterface);
  1521. }
  1522. case SYNCHRONIZE_IF: {
  1523. WsbTraceAndPrint(CLI_MESSAGE_MEDIA_SYNCHRONIZE_HELP, NULL);
  1524. BREAK_IF_NOT_UNKNOWN_IF(SubInterface);
  1525. }
  1526. case RECREATEMASTER_IF: {
  1527. WsbTraceAndPrint(CLI_MESSAGE_MEDIA_RECREATEMASTER_HELP, NULL);
  1528. BREAK_IF_NOT_UNKNOWN_IF(SubInterface);
  1529. }
  1530. }
  1531. BREAK_IF_NOT_UNKNOWN_IF(Interface);
  1532. }
  1533. case FILE_IF: {
  1534. switch (SubInterface) {
  1535. case HELP_IF:
  1536. case UNKNOWN_IF:
  1537. case RECALL_IF: {
  1538. WsbTraceAndPrint(CLI_MESSAGE_FILE_RECALL_HELP, NULL);
  1539. BREAK_IF_NOT_UNKNOWN_IF(SubInterface);
  1540. }
  1541. }
  1542. BREAK_IF_NOT_UNKNOWN_IF(Interface);
  1543. }
  1544. }
  1545. WsbTraceOut(OLESTR("ClipHelp"), OLESTR(""));
  1546. }
  1547. HRESULT
  1548. ClipParseTime(
  1549. IN LPWSTR TimeString,
  1550. OUT PSYSTEMTIME ScheduledTime)
  1551. /*++
  1552. Routine Description
  1553. Parses the passed in TimeString as a 24 hour format
  1554. (hh:mm:ss) and sets hour/minute/sec/millisec in the passed
  1555. in SYSTEMTIME structure
  1556. Arguments
  1557. TimeString - String in the format "hh:mm:ss"
  1558. ScheduledTime - Pointer to SYSTEMTIME structure. Time parsed from TimeString
  1559. (if ok) will be used to set hour/min/sec/millisec fields in this struc.
  1560. Return Value
  1561. S_OK - TimeString is valid and time was successfully parsed
  1562. Any other - Syntax error in TimeString
  1563. --*/
  1564. {
  1565. LPWSTR stopString = NULL, hourString = NULL, minuteString = NULL, secondString = NULL;
  1566. DWORD hour, minute, second = 0;
  1567. HRESULT hr = S_OK;
  1568. WsbTraceIn(OLESTR("ClipParseTime"), OLESTR(""));
  1569. try {
  1570. hourString = wcstok(TimeString, HSM_SCHED_TIME_SEPARATORS);
  1571. WsbAssert(hourString != NULL, E_NOINTERFACE);
  1572. CLIP_GET_DWORD_ARG(hour, hourString, stopString);
  1573. if (hour > 23) {
  1574. WsbThrow(E_NOINTERFACE);
  1575. }
  1576. minuteString = wcstok(NULL, HSM_SCHED_TIME_SEPARATORS);
  1577. WsbAssert(minuteString != NULL, E_NOINTERFACE);
  1578. CLIP_GET_DWORD_ARG(minute, minuteString, stopString);
  1579. if (minute > 59) {
  1580. WsbThrow(E_NOINTERFACE);
  1581. }
  1582. secondString = wcstok(NULL, HSM_SCHED_TIME_SEPARATORS);
  1583. if (secondString != NULL) {
  1584. CLIP_GET_DWORD_ARG(second, secondString, stopString);
  1585. if (second > 59) {
  1586. WsbThrow(E_NOINTERFACE);
  1587. }
  1588. }
  1589. ScheduledTime->wHour = (WORD) hour;
  1590. ScheduledTime->wMinute = (WORD) minute;
  1591. ScheduledTime->wSecond = (WORD) second;
  1592. ScheduledTime->wMilliseconds = 0;
  1593. }WsbCatch(hr);
  1594. WsbTraceOut(OLESTR("ClipParseTime"), OLESTR(""));
  1595. return hr;
  1596. }
  1597. HRESULT
  1598. ClipParseSchedule(
  1599. IN LPWSTR ScheduleString,
  1600. OUT PHSM_JOB_SCHEDULE Schedule
  1601. )
  1602. /*++
  1603. Routine Description
  1604. Parses the passed in schedule string, and constructs the canonical schedule
  1605. form (of type HSM_JOB_SCHEDULE)
  1606. Examples of schedule parameter:
  1607. "At 21:03:00"
  1608. "At Startup"
  1609. "At Login"
  1610. "At Idle"
  1611. "Every 1 Week 1 21:03:00"
  1612. "Every 2 Day 21:03:00"
  1613. "Every 1 Month 2 21:03:00"
  1614. Arguments
  1615. ScheduleString - String specifying the schedule in user-readable syntax
  1616. Schedule - Pointer to canonical schedule form will be returned in this var.
  1617. Return Value
  1618. S_OK - Successful, Schedule contains a pointer to the constructed schedule.
  1619. E_OUTOFMEMORY - Lack of sufficient system resources
  1620. Any other error: incorrect schedule specification
  1621. --*/
  1622. {
  1623. LPWSTR token;
  1624. DWORD occurrence;
  1625. HSM_JOB_FREQUENCY frequency;
  1626. SYSTEMTIME scheduledTime;
  1627. DWORD day;
  1628. HRESULT hr = S_OK;
  1629. WsbTraceIn(OLESTR("ClipParseSchedule"), OLESTR(""));
  1630. try {
  1631. token = wcstok(ScheduleString, SEPARATORS);
  1632. WsbAssert(token != NULL, E_NOINTERFACE);
  1633. if (!_wcsicmp(token, HSM_SCHED_AT)) {
  1634. token = wcstok(NULL, SEPARATORS);
  1635. if (token == NULL) {
  1636. //
  1637. // Bad arguments
  1638. //
  1639. WsbThrow(E_NOINTERFACE);
  1640. } else if (!_wcsicmp(token, HSM_SCHED_SYSTEMSTARTUP)) {
  1641. //
  1642. // Once at system startup
  1643. //
  1644. Schedule->Frequency = SystemStartup;
  1645. WsbThrow(S_OK);
  1646. } else if (!_wcsicmp(token, HSM_SCHED_LOGIN)) {
  1647. //
  1648. // Once at login time
  1649. //
  1650. Schedule->Frequency = Login;
  1651. WsbThrow(S_OK);
  1652. } else if (!_wcsicmp(token, HSM_SCHED_IDLE)) {
  1653. //
  1654. // Whenever system's idle
  1655. //
  1656. Schedule->Frequency = WhenIdle;
  1657. WsbThrow(S_OK);
  1658. } else {
  1659. GetSystemTime(&scheduledTime);
  1660. //
  1661. // Once at specified time.
  1662. // Parse the time string and obtain it
  1663. // TBD - Add provision to specify date as well as time
  1664. //
  1665. hr = ClipParseTime(token,
  1666. &scheduledTime);
  1667. WsbAssertHr(hr);
  1668. Schedule->Frequency = Once;
  1669. Schedule->Parameters.Once.Time = scheduledTime;
  1670. WsbThrow(S_OK);
  1671. }
  1672. } else if (!_wcsicmp(token, HSM_SCHED_EVERY)) {
  1673. LPWSTR stopString = NULL;
  1674. //
  1675. // Get the occurrence
  1676. //
  1677. token = wcstok(NULL, SEPARATORS);
  1678. WsbAssert(token != NULL, E_NOINTERFACE);
  1679. CLIP_GET_DWORD_ARG(occurrence, token, stopString);
  1680. //
  1681. // Get the qualifier: Daily/Weekly/Monthly
  1682. //
  1683. token = wcstok(NULL, SEPARATORS);
  1684. WsbAssert(token != NULL, E_NOINTERFACE);
  1685. if (!_wcsicmp(token, HSM_SCHED_DAILY)) {
  1686. frequency = Daily;
  1687. } else if (!_wcsicmp(token, HSM_SCHED_WEEKLY)) {
  1688. frequency = Weekly;
  1689. } else if (!_wcsicmp(token, HSM_SCHED_MONTHLY)) {
  1690. frequency = Monthly;
  1691. } else {
  1692. //
  1693. // Badly constructed argument
  1694. //
  1695. WsbThrow(E_NOINTERFACE);
  1696. }
  1697. //
  1698. // Get current time
  1699. //
  1700. GetSystemTime(&scheduledTime);
  1701. //
  1702. // For weekly/monthly we also need to get the day of the week/month
  1703. // Monday = 1, Sunday = 7 for weekly
  1704. //
  1705. if ((frequency == Weekly) || (frequency == Monthly)) {
  1706. token = wcstok(NULL, SEPARATORS);
  1707. WsbAssert(token != NULL, E_NOINTERFACE);
  1708. CLIP_GET_DWORD_ARG(day, token, stopString);
  1709. //
  1710. // Validate & update the parameters
  1711. //
  1712. if (frequency == Weekly) {
  1713. if (day > 6) {
  1714. WsbThrow(E_NOINTERFACE);
  1715. }
  1716. scheduledTime.wDayOfWeek = (WORD) day;
  1717. }
  1718. if (frequency == Monthly) {
  1719. if ((day > 31) || (day < 1)) {
  1720. WsbThrow(E_NOINTERFACE);
  1721. }
  1722. scheduledTime.wDay = (WORD) day;
  1723. }
  1724. }
  1725. //
  1726. // Fetch the time
  1727. //
  1728. token = wcstok(NULL, SEPARATORS);
  1729. WsbAssert(token != NULL, E_NOINTERFACE);
  1730. hr = ClipParseTime(token,
  1731. &scheduledTime);
  1732. WsbAssertHr(hr);
  1733. Schedule->Frequency = frequency;
  1734. Schedule->Parameters.Daily.Occurrence = occurrence;
  1735. Schedule->Parameters.Daily.Time = scheduledTime;
  1736. } else {
  1737. WsbThrow(E_NOINTERFACE);
  1738. }
  1739. }WsbCatch(hr);
  1740. WsbTraceOut(OLESTR("ClipParseSchedule"), OLESTR(""));
  1741. return hr;
  1742. }
  1743. BOOL
  1744. ClipInitializeTrace(
  1745. VOID
  1746. )
  1747. /*++
  1748. Routine Description
  1749. Initializes the trace/printing mechanism for CLI
  1750. Arguments
  1751. NONE
  1752. Return Value
  1753. TRUE if successful, FALSE otherwise
  1754. --*/
  1755. {
  1756. BOOL ret = TRUE;
  1757. if (S_OK == CoCreateInstance(CLSID_CWsbTrace, 0, CLSCTX_SERVER, IID_IWsbTrace, (void **)&g_pTrace)) {
  1758. CWsbStringPtr tracePath;
  1759. CWsbStringPtr regPath;
  1760. CWsbStringPtr outString;
  1761. // Registry path for CLI settings
  1762. // If those expand beyond Trace settings, this path should go to a header file
  1763. regPath = L"SOFTWARE\\Microsoft\\RemoteStorage\\CLI";
  1764. // Check if tracing path already exists, if not - set it (this should happen only once)
  1765. WsbAffirmHr(outString.Alloc(WSB_TRACE_BUFF_SIZE));
  1766. if ( WsbGetRegistryValueString(NULL, regPath, L"WsbTraceFileName", outString, WSB_TRACE_BUFF_SIZE, 0) != S_OK) {
  1767. // No trace settings yet
  1768. WCHAR *systemPath;
  1769. systemPath = _wgetenv(L"SystemRoot");
  1770. WsbAffirmHr(tracePath.Printf( L"%ls\\System32\\RemoteStorage\\Trace\\RsCli.Trc", systemPath));
  1771. // Set default settings in the Registry
  1772. WsbEnsureRegistryKeyExists(0, regPath);
  1773. WsbSetRegistryValueString(0, regPath, L"WsbTraceFileName", tracePath);
  1774. // Make sure the trace directory exists.
  1775. WsbAffirmHr(tracePath.Printf( L"%ls\\System32\\RemoteStorage", systemPath));
  1776. CreateDirectory(tracePath, 0);
  1777. WsbAffirmHr(tracePath.Printf( L"%ls\\System32\\RemoteStorage\\Trace", systemPath));
  1778. CreateDirectory(tracePath, 0);
  1779. }
  1780. g_pTrace->SetRegistryEntry(regPath);
  1781. g_pTrace->LoadFromRegistry();
  1782. }
  1783. return ret;
  1784. }
  1785. VOID
  1786. ClipUninitializeTrace(
  1787. VOID
  1788. )
  1789. /*++
  1790. Routine Description
  1791. Uninitializes the trace/print mechansim
  1792. Paired with ClipInitializeTrace
  1793. Arguments
  1794. NONE
  1795. Return Value
  1796. NONE
  1797. --*/
  1798. {
  1799. g_pTrace = 0;
  1800. }
  1801. VOID
  1802. ClipHandleErrors(
  1803. IN HRESULT RetCode,
  1804. IN RSS_INTERFACE Interface,
  1805. IN RSS_INTERFACE SubInterface
  1806. )
  1807. /*++
  1808. Routine Description
  1809. Translates the main return value & displays any appropriate
  1810. error messages and returns
  1811. Arguments
  1812. RetCode - Error to handle
  1813. Interface - RSS interface specified in the command
  1814. SubInterface - RSS sub-interface specified in the command
  1815. Return Value
  1816. None
  1817. --*/
  1818. {
  1819. WsbTraceIn(OLESTR("ClipHandleErrors"), OLESTR(""));
  1820. switch (RetCode) {
  1821. case E_INVALIDARG:
  1822. case S_OK:{
  1823. //
  1824. // Nothing to print
  1825. //
  1826. break;}
  1827. case E_NOINTERFACE:{
  1828. WsbTraceAndPrint(CLI_MESSAGE_VALUE_DISPLAY, WsbHrAsString(E_INVALIDARG));
  1829. ClipHelp(Interface,
  1830. SubInterface);
  1831. break;}
  1832. default:{
  1833. WsbTraceAndPrint(CLI_MESSAGE_VALUE_DISPLAY, WsbHrAsString(RetCode));
  1834. break;}
  1835. }
  1836. WsbTraceOut(OLESTR("ClipHandleErrors"), OLESTR(""));
  1837. }
  1838. extern "C"
  1839. int __cdecl
  1840. wmain()
  1841. {
  1842. LPWSTR commandLine, token;
  1843. HRESULT hr = E_NOINTERFACE;
  1844. RSS_INTERFACE intrface = HELP_IF, subInterface = UNKNOWN_IF;
  1845. try {
  1846. WsbAffirmHr(CoInitialize(NULL));
  1847. //
  1848. // Set to OEM page locale
  1849. //
  1850. _wsetlocale(LC_ALL, L".OCP");
  1851. ClipInitializeTrace();
  1852. commandLine = GetCommandLine();
  1853. //
  1854. // Get argv[0] out of the way
  1855. //
  1856. token = wcstok(commandLine, SEPARATORS);
  1857. //
  1858. // Get the interface string
  1859. //
  1860. token = wcstok(NULL, SEPARATORS);
  1861. if (token == NULL) {
  1862. ClipHelp(HELP_IF,
  1863. UNKNOWN_IF);
  1864. hr = S_OK;
  1865. goto exit;
  1866. }
  1867. intrface = ClipGetInterface(token);
  1868. if (intrface == UNKNOWN_IF) {
  1869. hr = E_NOINTERFACE;
  1870. intrface = HELP_IF;
  1871. goto exit;
  1872. }
  1873. if (intrface == HELP_IF) {
  1874. ClipHelp(HELP_IF,
  1875. UNKNOWN_IF);
  1876. hr = S_OK;
  1877. goto exit;
  1878. }
  1879. //
  1880. // Get sub interface string
  1881. //
  1882. token = wcstok(NULL, SEPARATORS);
  1883. if (token == NULL) {
  1884. hr = E_NOINTERFACE;
  1885. goto exit;
  1886. }
  1887. subInterface = ClipGetInterface(token);
  1888. if (subInterface == UNKNOWN_IF) {
  1889. hr = E_NOINTERFACE;
  1890. goto exit;
  1891. }
  1892. if (subInterface == HELP_IF) {
  1893. ClipHelp(intrface,
  1894. UNKNOWN_IF);
  1895. hr = S_OK;
  1896. goto exit;
  1897. }
  1898. //
  1899. // Now compile the switches & arguments into separate arrays
  1900. // First, get the rest of line ..
  1901. //
  1902. token = wcstok(NULL, L"");
  1903. hr = ClipCompileSwitchesAndArgs(token,
  1904. intrface,
  1905. subInterface);
  1906. if (hr != S_OK) {
  1907. goto exit;
  1908. }
  1909. switch (intrface) {
  1910. case ADMIN_IF:{
  1911. if (subInterface == SHOW_IF) {
  1912. hr = ClipAdminShow();
  1913. } else if (subInterface == SET_IF) {
  1914. hr = ClipAdminSet();
  1915. } else {
  1916. hr = E_NOINTERFACE;
  1917. }
  1918. break;
  1919. }
  1920. case VOLUME_IF:{
  1921. if (subInterface == MANAGE_IF) {
  1922. hr = ClipVolumeSetManage(FALSE);
  1923. } else if (subInterface == UNMANAGE_IF) {
  1924. hr = ClipVolumeUnmanage();
  1925. } else if (subInterface == SET_IF) {
  1926. hr = ClipVolumeSetManage(TRUE);
  1927. } else if (subInterface == SHOW_IF) {
  1928. hr = ClipVolumeShow();
  1929. } else if (subInterface == DELETE_IF) {
  1930. hr = ClipVolumeDelete();
  1931. } else if (subInterface == JOB_IF) {
  1932. hr = ClipVolumeJob();
  1933. } else {
  1934. hr = E_NOINTERFACE;
  1935. }
  1936. break;
  1937. }
  1938. case FILE_IF:{
  1939. if (subInterface == RECALL_IF) {
  1940. hr = ClipFileRecall();
  1941. } else {
  1942. hr = E_NOINTERFACE;
  1943. }
  1944. break;
  1945. }
  1946. case MEDIA_IF:{
  1947. if (subInterface == SYNCHRONIZE_IF) {
  1948. hr = ClipMediaSynchronize();
  1949. } else if (subInterface == RECREATEMASTER_IF) {
  1950. hr = ClipMediaRecreateMaster();
  1951. } else if (subInterface == DELETE_IF) {
  1952. hr = ClipMediaDelete();
  1953. } else if (subInterface == SHOW_IF) {
  1954. hr = ClipMediaShow();
  1955. } else {
  1956. hr = E_NOINTERFACE;
  1957. }
  1958. break;
  1959. }
  1960. default:{
  1961. hr = E_NOINTERFACE;
  1962. break;
  1963. }
  1964. }
  1965. exit:
  1966. ClipHandleErrors(hr,
  1967. intrface,
  1968. subInterface);
  1969. ClipCleanup();
  1970. ClipUninitializeTrace();
  1971. CoUninitialize();
  1972. }WsbCatchAndDo(hr,
  1973. WsbTraceAndPrint(CLI_MESSAGE_GENERIC_ERROR, WsbHrAsString(hr));
  1974. );
  1975. CLIP_TRANSLATE_HR_AND_RETURN(hr);
  1976. }