Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <unistd.h>
21 : #include <sys/wait.h>
22 : #include <signal.h>
23 :
24 : #include "cupsmgr.hxx"
25 : #include "vcl/strhelper.hxx"
26 :
27 : #include "unx/saldata.hxx"
28 :
29 : #include "tools/urlobj.hxx"
30 : #include "tools/stream.hxx"
31 : #include "tools/debug.hxx"
32 : #include "tools/config.hxx"
33 :
34 : #include "i18nutil/paper.hxx"
35 : #include <comphelper/string.hxx>
36 : #include "rtl/strbuf.hxx"
37 : #include <sal/macros.h>
38 :
39 : #include "osl/thread.hxx"
40 : #include "osl/mutex.hxx"
41 : #include "osl/process.h"
42 :
43 : #include <boost/scoped_ptr.hpp>
44 :
45 : // filename of configuration files
46 : #define PRINT_FILENAME "psprint.conf"
47 : // the group of the global defaults
48 : #define GLOBAL_DEFAULTS_GROUP "__Global_Printer_Defaults__"
49 :
50 : #include <boost/unordered_set.hpp>
51 :
52 : using namespace psp;
53 : using namespace osl;
54 :
55 : namespace psp
56 : {
57 : class SystemQueueInfo : public Thread
58 : {
59 : mutable Mutex m_aMutex;
60 : bool m_bChanged;
61 : std::list< PrinterInfoManager::SystemPrintQueue >
62 : m_aQueues;
63 : OUString m_aCommand;
64 :
65 : virtual void run() SAL_OVERRIDE;
66 :
67 : public:
68 : SystemQueueInfo();
69 : virtual ~SystemQueueInfo();
70 :
71 : bool hasChanged() const;
72 : OUString getCommand() const;
73 :
74 : // sets changed status to false; therefore not const
75 : void getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues );
76 : };
77 : } // namespace
78 :
79 : /*
80 : * class PrinterInfoManager
81 : */
82 :
83 4366 : PrinterInfoManager& PrinterInfoManager::get()
84 : {
85 4366 : SalData* pSalData = GetSalData();
86 :
87 4366 : if( ! pSalData->m_pPIManager )
88 : {
89 116 : pSalData->m_pPIManager = CUPSManager::tryLoadCUPS();
90 116 : if( ! pSalData->m_pPIManager )
91 0 : pSalData->m_pPIManager = new PrinterInfoManager();
92 :
93 116 : pSalData->m_pPIManager->initialize();
94 : #if OSL_DEBUG_LEVEL > 1
95 : fprintf( stderr, "PrinterInfoManager::get create Manager of type %d\n", pSalData->m_pPIManager->getType() );
96 : #endif
97 : }
98 :
99 4366 : return *pSalData->m_pPIManager;
100 : }
101 :
102 0 : void PrinterInfoManager::release()
103 : {
104 0 : SalData* pSalData = GetSalData();
105 0 : delete pSalData->m_pPIManager;
106 0 : pSalData->m_pPIManager = NULL;
107 0 : }
108 :
109 116 : PrinterInfoManager::PrinterInfoManager( Type eType ) :
110 : m_pQueueInfo( NULL ),
111 : m_eType( eType ),
112 : m_bUseIncludeFeature( false ),
113 : m_bUseJobPatch( true ),
114 116 : m_aSystemDefaultPaper( "A4" )
115 : {
116 116 : if( eType == Default )
117 0 : m_pQueueInfo = new SystemQueueInfo();
118 116 : initSystemDefaultPaper();
119 116 : }
120 :
121 0 : PrinterInfoManager::~PrinterInfoManager()
122 : {
123 0 : delete m_pQueueInfo;
124 : #if OSL_DEBUG_LEVEL > 1
125 : fprintf( stderr, "PrinterInfoManager: destroyed Manager of type %d\n", getType() );
126 : #endif
127 0 : }
128 :
129 116 : void PrinterInfoManager::initSystemDefaultPaper()
130 : {
131 232 : m_aSystemDefaultPaper = OStringToOUString(
132 : PaperInfo::toPSName(PaperInfo::getSystemDefaultPaper().getPaper()),
133 116 : RTL_TEXTENCODING_UTF8);
134 116 : }
135 :
136 74 : bool PrinterInfoManager::checkPrintersChanged( bool bWait )
137 : {
138 : // check if files were created, deleted or modified since initialize()
139 74 : ::std::list< WatchFile >::const_iterator it;
140 74 : bool bChanged = false;
141 222 : for( it = m_aWatchFiles.begin(); it != m_aWatchFiles.end() && ! bChanged; ++it )
142 : {
143 148 : DirectoryItem aItem;
144 148 : if( DirectoryItem::get( it->m_aFilePath, aItem ) )
145 : {
146 74 : if( it->m_aModified.Seconds != 0 )
147 0 : bChanged = true; // file probably has vanished
148 : }
149 : else
150 : {
151 74 : FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
152 74 : if( aItem.getFileStatus( aStatus ) )
153 0 : bChanged = true; // unlikely but not impossible
154 : else
155 : {
156 74 : TimeValue aModified = aStatus.getModifyTime();
157 74 : if( aModified.Seconds != it->m_aModified.Seconds )
158 0 : bChanged = true;
159 74 : }
160 : }
161 148 : }
162 :
163 74 : if( bWait && m_pQueueInfo )
164 : {
165 : #if OSL_DEBUG_LEVEL > 1
166 : fprintf( stderr, "syncing printer discovery thread\n" );
167 : #endif
168 0 : m_pQueueInfo->join();
169 : #if OSL_DEBUG_LEVEL > 1
170 : fprintf( stderr, "done: syncing printer discovery thread\n" );
171 : #endif
172 : }
173 :
174 74 : if( ! bChanged && m_pQueueInfo )
175 0 : bChanged = m_pQueueInfo->hasChanged();
176 74 : if( bChanged )
177 : {
178 0 : initialize();
179 : }
180 :
181 74 : return bChanged;
182 : }
183 :
184 116 : void PrinterInfoManager::initialize()
185 : {
186 116 : m_bUseIncludeFeature = false;
187 116 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
188 116 : m_aPrinters.clear();
189 116 : m_aWatchFiles.clear();
190 116 : OUString aDefaultPrinter;
191 :
192 : // first initialize the global defaults
193 : // have to iterate over all possible files
194 : // there should be only one global setup section in all
195 : // available config files
196 116 : m_aGlobalDefaults = PrinterInfo();
197 :
198 : // need a parser for the PPDContext. generic printer should do.
199 116 : m_aGlobalDefaults.m_pParser = PPDParser::getParser( OUString( "SGENPRT" ) );
200 116 : m_aGlobalDefaults.m_aContext.setParser( m_aGlobalDefaults.m_pParser );
201 :
202 116 : if( ! m_aGlobalDefaults.m_pParser )
203 : {
204 : #if OSL_DEBUG_LEVEL > 1
205 : fprintf( stderr, "Error: no default PPD file SGENPRT available, shutting down psprint...\n" );
206 : #endif
207 0 : return;
208 : }
209 :
210 116 : std::list< OUString > aDirList;
211 116 : psp::getPrinterPathList( aDirList, NULL );
212 116 : std::list< OUString >::const_iterator print_dir_it;
213 348 : for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it )
214 : {
215 232 : INetURLObject aFile( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
216 232 : aFile.Append( OUString( PRINT_FILENAME ) );
217 464 : Config aConfig( aFile.PathToFileName() );
218 232 : if( aConfig.HasGroup( GLOBAL_DEFAULTS_GROUP ) )
219 : {
220 : #if OSL_DEBUG_LEVEL > 1
221 : fprintf( stderr, "found global defaults in %s\n", OUStringToOString( aFile.PathToFileName(), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
222 : #endif
223 116 : aConfig.SetGroup( GLOBAL_DEFAULTS_GROUP );
224 :
225 116 : OString aValue( aConfig.ReadKey( "Copies" ) );
226 116 : if (!aValue.isEmpty())
227 0 : m_aGlobalDefaults.m_nCopies = aValue.toInt32();
228 :
229 116 : aValue = aConfig.ReadKey( "Orientation" );
230 116 : if (!aValue.isEmpty())
231 0 : m_aGlobalDefaults.m_eOrientation = aValue.equalsIgnoreAsciiCase("Landscape") ? orientation::Landscape : orientation::Portrait;
232 :
233 : using comphelper::string::getToken;
234 :
235 116 : aValue = aConfig.ReadKey( "MarginAdjust" );
236 116 : if (!aValue.isEmpty())
237 : {
238 0 : m_aGlobalDefaults.m_nLeftMarginAdjust = getToken(aValue, 0, ',').toInt32();
239 0 : m_aGlobalDefaults.m_nRightMarginAdjust = getToken(aValue, 1, ',').toInt32();
240 0 : m_aGlobalDefaults.m_nTopMarginAdjust = getToken(aValue, 2, ',').toInt32();
241 0 : m_aGlobalDefaults.m_nBottomMarginAdjust = getToken(aValue, 3, ',').toInt32();
242 : }
243 :
244 116 : aValue = aConfig.ReadKey( "ColorDepth", "24" );
245 116 : if (!aValue.isEmpty())
246 116 : m_aGlobalDefaults.m_nColorDepth = aValue.toInt32();
247 :
248 116 : aValue = aConfig.ReadKey( "ColorDevice" );
249 116 : if (!aValue.isEmpty())
250 0 : m_aGlobalDefaults.m_nColorDevice = aValue.toInt32();
251 :
252 116 : aValue = aConfig.ReadKey( "PSLevel" );
253 116 : if (!aValue.isEmpty())
254 0 : m_aGlobalDefaults.m_nPSLevel = aValue.toInt32();
255 :
256 116 : aValue = aConfig.ReadKey( "PDFDevice" );
257 116 : if (!aValue.isEmpty())
258 0 : m_aGlobalDefaults.m_nPDFDevice = aValue.toInt32();
259 :
260 : // get the PPDContext of global JobData
261 116 : for( int nKey = 0; nKey < aConfig.GetKeyCount(); ++nKey )
262 : {
263 0 : OString aKey( aConfig.GetKeyName( nKey ) );
264 0 : if (aKey.startsWith("PPD_"))
265 : {
266 0 : aValue = aConfig.ReadKey( aKey );
267 0 : const PPDKey* pKey = m_aGlobalDefaults.m_pParser->getKey(OStringToOUString(aKey.copy(4), RTL_TEXTENCODING_ISO_8859_1));
268 0 : if( pKey )
269 : {
270 : m_aGlobalDefaults.m_aContext.
271 : setValue( pKey,
272 0 : aValue.equals("*nil") ? NULL : pKey->getValue(OStringToOUString(aValue, RTL_TEXTENCODING_ISO_8859_1)),
273 0 : true );
274 : }
275 : }
276 116 : }
277 : }
278 232 : }
279 116 : setDefaultPaper( m_aGlobalDefaults.m_aContext );
280 :
281 : // now collect all available printers
282 348 : for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it )
283 : {
284 232 : INetURLObject aDir( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
285 464 : INetURLObject aFile( aDir );
286 232 : aFile.Append( OUString( PRINT_FILENAME ) );
287 :
288 : // check directory validity
289 464 : OUString aUniPath;
290 232 : FileBase::getFileURLFromSystemPath( aDir.PathToFileName(), aUniPath );
291 464 : Directory aDirectory( aUniPath );
292 232 : if( aDirectory.open() )
293 0 : continue;
294 232 : aDirectory.close();
295 :
296 232 : FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aUniPath );
297 464 : FileStatus aStatus( osl_FileStatus_Mask_ModifyTime );
298 464 : DirectoryItem aItem;
299 :
300 : // setup WatchFile list
301 464 : WatchFile aWatchFile;
302 232 : aWatchFile.m_aFilePath = aUniPath;
303 348 : if( ! DirectoryItem::get( aUniPath, aItem ) &&
304 116 : ! aItem.getFileStatus( aStatus ) )
305 : {
306 116 : aWatchFile.m_aModified = aStatus.getModifyTime();
307 : }
308 : else
309 : {
310 116 : aWatchFile.m_aModified.Seconds = 0;
311 116 : aWatchFile.m_aModified.Nanosec = 0;
312 : }
313 232 : m_aWatchFiles.push_back( aWatchFile );
314 :
315 464 : Config aConfig( aFile.PathToFileName() );
316 580 : for( int nGroup = 0; nGroup < aConfig.GetGroupCount(); nGroup++ )
317 : {
318 348 : aConfig.SetGroup( aConfig.GetGroupName( nGroup ) );
319 348 : OString aValue = aConfig.ReadKey( "Printer" );
320 348 : if (!aValue.isEmpty())
321 : {
322 116 : OUString aPrinterName;
323 :
324 116 : sal_Int32 nNamePos = aValue.indexOf('/');
325 : // check for valid value of "Printer"
326 116 : if (nNamePos == -1)
327 0 : continue;
328 :
329 232 : Printer aPrinter;
330 : // initialize to global defaults
331 116 : aPrinter.m_aInfo = m_aGlobalDefaults;
332 :
333 232 : aPrinterName = OStringToOUString(aValue.copy(nNamePos+1),
334 116 : RTL_TEXTENCODING_UTF8);
335 116 : aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
336 116 : aPrinter.m_aInfo.m_aDriverName = OStringToOUString(aValue.copy(0, nNamePos), RTL_TEXTENCODING_UTF8);
337 :
338 : // set parser, merge settings
339 : // don't do this for CUPS printers as this is done
340 : // by the CUPS system itself
341 116 : if( !aPrinter.m_aInfo.m_aDriverName.startsWith( "CUPS:" ) )
342 : {
343 116 : aPrinter.m_aInfo.m_pParser = PPDParser::getParser( aPrinter.m_aInfo.m_aDriverName );
344 116 : aPrinter.m_aInfo.m_aContext.setParser( aPrinter.m_aInfo.m_pParser );
345 : // note: setParser also purges the context
346 :
347 : // ignore this printer if its driver is not found
348 116 : if( ! aPrinter.m_aInfo.m_pParser )
349 0 : continue;
350 :
351 : // merge the ppd context keys if the printer has the same keys and values
352 : // this is a bit tricky, since it involves mixing two PPDs
353 : // without constraints which might end up badly
354 : // this feature should be use with caution
355 : // it is mainly to select default paper sizes for new printers
356 232 : for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
357 : {
358 116 : const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
359 116 : const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
360 116 : const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL;
361 116 : if( pDefKey && pPrinterKey )
362 : // at least the options exist in both PPDs
363 : {
364 116 : if( pDefValue )
365 : {
366 116 : const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
367 116 : if( pPrinterValue )
368 : // the printer has a corresponding option for the key
369 116 : aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
370 : }
371 : else
372 0 : aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL );
373 : }
374 : }
375 :
376 116 : aValue = aConfig.ReadKey( "Command" );
377 : // no printer without a command
378 116 : if (aValue.isEmpty())
379 : {
380 : /* TODO:
381 : * porters: please append your platform to the Solaris
382 : * case if your platform has SystemV printing per default.
383 : */
384 : #if defined SOLARIS
385 : aValue = "lp";
386 : #else
387 116 : aValue = "lpr";
388 : #endif
389 : }
390 116 : aPrinter.m_aInfo.m_aCommand = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
391 : }
392 :
393 116 : aValue = aConfig.ReadKey( "QuickCommand" );
394 116 : aPrinter.m_aInfo.m_aQuickCommand = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
395 :
396 116 : aValue = aConfig.ReadKey( "Features" );
397 116 : aPrinter.m_aInfo.m_aFeatures = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
398 :
399 : // override the settings in m_aGlobalDefaults if keys exist
400 116 : aValue = aConfig.ReadKey( "DefaultPrinter" );
401 116 : if (!aValue.equals("0") && !aValue.equalsIgnoreAsciiCase("false"))
402 116 : aDefaultPrinter = aPrinterName;
403 :
404 116 : aValue = aConfig.ReadKey( "Location" );
405 116 : aPrinter.m_aInfo.m_aLocation = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
406 :
407 116 : aValue = aConfig.ReadKey( "Comment" );
408 116 : aPrinter.m_aInfo.m_aComment = OStringToOUString(aValue, RTL_TEXTENCODING_UTF8);
409 :
410 116 : aValue = aConfig.ReadKey( "Copies" );
411 116 : if (!aValue.isEmpty())
412 0 : aPrinter.m_aInfo.m_nCopies = aValue.toInt32();
413 :
414 116 : aValue = aConfig.ReadKey( "Orientation" );
415 116 : if (!aValue.isEmpty())
416 0 : aPrinter.m_aInfo.m_eOrientation = aValue.equalsIgnoreAsciiCase("Landscape") ? orientation::Landscape : orientation::Portrait;
417 :
418 : using comphelper::string::getToken;
419 :
420 116 : aValue = aConfig.ReadKey( "MarginAdjust" );
421 116 : if (!aValue.isEmpty())
422 : {
423 0 : aPrinter.m_aInfo.m_nLeftMarginAdjust = getToken(aValue, 0, ',' ).toInt32();
424 0 : aPrinter.m_aInfo.m_nRightMarginAdjust = getToken(aValue, 1, ',' ).toInt32();
425 0 : aPrinter.m_aInfo.m_nTopMarginAdjust = getToken(aValue, 2, ',' ).toInt32();
426 0 : aPrinter.m_aInfo.m_nBottomMarginAdjust = getToken(aValue, 3, ',' ).toInt32();
427 : }
428 :
429 116 : aValue = aConfig.ReadKey( "ColorDepth" );
430 116 : if (!aValue.isEmpty())
431 0 : aPrinter.m_aInfo.m_nColorDepth = aValue.toInt32();
432 :
433 116 : aValue = aConfig.ReadKey( "ColorDevice" );
434 116 : if (!aValue.isEmpty())
435 0 : aPrinter.m_aInfo.m_nColorDevice = aValue.toInt32();
436 :
437 116 : aValue = aConfig.ReadKey( "PSLevel" );
438 116 : if (!aValue.isEmpty())
439 0 : aPrinter.m_aInfo.m_nPSLevel = aValue.toInt32();
440 :
441 116 : aValue = aConfig.ReadKey( "PDFDevice" );
442 116 : if (!aValue.isEmpty())
443 0 : aPrinter.m_aInfo.m_nPDFDevice = aValue.toInt32();
444 :
445 : // now iterate over all keys to extract multi key information:
446 : // 1. PPDContext information
447 696 : for( int nKey = 0; nKey < aConfig.GetKeyCount(); ++nKey )
448 : {
449 580 : OString aKey( aConfig.GetKeyName( nKey ) );
450 580 : if( aKey.startsWith("PPD_") && aPrinter.m_aInfo.m_pParser )
451 : {
452 0 : aValue = aConfig.ReadKey( aKey );
453 0 : const PPDKey* pKey = aPrinter.m_aInfo.m_pParser->getKey(OStringToOUString(aKey.copy(4), RTL_TEXTENCODING_ISO_8859_1));
454 0 : if( pKey )
455 : {
456 : aPrinter.m_aInfo.m_aContext.
457 : setValue( pKey,
458 0 : aValue.equals("*nil") ? NULL : pKey->getValue(OStringToOUString(aValue, RTL_TEXTENCODING_ISO_8859_1)),
459 0 : true );
460 : }
461 : }
462 580 : }
463 :
464 116 : setDefaultPaper( aPrinter.m_aInfo.m_aContext );
465 :
466 : // finally insert printer
467 116 : FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aPrinter.m_aFile );
468 116 : aPrinter.m_bModified = false;
469 116 : aPrinter.m_aGroup = aConfig.GetGroupName( nGroup );
470 : boost::unordered_map< OUString, Printer, OUStringHash >::const_iterator find_it =
471 116 : m_aPrinters.find( aPrinterName );
472 116 : if( find_it != m_aPrinters.end() )
473 : {
474 0 : aPrinter.m_aAlternateFiles = find_it->second.m_aAlternateFiles;
475 0 : aPrinter.m_aAlternateFiles.push_front( find_it->second.m_aFile );
476 : }
477 232 : m_aPrinters[ aPrinterName ] = aPrinter;
478 : }
479 348 : }
480 232 : }
481 :
482 : // set default printer
483 116 : if( m_aPrinters.size() )
484 : {
485 116 : if( m_aPrinters.find( aDefaultPrinter ) == m_aPrinters.end() )
486 0 : aDefaultPrinter = m_aPrinters.begin()->first;
487 : }
488 : else
489 0 : aDefaultPrinter = OUString();
490 116 : m_aDefaultPrinter = aDefaultPrinter;
491 :
492 116 : if( m_eType != Default )
493 116 : return;
494 :
495 : // add a default printer for every available print queue
496 : // merge paper default printer, all else from global defaults
497 0 : PrinterInfo aMergeInfo( m_aGlobalDefaults );
498 0 : aMergeInfo.m_aDriverName = "SGENPRT";
499 0 : aMergeInfo.m_aFeatures = "autoqueue";
500 :
501 0 : if( !m_aDefaultPrinter.isEmpty() )
502 : {
503 0 : PrinterInfo aDefaultInfo( getPrinterInfo( m_aDefaultPrinter ) );
504 :
505 0 : const PPDKey* pDefKey = aDefaultInfo.m_pParser->getKey( OUString( "PageSize" ) );
506 0 : const PPDKey* pMergeKey = aMergeInfo.m_pParser->getKey( OUString( "PageSize" ) );
507 0 : const PPDValue* pDefValue = aDefaultInfo.m_aContext.getValue( pDefKey );
508 0 : const PPDValue* pMergeValue = pMergeKey ? pMergeKey->getValue( pDefValue->m_aOption ) : NULL;
509 0 : if( pMergeKey && pMergeValue )
510 0 : aMergeInfo.m_aContext.setValue( pMergeKey, pMergeValue );
511 : }
512 :
513 0 : getSystemPrintQueues();
514 0 : for( ::std::list< SystemPrintQueue >::iterator it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it )
515 : {
516 0 : OUString aPrinterName( "<" );
517 0 : aPrinterName += it->m_aQueue;
518 0 : aPrinterName += ">";
519 :
520 0 : if( m_aPrinters.find( aPrinterName ) != m_aPrinters.end() )
521 : // probably user made this one permanent
522 0 : continue;
523 :
524 0 : OUString aCmd( m_aSystemPrintCommand );
525 0 : aCmd = aCmd.replaceAll( "(PRINTER)", it->m_aQueue );
526 :
527 0 : Printer aPrinter;
528 :
529 : // initialize to merged defaults
530 0 : aPrinter.m_aInfo = aMergeInfo;
531 0 : aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
532 0 : aPrinter.m_aInfo.m_aCommand = aCmd;
533 0 : aPrinter.m_aInfo.m_aComment = it->m_aComment;
534 0 : aPrinter.m_aInfo.m_aLocation = it->m_aLocation;
535 0 : aPrinter.m_bModified = false;
536 0 : aPrinter.m_aGroup = OUStringToOString(aPrinterName, aEncoding); //provide group name in case user makes this one permanent
537 :
538 0 : m_aPrinters[ aPrinterName ] = aPrinter;
539 0 : }
540 : }
541 :
542 74 : void PrinterInfoManager::listPrinters( ::std::list< OUString >& rList ) const
543 : {
544 74 : ::boost::unordered_map< OUString, Printer, OUStringHash >::const_iterator it;
545 74 : rList.clear();
546 148 : for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it )
547 74 : rList.push_back( it->first );
548 74 : }
549 :
550 2314 : const PrinterInfo& PrinterInfoManager::getPrinterInfo( const OUString& rPrinter ) const
551 : {
552 2314 : static PrinterInfo aEmptyInfo;
553 2314 : ::boost::unordered_map< OUString, Printer, OUStringHash >::const_iterator it = m_aPrinters.find( rPrinter );
554 :
555 : DBG_ASSERT( it != m_aPrinters.end(), "Do not ask for info about nonexistent printers" );
556 :
557 2314 : return it != m_aPrinters.end() ? it->second.m_aInfo : aEmptyInfo;
558 : }
559 :
560 0 : void PrinterInfoManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo )
561 : {
562 0 : ::boost::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinter );
563 :
564 : DBG_ASSERT( it != m_aPrinters.end(), "Do not change nonexistant printers" );
565 :
566 0 : if( it != m_aPrinters.end() )
567 : {
568 0 : it->second.m_aInfo = rNewInfo;
569 0 : it->second.m_bModified = true;
570 0 : writePrinterConfig();
571 : }
572 0 : }
573 :
574 : // need to check writeability / creatability of config files
575 0 : static bool checkWriteability( const OUString& rUniPath )
576 : {
577 0 : bool bRet = false;
578 0 : OUString aSysPath;
579 0 : FileBase::getSystemPathFromFileURL( rUniPath, aSysPath );
580 0 : SvFileStream aStream( aSysPath, STREAM_READ | STREAM_WRITE );
581 0 : if( aStream.IsOpen() && aStream.IsWritable() )
582 0 : bRet = true;
583 0 : return bRet;
584 : }
585 :
586 0 : bool PrinterInfoManager::writePrinterConfig()
587 : {
588 : // find at least one writeable config
589 0 : ::boost::unordered_map< OUString, Config*, OUStringHash > files;
590 0 : ::boost::unordered_map< OUString, int, OUStringHash > rofiles;
591 0 : ::boost::unordered_map< OUString, Config*, OUStringHash >::iterator file_it;
592 :
593 0 : for( ::std::list< WatchFile >::const_iterator wit = m_aWatchFiles.begin(); wit != m_aWatchFiles.end(); ++wit )
594 : {
595 0 : if( checkWriteability( wit->m_aFilePath ) )
596 : {
597 0 : files[ wit->m_aFilePath ] = new Config( wit->m_aFilePath );
598 0 : break;
599 : }
600 : }
601 :
602 0 : if( files.empty() )
603 0 : return false;
604 :
605 0 : Config* pGlobal = files.begin()->second;
606 0 : pGlobal->SetGroup( GLOBAL_DEFAULTS_GROUP );
607 :
608 0 : ::boost::unordered_map< OUString, Printer, OUStringHash >::iterator it;
609 0 : for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it )
610 : {
611 0 : if( ! it->second.m_bModified )
612 : // printer was not changed, do nothing
613 0 : continue;
614 :
615 : // don't save autoqueue printers
616 0 : sal_Int32 nIndex = 0;
617 0 : bool bAutoQueue = false;
618 0 : while( nIndex != -1 && ! bAutoQueue )
619 : {
620 0 : OUString aToken( it->second.m_aInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
621 0 : if( aToken.equalsAscii( "autoqueue" ) )
622 0 : bAutoQueue = true;
623 0 : }
624 0 : if( bAutoQueue )
625 0 : continue;
626 :
627 0 : if( !it->second.m_aFile.isEmpty() )
628 : {
629 : // check if file is writable
630 0 : if( files.find( it->second.m_aFile ) == files.end() )
631 : {
632 0 : bool bInsertToNewFile = false;
633 : // maybe it is simply not inserted yet
634 0 : if( rofiles.find( it->second.m_aFile ) == rofiles.end() )
635 : {
636 0 : if( checkWriteability( it->second.m_aFile ) )
637 0 : files[ it->second.m_aFile ] = new Config( it->second.m_aFile );
638 : else
639 0 : bInsertToNewFile = true;
640 : }
641 : else
642 0 : bInsertToNewFile = true;
643 : // original file is read only, insert printer in a new writeable file
644 0 : if( bInsertToNewFile )
645 : {
646 0 : rofiles[ it->second.m_aFile ] = 1;
647 : // update alternate file list
648 : // the remove operation ensures uniqueness of each alternate
649 0 : it->second.m_aAlternateFiles.remove( it->second.m_aFile );
650 0 : it->second.m_aAlternateFiles.remove( files.begin()->first );
651 0 : it->second.m_aAlternateFiles.push_front( it->second.m_aFile );
652 : // update file
653 0 : it->second.m_aFile = files.begin()->first;
654 : }
655 : }
656 : }
657 : else // a new printer, write it to the first file available
658 0 : it->second.m_aFile = files.begin()->first;
659 :
660 0 : if( it->second.m_aGroup.isEmpty() ) // probably a new printer
661 0 : it->second.m_aGroup = OString( it->first.getStr(), it->first.getLength(), RTL_TEXTENCODING_UTF8 );
662 :
663 0 : if( files.find( it->second.m_aFile ) != files.end() )
664 : {
665 0 : Config* pConfig = files[ it->second.m_aFile ];
666 0 : pConfig->DeleteGroup( it->second.m_aGroup ); // else some old keys may remain
667 0 : pConfig->SetGroup( it->second.m_aGroup );
668 :
669 0 : OStringBuffer aValue(OUStringToOString(it->second.m_aInfo.m_aDriverName, RTL_TEXTENCODING_UTF8));
670 0 : aValue.append('/');
671 0 : aValue.append(OUStringToOString(it->first, RTL_TEXTENCODING_UTF8));
672 0 : pConfig->WriteKey("Printer", aValue.makeStringAndClear());
673 0 : pConfig->WriteKey( "DefaultPrinter", it->first == m_aDefaultPrinter ? "1" : "0" );
674 0 : pConfig->WriteKey( "Location", OUStringToOString(it->second.m_aInfo.m_aLocation, RTL_TEXTENCODING_UTF8) );
675 0 : pConfig->WriteKey( "Comment", OUStringToOString(it->second.m_aInfo.m_aComment, RTL_TEXTENCODING_UTF8) );
676 0 : pConfig->WriteKey( "Command", OUStringToOString(it->second.m_aInfo.m_aCommand, RTL_TEXTENCODING_UTF8) );
677 0 : pConfig->WriteKey( "QuickCommand", OUStringToOString(it->second.m_aInfo.m_aQuickCommand, RTL_TEXTENCODING_UTF8) );
678 0 : pConfig->WriteKey( "Features", OUStringToOString(it->second.m_aInfo.m_aFeatures, RTL_TEXTENCODING_UTF8) );
679 0 : pConfig->WriteKey("Copies", OString::number(it->second.m_aInfo.m_nCopies));
680 0 : pConfig->WriteKey( "Orientation", it->second.m_aInfo.m_eOrientation == orientation::Landscape ? "Landscape" : "Portrait" );
681 0 : pConfig->WriteKey("PSLevel", OString::number(it->second.m_aInfo.m_nPSLevel));
682 0 : pConfig->WriteKey("PDFDevice", OString::number(it->second.m_aInfo.m_nPDFDevice));
683 0 : pConfig->WriteKey("ColorDevice", OString::number(it->second.m_aInfo.m_nColorDevice));
684 0 : pConfig->WriteKey("ColorDepth", OString::number(it->second.m_aInfo.m_nColorDepth));
685 0 : aValue.append(static_cast<sal_Int32>(it->second.m_aInfo.m_nLeftMarginAdjust));
686 0 : aValue.append(',');
687 0 : aValue.append(static_cast<sal_Int32>(it->second.m_aInfo.m_nRightMarginAdjust));
688 0 : aValue.append(',');
689 0 : aValue.append(static_cast<sal_Int32>(it->second.m_aInfo.m_nTopMarginAdjust));
690 0 : aValue.append(',');
691 0 : aValue.append(static_cast<sal_Int32>(it->second.m_aInfo.m_nBottomMarginAdjust));
692 0 : pConfig->WriteKey("MarginAdjust", aValue.makeStringAndClear());
693 :
694 0 : if( ! it->second.m_aInfo.m_aDriverName.startsWith( "CUPS:" ) )
695 : {
696 : // write PPDContext (not for CUPS)
697 0 : for( int i = 0; i < it->second.m_aInfo.m_aContext.countValuesModified(); i++ )
698 : {
699 0 : const PPDKey* pKey = it->second.m_aInfo.m_aContext.getModifiedKey( i );
700 0 : OStringBuffer aKey("PPD_");
701 0 : aKey.append(OUStringToOString(pKey->getKey(), RTL_TEXTENCODING_ISO_8859_1));
702 :
703 0 : const PPDValue* pValue = it->second.m_aInfo.m_aContext.getValue( pKey );
704 0 : if (pValue)
705 0 : aValue.append(OUStringToOString(pValue->m_aOption, RTL_TEXTENCODING_ISO_8859_1));
706 : else
707 0 : aValue.append("*nil");
708 0 : pConfig->WriteKey(aKey.makeStringAndClear(), aValue.makeStringAndClear());
709 0 : }
710 0 : }
711 : }
712 : }
713 :
714 : // get rid of Config objects. this also writes any changes
715 0 : for( file_it = files.begin(); file_it != files.end(); ++file_it )
716 0 : delete file_it->second;
717 :
718 0 : return true;
719 : }
720 :
721 0 : bool PrinterInfoManager::addPrinter( const OUString& rPrinterName, const OUString& rDriverName )
722 : {
723 0 : bool bSuccess = false;
724 :
725 0 : const PPDParser* pParser = NULL;
726 0 : if( m_aPrinters.find( rPrinterName ) == m_aPrinters.end() && ( pParser = PPDParser::getParser( rDriverName ) ) )
727 : {
728 0 : Printer aPrinter;
729 0 : aPrinter.m_bModified = true;
730 0 : aPrinter.m_aInfo = m_aGlobalDefaults;
731 0 : aPrinter.m_aInfo.m_aDriverName = rDriverName;
732 0 : aPrinter.m_aInfo.m_pParser = pParser;
733 0 : aPrinter.m_aInfo.m_aContext.setParser( pParser );
734 0 : aPrinter.m_aInfo.m_aPrinterName = rPrinterName;
735 :
736 : // merge PPD values with global defaults
737 0 : for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
738 : {
739 0 : const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
740 0 : const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
741 0 : const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL;
742 0 : if( pDefKey && pPrinterKey )
743 : // at least the options exist in both PPDs
744 : {
745 0 : if( pDefValue )
746 : {
747 0 : const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
748 0 : if( pPrinterValue )
749 : // the printer has a corresponding option for the key
750 0 : aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
751 : }
752 : else
753 0 : aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL );
754 : }
755 : }
756 :
757 0 : m_aPrinters[ rPrinterName ] = aPrinter;
758 0 : bSuccess = true;
759 : #if OSL_DEBUG_LEVEL > 1
760 : fprintf( stderr, "new printer %s, level = %d, pdfdevice = %d, colordevice = %d, depth = %d\n",
761 : OUStringToOString( rPrinterName, osl_getThreadTextEncoding() ).getStr(),
762 : m_aPrinters[rPrinterName].m_aInfo.m_nPSLevel,
763 : m_aPrinters[rPrinterName].m_aInfo.m_nPDFDevice,
764 : m_aPrinters[rPrinterName].m_aInfo.m_nColorDevice,
765 : m_aPrinters[rPrinterName].m_aInfo.m_nColorDepth );
766 : #endif
767 : // comment: logically one should writePrinterConfig() here
768 : // but immediately after addPrinter() a changePrinterInfo()
769 : // will follow which writes it again, so we can currently save some
770 : // performance here
771 : }
772 0 : return bSuccess;
773 : }
774 :
775 0 : bool PrinterInfoManager::removePrinter( const OUString& rPrinterName, bool bCheckOnly )
776 : {
777 0 : bool bSuccess = true;
778 :
779 0 : ::boost::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName );
780 0 : if( it != m_aPrinters.end() )
781 : {
782 0 : if( !it->second.m_aFile.isEmpty() )
783 : {
784 : // this printer already exists in a config file
785 :
786 : // check writeability of config file(s)
787 0 : if( ! checkWriteability( it->second.m_aFile ) )
788 0 : bSuccess = false;
789 : else
790 : {
791 0 : for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin();
792 0 : file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it )
793 : {
794 0 : if( ! checkWriteability( *file_it ) )
795 0 : bSuccess = false;
796 : }
797 : }
798 0 : if( bSuccess && ! bCheckOnly )
799 : {
800 :
801 0 : Config aConfig( it->second.m_aFile );
802 0 : aConfig.DeleteGroup( it->second.m_aGroup );
803 0 : aConfig.Flush();
804 0 : for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin();
805 0 : file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it )
806 : {
807 0 : Config aAltConfig( *file_it );
808 0 : aAltConfig.DeleteGroup( it->second.m_aGroup );
809 0 : aAltConfig.Flush();
810 0 : }
811 : }
812 : }
813 0 : if( bSuccess && ! bCheckOnly )
814 : {
815 0 : m_aPrinters.erase( it );
816 : // need this here because someone may call
817 : // checkPrintersChanged after the removal
818 : // but then other added printers were not flushed
819 : // to disk, so they are discarded
820 0 : writePrinterConfig();
821 : }
822 : }
823 0 : return bSuccess;
824 : }
825 :
826 0 : bool PrinterInfoManager::setDefaultPrinter( const OUString& rPrinterName )
827 : {
828 0 : bool bSuccess = false;
829 :
830 0 : ::boost::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName );
831 0 : if( it != m_aPrinters.end() )
832 : {
833 0 : bSuccess = true;
834 0 : it->second.m_bModified = true;
835 0 : if( ( it = m_aPrinters.find( m_aDefaultPrinter ) ) != m_aPrinters.end() )
836 0 : it->second.m_bModified = true;
837 0 : m_aDefaultPrinter = rPrinterName;
838 0 : writePrinterConfig();
839 : }
840 0 : return bSuccess;
841 : }
842 :
843 0 : void PrinterInfoManager::getSystemPrintCommands( std::list< OUString >& rCommands )
844 : {
845 0 : if( m_pQueueInfo && m_pQueueInfo->hasChanged() )
846 : {
847 0 : m_aSystemPrintCommand = m_pQueueInfo->getCommand();
848 0 : m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues );
849 0 : delete m_pQueueInfo, m_pQueueInfo = NULL;
850 : }
851 :
852 0 : std::list< SystemPrintQueue >::const_iterator it;
853 0 : rCommands.clear();
854 0 : OUString aPrinterConst( "(PRINTER)" );
855 0 : for( it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it )
856 : {
857 0 : OUString aCmd( m_aSystemPrintCommand );
858 0 : aCmd = aCmd.replaceAll( aPrinterConst, it->m_aQueue );
859 0 : rCommands.push_back( aCmd );
860 0 : }
861 0 : }
862 :
863 0 : const std::list< PrinterInfoManager::SystemPrintQueue >& PrinterInfoManager::getSystemPrintQueues()
864 : {
865 0 : if( m_pQueueInfo && m_pQueueInfo->hasChanged() )
866 : {
867 0 : m_aSystemPrintCommand = m_pQueueInfo->getCommand();
868 0 : m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues );
869 0 : delete m_pQueueInfo, m_pQueueInfo = NULL;
870 : }
871 :
872 0 : return m_aSystemPrintQueues;
873 : }
874 :
875 0 : bool PrinterInfoManager::checkFeatureToken( const OUString& rPrinterName, const char* pToken ) const
876 : {
877 0 : const PrinterInfo& rPrinterInfo( getPrinterInfo( rPrinterName ) );
878 0 : sal_Int32 nIndex = 0;
879 0 : while( nIndex != -1 )
880 : {
881 0 : OUString aOuterToken = rPrinterInfo.m_aFeatures.getToken( 0, ',', nIndex );
882 0 : sal_Int32 nInnerIndex = 0;
883 0 : OUString aInnerToken = aOuterToken.getToken( 0, '=', nInnerIndex );
884 0 : if( aInnerToken.equalsIgnoreAsciiCaseAscii( pToken ) )
885 0 : return true;
886 0 : }
887 0 : return false;
888 : }
889 :
890 0 : FILE* PrinterInfoManager::startSpool( const OUString& rPrintername, bool bQuickCommand )
891 : {
892 0 : const PrinterInfo& rPrinterInfo = getPrinterInfo (rPrintername);
893 0 : const OUString& rCommand = (bQuickCommand && !rPrinterInfo.m_aQuickCommand.isEmpty() ) ?
894 0 : rPrinterInfo.m_aQuickCommand : rPrinterInfo.m_aCommand;
895 0 : OString aShellCommand = OUStringToOString (rCommand, RTL_TEXTENCODING_ISO_8859_1);
896 0 : aShellCommand += OString( " 2>/dev/null" );
897 :
898 0 : return popen (aShellCommand.getStr(), "w");
899 : }
900 :
901 0 : bool PrinterInfoManager::endSpool( const OUString& /*rPrintername*/, const OUString& /*rJobTitle*/, FILE* pFile, const JobData& /*rDocumentJobData*/, bool /*bBanner*/, const OUString& /*rFaxNumber*/ )
902 : {
903 0 : return (0 == pclose( pFile ));
904 : }
905 :
906 0 : void PrinterInfoManager::setupJobContextData( JobData& rData )
907 : {
908 : boost::unordered_map< OUString, Printer, OUStringHash >::iterator it =
909 0 : m_aPrinters.find( rData.m_aPrinterName );
910 0 : if( it != m_aPrinters.end() )
911 : {
912 0 : rData.m_pParser = it->second.m_aInfo.m_pParser;
913 0 : rData.m_aContext = it->second.m_aInfo.m_aContext;
914 : }
915 0 : }
916 :
917 232 : void PrinterInfoManager::setDefaultPaper( PPDContext& rContext ) const
918 : {
919 232 : if( ! rContext.getParser() )
920 0 : return;
921 :
922 232 : const PPDKey* pPageSizeKey = rContext.getParser()->getKey( OUString( "PageSize" ) );
923 232 : if( ! pPageSizeKey )
924 0 : return;
925 :
926 232 : int nModified = rContext.countValuesModified();
927 348 : while( nModified-- &&
928 116 : rContext.getModifiedKey( nModified ) != pPageSizeKey )
929 : ;
930 :
931 232 : if( nModified >= 0 ) // paper was set already, do not modify
932 : {
933 : #if OSL_DEBUG_LEVEL > 1
934 : fprintf( stderr, "not setting default paper, already set %s\n",
935 : OUStringToOString( rContext.getValue( pPageSizeKey )->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
936 : #endif
937 116 : return;
938 : }
939 :
940 : // paper not set, fill in default value
941 116 : const PPDValue* pPaperVal = NULL;
942 116 : int nValues = pPageSizeKey->countValues();
943 1018 : for( int i = 0; i < nValues && ! pPaperVal; i++ )
944 : {
945 902 : const PPDValue* pVal = pPageSizeKey->getValue( i );
946 902 : if( pVal->m_aOption.equalsIgnoreAsciiCase( m_aSystemDefaultPaper ) )
947 116 : pPaperVal = pVal;
948 : }
949 116 : if( pPaperVal )
950 : {
951 : #if OSL_DEBUG_LEVEL > 1
952 : fprintf( stderr, "setting default paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
953 : #endif
954 116 : rContext.setValue( pPageSizeKey, pPaperVal );
955 : #if OSL_DEBUG_LEVEL > 1
956 : pPaperVal = rContext.getValue( pPageSizeKey );
957 : fprintf( stderr, "-> got paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
958 : #endif
959 : }
960 : }
961 :
962 0 : SystemQueueInfo::SystemQueueInfo() :
963 0 : m_bChanged( false )
964 : {
965 0 : create();
966 0 : }
967 :
968 0 : SystemQueueInfo::~SystemQueueInfo()
969 : {
970 0 : static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
971 0 : if( ! pNoSyncDetection || !*pNoSyncDetection )
972 0 : join();
973 : else
974 0 : terminate();
975 0 : }
976 :
977 0 : bool SystemQueueInfo::hasChanged() const
978 : {
979 0 : MutexGuard aGuard( m_aMutex );
980 0 : bool bChanged = m_bChanged;
981 0 : return bChanged;
982 : }
983 :
984 0 : void SystemQueueInfo::getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues )
985 : {
986 0 : MutexGuard aGuard( m_aMutex );
987 0 : rQueues = m_aQueues;
988 0 : m_bChanged = false;
989 0 : }
990 :
991 0 : OUString SystemQueueInfo::getCommand() const
992 : {
993 0 : MutexGuard aGuard( m_aMutex );
994 0 : OUString aRet = m_aCommand;
995 0 : return aRet;
996 : }
997 :
998 : struct SystemCommandParameters;
999 : typedef void(* tokenHandler)(const std::list< OString >&,
1000 : std::list< PrinterInfoManager::SystemPrintQueue >&,
1001 : const SystemCommandParameters*);
1002 :
1003 : struct SystemCommandParameters
1004 : {
1005 : const char* pQueueCommand;
1006 : const char* pPrintCommand;
1007 : const char* pForeToken;
1008 : const char* pAftToken;
1009 : unsigned int nForeTokenCount;
1010 : tokenHandler pHandler;
1011 : };
1012 :
1013 : #if ! (defined(LINUX) || defined(NETBSD) || defined(FREEBSD) || defined(OPENBSD))
1014 : static void lpgetSysQueueTokenHandler(
1015 : const std::list< OString >& i_rLines,
1016 : std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
1017 : const SystemCommandParameters* )
1018 : {
1019 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1020 : boost::unordered_set< OUString, OUStringHash > aUniqueSet;
1021 : boost::unordered_set< OUString, OUStringHash > aOnlySet;
1022 : aUniqueSet.insert( OUString( "_all" ) );
1023 : aUniqueSet.insert( OUString( "_default" ) );
1024 :
1025 : // the eventual "all" attribute of the "_all" queue tells us, which
1026 : // printers are to be used for this user at all
1027 :
1028 : // find _all: line
1029 : OString aAllLine( "_all:" );
1030 : OString aAllAttr( "all=" );
1031 : for( std::list< OString >::const_iterator it = i_rLines.begin();
1032 : it != i_rLines.end(); ++it )
1033 : {
1034 : if( it->indexOf( aAllLine, 0 ) == 0 )
1035 : {
1036 : // now find the "all" attribute
1037 : ++it;
1038 : while( it != i_rLines.end() )
1039 : {
1040 : OString aClean( WhitespaceToSpace( *it ) );
1041 : if( aClean.startsWith( aAllAttr ) )
1042 : {
1043 : // insert the comma separated entries into the set of printers to use
1044 : sal_Int32 nPos = aAllAttr.getLength();
1045 : while( nPos != -1 )
1046 : {
1047 : OString aTok( aClean.getToken( 0, ',', nPos ) );
1048 : if( !aTok.isEmpty() )
1049 : aOnlySet.insert( OStringToOUString( aTok, aEncoding ) );
1050 : }
1051 : break;
1052 : }
1053 : }
1054 : break;
1055 : }
1056 : }
1057 :
1058 : bool bInsertAttribute = false;
1059 : OString aDescrStr( "description=" );
1060 : OString aLocStr( "location=" );
1061 : for( std::list< OString >::const_iterator it = i_rLines.begin();
1062 : it != i_rLines.end(); ++it )
1063 : {
1064 : sal_Int32 nPos = 0;
1065 : // find the begin of a new printer section
1066 : nPos = it->indexOf( ':', 0 );
1067 : if( nPos != -1 )
1068 : {
1069 : OUString aSysQueue( OStringToOUString( it->copy( 0, nPos ), aEncoding ) );
1070 : // do not insert duplicates (e.g. lpstat tends to produce such lines)
1071 : // in case there was a "_all" section, insert only those printer explicitly
1072 : // set in the "all" attribute
1073 : if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() &&
1074 : ( aOnlySet.empty() || aOnlySet.find( aSysQueue ) != aOnlySet.end() )
1075 : )
1076 : {
1077 : o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
1078 : o_rQueues.back().m_aQueue = aSysQueue;
1079 : o_rQueues.back().m_aLocation = aSysQueue;
1080 : aUniqueSet.insert( aSysQueue );
1081 : bInsertAttribute = true;
1082 : }
1083 : else
1084 : bInsertAttribute = false;
1085 : continue;
1086 : }
1087 : if( bInsertAttribute && ! o_rQueues.empty() )
1088 : {
1089 : // look for "description" attribute, insert as comment
1090 : nPos = it->indexOf( aDescrStr, 0 );
1091 : if( nPos != -1 )
1092 : {
1093 : OString aComment( WhitespaceToSpace( it->copy(nPos+12) ) );
1094 : if( !aComment.isEmpty() )
1095 : o_rQueues.back().m_aComment = OStringToOUString(aComment, aEncoding);
1096 : continue;
1097 : }
1098 : // look for "location" attribute, inser as location
1099 : nPos = it->indexOf( aLocStr, 0 );
1100 : if( nPos != -1 )
1101 : {
1102 : OString aLoc( WhitespaceToSpace( it->copy(nPos+9) ) );
1103 : if( !aLoc.isEmpty() )
1104 : o_rQueues.back().m_aLocation = OStringToOUString(aLoc, aEncoding);
1105 : continue;
1106 : }
1107 : }
1108 : }
1109 : }
1110 : #endif
1111 0 : static void standardSysQueueTokenHandler(
1112 : const std::list< OString >& i_rLines,
1113 : std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
1114 : const SystemCommandParameters* i_pParms)
1115 : {
1116 0 : rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1117 0 : boost::unordered_set< OUString, OUStringHash > aUniqueSet;
1118 0 : OString aForeToken( i_pParms->pForeToken );
1119 0 : OString aAftToken( i_pParms->pAftToken );
1120 : /* Normal Unix print queue discovery, also used for Darwin 5 LPR printing
1121 : */
1122 0 : for( std::list< OString >::const_iterator it = i_rLines.begin();
1123 0 : it != i_rLines.end(); ++it )
1124 : {
1125 0 : sal_Int32 nPos = 0;
1126 :
1127 : // search for a line describing a printer:
1128 : // find if there are enough tokens before the name
1129 0 : for( unsigned int i = 0; i < i_pParms->nForeTokenCount && nPos != -1; i++ )
1130 : {
1131 0 : nPos = it->indexOf( aForeToken, nPos );
1132 0 : if( nPos != -1 && it->getLength() >= nPos+aForeToken.getLength() )
1133 0 : nPos += aForeToken.getLength();
1134 : }
1135 0 : if( nPos != -1 )
1136 : {
1137 : // find if there is the token after the queue
1138 0 : sal_Int32 nAftPos = it->indexOf( aAftToken, nPos );
1139 0 : if( nAftPos != -1 )
1140 : {
1141 : // get the queue name between fore and aft tokens
1142 0 : OUString aSysQueue( OStringToOUString( it->copy( nPos, nAftPos - nPos ), aEncoding ) );
1143 : // do not insert duplicates (e.g. lpstat tends to produce such lines)
1144 0 : if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() )
1145 : {
1146 0 : o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
1147 0 : o_rQueues.back().m_aQueue = aSysQueue;
1148 0 : o_rQueues.back().m_aLocation = aSysQueue;
1149 0 : aUniqueSet.insert( aSysQueue );
1150 0 : }
1151 : }
1152 : }
1153 0 : }
1154 0 : }
1155 :
1156 : static const struct SystemCommandParameters aParms[] =
1157 : {
1158 : #if defined(LINUX) || defined(NETBSD) || defined(FREEBSD) || defined(OPENBSD)
1159 : { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
1160 : { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
1161 : { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler }
1162 : #else
1163 : { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpget list", "lp -d \"(PRINTER)\"", "", ":", 0, lpgetSysQueueTokenHandler },
1164 : { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler },
1165 : { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
1166 : { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler }
1167 : #endif
1168 : };
1169 :
1170 0 : void SystemQueueInfo::run()
1171 : {
1172 0 : osl_setThreadName("LPR psp::SystemQueueInfo");
1173 :
1174 : char pBuffer[1024];
1175 : FILE *pPipe;
1176 0 : std::list< OString > aLines;
1177 :
1178 : /* Discover which command we can use to get a list of all printer queues */
1179 0 : for( unsigned int i = 0; i < SAL_N_ELEMENTS(aParms); i++ )
1180 : {
1181 0 : aLines.clear();
1182 0 : OStringBuffer aCmdLine( 128 );
1183 0 : aCmdLine.append( aParms[i].pQueueCommand );
1184 : #if OSL_DEBUG_LEVEL > 1
1185 : fprintf( stderr, "trying print queue command \"%s\" ... ", aParms[i].pQueueCommand );
1186 : #endif
1187 0 : aCmdLine.append( " 2>/dev/null" );
1188 0 : if( (pPipe = popen( aCmdLine.getStr(), "r" )) )
1189 : {
1190 0 : while( fgets( pBuffer, 1024, pPipe ) )
1191 0 : aLines.push_back( OString( pBuffer ) );
1192 0 : if( ! pclose( pPipe ) )
1193 : {
1194 0 : std::list< PrinterInfoManager::SystemPrintQueue > aSysPrintQueues;
1195 0 : aParms[i].pHandler( aLines, aSysPrintQueues, &(aParms[i]) );
1196 0 : MutexGuard aGuard( m_aMutex );
1197 0 : m_bChanged = true;
1198 0 : m_aQueues = aSysPrintQueues;
1199 0 : m_aCommand = OUString::createFromAscii( aParms[i].pPrintCommand );
1200 : #if OSL_DEBUG_LEVEL > 1
1201 : fprintf( stderr, "success\n" );
1202 : #endif
1203 0 : break;
1204 : }
1205 : }
1206 : #if OSL_DEBUG_LEVEL > 1
1207 : fprintf( stderr, "failed\n" );
1208 : #endif
1209 0 : }
1210 1233 : }
1211 :
1212 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|