Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include <cups/cups.h>
31 : : #include <cups/http.h>
32 : : #include <cups/ipp.h>
33 : : #include <cups/ppd.h>
34 : :
35 : : #include <unistd.h>
36 : :
37 : : #include "cupsmgr.hxx"
38 : :
39 : : #include "osl/thread.h"
40 : : #include "osl/diagnose.h"
41 : : #include "osl/conditn.hxx"
42 : :
43 : : #include "rtl/ustrbuf.hxx"
44 : :
45 : : #include <algorithm>
46 : :
47 : : #define CUPS_LIB_NAME "libcups.so.2"
48 : :
49 : : namespace psp
50 : : {
51 : : class CUPSWrapper
52 : : {
53 : : oslModule m_pLib;
54 : : osl::Mutex m_aGetPPDMutex;
55 : : bool m_bPPDThreadRunning;
56 : :
57 : : int (*m_pcupsPrintFile)(const char*, const char*, const char*, int, cups_option_t*);
58 : : int (*m_pcupsGetDests)(cups_dest_t**);
59 : : void (*m_pcupsSetDests)(int,cups_dest_t*);
60 : : void (*m_pcupsFreeDests)(int,cups_dest_t*);
61 : : const char* (*m_pcupsGetPPD)(const char*);
62 : : int (*m_pcupsMarkOptions)(ppd_file_t*,int,cups_option_t*);
63 : : int (*m_pcupsAddOption)(const char*,const char*,int,cups_option_t**);
64 : : void (*m_pcupsFreeOptions)(int,cups_option_t*);
65 : : ppd_file_t* (*m_pppdOpenFile)(const char* pFile);
66 : : void (*m_pppdClose)(ppd_file_t*);
67 : : http_t* (*m_phttpConnectEncrypt)(const char*, int, http_encryption_t);
68 : : void (*m_phttpClose)(http_t*);
69 : : int (*m_pippPort)();
70 : : const char* (*m_pcupsServer)();
71 : : http_encryption_t (*m_pcupsEncryption)();
72 : : void (*m_pcupsSetPasswordCB)(const char*(cb)(const char*));
73 : : const char* (*m_pcupsUser)();
74 : : void (*m_pcupsSetUser)(const char*);
75 : : const char* (*m_pcupsGetOption)(const char*,int,cups_option_t*);
76 : :
77 : : oslGenericFunction loadSymbol( const char* );
78 : : public:
79 : : CUPSWrapper();
80 : : ~CUPSWrapper();
81 : :
82 : : bool isValid();
83 : :
84 : 103 : int cupsGetDests(cups_dest_t** pDests)
85 : 103 : { return m_pcupsGetDests(pDests); }
86 : :
87 : 0 : void cupsSetDests( int nDests, cups_dest_t* pDests )
88 : 0 : { m_pcupsSetDests( nDests, pDests ); }
89 : :
90 : 0 : void cupsFreeDests(int nDests, cups_dest_t* pDests)
91 : 0 : { m_pcupsFreeDests(nDests, pDests); }
92 : :
93 : 0 : int cupsPrintFile( const char* pPrinter,
94 : : const char* pFileName,
95 : : const char* pTitle,
96 : : int nOptions,
97 : : cups_option_t* pOptions )
98 : 0 : { return m_pcupsPrintFile( pPrinter, pFileName, pTitle, nOptions, pOptions ); }
99 : :
100 : : rtl::OString cupsGetPPD( const char* pPrinter );
101 : :
102 : 0 : int cupsMarkOptions(ppd_file_t* pPPD, int nOptions, cups_option_t* pOptions )
103 : 0 : { return m_pcupsMarkOptions(pPPD, nOptions, pOptions); }
104 : :
105 : 0 : int cupsAddOption( const char* pName, const char* pValue, int nOptions, cups_option_t** pOptions )
106 : 0 : { return m_pcupsAddOption( pName, pValue, nOptions, pOptions ); }
107 : :
108 : 0 : void cupsFreeOptions( int nOptions, cups_option_t* pOptions )
109 : 0 : { m_pcupsFreeOptions( nOptions, pOptions ); }
110 : :
111 : 0 : ppd_file_t* ppdOpenFile( const char* pFileName )
112 : 0 : { return m_pppdOpenFile( pFileName ); }
113 : :
114 : 0 : void ppdClose( ppd_file_t* pPPD )
115 : 0 : { m_pppdClose( pPPD ); }
116 : :
117 : 103 : http_t* httpConnectEncrypt(const char* host, int port, http_encryption_t crypt)
118 : 103 : { return m_phttpConnectEncrypt(host, port, crypt); }
119 : :
120 : 103 : void httpClose(http_t* server)
121 : 103 : { m_phttpClose(server); }
122 : :
123 : 103 : int ippPort()
124 : 103 : { return m_pippPort(); }
125 : :
126 : 103 : const char *cupsServer(void)
127 : 103 : { return m_pcupsServer(); }
128 : :
129 : 103 : http_encryption_t cupsEncryption()
130 : 103 : { return m_pcupsEncryption(); }
131 : :
132 : 0 : const char *cupsUser(void)
133 : 0 : { return m_pcupsUser(); }
134 : :
135 : 0 : void cupsSetPasswordCB(const char *(*cb)(const char *))
136 : 0 : { m_pcupsSetPasswordCB( cb ); }
137 : :
138 : 0 : void cupsSetUser(const char *user)
139 : 0 : { m_pcupsSetUser( user ); }
140 : :
141 : 0 : const char* cupsGetOption(const char* name, int num_options, cups_option_t* options)
142 : 0 : { return m_pcupsGetOption( name, num_options, options ); }
143 : :
144 : : };
145 : : }
146 : :
147 : : using namespace psp;
148 : : using namespace osl;
149 : :
150 : : using ::rtl::OUString;
151 : : using ::rtl::OUStringBuffer;
152 : : using ::rtl::OUStringToOString;
153 : : using ::rtl::OStringToOUString;
154 : : using ::rtl::OUStringHash;
155 : : using ::rtl::OString;
156 : :
157 : : /*
158 : : * CUPSWrapper class
159 : : */
160 : :
161 : 1748 : oslGenericFunction CUPSWrapper::loadSymbol( const char* pSymbol )
162 : : {
163 : 1748 : OUString aSym( OUString::createFromAscii( pSymbol ) );
164 [ + - ]: 1748 : oslGenericFunction pSym = osl_getFunctionSymbol( m_pLib, aSym.pData );
165 : : #if OSL_DEBUG_LEVEL > 1
166 : : fprintf( stderr, "%s %s\n", pSymbol, pSym ? "found" : "not found" );
167 : : #endif
168 : 1748 : return pSym;
169 : : }
170 : :
171 : 92 : CUPSWrapper::CUPSWrapper()
172 : : : m_pLib( NULL ),
173 : 92 : m_bPPDThreadRunning( false )
174 : : {
175 : 92 : OUString aLib( CUPS_LIB_NAME );
176 [ + - ]: 92 : m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
177 [ - + ]: 92 : if( ! m_pLib )
178 : : {
179 : 0 : aLib = OUString( SAL_MODULENAME( "cups" ) );
180 [ # # ]: 0 : m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
181 : : }
182 : :
183 [ - + ]: 92 : if( ! m_pLib )
184 : : {
185 : : #if OSL_DEBUG_LEVEL > 1
186 : : fprintf( stderr, "no cups library found\n" );
187 : : #endif
188 : 92 : return;
189 : : }
190 : :
191 : : m_pcupsPrintFile = (int(*)(const char*,const char*,const char*,int,cups_option_t*))
192 [ + - ]: 92 : loadSymbol( "cupsPrintFile" );
193 : : m_pcupsGetDests = (int(*)(cups_dest_t**))
194 [ + - ]: 92 : loadSymbol( "cupsGetDests" );
195 : : m_pcupsSetDests = (void(*)(int,cups_dest_t*))
196 [ + - ]: 92 : loadSymbol( "cupsSetDests" );
197 : : m_pcupsFreeDests = (void(*)(int,cups_dest_t*))
198 [ + - ]: 92 : loadSymbol( "cupsFreeDests" );
199 : : m_pcupsGetPPD = (const char*(*)(const char*))
200 [ + - ]: 92 : loadSymbol( "cupsGetPPD" );
201 : : m_pcupsMarkOptions = (int(*)(ppd_file_t*,int,cups_option_t*))
202 [ + - ]: 92 : loadSymbol( "cupsMarkOptions" );
203 : : m_pcupsAddOption = (int(*)(const char*,const char*,int,cups_option_t**))
204 [ + - ]: 92 : loadSymbol( "cupsAddOption" );
205 : : m_pcupsFreeOptions = (void(*)(int,cups_option_t*))
206 [ + - ]: 92 : loadSymbol( "cupsFreeOptions" );
207 : : m_pppdOpenFile = (ppd_file_t*(*)(const char*))
208 [ + - ]: 92 : loadSymbol( "ppdOpenFile" );
209 : : m_pppdClose = (void(*)(ppd_file_t*))
210 [ + - ]: 92 : loadSymbol( "ppdClose" );
211 : : m_phttpConnectEncrypt = (http_t*(*)(const char*, int, http_encryption_t))
212 [ + - ]: 92 : loadSymbol( "httpConnectEncrypt" );
213 : : m_phttpClose = (void(*)(http_t*))
214 [ + - ]: 92 : loadSymbol( "httpClose" );
215 : : m_pippPort = (int(*)())
216 [ + - ]: 92 : loadSymbol( "ippPort" );
217 : : m_pcupsServer = (const char*(*)())
218 [ + - ]: 92 : loadSymbol( "cupsServer" );
219 : : m_pcupsEncryption = (http_encryption_t(*)())
220 [ + - ]: 92 : loadSymbol( "cupsEncryption" );
221 : : m_pcupsUser = (const char*(*)())
222 [ + - ]: 92 : loadSymbol( "cupsUser" );
223 : : m_pcupsSetPasswordCB = (void(*)(const char*(*)(const char*)))
224 [ + - ]: 92 : loadSymbol( "cupsSetPasswordCB" );
225 : : m_pcupsSetUser = (void(*)(const char*))
226 [ + - ]: 92 : loadSymbol( "cupsSetUser" );
227 : : m_pcupsGetOption = (const char*(*)(const char*,int,cups_option_t*))
228 [ + - ]: 92 : loadSymbol( "cupsGetOption" );
229 : :
230 [ + - ]: 92 : if( ! (
231 : : m_pcupsPrintFile &&
232 : : m_pcupsGetDests &&
233 : : m_pcupsSetDests &&
234 : : m_pcupsFreeDests &&
235 : : m_pcupsGetPPD &&
236 : : m_pcupsMarkOptions &&
237 : : m_pcupsAddOption &&
238 : : m_pcupsServer &&
239 : : m_pcupsUser &&
240 : : m_pcupsSetPasswordCB &&
241 : : m_pcupsSetUser &&
242 : : m_pcupsFreeOptions &&
243 : : m_pppdOpenFile &&
244 : : m_pppdClose &&
245 : : m_phttpConnectEncrypt &&
246 : : m_phttpClose &&
247 : : m_pippPort &&
248 : : m_pcupsGetOption
249 [ + - ][ + - ]: 92 : ) )
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ - + ]
250 : : {
251 [ # # ]: 0 : osl_unloadModule( m_pLib );
252 : 92 : m_pLib = NULL;
253 [ + - ]: 92 : }
254 : : }
255 : :
256 : 0 : CUPSWrapper::~CUPSWrapper()
257 : : {
258 [ # # ]: 0 : if( m_pLib )
259 [ # # ]: 0 : osl_unloadModule( m_pLib );
260 : 0 : }
261 : :
262 : 92 : bool CUPSWrapper::isValid()
263 : : {
264 : 92 : return m_pLib != NULL;
265 : : }
266 : :
267 : : typedef const char*(*PPDFunction)(const char*);
268 : : struct GetPPDAttribs
269 : : {
270 : : PPDFunction m_pFunction;
271 : : osl::Condition m_aCondition;
272 : : OString m_aParameter;
273 : : OString m_aResult;
274 : : oslThread m_aThread;
275 : : int m_nRefs;
276 : : bool* m_pResetRunning;
277 : : osl::Mutex* m_pSyncMutex;
278 : :
279 : 0 : GetPPDAttribs( PPDFunction pFn, const char * m_pParameter,
280 : : bool* pResetRunning, osl::Mutex* pSyncMutex )
281 : : : m_pFunction( pFn ),
282 : : m_aParameter( m_pParameter ),
283 : : m_pResetRunning( pResetRunning ),
284 : 0 : m_pSyncMutex( pSyncMutex )
285 : : {
286 : 0 : m_nRefs = 2;
287 [ # # ]: 0 : m_aCondition.reset();
288 : 0 : }
289 : :
290 : 0 : ~GetPPDAttribs()
291 : 0 : {
292 [ # # ]: 0 : if( !m_aResult.isEmpty() )
293 : 0 : unlink( m_aResult.getStr() );
294 : 0 : }
295 : :
296 : 0 : void unref()
297 : : {
298 [ # # ]: 0 : if( --m_nRefs == 0 )
299 : : {
300 : 0 : *m_pResetRunning = false;
301 [ # # ]: 0 : delete this;
302 : : }
303 : 0 : }
304 : :
305 : 0 : void executeCall()
306 : : {
307 : : // This CUPS method is not at all thread-safe we need
308 : : // to dup the pointer to a static buffer it returns ASAP
309 [ # # ]: 0 : OString aResult = m_pFunction( m_aParameter.getStr() );
310 [ # # ]: 0 : MutexGuard aGuard( *m_pSyncMutex );
311 : 0 : m_aResult = aResult;
312 [ # # ]: 0 : m_aCondition.set();
313 [ # # ][ # # ]: 0 : unref();
314 : 0 : }
315 : :
316 : 0 : OString waitResult( TimeValue *pDelay )
317 : : {
318 : 0 : m_pSyncMutex->release();
319 : :
320 : 0 : if (m_aCondition.wait( pDelay ) != Condition::result_ok
321 : : )
322 : : {
323 : : #if OSL_DEBUG_LEVEL > 1
324 : : fprintf( stderr, "cupsGetPPD %s timed out\n", m_aParameter.getStr() );
325 : : #endif
326 : : }
327 : 0 : m_pSyncMutex->acquire();
328 : :
329 : 0 : OString aRetval = m_aResult;
330 : 0 : m_aResult = OString();
331 [ # # ]: 0 : unref();
332 : :
333 : 0 : return aRetval;
334 : : }
335 : : };
336 : :
337 : : extern "C" {
338 : 0 : static void getPPDWorker(void* pData)
339 : : {
340 : 0 : GetPPDAttribs* pAttribs = (GetPPDAttribs*)pData;
341 : 0 : pAttribs->executeCall();
342 : 0 : }
343 : : }
344 : :
345 : 0 : OString CUPSWrapper::cupsGetPPD( const char* pPrinter )
346 : : {
347 : 0 : OString aResult;
348 : :
349 [ # # ]: 0 : m_aGetPPDMutex.acquire();
350 : : // if one thread hangs in cupsGetPPD already, don't start another
351 [ # # ]: 0 : if( ! m_bPPDThreadRunning )
352 : : {
353 : 0 : m_bPPDThreadRunning = true;
354 : : GetPPDAttribs* pAttribs = new GetPPDAttribs( m_pcupsGetPPD,
355 : : pPrinter,
356 : : &m_bPPDThreadRunning,
357 [ # # ][ # # ]: 0 : &m_aGetPPDMutex );
358 : :
359 [ # # ]: 0 : oslThread aThread = osl_createThread( getPPDWorker, pAttribs );
360 : :
361 : : TimeValue aValue;
362 : 0 : aValue.Seconds = 5;
363 : 0 : aValue.Nanosec = 0;
364 : :
365 : : // NOTE: waitResult release and acquires the GetPPD mutex
366 [ # # ]: 0 : aResult = pAttribs->waitResult( &aValue );
367 [ # # ]: 0 : osl_destroyThread( aThread );
368 : : }
369 [ # # ]: 0 : m_aGetPPDMutex.release();
370 : :
371 : 0 : return aResult;
372 : : }
373 : :
374 : 0 : static const char* setPasswordCallback( const char* pIn )
375 : : {
376 : 0 : const char* pRet = NULL;
377 : :
378 : 0 : PrinterInfoManager& rMgr = PrinterInfoManager::get();
379 [ # # ]: 0 : if( rMgr.getType() == PrinterInfoManager::CUPS ) // sanity check
380 : 0 : pRet = static_cast<CUPSManager&>(rMgr).authenticateUser( pIn );
381 : 0 : return pRet;
382 : : }
383 : :
384 : : /*
385 : : * CUPSManager class
386 : : */
387 : :
388 : 92 : CUPSManager* CUPSManager::tryLoadCUPS()
389 : : {
390 : 92 : CUPSManager* pManager = NULL;
391 [ + - ][ + - ]: 92 : static const char* pEnv = getenv( "SAL_DISABLE_CUPS" );
392 : :
393 [ - + ][ # # ]: 92 : if( ! pEnv || ! *pEnv )
394 : : {
395 : : // try to load CUPS
396 [ + - ]: 92 : CUPSWrapper* pWrapper = new CUPSWrapper();
397 [ + - ]: 92 : if( pWrapper->isValid() )
398 [ + - ]: 92 : pManager = new CUPSManager( pWrapper );
399 : : else
400 [ # # ]: 0 : delete pWrapper;
401 : : }
402 : 92 : return pManager;
403 : : }
404 : :
405 : : extern "C"
406 : : {
407 : 92 : static void run_dest_thread_stub( void* pThis )
408 : : {
409 : 92 : CUPSManager::runDestThread( pThis );
410 : 92 : }
411 : : }
412 : :
413 : 92 : CUPSManager::CUPSManager( CUPSWrapper* pWrapper ) :
414 : : PrinterInfoManager( CUPS ),
415 : : m_pCUPSWrapper( pWrapper ),
416 : : m_nDests( 0 ),
417 : : m_pDests( NULL ),
418 [ + - ][ + - ]: 92 : m_bNewDests( false )
[ + - ][ + - ]
419 : : {
420 [ + - ]: 92 : m_aDestThread = osl_createThread( run_dest_thread_stub, this );
421 : 92 : }
422 : :
423 [ # # ][ # # ]: 0 : CUPSManager::~CUPSManager()
[ # # ][ # # ]
424 : : {
425 [ # # ]: 0 : if( m_aDestThread )
426 : : {
427 : : // if the thread is still running here, then
428 : : // cupsGetDests is hung; terminate the thread instead of joining
429 [ # # ]: 0 : osl_terminateThread( m_aDestThread );
430 [ # # ]: 0 : osl_destroyThread( m_aDestThread );
431 : : }
432 : :
433 [ # # ][ # # ]: 0 : if( m_nDests && m_pDests )
434 [ # # ]: 0 : m_pCUPSWrapper->cupsFreeDests( m_nDests, (cups_dest_t*)m_pDests );
435 [ # # ][ # # ]: 0 : delete m_pCUPSWrapper;
436 [ # # ]: 0 : }
437 : :
438 : 92 : void CUPSManager::runDestThread( void* pThis )
439 : : {
440 : 92 : ((CUPSManager*)pThis)->runDests();
441 : 92 : }
442 : :
443 : 103 : void CUPSManager::runDests()
444 : : {
445 : : #if OSL_DEBUG_LEVEL > 1
446 : : fprintf( stderr, "starting cupsGetDests\n" );
447 : : #endif
448 : 103 : cups_dest_t* pDests = NULL;
449 : :
450 : : // n#722902 - do a fast-failing check for cups working *at all* first
451 : : http_t* p_http;
452 [ + - ][ + - ]: 103 : if( (p_http=m_pCUPSWrapper->httpConnectEncrypt(
453 : : m_pCUPSWrapper->cupsServer(),
454 : : m_pCUPSWrapper->ippPort(),
455 [ + - ][ + - ]: 103 : m_pCUPSWrapper->cupsEncryption())) != NULL )
[ + - ]
456 : : {
457 : : // neat, cups is up, clean up the canary
458 [ + - ]: 103 : m_pCUPSWrapper->httpClose(p_http);
459 : :
460 [ + - ]: 103 : int nDests = m_pCUPSWrapper->cupsGetDests( &pDests );
461 : : #if OSL_DEBUG_LEVEL > 1
462 : : fprintf( stderr, "came out of cupsGetDests\n" );
463 : : #endif
464 : :
465 [ + - ]: 103 : osl::MutexGuard aGuard( m_aCUPSMutex );
466 : 103 : m_nDests = nDests;
467 : 103 : m_pDests = pDests;
468 [ + - ]: 103 : m_bNewDests = true;
469 : : #if OSL_DEBUG_LEVEL > 1
470 : : fprintf( stderr, "finished cupsGetDests\n" );
471 : : #endif
472 : : }
473 : 103 : }
474 : :
475 : 136 : void CUPSManager::initialize()
476 : : {
477 : : // get normal printers, clear printer list
478 [ + - ]: 136 : PrinterInfoManager::initialize();
479 : :
480 : : // check whether thread has completed
481 : : // if not behave like old printing system
482 [ + - ]: 136 : osl::MutexGuard aGuard( m_aCUPSMutex );
483 : :
484 [ + + ]: 136 : if( ! m_bNewDests )
485 : : return;
486 : :
487 : : // dest thread has run, clean up
488 [ + + ]: 98 : if( m_aDestThread )
489 : : {
490 [ + - ]: 54 : osl_joinWithThread( m_aDestThread );
491 [ + - ]: 54 : osl_destroyThread( m_aDestThread );
492 : 54 : m_aDestThread = NULL;
493 : : }
494 : 98 : m_bNewDests = false;
495 : :
496 : : // clear old stuff
497 [ + - ]: 98 : m_aCUPSDestMap.clear();
498 : :
499 [ - + ][ # # ]: 98 : if( ! (m_nDests && m_pDests ) )
500 : : return;
501 : :
502 [ # # ][ # # ]: 0 : if( isCUPSDisabled() )
503 : : return;
504 : :
505 : : // check for CUPS server(?) > 1.2
506 : : // since there is no API to query, check for options that were
507 : : // introduced in dests with 1.2
508 : : // this is needed to check for %%IncludeFeature support
509 : : // (#i65684#, #i65491#)
510 : 0 : bool bUsePDF = false;
511 : 0 : cups_dest_t* pDest = ((cups_dest_t*)m_pDests);
512 : : const char* pOpt = m_pCUPSWrapper->cupsGetOption( "printer-info",
513 : : pDest->num_options,
514 [ # # ]: 0 : pDest->options );
515 [ # # ]: 0 : if( pOpt )
516 : : {
517 : 0 : m_bUseIncludeFeature = true;
518 : 0 : bUsePDF = true;
519 [ # # ][ # # ]: 0 : if( m_aGlobalDefaults.m_nPSLevel == 0 && m_aGlobalDefaults.m_nPDFDevice == 0 )
520 : 0 : m_aGlobalDefaults.m_nPDFDevice = 1;
521 : : }
522 : : // do not send include JobPatch; CUPS will insert that itself
523 : : // TODO: currently unknown which versions of CUPS insert JobPatches
524 : : // so currently it is assumed CUPS = don't insert JobPatch files
525 : 0 : m_bUseJobPatch = false;
526 : :
527 [ # # ]: 0 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
528 : 0 : int nPrinter = m_nDests;
529 : :
530 : : // reset global default PPD options; these are queried on demand from CUPS
531 : 0 : m_aGlobalDefaults.m_pParser = NULL;
532 [ # # ][ # # ]: 0 : m_aGlobalDefaults.m_aContext = PPDContext();
[ # # ]
533 : :
534 : : // add CUPS printers, should there be a printer
535 : : // with the same name as a CUPS printer, overwrite it
536 [ # # ]: 0 : while( nPrinter-- )
537 : : {
538 : 0 : pDest = ((cups_dest_t*)m_pDests)+nPrinter;
539 [ # # ]: 0 : OUString aPrinterName = OStringToOUString( pDest->name, aEncoding );
540 [ # # ][ # # ]: 0 : if( pDest->instance && *pDest->instance )
541 : : {
542 : 0 : OUStringBuffer aBuf( 256 );
543 [ # # ]: 0 : aBuf.append( aPrinterName );
544 [ # # ]: 0 : aBuf.append( sal_Unicode( '/' ) );
545 [ # # ][ # # ]: 0 : aBuf.append( OStringToOUString( pDest->instance, aEncoding ) );
546 [ # # ]: 0 : aPrinterName = aBuf.makeStringAndClear();
547 : : }
548 : :
549 : : // initialize printer with possible configuration from psprint.conf
550 [ # # ][ # # ]: 0 : bool bSetToGlobalDefaults = m_aPrinters.find( aPrinterName ) == m_aPrinters.end();
551 [ # # ][ # # ]: 0 : Printer aPrinter = m_aPrinters[ aPrinterName ];
552 [ # # ]: 0 : if( bSetToGlobalDefaults )
553 [ # # ]: 0 : aPrinter.m_aInfo = m_aGlobalDefaults;
554 : 0 : aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
555 [ # # ]: 0 : if( pDest->is_default )
556 : 0 : m_aDefaultPrinter = aPrinterName;
557 : :
558 [ # # ]: 0 : for( int k = 0; k < pDest->num_options; k++ )
559 : : {
560 [ # # ]: 0 : if(!strcmp(pDest->options[k].name, "printer-info"))
561 [ # # ]: 0 : aPrinter.m_aInfo.m_aComment=OStringToOUString(pDest->options[k].value, aEncoding);
562 [ # # ]: 0 : if(!strcmp(pDest->options[k].name, "printer-location"))
563 [ # # ]: 0 : aPrinter.m_aInfo.m_aLocation=OStringToOUString(pDest->options[k].value, aEncoding);
564 : : }
565 : :
566 : :
567 : 0 : OUStringBuffer aBuf( 256 );
568 [ # # ]: 0 : aBuf.appendAscii( "CUPS:" );
569 [ # # ]: 0 : aBuf.append( aPrinterName );
570 : : // note: the parser that goes with the PrinterInfo
571 : : // is created implicitly by the JobData::operator=()
572 : : // when it detects the NULL ptr m_pParser.
573 : : // if we wanted to fill in the parser here this
574 : : // would mean we'd have to download PPDs for each and
575 : : // every printer - which would be really bad runtime
576 : : // behaviour
577 : 0 : aPrinter.m_aInfo.m_pParser = NULL;
578 [ # # ]: 0 : aPrinter.m_aInfo.m_aContext.setParser( NULL );
579 [ # # ]: 0 : boost::unordered_map< OUString, PPDContext, OUStringHash >::const_iterator c_it = m_aDefaultContexts.find( aPrinterName );
580 [ # # ][ # # ]: 0 : if( c_it != m_aDefaultContexts.end() )
581 : : {
582 [ # # ]: 0 : aPrinter.m_aInfo.m_pParser = c_it->second.getParser();
583 [ # # ][ # # ]: 0 : aPrinter.m_aInfo.m_aContext = c_it->second;
584 : : }
585 [ # # ][ # # ]: 0 : if( bUsePDF && aPrinter.m_aInfo.m_nPSLevel == 0 && aPrinter.m_aInfo.m_nPDFDevice == 0 )
[ # # ]
586 : 0 : aPrinter.m_aInfo.m_nPDFDevice = 1;
587 [ # # ]: 0 : aPrinter.m_aInfo.m_aDriverName = aBuf.makeStringAndClear();
588 : 0 : aPrinter.m_bModified = false;
589 : :
590 [ # # ][ # # ]: 0 : m_aPrinters[ aPrinter.m_aInfo.m_aPrinterName ] = aPrinter;
591 [ # # ]: 0 : m_aCUPSDestMap[ aPrinter.m_aInfo.m_aPrinterName ] = nPrinter;
592 [ # # ]: 0 : }
593 : :
594 : : // remove everything that is not a CUPS printer and not
595 : : // a special purpose printer (PDF, Fax)
596 [ # # ]: 0 : std::list< OUString > aRemovePrinters;
597 [ # # ][ # # ]: 0 : for( boost::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.begin();
598 [ # # ]: 0 : it != m_aPrinters.end(); ++it )
599 : : {
600 [ # # ][ # # ]: 0 : if( m_aCUPSDestMap.find( it->first ) != m_aCUPSDestMap.end() )
[ # # ][ # # ]
601 : 0 : continue;
602 : :
603 [ # # ][ # # ]: 0 : if( !it->second.m_aInfo.m_aFeatures.isEmpty() )
604 : 0 : continue;
605 [ # # ][ # # ]: 0 : aRemovePrinters.push_back( it->first );
606 : : }
607 [ # # ]: 0 : while( aRemovePrinters.begin() != aRemovePrinters.end() )
608 : : {
609 [ # # ][ # # ]: 0 : m_aPrinters.erase( aRemovePrinters.front() );
610 [ # # ]: 0 : aRemovePrinters.pop_front();
611 : : }
612 : :
613 [ # # ][ + - ]: 136 : m_pCUPSWrapper->cupsSetPasswordCB( setPasswordCallback );
[ - + ]
614 : : }
615 : :
616 : 0 : static void updatePrinterContextInfo( ppd_group_t* pPPDGroup, PPDContext& rContext )
617 : : {
618 : 0 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
619 [ # # ]: 0 : for( int i = 0; i < pPPDGroup->num_options; i++ )
620 : : {
621 : 0 : ppd_option_t* pOption = pPPDGroup->options + i;
622 [ # # ]: 0 : for( int n = 0; n < pOption->num_choices; n++ )
623 : : {
624 : 0 : ppd_choice_t* pChoice = pOption->choices + n;
625 [ # # ]: 0 : if( pChoice->marked )
626 : : {
627 [ # # ][ # # ]: 0 : const PPDKey* pKey = rContext.getParser()->getKey( OStringToOUString( pOption->keyword, aEncoding ) );
[ # # ][ # # ]
628 [ # # ]: 0 : if( pKey )
629 : : {
630 [ # # ][ # # ]: 0 : const PPDValue* pValue = pKey->getValue( OStringToOUString( pChoice->choice, aEncoding ) );
[ # # ][ # # ]
631 [ # # ]: 0 : if( pValue )
632 : : {
633 [ # # ]: 0 : if( pValue != pKey->getDefaultValue() )
634 : : {
635 : 0 : rContext.setValue( pKey, pValue, true );
636 : : #if OSL_DEBUG_LEVEL > 1
637 : : fprintf( stderr, "key %s is set to %s\n", pOption->keyword, pChoice->choice );
638 : : #endif
639 : :
640 : : }
641 : : #if OSL_DEBUG_LEVEL > 1
642 : : else
643 : : fprintf( stderr, "key %s is defaulted to %s\n", pOption->keyword, pChoice->choice );
644 : : #endif
645 : : }
646 : : #if OSL_DEBUG_LEVEL > 1
647 : : else
648 : : fprintf( stderr, "caution: value %s not found in key %s\n", pChoice->choice, pOption->keyword );
649 : : #endif
650 : : }
651 : : #if OSL_DEBUG_LEVEL > 1
652 : : else
653 : : fprintf( stderr, "caution: key %s not found in parser\n", pOption->keyword );
654 : : #endif
655 : : }
656 : : }
657 : : }
658 : :
659 : : // recurse through subgroups
660 [ # # ]: 0 : for( int g = 0; g < pPPDGroup->num_subgroups; g++ )
661 : : {
662 : 0 : updatePrinterContextInfo( pPPDGroup->subgroups + g, rContext );
663 : : }
664 : 0 : }
665 : :
666 : 0 : const PPDParser* CUPSManager::createCUPSParser( const OUString& rPrinter )
667 : : {
668 : 0 : const PPDParser* pNewParser = NULL;
669 : 0 : OUString aPrinter;
670 : :
671 [ # # ]: 0 : if( rPrinter.compareToAscii( "CUPS:", 5 ) == 0 )
672 : 0 : aPrinter = rPrinter.copy( 5 );
673 : : else
674 : 0 : aPrinter = rPrinter;
675 : :
676 [ # # ][ # # ]: 0 : if( m_aCUPSMutex.tryToAcquire() )
677 : : {
678 [ # # ][ # # ]: 0 : if( m_nDests && m_pDests && ! isCUPSDisabled() )
[ # # ][ # # ]
[ # # ]
679 : : {
680 : : boost::unordered_map< OUString, int, OUStringHash >::iterator dest_it =
681 [ # # ]: 0 : m_aCUPSDestMap.find( aPrinter );
682 [ # # ][ # # ]: 0 : if( dest_it != m_aCUPSDestMap.end() )
683 : : {
684 [ # # ]: 0 : cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second;
685 [ # # ]: 0 : OString aPPDFile = m_pCUPSWrapper->cupsGetPPD( pDest->name );
686 : : #if OSL_DEBUG_LEVEL > 1
687 : : fprintf( stderr, "PPD for %s is %s\n", OUStringToOString( aPrinter, osl_getThreadTextEncoding() ).getStr(), aPPDFile.getStr() );
688 : : #endif
689 [ # # ]: 0 : if( !aPPDFile.isEmpty() )
690 : : {
691 [ # # ]: 0 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
692 [ # # ]: 0 : OUString aFileName( OStringToOUString( aPPDFile, aEncoding ) );
693 : : // update the printer info with context information
694 [ # # ]: 0 : ppd_file_t* pPPD = m_pCUPSWrapper->ppdOpenFile( aPPDFile.getStr() );
695 [ # # ]: 0 : if( pPPD )
696 : : {
697 : : // create the new parser
698 [ # # ][ # # ]: 0 : PPDParser* pCUPSParser = new PPDParser( aFileName );
[ # # ][ # # ]
699 [ # # ]: 0 : pCUPSParser->m_aFile = rPrinter;
700 : 0 : pNewParser = pCUPSParser;
701 : :
702 [ # # ]: 0 : /*int nConflicts =*/ m_pCUPSWrapper->cupsMarkOptions( pPPD, pDest->num_options, pDest->options );
703 : : #if OSL_DEBUG_LEVEL > 1
704 : : fprintf( stderr, "processing the following options for printer %s (instance %s):\n",
705 : : pDest->name, pDest->instance );
706 : : for( int k = 0; k < pDest->num_options; k++ )
707 : : fprintf( stderr, " \"%s\" = \"%s\"\n",
708 : : pDest->options[k].name,
709 : : pDest->options[k].value );
710 : : #endif
711 [ # # ]: 0 : PrinterInfo& rInfo = m_aPrinters[ aPrinter ].m_aInfo;
712 : :
713 : : // remember the default context for later use
714 [ # # ]: 0 : PPDContext& rContext = m_aDefaultContexts[ aPrinter ];
715 [ # # ]: 0 : rContext.setParser( pNewParser );
716 : : // set system default paper; printer CUPS PPD options
717 : : // may overwrite it
718 [ # # ]: 0 : setDefaultPaper( rContext );
719 [ # # ]: 0 : for( int i = 0; i < pPPD->num_groups; i++ )
720 [ # # ]: 0 : updatePrinterContextInfo( pPPD->groups + i, rContext );
721 : :
722 : 0 : rInfo.m_pParser = pNewParser;
723 [ # # ]: 0 : rInfo.m_aContext = rContext;
724 : :
725 : : // clean up the mess
726 [ # # ]: 0 : m_pCUPSWrapper->ppdClose( pPPD );
727 : : }
728 : : #if OSL_DEBUG_LEVEL > 1
729 : : else
730 : : fprintf( stderr, "ppdOpenFile failed, falling back to generic driver\n" );
731 : : #endif
732 : :
733 : : // remove temporary PPD file
734 : 0 : unlink( aPPDFile.getStr() );
735 : 0 : }
736 : : #if OSL_DEBUG_LEVEL > 1
737 : : else
738 : : fprintf( stderr, "cupsGetPPD failed, falling back to generic driver\n" );
739 : : #endif
740 : : }
741 : : #if OSL_DEBUG_LEVEL > 1
742 : : else
743 : : fprintf( stderr, "no dest found for printer %s\n", OUStringToOString( aPrinter, osl_getThreadTextEncoding() ).getStr() );
744 : : #endif
745 : : }
746 [ # # ]: 0 : m_aCUPSMutex.release();
747 : : }
748 : : #if OSL_DEBUG_LEVEL >1
749 : : else
750 : : fprintf( stderr, "could not acquire CUPS mutex !!!\n" );
751 : : #endif
752 : :
753 [ # # ]: 0 : if( ! pNewParser )
754 : : {
755 : : // get the default PPD
756 [ # # ][ # # ]: 0 : pNewParser = PPDParser::getParser( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) );
[ # # ]
757 : :
758 [ # # ]: 0 : PrinterInfo& rInfo = m_aPrinters[ aPrinter ].m_aInfo;
759 : :
760 : 0 : rInfo.m_pParser = pNewParser;
761 [ # # ]: 0 : rInfo.m_aContext.setParser( pNewParser );
762 : : }
763 : :
764 : 0 : return pNewParser;
765 : : }
766 : :
767 : 0 : void CUPSManager::setupJobContextData( JobData& rData )
768 : : {
769 : : boost::unordered_map< OUString, int, OUStringHash >::iterator dest_it =
770 [ # # ]: 0 : m_aCUPSDestMap.find( rData.m_aPrinterName );
771 : :
772 [ # # ][ # # ]: 0 : if( dest_it == m_aCUPSDestMap.end() )
773 [ # # ]: 0 : return PrinterInfoManager::setupJobContextData( rData );
774 : :
775 : : boost::unordered_map< OUString, Printer, OUStringHash >::iterator p_it =
776 [ # # ]: 0 : m_aPrinters.find( rData.m_aPrinterName );
777 [ # # ][ # # ]: 0 : if( p_it == m_aPrinters.end() ) // huh ?
778 : : {
779 : : #if OSL_DEBUG_LEVEL > 1
780 : : fprintf( stderr, "CUPS printer list in disorder, no dest for printer %s !\n", OUStringToOString( rData.m_aPrinterName, osl_getThreadTextEncoding() ).getStr() );
781 : : #endif
782 : : return;
783 : : }
784 : :
785 [ # # ][ # # ]: 0 : if( p_it->second.m_aInfo.m_pParser == NULL )
786 : : {
787 : : // in turn calls createCUPSParser
788 : : // which updates the printer info
789 [ # # ][ # # ]: 0 : p_it->second.m_aInfo.m_pParser = PPDParser::getParser( p_it->second.m_aInfo.m_aDriverName );
[ # # ][ # # ]
[ # # ]
790 : : }
791 [ # # ][ # # ]: 0 : if( p_it->second.m_aInfo.m_aContext.getParser() == NULL )
792 : : {
793 : 0 : OUString aPrinter;
794 [ # # ][ # # ]: 0 : if( p_it->second.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) == 0 )
795 [ # # ]: 0 : aPrinter = p_it->second.m_aInfo.m_aDriverName.copy( 5 );
796 : : else
797 [ # # ]: 0 : aPrinter = p_it->second.m_aInfo.m_aDriverName;
798 : :
799 [ # # ][ # # ]: 0 : p_it->second.m_aInfo.m_aContext = m_aDefaultContexts[ aPrinter ];
[ # # ]
800 : : }
801 : :
802 [ # # ]: 0 : rData.m_pParser = p_it->second.m_aInfo.m_pParser;
803 [ # # ][ # # ]: 0 : rData.m_aContext = p_it->second.m_aInfo.m_aContext;
804 : : }
805 : :
806 : 0 : FILE* CUPSManager::startSpool( const OUString& rPrintername, bool bQuickCommand )
807 : : {
808 : : OSL_TRACE( "endSpool: %s, %s",
809 : : rtl::OUStringToOString( rPrintername, RTL_TEXTENCODING_UTF8 ).getStr(),
810 : : bQuickCommand ? "true" : "false" );
811 : :
812 [ # # ][ # # ]: 0 : if( m_aCUPSDestMap.find( rPrintername ) == m_aCUPSDestMap.end() )
[ # # ]
813 : : {
814 : : OSL_TRACE( "defer to PrinterInfoManager::startSpool" );
815 [ # # ]: 0 : return PrinterInfoManager::startSpool( rPrintername, bQuickCommand );
816 : : }
817 : :
818 : 0 : OUString aTmpURL, aTmpFile;
819 [ # # ]: 0 : osl_createTempFile( NULL, NULL, &aTmpURL.pData );
820 [ # # ]: 0 : osl_getSystemPathFromFileURL( aTmpURL.pData, &aTmpFile.pData );
821 [ # # ][ # # ]: 0 : OString aSysFile = OUStringToOString( aTmpFile, osl_getThreadTextEncoding() );
822 [ # # ]: 0 : FILE* fp = fopen( aSysFile.getStr(), "w" );
823 [ # # ]: 0 : if( fp )
824 [ # # ]: 0 : m_aSpoolFiles[fp] = aSysFile;
825 : :
826 : 0 : return fp;
827 : : }
828 : :
829 : : struct less_ppd_key : public ::std::binary_function<double, double, bool>
830 : : {
831 : 0 : bool operator()(const PPDKey* left, const PPDKey* right)
832 : 0 : { return left->getOrderDependency() < right->getOrderDependency(); }
833 : : };
834 : :
835 : 0 : void CUPSManager::getOptionsFromDocumentSetup( const JobData& rJob, bool bBanner, int& rNumOptions, void** rOptions ) const
836 : : {
837 : 0 : rNumOptions = 0;
838 : 0 : *rOptions = NULL;
839 : :
840 : : // emit features ordered to OrderDependency
841 : : // ignore features that are set to default
842 : :
843 : : // sanity check
844 [ # # ][ # # ]: 0 : if( rJob.m_pParser == rJob.m_aContext.getParser() && rJob.m_pParser )
[ # # ]
845 : : {
846 : : int i;
847 [ # # ]: 0 : int nKeys = rJob.m_aContext.countValuesModified();
848 [ # # ]: 0 : ::std::vector< const PPDKey* > aKeys( nKeys );
849 [ # # ]: 0 : for( i = 0; i < nKeys; i++ )
850 [ # # ][ # # ]: 0 : aKeys[i] = rJob.m_aContext.getModifiedKey( i );
851 [ # # ]: 0 : ::std::sort( aKeys.begin(), aKeys.end(), less_ppd_key() );
852 : :
853 [ # # ]: 0 : for( i = 0; i < nKeys; i++ )
854 : : {
855 [ # # ]: 0 : const PPDKey* pKey = aKeys[i];
856 [ # # ]: 0 : const PPDValue* pValue = rJob.m_aContext.getValue( pKey );
857 [ # # ][ # # ]: 0 : if(pValue && pValue->m_eType == eInvocation && pValue->m_aValue.Len() )
[ # # ][ # # ]
858 : : {
859 [ # # ][ # # ]: 0 : OString aKey = OUStringToOString( pKey->getKey(), RTL_TEXTENCODING_ASCII_US );
860 [ # # ][ # # ]: 0 : OString aValue = OUStringToOString( pValue->m_aOption, RTL_TEXTENCODING_ASCII_US );
861 [ # # ]: 0 : rNumOptions = m_pCUPSWrapper->cupsAddOption( aKey.getStr(), aValue.getStr(), rNumOptions, (cups_option_t**)rOptions );
862 : : }
863 : 0 : }
864 : : }
865 : :
866 [ # # ][ # # ]: 0 : if( rJob.m_nPDFDevice > 0 && rJob.m_nCopies > 1 )
867 : : {
868 : 0 : rtl::OString aVal( rtl::OString::valueOf( sal_Int32( rJob.m_nCopies ) ) );
869 [ # # ]: 0 : rNumOptions = m_pCUPSWrapper->cupsAddOption( "copies", aVal.getStr(), rNumOptions, (cups_option_t**)rOptions );
870 : : }
871 [ # # ]: 0 : if( ! bBanner )
872 : : {
873 : 0 : rNumOptions = m_pCUPSWrapper->cupsAddOption( "job-sheets", "none", rNumOptions, (cups_option_t**)rOptions );
874 : : }
875 : 0 : }
876 : :
877 : 0 : int CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData, bool bBanner )
878 : : {
879 : : OSL_TRACE( "endSpool: %s, %s, copy count = %d",
880 : : rtl::OUStringToOString( rPrintername, RTL_TEXTENCODING_UTF8 ).getStr(),
881 : : rtl::OUStringToOString( rJobTitle, RTL_TEXTENCODING_UTF8 ).getStr(),
882 : : rDocumentJobData.m_nCopies
883 : : );
884 : :
885 : 0 : int nJobID = 0;
886 : :
887 [ # # ]: 0 : osl::MutexGuard aGuard( m_aCUPSMutex );
888 : :
889 : : boost::unordered_map< OUString, int, OUStringHash >::iterator dest_it =
890 [ # # ]: 0 : m_aCUPSDestMap.find( rPrintername );
891 [ # # ][ # # ]: 0 : if( dest_it == m_aCUPSDestMap.end() )
892 : : {
893 : : OSL_TRACE( "defer to PrinterInfoManager::endSpool" );
894 [ # # ]: 0 : return PrinterInfoManager::endSpool( rPrintername, rJobTitle, pFile, rDocumentJobData, bBanner );
895 : : }
896 : :
897 [ # # ]: 0 : boost::unordered_map< FILE*, OString, FPtrHash >::const_iterator it = m_aSpoolFiles.find( pFile );
898 [ # # ][ # # ]: 0 : if( it != m_aSpoolFiles.end() )
899 : : {
900 [ # # ]: 0 : fclose( pFile );
901 [ # # ]: 0 : rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
902 : :
903 : : // setup cups options
904 : 0 : int nNumOptions = 0;
905 : 0 : cups_option_t* pOptions = NULL;
906 [ # # ]: 0 : getOptionsFromDocumentSetup( rDocumentJobData, bBanner, nNumOptions, (void**)&pOptions );
907 : :
908 [ # # ]: 0 : cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second;
909 : : nJobID = m_pCUPSWrapper->cupsPrintFile( pDest->name,
910 [ # # ]: 0 : it->second.getStr(),
911 : : OUStringToOString( rJobTitle, aEnc ).getStr(),
912 [ # # ][ # # ]: 0 : nNumOptions, pOptions );
913 : : #if OSL_DEBUG_LEVEL > 1
914 : : fprintf( stderr, "cupsPrintFile( %s, %s, %s, %d, %p ) returns %d\n",
915 : : pDest->name,
916 : : it->second.getStr(),
917 : : OUStringToOString( rJobTitle, aEnc ).getStr(),
918 : : nNumOptions,
919 : : pOptions,
920 : : nJobID
921 : : );
922 : : for( int n = 0; n < nNumOptions; n++ )
923 : : fprintf( stderr, " option %s=%s\n", pOptions[n].name, pOptions[n].value );
924 : : OString aCmd( "cp " );
925 : : aCmd = aCmd + it->second;
926 : : aCmd = aCmd + OString( " $HOME/cupsprint.ps" );
927 : : system( aCmd.getStr() );
928 : : #endif
929 : :
930 [ # # ]: 0 : unlink( it->second.getStr() );
931 [ # # ]: 0 : m_aSpoolFiles.erase( pFile );
932 [ # # ]: 0 : if( pOptions )
933 [ # # ]: 0 : m_pCUPSWrapper->cupsFreeOptions( nNumOptions, pOptions );
934 : : }
935 : :
936 [ # # ]: 0 : return nJobID;
937 : : }
938 : :
939 : :
940 : 0 : void CUPSManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo )
941 : : {
942 : 0 : PrinterInfoManager::changePrinterInfo( rPrinter, rNewInfo );
943 : 0 : }
944 : :
945 : 44 : bool CUPSManager::checkPrintersChanged( bool bWait )
946 : : {
947 : 44 : bool bChanged = false;
948 [ + - ]: 44 : if( bWait )
949 : : {
950 [ + + ]: 44 : if( m_aDestThread )
951 : : {
952 : : // initial asynchronous detection still running
953 : : #if OSL_DEBUG_LEVEL > 1
954 : : fprintf( stderr, "syncing cups discovery thread\n" );
955 : : #endif
956 : 33 : osl_joinWithThread( m_aDestThread );
957 : 33 : osl_destroyThread( m_aDestThread );
958 : 33 : m_aDestThread = NULL;
959 : : #if OSL_DEBUG_LEVEL > 1
960 : : fprintf( stderr, "done: syncing cups discovery thread\n" );
961 : : #endif
962 : : }
963 : : else
964 : : {
965 : : // #i82321# check for cups printer updates
966 : : // with this change the whole asynchronous detection in a thread is
967 : : // almost useless. The only relevance left is for some stalled systems
968 : : // where the user can set SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION
969 : : // (see vcl/unx/source/gdi/salprnpsp.cxx)
970 : : // so that checkPrintersChanged( true ) will never be called
971 : :
972 : : // there is no way to query CUPS whether the printer list has changed
973 : : // so get the dest list anew
974 [ - + ][ # # ]: 11 : if( m_nDests && m_pDests )
975 : 0 : m_pCUPSWrapper->cupsFreeDests( m_nDests, (cups_dest_t*)m_pDests );
976 : 11 : m_nDests = 0;
977 : 11 : m_pDests = NULL;
978 : 11 : runDests();
979 : : }
980 : : }
981 [ + - ]: 44 : if( m_aCUPSMutex.tryToAcquire() )
982 : : {
983 : 44 : bChanged = m_bNewDests;
984 : 44 : m_aCUPSMutex.release();
985 : : }
986 : :
987 [ - + ]: 44 : if( ! bChanged )
988 : : {
989 : 0 : bChanged = PrinterInfoManager::checkPrintersChanged( bWait );
990 : : // #i54375# ensure new merging with CUPS list in :initialize
991 [ # # ]: 0 : if( bChanged )
992 : 0 : m_bNewDests = true;
993 : : }
994 : :
995 [ + - ]: 44 : if( bChanged )
996 : 44 : initialize();
997 : :
998 : 44 : return bChanged;
999 : : }
1000 : :
1001 : 0 : bool CUPSManager::addPrinter( const OUString& rName, const OUString& rDriver )
1002 : : {
1003 : : // don't touch the CUPS printers
1004 [ # # ][ # # ]: 0 : if( m_aCUPSDestMap.find( rName ) != m_aCUPSDestMap.end() ||
[ # # # # ]
[ # # ][ # # ]
[ # # # #
# # ]
1005 : 0 : rDriver.compareToAscii( "CUPS:", 5 ) == 0
1006 : : )
1007 : 0 : return false;
1008 : 0 : return PrinterInfoManager::addPrinter( rName, rDriver );
1009 : : }
1010 : :
1011 : 0 : bool CUPSManager::removePrinter( const OUString& rName, bool bCheck )
1012 : : {
1013 : : // don't touch the CUPS printers
1014 [ # # ][ # # ]: 0 : if( m_aCUPSDestMap.find( rName ) != m_aCUPSDestMap.end() )
1015 : 0 : return false;
1016 : 0 : return PrinterInfoManager::removePrinter( rName, bCheck );
1017 : : }
1018 : :
1019 : 0 : bool CUPSManager::setDefaultPrinter( const OUString& rName )
1020 : : {
1021 : 0 : bool bSuccess = false;
1022 : : boost::unordered_map< OUString, int, OUStringHash >::iterator nit =
1023 [ # # ]: 0 : m_aCUPSDestMap.find( rName );
1024 [ # # ][ # # ]: 0 : if( nit != m_aCUPSDestMap.end() && m_aCUPSMutex.tryToAcquire() )
[ # # ][ # # ]
[ # # ]
[ # # # # ]
1025 : : {
1026 : 0 : cups_dest_t* pDests = (cups_dest_t*)m_pDests;
1027 [ # # ]: 0 : for( int i = 0; i < m_nDests; i++ )
1028 : 0 : pDests[i].is_default = 0;
1029 [ # # ]: 0 : pDests[ nit->second ].is_default = 1;
1030 [ # # ]: 0 : m_pCUPSWrapper->cupsSetDests( m_nDests, (cups_dest_t*)m_pDests );
1031 : 0 : m_aDefaultPrinter = rName;
1032 [ # # ]: 0 : m_aCUPSMutex.release();
1033 : 0 : bSuccess = true;
1034 : : }
1035 : : else
1036 [ # # ]: 0 : bSuccess = PrinterInfoManager::setDefaultPrinter( rName );
1037 : :
1038 : 0 : return bSuccess;
1039 : : }
1040 : :
1041 : 0 : bool CUPSManager::writePrinterConfig()
1042 : : {
1043 : 0 : bool bDestModified = false;
1044 : 0 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1045 : :
1046 [ # # ]: 0 : for( boost::unordered_map< OUString, Printer, OUStringHash >::iterator prt =
1047 [ # # ][ # # ]: 0 : m_aPrinters.begin(); prt != m_aPrinters.end(); ++prt )
1048 : : {
1049 : : boost::unordered_map< OUString, int, OUStringHash >::iterator nit =
1050 [ # # ][ # # ]: 0 : m_aCUPSDestMap.find( prt->first );
1051 [ # # ][ # # ]: 0 : if( nit == m_aCUPSDestMap.end() )
1052 : 0 : continue;
1053 : :
1054 [ # # ][ # # ]: 0 : if( ! prt->second.m_bModified )
1055 : 0 : continue;
1056 : :
1057 [ # # ][ # # ]: 0 : if( m_aCUPSMutex.tryToAcquire() )
1058 : : {
1059 : 0 : bDestModified = true;
1060 [ # # ]: 0 : cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + nit->second;
1061 [ # # ]: 0 : PrinterInfo& rInfo = prt->second.m_aInfo;
1062 : :
1063 : : // create new option list
1064 : 0 : int nNewOptions = 0;
1065 : 0 : cups_option_t* pNewOptions = NULL;
1066 [ # # ]: 0 : int nValues = rInfo.m_aContext.countValuesModified();
1067 [ # # ]: 0 : for( int i = 0; i < nValues; i++ )
1068 : : {
1069 [ # # ]: 0 : const PPDKey* pKey = rInfo.m_aContext.getModifiedKey( i );
1070 [ # # ]: 0 : const PPDValue* pValue = rInfo.m_aContext.getValue( pKey );
1071 [ # # ][ # # ]: 0 : if( pKey && pValue ) // sanity check
1072 : : {
1073 [ # # ][ # # ]: 0 : OString aName = OUStringToOString( pKey->getKey(), aEncoding );
1074 [ # # ][ # # ]: 0 : OString aValue = OUStringToOString( pValue->m_aOption, aEncoding );
1075 [ # # ]: 0 : nNewOptions = m_pCUPSWrapper->cupsAddOption( aName.getStr(), aValue.getStr(), nNewOptions, &pNewOptions );
1076 : : }
1077 : : }
1078 : : // set PPD options on CUPS dest
1079 [ # # ]: 0 : m_pCUPSWrapper->cupsFreeOptions( pDest->num_options, pDest->options );
1080 : 0 : pDest->num_options = nNewOptions;
1081 : 0 : pDest->options = pNewOptions;
1082 [ # # ]: 0 : m_aCUPSMutex.release();
1083 : : }
1084 : : }
1085 [ # # ][ # # ]: 0 : if( bDestModified && m_aCUPSMutex.tryToAcquire() )
[ # # ]
1086 : : {
1087 : 0 : m_pCUPSWrapper->cupsSetDests( m_nDests, (cups_dest_t*)m_pDests );
1088 : 0 : m_aCUPSMutex.release();
1089 : : }
1090 : :
1091 : 0 : return PrinterInfoManager::writePrinterConfig();
1092 : : }
1093 : :
1094 : 0 : bool CUPSManager::addOrRemovePossible() const
1095 : : {
1096 [ # # ][ # # ]: 0 : return (m_nDests && m_pDests && ! isCUPSDisabled())? false : PrinterInfoManager::addOrRemovePossible();
[ # # ]
1097 : : }
1098 : :
1099 : 0 : const char* CUPSManager::authenticateUser( const char* /*pIn*/ )
1100 : : {
1101 : 0 : const char* pRet = NULL;
1102 : :
1103 : 0 : OUString aLib(_XSALSET_LIBNAME );
1104 [ # # ]: 0 : oslModule pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
1105 [ # # ]: 0 : if( pLib )
1106 : : {
1107 : 0 : OUString aSym( "Sal_authenticateQuery" );
1108 : : bool (*getpw)( const OString& rServer, OString& rUser, OString& rPw) =
1109 [ # # ]: 0 : (bool(*)(const OString&,OString&,OString&))osl_getFunctionSymbol( pLib, aSym.pData );
1110 [ # # ]: 0 : if( getpw )
1111 : : {
1112 [ # # ]: 0 : osl::MutexGuard aGuard( m_aCUPSMutex );
1113 : :
1114 [ # # ]: 0 : OString aUser = m_pCUPSWrapper->cupsUser();
1115 [ # # ]: 0 : OString aServer = m_pCUPSWrapper->cupsServer();
1116 : 0 : OString aPassword;
1117 [ # # ][ # # ]: 0 : if( getpw( aServer, aUser, aPassword ) )
1118 : : {
1119 : 0 : m_aPassword = aPassword;
1120 : 0 : m_aUser = aUser;
1121 [ # # ]: 0 : m_pCUPSWrapper->cupsSetUser( m_aUser.getStr() );
1122 : 0 : pRet = m_aPassword.getStr();
1123 [ # # ]: 0 : }
1124 : : }
1125 [ # # ]: 0 : osl_unloadModule( pLib );
1126 : : }
1127 : : #if OSL_DEBUG_LEVEL > 1
1128 : : else fprintf( stderr, "loading of module %s failed\n", OUStringToOString( aLib, osl_getThreadTextEncoding() ).getStr() );
1129 : : #endif
1130 : :
1131 : 0 : return pRet;
1132 : : }
1133 : :
1134 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|