merge the formfield patch from ooo-build
[ooovba.git] / vcl / unx / source / printer / printerinfomanager.cxx
blob537d96b85bd85a3b78012b93c3a77a30240a6683
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: printerinfomanager.cxx,v $
10 * $Revision: 1.50 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
34 #include <unistd.h>
35 #include <sys/wait.h>
36 #include <signal.h>
38 #include "cupsmgr.hxx"
39 #include "vcl/fontmanager.hxx"
40 #include "vcl/strhelper.hxx"
42 #include "tools/urlobj.hxx"
43 #include "tools/stream.hxx"
44 #include "tools/debug.hxx"
45 #include "tools/config.hxx"
47 #include "i18npool/paper.hxx"
49 #include "rtl/strbuf.hxx"
51 #include "osl/thread.hxx"
52 #include "osl/mutex.hxx"
53 #include "osl/process.h"
55 // filename of configuration files
56 #define PRINT_FILENAME "psprint.conf"
57 // the group of the global defaults
58 #define GLOBAL_DEFAULTS_GROUP "__Global_Printer_Defaults__"
60 #include <hash_set>
62 using namespace psp;
63 using namespace rtl;
64 using namespace osl;
66 namespace psp
68 class SystemQueueInfo : public Thread
70 mutable Mutex m_aMutex;
71 bool m_bChanged;
72 std::list< PrinterInfoManager::SystemPrintQueue >
73 m_aQueues;
74 OUString m_aCommand;
76 virtual void run();
78 public:
79 SystemQueueInfo();
80 ~SystemQueueInfo();
82 bool hasChanged() const;
83 OUString getCommand() const;
85 // sets changed status to false; therefore not const
86 void getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues );
88 } // namespace
91 * class PrinterInfoManager
94 // -----------------------------------------------------------------
96 PrinterInfoManager& PrinterInfoManager::get()
98 static PrinterInfoManager* pManager = NULL;
100 if( ! pManager )
102 pManager = CUPSManager::tryLoadCUPS();
103 if( ! pManager )
104 pManager = new PrinterInfoManager();
106 if( pManager )
107 pManager->initialize();
108 #if OSL_DEBUG_LEVEL > 1
109 fprintf( stderr, "PrinterInfoManager::get create Manager of type %d\n", pManager->getType() );
110 #endif
113 return *pManager;
116 // -----------------------------------------------------------------
118 PrinterInfoManager::PrinterInfoManager( Type eType ) :
119 m_pQueueInfo( NULL ),
120 m_eType( eType ),
121 m_bUseIncludeFeature( false ),
122 m_aSystemDefaultPaper( RTL_CONSTASCII_USTRINGPARAM( "A4" ) ),
123 m_bDisableCUPS( false )
125 if( eType == Default )
126 m_pQueueInfo = new SystemQueueInfo();
127 initSystemDefaultPaper();
130 // -----------------------------------------------------------------
132 PrinterInfoManager::~PrinterInfoManager()
134 delete m_pQueueInfo;
137 // -----------------------------------------------------------------
139 bool PrinterInfoManager::isCUPSDisabled() const
141 return m_bDisableCUPS;
144 // -----------------------------------------------------------------
146 void PrinterInfoManager::setCUPSDisabled( bool bDisable )
148 m_bDisableCUPS = bDisable;
149 writePrinterConfig();
150 // actually we know the printers changed
151 // however this triggers reinitialization the right way
152 checkPrintersChanged( true );
155 // -----------------------------------------------------------------
157 void PrinterInfoManager::initSystemDefaultPaper()
159 m_aSystemDefaultPaper = rtl::OStringToOUString(
160 PaperInfo::toPSName(PaperInfo::getSystemDefaultPaper().getPaper()),
161 RTL_TEXTENCODING_UTF8);
164 // -----------------------------------------------------------------
166 bool PrinterInfoManager::checkPrintersChanged( bool bWait )
168 // check if files were created, deleted or modified since initialize()
169 ::std::list< WatchFile >::const_iterator it;
170 bool bChanged = false;
171 for( it = m_aWatchFiles.begin(); it != m_aWatchFiles.end() && ! bChanged; ++it )
173 DirectoryItem aItem;
174 if( DirectoryItem::get( it->m_aFilePath, aItem ) )
176 if( it->m_aModified.Seconds != 0 )
177 bChanged = true; // file probably has vanished
179 else
181 FileStatus aStatus( FileStatusMask_ModifyTime );
182 if( aItem.getFileStatus( aStatus ) )
183 bChanged = true; // unlikely but not impossible
184 else
186 TimeValue aModified = aStatus.getModifyTime();
187 if( aModified.Seconds != it->m_aModified.Seconds )
188 bChanged = true;
193 if( bWait && m_pQueueInfo )
195 #if OSL_DEBUG_LEVEL > 1
196 fprintf( stderr, "syncing printer discovery thread\n" );
197 #endif
198 m_pQueueInfo->join();
199 #if OSL_DEBUG_LEVEL > 1
200 fprintf( stderr, "done: syncing printer discovery thread\n" );
201 #endif
204 if( ! bChanged && m_pQueueInfo )
205 bChanged = m_pQueueInfo->hasChanged();
206 if( bChanged )
208 initialize();
211 return bChanged;
214 // -----------------------------------------------------------------
216 void PrinterInfoManager::initialize()
218 m_bUseIncludeFeature = false;
219 rtl_TextEncoding aEncoding = gsl_getSystemTextEncoding();
220 m_aPrinters.clear();
221 m_aWatchFiles.clear();
222 OUString aDefaultPrinter;
224 // first initialize the global defaults
225 // have to iterate over all possible files
226 // there should be only one global setup section in all
227 // available config files
228 m_aGlobalDefaults = PrinterInfo();
230 // need a parser for the PPDContext. generic printer should do.
231 m_aGlobalDefaults.m_pParser = PPDParser::getParser( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) );
232 m_aGlobalDefaults.m_aContext.setParser( m_aGlobalDefaults.m_pParser );
233 m_aGlobalDefaults.m_bPerformFontSubstitution = true;
234 m_bDisableCUPS = false;
236 if( ! m_aGlobalDefaults.m_pParser )
238 #if OSL_DEBUG_LEVEL > 1
239 fprintf( stderr, "Error: no default PPD file SGENPRT available, shutting down psprint...\n" );
240 #endif
241 return;
244 std::list< OUString > aDirList;
245 psp::getPrinterPathList( aDirList, NULL );
246 std::list< OUString >::const_iterator print_dir_it;
247 for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it )
249 INetURLObject aFile( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
250 aFile.Append( String( RTL_CONSTASCII_USTRINGPARAM( PRINT_FILENAME ) ) );
251 Config aConfig( aFile.PathToFileName() );
252 if( aConfig.HasGroup( GLOBAL_DEFAULTS_GROUP ) )
254 #if OSL_DEBUG_LEVEL > 1
255 fprintf( stderr, "found global defaults in %s\n", OUStringToOString( aFile.PathToFileName(), RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
256 #endif
257 aConfig.SetGroup( GLOBAL_DEFAULTS_GROUP );
259 ByteString aValue( aConfig.ReadKey( "Copies" ) );
260 if( aValue.Len() )
261 m_aGlobalDefaults.m_nCopies = aValue.ToInt32();
263 aValue = aConfig.ReadKey( "Orientation" );
264 if( aValue.Len() )
265 m_aGlobalDefaults.m_eOrientation = aValue.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape : orientation::Portrait;
267 aValue = aConfig.ReadKey( "MarginAdjust" );
268 if( aValue.Len() )
270 m_aGlobalDefaults.m_nLeftMarginAdjust = aValue.GetToken( 0, ',' ).ToInt32();
271 m_aGlobalDefaults.m_nRightMarginAdjust = aValue.GetToken( 1, ',' ).ToInt32();
272 m_aGlobalDefaults.m_nTopMarginAdjust = aValue.GetToken( 2, ',' ).ToInt32();
273 m_aGlobalDefaults.m_nBottomMarginAdjust = aValue.GetToken( 3, ',' ).ToInt32();
276 aValue = aConfig.ReadKey( "ColorDepth", "24" );
277 if( aValue.Len() )
278 m_aGlobalDefaults.m_nColorDepth = aValue.ToInt32();
280 aValue = aConfig.ReadKey( "ColorDevice" );
281 if( aValue.Len() )
282 m_aGlobalDefaults.m_nColorDevice = aValue.ToInt32();
284 aValue = aConfig.ReadKey( "PSLevel" );
285 if( aValue.Len() )
286 m_aGlobalDefaults.m_nPSLevel = aValue.ToInt32();
288 aValue = aConfig.ReadKey( "PerformFontSubstitution" );
289 if( aValue.Len() )
291 if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) )
292 m_aGlobalDefaults.m_bPerformFontSubstitution = true;
293 else
294 m_aGlobalDefaults.m_bPerformFontSubstitution = false;
297 aValue = aConfig.ReadKey( "DisableCUPS" );
298 if( aValue.Len() )
300 if( aValue.Equals( "1" ) || aValue.EqualsIgnoreCaseAscii( "true" ) )
301 m_bDisableCUPS = true;
302 else
303 m_bDisableCUPS = false;
306 // get the PPDContext of global JobData
307 for( int nKey = 0; nKey < aConfig.GetKeyCount(); nKey++ )
309 ByteString aKey( aConfig.GetKeyName( nKey ) );
310 if( aKey.CompareTo( "PPD_", 4 ) == COMPARE_EQUAL )
312 aValue = aConfig.ReadKey( aKey );
313 const PPDKey* pKey = m_aGlobalDefaults.m_pParser->getKey( String( aKey.Copy( 4 ), RTL_TEXTENCODING_ISO_8859_1 ) );
314 if( pKey )
316 m_aGlobalDefaults.m_aContext.
317 setValue( pKey,
318 aValue.Equals( "*nil" ) ? NULL : pKey->getValue( String( aValue, RTL_TEXTENCODING_ISO_8859_1 ) ),
319 TRUE );
322 else if( aKey.Len() > 10 && aKey.CompareTo("SubstFont_", 10 ) == COMPARE_EQUAL )
324 aValue = aConfig.ReadKey( aKey );
325 m_aGlobalDefaults.m_aFontSubstitutes[ OStringToOUString( aKey.Copy( 10 ), RTL_TEXTENCODING_ISO_8859_1 ) ] = OStringToOUString( aValue, RTL_TEXTENCODING_ISO_8859_1 );
328 #if OSL_DEBUG_LEVEL > 1
329 fprintf( stderr, "global settings: fontsubst = %s, %d substitutes\n", m_aGlobalDefaults.m_bPerformFontSubstitution ? "true" : "false", m_aGlobalDefaults.m_aFontSubstitutes.size() );
330 #endif
333 setDefaultPaper( m_aGlobalDefaults.m_aContext );
334 fillFontSubstitutions( m_aGlobalDefaults );
336 // now collect all available printers
337 for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it )
339 INetURLObject aDir( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL );
340 INetURLObject aFile( aDir );
341 aFile.Append( String( RTL_CONSTASCII_USTRINGPARAM( PRINT_FILENAME ) ) );
343 // check directory validity
344 OUString aUniPath;
345 FileBase::getFileURLFromSystemPath( aDir.PathToFileName(), aUniPath );
346 Directory aDirectory( aUniPath );
347 if( aDirectory.open() )
348 continue;
349 aDirectory.close();
352 FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aUniPath );
353 FileStatus aStatus( FileStatusMask_ModifyTime );
354 DirectoryItem aItem;
356 // setup WatchFile list
357 WatchFile aWatchFile;
358 aWatchFile.m_aFilePath = aUniPath;
359 if( ! DirectoryItem::get( aUniPath, aItem ) &&
360 ! aItem.getFileStatus( aStatus ) )
362 aWatchFile.m_aModified = aStatus.getModifyTime();
364 else
366 aWatchFile.m_aModified.Seconds = 0;
367 aWatchFile.m_aModified.Nanosec = 0;
369 m_aWatchFiles.push_back( aWatchFile );
371 Config aConfig( aFile.PathToFileName() );
372 for( int nGroup = 0; nGroup < aConfig.GetGroupCount(); nGroup++ )
374 aConfig.SetGroup( aConfig.GetGroupName( nGroup ) );
375 ByteString aValue = aConfig.ReadKey( "Printer" );
376 if( aValue.Len() )
378 OUString aPrinterName;
380 int nNamePos = aValue.Search( '/' );
381 // check for valid value of "Printer"
382 if( nNamePos == STRING_NOTFOUND )
383 continue;
385 Printer aPrinter;
386 // initialize to global defaults
387 aPrinter.m_aInfo = m_aGlobalDefaults;
388 // global settings do not default the printer substitution
389 // list ! the substitution list in there is only used for
390 // newly created printers
391 aPrinter.m_aInfo.m_aFontSubstitutes.clear();
392 aPrinter.m_aInfo.m_aFontSubstitutions.clear();
394 aPrinterName = String( aValue.Copy( nNamePos+1 ), RTL_TEXTENCODING_UTF8 );
395 aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
396 aPrinter.m_aInfo.m_aDriverName = String( aValue.Copy( 0, nNamePos ), RTL_TEXTENCODING_UTF8 );
398 // set parser, merge settings
399 // don't do this for CUPS printers as this is done
400 // by the CUPS system itself
401 if( aPrinter.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) != 0 )
403 aPrinter.m_aInfo.m_pParser = PPDParser::getParser( aPrinter.m_aInfo.m_aDriverName );
404 aPrinter.m_aInfo.m_aContext.setParser( aPrinter.m_aInfo.m_pParser );
405 // note: setParser also purges the context
407 // ignore this printer if its driver is not found
408 if( ! aPrinter.m_aInfo.m_pParser )
409 continue;
411 // merge the ppd context keys if the printer has the same keys and values
412 // this is a bit tricky, since it involves mixing two PPDs
413 // without constraints which might end up badly
414 // this feature should be use with caution
415 // it is mainly to select default paper sizes for new printers
416 for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
418 const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
419 const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
420 const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL;
421 if( pDefKey && pPrinterKey )
422 // at least the options exist in both PPDs
424 if( pDefValue )
426 const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
427 if( pPrinterValue )
428 // the printer has a corresponding option for the key
429 aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
431 else
432 aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL );
436 aValue = aConfig.ReadKey( "Command" );
437 // no printer without a command
438 if( ! aValue.Len() )
440 /* TODO:
441 * porters: please append your platform to the Solaris
442 * case if your platform has SystemV printing per default.
444 #if defined SOLARIS || defined(IRIX)
445 aValue = "lp";
446 #else
447 aValue = "lpr";
448 #endif
450 aPrinter.m_aInfo.m_aCommand = String( aValue, RTL_TEXTENCODING_UTF8 );
453 aValue = aConfig.ReadKey( "QuickCommand" );
454 aPrinter.m_aInfo.m_aQuickCommand = String( aValue, RTL_TEXTENCODING_UTF8 );
456 aValue = aConfig.ReadKey( "Features" );
457 aPrinter.m_aInfo.m_aFeatures = String( aValue, RTL_TEXTENCODING_UTF8 );
459 // override the settings in m_aGlobalDefaults if keys exist
460 aValue = aConfig.ReadKey( "DefaultPrinter" );
461 if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) )
462 aDefaultPrinter = aPrinterName;
464 aValue = aConfig.ReadKey( "Location" );
465 aPrinter.m_aInfo.m_aLocation = String( aValue, RTL_TEXTENCODING_UTF8 );
467 aValue = aConfig.ReadKey( "Comment" );
468 aPrinter.m_aInfo.m_aComment = String( aValue, RTL_TEXTENCODING_UTF8 );
470 aValue = aConfig.ReadKey( "Copies" );
471 if( aValue.Len() )
472 aPrinter.m_aInfo.m_nCopies = aValue.ToInt32();
474 aValue = aConfig.ReadKey( "Orientation" );
475 if( aValue.Len() )
476 aPrinter.m_aInfo.m_eOrientation = aValue.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape : orientation::Portrait;
478 aValue = aConfig.ReadKey( "MarginAdjust" );
479 if( aValue.Len() )
481 aPrinter.m_aInfo.m_nLeftMarginAdjust = aValue.GetToken( 0, ',' ).ToInt32();
482 aPrinter.m_aInfo.m_nRightMarginAdjust = aValue.GetToken( 1, ',' ).ToInt32();
483 aPrinter.m_aInfo.m_nTopMarginAdjust = aValue.GetToken( 2, ',' ).ToInt32();
484 aPrinter.m_aInfo.m_nBottomMarginAdjust = aValue.GetToken( 3, ',' ).ToInt32();
487 aValue = aConfig.ReadKey( "ColorDepth" );
488 if( aValue.Len() )
489 aPrinter.m_aInfo.m_nColorDepth = aValue.ToInt32();
491 aValue = aConfig.ReadKey( "ColorDevice" );
492 if( aValue.Len() )
493 aPrinter.m_aInfo.m_nColorDevice = aValue.ToInt32();
495 aValue = aConfig.ReadKey( "PSLevel" );
496 if( aValue.Len() )
497 aPrinter.m_aInfo.m_nPSLevel = aValue.ToInt32();
499 aValue = aConfig.ReadKey( "PerformFontSubstitution" );
500 if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) )
501 aPrinter.m_aInfo.m_bPerformFontSubstitution = true;
502 else
503 aPrinter.m_aInfo.m_bPerformFontSubstitution = false;
505 // now iterate over all keys to extract multi key information:
506 // 1. PPDContext information
507 // 2. Font substitution table
508 for( int nKey = 0; nKey < aConfig.GetKeyCount(); nKey++ )
510 ByteString aKey( aConfig.GetKeyName( nKey ) );
511 if( aKey.CompareTo( "PPD_", 4 ) == COMPARE_EQUAL && aPrinter.m_aInfo.m_pParser )
513 aValue = aConfig.ReadKey( aKey );
514 const PPDKey* pKey = aPrinter.m_aInfo.m_pParser->getKey( String( aKey.Copy( 4 ), RTL_TEXTENCODING_ISO_8859_1 ) );
515 if( pKey )
517 aPrinter.m_aInfo.m_aContext.
518 setValue( pKey,
519 aValue.Equals( "*nil" ) ? NULL : pKey->getValue( String( aValue, RTL_TEXTENCODING_ISO_8859_1 ) ),
520 TRUE );
523 else if( aKey.Len() > 10 && aKey.CompareTo("SubstFont_", 10 ) == COMPARE_EQUAL )
525 aValue = aConfig.ReadKey( aKey );
526 aPrinter.m_aInfo.m_aFontSubstitutes[ OStringToOUString( aKey.Copy( 10 ), RTL_TEXTENCODING_ISO_8859_1 ) ] = OStringToOUString( aValue, RTL_TEXTENCODING_ISO_8859_1 );
530 setDefaultPaper( aPrinter.m_aInfo.m_aContext );
531 fillFontSubstitutions( aPrinter.m_aInfo );
533 // finally insert printer
534 FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aPrinter.m_aFile );
535 aPrinter.m_bModified = false;
536 aPrinter.m_aGroup = aConfig.GetGroupName( nGroup );
537 std::hash_map< OUString, Printer, OUStringHash >::const_iterator find_it =
538 m_aPrinters.find( aPrinterName );
539 if( find_it != m_aPrinters.end() )
541 aPrinter.m_aAlternateFiles = find_it->second.m_aAlternateFiles;
542 aPrinter.m_aAlternateFiles.push_front( find_it->second.m_aFile );
544 m_aPrinters[ aPrinterName ] = aPrinter;
549 // set default printer
550 if( m_aPrinters.size() )
552 if( m_aPrinters.find( aDefaultPrinter ) == m_aPrinters.end() )
553 aDefaultPrinter = m_aPrinters.begin()->first;
555 else
556 aDefaultPrinter = OUString();
557 m_aDefaultPrinter = aDefaultPrinter;
559 if( m_eType != Default )
560 return;
562 // add a default printer for every available print queue
563 // merge paper and font substitution from default printer,
564 // all else from global defaults
565 PrinterInfo aMergeInfo( m_aGlobalDefaults );
566 aMergeInfo.m_aDriverName = String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) );
567 aMergeInfo.m_aFeatures = String( RTL_CONSTASCII_USTRINGPARAM( "autoqueue" ) );
569 if( m_aDefaultPrinter.getLength() )
571 PrinterInfo aDefaultInfo( getPrinterInfo( m_aDefaultPrinter ) );
572 aMergeInfo.m_bPerformFontSubstitution = aDefaultInfo.m_bPerformFontSubstitution;
573 fillFontSubstitutions( aMergeInfo );
575 const PPDKey* pDefKey = aDefaultInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
576 const PPDKey* pMergeKey = aMergeInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
577 const PPDValue* pDefValue = aDefaultInfo.m_aContext.getValue( pDefKey );
578 const PPDValue* pMergeValue = pMergeKey ? pMergeKey->getValue( pDefValue->m_aOption ) : NULL;
579 if( pMergeKey && pMergeValue )
580 aMergeInfo.m_aContext.setValue( pMergeKey, pMergeValue );
583 getSystemPrintQueues();
584 for( ::std::list< SystemPrintQueue >::iterator it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it )
586 String aPrinterName( RTL_CONSTASCII_USTRINGPARAM( "<" ) );
587 aPrinterName += String( it->m_aQueue );
588 aPrinterName.Append( '>' );
590 if( m_aPrinters.find( aPrinterName ) != m_aPrinters.end() )
591 // probably user made this one permanent in padmin
592 continue;
594 String aCmd( m_aSystemPrintCommand );
595 aCmd.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PRINTER)" ) ), it->m_aQueue );
597 Printer aPrinter;
599 // initialize to merged defaults
600 aPrinter.m_aInfo = aMergeInfo;
601 aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
602 aPrinter.m_aInfo.m_aCommand = aCmd;
603 aPrinter.m_aInfo.m_aComment = it->m_aComment;
604 aPrinter.m_aInfo.m_aLocation = it->m_aLocation;
605 aPrinter.m_bModified = false;
606 aPrinter.m_aGroup = ByteString( aPrinterName, aEncoding ); //provide group name in case user makes this one permanent in padmin
608 m_aPrinters[ aPrinterName ] = aPrinter;
612 // -----------------------------------------------------------------
614 void PrinterInfoManager::listPrinters( ::std::list< OUString >& rList ) const
616 ::std::hash_map< OUString, Printer, OUStringHash >::const_iterator it;
617 rList.clear();
618 for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it )
619 rList.push_back( it->first );
622 // -----------------------------------------------------------------
624 const PrinterInfo& PrinterInfoManager::getPrinterInfo( const OUString& rPrinter ) const
626 static PrinterInfo aEmptyInfo;
627 ::std::hash_map< OUString, Printer, OUStringHash >::const_iterator it = m_aPrinters.find( rPrinter );
629 DBG_ASSERT( it != m_aPrinters.end(), "Do not ask for info about nonexistant printers" );
631 return it != m_aPrinters.end() ? it->second.m_aInfo : aEmptyInfo;
634 // -----------------------------------------------------------------
636 void PrinterInfoManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo )
638 ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinter );
640 DBG_ASSERT( it != m_aPrinters.end(), "Do not change nonexistant printers" );
642 if( it != m_aPrinters.end() )
644 it->second.m_aInfo = rNewInfo;
645 // recalculate font substitutions
646 fillFontSubstitutions( it->second.m_aInfo );
647 it->second.m_bModified = true;
648 writePrinterConfig();
652 // -----------------------------------------------------------------
654 // need to check writeability / creatability of config files
655 static bool checkWriteability( const OUString& rUniPath )
657 bool bRet = false;
658 OUString aSysPath;
659 FileBase::getSystemPathFromFileURL( rUniPath, aSysPath );
660 SvFileStream aStream( aSysPath, STREAM_READ | STREAM_WRITE );
661 if( aStream.IsOpen() && aStream.IsWritable() )
662 bRet = true;
663 return bRet;
666 bool PrinterInfoManager::writePrinterConfig()
668 // find at least one writeable config
669 ::std::hash_map< OUString, Config*, OUStringHash > files;
670 ::std::hash_map< OUString, int, OUStringHash > rofiles;
671 ::std::hash_map< OUString, Config*, OUStringHash >::iterator file_it;
673 for( ::std::list< WatchFile >::const_iterator wit = m_aWatchFiles.begin(); wit != m_aWatchFiles.end(); ++wit )
675 if( checkWriteability( wit->m_aFilePath ) )
677 files[ wit->m_aFilePath ] = new Config( wit->m_aFilePath );
678 break;
682 if( files.empty() )
683 return false;
685 Config* pGlobal = files.begin()->second;
686 pGlobal->SetGroup( GLOBAL_DEFAULTS_GROUP );
687 pGlobal->WriteKey( "DisableCUPS", m_bDisableCUPS ? "true" : "false" );
689 ::std::hash_map< OUString, Printer, OUStringHash >::iterator it;
690 for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it )
692 if( ! it->second.m_bModified )
693 // printer was not changed, do nothing
694 continue;
696 // don't save autoqueue printers
697 sal_Int32 nIndex = 0;
698 bool bAutoQueue = false;
699 while( nIndex != -1 && ! bAutoQueue )
701 OUString aToken( it->second.m_aInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
702 if( aToken.getLength() && aToken.compareToAscii( "autoqueue" ) == 0 )
703 bAutoQueue = true;
705 if( bAutoQueue )
706 continue;
708 if( it->second.m_aFile.getLength() )
710 // check if file is writable
711 if( files.find( it->second.m_aFile ) == files.end() )
713 bool bInsertToNewFile = false;
714 // maybe it is simply not inserted yet
715 if( rofiles.find( it->second.m_aFile ) == rofiles.end() )
717 if( checkWriteability( it->second.m_aFile ) )
718 files[ it->second.m_aFile ] = new Config( it->second.m_aFile );
719 else
720 bInsertToNewFile = true;
722 else
723 bInsertToNewFile = true;
724 // original file is read only, insert printer in a new writeable file
725 if( bInsertToNewFile )
727 rofiles[ it->second.m_aFile ] = 1;
728 // update alternate file list
729 // the remove operation ensures uniqueness of each alternate
730 it->second.m_aAlternateFiles.remove( it->second.m_aFile );
731 it->second.m_aAlternateFiles.remove( files.begin()->first );
732 it->second.m_aAlternateFiles.push_front( it->second.m_aFile );
733 // update file
734 it->second.m_aFile = files.begin()->first;
738 else // a new printer, write it to the first file available
739 it->second.m_aFile = files.begin()->first;
741 if( ! it->second.m_aGroup.getLength() ) // probably a new printer
742 it->second.m_aGroup = OString( it->first.getStr(), it->first.getLength(), RTL_TEXTENCODING_UTF8 );
744 if( files.find( it->second.m_aFile ) != files.end() )
746 Config* pConfig = files[ it->second.m_aFile ];
747 pConfig->DeleteGroup( it->second.m_aGroup ); // else some old keys may remain
748 pConfig->SetGroup( it->second.m_aGroup );
750 ByteString aValue( String( it->second.m_aInfo.m_aDriverName ), RTL_TEXTENCODING_UTF8 );
751 aValue += '/';
752 aValue += ByteString( String( it->first ), RTL_TEXTENCODING_UTF8 );
753 pConfig->WriteKey( "Printer", aValue );
754 pConfig->WriteKey( "DefaultPrinter", it->first == m_aDefaultPrinter ? "1" : "0" );
755 pConfig->WriteKey( "Location", ByteString( String( it->second.m_aInfo.m_aLocation ), RTL_TEXTENCODING_UTF8 ) );
756 pConfig->WriteKey( "Comment", ByteString( String( it->second.m_aInfo.m_aComment ), RTL_TEXTENCODING_UTF8 ) );
757 pConfig->WriteKey( "Command", ByteString( String( it->second.m_aInfo.m_aCommand ), RTL_TEXTENCODING_UTF8 ) );
758 pConfig->WriteKey( "QuickCommand", ByteString( String( it->second.m_aInfo.m_aQuickCommand ), RTL_TEXTENCODING_UTF8 ) );
759 pConfig->WriteKey( "Features", ByteString( String( it->second.m_aInfo.m_aFeatures ), RTL_TEXTENCODING_UTF8 ) );
760 pConfig->WriteKey( "Copies", ByteString::CreateFromInt32( it->second.m_aInfo.m_nCopies ) );
761 pConfig->WriteKey( "Orientation", it->second.m_aInfo.m_eOrientation == orientation::Landscape ? "Landscape" : "Portrait" );
762 pConfig->WriteKey( "PSLevel", ByteString::CreateFromInt32( it->second.m_aInfo.m_nPSLevel ) );
763 pConfig->WriteKey( "ColorDevice", ByteString::CreateFromInt32( it->second.m_aInfo.m_nColorDevice ) );
764 pConfig->WriteKey( "ColorDepth", ByteString::CreateFromInt32( it->second.m_aInfo.m_nColorDepth ) );
765 aValue = ByteString::CreateFromInt32( it->second.m_aInfo.m_nLeftMarginAdjust );
766 aValue += ',';
767 aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nRightMarginAdjust );
768 aValue += ',';
769 aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nTopMarginAdjust );
770 aValue += ',';
771 aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nBottomMarginAdjust );
772 pConfig->WriteKey( "MarginAdjust", aValue );
774 if( it->second.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) != 0 )
776 // write PPDContext (not for CUPS)
777 for( int i = 0; i < it->second.m_aInfo.m_aContext.countValuesModified(); i++ )
779 const PPDKey* pKey = it->second.m_aInfo.m_aContext.getModifiedKey( i );
780 ByteString aKey( "PPD_" );
781 aKey += ByteString( pKey->getKey(), RTL_TEXTENCODING_ISO_8859_1 );
783 const PPDValue* pValue = it->second.m_aInfo.m_aContext.getValue( pKey );
784 aValue = pValue ? ByteString( pValue->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ) : ByteString( "*nil" );
785 pConfig->WriteKey( aKey, aValue );
789 // write font substitution table
790 pConfig->WriteKey( "PerformFontSubstitution", it->second.m_aInfo.m_bPerformFontSubstitution ? "true" : "false" );
791 for( ::std::hash_map< OUString, OUString, OUStringHash >::const_iterator subst = it->second.m_aInfo.m_aFontSubstitutes.begin();
792 subst != it->second.m_aInfo.m_aFontSubstitutes.end(); ++subst )
794 ByteString aKey( "SubstFont_" );
795 aKey.Append( OUStringToOString( subst->first, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
796 pConfig->WriteKey( aKey, OUStringToOString( subst->second, RTL_TEXTENCODING_ISO_8859_1 ) );
801 // get rid of Config objects. this also writes any changes
802 for( file_it = files.begin(); file_it != files.end(); ++file_it )
803 delete file_it->second;
805 return true;
808 // -----------------------------------------------------------------
810 bool PrinterInfoManager::addPrinter( const OUString& rPrinterName, const OUString& rDriverName )
812 bool bSuccess = false;
814 const PPDParser* pParser = NULL;
815 if( m_aPrinters.find( rPrinterName ) == m_aPrinters.end() && ( pParser = PPDParser::getParser( rDriverName ) ) )
817 Printer aPrinter;
818 aPrinter.m_bModified = true;
819 aPrinter.m_aInfo = m_aGlobalDefaults;
820 aPrinter.m_aInfo.m_aDriverName = rDriverName;
821 aPrinter.m_aInfo.m_pParser = pParser;
822 aPrinter.m_aInfo.m_aContext.setParser( pParser );
823 aPrinter.m_aInfo.m_aPrinterName = rPrinterName;
825 fillFontSubstitutions( aPrinter.m_aInfo );
826 // merge PPD values with global defaults
827 for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ )
829 const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified );
830 const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey );
831 const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL;
832 if( pDefKey && pPrinterKey )
833 // at least the options exist in both PPDs
835 if( pDefValue )
837 const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption );
838 if( pPrinterValue )
839 // the printer has a corresponding option for the key
840 aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue );
842 else
843 aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL );
847 m_aPrinters[ rPrinterName ] = aPrinter;
848 bSuccess = true;
849 #if OSL_DEBUG_LEVEL > 1
850 fprintf( stderr, "new printer %s, level = %d, colordevice = %d, depth = %d\n",
851 OUStringToOString( rPrinterName, osl_getThreadTextEncoding() ).getStr(),
852 m_aPrinters[rPrinterName].m_aInfo.m_nPSLevel,
853 m_aPrinters[rPrinterName].m_aInfo.m_nColorDevice,
854 m_aPrinters[rPrinterName].m_aInfo.m_nColorDepth );
855 #endif
856 // comment: logically one should writePrinterConfig() here
857 // but immediately after addPrinter() a changePrinterInfo()
858 // will follow (see padmin code), which writes it again,
859 // so we can currently save some performance here
861 return bSuccess;
864 // -----------------------------------------------------------------
866 bool PrinterInfoManager::removePrinter( const OUString& rPrinterName, bool bCheckOnly )
868 bool bSuccess = true;
870 ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName );
871 if( it != m_aPrinters.end() )
873 if( it->second.m_aFile.getLength() )
875 // this printer already exists in a config file
878 // check writeability of config file(s)
879 if( ! checkWriteability( it->second.m_aFile ) )
880 bSuccess = false;
881 else
883 for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin();
884 file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it )
886 if( ! checkWriteability( *file_it ) )
887 bSuccess = false;
890 if( bSuccess && ! bCheckOnly )
893 Config aConfig( it->second.m_aFile );
894 aConfig.DeleteGroup( it->second.m_aGroup );
895 aConfig.Flush();
896 for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin();
897 file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it )
899 Config aAltConfig( *file_it );
900 aAltConfig.DeleteGroup( it->second.m_aGroup );
901 aAltConfig.Flush();
905 if( bSuccess && ! bCheckOnly )
907 m_aPrinters.erase( it );
908 // need this here because someone may call
909 // checkPrintersChanged after the removal
910 // but then other added printers were not flushed
911 // to disk, so they are discarded
912 writePrinterConfig();
915 return bSuccess;
918 // -----------------------------------------------------------------
920 bool PrinterInfoManager::setDefaultPrinter( const OUString& rPrinterName )
922 bool bSuccess = false;
924 ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName );
925 if( it != m_aPrinters.end() )
927 bSuccess = true;
928 it->second.m_bModified = true;
929 if( ( it = m_aPrinters.find( m_aDefaultPrinter ) ) != m_aPrinters.end() )
930 it->second.m_bModified = true;
931 m_aDefaultPrinter = rPrinterName;
932 writePrinterConfig();
934 return bSuccess;
937 // -----------------------------------------------------------------
938 bool PrinterInfoManager::addOrRemovePossible() const
940 return true;
943 // -----------------------------------------------------------------
945 void PrinterInfoManager::fillFontSubstitutions( PrinterInfo& rInfo ) const
947 PrintFontManager& rFontManager( PrintFontManager::get() );
948 rInfo.m_aFontSubstitutions.clear();
950 if( ! rInfo.m_bPerformFontSubstitution ||
951 ! rInfo.m_aFontSubstitutes.size() )
952 return;
954 ::std::list< FastPrintFontInfo > aFonts;
955 ::std::hash_map< OUString, ::std::list< FastPrintFontInfo >, OUStringHash > aPrinterFonts;
956 rFontManager.getFontListWithFastInfo( aFonts, rInfo.m_pParser );
958 // get builtin fonts
959 ::std::list< FastPrintFontInfo >::const_iterator it;
960 for( it = aFonts.begin(); it != aFonts.end(); ++it )
961 if( it->m_eType == fonttype::Builtin )
962 aPrinterFonts[ it->m_aFamilyName.toAsciiLowerCase() ].push_back( *it );
964 // map lower case, so build a local copy of the font substitutions
965 ::std::hash_map< OUString, OUString, OUStringHash > aSubstitutions;
966 ::std::hash_map< OUString, OUString, OUStringHash >::const_iterator subst;
967 for( subst = rInfo.m_aFontSubstitutes.begin(); subst != rInfo.m_aFontSubstitutes.end(); ++subst )
969 OUString aFamily( subst->first.toAsciiLowerCase() );
970 // first look if there is a builtin of this family
971 // in this case override the substitution table
972 if( aPrinterFonts.find( aFamily ) != aPrinterFonts.end() )
973 aSubstitutions[ aFamily ] = aFamily;
974 else
975 aSubstitutions[ aFamily ] = subst->second.toAsciiLowerCase();
979 // now find substitutions
980 for( it = aFonts.begin(); it != aFonts.end(); ++it )
982 if( it->m_eType != fonttype::Builtin )
984 OUString aFamily( it->m_aFamilyName.toAsciiLowerCase() );
985 subst = aSubstitutions.find( aFamily );
986 if( subst != aSubstitutions.end() )
988 // search a substitution
989 const ::std::list< FastPrintFontInfo >& rBuiltins( aPrinterFonts[ aSubstitutions[ aFamily ] ] );
990 ::std::list< FastPrintFontInfo >::const_iterator builtin;
991 int nLastMatch = -10000;
992 fontID nSubstitute = -1;
993 for( builtin = rBuiltins.begin(); builtin != rBuiltins.end(); ++builtin )
995 int nMatch = 0;
996 int nDiff;
997 if( builtin->m_eItalic == it->m_eItalic )
998 nMatch += 8000;
1000 nDiff = builtin->m_eWeight - it->m_eWeight;
1001 nDiff = nDiff < 0 ? -nDiff : nDiff;
1002 nMatch += 4000 - 1000*nDiff;
1004 nDiff = builtin->m_eWidth - it->m_eWidth;
1005 nDiff = nDiff < 0 ? -nDiff : nDiff;
1006 nMatch += 2000 - 500*nDiff;
1008 if( nMatch > nLastMatch )
1010 nLastMatch = nMatch;
1011 nSubstitute = builtin->m_nID;
1014 if( nSubstitute != -1 )
1016 rInfo.m_aFontSubstitutions[ it->m_nID ] = nSubstitute;
1017 #if OSL_DEBUG_LEVEL > 2
1018 FastPrintFontInfo aInfo;
1019 rFontManager.getFontFastInfo( nSubstitute, aInfo );
1020 fprintf( stderr,
1021 "substitute %s %s %d %d\n"
1022 " -> %s %s %d %d\n",
1023 OUStringToOString( it->m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1024 it->m_eItalic == italic::Upright ? "r" : it->m_eItalic == italic::Oblique ? "o" : it->m_eItalic == italic::Italic ? "i" : "u",
1025 it->m_eWeight,
1026 it->m_eWidth,
1028 OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr(),
1029 aInfo.m_eItalic == italic::Upright ? "r" : aInfo.m_eItalic == italic::Oblique ? "o" : aInfo.m_eItalic == italic::Italic ? "i" : "u",
1030 aInfo.m_eWeight,
1031 aInfo.m_eWidth
1033 #endif
1040 // -----------------------------------------------------------------
1042 void PrinterInfoManager::getSystemPrintCommands( std::list< OUString >& rCommands )
1044 if( m_pQueueInfo && m_pQueueInfo->hasChanged() )
1046 m_aSystemPrintCommand = m_pQueueInfo->getCommand();
1047 m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues );
1048 delete m_pQueueInfo, m_pQueueInfo = NULL;
1051 std::list< SystemPrintQueue >::const_iterator it;
1052 rCommands.clear();
1053 String aPrinterConst( RTL_CONSTASCII_USTRINGPARAM( "(PRINTER)" ) );
1054 for( it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it )
1056 String aCmd( m_aSystemPrintCommand );
1057 aCmd.SearchAndReplace( aPrinterConst, it->m_aQueue );
1058 rCommands.push_back( aCmd );
1062 const std::list< PrinterInfoManager::SystemPrintQueue >& PrinterInfoManager::getSystemPrintQueues()
1064 if( m_pQueueInfo && m_pQueueInfo->hasChanged() )
1066 m_aSystemPrintCommand = m_pQueueInfo->getCommand();
1067 m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues );
1068 delete m_pQueueInfo, m_pQueueInfo = NULL;
1071 return m_aSystemPrintQueues;
1074 bool PrinterInfoManager::checkFeatureToken( const rtl::OUString& rPrinterName, const char* pToken ) const
1076 const PrinterInfo& rPrinterInfo( getPrinterInfo( rPrinterName ) );
1077 sal_Int32 nIndex = 0;
1078 while( nIndex != -1 )
1080 OUString aOuterToken = rPrinterInfo.m_aFeatures.getToken( 0, ',', nIndex );
1081 sal_Int32 nInnerIndex = 0;
1082 OUString aInnerToken = aOuterToken.getToken( 0, '=', nInnerIndex );
1083 if( aInnerToken.equalsIgnoreAsciiCaseAscii( pToken ) )
1084 return true;
1086 return false;
1089 FILE* PrinterInfoManager::startSpool( const OUString& rPrintername, bool bQuickCommand )
1091 const PrinterInfo& rPrinterInfo = getPrinterInfo (rPrintername);
1092 const rtl::OUString& rCommand = (bQuickCommand && rPrinterInfo.m_aQuickCommand.getLength() ) ?
1093 rPrinterInfo.m_aQuickCommand : rPrinterInfo.m_aCommand;
1094 rtl::OString aShellCommand = OUStringToOString (rCommand, RTL_TEXTENCODING_ISO_8859_1);
1095 aShellCommand += rtl::OString( " 2>/dev/null" );
1097 return popen (aShellCommand.getStr(), "w");
1100 int PrinterInfoManager::endSpool( const OUString& /*rPrintername*/, const OUString& /*rJobTitle*/, FILE* pFile, const JobData& /*rDocumentJobData*/ )
1102 return (0 == pclose( pFile ));
1105 void PrinterInfoManager::setupJobContextData( JobData& rData )
1107 std::hash_map< OUString, Printer, OUStringHash >::iterator it =
1108 m_aPrinters.find( rData.m_aPrinterName );
1109 if( it != m_aPrinters.end() )
1111 rData.m_pParser = it->second.m_aInfo.m_pParser;
1112 rData.m_aContext = it->second.m_aInfo.m_aContext;
1116 void PrinterInfoManager::setDefaultPaper( PPDContext& rContext ) const
1118 if( ! rContext.getParser() )
1119 return;
1121 const PPDKey* pPageSizeKey = rContext.getParser()->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
1122 if( ! pPageSizeKey )
1123 return;
1125 int nModified = rContext.countValuesModified();
1126 while( nModified-- &&
1127 rContext.getModifiedKey( nModified ) != pPageSizeKey )
1130 if( nModified >= 0 ) // paper was set already, do not modify
1132 #if OSL_DEBUG_LEVEL > 1
1133 fprintf( stderr, "not setting default paper, already set %s\n",
1134 OUStringToOString( rContext.getValue( pPageSizeKey )->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
1135 #endif
1136 return;
1139 // paper not set, fill in default value
1140 const PPDValue* pPaperVal = NULL;
1141 int nValues = pPageSizeKey->countValues();
1142 for( int i = 0; i < nValues && ! pPaperVal; i++ )
1144 const PPDValue* pVal = pPageSizeKey->getValue( i );
1145 if( pVal->m_aOption.EqualsIgnoreCaseAscii( m_aSystemDefaultPaper.getStr() ) )
1146 pPaperVal = pVal;
1148 if( pPaperVal )
1150 #if OSL_DEBUG_LEVEL > 1
1151 fprintf( stderr, "setting default paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
1152 #endif
1153 rContext.setValue( pPageSizeKey, pPaperVal );
1154 #if OSL_DEBUG_LEVEL > 1
1155 pPaperVal = rContext.getValue( pPageSizeKey );
1156 fprintf( stderr, "-> got paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() );
1157 #endif
1161 // -----------------------------------------------------------------
1163 SystemQueueInfo::SystemQueueInfo() :
1164 m_bChanged( false )
1166 create();
1169 SystemQueueInfo::~SystemQueueInfo()
1171 terminate();
1174 bool SystemQueueInfo::hasChanged() const
1176 MutexGuard aGuard( m_aMutex );
1177 bool bChanged = m_bChanged;
1178 return bChanged;
1181 void SystemQueueInfo::getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues )
1183 MutexGuard aGuard( m_aMutex );
1184 rQueues = m_aQueues;
1185 m_bChanged = false;
1188 OUString SystemQueueInfo::getCommand() const
1190 MutexGuard aGuard( m_aMutex );
1191 OUString aRet = m_aCommand;
1192 return aRet;
1195 struct SystemCommandParameters;
1196 typedef void(* tokenHandler)(const std::list< rtl::OString >&,
1197 std::list< PrinterInfoManager::SystemPrintQueue >&,
1198 const SystemCommandParameters*);
1200 struct SystemCommandParameters
1202 const char* pQueueCommand;
1203 const char* pPrintCommand;
1204 const char* pForeToken;
1205 const char* pAftToken;
1206 unsigned int nForeTokenCount;
1207 tokenHandler pHandler;
1210 #if ! (defined(LINUX) || defined(NETBSD) || defined(FREEBSD))
1211 static void lpgetSysQueueTokenHandler(
1212 const std::list< rtl::OString >& i_rLines,
1213 std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
1214 const SystemCommandParameters* )
1216 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1217 std::hash_set< OUString, OUStringHash > aUniqueSet;
1218 std::hash_set< OUString, OUStringHash > aOnlySet;
1219 aUniqueSet.insert( OUString( RTL_CONSTASCII_USTRINGPARAM( "_all" ) ) );
1220 aUniqueSet.insert( OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
1222 // the eventual "all" attribute of the "_all" queue tells us, which
1223 // printers are to be used for this user at all
1225 // find _all: line
1226 rtl::OString aAllLine( "_all:" );
1227 rtl::OString aAllAttr( "all=" );
1228 for( std::list< rtl::OString >::const_iterator it = i_rLines.begin();
1229 it != i_rLines.end(); ++it )
1231 if( it->indexOf( aAllLine, 0 ) == 0 )
1233 // now find the "all" attribute
1234 ++it;
1235 while( it != i_rLines.end() )
1237 rtl::OString aClean( WhitespaceToSpace( *it ) );
1238 if( aClean.indexOf( aAllAttr, 0 ) == 0 )
1240 // insert the comma separated entries into the set of printers to use
1241 sal_Int32 nPos = aAllAttr.getLength();
1242 while( nPos != -1 )
1244 OString aTok( aClean.getToken( 0, ',', nPos ) );
1245 if( aTok.getLength() > 0 )
1246 aOnlySet.insert( rtl::OStringToOUString( aTok, aEncoding ) );
1248 break;
1251 break;
1255 bool bInsertAttribute = false;
1256 rtl::OString aDescrStr( "description=" );
1257 rtl::OString aLocStr( "location=" );
1258 for( std::list< rtl::OString >::const_iterator it = i_rLines.begin();
1259 it != i_rLines.end(); ++it )
1261 sal_Int32 nPos = 0;
1262 // find the begin of a new printer section
1263 nPos = it->indexOf( ':', 0 );
1264 if( nPos != -1 )
1266 OUString aSysQueue( rtl::OStringToOUString( it->copy( 0, nPos ), aEncoding ) );
1267 // do not insert duplicates (e.g. lpstat tends to produce such lines)
1268 // in case there was a "_all" section, insert only those printer explicitly
1269 // set in the "all" attribute
1270 if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() &&
1271 ( aOnlySet.empty() || aOnlySet.find( aSysQueue ) != aOnlySet.end() )
1274 o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
1275 o_rQueues.back().m_aQueue = aSysQueue;
1276 o_rQueues.back().m_aLocation = aSysQueue;
1277 aUniqueSet.insert( aSysQueue );
1278 bInsertAttribute = true;
1280 else
1281 bInsertAttribute = false;
1282 continue;
1284 if( bInsertAttribute && ! o_rQueues.empty() )
1286 // look for "description" attribute, insert as comment
1287 nPos = it->indexOf( aDescrStr, 0 );
1288 if( nPos != -1 )
1290 ByteString aComment( WhitespaceToSpace( it->copy(nPos+12) ) );
1291 if( aComment.Len() > 0 )
1292 o_rQueues.back().m_aComment = String( aComment, aEncoding );
1293 continue;
1295 // look for "location" attribute, inser as location
1296 nPos = it->indexOf( aLocStr, 0 );
1297 if( nPos != -1 )
1299 ByteString aLoc( WhitespaceToSpace( it->copy(nPos+9) ) );
1300 if( aLoc.Len() > 0 )
1301 o_rQueues.back().m_aLocation = String( aLoc, aEncoding );
1302 continue;
1307 #endif
1308 static void standardSysQueueTokenHandler(
1309 const std::list< rtl::OString >& i_rLines,
1310 std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues,
1311 const SystemCommandParameters* i_pParms)
1313 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
1314 std::hash_set< OUString, OUStringHash > aUniqueSet;
1315 rtl::OString aForeToken( i_pParms->pForeToken );
1316 rtl::OString aAftToken( i_pParms->pAftToken );
1317 /* Normal Unix print queue discovery, also used for Darwin 5 LPR printing
1319 for( std::list< rtl::OString >::const_iterator it = i_rLines.begin();
1320 it != i_rLines.end(); ++it )
1322 sal_Int32 nPos = 0;
1324 // search for a line describing a printer:
1325 // find if there are enough tokens before the name
1326 for( unsigned int i = 0; i < i_pParms->nForeTokenCount && nPos != -1; i++ )
1328 nPos = it->indexOf( aForeToken, nPos );
1329 if( nPos != -1 && it->getLength() >= nPos+aForeToken.getLength() )
1330 nPos += aForeToken.getLength();
1332 if( nPos != -1 )
1334 // find if there is the token after the queue
1335 sal_Int32 nAftPos = it->indexOf( aAftToken, nPos );
1336 if( nAftPos != -1 )
1338 // get the queue name between fore and aft tokens
1339 OUString aSysQueue( rtl::OStringToOUString( it->copy( nPos, nAftPos - nPos ), aEncoding ) );
1340 // do not insert duplicates (e.g. lpstat tends to produce such lines)
1341 if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() )
1343 o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() );
1344 o_rQueues.back().m_aQueue = aSysQueue;
1345 o_rQueues.back().m_aLocation = aSysQueue;
1346 aUniqueSet.insert( aSysQueue );
1353 static const struct SystemCommandParameters aParms[] =
1355 #if defined(LINUX) || defined(NETBSD) || defined(FREEBSD)
1356 { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
1357 { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
1358 { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler }
1359 #else
1360 { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpget list", "lp -d \"(PRINTER)\"", "", ":", 0, lpgetSysQueueTokenHandler },
1361 { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler },
1362 { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler },
1363 { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler }
1364 #endif
1367 void SystemQueueInfo::run()
1369 char pBuffer[1024];
1370 FILE *pPipe;
1371 std::list< rtl::OString > aLines;
1373 /* Discover which command we can use to get a list of all printer queues */
1374 for( unsigned int i = 0; i < sizeof(aParms)/sizeof(aParms[0]); i++ )
1376 aLines.clear();
1377 rtl::OStringBuffer aCmdLine( 128 );
1378 aCmdLine.append( aParms[i].pQueueCommand );
1379 #if OSL_DEBUG_LEVEL > 1
1380 fprintf( stderr, "trying print queue command \"%s\" ... ", aParms[i].pQueueCommand );
1381 #endif
1382 aCmdLine.append( " 2>/dev/null" );
1383 if( (pPipe = popen( aCmdLine.getStr(), "r" )) )
1385 while( fgets( pBuffer, 1024, pPipe ) )
1386 aLines.push_back( rtl::OString( pBuffer ) );
1387 if( ! pclose( pPipe ) )
1389 std::list< PrinterInfoManager::SystemPrintQueue > aSysPrintQueues;
1390 aParms[i].pHandler( aLines, aSysPrintQueues, &(aParms[i]) );
1391 MutexGuard aGuard( m_aMutex );
1392 m_bChanged = true;
1393 m_aQueues = aSysPrintQueues;
1394 m_aCommand = rtl::OUString::createFromAscii( aParms[i].pPrintCommand );
1395 #if OSL_DEBUG_LEVEL > 1
1396 fprintf( stderr, "success\n" );
1397 #endif
1398 break;
1401 #if OSL_DEBUG_LEVEL > 1
1402 fprintf( stderr, "failed\n" );
1403 #endif