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

2115 lines
50 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. XmlMgr.c
  5. Abstract:
  6. Routines for managing channels in the sac.
  7. Author:
  8. Brian Guarraci (briangu) March, 2001.
  9. Revision History:
  10. --*/
  11. #include "sac.h"
  12. #include "xmlcmd.h"
  13. //
  14. // Definitions for this file.
  15. //
  16. //
  17. // Spinlock macros
  18. //
  19. #if 0
  20. #define INIT_CURRENT_CHANNEL_LOCK() \
  21. KeInitializeMutex( \
  22. &XmlMgrCurrentChannelLock, \
  23. 0 \
  24. ); \
  25. XmlMgrCurrentChannelRefCount = 0;
  26. #define LOCK_CURRENT_CHANNEL() \
  27. KdPrint((":? cclock: %d\r\n", __LINE__)); \
  28. { \
  29. NTSTATUS Status; \
  30. Status = KeWaitForMutexObject( \
  31. &XmlMgrCurrentChannelLock, \
  32. Executive, \
  33. KernelMode, \
  34. FALSE, \
  35. NULL \
  36. ); \
  37. ASSERT(Status == STATUS_SUCCESS); \
  38. } \
  39. ASSERT(XmlMgrCurrentChannelRefCount == 0); \
  40. InterlockedIncrement(&XmlMgrCurrentChannelRefCount);\
  41. ASSERT(XmlMgrCurrentChannelRefCount == 1); \
  42. KdPrint((":) cclock: %d\r\n", __LINE__));
  43. #define UNLOCK_CURRENT_CHANNEL() \
  44. KdPrint((":* cclock: %d\r\n", __LINE__)); \
  45. ASSERT(XmlMgrCurrentChannelRefCount == 1); \
  46. InterlockedDecrement(&XmlMgrCurrentChannelRefCount); \
  47. ASSERT(XmlMgrCurrentChannelRefCount == 0); \
  48. ASSERT(KeReadStateMutex(&XmlMgrCurrentChannelLock)==0); \
  49. ASSERT(KeReleaseMutex(&XmlMgrCurrentChannelLock,FALSE)==0);\
  50. KdPrint((":( cclock: %d\r\n", __LINE__));
  51. #else
  52. #define INIT_CURRENT_CHANNEL_LOCK() \
  53. KeInitializeMutex( \
  54. &XmlMgrCurrentChannelLock, \
  55. 0 \
  56. ); \
  57. XmlMgrCurrentChannelRefCount = 0;
  58. #define LOCK_CURRENT_CHANNEL() \
  59. { \
  60. NTSTATUS Status; \
  61. Status = KeWaitForMutexObject( \
  62. &XmlMgrCurrentChannelLock, \
  63. Executive, \
  64. KernelMode, \
  65. FALSE, \
  66. NULL \
  67. ); \
  68. ASSERT(Status == STATUS_SUCCESS); \
  69. } \
  70. ASSERT(XmlMgrCurrentChannelRefCount == 0); \
  71. InterlockedIncrement(&XmlMgrCurrentChannelRefCount); \
  72. ASSERT(XmlMgrCurrentChannelRefCount == 1);
  73. #define UNLOCK_CURRENT_CHANNEL() \
  74. ASSERT(XmlMgrCurrentChannelRefCount == 1); \
  75. InterlockedDecrement(&XmlMgrCurrentChannelRefCount); \
  76. ASSERT(XmlMgrCurrentChannelRefCount == 0); \
  77. ASSERT(KeReadStateMutex(&XmlMgrCurrentChannelLock)==0); \
  78. ASSERT(KeReleaseMutex(&XmlMgrCurrentChannelLock,FALSE)==0);
  79. #endif
  80. //
  81. // lock for r/w access on current channel globals
  82. //
  83. KMUTEX XmlMgrCurrentChannelLock;
  84. ULONG XmlMgrCurrentChannelRefCount;
  85. BOOLEAN XmlMgrInputInEscape = FALSE;
  86. UCHAR XmlMgrInputBuffer[SAC_VT100_COL_WIDTH];
  87. PSAC_CHANNEL XmlMgrSacChannel = NULL;
  88. #define SAC_CHANNEL_INDEX 0
  89. //
  90. //
  91. //
  92. SAC_CHANNEL_HANDLE XmlMgrCurrentChannelHandle;
  93. //
  94. // The index of the current channel in the global channel list
  95. //
  96. ULONG XmlMgrCurrentChannelIndex = 0;
  97. WCHAR SacOWriteUnicodeValue;
  98. UCHAR SacOWriteUtf8ConversionBuffer[3];
  99. VOID
  100. XmlMgrSerialPortConsumer(
  101. IN PSAC_DEVICE_CONTEXT DeviceContext
  102. );
  103. BOOLEAN
  104. XmlMgrProcessInputLine(
  105. VOID
  106. );
  107. NTSTATUS
  108. XmlMgrInitialize(
  109. VOID
  110. )
  111. /*++
  112. Routine Description:
  113. Initialize the console manager
  114. Arguments:
  115. none
  116. Return Value:
  117. Status
  118. --*/
  119. {
  120. NTSTATUS Status;
  121. PSAC_CMD_OPEN_CHANNEL OpenChannelCmd;
  122. PWSTR XMLBuffer;
  123. //
  124. // Get the global buffer started so that we have room for error messages.
  125. //
  126. if (GlobalBuffer == NULL) {
  127. GlobalBuffer = ALLOCATE_POOL(MEMORY_INCREMENT, GENERAL_POOL_TAG);
  128. if (GlobalBuffer == NULL) {
  129. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC DoRaisePriorityCommand: Exiting (1).\n")));
  130. return STATUS_NO_MEMORY;
  131. }
  132. GlobalBufferSize = MEMORY_INCREMENT;
  133. }
  134. //
  135. // Initialize the Serial port globals
  136. //
  137. INIT_CURRENT_CHANNEL_LOCK();
  138. //
  139. // Lock down the current channel globals
  140. //
  141. // Note: we need to do this here since many of the XmlMgr support
  142. // routines do ASSERTs to ensure the current channel lock is held
  143. //
  144. LOCK_CURRENT_CHANNEL();
  145. //
  146. // Initialize
  147. //
  148. do {
  149. //
  150. // create the open channel cmd that will open the SAC channel
  151. //
  152. Status = ChanMgrCreateOpenChannelCmd(
  153. &OpenChannelCmd,
  154. ChannelTypeRaw,
  155. PRIMARY_SAC_CHANNEL_NAME,
  156. PRIMARY_SAC_CHANNEL_DESCRIPTION,
  157. SAC_CHANNEL_FLAG_PRESERVE,
  158. NULL,
  159. NULL,
  160. PRIMARY_SAC_CHANNEL_APPLICATION_GUID
  161. );
  162. if (! NT_SUCCESS(Status)) {
  163. break;
  164. }
  165. //
  166. // create the SAC channel
  167. //
  168. Status = ChanMgrCreateChannel(
  169. &XmlMgrSacChannel,
  170. OpenChannelCmd
  171. );
  172. FREE_POOL(&OpenChannelCmd);
  173. if (! NT_SUCCESS(Status)) {
  174. break;
  175. }
  176. //
  177. // Make the SAC channel the current channel
  178. //
  179. Status = XmlMgrSetCurrentChannel(
  180. SAC_CHANNEL_INDEX,
  181. XmlMgrSacChannel
  182. );
  183. if (! NT_SUCCESS(Status)) {
  184. break;
  185. }
  186. //
  187. // We are done with the Channel
  188. //
  189. Status = ChanMgrReleaseChannel(XmlMgrSacChannel);
  190. if (! NT_SUCCESS(Status)) {
  191. break;
  192. }
  193. //
  194. // Flush the channel data to the screen
  195. //
  196. Status = XmlMgrDisplayCurrentChannel();
  197. if (! NT_SUCCESS(Status)) {
  198. break;
  199. }
  200. //
  201. // NOTE: this really belongs back in data.c (InitializeDeviceData) since it is
  202. // a global behavior
  203. //
  204. // Send XML machine information to management application
  205. //
  206. // <<<<
  207. Status = TranslateMachineInformationXML(
  208. &XMLBuffer,
  209. NULL
  210. );
  211. if (NT_SUCCESS(Status)) {
  212. XmlMgrSacPutString(XML_VERSION_HEADER);
  213. XmlMgrSacPutString(XMLBuffer);
  214. FREE_POOL(&XMLBuffer);
  215. }
  216. // <<<<
  217. //
  218. // Display the prompt
  219. //
  220. Status = HeadlessDispatch(
  221. HeadlessCmdClearDisplay,
  222. NULL,
  223. 0,
  224. NULL,
  225. NULL
  226. );
  227. if (! NT_SUCCESS(Status)) {
  228. IF_SAC_DEBUG(
  229. SAC_DEBUG_FAILS,
  230. KdPrint(("SAC InitializeDeviceData: Failed dispatch\n")));
  231. }
  232. XmlMgrEventMessage(L"SAC_INITIALIZED");
  233. } while (FALSE);
  234. //
  235. // We are done with the current channel globals
  236. //
  237. UNLOCK_CURRENT_CHANNEL();
  238. return STATUS_SUCCESS;
  239. }
  240. NTSTATUS
  241. XmlMgrShutdown(
  242. VOID
  243. )
  244. /*++
  245. Routine Description:
  246. Shutdown the console manager
  247. Arguments:
  248. none
  249. Return Value:
  250. Status
  251. --*/
  252. {
  253. if (GlobalBuffer) {
  254. FREE_POOL(&GlobalBuffer);
  255. }
  256. return STATUS_SUCCESS;
  257. }
  258. NTSTATUS
  259. XmlMgrDisplayFastChannelSwitchingInterface(
  260. PSAC_CHANNEL Channel
  261. )
  262. /*++
  263. Routine Description:
  264. This routine displays the fast-channel-switching interface
  265. Note: caller must hold channel mutex
  266. Arguments:
  267. Channel - Channel to display
  268. Return Value:
  269. Status
  270. --*/
  271. {
  272. HEADLESS_CMD_POSITION_CURSOR SetCursor;
  273. HEADLESS_CMD_SET_COLOR SetColor;
  274. PCWSTR Message;
  275. NTSTATUS Status;
  276. BOOLEAN bStatus;
  277. ULONG Length;
  278. PWSTR LocalBuffer;
  279. ASSERT(XmlMgrCurrentChannelRefCount == 1);
  280. //
  281. // Display the Fast-Channel-Switching interface
  282. //
  283. LocalBuffer = NULL;
  284. do {
  285. LocalBuffer = ALLOCATE_POOL(0x100 * sizeof(WCHAR), GENERAL_POOL_TAG);
  286. ASSERT(LocalBuffer);
  287. if (!LocalBuffer) {
  288. Status = STATUS_INSUFFICIENT_RESOURCES;
  289. break;
  290. }
  291. //
  292. // We cannot use the standard XmlMgrSacPutString() functions, because those write
  293. // over the channel screen buffer. We force directly onto the terminal here.
  294. //
  295. ASSERT(Utf8ConversionBuffer);
  296. if (!Utf8ConversionBuffer) {
  297. Status = STATUS_INSUFFICIENT_RESOURCES;
  298. break;
  299. }
  300. swprintf(
  301. LocalBuffer,
  302. L"<event type='channel-switch' channel-name='%s'/>\r\n",
  303. ChannelGetName(Channel)
  304. );
  305. //
  306. //
  307. //
  308. ASSERT((wcslen(LocalBuffer) + 1) * sizeof(WCHAR) < Utf8ConversionBufferSize);
  309. bStatus = SacTranslateUnicodeToUtf8(
  310. LocalBuffer,
  311. (PUCHAR)Utf8ConversionBuffer,
  312. Utf8ConversionBufferSize
  313. );
  314. if (! bStatus) {
  315. Status = STATUS_UNSUCCESSFUL;
  316. break;
  317. }
  318. //
  319. // Ensure that the utf8 buffer contains a non-emtpy string
  320. //
  321. Length = strlen(Utf8ConversionBuffer);
  322. ASSERT(Length > 0);
  323. if (Length == 0) {
  324. break;
  325. }
  326. Status = HeadlessDispatch(
  327. HeadlessCmdPutData,
  328. (PUCHAR)Utf8ConversionBuffer,
  329. strlen(Utf8ConversionBuffer) * sizeof(UCHAR),
  330. NULL,
  331. NULL
  332. );
  333. if (! NT_SUCCESS(Status)) {
  334. ASSERT(strlen(Utf8ConversionBuffer) > 0);
  335. break;
  336. }
  337. } while ( FALSE );
  338. if (LocalBuffer) {
  339. FREE_POOL(&LocalBuffer);
  340. }
  341. return Status;
  342. }
  343. NTSTATUS
  344. XmlMgrResetCurrentChannel(
  345. VOID
  346. )
  347. /*++
  348. Routine Description:
  349. This routine makes the SAC the current channel
  350. Note: caller must hold channel mutex
  351. Arguments:
  352. ChannelIndex - The new index of the current channel
  353. NewChannel - the new current channel
  354. Return Value:
  355. Status
  356. --*/
  357. {
  358. NTSTATUS Status;
  359. ASSERT(XmlMgrCurrentChannelRefCount == 1);
  360. Status = XmlMgrSetCurrentChannel(
  361. SAC_CHANNEL_INDEX,
  362. XmlMgrSacChannel
  363. );
  364. if (! NT_SUCCESS(Status)) {
  365. return Status;
  366. }
  367. //
  368. // Flush the buffered channel data to the screen
  369. //
  370. // Note: we don't need to lock down the SAC, since we own it
  371. //
  372. Status = XmlMgrDisplayCurrentChannel();
  373. return Status;
  374. }
  375. NTSTATUS
  376. XmlMgrSetCurrentChannel(
  377. IN ULONG ChannelIndex,
  378. IN PSAC_CHANNEL XmlMgrCurrentChannel
  379. )
  380. /*++
  381. Routine Description:
  382. This routine sets the currently active channel to the one given.
  383. Note: caller must hold channel mutex
  384. Arguments:
  385. ChannelIndex - The new index of the current channel
  386. NewChannel - the new current channel
  387. Return Value:
  388. Status
  389. --*/
  390. {
  391. NTSTATUS Status;
  392. ASSERT(XmlMgrCurrentChannelRefCount == 1);
  393. //
  394. // Update the current channel
  395. //
  396. XmlMgrCurrentChannelIndex = ChannelIndex;
  397. //
  398. // Keep track of the handle
  399. //
  400. XmlMgrCurrentChannelHandle = XmlMgrCurrentChannel->Handle;
  401. //
  402. // Update the sent to screen status
  403. //
  404. XmlMgrCurrentChannel->SentToScreen = FALSE;
  405. return STATUS_SUCCESS;
  406. }
  407. NTSTATUS
  408. XmlMgrDisplayCurrentChannel(
  409. VOID
  410. )
  411. /*++
  412. Routine Description:
  413. This routine sets the currently active channel to the one given. It will transmit
  414. the channel buffer to the terminal if SendToScreen is TRUE.
  415. Note: caller must hold channel mutex
  416. Arguments:
  417. None
  418. Return Value:
  419. Status
  420. --*/
  421. {
  422. NTSTATUS Status;
  423. PSAC_CHANNEL Channel;
  424. ASSERT(XmlMgrCurrentChannelRefCount == 1);
  425. //
  426. // Get the current channel
  427. //
  428. Status = ChanMgrGetByHandle(
  429. XmlMgrCurrentChannelHandle,
  430. &Channel
  431. );
  432. if (! NT_SUCCESS(Status)) {
  433. return Status;
  434. }
  435. //
  436. // The channel buffer has been sent to the screen
  437. //
  438. Channel->SentToScreen = TRUE;
  439. //
  440. // Flush the buffered data to the screen
  441. //
  442. Status = Channel->OFlush(Channel);
  443. //
  444. // We are done with the current channel
  445. //
  446. ChanMgrReleaseChannel(Channel);
  447. return Status;
  448. }
  449. NTSTATUS
  450. XmlMgrAdvanceXmlMgrCurrentChannel(
  451. VOID
  452. )
  453. {
  454. NTSTATUS Status;
  455. ULONG NewIndex;
  456. PSAC_CHANNEL Channel;
  457. ASSERT(XmlMgrCurrentChannelRefCount == 1);
  458. do {
  459. //
  460. // Query the channel manager for an array of currently active channels
  461. //
  462. Status = ChanMgrGetNextActiveChannel(
  463. XmlMgrCurrentChannelIndex,
  464. &NewIndex,
  465. &Channel
  466. );
  467. if (! NT_SUCCESS(Status)) {
  468. break;
  469. }
  470. //
  471. // Change the current channel to the next active channel
  472. //
  473. Status = XmlMgrSetCurrentChannel(
  474. NewIndex,
  475. Channel
  476. );
  477. if (! NT_SUCCESS(Status)) {
  478. break;
  479. }
  480. //
  481. // Let the user know we switched via the Channel switching interface
  482. //
  483. Status = XmlMgrDisplayFastChannelSwitchingInterface(Channel);
  484. if (! NT_SUCCESS(Status)) {
  485. break;
  486. }
  487. //
  488. // We are done with the channel
  489. //
  490. Status = ChanMgrReleaseChannel(Channel);
  491. } while ( FALSE );
  492. return Status;
  493. }
  494. BOOLEAN
  495. XmlMgrIsCurrentChannel(
  496. IN PSAC_CHANNEL Channel
  497. )
  498. /*++
  499. Routine Description:
  500. Determine if the channel in question is the current channel
  501. Arguments:
  502. ChannelHandle - channel handle to compare against
  503. Return Value:
  504. --*/
  505. {
  506. // ASSERT(XmlMgrCurrentChannelRefCount == 1);
  507. //
  508. // Determine if the channel in question is the current channel
  509. //
  510. return ChannelIsEqual(
  511. Channel,
  512. &XmlMgrCurrentChannelHandle
  513. );
  514. }
  515. VOID
  516. XmlMgrWorkerProcessEvents(
  517. IN PSAC_DEVICE_CONTEXT DeviceContext
  518. )
  519. /*++
  520. Routine Description:
  521. This is the routine for the worker thread. It blocks on an event, when
  522. the event is signalled, then that indicates a request is ready to be processed.
  523. Arguments:
  524. DeviceContext - A pointer to this device.
  525. Return Value:
  526. None.
  527. --*/
  528. {
  529. NTSTATUS Status;
  530. KIRQL OldIrql;
  531. PLIST_ENTRY ListEntry;
  532. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC WorkerProcessEvents: Entering.\n")));
  533. //
  534. // Loop forever.
  535. //
  536. while (1) {
  537. //
  538. // Block until there is work to do.
  539. //
  540. Status = KeWaitForSingleObject(
  541. (PVOID)&(DeviceContext->ProcessEvent),
  542. Executive,
  543. KernelMode,
  544. FALSE,
  545. NULL
  546. );
  547. if (DeviceContext->ExitThread) {
  548. KdBreakPoint();
  549. XmlCmdCancelIPIoRequest();
  550. //
  551. // Make sure the user is looking at the SAC
  552. //
  553. XmlMgrResetCurrentChannel();
  554. //
  555. // Issue the shutting down message
  556. //
  557. XmlMgrEventMessage(L"SAC_UNLOADED");
  558. KeSetEvent(&(DeviceContext->ThreadExitEvent), DeviceContext->PriorityBoost, FALSE);
  559. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC WorkerProcessEvents: Terminating.\n")));
  560. PsTerminateSystemThread(STATUS_SUCCESS);
  561. }
  562. switch (Status) {
  563. case STATUS_TIMEOUT:
  564. //
  565. // Do TIMEOUT work
  566. //
  567. break;
  568. default:
  569. //
  570. // Do EVENT work
  571. //
  572. switch ( ProcessingType ) {
  573. case SAC_PROCESS_SERIAL_PORT_BUFFER:
  574. //
  575. // Process teh serial port buffer and return a processing state
  576. //
  577. XmlMgrSerialPortConsumer(DeviceContext);
  578. break;
  579. case SAC_SUBMIT_IOCTL:
  580. if ( !IoctlSubmitted ) {
  581. // submit the notify request with the
  582. // IP driver. This procedure will also
  583. // ensure that it is done only once in
  584. // the lifetime of the driver.
  585. XmlCmdSubmitIPIoRequest();
  586. }
  587. break;
  588. default:
  589. break;
  590. }
  591. break;
  592. }
  593. //
  594. // Reset the process action
  595. //
  596. ProcessingType = SAC_NO_OP;
  597. #if 0
  598. //
  599. // If there is any stuff that got delayed, process it.
  600. //
  601. DoDeferred(DeviceContext);
  602. #endif
  603. }
  604. ASSERT(0);
  605. }
  606. #if 0
  607. VOID
  608. XmlMgrSerialPortConsumer(
  609. IN PSAC_DEVICE_CONTEXT DeviceContext
  610. )
  611. /*++
  612. Routine Description:
  613. This is a DPC routine that is queue'd by DriverEntry. It is used to check for any
  614. user input and then processes them.
  615. Arguments:
  616. DeferredContext - A pointer to the device context.
  617. All other parameters are unused.
  618. Return Value:
  619. None.
  620. --*/
  621. {
  622. NTSTATUS Status;
  623. UCHAR LocalTmpBuffer[4];
  624. PSAC_CHANNEL XmlMgrCurrentChannel;
  625. ULONG i;
  626. UCHAR ch;
  627. do {
  628. //
  629. // Bail if there are no new characters to read
  630. //
  631. if (SerialPortConsumerIndex == SerialPortProducerIndex) {
  632. break;
  633. }
  634. //
  635. // Get new character
  636. //
  637. ch = SerialPortBuffer[SerialPortConsumerIndex];
  638. //
  639. // Compute the new producer index and store it atomically
  640. //
  641. InterlockedExchange(&SerialPortConsumerIndex, (SerialPortConsumerIndex + 1) % SERIAL_PORT_BUFFER_SIZE);
  642. //
  643. //
  644. //
  645. HeadlessDispatch(
  646. HeadlessCmdPutData,
  647. (PUCHAR)&ch,
  648. sizeof(UCHAR),
  649. NULL,
  650. NULL
  651. );
  652. } while ( TRUE );
  653. }
  654. #endif
  655. VOID
  656. XmlMgrSerialPortConsumer(
  657. IN PSAC_DEVICE_CONTEXT DeviceContext
  658. )
  659. /*++
  660. Routine Description:
  661. This is a DPC routine that is queue'd by DriverEntry. It is used to check for any
  662. user input and then processes them.
  663. Arguments:
  664. DeferredContext - A pointer to the device context.
  665. All other parameters are unused.
  666. Return Value:
  667. None.
  668. --*/
  669. {
  670. NTSTATUS Status;
  671. UCHAR LocalTmpBuffer[4];
  672. PSAC_CHANNEL XmlMgrCurrentChannel;
  673. ULONG i;
  674. UCHAR ch;
  675. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE_LOUD, KdPrint(("SAC TimerDpcRoutine: Entering.\n")));
  676. //
  677. // lock down the current channel globals
  678. //
  679. LOCK_CURRENT_CHANNEL();
  680. //
  681. // Get the current channel
  682. //
  683. Status = ChanMgrGetByHandle(
  684. XmlMgrCurrentChannelHandle,
  685. &XmlMgrCurrentChannel
  686. );
  687. if (! NT_SUCCESS(Status)) {
  688. //
  689. // the current channel wasn't found,
  690. // so reset the current channel to the SAC
  691. //
  692. XmlMgrResetCurrentChannel();
  693. //
  694. // We are done with current channel globals
  695. //
  696. UNLOCK_CURRENT_CHANNEL();
  697. return;
  698. }
  699. ASSERT(XmlMgrCurrentChannel != NULL);
  700. GetNextByte:
  701. //
  702. // Bail if there are no new characters to read
  703. //
  704. if (SerialPortConsumerIndex == SerialPortProducerIndex) {
  705. goto XmlMgrSerialPortConsumerDone;
  706. }
  707. //
  708. // Get new character
  709. //
  710. ch = SerialPortBuffer[SerialPortConsumerIndex];
  711. //
  712. // Compute the new producer index and store it atomically
  713. //
  714. InterlockedExchange(&SerialPortConsumerIndex, (SerialPortConsumerIndex + 1) % SERIAL_PORT_BUFFER_SIZE);
  715. //
  716. // Check for <ESC><TAB>
  717. //
  718. if (ch == 0x1B) {
  719. XmlMgrInputInEscape = TRUE;
  720. goto GetNextByte;
  721. } else if ((ch == '\t') && XmlMgrInputInEscape) {
  722. XmlMgrInputInEscape = FALSE;
  723. do {
  724. //
  725. // We are done with the current channel
  726. //
  727. Status = ChanMgrReleaseChannel(XmlMgrCurrentChannel);
  728. if (!NT_SUCCESS(Status)) {
  729. break;
  730. }
  731. //
  732. // Find the next active channel and make it the current
  733. //
  734. Status = XmlMgrAdvanceXmlMgrCurrentChannel();
  735. if (!NT_SUCCESS(Status)) {
  736. break;
  737. }
  738. //
  739. // Get the current channel
  740. //
  741. Status = ChanMgrGetByHandle(
  742. XmlMgrCurrentChannelHandle,
  743. &XmlMgrCurrentChannel
  744. );
  745. } while ( FALSE );
  746. if (! NT_SUCCESS(Status)) {
  747. //
  748. // We are done with current channel globals
  749. //
  750. UNLOCK_CURRENT_CHANNEL();
  751. goto XmlMgrSerialPortConsumerExit;
  752. }
  753. goto GetNextByte;
  754. } else {
  755. //
  756. // If this screen has not yet been displayed, and the user entered a 0
  757. // then switch to the SAC Channel
  758. //
  759. if (!ChannelSentToScreen(XmlMgrCurrentChannel) && ch == '0') {
  760. //
  761. // Notify that we want the current channel to be displayed
  762. //
  763. XmlMgrInputInEscape = FALSE;
  764. do {
  765. //
  766. // We are done with the current channel
  767. //
  768. Status = ChanMgrReleaseChannel(XmlMgrCurrentChannel);
  769. if (!NT_SUCCESS(Status)) {
  770. break;
  771. }
  772. //
  773. // Make the current channel the SAC
  774. //
  775. // Note: There should not be anything modifying the XmlMgrSacChannel
  776. // at this time, so this should be safe
  777. //
  778. Status = XmlMgrResetCurrentChannel();
  779. if (!NT_SUCCESS(Status)) {
  780. break;
  781. }
  782. //
  783. // Get the current channel
  784. //
  785. Status = ChanMgrGetByHandle(
  786. XmlMgrCurrentChannelHandle,
  787. &XmlMgrCurrentChannel
  788. );
  789. } while ( FALSE );
  790. if (! NT_SUCCESS(Status)) {
  791. //
  792. // We are done with current channel globals
  793. //
  794. UNLOCK_CURRENT_CHANNEL();
  795. goto XmlMgrSerialPortConsumerExit;
  796. }
  797. goto GetNextByte;
  798. }
  799. //
  800. // If this screen has not yet been displayed, and the user entered a keystroke,
  801. // then display it.
  802. //
  803. if (!ChannelSentToScreen(XmlMgrCurrentChannel)) {
  804. //
  805. // Notify that we want the current channel to be displayed
  806. //
  807. XmlMgrInputInEscape = FALSE;
  808. do {
  809. //
  810. // We are done with the current channel
  811. //
  812. Status = ChanMgrReleaseChannel(XmlMgrCurrentChannel);
  813. if (!NT_SUCCESS(Status)) {
  814. break;
  815. }
  816. //
  817. // Flush the buffered channel data to the screen
  818. //
  819. Status = XmlMgrDisplayCurrentChannel();
  820. if (!NT_SUCCESS(Status)) {
  821. break;
  822. }
  823. //
  824. // Get the current channel
  825. //
  826. Status = ChanMgrGetByHandle(
  827. XmlMgrCurrentChannelHandle,
  828. &XmlMgrCurrentChannel
  829. );
  830. } while ( FALSE );
  831. if (! NT_SUCCESS(Status)) {
  832. //
  833. // We are done with current channel globals
  834. //
  835. UNLOCK_CURRENT_CHANNEL();
  836. goto XmlMgrSerialPortConsumerExit;
  837. }
  838. goto GetNextByte;
  839. }
  840. //
  841. // If the user was entering ESC-<something>, rebuffer the escape. Note: <esc><esc>
  842. // buffers a single <esc>. This allows sending an real <esc><tab> to the channel.
  843. //
  844. if (XmlMgrInputInEscape && (XmlMgrCurrentChannel != XmlMgrSacChannel) && (ch != 0x1B)) {
  845. LocalTmpBuffer[0] = 0x1B;
  846. Status = XmlMgrCurrentChannel->IWrite(XmlMgrCurrentChannel, LocalTmpBuffer, sizeof(LocalTmpBuffer[0]));
  847. }
  848. XmlMgrInputInEscape = FALSE;
  849. //
  850. // Buffer this input
  851. //
  852. LocalTmpBuffer[0] = ch;
  853. XmlMgrCurrentChannel->IWrite(XmlMgrCurrentChannel, LocalTmpBuffer, sizeof(LocalTmpBuffer[0]));
  854. }
  855. if (XmlMgrCurrentChannel != XmlMgrSacChannel) {
  856. goto GetNextByte;
  857. } else {
  858. //
  859. // Now do processing if the SAC is the active channel.
  860. //
  861. ULONG ResponseLength;
  862. WCHAR wch;
  863. //
  864. // If this is a return, then we are done and need to return the line
  865. //
  866. if ((ch == '\n') || (ch == '\r')) {
  867. XmlMgrSacPutString(L"\r\n");
  868. XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
  869. LocalTmpBuffer[0] = '\0';
  870. XmlMgrCurrentChannel->IWrite(XmlMgrCurrentChannel, LocalTmpBuffer, sizeof(LocalTmpBuffer[0]));
  871. goto StripWhitespaceAndReturnLine;
  872. }
  873. //
  874. // If this is a backspace or delete, then we need to do that.
  875. //
  876. if ((ch == 0x8) || (ch == 0x7F)) { // backspace (^H) or delete
  877. if (ChannelGetLengthOfBufferedInput(XmlMgrCurrentChannel) > 0) {
  878. XmlMgrSacPutString(L"\010 \010");
  879. XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
  880. XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
  881. }
  882. } else if (ch == 0x3) { // Control-C
  883. //
  884. // Terminate the string and return it.
  885. //
  886. XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
  887. LocalTmpBuffer[0] = '\0';
  888. XmlMgrCurrentChannel->IWrite(XmlMgrCurrentChannel, LocalTmpBuffer, sizeof(LocalTmpBuffer[0]));
  889. goto StripWhitespaceAndReturnLine;
  890. } else if (ch == 0x9) { // Tab
  891. //
  892. // Ignore tabs
  893. //
  894. XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
  895. XmlMgrSacPutString(L"\007"); // send a BEL
  896. goto GetNextByte;
  897. } else if (ChannelGetLengthOfBufferedInput(XmlMgrCurrentChannel) == SAC_VT100_COL_WIDTH - 2) {
  898. WCHAR Buffer[4];
  899. //
  900. // We are at the end of the screen - remove the last character from
  901. // the terminal screen and replace it with this one.
  902. //
  903. swprintf(Buffer, L"\010%c", ch);
  904. XmlMgrSacPutString(Buffer);
  905. XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
  906. XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
  907. LocalTmpBuffer[0] = ch;
  908. XmlMgrCurrentChannel->IWrite(XmlMgrCurrentChannel, LocalTmpBuffer, sizeof(LocalTmpBuffer[0]));
  909. } else {
  910. WCHAR Buffer[4];
  911. //
  912. // Echo the character to the screen
  913. //
  914. swprintf(Buffer, L"%c", ch);
  915. XmlMgrSacPutString(Buffer);
  916. }
  917. goto GetNextByte;
  918. StripWhitespaceAndReturnLine:
  919. //
  920. // Before returning the input line, strip off all leading and trailing blanks
  921. //
  922. do {
  923. LocalTmpBuffer[0] = (UCHAR)XmlMgrCurrentChannel->IReadLast(XmlMgrCurrentChannel);
  924. } while (((LocalTmpBuffer[0] == '\0') ||
  925. (LocalTmpBuffer[0] == ' ') ||
  926. (LocalTmpBuffer[0] == '\t')) &&
  927. (ChannelGetLengthOfBufferedInput(XmlMgrCurrentChannel) > 0)
  928. );
  929. XmlMgrCurrentChannel->IWrite(XmlMgrCurrentChannel, LocalTmpBuffer, sizeof(LocalTmpBuffer[0]));
  930. LocalTmpBuffer[0] = '\0';
  931. XmlMgrCurrentChannel->IWrite(XmlMgrCurrentChannel, LocalTmpBuffer, sizeof(LocalTmpBuffer[0]));
  932. do {
  933. ResponseLength = XmlMgrCurrentChannel->IRead(
  934. XmlMgrCurrentChannel,
  935. (PUCHAR)&wch,
  936. sizeof(UCHAR)
  937. );
  938. LocalTmpBuffer[0] = (UCHAR)wch;
  939. } while ((ResponseLength != 0) &&
  940. ((LocalTmpBuffer[0] == ' ') ||
  941. (LocalTmpBuffer[0] == '\t')));
  942. XmlMgrInputBuffer[0] = LocalTmpBuffer[0];
  943. i = 1;
  944. do {
  945. ResponseLength = XmlMgrCurrentChannel->IRead(
  946. XmlMgrCurrentChannel,
  947. (PUCHAR)&wch,
  948. sizeof(UCHAR)
  949. );
  950. XmlMgrInputBuffer[i++] = (UCHAR)wch;
  951. } while (ResponseLength != 0);
  952. //
  953. // Lower case all the characters. We do not use strlwr() or the like, so that
  954. // the SAC (expecting ASCII always) doesn't accidently get DBCS or the like
  955. // translation of the UCHAR stream.
  956. //
  957. for (i = 0; XmlMgrInputBuffer[i] != '\0'; i++) {
  958. if ((XmlMgrInputBuffer[i] >= 'A') && (XmlMgrInputBuffer[i] <= 'Z')) {
  959. XmlMgrInputBuffer[i] = XmlMgrInputBuffer[i] - 'A' + 'a';
  960. }
  961. }
  962. //
  963. // We are done with the current channel
  964. //
  965. Status = ChanMgrReleaseChannel(XmlMgrCurrentChannel);
  966. //
  967. // We are done with the current channel globals
  968. //
  969. UNLOCK_CURRENT_CHANNEL();
  970. if (!NT_SUCCESS(Status)) {
  971. goto XmlMgrSerialPortConsumerExit;
  972. }
  973. //
  974. // Process the input line.
  975. //
  976. if( XmlMgrProcessInputLine() == FALSE ) {
  977. //
  978. // We don't know what this is.
  979. //
  980. XmlMgrSacPutErrorMessage(L"sac", L"SAC_UNKNOWN_COMMAND");
  981. }
  982. #if 0
  983. //
  984. // Put the next command prompt
  985. //
  986. XmlMgrSacPutSimpleMessage(SAC_PROMPT);
  987. #endif
  988. //
  989. //
  990. //
  991. LOCK_CURRENT_CHANNEL();
  992. //
  993. // Get the current channel
  994. //
  995. Status = ChanMgrGetByHandle(
  996. XmlMgrCurrentChannelHandle,
  997. &XmlMgrCurrentChannel
  998. );
  999. if (! NT_SUCCESS(Status)) {
  1000. //
  1001. // We are done with the current channel globals
  1002. //
  1003. UNLOCK_CURRENT_CHANNEL();
  1004. goto XmlMgrSerialPortConsumerExit;
  1005. }
  1006. goto GetNextByte;
  1007. }
  1008. XmlMgrSerialPortConsumerDone:
  1009. //
  1010. // We are done with the current channel
  1011. //
  1012. ChanMgrReleaseChannel(XmlMgrCurrentChannel);
  1013. //
  1014. // We are done with current channel globals
  1015. //
  1016. UNLOCK_CURRENT_CHANNEL();
  1017. XmlMgrSerialPortConsumerExit:
  1018. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE_LOUD, KdPrint(("SAC TimerDpcRoutine: Exiting.\n")));
  1019. return;
  1020. }
  1021. BOOLEAN
  1022. XmlMgrProcessInputLine(
  1023. VOID
  1024. )
  1025. /*++
  1026. Routine Description:
  1027. This routine is called to process an input line.
  1028. Arguments:
  1029. None.
  1030. Return Value:
  1031. None.
  1032. --*/
  1033. {
  1034. PUCHAR InputLine;
  1035. BOOLEAN CommandFound = FALSE;
  1036. InputLine = &(XmlMgrInputBuffer[0]);
  1037. if (!strcmp((LPSTR)InputLine, TLIST_COMMAND_STRING)) {
  1038. XmlCmdDoTlistCommand();
  1039. CommandFound = TRUE;
  1040. } else if ((!strcmp((LPSTR)InputLine, HELP1_COMMAND_STRING)) ||
  1041. (!strcmp((LPSTR)InputLine, HELP2_COMMAND_STRING))) {
  1042. XmlCmdDoHelpCommand();
  1043. CommandFound = TRUE;
  1044. } else if (!strcmp((LPSTR)InputLine, DUMP_COMMAND_STRING)) {
  1045. XmlCmdDoKernelLogCommand();
  1046. CommandFound = TRUE;
  1047. } else if (!strcmp((LPSTR)InputLine, FULLINFO_COMMAND_STRING)) {
  1048. XmlCmdDoFullInfoCommand();
  1049. CommandFound = TRUE;
  1050. } else if (!strcmp((LPSTR)InputLine, PAGING_COMMAND_STRING)) {
  1051. XmlCmdDoPagingCommand();
  1052. CommandFound = TRUE;
  1053. } else if (!strncmp((LPSTR)InputLine,
  1054. CHANNEL_COMMAND_STRING,
  1055. strlen(CHANNEL_COMMAND_STRING))) {
  1056. ULONG Length;
  1057. Length = strlen(CHANNEL_COMMAND_STRING);
  1058. if (((strlen((LPSTR)InputLine) > 1) && (InputLine[Length] == ' ')) ||
  1059. (strlen((LPSTR)InputLine) == strlen(CHANNEL_COMMAND_STRING))) {
  1060. XmlCmdDoChannelCommand(InputLine);
  1061. CommandFound = TRUE;
  1062. }
  1063. } else if (!strncmp((LPSTR)InputLine,
  1064. CMD_COMMAND_STRING,
  1065. strlen(CMD_COMMAND_STRING))) {
  1066. ULONG Length;
  1067. Length = strlen(CMD_COMMAND_STRING);
  1068. if (((strlen((LPSTR)InputLine) > 1) && (InputLine[Length] == ' ')) ||
  1069. (strlen((LPSTR)InputLine) == strlen(CMD_COMMAND_STRING))) {
  1070. XmlCmdDoCmdCommand(InputLine);
  1071. CommandFound = TRUE;
  1072. }
  1073. } else if (!strcmp((LPSTR)InputLine, REBOOT_COMMAND_STRING)) {
  1074. XmlCmdDoRebootCommand(TRUE);
  1075. CommandFound = TRUE;
  1076. } else if (!strcmp((LPSTR)InputLine, SHUTDOWN_COMMAND_STRING)) {
  1077. XmlCmdDoRebootCommand(FALSE);
  1078. CommandFound = TRUE;
  1079. } else if (!strcmp((LPSTR)InputLine, CRASH_COMMAND_STRING)) {
  1080. CommandFound = TRUE;
  1081. XmlCmdDoCrashCommand(); // this call does not return
  1082. } else if (!strncmp((LPSTR)InputLine,
  1083. KILL_COMMAND_STRING,
  1084. sizeof(KILL_COMMAND_STRING) - sizeof(UCHAR))) {
  1085. if ((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) {
  1086. XmlCmdDoKillCommand(InputLine);
  1087. CommandFound = TRUE;
  1088. }
  1089. } else if (!strncmp((LPSTR)InputLine,
  1090. LOWER_COMMAND_STRING,
  1091. sizeof(LOWER_COMMAND_STRING) - sizeof(UCHAR))) {
  1092. if ((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) {
  1093. XmlCmdDoLowerPriorityCommand(InputLine);
  1094. CommandFound = TRUE;
  1095. }
  1096. } else if (!strncmp((LPSTR)InputLine,
  1097. RAISE_COMMAND_STRING,
  1098. sizeof(RAISE_COMMAND_STRING) - sizeof(UCHAR))) {
  1099. if ((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) {
  1100. XmlCmdDoRaisePriorityCommand(InputLine);
  1101. CommandFound = TRUE;
  1102. }
  1103. } else if (!strncmp((LPSTR)InputLine,
  1104. LIMIT_COMMAND_STRING,
  1105. sizeof(LIMIT_COMMAND_STRING) - sizeof(UCHAR))) {
  1106. if ((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) {
  1107. XmlCmdDoLimitMemoryCommand(InputLine);
  1108. CommandFound = TRUE;
  1109. }
  1110. } else if (!strncmp((LPSTR)InputLine,
  1111. TIME_COMMAND_STRING,
  1112. sizeof(TIME_COMMAND_STRING) - sizeof(UCHAR))) {
  1113. if (((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) ||
  1114. (strlen((LPSTR)InputLine) == 1)) {
  1115. XmlCmdDoSetTimeCommand(InputLine);
  1116. CommandFound = TRUE;
  1117. }
  1118. } else if (!strcmp((LPSTR)InputLine, INFORMATION_COMMAND_STRING)) {
  1119. XmlCmdDoMachineInformationCommand();
  1120. CommandFound = TRUE;
  1121. } else if (!strncmp((LPSTR)InputLine,
  1122. SETIP_COMMAND_STRING,
  1123. sizeof(SETIP_COMMAND_STRING) - sizeof(UCHAR))) {
  1124. if (((strlen((LPSTR)InputLine) > 1) && (InputLine[1] == ' ')) ||
  1125. (strlen((LPSTR)InputLine) == 1)) {
  1126. XmlCmdDoSetIpAddressCommand(InputLine);
  1127. CommandFound = TRUE;
  1128. }
  1129. } else if ((InputLine[0] == '\n') || (InputLine[0] == '\0')) {
  1130. CommandFound = TRUE;
  1131. }
  1132. return CommandFound;
  1133. }
  1134. //
  1135. // Utility routines for writing to the SAC
  1136. //
  1137. BOOLEAN
  1138. XmlMgrChannelEventMessage(
  1139. PCWSTR String,
  1140. PCWSTR ChannelName
  1141. )
  1142. /*++
  1143. Routine Description:
  1144. This routine deploys an event message
  1145. Arguments:
  1146. String - The string to display.
  1147. Return Value:
  1148. None.
  1149. --*/
  1150. {
  1151. //
  1152. // Currently, event messages are sent to the SAC channel
  1153. //
  1154. XmlMgrSacPutString(L"<event type='channel' name='");
  1155. XmlMgrSacPutString(String);
  1156. XmlMgrSacPutString(L"' channel-name='");
  1157. XmlMgrSacPutString(ChannelName);
  1158. XmlMgrSacPutString(L"'/>\r\n");
  1159. return TRUE;
  1160. }
  1161. BOOLEAN
  1162. XmlMgrEventMessage(
  1163. PCWSTR String
  1164. )
  1165. /*++
  1166. Routine Description:
  1167. This routine deploys an event message
  1168. Arguments:
  1169. String - The string to display.
  1170. Return Value:
  1171. None.
  1172. --*/
  1173. {
  1174. //
  1175. // Currently, event messages are sent to the SAC channel
  1176. //
  1177. XmlMgrSacPutString(L"<event type='global' name='");
  1178. XmlMgrSacPutString(String);
  1179. XmlMgrSacPutString(L"'/>\r\n");
  1180. return TRUE;
  1181. }
  1182. VOID
  1183. XmlMgrSacPutString(
  1184. PCWSTR String
  1185. )
  1186. /*++
  1187. Routine Description:
  1188. This routine takes a string and packages it into a command structure for the
  1189. HeadlessDispatch routine.
  1190. Arguments:
  1191. String - The string to display.
  1192. Return Value:
  1193. None.
  1194. --*/
  1195. {
  1196. ULONG StringLength;
  1197. ULONG UTF8Length;
  1198. WCHAR wchBuffer[2];
  1199. BOOLEAN bStatus;
  1200. ULONG i;
  1201. NTSTATUS Status;
  1202. PUCHAR LocalUtf8ConversionBuffer;
  1203. ULONG LocalUtf8ConversionBufferSize;
  1204. LocalUtf8ConversionBufferSize = 0x4 * sizeof(UCHAR);
  1205. LocalUtf8ConversionBuffer = ALLOCATE_POOL(LocalUtf8ConversionBufferSize, GENERAL_POOL_TAG);
  1206. ASSERT(LocalUtf8ConversionBuffer);
  1207. if (!LocalUtf8ConversionBuffer) {
  1208. IF_SAC_DEBUG(
  1209. SAC_DEBUG_FAILS,
  1210. KdPrint(("SAC XmlMgrSacPutString: Failed allocating utf8 buffer.\n"))
  1211. );
  1212. return;
  1213. }
  1214. ASSERT(FIELD_OFFSET(HEADLESS_CMD_PUT_STRING, String) == 0); // ASSERT if anyone changes this structure.
  1215. StringLength = wcslen(String);
  1216. for (i = 0; i < StringLength; i++) {
  1217. wchBuffer[0] = String[i];
  1218. wchBuffer[1] = UNICODE_NULL;
  1219. bStatus = SacTranslateUnicodeToUtf8(
  1220. (PCWSTR)wchBuffer,
  1221. LocalUtf8ConversionBuffer,
  1222. LocalUtf8ConversionBufferSize
  1223. );
  1224. if (! bStatus) {
  1225. Status = STATUS_UNSUCCESSFUL;
  1226. IF_SAC_DEBUG(
  1227. SAC_DEBUG_FAILS,
  1228. KdPrint(("SAC XmlMgrSacPutString: Failed UTF8 encoding\n"))
  1229. );
  1230. break;
  1231. }
  1232. //
  1233. // Ensure that the utf8 buffer contains a non-emtpy string
  1234. //
  1235. UTF8Length = strlen(LocalUtf8ConversionBuffer);
  1236. ASSERT(UTF8Length > 0);
  1237. if (UTF8Length == 0) {
  1238. IF_SAC_DEBUG(
  1239. SAC_DEBUG_FAILS,
  1240. KdPrint(("SAC XmlMgrSacPutString: Empty UTF8 buffer\n"))
  1241. );
  1242. break;
  1243. }
  1244. //
  1245. // Write the uft8 encoding to the sac channel
  1246. //
  1247. Status = XmlMgrSacChannel->OWrite(
  1248. XmlMgrSacChannel,
  1249. (PCUCHAR)LocalUtf8ConversionBuffer,
  1250. UTF8Length*sizeof(UCHAR)
  1251. );
  1252. if (! NT_SUCCESS(Status)) {
  1253. IF_SAC_DEBUG(
  1254. SAC_DEBUG_FAILS,
  1255. KdPrint(("SAC XmlMgrSacPutString: OWrite failed\n"))
  1256. );
  1257. break;
  1258. }
  1259. }
  1260. FREE_POOL(&LocalUtf8ConversionBuffer);
  1261. }
  1262. #if 0
  1263. BOOLEAN
  1264. XmlMgrSacPutSimpleMessage(
  1265. ULONG MessageId
  1266. )
  1267. /*++
  1268. Routine Description:
  1269. This routine retrieves a message resource and sends it to the SAC channel
  1270. Arguments:
  1271. MessageId - The message id of the resource to send
  1272. Return Value:
  1273. TRUE - the message was found
  1274. otherwise, FALSE
  1275. --*/
  1276. {
  1277. PCWSTR p;
  1278. p = GetMessage(MessageId);
  1279. if (p) {
  1280. XmlMgrSacPutString(p);
  1281. return(TRUE);
  1282. }
  1283. return(FALSE);
  1284. }
  1285. #endif
  1286. BOOLEAN
  1287. XmlMgrSacPutErrorMessage(
  1288. PCWSTR ActionName,
  1289. PCWSTR MessageId
  1290. )
  1291. /*++
  1292. Routine Description:
  1293. This routine retrieves a message resource and sends it to the SAC channel
  1294. Arguments:
  1295. MessageId - The message id of the resource to send
  1296. Return Value:
  1297. TRUE - the message was found
  1298. otherwise, FALSE
  1299. --*/
  1300. {
  1301. XmlMgrSacPutString(L"<error ");
  1302. XmlMgrSacPutString(L"action='");
  1303. XmlMgrSacPutString(ActionName);
  1304. XmlMgrSacPutString(L"' message-id='");
  1305. XmlMgrSacPutString(MessageId);
  1306. XmlMgrSacPutString(L"'/>\r\n");
  1307. return(TRUE);
  1308. }
  1309. BOOLEAN
  1310. XmlMgrSacPutErrorMessageWithStatus(
  1311. PCWSTR ActionName,
  1312. PCWSTR MessageId,
  1313. NTSTATUS Status
  1314. )
  1315. /*++
  1316. Routine Description:
  1317. This routine retrieves a message resource and sends it to the SAC channel
  1318. Arguments:
  1319. MessageId - The message id of the resource to send
  1320. Return Value:
  1321. TRUE - the message was found
  1322. otherwise, FALSE
  1323. --*/
  1324. {
  1325. PWSTR Buffer;
  1326. Buffer = ALLOCATE_POOL(0x100, GENERAL_POOL_TAG);
  1327. ASSERT(Buffer);
  1328. if (! Buffer) {
  1329. return FALSE;
  1330. }
  1331. XmlMgrSacPutString(L"<error ");
  1332. XmlMgrSacPutString(L"action='");
  1333. XmlMgrSacPutString(ActionName);
  1334. XmlMgrSacPutString(L"' message-id='");
  1335. XmlMgrSacPutString(MessageId);
  1336. XmlMgrSacPutString(L"' status='");
  1337. swprintf(
  1338. Buffer,
  1339. L"%08x",
  1340. Status
  1341. );
  1342. XmlMgrSacPutString(Buffer);
  1343. XmlMgrSacPutString(L"'/>\r\n");
  1344. FREE_POOL(&Buffer);
  1345. return(TRUE);
  1346. }
  1347. NTSTATUS
  1348. XmlMgrChannelOWrite(
  1349. PSAC_CMD_WRITE_CHANNEL ChannelWriteCmd
  1350. )
  1351. /*++
  1352. Routine Description:
  1353. This routine attempts to write data to a channel
  1354. Arguments:
  1355. ChannelWriteCmd - the write IOCTL command structure
  1356. Return Value:
  1357. Status
  1358. --*/
  1359. {
  1360. NTSTATUS Status;
  1361. PSAC_CHANNEL Channel;
  1362. //
  1363. //
  1364. //
  1365. LOCK_CURRENT_CHANNEL();
  1366. //
  1367. // Get the referred channel by it's handle
  1368. //
  1369. Status = ChanMgrGetByHandle(ChannelWriteCmd->Handle, &Channel);
  1370. if (NT_SUCCESS(Status)) {
  1371. do {
  1372. //
  1373. // Write the data to the channel's output buffer
  1374. //
  1375. Status = Channel->OWrite(
  1376. Channel,
  1377. &(ChannelWriteCmd->Buffer[0]),
  1378. ChannelWriteCmd->Size
  1379. );
  1380. if (!NT_SUCCESS(Status)) {
  1381. break;
  1382. }
  1383. //
  1384. // We are done with the channel
  1385. //
  1386. Status = ChanMgrReleaseChannel(Channel);
  1387. } while ( FALSE );
  1388. }
  1389. //
  1390. //
  1391. //
  1392. UNLOCK_CURRENT_CHANNEL();
  1393. ASSERT(NT_SUCCESS(Status));
  1394. return Status;
  1395. }
  1396. NTSTATUS
  1397. XmlMgrChannelClose(
  1398. PSAC_CHANNEL Channel
  1399. )
  1400. /*++
  1401. Routine Description:
  1402. This routine attempts to close a channel.
  1403. If we successfully close the channel and this channel was
  1404. the current channel, we reset the current channel to the SAC channel
  1405. Arguments:
  1406. Channel - the channel to close
  1407. Return Value:
  1408. STATUS_SUCCESS - the channel was closed
  1409. STATUS_ALREADY_DISCONNECTED - the channel was already closed
  1410. otherwise, error status
  1411. --*/
  1412. {
  1413. NTSTATUS Status;
  1414. //
  1415. // Attempt to make the specified channel inactive
  1416. //
  1417. do {
  1418. //
  1419. // Make sure the channel is not already inactive
  1420. //
  1421. if (! ChannelIsActive(Channel)) {
  1422. Status = STATUS_ALREADY_DISCONNECTED;
  1423. break;
  1424. }
  1425. //
  1426. // Change the status of the channel to Inactive
  1427. //
  1428. Status = ChannelClose(Channel);
  1429. if (! NT_SUCCESS(Status)) {
  1430. break;
  1431. }
  1432. //
  1433. // The current channel is being closed,
  1434. // so reset the current channel to the SAC
  1435. //
  1436. if (XmlMgrIsCurrentChannel(Channel)) {
  1437. Status = XmlMgrResetCurrentChannel();
  1438. }
  1439. } while ( FALSE );
  1440. ASSERT(NT_SUCCESS(Status) || Status == STATUS_ALREADY_DISCONNECTED);
  1441. return Status;
  1442. }
  1443. NTSTATUS
  1444. XmlMgrHandleEvent(
  1445. IN IO_MGR_EVENT Event,
  1446. IN PVOID Data
  1447. )
  1448. {
  1449. NTSTATUS Status;
  1450. Status = STATUS_SUCCESS;
  1451. switch(Event) {
  1452. case IO_MGR_EVENT_CHANNEL_CREATE: {
  1453. PWCHAR OutputBuffer;
  1454. PSAC_CHANNEL Channel;
  1455. Channel = (PSAC_CHANNEL)Data;
  1456. ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_2);
  1457. OutputBuffer = ALLOCATE_POOL(SAC_VT100_COL_WIDTH*sizeof(WCHAR), GENERAL_POOL_TAG);
  1458. ASSERT_STATUS(OutputBuffer, STATUS_NO_MEMORY);
  1459. //
  1460. // Notify the SAC that a channel was created
  1461. //
  1462. XmlMgrChannelEventMessage(
  1463. L"SAC_NEW_CHANNEL_CREATED",
  1464. ChannelGetName(Channel)
  1465. );
  1466. FREE_POOL(&OutputBuffer);
  1467. break;
  1468. }
  1469. case IO_MGR_EVENT_CHANNEL_CLOSE:
  1470. //
  1471. //
  1472. //
  1473. LOCK_CURRENT_CHANNEL();
  1474. do {
  1475. PSAC_CHANNEL Channel;
  1476. //
  1477. // Get the referred channel by it's handle
  1478. //
  1479. Status = ChanMgrGetByHandle(
  1480. *(PSAC_CHANNEL_HANDLE)Data,
  1481. &Channel
  1482. );
  1483. if (! NT_SUCCESS(Status)) {
  1484. break;
  1485. }
  1486. //
  1487. // Attempt to close the channel
  1488. //
  1489. Status = XmlMgrChannelClose(Channel);
  1490. //
  1491. // notify the user the status of the operation
  1492. //
  1493. if (NT_SUCCESS(Status)) {
  1494. //
  1495. // report the channel has been closed
  1496. //
  1497. XmlMgrChannelEventMessage(
  1498. L"SAC_CHANNEL_CLOSED",
  1499. ChannelGetName(Channel)
  1500. );
  1501. } else if (Status == STATUS_ALREADY_DISCONNECTED) {
  1502. //
  1503. // report the channel was already closed
  1504. //
  1505. XmlMgrChannelEventMessage(
  1506. L"SAC_CHANNEL_ALREADY_CLOSED",
  1507. ChannelGetName(Channel)
  1508. );
  1509. } else {
  1510. //
  1511. // report that we failed to close the channel
  1512. //
  1513. XmlMgrChannelEventMessage(
  1514. L"SAC_CHANNEL_FAILED_CLOSE",
  1515. ChannelGetName(Channel)
  1516. );
  1517. }
  1518. //
  1519. // We are done with the channel
  1520. //
  1521. ChanMgrReleaseChannel(Channel);
  1522. } while(FALSE);
  1523. //
  1524. //
  1525. //
  1526. UNLOCK_CURRENT_CHANNEL();
  1527. break;
  1528. case IO_MGR_EVENT_CHANNEL_WRITE:
  1529. Status = XmlMgrChannelOWrite((PSAC_CMD_WRITE_CHANNEL)Data);
  1530. break;
  1531. case IO_MGR_EVENT_REGISTER_SAC_CMD_EVENT:
  1532. //
  1533. //
  1534. //
  1535. LOCK_CURRENT_CHANNEL();
  1536. Status = XmlMgrEventMessage(L"SAC_CMD_SERVICE_REGISTERED") ?
  1537. STATUS_SUCCESS :
  1538. STATUS_UNSUCCESSFUL;
  1539. //
  1540. //
  1541. //
  1542. UNLOCK_CURRENT_CHANNEL();
  1543. break;
  1544. case IO_MGR_EVENT_UNREGISTER_SAC_CMD_EVENT:
  1545. //
  1546. //
  1547. //
  1548. LOCK_CURRENT_CHANNEL();
  1549. Status = XmlMgrEventMessage(L"SAC_CMD_SERVICE_UNREGISTERED") ?
  1550. STATUS_SUCCESS :
  1551. STATUS_UNSUCCESSFUL;
  1552. //
  1553. //
  1554. //
  1555. UNLOCK_CURRENT_CHANNEL();
  1556. break;
  1557. case IO_MGR_EVENT_SHUTDOWN:
  1558. Status = XmlMgrEventMessage(L"SAC_SHUTDOWN") ?
  1559. STATUS_SUCCESS :
  1560. STATUS_UNSUCCESSFUL;
  1561. break;
  1562. default:
  1563. Status = STATUS_INVALID_PARAMETER_1;
  1564. break;
  1565. }
  1566. return Status;
  1567. }