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.

469 lines
10 KiB

  1. /*************************************************************************
  2. *
  3. * cpmutil.c
  4. *
  5. * System Library Client Printer functions
  6. *
  7. * These functions tend to be includes in the spooler, printman,
  8. * and various port monitor DLL's. So they are here for common code.
  9. *
  10. * Copyright Microsoft, 1998
  11. *
  12. *
  13. *
  14. *
  15. *************************************************************************/
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h>
  20. #include "winsta.h"
  21. #include "syslib.h"
  22. #if DBG
  23. #define DBGPRINT(x) DbgPrint x
  24. #if DBGTRACE
  25. #define TRACE0(x) DbgPrint x
  26. #define TRACE1(x) DbgPrint x
  27. #else
  28. #define TRACE0(x)
  29. #define TRACE1(x)
  30. #endif
  31. #else
  32. #define DBGPRINT(x)
  33. #define TRACE0(x)
  34. #define TRACE1(x)
  35. #endif
  36. /*****************************************************************************
  37. *
  38. * IsClientPrinterPort
  39. *
  40. * Return whether the name is a client printer port
  41. *
  42. * ENTRY:
  43. * Param1 (input/output)
  44. * Comments
  45. *
  46. * EXIT:
  47. * STATUS_SUCCESS - no error
  48. *
  49. ****************************************************************************/
  50. BOOL
  51. IsClientPrinterPort(
  52. PWCHAR pName
  53. )
  54. {
  55. BOOL Result;
  56. PORTNAMETYPE Type;
  57. //
  58. // This just does a brute force compare
  59. //
  60. if( pName == NULL ) {
  61. return( FALSE );
  62. }
  63. if( _wcsicmp( L"Client\\LPT1:", pName ) == 0 ) {
  64. return( TRUE );
  65. }
  66. if( _wcsicmp( L"Client\\LPT2:", pName ) == 0 ) {
  67. return( TRUE );
  68. }
  69. if( _wcsicmp( L"Client\\LPT3:", pName ) == 0 ) {
  70. return( TRUE );
  71. }
  72. if( _wcsicmp( L"Client\\LPT4:", pName ) == 0 ) {
  73. return( TRUE );
  74. }
  75. if( _wcsicmp( L"Client\\COM1:", pName ) == 0 ) {
  76. return( TRUE );
  77. }
  78. if( _wcsicmp( L"Client\\COM2:", pName ) == 0 ) {
  79. return( TRUE );
  80. }
  81. if( _wcsicmp( L"Client\\COM3:", pName ) == 0 ) {
  82. return( TRUE );
  83. }
  84. if( _wcsicmp( L"Client\\COM4:", pName ) == 0 ) {
  85. return( TRUE );
  86. }
  87. //
  88. // See if its a specific port
  89. //
  90. Result = ParseDynamicPortName(
  91. pName,
  92. NULL,
  93. NULL,
  94. &Type
  95. );
  96. if( Type != PortNameUnknown ) {
  97. return( TRUE );
  98. }
  99. return( FALSE );
  100. }
  101. /*****************************************************************************
  102. *
  103. * ExtractDosNamePtr
  104. *
  105. * Extract the DOS name from a client port string.
  106. *
  107. * Returns a pointer to the DOS name which is contained within
  108. * the argument string.
  109. *
  110. * Does not modify the argument string.
  111. *
  112. * ENTRY:
  113. * pName (input)
  114. * Input name string
  115. *
  116. * EXIT:
  117. * NULL: No DOS name
  118. * !=NULL Pointer to DOS name
  119. *
  120. ****************************************************************************/
  121. PWCHAR
  122. ExtractDosNamePtr(
  123. PWCHAR pName
  124. )
  125. {
  126. PWCHAR this, prev;
  127. LPWSTR Ptr;
  128. ULONG Len, i, Count;
  129. WCHAR NameBuf[USERNAME_LENGTH+9];
  130. if( pName == NULL ) {
  131. return NULL;
  132. }
  133. // Make sure it starts with "Client\"
  134. if( _wcsnicmp( pName, L"Client\\", 7 ) != 0 ) {
  135. return NULL;
  136. }
  137. // Count the '\'s
  138. prev = pName;
  139. Count = 0;
  140. while( 1 ) {
  141. this = wcschr( prev, L'\\' );
  142. if( this == NULL ) {
  143. break;
  144. }
  145. // Now we must skip over the '\' character
  146. this++;
  147. Count++;
  148. prev = this;
  149. }
  150. if( Count == 0 ) {
  151. DBGPRINT(("ExtractDosNamePtr: Bad Dynamic name format No separators :%ws:\n",pName));
  152. return NULL;
  153. }
  154. //
  155. // Might be Client\LPTx:
  156. //
  157. // NOTE: Windows printers currently do not support
  158. // a generic name.
  159. //
  160. if( Count == 1 ) {
  161. Len = wcslen( pName );
  162. if( Len < 11 ) {
  163. DBGPRINT(("ExtractDosNamePtr: Bad Dynamic name format Len < 11 :%ws:\n",pName));
  164. return NULL;
  165. }
  166. // Skip over "Client\"
  167. Ptr = pName + 7;
  168. return( Ptr );
  169. }
  170. // Skip over "Client\"
  171. Ptr = pName + 7;
  172. //
  173. // Here we must skip over the ICAName# or WinStationName
  174. //
  175. while( *Ptr ) {
  176. if( *Ptr == '\\' ) {
  177. break;
  178. }
  179. Ptr++;
  180. }
  181. //
  182. // Ptr now points to the '\\' after the
  183. // WinStation or ICA name. After this slash,
  184. // is the rest of the printer or port name.
  185. //
  186. Ptr++;
  187. return( Ptr );
  188. }
  189. /*****************************************************************************
  190. *
  191. * ExtractDosName
  192. *
  193. * Extract the DOS name from a client port string.
  194. *
  195. * Returns the DOS name which is in a newly allocated string.
  196. *
  197. * Does not modify the argument string.
  198. *
  199. * ENTRY:
  200. * pName (input)
  201. * Input name string
  202. *
  203. * EXIT:
  204. * NULL: No DOS name
  205. * !=NULL Pointer to DOS name
  206. *
  207. ****************************************************************************/
  208. PWCHAR
  209. ExtractDosName(
  210. PWCHAR pName
  211. )
  212. {
  213. PWCHAR Ptr;
  214. PWCHAR pNewName = NULL;
  215. Ptr = ExtractDosNamePtr( pName );
  216. if( Ptr == NULL ) return NULL;
  217. pNewName = RtlAllocateHeap( RtlProcessHeap(), 0, (wcslen( Ptr )+1)*sizeof(WCHAR) );
  218. if( pNewName == NULL ) return NULL;
  219. wcscpy( pNewName, Ptr );
  220. return( pNewName );
  221. }
  222. /*****************************************************************************
  223. *
  224. * ParseDynamicPortName
  225. *
  226. * Parse a dynamic port name into its components.
  227. * (NOTE: This is also in \nt\private\windows\spooler\localspl\citrix\cpmsup.c)
  228. *
  229. * A dynamic port name is of the form:
  230. *
  231. * Client\WinStationName\LPTx:, where WinStationName is the hardwire name
  232. * Client\ICAName#\LPTx:, where ICAName is the ICA configured client name
  233. * Client\LPTx:
  234. * Client\IcaName#\Windows_Printer_Name
  235. * where Windows_Printer_Name is
  236. * the remote windows client print
  237. * manager printer name.
  238. *
  239. * Client\IcaName#\\\ntbuild\print1
  240. * where Windows_Printer_Name is
  241. * the remote windows client print
  242. * manager printer name.
  243. *
  244. * ENTRY:
  245. * pName (input)
  246. * Name to be parsed
  247. *
  248. * EXIT:
  249. * TRUE - Name parsed successfully
  250. * FALSE - Name is incorrect.
  251. *
  252. ****************************************************************************/
  253. BOOL
  254. ParseDynamicPortName(
  255. LPWSTR pName,
  256. LPWSTR pUser,
  257. LPWSTR pDosPort,
  258. PORTNAMETYPE *pType
  259. )
  260. {
  261. PWCHAR this, prev;
  262. LPWSTR Ptr;
  263. ULONG Len, i, Count;
  264. WCHAR NameBuf[USERNAME_LENGTH+9];
  265. if( pName == NULL ) {
  266. *pType = PortNameUnknown;
  267. return(FALSE);
  268. }
  269. // Make sure it starts with "Client\"
  270. if( _wcsnicmp( pName, L"Client\\", 7 ) != 0 ) {
  271. *pType = PortNameUnknown;
  272. return(FALSE);
  273. }
  274. // Count the '\'s
  275. prev = pName;
  276. Count = 0;
  277. while( 1 ) {
  278. this = wcschr( prev, L'\\' );
  279. if( this == NULL ) {
  280. break;
  281. }
  282. // Now we must skip over the '\' character
  283. this++;
  284. Count++;
  285. prev = this;
  286. }
  287. if( Count == 0 ) {
  288. DBGPRINT(("ParseDynamicName: Bad Dynamic name format No separators :%ws:\n",pName));
  289. *pType = PortNameUnknown;
  290. return(FALSE);
  291. }
  292. //
  293. // Might be Client\LPTx:
  294. //
  295. // NOTE: Windows printers currently do not support
  296. // a generic name.
  297. //
  298. if( Count == 1 ) {
  299. Len = wcslen( pName );
  300. if( Len < 11 ) {
  301. *pType = PortNameUnknown;
  302. DBGPRINT(("ParseDynamicName: Bad Dynamic name format Len < 11 :%ws:\n",pName));
  303. return(FALSE);
  304. }
  305. // Skip over "Client\"
  306. Ptr = pName + 7;
  307. if( !((_wcsnicmp( Ptr, L"LPT", 3 ) == 0)
  308. ||
  309. (_wcsnicmp( Ptr, L"COM", 3 ) == 0)
  310. ||
  311. (_wcsnicmp( Ptr, L"AUX", 3 ) == 0)) ) {
  312. *pType = PortNameUnknown;
  313. DBGPRINT(("ParseDynamicName: Bad Dynamic name format Not LPT!COM!AUX :%ws:\n",pName));
  314. return(FALSE);
  315. }
  316. // Range check the number
  317. if( (Ptr[3] < L'1') || (Ptr[3] > L'4') ) {
  318. *pType = PortNameUnknown;
  319. DBGPRINT(("ParseDynamicName: Bad Dynamic name format Number Range:%ws:\n",pName));
  320. return(FALSE);
  321. }
  322. Ptr = ExtractDosNamePtr( pName );
  323. if( Ptr == NULL ) {
  324. // Bad Dos component
  325. *pType = PortNameUnknown;
  326. DBGPRINT(("ParseDynamicName: Bad Dynamic name format DosName :%ws:\n",pName));
  327. return(FALSE);
  328. }
  329. // Copy out the Dos name
  330. if( pDosPort )
  331. wcscpy( pDosPort, Ptr );
  332. // Set the rest of the flags
  333. if( pUser )
  334. pUser[0] = 0;
  335. *pType = PortNameGeneric;
  336. return(TRUE);
  337. }
  338. #ifdef notdef
  339. //
  340. // The rest of the formats have two '\'s
  341. //
  342. if( Count != 2 ) {
  343. DBGPRINT(("ParseDynamicName: Bad Dynamic name format Must be 2 :%ws:\n",pName));
  344. *pType = PortNameUnknown;
  345. return(FALSE);
  346. }
  347. // Get the Dos Name, which could also be a Windows printer name
  348. Ptr = ExtractDosNamePtr( pName );
  349. if( Ptr == NULL ) {
  350. // Bad Dos component
  351. *pType = PortNameUnknown;
  352. return(FALSE);
  353. }
  354. // Copy out the Dos name
  355. if( pDosPort )
  356. wcscpy( pDosPort, Ptr );
  357. #endif
  358. // Skip over "Client\"
  359. Ptr = pName + 7;
  360. //
  361. // Now copy the ICAName#, or WinStationName to a local
  362. // buffer for further processing
  363. i = 0;
  364. NameBuf[i] = 0;
  365. while( *Ptr ) {
  366. if( *Ptr == '\\' ) {
  367. NameBuf[i] = 0;
  368. break;
  369. }
  370. NameBuf[i] = *Ptr;
  371. Ptr++;
  372. i++;
  373. }
  374. //
  375. // Ptr now points to the '\\' after the
  376. // WinStation or ICA name. After this slash,
  377. // is the rest of the printer or port name.
  378. //
  379. Ptr++;
  380. // Copy out the Dos name
  381. if( pDosPort )
  382. wcscpy( pDosPort, Ptr );
  383. //
  384. // See if this is an ICA name, or a WinStation name
  385. //
  386. Ptr = wcschr( NameBuf, L'#' );
  387. if( Ptr != NULL ) {
  388. // NULL terminate the ICAName and copy it out
  389. *Ptr = (WCHAR)NULL;
  390. if( pUser )
  391. wcscpy( pUser, NameBuf );
  392. // Set the type to an ICA named roving WinStation
  393. *pType = PortNameICA;
  394. }
  395. else {
  396. //
  397. // The name will be treated as a WinStation name
  398. //
  399. if( pUser )
  400. wcscpy( pUser, NameBuf );
  401. *pType = PortNameHardWire;
  402. }
  403. return(TRUE);
  404. }