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.

2091 lines
67 KiB

  1. /*
  2. Microsoft Windows NT
  3. Copyright(c) Microsoft Corp., 1994-1997
  4. File: //KERNEL/RAZZLE3/src/sockets/tcpsvcs/lpd/print.c
  5. Revision History:
  6. Jan. 24,94 Koti Created
  7. 05-May-97 MohsinA Thread Pooling and Perf.
  8. Description:
  9. This file contains all the functions that make calls to the Spooler
  10. to print or manipulate a print job.
  11. */
  12. #include "lpd.h"
  13. BOOL IsPrinterDataSet( IN HANDLE hPrinter, IN LPTSTR pszParameterName );
  14. BOOL IsDataTypeRaw( PCHAR pchDataBuf, int cchBufferLen );
  15. extern FILE * pErrFile; // Debug output log file.
  16. #define MAX_PCL_SEARCH_DEPTH 4096
  17. /*****************************************************************************
  18. * *
  19. * ResumePrinting(): *
  20. * This function issues the PRINTER_CONTROL_RESUME to the spooler. *
  21. * *
  22. * Returns: *
  23. * NO_ERROR if everything went well *
  24. * ErrorCode if something went wrong somewhere *
  25. * *
  26. * Parameters: *
  27. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  28. * *
  29. * History: *
  30. * Jan.25, 94 Koti Created *
  31. * *
  32. *****************************************************************************/
  33. DWORD ResumePrinting( PSOCKCONN pscConn )
  34. {
  35. HANDLE hPrinter;
  36. PCHAR aszStrings[2];
  37. if( pscConn->pchPrinterName == NULL ){
  38. LPD_DEBUG( "ResumePrinting(): pscConn->pchPrinterName NULL.\n" );
  39. return( LPDERR_NOPRINTER );
  40. }
  41. if( !OpenPrinter( pscConn->pchPrinterName, &hPrinter, NULL ) ){
  42. LPD_DEBUG( "OpenPrinter() failed in ResumePrinting()\n" );
  43. return( LPDERR_NOPRINTER );
  44. }
  45. pscConn->hPrinter = hPrinter;
  46. if ( !SetPrinter( hPrinter, 0, NULL, PRINTER_CONTROL_RESUME ) )
  47. {
  48. LPD_DEBUG( "SetPrinter() failed in ResumePrinting()\n" );
  49. return( LPDERR_NOPRINTER );
  50. }
  51. aszStrings[0] = pscConn->szIPAddr;
  52. aszStrings[1] = pscConn->pchPrinterName;
  53. LpdReportEvent( LPDLOG_PRINTER_RESUMED, 2, aszStrings, 0 );
  54. pscConn->wState = LPDS_ALL_WENT_WELL;
  55. return( NO_ERROR );
  56. }
  57. /*****************************************************************************
  58. * *
  59. * InitializePrinter(): *
  60. * This function lays the ground work with the spooler so that we can *
  61. * print the job after receiving data from the client. *
  62. * *
  63. * Returns: *
  64. * NO_ERROR if initialization went well *
  65. * ErrorCode if something went wrong somewhere *
  66. * *
  67. * Parameters: *
  68. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  69. * *
  70. * History: *
  71. * Jan.25, 94 Koti Created *
  72. * *
  73. *****************************************************************************/
  74. DWORD InitializePrinter( PSOCKCONN pscConn )
  75. {
  76. HANDLE hPrinter;
  77. DWORD dwActualSize;
  78. DWORD dwErrcode;
  79. BOOL fBagIt = FALSE;
  80. PPRINTER_INFO_2 p2Info;
  81. PRINTER_DEFAULTS prtDefaults;
  82. LONG lcbDevModeSize;
  83. LONG lRetval;
  84. PDEVMODE pLocalDevMode;
  85. // Make sure a printer by this name exists!
  86. if ( ( pscConn->pchPrinterName == NULL )
  87. || ( !OpenPrinter( pscConn->pchPrinterName, &hPrinter, NULL ) ) )
  88. {
  89. LPD_DEBUG( "OpenPrinter() failed in InitializePrinter()\n" );
  90. return( LPDERR_NOPRINTER );
  91. }
  92. pscConn->hPrinter = hPrinter;
  93. // allocate a 4k buffer..
  94. p2Info = (PPRINTER_INFO_2)LocalAlloc( LMEM_FIXED, 4096 );
  95. if ( p2Info == NULL )
  96. {
  97. LPD_DEBUG( "4K LocalAlloc() failed in InitializePrinter\n" );
  98. return( LPDERR_NOBUFS );
  99. }
  100. // do a GetPrinter so that we know what the default pDevMode is. Then
  101. // we will modify the fields of our interest and do OpenPrinter again
  102. if ( !GetPrinter(hPrinter, 2, (LPBYTE)p2Info, 4096, &dwActualSize) )
  103. {
  104. if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  105. {
  106. LocalFree( p2Info );
  107. // 4k buffer wasn't enough: allocate however much that's needed
  108. p2Info = (PPRINTER_INFO_2)LocalAlloc( LMEM_FIXED, dwActualSize );
  109. if ( p2Info == NULL )
  110. {
  111. LPD_DEBUG( "LocalAlloc() failed in InitializePrinter\n" );
  112. return( LPDERR_NOBUFS );
  113. }
  114. if ( !GetPrinter(hPrinter, 2, (LPBYTE)p2Info, dwActualSize, &dwActualSize) )
  115. {
  116. LPD_DEBUG( "InitializePrinter(): GetPrinter failed again\n" );
  117. fBagIt = TRUE;
  118. }
  119. }
  120. else
  121. {
  122. fBagIt = TRUE;
  123. }
  124. }
  125. if ( fBagIt )
  126. {
  127. LPD_DEBUG( "InitializePrinter(): GetPrinter failed\n" );
  128. LocalFree( p2Info );
  129. return( LPDERR_NOPRINTER );
  130. }
  131. //
  132. // QFE: t-heathh - 25 Aug 1994 - Fixes 24342
  133. //
  134. // In the case where a printer has not yet been configured, the
  135. // pDevMode may come back NULL. In this case, we need to call
  136. // DocumentProperties to fill in the DevMode for us.
  137. //
  138. if ( p2Info->pDevMode == NULL )
  139. {
  140. // Get the size of the needed buffer.
  141. lcbDevModeSize = DocumentProperties( NULL, // No Dialog box, please
  142. hPrinter,
  143. pscConn->pchPrinterName,
  144. NULL, // No output buf
  145. NULL, // No input buf
  146. 0 ); // ( flags = 0 ) => return size of out buf
  147. if ( lcbDevModeSize < 0L )
  148. {
  149. LPD_DEBUG( "DocumentProperties not able to return needed BufSize\n" );
  150. LocalFree( p2Info );
  151. return( LPDERR_NOBUFS );
  152. }
  153. pLocalDevMode = LocalAlloc( LMEM_FIXED, lcbDevModeSize );
  154. if ( pLocalDevMode == NULL )
  155. {
  156. LPD_DEBUG( "Cannot allocate local DevMode\n" );
  157. LocalFree( p2Info );
  158. return( LPDERR_NOBUFS );
  159. }
  160. lRetval = DocumentProperties( NULL,
  161. hPrinter,
  162. pscConn->pchPrinterName,
  163. pLocalDevMode,
  164. NULL,
  165. DM_OUT_BUFFER );
  166. if ( lRetval < 0 )
  167. {
  168. LPD_DEBUG( "Document properties won't fill-in DevMode buffer.\n" );
  169. LocalFree( pLocalDevMode );
  170. LocalFree( p2Info );
  171. return( LPDERR_NOBUFS );
  172. }
  173. p2Info->pDevMode = pLocalDevMode;
  174. }
  175. else
  176. {
  177. pLocalDevMode = NULL;
  178. }
  179. p2Info->pDevMode->dmCopies = 1;
  180. //
  181. // Since we haven't even read the Data file yet, we can't have an override
  182. //
  183. pscConn->bDataTypeOverride = FALSE;
  184. // If not, set to default and UpdateJobInfo will correct it later
  185. prtDefaults.pDatatype = LPD_RAW_STRING;
  186. // Close it: we will open it again after modifying the pDevMode struct
  187. ShutdownPrinter( pscConn );
  188. prtDefaults.pDevMode = p2Info->pDevMode;
  189. prtDefaults.DesiredAccess = PRINTER_ACCESS_USE | PRINTER_ACCESS_ADMINISTER;
  190. if ( !OpenPrinter( pscConn->pchPrinterName, &hPrinter, &prtDefaults) )
  191. {
  192. LPD_DEBUG( "InitializePrinter(): second OpenPrinter() failed\n" );
  193. LocalFree( p2Info );
  194. if ( pLocalDevMode != NULL )
  195. {
  196. LocalFree( pLocalDevMode );
  197. pLocalDevMode = NULL;
  198. }
  199. return( LPDERR_NOPRINTER );
  200. }
  201. if ( pLocalDevMode != NULL )
  202. {
  203. LocalFree( pLocalDevMode );
  204. pLocalDevMode = NULL;
  205. }
  206. LocalFree( p2Info );
  207. pscConn->hPrinter = hPrinter;
  208. return( NO_ERROR );
  209. } // end InitializePrinter()
  210. /*****************************************************************************
  211. * *
  212. * UpdateJobInfo(): *
  213. * This function does a SetJob so that the spooler has more info about *
  214. * the job/client. *
  215. * *
  216. * Returns: *
  217. * NO_ERROR if initialization went well *
  218. * ErrorCode if something went wrong somewhere *
  219. * *
  220. * Parameters: *
  221. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  222. * *
  223. * History: *
  224. * Jan.25, 94 Koti Created *
  225. * *
  226. *****************************************************************************/
  227. DWORD UpdateJobInfo( PSOCKCONN pscConn, PCFILE_INFO pCFileInfo )
  228. {
  229. PJOB_INFO_2 pji2GetJob;
  230. DWORD dwNeeded;
  231. PCHAR pchTmpBuf;
  232. int ErrCode;
  233. int len;
  234. PCHAR pchModHostName=NULL;
  235. // first do a GetJob (that way we know all fields are valid to begin
  236. // with, and we only change the ones we want)
  237. // Mr.Spooler, how big a buffer should I allocate?
  238. if ( !GetJob( pscConn->hPrinter, pscConn->dwJobId, 2, NULL, 0, &dwNeeded ) )
  239. {
  240. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  241. {
  242. return( LPDERR_GODKNOWS );
  243. }
  244. }
  245. pji2GetJob = LocalAlloc( LMEM_FIXED, dwNeeded );
  246. if ( pji2GetJob == NULL )
  247. {
  248. return( LPDERR_NOBUFS );
  249. }
  250. if ( !GetJob( pscConn->hPrinter, pscConn->dwJobId, 2,
  251. (LPBYTE)pji2GetJob, dwNeeded, &dwNeeded ) )
  252. {
  253. LocalFree( pji2GetJob );
  254. return( LPDERR_GODKNOWS );
  255. }
  256. // store ip address, so we can match ip addr if the client later
  257. // sends request to delete this job (yes, that's our security!)
  258. pchTmpBuf = StoreIpAddr( pscConn );
  259. if (pchTmpBuf) {
  260. pji2GetJob->pUserName = pchTmpBuf;
  261. } else {
  262. pji2GetJob->pUserName = pCFileInfo->pchUserName;
  263. }
  264. pji2GetJob->pNotifyName = pCFileInfo->pchUserName;
  265. // Fill in the Job title.
  266. if ( pCFileInfo->pchTitle != NULL ) {
  267. pji2GetJob->pDocument = pCFileInfo->pchTitle;
  268. } else if ( pCFileInfo->pchSrcFile != NULL ) {
  269. pji2GetJob->pDocument = pCFileInfo->pchSrcFile;
  270. } else if ( pCFileInfo->pchJobName != NULL ) {
  271. pji2GetJob->pDocument = pCFileInfo->pchJobName;
  272. } else {
  273. pji2GetJob->pDocument = GETSTRING( LPD_DEFAULT_DOC_NAME );
  274. }
  275. if ( pCFileInfo->pchHost != NULL )
  276. {
  277. len = strlen(pCFileInfo->pchHost) + strlen(LPD_JOB_PREFIX) + 2;
  278. pchModHostName = LocalAlloc( LMEM_FIXED, len);
  279. if (pchModHostName)
  280. {
  281. // convert HostName to job=lpdHostName so lpr knows we set the name
  282. strcpy(pchModHostName, LPD_JOB_PREFIX);
  283. strcat(pchModHostName, pCFileInfo->pchHost);
  284. pji2GetJob->pParameters = pchModHostName;
  285. }
  286. }
  287. //
  288. // Set the datatype to what the control files reflects, unless the
  289. // auto-sense code has already overriden the control file.
  290. //
  291. // Illogical? Printit() might have overridden it or it is NULL.
  292. // - MohsinA, 23-Jan-97.
  293. //
  294. // if( !pscConn->bDataTypeOverride )?
  295. // if( pji2GetJob->pDatatype == NULL ){
  296. // pji2GetJob->pDatatype = pCFileInfo->szPrintFormat;
  297. // }
  298. pji2GetJob->Position = JOB_POSITION_UNSPECIFIED;
  299. ErrCode =
  300. SetJob( pscConn->hPrinter, pscConn->dwJobId, 2, (LPBYTE)pji2GetJob, 0 );
  301. if( ErrCode ){
  302. LPD_DEBUG("lpd:UpdateJobInfo: SetJob failed\n");
  303. }
  304. LocalFree( pji2GetJob );
  305. if (pchTmpBuf)
  306. {
  307. LocalFree( pchTmpBuf );
  308. }
  309. if (pchModHostName)
  310. {
  311. LocalFree( pchModHostName );
  312. }
  313. return( NO_ERROR );
  314. } // end UpdateJobInfo()
  315. /* ========================================================================
  316. Routine Description:
  317. This function looks at the data file contents and the registry settings to
  318. see if the control file specified data type shall be overridden.
  319. Arguments:
  320. pscConn - Pointer to a SOCKCONN that has already received the first part
  321. of the data file.
  322. Returns:
  323. NO_ERROR in the usual case, various error codes otherwise
  324. */
  325. DWORD UpdateJobType(
  326. PSOCKCONN pscConn,
  327. PCHAR pchDataBuf,
  328. DWORD cbDataLen
  329. )
  330. {
  331. PJOB_INFO_2 pji2GetJob;
  332. DWORD dwNeeded;
  333. PCHAR pchTmpBuf;
  334. BOOL override = FALSE;
  335. int ErrCode;
  336. // first do a GetJob (that way we know all fields are valid to begin
  337. // with, and we only change the ones we want)
  338. // Mr.Spooler, how big a buffer should I allocate?
  339. if ( !GetJob( pscConn->hPrinter, pscConn->dwJobId, 2, NULL, 0, &dwNeeded ) )
  340. {
  341. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  342. {
  343. LPD_DEBUG("lpd:UpdateJobType: GetJob failed/1.\n");
  344. return( LPDERR_GODKNOWS );
  345. }
  346. }
  347. pji2GetJob = LocalAlloc( LMEM_FIXED, dwNeeded );
  348. if ( pji2GetJob == NULL )
  349. {
  350. LPD_DEBUG("lpd:UpdateJobType: no mem.\n");
  351. return( LPDERR_NOBUFS );
  352. }
  353. if ( !GetJob( pscConn->hPrinter, pscConn->dwJobId, 2,
  354. (LPBYTE)pji2GetJob, dwNeeded, &dwNeeded ) )
  355. {
  356. LPD_DEBUG("lpd:UpdateJobType: GetJob failed/2.\n");
  357. LocalFree( pji2GetJob );
  358. return( LPDERR_GODKNOWS );
  359. }
  360. //
  361. // Set the datatype to NULL so that we will know if it isn't explicitly
  362. // set by the registry.
  363. //
  364. //
  365. // See if this printer has a registry setting that tells us to always
  366. // print the job as RAW data. This registry value is accessed through
  367. // the {Get|Set}PrinterData API that will always know where to look
  368. // for printer settings.
  369. //
  370. // MohsinA, 23-Jan-97.
  371. if ( IsPrinterDataSet( pscConn->hPrinter,
  372. TEXT( LPD_PARMNAME_PRINTER_PASS_THROUGH ))
  373. ){
  374. #if DBG
  375. LpdPrintf( "Printer %s has registry setting for PASS_THROUGH mode.\n",
  376. pscConn->pchPrinterName );
  377. #endif
  378. override = TRUE;
  379. // else not PASS_THROUGH and AUTO-DETECT for raw job type.
  380. }else if( !IsPrinterDataSet( pscConn->hPrinter,
  381. TEXT( LPD_PARMNAME_DONT_DETECT ))
  382. && IsDataTypeRaw( pchDataBuf, cbDataLen )
  383. ){
  384. // We detect PS or PCL, so make it raw.
  385. override = TRUE;
  386. }
  387. if ( override ){
  388. #if DBG
  389. LpdPrintf( "Printer %s override to raw mode.\n",
  390. pscConn->pchPrinterName );
  391. #endif
  392. pscConn->bDataTypeOverride = TRUE;
  393. pji2GetJob->pDatatype = LPD_RAW_STRING;
  394. ErrCode =
  395. SetJob( pscConn->hPrinter, pscConn->dwJobId, 2, (LPBYTE)pji2GetJob, 0 );
  396. if( ErrCode ){
  397. LPD_DEBUG("lpd:UpdateJobType: SetJob failed.\n");
  398. LocalFree( pji2GetJob );
  399. return LPDERR_GODKNOWS;
  400. }
  401. }
  402. LocalFree( pji2GetJob );
  403. return( NO_ERROR );
  404. } // end UpdateJobInfo()
  405. /*****************************************************************************
  406. * *
  407. * StoreIpAddr(): *
  408. * This function returns a buffer that contains the user name with the *
  409. * ip address appended to it, so that if a request comes in later to *
  410. * delete the job, we match the ipaddrs (some security at least!) *
  411. * *
  412. * Returns: *
  413. * Pointer to a buffer that contains the modified user name *
  414. * NULL If the name is not modified (unlikely, but possible if lpd and *
  415. * lprmon point to each other!), or if malloc fails. *
  416. * *
  417. * Parameters: *
  418. * pscConn (IN) : pointer to SOCKCONN structure for this connection *
  419. * *
  420. * Notes: Caller must free the buffer that's allocated here *
  421. * *
  422. * History: *
  423. * Jan.17, 95 Koti Created *
  424. * *
  425. *****************************************************************************/
  426. PCHAR StoreIpAddr( PSOCKCONN pscConn )
  427. {
  428. DWORD dwBufLen;
  429. PCHAR pchBuf;
  430. PCHAR pchUserName;
  431. DWORD i;
  432. DWORD dwDots=0;
  433. BOOL fOpenPara=FALSE, fClosePara=FALSE;
  434. pchUserName = pscConn->pchUserName;
  435. //
  436. // if the user name was "Koti" then it will be "Koti (11.101.4.25)" after
  437. // this function.
  438. // In some configurations (e.g. point lpd to lprmon and lprmon back to lpd)
  439. // we could keep appending ipaddrs for each instance of the job. First
  440. // find out if ipaddr is already appended
  441. //
  442. dwBufLen = strlen (pchUserName);
  443. for (i=0; i<dwBufLen; i++)
  444. {
  445. switch( *(pchUserName+i) )
  446. {
  447. case '(': fOpenPara = TRUE;
  448. break;
  449. case ')': fClosePara = TRUE;
  450. break;
  451. case '.': dwDots++;
  452. break;
  453. }
  454. }
  455. //
  456. // if name already contains the ipaddr, don't append again
  457. //
  458. if (fOpenPara && fClosePara && dwDots >= 3)
  459. {
  460. return( NULL );
  461. }
  462. // buffer to store a string in the form "Koti (11.101.4.25)"
  463. dwBufLen += INET6_ADDRSTRLEN + 4;
  464. pchBuf = LocalAlloc (LMEM_FIXED, dwBufLen);
  465. if (pchBuf == NULL)
  466. {
  467. LPD_DEBUG( "StoreIpAddr(): LocalAlloc failed\n" );
  468. return( NULL );
  469. }
  470. sprintf (pchBuf, "%s (%s)", pchUserName, pscConn->szIPAddr);
  471. return( pchBuf );
  472. } // end StoreIpAddr()
  473. // ========================================================================
  474. //
  475. // Sends profiling information back on socket qsock.
  476. // Scans the wait queue and reports clients/peers also.
  477. //
  478. // Created: MohsinA, 05-May-97.
  479. //
  480. #ifdef PROFILING
  481. void
  482. SendProfileStatus( SOCKET qsock )
  483. {
  484. char buff[4000], buff2[NI_MAXHOST];
  485. int buflen;
  486. COMMON_LPD local_common = Common; // struct copy, for readonly.
  487. PSOCKCONN pscConn = NULL; // S0186, B#101002, MohsinA, 18/8/97.
  488. SOCKCONN local_sockconn;
  489. int again = 1;
  490. int ok;
  491. int count = 0;
  492. SOCKET csocket;
  493. SOCKADDR_STORAGE csock_addr;
  494. int csock_len;
  495. // ====================================================================
  496. // First send the Common information.
  497. buflen =
  498. sprintf(buff,
  499. "--- PROFILING NT 5.0 LPD Server of %s %s ---\n"
  500. "AliveThreads=%d, MaxThreads=%d, TotalAccepts=%d,\n"
  501. "TotalErrors=%d, QueueLength=%d\n"
  502. ,
  503. __DATE__, __TIME__,
  504. local_common.AliveThreads,
  505. local_common.MaxThreads,
  506. local_common.TotalAccepts,
  507. local_common.TotalErrors,
  508. local_common.QueueLength
  509. );
  510. if( buflen > 0 ){
  511. assert( buflen < sizeof( buff ) );
  512. SendData( qsock, buff, buflen );
  513. }
  514. // ====================================================================
  515. // Now scan the wait queue.
  516. EnterCriticalSection( &csConnSemGLB );
  517. while( again && !fShuttingDownGLB ){
  518. {
  519. if( pscConn == NULL ){ // First time?
  520. pscConn = scConnHeadGLB.pNext;
  521. }else{
  522. pscConn = pscConn->pNext;
  523. }
  524. if( pscConn == NULL ){
  525. again = 0;
  526. }else{
  527. local_sockconn = *pscConn; // struct copy.
  528. csocket = local_sockconn.sSock;
  529. csock_len = sizeof(csock_addr);
  530. ok = getpeername( csocket,
  531. (SOCKADDR *) &csock_addr,
  532. &csock_len );
  533. }
  534. }
  535. if( fShuttingDownGLB || !again )
  536. break;
  537. count++;
  538. assert( count <= local_common.QueueLength );
  539. if( ok == SOCKET_ERROR ){
  540. buflen = sprintf( buff, "(%d) Bad peer, err=%d, queued at %s",
  541. count,
  542. GetLastError(),
  543. ctime(&local_sockconn.time_queued )
  544. );
  545. }else{
  546. buflen = NI_MAXHOST;
  547. WSAAddressToString((LPSOCKADDR)&csock_addr, csock_len, NULL,
  548. buff2, &buflen);
  549. buflen = sprintf( buff, "(%d) Client %s queued since %s",
  550. count,
  551. buff2,
  552. ctime(&local_sockconn.time_queued )
  553. );
  554. }
  555. if( buflen > 0 ){
  556. assert( buflen < sizeof( buff ) );
  557. SendData( qsock, buff, buflen );
  558. }
  559. } // end while pscConn.
  560. LeaveCriticalSection( &csConnSemGLB );
  561. return;
  562. }
  563. #endif
  564. /*****************************************************************************
  565. * *
  566. * SendQueueStatus(): *
  567. * This function retrieves the status of all the jobs on the printer of *
  568. * our interest and sends over to the client. If the client specified *
  569. * users and/or job-ids in the status request then we send status of jobs *
  570. * of only those users and/or those job-ids. *
  571. * *
  572. * Returns: *
  573. * Nothing *
  574. * *
  575. * Parameters: *
  576. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  577. * wMode (IN): whether short or long status info is requested *
  578. * *
  579. * History: *
  580. * Jan.25, 94 Koti Created *
  581. * *
  582. *****************************************************************************/
  583. VOID SendQueueStatus( PSOCKCONN pscConn, WORD wMode )
  584. {
  585. BOOL fResult;
  586. HANDLE hPrinter;
  587. DWORD dwBufSize;
  588. DWORD dwHdrsize;
  589. DWORD dwNumJobs;
  590. PCHAR pchSndBuf=NULL;
  591. PCHAR pchSpoolerBuf=NULL;
  592. BOOL fNoPrinter=FALSE;
  593. BOOL fAtLeastOneJob=TRUE;
  594. CHAR szPrinterNameAndStatus[300];
  595. int nResult;
  596. // for now, we return the same status info regardless of whether
  597. // the client asked for Short or Long queue Status. This might
  598. // be enough since we are giving adequate info anyway
  599. #ifdef PROFILING
  600. SendProfileStatus( pscConn->sSock );
  601. #endif
  602. if ( ( pscConn->pchPrinterName == NULL )
  603. || ( !OpenPrinter( pscConn->pchPrinterName, &hPrinter, NULL ) ) )
  604. {
  605. LPD_DEBUG( "OpenPrinter() failed in SendQueueStatus()\n" );
  606. fNoPrinter = TRUE;
  607. goto SendQueueStatus_BAIL;
  608. }
  609. pscConn->hPrinter = hPrinter;
  610. pchSpoolerBuf = LocalAlloc( LMEM_FIXED, 4096 );
  611. if ( pchSpoolerBuf == NULL )
  612. {
  613. goto SendQueueStatus_BAIL;
  614. }
  615. // store the printer name (we might append status to it)
  616. strcpy( szPrinterNameAndStatus, pscConn->pchPrinterName );
  617. // do a get printer to see how the printer is doing
  618. if ( GetPrinter(pscConn->hPrinter, 2, pchSpoolerBuf, 4096, &dwBufSize) )
  619. {
  620. if ( ((PPRINTER_INFO_2)pchSpoolerBuf)->Status == PRINTER_STATUS_PAUSED )
  621. {
  622. strcat( szPrinterNameAndStatus, GETSTRING( LPD_PRINTER_PAUSED ) );
  623. }
  624. else if ( ((PPRINTER_INFO_2)pchSpoolerBuf)->Status == PRINTER_STATUS_PENDING_DELETION )
  625. {
  626. strcat( szPrinterNameAndStatus, GETSTRING( LPD_PRINTER_PENDING_DEL ) );
  627. }
  628. }
  629. else
  630. {
  631. LPD_DEBUG( "GetPrinter() failed in SendQueueStatus()\n" );
  632. }
  633. // Since OpenPrinter succeeded, we will be sending to the client
  634. // at least dwHdrsize bytes that includes the printername
  635. dwHdrsize = strlen( GETSTRING( LPD_LOGO ) )
  636. + strlen( GETSTRING( LPD_PRINTER_TITLE) )
  637. + strlen( szPrinterNameAndStatus )
  638. + strlen( GETSTRING( LPD_QUEUE_HEADER ))
  639. + strlen( GETSTRING( LPD_QUEUE_HEADER2))
  640. + strlen( LPD_NEWLINE );
  641. //
  642. // query spooler for all the jobs currently pending
  643. // (we have already allocate 4K buffer)
  644. //
  645. dwBufSize = 4096;
  646. while(1)
  647. {
  648. fResult = EnumJobs( pscConn->hPrinter, 0, LPD_MAXJOBS_ENUM, 2,
  649. pchSpoolerBuf, dwBufSize, &dwBufSize, &dwNumJobs );
  650. // most common case: will work the first time
  651. if (fResult == TRUE)
  652. {
  653. break;
  654. }
  655. // it's possible spooler got a new job, and our buffer is now small
  656. // so it returns ERROR_INSUFFICIENT_BUFFER. Other than that, quit!
  657. if ( (fResult == FALSE) &&
  658. ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) )
  659. {
  660. goto SendQueueStatus_BAIL;
  661. }
  662. LocalFree( pchSpoolerBuf );
  663. // spooler wants more memory: allocate it
  664. pchSpoolerBuf = LocalAlloc( LMEM_FIXED, dwBufSize );
  665. if ( pchSpoolerBuf == NULL )
  666. {
  667. goto SendQueueStatus_BAIL;
  668. }
  669. }
  670. if (dwNumJobs == 0)
  671. {
  672. fAtLeastOneJob = FALSE;
  673. }
  674. // header, and one line per job that's queued (potentially, dwNumJobs=0)
  675. dwBufSize = dwHdrsize + ( dwNumJobs * LPD_LINE_SIZE );
  676. // to put a newline at the end of display!
  677. dwBufSize += sizeof( LPD_NEWLINE );
  678. ShutdownPrinter( pscConn );
  679. // this is the buffer we use to send the data out
  680. pchSndBuf = LocalAlloc( LMEM_FIXED, dwBufSize );
  681. if ( pchSndBuf == NULL )
  682. {
  683. goto SendQueueStatus_BAIL;
  684. }
  685. // copy the dwHdrsize bytes of header
  686. nResult = sprintf( pchSndBuf, "%s%s%s%s%s%s", GETSTRING( LPD_LOGO ),
  687. GETSTRING( LPD_PRINTER_TITLE ),
  688. szPrinterNameAndStatus,
  689. GETSTRING( LPD_QUEUE_HEADER ),
  690. GETSTRING( LPD_QUEUE_HEADER2 ),
  691. LPD_NEWLINE );
  692. //
  693. // watch for buffer overwrites
  694. //
  695. LPD_ASSERT( nResult == (int) dwHdrsize );
  696. // if there are any jobs, fill the buffer with status
  697. // of each of the jobs
  698. if ( fAtLeastOneJob )
  699. {
  700. nResult += FillJobStatus( pscConn, (pchSndBuf + dwHdrsize ),
  701. (PJOB_INFO_2)pchSpoolerBuf, dwNumJobs );
  702. LPD_ASSERT ((int) dwBufSize >= nResult);
  703. if (nResult > (int) dwBufSize)
  704. {
  705. nResult = (int) dwBufSize;
  706. }
  707. }
  708. // not much can be done if SendData fails!
  709. SendData( pscConn->sSock, pchSndBuf, nResult);
  710. if ( pchSpoolerBuf != NULL )
  711. {
  712. LocalFree( pchSpoolerBuf );
  713. }
  714. LocalFree( pchSndBuf );
  715. pscConn->wState = LPDS_ALL_WENT_WELL;
  716. return;
  717. // if we reached here, some error occured while getting job status.
  718. // Tell the client that we had a problem!
  719. SendQueueStatus_BAIL:
  720. ShutdownPrinter( pscConn );
  721. if ( pchSndBuf != NULL )
  722. {
  723. LocalFree( pchSndBuf );
  724. }
  725. if ( pchSpoolerBuf != NULL )
  726. {
  727. LocalFree( pchSpoolerBuf );
  728. }
  729. // just add size of all possible error messages, so we have room for
  730. // the largest message!
  731. dwBufSize = strlen( GETSTRING( LPD_LOGO ) ) + strlen( GETSTRING( LPD_QUEUE_ERRMSG ) )
  732. + strlen( GETSTRING( LPD_QUEUE_NOPRINTER ) );
  733. pchSndBuf = LocalAlloc( LMEM_FIXED, dwBufSize );
  734. if ( pchSndBuf == NULL )
  735. {
  736. return;
  737. }
  738. if ( fNoPrinter )
  739. {
  740. LPD_DEBUG( "Rejected status request for non-existent printer\n" );
  741. sprintf( pchSndBuf, "%s%s", GETSTRING( LPD_LOGO ), GETSTRING( LPD_QUEUE_NOPRINTER ) );
  742. }
  743. else
  744. {
  745. LPD_DEBUG( "Something went wrong in SendQueueStatus()\n" );
  746. sprintf( pchSndBuf, "%s%s", GETSTRING( LPD_LOGO ), GETSTRING( LPD_QUEUE_ERRMSG ) );
  747. }
  748. // Not much can be done about an error here: don't bother checking!
  749. SendData( pscConn->sSock, pchSndBuf, dwBufSize );
  750. LocalFree( pchSndBuf );
  751. return;
  752. } // end SendQueueStatus()
  753. /*****************************************************************************
  754. * *
  755. * ShutDownPrinter(): *
  756. * This function closes the printer in our context. *
  757. * *
  758. * Returns: *
  759. * Nothing *
  760. * *
  761. * Parameters: *
  762. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  763. * *
  764. * History: *
  765. * Jan.25, 94 Koti Created *
  766. * *
  767. *****************************************************************************/
  768. VOID ShutdownPrinter( PSOCKCONN pscConn )
  769. {
  770. if ( pscConn->hPrinter == (HANDLE)INVALID_HANDLE_VALUE )
  771. {
  772. return;
  773. }
  774. if ( ClosePrinter( pscConn->hPrinter ) )
  775. {
  776. pscConn->hPrinter = (HANDLE)INVALID_HANDLE_VALUE;
  777. }
  778. else
  779. {
  780. LPD_DEBUG( "ShutDownPrinter: ClosePrinter failed\n" );
  781. }
  782. return;
  783. } // end ShutdownPrinter()
  784. /*****************************************************************************
  785. * *
  786. * SpoolData(): *
  787. * This function writes the data that we got from client into spool file. *
  788. * *
  789. * Returns: *
  790. * NO_ERROR if things went well *
  791. * ErrorCode if something didn't go right *
  792. * *
  793. * Parameters: *
  794. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  795. * *
  796. * History: *
  797. * Jan.25, 94 Koti Created *
  798. * *
  799. *****************************************************************************/
  800. DWORD SpoolData( HANDLE hSpoolFile, PCHAR pchDataBuf, DWORD cbDataBufLen )
  801. {
  802. DWORD dwBytesWritten;
  803. BOOL fRetval;
  804. fRetval = WriteFile( hSpoolFile, pchDataBuf,
  805. cbDataBufLen, &dwBytesWritten, NULL );
  806. // if WriteFile failed, or if fewer bytes got written, quit!
  807. if ( (fRetval == FALSE) || (dwBytesWritten != cbDataBufLen) )
  808. {
  809. LPD_DEBUG( "WriteFile() failed in SpoolData\n" );
  810. return( LPDERR_NOPRINTER );
  811. }
  812. return( NO_ERROR );
  813. } // end SpoolData()
  814. /*****************************************************************************
  815. * *
  816. * PrintData(): *
  817. * This function tells the spooler that we are done writing to the spool *
  818. * file and that it should go ahead and dispatch it. *
  819. * *
  820. * Returns: *
  821. * NO_ERROR if everything went ok *
  822. * *
  823. * Parameters: *
  824. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  825. * *
  826. * History: *
  827. * Jan.25, 94 Koti Created *
  828. * *
  829. *****************************************************************************/
  830. DWORD PrintData( PSOCKCONN pscConn )
  831. {
  832. CFILE_ENTRY *pCFile;
  833. DWORD dwRetval;
  834. LIST_ENTRY *pTmpList;
  835. while ( !IsListEmpty( &pscConn->CFile_List ) ) {
  836. pTmpList = RemoveHeadList( &pscConn->CFile_List );
  837. pCFile = CONTAINING_RECORD( pTmpList,
  838. CFILE_ENTRY,
  839. Link );
  840. if ( (dwRetval = ParseControlFile( pscConn, pCFile )) != NO_ERROR )
  841. {
  842. PCHAR aszStrings[2]={ pscConn->szIPAddr, NULL };
  843. LpdReportEvent( LPDLOG_BAD_FORMAT, 1, aszStrings, 0 );
  844. pscConn->fLogGenericEvent = FALSE;
  845. LPD_DEBUG( "ParseControlFile() failed in ProcessJob()\n" );
  846. CleanupCFile( pCFile );
  847. return( dwRetval ); // the thread exits
  848. }
  849. CleanupCFile( pCFile );
  850. }
  851. return( NO_ERROR );
  852. } // end PrintData()
  853. /*****************************************************************************
  854. * *
  855. * PrintIt(): *
  856. * This function tells the spooler that we are done writing to the spool *
  857. * file and that it should go ahead and dispatch it. *
  858. * *
  859. * Returns: *
  860. * Nothing *
  861. * *
  862. * Parameters: *
  863. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  864. * *
  865. * History: *
  866. * *
  867. *****************************************************************************/
  868. DWORD
  869. PrintIt(
  870. PSOCKCONN pscConn,
  871. PCFILE_ENTRY pCFileEntry,
  872. PCFILE_INFO pCFileInfo,
  873. PCHAR pFileName
  874. )
  875. {
  876. DOC_INFO_1 dc1Info;
  877. PDFILE_ENTRY pDFile;
  878. DWORD cbTotalDataLen;
  879. DWORD cbBytesSpooled;
  880. DWORD cbBytesToSpool;
  881. DWORD cbDataBufLen;
  882. DWORD cbBytesRemaining;
  883. DWORD cbBytesActuallySpooled;
  884. PCHAR pchDataBuf;
  885. DWORD dwRetval;
  886. BOOL fRetval;
  887. USHORT cbCount;
  888. #ifdef DBG
  889. if( !pCFileInfo || !pCFileInfo->pchSrcFile
  890. || strstr( pCFileInfo->pchSrcFile, "debug" )
  891. ){
  892. print__controlfile_info( "PrintIt: ", pCFileInfo );
  893. print__cfile_entry( "Printit: ", pCFileEntry );
  894. }
  895. #endif
  896. memset( &dc1Info, 0, sizeof( dc1Info ) );
  897. // Defaults.
  898. dc1Info.pDatatype = LPD_RAW_STRING;
  899. // Get the job title if any.
  900. if ( pCFileInfo->pchTitle != NULL ) {
  901. dc1Info.pDocName = pCFileInfo->pchTitle;
  902. } else if ( pCFileInfo->pchSrcFile != NULL ) {
  903. dc1Info.pDocName = pCFileInfo->pchSrcFile;
  904. } else if ( pCFileInfo->pchJobName != NULL ) {
  905. dc1Info.pDocName = pCFileInfo->pchJobName;
  906. } else {
  907. dc1Info.pDocName
  908. = pCFileInfo->pchTitle
  909. = pCFileInfo->pchJobName
  910. = pCFileInfo->pchSrcFile
  911. = pFileName;
  912. }
  913. dc1Info.pOutputFile = NULL; // we aren't writing to file
  914. //
  915. // If datatype is known, set it.
  916. // Doesn't it default to raw? - MohsinA, 23-Jan-97.
  917. //
  918. if( pCFileInfo->szPrintFormat != NULL ) {
  919. dc1Info.pDatatype = pCFileInfo->szPrintFormat;
  920. }
  921. for (cbCount = 0; cbCount < pCFileInfo->usNumCopies; cbCount++) {
  922. pscConn->dwJobId = StartDocPrinter( pscConn->hPrinter, 1, (LPBYTE)&dc1Info ) ;
  923. if ( pscConn->dwJobId == 0 )
  924. {
  925. LPD_DEBUG( "InitializePrinter(): StartDocPrinter() failed\n" );
  926. return( LPDERR_NOPRINTER );
  927. }
  928. UpdateJobInfo( pscConn, pCFileInfo );
  929. #ifdef DBG
  930. if( !pCFileInfo || !pCFileInfo->pchSrcFile
  931. || strstr( pCFileInfo->pchSrcFile, "debug" )
  932. ){
  933. print__controlfile_info( "PrintIt: after UpdateJobInfo ", pCFileInfo );
  934. print__cfile_entry( "Printit: after UpdateJobInfo", pCFileEntry );
  935. }
  936. #endif
  937. if (!IsListEmpty( &pscConn->DFile_List ) ) {
  938. pDFile = (PDFILE_ENTRY)pscConn->DFile_List.Flink;
  939. while (strncmp( pDFile->pchDFileName, pFileName, strlen(pFileName) ) != 0 ) {
  940. pDFile = (PDFILE_ENTRY)pDFile->Link.Flink;
  941. if (pDFile == (PDFILE_ENTRY)&pscConn->DFile_List) {
  942. return( LPDERR_BADFORMAT );
  943. }
  944. }
  945. dwRetval = SetFilePointer( pDFile->hDataFile, 0, NULL, FILE_BEGIN );
  946. if (dwRetval == 0xFFFFFFFF) {
  947. LPD_DEBUG( "ERROR: SetFilePointer() failed in PrintIt\n" );
  948. return( LPDERR_GODKNOWS );
  949. }
  950. cbTotalDataLen = pDFile->cbDFileLen;
  951. cbBytesToSpool = (cbTotalDataLen > LPD_BIGBUFSIZE ) ?
  952. LPD_BIGBUFSIZE : cbTotalDataLen;
  953. pchDataBuf = LocalAlloc( LMEM_FIXED, cbBytesToSpool );
  954. if ( pchDataBuf == NULL )
  955. {
  956. CloseHandle(pDFile->hDataFile);
  957. pDFile->hDataFile = INVALID_HANDLE_VALUE;
  958. return( (DWORD)LPDERR_NOBUFS );
  959. }
  960. cbBytesSpooled = 0;
  961. cbBytesRemaining = cbTotalDataLen;
  962. // keep receiving until we have all the data client said it
  963. // would send
  964. while( cbBytesSpooled < cbTotalDataLen )
  965. {
  966. fRetval = ReadFile( pDFile->hDataFile,
  967. pchDataBuf,
  968. cbBytesToSpool,
  969. &cbBytesActuallySpooled,
  970. NULL );
  971. if ( (!fRetval) || (cbBytesActuallySpooled != cbBytesToSpool) )
  972. {
  973. LPD_DEBUG( "ReadFile() failed in PrintIt(): job aborted)\n" );
  974. LocalFree( pchDataBuf );
  975. CloseHandle(pDFile->hDataFile);
  976. pDFile->hDataFile = INVALID_HANDLE_VALUE;
  977. return( LPDERR_NOPRINTER );
  978. }
  979. // MohsinA, 23-Jan-97?
  980. if ( cbBytesSpooled == 0 ) {
  981. UpdateJobType( pscConn, pchDataBuf, cbBytesToSpool );
  982. }
  983. cbDataBufLen = cbBytesToSpool;
  984. fRetval = WritePrinter( pscConn->hPrinter,
  985. pchDataBuf,
  986. cbBytesToSpool,
  987. &cbBytesActuallySpooled);
  988. if ( (fRetval==FALSE) || (cbBytesToSpool != cbBytesActuallySpooled) )
  989. {
  990. LPD_DEBUG( "WritePrinter() failed in PrintIt():job aborted)\n" );
  991. LocalFree( pchDataBuf );
  992. CloseHandle(pDFile->hDataFile);
  993. pDFile->hDataFile = INVALID_HANDLE_VALUE;
  994. return( LPDERR_NOPRINTER );
  995. }
  996. cbBytesSpooled += cbBytesToSpool;
  997. cbBytesRemaining -= cbBytesToSpool;
  998. cbBytesToSpool = (cbBytesRemaining > LPD_BIGBUFSIZE ) ?
  999. LPD_BIGBUFSIZE : cbBytesRemaining;
  1000. }
  1001. LocalFree( pchDataBuf );
  1002. if ( !EndDocPrinter( pscConn->hPrinter ) )
  1003. {
  1004. LPD_DEBUG( "EndDocPrinter() failed in PrintData\n" );
  1005. return( LPDERR_NOPRINTER );
  1006. }
  1007. }
  1008. }
  1009. return(NO_ERROR);
  1010. } // end PrintIt()
  1011. /*****************************************************************************
  1012. * *
  1013. * AbortThisJob(): *
  1014. * This function tells the spooler to abort the specified job. *
  1015. * *
  1016. * Returns: *
  1017. * Nothing *
  1018. * *
  1019. * Parameters: *
  1020. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  1021. * *
  1022. * History: *
  1023. * Jan.25, 94 Koti Created *
  1024. * *
  1025. *****************************************************************************/
  1026. VOID AbortThisJob( PSOCKCONN pscConn )
  1027. {
  1028. assert( pscConn );
  1029. if( pscConn->hPrinter == INVALID_HANDLE_VALUE )
  1030. {
  1031. LOGIT(("lpd:AbortThisJob: invalid hPrinter %d.\n",
  1032. pscConn->hPrinter ));
  1033. return;
  1034. }
  1035. // not much can be done if there is an error: don't bother checking
  1036. if (!SetJob( pscConn->hPrinter,
  1037. pscConn->dwJobId,
  1038. 0,
  1039. NULL,
  1040. JOB_CONTROL_CANCEL )
  1041. )
  1042. {
  1043. LPD_DEBUG( "AbortThisJob: SetJob failed\n");
  1044. }
  1045. if ( !EndDocPrinter( pscConn->hPrinter ) )
  1046. {
  1047. LPD_DEBUG( "EndDocPrinter() failed in AbortThisJob\n" );
  1048. }
  1049. LPD_DEBUG( "AbortThisJob(): job aborted\n" );
  1050. return;
  1051. } // end AbortThisJob()
  1052. /*****************************************************************************
  1053. * *
  1054. * RemoveJobs(): *
  1055. * This function removes all the jobs the user has asked us to remove, *
  1056. * after verifying that the job was indeed sent originally by the same *
  1057. * user (ip addresses of machine sending the original job and the request *
  1058. * to remove it should match). *
  1059. * *
  1060. * Returns: *
  1061. * NO_ERROR if everything went ok *
  1062. * Errorcode if job couldn't be deleted *
  1063. * *
  1064. * Parameters: *
  1065. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  1066. * *
  1067. * History: *
  1068. * Jan.25, 94 Koti Created *
  1069. * *
  1070. *****************************************************************************/
  1071. DWORD RemoveJobs( PSOCKCONN pscConn )
  1072. {
  1073. PQSTATUS pqStatus;
  1074. PJOB_INFO_1 pji1GetJob;
  1075. BOOL fSuccess=TRUE;
  1076. HANDLE hPrinter;
  1077. DWORD dwNeeded;
  1078. DWORD dwBufLen;
  1079. PCHAR pchUserName;
  1080. PCHAR pchIPAddr;
  1081. DWORD i, j;
  1082. if ( (pqStatus = pscConn->pqStatus) == NULL )
  1083. {
  1084. return( LPDERR_BADFORMAT );
  1085. }
  1086. if ( ( pscConn->pchPrinterName == NULL )
  1087. || ( !OpenPrinter( pscConn->pchPrinterName, &hPrinter, NULL ) ) )
  1088. {
  1089. LPD_DEBUG( "OpenPrinter() failed in RemoveJobs()\n" );
  1090. return( LPDERR_NOPRINTER );
  1091. }
  1092. pscConn->hPrinter = hPrinter;
  1093. // the "List" field can contain UserNames or JobId's of the jobs to be
  1094. // removed. Even though we parse UserNames into the ppchUsers[] array
  1095. // (in pqStatus struct), we only use the JobId's, and not use the UserNames
  1096. // at all. Reason is we only want to remove jobs that the user submitted
  1097. // and not allow a user to specify other usernames.
  1098. // try to remove every job the user has asked us to remove
  1099. for ( i=0; i<pqStatus->cbActualJobIds; i++ )
  1100. {
  1101. // ask GetJob how big a buffer we must pass. If the errorcode is
  1102. // anything other than ERROR_INSUFFICIENT_BUFFER, the job must be
  1103. // done (so JobId is invalid), and we won't do anything
  1104. if ( !GetJob( pscConn->hPrinter, pqStatus->adwJobIds[i], 1,
  1105. NULL, 0, &dwNeeded ) )
  1106. {
  1107. if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
  1108. {
  1109. LPD_DEBUG( "lpd:RemoveJobs: GetJob failed.\n" );
  1110. fSuccess = FALSE;
  1111. continue;
  1112. }
  1113. }
  1114. pji1GetJob = LocalAlloc( LMEM_FIXED, dwNeeded );
  1115. if ( pji1GetJob == NULL )
  1116. {
  1117. LPD_DEBUG("lpd:RemoveJobs: no mem\n");
  1118. return( LPDERR_NOBUFS );
  1119. }
  1120. if ( !GetJob( pscConn->hPrinter, pqStatus->adwJobIds[i], 1,
  1121. (LPBYTE)pji1GetJob, dwNeeded, &dwNeeded ) )
  1122. {
  1123. fSuccess = FALSE;
  1124. LocalFree( pji1GetJob );
  1125. continue;
  1126. }
  1127. // pUserName is in the form "Koti (11.101.4.25)"
  1128. // (we store the string in this exact format (in UpdateJobInfo()))
  1129. // Also, jobs coming from unix can't use space in user name, so if
  1130. // we do find a space, it must be the one we introduced (before '(' )
  1131. pchUserName = pji1GetJob->pUserName;
  1132. dwBufLen = strlen( pchUserName );
  1133. pchIPAddr = pchUserName;
  1134. j = 0;
  1135. while( *pchIPAddr != ')' ) // first convert the last ')' to '\0'
  1136. {
  1137. pchIPAddr++;
  1138. j++;
  1139. //
  1140. // if we traversed the entire name and didn't find ')', something
  1141. // isn't right (e.g. not one of our jobs): just skip this one
  1142. //
  1143. if (j >= dwBufLen)
  1144. {
  1145. LocalFree( pji1GetJob );
  1146. break;
  1147. }
  1148. }
  1149. if (j >= dwBufLen)
  1150. {
  1151. continue;
  1152. }
  1153. *pchIPAddr = '\0'; // convert the ')' to '\0'
  1154. pchIPAddr = pchUserName;
  1155. while ( !IS_WHITE_SPACE( *pchIPAddr ) )
  1156. {
  1157. pchIPAddr++;
  1158. }
  1159. *pchIPAddr = '\0'; // convert the space to \0
  1160. //
  1161. // just make sure that it's what we had set earlier
  1162. //
  1163. if ( *(pchIPAddr+1) != '(' )
  1164. {
  1165. LocalFree( pji1GetJob );
  1166. continue;
  1167. }
  1168. pchIPAddr += 2; // skip over the new \0 and the '('
  1169. // make sure the job was indeed submitted by the same user from
  1170. // the same machine (that's the extent of our security!)
  1171. if ( ( strcmp( pchUserName, pqStatus->pchUserName ) != 0 ) ||
  1172. ( strcmp( pchIPAddr, pscConn->szIPAddr ) != 0 ) )
  1173. {
  1174. PCHAR aszStrings[4];
  1175. aszStrings[0] = pscConn->szIPAddr;
  1176. aszStrings[1] = pqStatus->pchUserName;
  1177. aszStrings[2] = pchUserName;
  1178. aszStrings[3] = pchIPAddr;
  1179. LpdReportEvent( LPDLOG_UNAUTHORIZED_REQUEST, 4, aszStrings, 0 );
  1180. LPD_DEBUG( "Unauthorized request in RemoveJobs(): refused\n" );
  1181. fSuccess = FALSE;
  1182. LocalFree( pji1GetJob );
  1183. continue;
  1184. }
  1185. // now that we've crossed all hurdles, delete the job!
  1186. SetJob( pscConn->hPrinter, pqStatus->adwJobIds[i],
  1187. 0, NULL, JOB_CONTROL_CANCEL );
  1188. LocalFree( pji1GetJob );
  1189. }
  1190. if ( !fSuccess )
  1191. {
  1192. return( LPDERR_BADFORMAT );
  1193. }
  1194. pscConn->wState = LPDS_ALL_WENT_WELL;
  1195. return( NO_ERROR );
  1196. } // end RemoveJobs()
  1197. /*****************************************************************************
  1198. * *
  1199. * FillJobStatus(): *
  1200. * This function takes output from the EnumJobs() call and puts into a *
  1201. * buffer info about the job that's of interest to us. *
  1202. * *
  1203. * Returns: *
  1204. * Nothing *
  1205. * *
  1206. * Parameters: *
  1207. * pscConn (IN-OUT): pointer to SOCKCONN structure for this connection *
  1208. * pchDest (OUT): buffer into which we put info about the jobs *
  1209. * pji2QStatus (IN): buffer we got as output from the EnumJobs() call *
  1210. * dwNumJobs (IN): how many jobs does data in pji2QStatus pertain to. *
  1211. * *
  1212. * History: *
  1213. * Jan.25, 94 Koti Created *
  1214. * *
  1215. *****************************************************************************/
  1216. INT FillJobStatus( PSOCKCONN pscConn, PCHAR pchDest,
  1217. PJOB_INFO_2 pji2QStatus, DWORD dwNumJobs )
  1218. {
  1219. DWORD i, j;
  1220. BOOL fUsersSpecified=FALSE;
  1221. BOOL fJobIdsSpecified=FALSE;
  1222. BOOL fMatchFound;
  1223. PQSTATUS pqStatus;
  1224. CHAR szFormat[8];
  1225. PCHAR pchStart = pchDest;
  1226. // if users/job-ids not specified, we return status on all jobs
  1227. if ( (pqStatus = pscConn->pqStatus) == NULL )
  1228. {
  1229. fMatchFound = TRUE;
  1230. }
  1231. // looks like users and/or job-ids is specified
  1232. else
  1233. {
  1234. if ( pqStatus->cbActualUsers > 0 )
  1235. {
  1236. fUsersSpecified = TRUE;
  1237. }
  1238. if ( pqStatus->cbActualJobIds > 0 )
  1239. {
  1240. fJobIdsSpecified = TRUE;
  1241. }
  1242. fMatchFound = FALSE; // flip the default
  1243. }
  1244. // if user or job-ids or both are specified, then we fill in data only
  1245. // if we find a match. if neither is specified (most common case)
  1246. // then we report all jobs (default for fMatchFound does the trick)
  1247. for ( i=0; i<dwNumJobs; i++, pji2QStatus++ )
  1248. {
  1249. if ( fUsersSpecified )
  1250. {
  1251. for ( j=0; j<pqStatus->cbActualUsers; j++ )
  1252. {
  1253. if (_stricmp( pji2QStatus->pUserName, pqStatus->ppchUsers[j] ) == 0)
  1254. {
  1255. fMatchFound = TRUE;
  1256. break;
  1257. }
  1258. }
  1259. }
  1260. if ( (!fMatchFound) && (fJobIdsSpecified) )
  1261. {
  1262. for ( j=0; j<pqStatus->cbActualJobIds; j++ )
  1263. {
  1264. if ( pji2QStatus->JobId == pqStatus->adwJobIds[j] )
  1265. {
  1266. fMatchFound = TRUE;
  1267. break;
  1268. }
  1269. }
  1270. }
  1271. if ( !fMatchFound )
  1272. {
  1273. continue;
  1274. }
  1275. // put in the desired fields for each (selected) of the jobs
  1276. LpdFormat( pchDest, pji2QStatus->pUserName, LPD_FLD_OWNER );
  1277. pchDest += LPD_FLD_OWNER;
  1278. //
  1279. // Since we can have multiple bits set, but print only 1 status, so
  1280. // first handle the error bits
  1281. //
  1282. if (pji2QStatus->Status & JOB_STATUS_ERROR)
  1283. {
  1284. LpdFormat( pchDest, GETSTRING( LPD_STR_ERROR ), LPD_FLD_STATUS );
  1285. }
  1286. else if (pji2QStatus->Status & JOB_STATUS_OFFLINE)
  1287. {
  1288. LpdFormat( pchDest, GETSTRING( LPD_STR_OFFLINE), LPD_FLD_STATUS );
  1289. }
  1290. else if (pji2QStatus->Status & JOB_STATUS_PAPEROUT)
  1291. {
  1292. LpdFormat( pchDest, GETSTRING( LPD_STR_PAPEROUT), LPD_FLD_STATUS );
  1293. }
  1294. else if (pji2QStatus->Status & JOB_STATUS_USER_INTERVENTION)
  1295. {
  1296. LpdFormat( pchDest, GETSTRING( LPD_STR_USER_INTERVENTION ), LPD_FLD_STATUS );
  1297. }
  1298. else if (pji2QStatus->Status & JOB_STATUS_BLOCKED_DEVQ)
  1299. {
  1300. LpdFormat( pchDest, GETSTRING( LPD_STR_BLOCKED_DEVQ ), LPD_FLD_STATUS );
  1301. }
  1302. //
  1303. // Now, handle the processing states
  1304. //
  1305. else if (pji2QStatus->Status & JOB_STATUS_PRINTING)
  1306. {
  1307. LpdFormat( pchDest, GETSTRING( LPD_STR_PRINTING), LPD_FLD_STATUS );
  1308. }
  1309. else if (pji2QStatus->Status & JOB_STATUS_SPOOLING)
  1310. {
  1311. LpdFormat( pchDest, GETSTRING( LPD_STR_SPOOLING), LPD_FLD_STATUS );
  1312. }
  1313. else if (pji2QStatus->Status & JOB_STATUS_DELETING)
  1314. {
  1315. LpdFormat( pchDest, GETSTRING( LPD_STR_DELETING), LPD_FLD_STATUS );
  1316. }
  1317. //
  1318. // Now, handle the processed states
  1319. //
  1320. else if (pji2QStatus->Status & JOB_STATUS_DELETED)
  1321. {
  1322. LpdFormat( pchDest, GETSTRING( LPD_STR_DELETED ), LPD_FLD_STATUS );
  1323. }
  1324. else if (pji2QStatus->Status & JOB_STATUS_PAUSED)
  1325. {
  1326. LpdFormat( pchDest, GETSTRING( LPD_STR_PAUSED ), LPD_FLD_STATUS );
  1327. }
  1328. else if (pji2QStatus->Status & JOB_STATUS_PRINTED)
  1329. {
  1330. LpdFormat( pchDest, GETSTRING( LPD_STR_PRINTED), LPD_FLD_STATUS );
  1331. }
  1332. //
  1333. // Remaining cases
  1334. //
  1335. else if (pji2QStatus->Status & JOB_STATUS_RESTART)
  1336. {
  1337. LpdFormat( pchDest, GETSTRING( LPD_STR_RESTART ), LPD_FLD_STATUS );
  1338. }
  1339. else
  1340. {
  1341. LpdFormat( pchDest, GETSTRING( LPD_STR_PENDING), LPD_FLD_STATUS );
  1342. }
  1343. pchDest += LPD_FLD_STATUS;
  1344. LpdFormat( pchDest, pji2QStatus->pDocument, LPD_FLD_JOBNAME );
  1345. pchDest += LPD_FLD_JOBNAME;
  1346. sprintf( szFormat, "%s%d%s", "%", LPD_FLD_JOBID, "d" );
  1347. sprintf( pchDest, szFormat, pji2QStatus->JobId );
  1348. pchDest += LPD_FLD_JOBID;
  1349. sprintf( szFormat, "%s%d%s", "%", LPD_FLD_SIZE, "d" );
  1350. sprintf( pchDest, szFormat, pji2QStatus->Size );
  1351. pchDest += LPD_FLD_SIZE;
  1352. sprintf( szFormat, "%s%d%s", "%", LPD_FLD_PAGES, "d" );
  1353. sprintf( pchDest, szFormat, pji2QStatus->TotalPages );
  1354. pchDest += LPD_FLD_PAGES;
  1355. sprintf( szFormat, "%s%d%s", "%", LPD_FLD_PRIORITY, "d" );
  1356. sprintf( pchDest, szFormat, pji2QStatus->Priority );
  1357. pchDest += LPD_FLD_PRIORITY;
  1358. strncpy (pchDest, LPD_NEWLINE, sizeof(LPD_NEWLINE));
  1359. pchDest += sizeof( LPD_NEWLINE ) -1;
  1360. if (pqStatus)
  1361. {
  1362. //
  1363. // If a specific job was requested, then we should
  1364. // re-determine the criteria!
  1365. //
  1366. fMatchFound = FALSE;
  1367. }
  1368. } // for ( i=0; i<dwNumJobs; i++, pji2QStatus++ )
  1369. strncpy (pchDest, LPD_NEWLINE, sizeof(LPD_NEWLINE));
  1370. pchDest += sizeof( LPD_NEWLINE );
  1371. return (INT)(pchDest - pchStart);
  1372. } // end FillJobStatus()
  1373. /*****************************************************************************
  1374. * *
  1375. * LpdFormat(): *
  1376. * This function copies exactly the given number of bytes from source *
  1377. * to dest buffer, by truncating or padding with spaces if need be. The *
  1378. * byte copied into the dest buffer is always a space. *
  1379. * *
  1380. * Returns: *
  1381. * Nothing *
  1382. * *
  1383. * Parameters: *
  1384. * pchDest (OUT): destination buffer *
  1385. * pchSource (IN): source buffer *
  1386. * dwLimit (IN): number of bytes to copy *
  1387. * *
  1388. * History: *
  1389. * Jan.25, 94 Koti Created *
  1390. * *
  1391. *****************************************************************************/
  1392. VOID LpdFormat( PCHAR pchDest, PCHAR pchSource, DWORD dwLimit )
  1393. {
  1394. DWORD dwCharsToCopy;
  1395. BOOL fPaddingNeeded;
  1396. DWORD i;
  1397. if( pchSource ){
  1398. dwCharsToCopy = strlen( pchSource );
  1399. }else{
  1400. DEBUG_PRINT(("LpdFormat NULL pchSource\n"));
  1401. dwCharsToCopy = 0;
  1402. }
  1403. if ( dwCharsToCopy < (dwLimit-1) )
  1404. {
  1405. fPaddingNeeded = TRUE;
  1406. }
  1407. else
  1408. {
  1409. fPaddingNeeded = FALSE;
  1410. dwCharsToCopy = dwLimit-1;
  1411. }
  1412. for ( i=0; i<dwCharsToCopy; i++ )
  1413. {
  1414. pchDest[i] = pchSource[i];
  1415. }
  1416. if ( fPaddingNeeded )
  1417. {
  1418. for ( i=dwCharsToCopy; i<dwLimit-1; i++ )
  1419. {
  1420. pchDest[i] = ' ';
  1421. }
  1422. }
  1423. // make sure last byte is a space
  1424. pchDest[dwLimit-1] = ' ';
  1425. } // end LpdFormat()
  1426. /* ========================================================================
  1427. Routine Description:
  1428. Uses spooler-provided APIs to determine if the named registry DWORD is
  1429. a non-zero value. If the registry key does not exist, it is created,
  1430. with a value of zero.
  1431. Arguments:
  1432. hPrinter - A handle to the printer whose configuration is queried. In
  1433. order for writing the default value to work, this handle
  1434. must have been opened with PRINTER_ACCESS_ADMINISTER
  1435. pszParameterName - The name of the registry key to retrieve and test.
  1436. Return Value:
  1437. TRUE if the registry key exists for this printer and contains a non-zero
  1438. value. FALSE is returned in all other cases.
  1439. */
  1440. BOOL
  1441. IsPrinterDataSet(
  1442. IN HANDLE hPrinter,
  1443. IN LPTSTR pszParameterName
  1444. )
  1445. {
  1446. DWORD dwRegValue;
  1447. DWORD dwRegType;
  1448. DWORD cbValueSize;
  1449. DWORD dwErrcode;
  1450. if ( ( GetPrinterData( hPrinter,
  1451. pszParameterName,
  1452. &dwRegType,
  1453. ( LPBYTE )&dwRegValue,
  1454. sizeof( dwRegValue ),
  1455. &cbValueSize ) == ERROR_SUCCESS ) &&
  1456. ( dwRegType == REG_DWORD ) &&
  1457. ( cbValueSize == sizeof( DWORD ) ) )
  1458. {
  1459. if ( dwRegValue )
  1460. {
  1461. #if DBG
  1462. LpdPrintf( "Printer ox%08X has registry setting for %S.\n",
  1463. hPrinter,
  1464. pszParameterName );
  1465. #endif
  1466. return( TRUE );
  1467. }
  1468. }
  1469. else
  1470. {
  1471. #if DBG
  1472. LpdPrintf( "lpd:IsPrinterDataSet: GetPrinterData() failed.\n");
  1473. #endif
  1474. //
  1475. // Either the registry value in question is not in the registry, or it is
  1476. // not a REG_DWORD that we can read. The following code adds the setting
  1477. // and defaults it to zero (0). While this will not change the operation
  1478. // of the print queue, it will make it easier for a user wishing to do so
  1479. // to find the correct registry parameter. Notice that this paragraph is
  1480. // fully justified.
  1481. //
  1482. // If this fails we don't really care, so we don't check the return value
  1483. //
  1484. dwRegValue = 0;
  1485. dwErrcode =
  1486. SetPrinterData( hPrinter,
  1487. pszParameterName,
  1488. REG_DWORD,
  1489. ( LPBYTE )&dwRegValue,
  1490. sizeof( dwRegValue ) );
  1491. #if DBG
  1492. LpdPrintf( "lpd: wrote %S == %d for printer 0x%08X, dwErrcode is %s.\n",
  1493. pszParameterName,
  1494. dwRegValue,
  1495. hPrinter,
  1496. ( dwErrcode == ERROR_SUCCESS ) ? "Succesful" : "ERROR" );
  1497. #endif
  1498. }
  1499. return( FALSE );
  1500. }
  1501. /*
  1502. Routine Description:
  1503. This function looks at the data file contents and attempts to determine if
  1504. they are 'RAW' PostScript or PCL
  1505. Arguments:
  1506. pchDataBuf - Pointer to the _beginning_ of the data file.
  1507. cchBufferLen - Number of characters pointed to.
  1508. Returns:
  1509. TRUE if the job type is detected as raw, FALSE if it is not.
  1510. */
  1511. BOOL
  1512. IsDataTypeRaw(
  1513. PCHAR pchDataBuf,
  1514. int cchBufferLen
  1515. )
  1516. {
  1517. PCHAR pchData;
  1518. int cchAmountToSearch;
  1519. int cchAmountSearched;
  1520. ASSERT( STRING_LENGTH_POSTSCRIPT_HEADER == strlen( STRING_POSTSCRIPT_HEADER ) );
  1521. //
  1522. // Because some PS print drivers may send blank lines, end-of-file marks, and
  1523. // other control characters at the beginning of the print data, the following
  1524. // loop scans through these and skips them. The Windows 3.1 PostScript driver
  1525. // was notorious for doing this, as an example.
  1526. //
  1527. for ( pchData = pchDataBuf; ( pchData - pchDataBuf ) < cchBufferLen; pchData ++ )
  1528. {
  1529. if ( *pchData >= 0x20 )
  1530. {
  1531. break;
  1532. }
  1533. }
  1534. if ( (( cchBufferLen - ( pchData - pchDataBuf )) >= STRING_LENGTH_POSTSCRIPT_HEADER ) &&
  1535. ( memcmp( pchData, STRING_POSTSCRIPT_HEADER, STRING_LENGTH_POSTSCRIPT_HEADER ) == 0 ))
  1536. {
  1537. LPD_DEBUG( "Printed data was detected as PostScript\n" );
  1538. return( TRUE );
  1539. }
  1540. //
  1541. // The job was not determined to be PostScript, so check to see if it is PCL.
  1542. //
  1543. pchData = pchDataBuf;
  1544. cchAmountToSearch = min( cchBufferLen, MAX_PCL_SEARCH_DEPTH );
  1545. cchAmountSearched = 0;
  1546. while ( cchAmountSearched < cchAmountToSearch )
  1547. {
  1548. pchData = memchr( pchData, 0x1B, cchAmountToSearch - cchAmountSearched );
  1549. if ( pchData == NULL )
  1550. {
  1551. break;
  1552. }
  1553. cchAmountSearched = (int)(pchData - pchDataBuf);
  1554. if ( ( cchAmountSearched + 3 ) < cchAmountToSearch )
  1555. {
  1556. pchData++;
  1557. cchAmountSearched++;
  1558. if ( *pchData != '&' )
  1559. {
  1560. continue;
  1561. }
  1562. pchData++;
  1563. cchAmountSearched++;
  1564. if ( *pchData != 'l' )
  1565. {
  1566. continue;
  1567. }
  1568. pchData++;
  1569. cchAmountSearched++;
  1570. while (( cchAmountSearched < cchAmountToSearch ) && ( isdigit( *pchData )))
  1571. {
  1572. pchData++;
  1573. cchAmountSearched++;
  1574. }
  1575. if (( cchAmountSearched < cchAmountToSearch ) && ( isalpha( *pchData )))
  1576. {
  1577. LPD_DEBUG( "Printed data was detected as PCL\n" );
  1578. return( TRUE );
  1579. }
  1580. }
  1581. // reached end of buffer
  1582. else
  1583. {
  1584. break;
  1585. }
  1586. }
  1587. LPD_DEBUG( "Printed data was not detected as anything special (like PS or PCL)\n" );
  1588. return( FALSE );
  1589. }