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.

864 lines
27 KiB

  1. /*************************************************************************
  2. * Microsoft Windows NT *
  3. * *
  4. * Copyright(c) Microsoft Corp., 1994 *
  5. * *
  6. * Revision History: *
  7. * *
  8. * Jan. 24,94 Koti Created *
  9. * *
  10. * Description: *
  11. * *
  12. * This file contains functions for parsing the commands/control file *
  13. * sent by the LPR client. *
  14. * *
  15. *************************************************************************/
  16. #include "lpd.h"
  17. /*****************************************************************************
  18. * *
  19. * LicensingApproval(): *
  20. * This function passes the username or hostname to the licensing dll. *
  21. * The dll does whatever it needs to do and returns either a success in *
  22. * which case we continue with printing, or a failure in which case we *
  23. * refuse to print. *
  24. * *
  25. * Returns: *
  26. * TRUE if licensing approves and we should continue with printing *
  27. * FALSE if licensing disapproves and we should refuse printing *
  28. * *
  29. * Parameters: *
  30. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  31. * *
  32. * History: *
  33. * Nov.21, 94 Koti Created *
  34. * *
  35. *****************************************************************************/
  36. BOOL LicensingApproval( PSOCKCONN pscConn )
  37. {
  38. NT_LS_DATA LsData;
  39. LS_STATUS_CODE err;
  40. LS_HANDLE LicenseHandle;
  41. BOOL fRetval;
  42. fRetval = FALSE;
  43. LsData.DataType = NT_LS_USER_NAME;
  44. LsData.Data = (VOID *) pscConn->pchUserName;
  45. LsData.IsAdmin = FALSE;
  46. err = NtLicenseRequest(LPD_SERVICE_USRFRIENDLY_NAME,
  47. szNTVersion,
  48. &LicenseHandle,
  49. &LsData);
  50. switch (err)
  51. {
  52. case LS_SUCCESS:
  53. pscConn->LicenseHandle = LicenseHandle;
  54. pscConn->fMustFreeLicense = TRUE;
  55. fRetval = TRUE;
  56. break;
  57. case LS_INSUFFICIENT_UNITS:
  58. LPD_DEBUG( "LicensingApproval(): request rejected\n" );
  59. break;
  60. case LS_RESOURCES_UNAVAILABLE:
  61. LPD_DEBUG( "LicensingApproval(): no resources\n" );
  62. break;
  63. default:
  64. LPD_DEBUG( "LicensingApproval(): got back an unknown error code\n" );
  65. }
  66. return( fRetval );
  67. } // end LicensingApproval()
  68. /*****************************************************************************
  69. * *
  70. * ParseQueueName(): *
  71. * This function parses the first comand from the client to retrieve the *
  72. * name of the queue (printer). *
  73. * *
  74. * Returns: *
  75. * TRUE if we successfully got the queue name *
  76. * FALSE if something went wrong somewhere *
  77. * *
  78. * Parameters: *
  79. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  80. * *
  81. * Notes: *
  82. * We are parsing a string (command) that's of the following form: *
  83. * *
  84. * ------------------ *
  85. * | N | Queue | LF | where N=02 or 03 *
  86. * ------------------ Queue = name of the queue *
  87. * 1byte ..... 1byte *
  88. * *
  89. * This may not work in the case of GetQueue commands since the format *
  90. * may include space and list, too. ParseQueueRequest takes care of it. *
  91. * *
  92. * History: *
  93. * Jan.25, 94 Koti Created *
  94. * Mar 04, 97, MohsinA Albert Ting Cluster prefix with ip address. *
  95. *****************************************************************************/
  96. BOOL ParseQueueName( PSOCKCONN pscConn )
  97. {
  98. PCHAR pchPrinterName;
  99. DWORD cbPrinterNameLen;
  100. DWORD cbServerPrefixLen;
  101. // make sure Queue length is at least 1 byte
  102. // (i.e. command is at least 3 bytes long)
  103. if ( pscConn->cbCommandLen < 3 ){
  104. LPD_DEBUG( "Bad command in GetQueueName(): len < 3 bytes\n" );
  105. return( FALSE );
  106. }
  107. if( pscConn->szServerIPAddr == NULL ){
  108. LPD_DEBUG( "ParseQueueName_: pscConn->szServerIPAddr NULL.\n" );
  109. return FALSE ;
  110. }
  111. // What they call Queue in rfc1179, we call it Printer!
  112. //
  113. // We need to fully qualify the printer name with \\x.x.x.x\printer
  114. // since there may be multiple addresses with print clustering.
  115. // Prepend "\\x.x.x.x\" to regular name.
  116. cbPrinterNameLen = pscConn->cbCommandLen - 2 +
  117. 2 + strlen( pscConn->szServerIPAddr ) + 1;
  118. pchPrinterName = LocalAlloc( LMEM_FIXED, cbPrinterNameLen+1 );
  119. if ( pchPrinterName == NULL ){
  120. LPD_DEBUG( "LocalAlloc failed in GetQueueName()\n" );
  121. return( FALSE );
  122. }
  123. // Format the prefix of the printer name \\x.x.x.x\.
  124. sprintf( pchPrinterName, "\\\\%s\\", pscConn->szServerIPAddr );
  125. cbServerPrefixLen = strlen( pchPrinterName );
  126. // Append the printer name.
  127. strncpy( &pchPrinterName[cbServerPrefixLen],
  128. &(pscConn->pchCommand[1]),
  129. cbPrinterNameLen - cbServerPrefixLen );
  130. pchPrinterName[cbPrinterNameLen] = '\0';
  131. pscConn->pchPrinterName = pchPrinterName;
  132. return( TRUE );
  133. } // end ParseQueueName()
  134. /*****************************************************************************
  135. * *
  136. * ParseSubCommand(): *
  137. * This function parses the subcommand to get the count and of how many *
  138. * bytes are to come (as control file or data) and name of the control *
  139. * file or data file, as the case may be. pscConn->wState decides which *
  140. * subcommand is being parsed. *
  141. * *
  142. * Returns: *
  143. * NO_ERROR if everything went well *
  144. * ErrorCode if something went wrong somewhere *
  145. * *
  146. * Parameters: *
  147. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  148. * *
  149. * Notes: *
  150. * We are parsing a string (subcommand) that's of the following form: *
  151. * *
  152. * ------------------------------ *
  153. * | N | Count | SP | Name | LF | where N = 02 for Control file *
  154. * ------------------------------ 03 for Data file *
  155. * 1byte ..... 1byte .... 1byte *
  156. * *
  157. * History: *
  158. * Jan.25, 94 Koti Created *
  159. * *
  160. *****************************************************************************/
  161. DWORD ParseSubCommand( PSOCKCONN pscConn, DWORD *FileLen, PCHAR *FileName )
  162. {
  163. PCHAR pchFileName=NULL;
  164. PCHAR pchPtr;
  165. DWORD dwFileLen=0;
  166. DWORD dwFileNameLen=0;
  167. DWORD dwParseLen;
  168. DWORD dwParsedSoFar;
  169. WORD i;
  170. pchPtr = &pscConn->pchCommand[1];
  171. dwParseLen = pscConn->cbCommandLen;
  172. dwParsedSoFar = 1; // since we're starting from 2nd byte
  173. // pchPtr now points at the "Count" field of the subcommand
  174. // find out how long the file is
  175. dwFileLen = atol( pchPtr );
  176. if ( dwFileLen <= 0 )
  177. {
  178. return( LPDERR_BADFORMAT );
  179. }
  180. // go to the next field
  181. while ( !IS_WHITE_SPACE( *pchPtr ) )
  182. {
  183. pchPtr++;
  184. if ( ++dwParsedSoFar >= dwParseLen )
  185. {
  186. return( LPDERR_BADFORMAT );
  187. }
  188. }
  189. // skip any trailing white space
  190. while ( IS_WHITE_SPACE( *pchPtr ) )
  191. {
  192. pchPtr++;
  193. if ( ++dwParsedSoFar >= dwParseLen )
  194. {
  195. return( LPDERR_BADFORMAT );
  196. }
  197. }
  198. // pchPtr now points at the "Name" field of the subcommand
  199. // find out how long the filename is (the subcommand is terminated
  200. // by LF character)
  201. while( pchPtr[dwFileNameLen] != LF )
  202. {
  203. dwFileNameLen++;
  204. if ( ++dwParsedSoFar >= dwParseLen )
  205. {
  206. return( LPDERR_BADFORMAT );
  207. }
  208. }
  209. pchFileName = (PCHAR)LocalAlloc( LMEM_FIXED, (dwFileNameLen + 1) );
  210. if ( pchFileName == NULL )
  211. {
  212. return( LPDERR_NOBUFS );
  213. }
  214. for ( i=0; i<dwFileNameLen; i++ )
  215. {
  216. pchFileName[i] = pchPtr[i];
  217. }
  218. pchFileName[dwFileNameLen] = '\0';
  219. // is it a control file name or data file name that we parsed?
  220. *FileName = pchFileName;
  221. *FileLen = dwFileLen;
  222. return( NO_ERROR );
  223. } // end ParseSubCommand()
  224. /*****************************************************************************
  225. * *
  226. * ParseQueueRequest(): *
  227. * This function parses the subcommand sent by the client to request the *
  228. * status of the queue or to request removing of job(s). *
  229. * *
  230. * Returns: *
  231. * NO_ERROR if everything went well *
  232. * ErrorCode if something went wrong somewhere *
  233. * *
  234. * Parameters: *
  235. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  236. * fAgent (IN): whether to look for the Agent field. *
  237. * *
  238. * Notes: *
  239. * We are parsing a string that's like one of the following: *
  240. * *
  241. * ------------------------------ N=03 (Short Q), 04 (Long Q) *
  242. * | N | Queue | SP | List | LF | Queue = name of the Q (printer) *
  243. * ------------------------------ List = user name and/or job-ids *
  244. * 1byte ..... 1byte ..... 1byte *
  245. * OR *
  246. * -------------------------------------------- *
  247. * | 05 | Queue | SP | Agent | SP | List | LF | *
  248. * -------------------------------------------- *
  249. * 1byte ..... 1byte ..... 1byte 1byte *
  250. * *
  251. * History: *
  252. * Jan.25, 94 Koti Created *
  253. * *
  254. *****************************************************************************/
  255. DWORD ParseQueueRequest( PSOCKCONN pscConn, BOOL fAgent )
  256. {
  257. PCHAR pchPrinterName;
  258. PCHAR pchPrinterNameFQN;
  259. PCHAR pchPtr;
  260. DWORD cbPrinterNameLen;
  261. DWORD cbPrefixLen;
  262. DWORD dwParseLen;
  263. DWORD dwParsedSoFar;
  264. PQSTATUS pqStatus;
  265. //
  266. // ParseQueueName had allocated it: free it and reparse because
  267. // it was parsed for the most common case, not for the Queue case
  268. //
  269. if (pscConn->pchPrinterName)
  270. {
  271. LocalFree( pscConn->pchPrinterName );
  272. pscConn->pchPrinterName = NULL;
  273. }
  274. // get the printer (queue) name from the command request
  275. // make sure Queue length is at least 1 byte
  276. // (i.e. command is at least 4 bytes long)
  277. if ( pscConn->cbCommandLen < 4 )
  278. {
  279. LPD_DEBUG( "ParseQueueRequest(): error: len shorter than 4 bytes\n" );
  280. return( LPDERR_BADFORMAT );
  281. }
  282. cbPrefixLen = 2 + strlen( pscConn->szServerIPAddr ) + 1;
  283. // alloc buffer to store printer name (yes, allocating more than needed)
  284. pchPrinterName = LocalAlloc( LMEM_FIXED, (pscConn->cbCommandLen+cbPrefixLen) );
  285. if ( pchPrinterName == NULL )
  286. {
  287. LPD_DEBUG( "LocalAlloc failed in GetQueueName()\n" );
  288. return( LPDERR_NOBUFS );
  289. }
  290. pchPrinterNameFQN = pchPrinterName;
  291. // Format the prefix of the printer name \\x.x.x.x\.
  292. sprintf( pchPrinterName, "\\\\%s\\", pscConn->szServerIPAddr );
  293. // advance the pointer to point to start of the printer name
  294. pchPrinterName += strlen( pchPrinterName );
  295. dwParseLen = pscConn->cbCommandLen;
  296. cbPrinterNameLen = 0;
  297. pchPtr = &(pscConn->pchCommand[1]);
  298. while ( !IS_WHITE_SPACE( *pchPtr ) && ( *pchPtr != LF ) )
  299. {
  300. pchPrinterName[cbPrinterNameLen] = *pchPtr;
  301. pchPtr++;
  302. cbPrinterNameLen++;
  303. if (cbPrinterNameLen >= dwParseLen )
  304. {
  305. LPD_DEBUG( "ParseQueueRequest(): bad request (no SP found!)\n" );
  306. LocalFree( pchPrinterNameFQN );
  307. return( LPDERR_BADFORMAT );
  308. }
  309. }
  310. pchPrinterName[cbPrinterNameLen] = '\0';
  311. pscConn->pchPrinterName = pchPrinterNameFQN;
  312. dwParsedSoFar = cbPrinterNameLen + 1; // we started parsing from 2nd byte
  313. // skip any trailing white space
  314. while ( IS_WHITE_SPACE( *pchPtr ) )
  315. {
  316. pchPtr++;
  317. if ( ++dwParsedSoFar >= dwParseLen )
  318. {
  319. return( LPDERR_BADFORMAT );
  320. }
  321. }
  322. // quite often, lpq won't specify any users or job-ids (i.e., the "List"
  323. // field in the command is skipped). If so, we are done!
  324. if ( *pchPtr == LF )
  325. {
  326. return( NO_ERROR );
  327. }
  328. // first, create a QSTATUS structure
  329. pscConn->pqStatus = (PQSTATUS)LocalAlloc( LMEM_FIXED, sizeof(QSTATUS) );
  330. if ( pscConn->pqStatus == NULL )
  331. {
  332. return( LPDERR_NOBUFS );
  333. }
  334. pqStatus = pscConn->pqStatus;
  335. pqStatus->cbActualJobIds = 0;
  336. pqStatus->cbActualUsers = 0;
  337. pqStatus->pchUserName = NULL;
  338. // if we have been called to parse command code 05 ("Remove Jobs")
  339. // then get the username out of the string
  340. if ( fAgent )
  341. {
  342. pqStatus->pchUserName = pchPtr;
  343. // skip this field and go to the "List" field
  344. while ( !IS_WHITE_SPACE( *pchPtr ) )
  345. {
  346. pchPtr++;
  347. if ( ++dwParsedSoFar >= dwParseLen )
  348. {
  349. return( LPDERR_BADFORMAT );
  350. }
  351. }
  352. *pchPtr++ = '\0';
  353. // skip any trailing white space
  354. while ( IS_WHITE_SPACE( *pchPtr ) )
  355. {
  356. pchPtr++;
  357. if ( ++dwParsedSoFar >= dwParseLen )
  358. {
  359. return( LPDERR_BADFORMAT );
  360. }
  361. }
  362. }
  363. while ( *pchPtr != LF )
  364. {
  365. // if we reached the limit, stop parsing!
  366. if ( ( pqStatus->cbActualJobIds == LPD_SP_STATUSQ_LIMIT ) ||
  367. ( pqStatus->cbActualUsers == LPD_SP_STATUSQ_LIMIT ) )
  368. {
  369. break;
  370. }
  371. // skip any trailing white space
  372. while ( IS_WHITE_SPACE( *pchPtr ) )
  373. {
  374. pchPtr++;
  375. if ( ++dwParsedSoFar >= dwParseLen )
  376. {
  377. return( LPDERR_BADFORMAT );
  378. }
  379. }
  380. if ( *pchPtr == LF )
  381. {
  382. *pchPtr = '\0';
  383. return( NO_ERROR );
  384. }
  385. // is this a job id?
  386. if ( isdigit( *pchPtr ) )
  387. {
  388. pqStatus->adwJobIds[pqStatus->cbActualJobIds++] = atol( pchPtr );
  389. }
  390. else // nope, it's user name
  391. {
  392. pqStatus->ppchUsers[pqStatus->cbActualUsers++] = pchPtr;
  393. }
  394. while ( !IS_WHITE_SPACE( *pchPtr ) && ( *pchPtr != LF ) )
  395. {
  396. pchPtr++;
  397. if ( ++dwParsedSoFar >= dwParseLen )
  398. {
  399. return( LPDERR_BADFORMAT );
  400. }
  401. }
  402. // if we reached LF, we are done
  403. if ( *pchPtr == LF )
  404. {
  405. *pchPtr = '\0';
  406. return( NO_ERROR );
  407. }
  408. // go to the next username or jobid, or end
  409. *pchPtr++ = '\0';
  410. dwParsedSoFar++;
  411. if (dwParsedSoFar >= dwParseLen)
  412. {
  413. return( LPDERR_BADFORMAT );
  414. }
  415. }
  416. return( NO_ERROR );
  417. } // end ParseQueueRequest()
  418. /*****************************************************************************
  419. * *
  420. * ParseControlFile(): *
  421. * This function parses contrl file and assigns values to the appropriate *
  422. * fields of the CFILE_INFO structure. *
  423. * *
  424. * Returns: *
  425. * NO_ERROR if parsing went well *
  426. * LPDERR_BADFORMAT if the control file didn't conform to rfc1179 *
  427. * *
  428. * Parameters: *
  429. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  430. * *
  431. * History: *
  432. * Jan.29, 94 Koti Created *
  433. * *
  434. *****************************************************************************/
  435. DWORD ParseControlFile( PSOCKCONN pscConn, PCFILE_ENTRY pCFile )
  436. {
  437. CFILE_INFO CFileInfo;
  438. PCHAR pchCFile;
  439. DWORD dwBytesParsedSoFar;
  440. BOOL DocReady;
  441. PCHAR DocName;
  442. BOOL fUnsupportedCommand;
  443. #ifdef DBG
  444. if( !pscConn || !pscConn->pchPrinterName
  445. || strstr( pscConn->pchPrinterName, "debug" )
  446. ){
  447. print__sockconn( "ParseControlFile: entered", pscConn );
  448. }
  449. #endif
  450. memset( (PCHAR)&CFileInfo, 0, sizeof( CFILE_INFO ) );
  451. if ( pCFile->pchCFile == NULL )
  452. {
  453. LPD_DEBUG( "ParseControlFile(): pchCFile NULL on entry\n" );
  454. return( LPDERR_BADFORMAT );
  455. }
  456. if (pscConn==NULL ){
  457. LPD_DEBUG( "ParseControlFile(): pscConn NULL on entry\n" );
  458. return( LPDERR_BADFORMAT );
  459. }
  460. pchCFile = pCFile->pchCFile;
  461. dwBytesParsedSoFar = 0;
  462. // default: most likely, only one copy is needed
  463. CFileInfo.usNumCopies = 1;
  464. // default: most likely, it's "raw" data
  465. CFileInfo.szPrintFormat = LPD_RAW_STRING;
  466. // loop through and parse the entire file, as per rfc 1179, sec.7.
  467. DocReady = FALSE;
  468. CFileInfo.pchSrcFile = NULL;
  469. CFileInfo.pchTitle = NULL;
  470. CFileInfo.pchUnlink = NULL;
  471. DocName = NULL;
  472. fUnsupportedCommand = FALSE;
  473. while( dwBytesParsedSoFar < pCFile->cbCFileLen )
  474. {
  475. switch( *pchCFile++ )
  476. {
  477. case 'C' : CFileInfo.pchClass = pchCFile;
  478. break;
  479. case 'H' : CFileInfo.pchHost = pchCFile;
  480. break;
  481. case 'I' : CFileInfo.dwCount = atol( pchCFile );
  482. break;
  483. case 'J' : CFileInfo.pchJobName = pchCFile;
  484. break;
  485. case 'L' : CFileInfo.pchBannerName = pchCFile;
  486. break;
  487. case 'M' : CFileInfo.pchMailName = pchCFile;
  488. break;
  489. case 'N' : if (CFileInfo.pchSrcFile != NULL) {
  490. DocReady = TRUE;
  491. break;
  492. }
  493. CFileInfo.pchSrcFile = pchCFile;
  494. break;
  495. case 'P' : CFileInfo.pchUserName = pchCFile;
  496. pscConn->pchUserName = pchCFile;
  497. break;
  498. case 'S' : CFileInfo.pchSymLink = pchCFile;
  499. break;
  500. case 'T' : if (CFileInfo.pchTitle != NULL) {
  501. DocReady = TRUE;
  502. break;
  503. }
  504. CFileInfo.pchTitle = pchCFile;
  505. break;
  506. case 'U' : if (CFileInfo.pchUnlink != NULL) {
  507. DocReady = TRUE;
  508. break;
  509. }
  510. CFileInfo.pchUnlink = pchCFile;
  511. break;
  512. case 'W' : CFileInfo.dwWidth = atol( pchCFile );
  513. break;
  514. case '1' : CFileInfo.pchTrfRFile = pchCFile;
  515. break;
  516. case '2' : CFileInfo.pchTrfIFile = pchCFile;
  517. break;
  518. case '3' : CFileInfo.pchTrfBFile = pchCFile;
  519. break;
  520. case '4' : CFileInfo.pchTrfSFile = pchCFile;
  521. break;
  522. case 'K' :
  523. case '#' : CFileInfo.usNumCopies = (WORD)atoi(pchCFile);
  524. break;
  525. case 'f' : if (DocName != NULL) {
  526. DocReady = TRUE;
  527. break;
  528. }
  529. CFileInfo.pchFrmtdFile = pchCFile;
  530. CFileInfo.szPrintFormat = LPD_TEXT_STRING;
  531. if ( fAlwaysRawGLB ) {
  532. CFileInfo.szPrintFormat = LPD_RAW_STRING;
  533. }
  534. DocName = pchCFile;
  535. break;
  536. case 'g' : CFileInfo.pchPlotFile = pchCFile;
  537. // fall through
  538. case 'n' : CFileInfo.pchDitroffFile = pchCFile;
  539. case 'o' : CFileInfo.pchPscrptFile = pchCFile;
  540. case 't' : CFileInfo.pchTroffFile = pchCFile;
  541. case 'v' : CFileInfo.pchRasterFile = pchCFile;
  542. fUnsupportedCommand = TRUE;
  543. case 'l' : if (DocName != NULL) {
  544. DocReady = TRUE;
  545. break;
  546. }
  547. CFileInfo.pchUnfrmtdFile = pchCFile;
  548. if ( fAlwaysRawGLB ) {
  549. CFileInfo.szPrintFormat = LPD_RAW_STRING;
  550. }
  551. DocName = pchCFile;
  552. break;
  553. case 'p' : if (DocName != NULL) {
  554. DocReady = TRUE;
  555. break;
  556. }
  557. CFileInfo.pchPRFrmtFile = pchCFile;
  558. CFileInfo.szPrintFormat = LPD_TEXT_STRING;
  559. if ( fAlwaysRawGLB ) {
  560. CFileInfo.szPrintFormat = LPD_RAW_STRING;
  561. }
  562. DocName = pchCFile;
  563. break;
  564. case 'r' : if (DocName != NULL) {
  565. DocReady = TRUE;
  566. break;
  567. }
  568. CFileInfo.pchFortranFile = pchCFile;
  569. // if someone really sends 'r', treat it like text file
  570. CFileInfo.szPrintFormat = LPD_TEXT_STRING;
  571. if ( fAlwaysRawGLB ) {
  572. CFileInfo.szPrintFormat = LPD_RAW_STRING;
  573. }
  574. DocName = pchCFile;
  575. break;
  576. // unknown command! Ignore it
  577. default:
  578. fUnsupportedCommand = TRUE;
  579. break;
  580. } // end of switch( *pchCFile )
  581. if (DocReady) {
  582. pchCFile--;
  583. if ( ( CFileInfo.pchHost == NULL ) ||
  584. ( CFileInfo.pchUserName == NULL ) )
  585. {
  586. return( LPDERR_BADFORMAT );
  587. }
  588. if (!LicensingApproval( pscConn ))
  589. {
  590. return( LPDERR_BADFORMAT );
  591. }
  592. if (DocName != NULL) {
  593. PrintIt(pscConn, pCFile, &CFileInfo, DocName);
  594. }
  595. // Look for more work, first initialize correctly.
  596. // - MohsinA, 23-Jan-97.
  597. DocReady = FALSE;
  598. CFileInfo.usNumCopies = 1;
  599. CFileInfo.szPrintFormat = LPD_RAW_STRING;
  600. CFileInfo.pchSrcFile = NULL;
  601. CFileInfo.pchTitle = NULL;
  602. CFileInfo.pchUnlink = NULL;
  603. DocName = NULL;
  604. fUnsupportedCommand = FALSE;
  605. continue;
  606. }
  607. // we finished looking at the first char of the line
  608. dwBytesParsedSoFar++;
  609. // move to the end of the line
  610. while( !IS_LINEFEED_CHAR( *pchCFile ) )
  611. {
  612. pchCFile++;
  613. dwBytesParsedSoFar++;
  614. }
  615. // convert LF into 0 so each of our substrings above is now
  616. // a properly null-terminated string
  617. *pchCFile = '\0';
  618. pchCFile++;
  619. dwBytesParsedSoFar++;
  620. } // end of while( dwBytesParsedSoFar < pCFile->cbCFileLen )
  621. if( fUnsupportedCommand )
  622. {
  623. char *pszSource;
  624. if ( CFileInfo.pchUserName )
  625. pszSource = CFileInfo.pchUserName;
  626. else if ( CFileInfo.pchHost )
  627. pszSource = CFileInfo.pchHost;
  628. else
  629. pszSource = "Unknown";
  630. LpdReportEvent( LPDLOG_UNSUPPORTED_PRINT, 1, &pszSource, 0 );
  631. }
  632. if(DocName != NULL ){
  633. PrintIt(pscConn, pCFile, &CFileInfo, DocName);
  634. }
  635. #ifdef DBG
  636. if( !CFileInfo.pchSrcFile
  637. || strstr( CFileInfo.pchSrcFile, "debug" )
  638. ){
  639. print__controlfile_info( "ParseControlFile: all ok", &CFileInfo );
  640. print__sockconn( "ParseControlFile: entered", pscConn );
  641. print__cfile_entry( "ParseControlFile: ", pCFile );
  642. }
  643. #endif
  644. return( NO_ERROR );
  645. } // end ParseControlFile()