1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: printerinfomanager.cxx,v $
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_psprint.hxx"
38 #include <tools/urlobj.hxx>
39 #include <tools/stream.hxx>
40 #include <tools/debug.hxx>
41 #include <tools/config.hxx>
42 #include <cupsmgr.hxx>
43 #include <psprint/fontmanager.hxx>
44 #include <psprint/strhelper.hxx>
45 #include <rtl/strbuf.hxx>
47 #include <osl/thread.hxx>
48 #include <osl/mutex.hxx>
49 #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__"
68 class SystemQueueInfo
: public Thread
70 mutable Mutex m_aMutex
;
72 std::list
< PrinterInfoManager::SystemPrintQueue
>
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
);
91 * class PrinterInfoManager
94 // -----------------------------------------------------------------
96 PrinterInfoManager
& PrinterInfoManager::get()
98 static PrinterInfoManager
* pManager
= NULL
;
102 pManager
= CUPSManager::tryLoadCUPS();
104 pManager
= new PrinterInfoManager();
107 pManager
->initialize();
108 #if OSL_DEBUG_LEVEL > 1
109 fprintf( stderr
, "PrinterInfoManager::get create Manager of type %d\n", pManager
->getType() );
116 // -----------------------------------------------------------------
118 PrinterInfoManager::PrinterInfoManager( Type eType
) :
119 m_pQueueInfo( NULL
),
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()
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 bool bSuccess
= false;
163 // #i78617# workaround missing paperconf command
164 FILE* pPipe
= popen( "sh -c paperconf 2>/dev/null", "r" );
167 char pBuffer
[ 1024 ];
169 fgets( pBuffer
, sizeof(pBuffer
)-1, pPipe
);
172 ByteString
aPaper( pBuffer
);
173 aPaper
= WhitespaceToSpace( aPaper
);
176 m_aSystemDefaultPaper
= OUString( OStringToOUString( aPaper
, osl_getThreadTextEncoding() ) );
178 #if OSL_DEBUG_LEVEL > 1
179 fprintf( stderr
, "paper from paperconf = %s\n", aPaper
.GetBuffer() );
186 // default value is Letter for US (en_US), Cannada (en_CA, fr_CA); else A4
187 // en will be interpreted as en_US
189 // note: at this point m_aSystemDefaultPaper is set to "A4" from the constructor
191 // check for LC_PAPER
192 const char* pPaperLang
= getenv( "LC_PAPER" );
193 if( pPaperLang
&& *pPaperLang
)
195 OString
aLang( pPaperLang
);
196 if( aLang
.getLength() > 5 )
197 aLang
= aLang
.copy( 0, 5 );
198 if( aLang
.getLength() == 5 )
200 if( aLang
.equalsIgnoreAsciiCase( "en_us" )
201 || aLang
.equalsIgnoreAsciiCase( "en_ca" )
202 || aLang
.equalsIgnoreAsciiCase( "fr_ca" )
204 m_aSystemDefaultPaper
= OUString( RTL_CONSTASCII_USTRINGPARAM( "Letter" ) );
206 else if( aLang
.getLength() == 2 && aLang
.equalsIgnoreAsciiCase( "en" ) )
207 m_aSystemDefaultPaper
= OUString( RTL_CONSTASCII_USTRINGPARAM( "Letter" ) );
211 // use process locale to determine paper
212 rtl_Locale
* pLoc
= NULL
;
213 osl_getProcessLocale( &pLoc
);
216 if( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pLoc
->Language
->buffer
, pLoc
->Language
->length
, "en") )
218 if( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pLoc
->Country
->buffer
, pLoc
->Country
->length
, "us")
219 || 0 == rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pLoc
->Country
->buffer
, pLoc
->Country
->length
, "ca")
220 || pLoc
->Country
->length
== 0
222 m_aSystemDefaultPaper
= OUString( RTL_CONSTASCII_USTRINGPARAM( "Letter" ) );
224 else if( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pLoc
->Language
->buffer
, pLoc
->Language
->length
, "fr") )
226 if( 0 == rtl_ustr_ascii_compareIgnoreAsciiCase_WithLength( pLoc
->Country
->buffer
, pLoc
->Country
->length
, "ca") )
227 m_aSystemDefaultPaper
= OUString( RTL_CONSTASCII_USTRINGPARAM( "Letter" ) );
232 // -----------------------------------------------------------------
234 bool PrinterInfoManager::checkPrintersChanged( bool bWait
)
236 // check if files were created, deleted or modified since initialize()
237 ::std::list
< WatchFile
>::const_iterator it
;
238 bool bChanged
= false;
239 for( it
= m_aWatchFiles
.begin(); it
!= m_aWatchFiles
.end() && ! bChanged
; ++it
)
242 if( DirectoryItem::get( it
->m_aFilePath
, aItem
) )
244 if( it
->m_aModified
.Seconds
!= 0 )
245 bChanged
= true; // file probably has vanished
249 FileStatus
aStatus( FileStatusMask_ModifyTime
);
250 if( aItem
.getFileStatus( aStatus
) )
251 bChanged
= true; // unlikely but not impossible
254 TimeValue aModified
= aStatus
.getModifyTime();
255 if( aModified
.Seconds
!= it
->m_aModified
.Seconds
)
261 if( bWait
&& m_pQueueInfo
)
263 #if OSL_DEBUG_LEVEL > 1
264 fprintf( stderr
, "syncing printer discovery thread\n" );
266 m_pQueueInfo
->join();
267 #if OSL_DEBUG_LEVEL > 1
268 fprintf( stderr
, "done: syncing printer discovery thread\n" );
272 if( ! bChanged
&& m_pQueueInfo
)
273 bChanged
= m_pQueueInfo
->hasChanged();
282 // -----------------------------------------------------------------
284 void PrinterInfoManager::initialize()
286 m_bUseIncludeFeature
= false;
287 rtl_TextEncoding aEncoding
= gsl_getSystemTextEncoding();
289 m_aWatchFiles
.clear();
290 OUString aDefaultPrinter
;
292 // first initialize the global defaults
293 // have to iterate over all possible files
294 // there should be only one global setup section in all
295 // available config files
296 m_aGlobalDefaults
= PrinterInfo();
298 // need a parser for the PPDContext. generic printer should do.
299 m_aGlobalDefaults
.m_pParser
= PPDParser::getParser( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) );
300 m_aGlobalDefaults
.m_aContext
.setParser( m_aGlobalDefaults
.m_pParser
);
301 m_aGlobalDefaults
.m_bPerformFontSubstitution
= true;
302 m_bDisableCUPS
= false;
304 if( ! m_aGlobalDefaults
.m_pParser
)
306 #if OSL_DEBUG_LEVEL > 1
307 fprintf( stderr
, "Error: no default PPD file SGENPRT available, shutting down psprint...\n" );
312 std::list
< OUString
> aDirList
;
313 psp::getPrinterPathList( aDirList
, NULL
);
314 std::list
< OUString
>::const_iterator print_dir_it
;
315 for( print_dir_it
= aDirList
.begin(); print_dir_it
!= aDirList
.end(); ++print_dir_it
)
317 INetURLObject
aFile( *print_dir_it
, INET_PROT_FILE
, INetURLObject::ENCODE_ALL
);
318 aFile
.Append( String( RTL_CONSTASCII_USTRINGPARAM( PRINT_FILENAME
) ) );
319 Config
aConfig( aFile
.PathToFileName() );
320 if( aConfig
.HasGroup( GLOBAL_DEFAULTS_GROUP
) )
322 #if OSL_DEBUG_LEVEL > 1
323 fprintf( stderr
, "found global defaults in %s\n", OUStringToOString( aFile
.PathToFileName(), RTL_TEXTENCODING_ISO_8859_1
).getStr() );
325 aConfig
.SetGroup( GLOBAL_DEFAULTS_GROUP
);
327 ByteString
aValue( aConfig
.ReadKey( "Copies" ) );
329 m_aGlobalDefaults
.m_nCopies
= aValue
.ToInt32();
331 aValue
= aConfig
.ReadKey( "Orientation" );
333 m_aGlobalDefaults
.m_eOrientation
= aValue
.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape
: orientation::Portrait
;
335 aValue
= aConfig
.ReadKey( "MarginAdjust" );
338 m_aGlobalDefaults
.m_nLeftMarginAdjust
= aValue
.GetToken( 0, ',' ).ToInt32();
339 m_aGlobalDefaults
.m_nRightMarginAdjust
= aValue
.GetToken( 1, ',' ).ToInt32();
340 m_aGlobalDefaults
.m_nTopMarginAdjust
= aValue
.GetToken( 2, ',' ).ToInt32();
341 m_aGlobalDefaults
.m_nBottomMarginAdjust
= aValue
.GetToken( 3, ',' ).ToInt32();
344 aValue
= aConfig
.ReadKey( "ColorDepth", "24" );
346 m_aGlobalDefaults
.m_nColorDepth
= aValue
.ToInt32();
348 aValue
= aConfig
.ReadKey( "ColorDevice" );
350 m_aGlobalDefaults
.m_nColorDevice
= aValue
.ToInt32();
352 aValue
= aConfig
.ReadKey( "PSLevel" );
354 m_aGlobalDefaults
.m_nPSLevel
= aValue
.ToInt32();
356 aValue
= aConfig
.ReadKey( "PerformFontSubstitution" );
359 if( ! aValue
.Equals( "0" ) && ! aValue
.EqualsIgnoreCaseAscii( "false" ) )
360 m_aGlobalDefaults
.m_bPerformFontSubstitution
= true;
362 m_aGlobalDefaults
.m_bPerformFontSubstitution
= false;
365 aValue
= aConfig
.ReadKey( "DisableCUPS" );
368 if( aValue
.Equals( "1" ) || aValue
.EqualsIgnoreCaseAscii( "true" ) )
369 m_bDisableCUPS
= true;
371 m_bDisableCUPS
= false;
374 // get the PPDContext of global JobData
375 for( int nKey
= 0; nKey
< aConfig
.GetKeyCount(); nKey
++ )
377 ByteString
aKey( aConfig
.GetKeyName( nKey
) );
378 if( aKey
.CompareTo( "PPD_", 4 ) == COMPARE_EQUAL
)
380 aValue
= aConfig
.ReadKey( aKey
);
381 const PPDKey
* pKey
= m_aGlobalDefaults
.m_pParser
->getKey( String( aKey
.Copy( 4 ), RTL_TEXTENCODING_ISO_8859_1
) );
384 m_aGlobalDefaults
.m_aContext
.
386 aValue
.Equals( "*nil" ) ? NULL
: pKey
->getValue( String( aValue
, RTL_TEXTENCODING_ISO_8859_1
) ),
390 else if( aKey
.Len() > 10 && aKey
.CompareTo("SubstFont_", 10 ) == COMPARE_EQUAL
)
392 aValue
= aConfig
.ReadKey( aKey
);
393 m_aGlobalDefaults
.m_aFontSubstitutes
[ OStringToOUString( aKey
.Copy( 10 ), RTL_TEXTENCODING_ISO_8859_1
) ] = OStringToOUString( aValue
, RTL_TEXTENCODING_ISO_8859_1
);
396 #if OSL_DEBUG_LEVEL > 1
397 fprintf( stderr
, "global settings: fontsubst = %s, %d substitutes\n", m_aGlobalDefaults
.m_bPerformFontSubstitution
? "true" : "false", m_aGlobalDefaults
.m_aFontSubstitutes
.size() );
401 setDefaultPaper( m_aGlobalDefaults
.m_aContext
);
402 fillFontSubstitutions( m_aGlobalDefaults
);
404 // now collect all available printers
405 for( print_dir_it
= aDirList
.begin(); print_dir_it
!= aDirList
.end(); ++print_dir_it
)
407 INetURLObject
aDir( *print_dir_it
, INET_PROT_FILE
, INetURLObject::ENCODE_ALL
);
408 INetURLObject
aFile( aDir
);
409 aFile
.Append( String( RTL_CONSTASCII_USTRINGPARAM( PRINT_FILENAME
) ) );
411 // check directory validity
413 FileBase::getFileURLFromSystemPath( aDir
.PathToFileName(), aUniPath
);
414 Directory
aDirectory( aUniPath
);
415 if( aDirectory
.open() )
420 FileBase::getFileURLFromSystemPath( aFile
.PathToFileName(), aUniPath
);
421 FileStatus
aStatus( FileStatusMask_ModifyTime
);
424 // setup WatchFile list
425 WatchFile aWatchFile
;
426 aWatchFile
.m_aFilePath
= aUniPath
;
427 if( ! DirectoryItem::get( aUniPath
, aItem
) &&
428 ! aItem
.getFileStatus( aStatus
) )
430 aWatchFile
.m_aModified
= aStatus
.getModifyTime();
434 aWatchFile
.m_aModified
.Seconds
= 0;
435 aWatchFile
.m_aModified
.Nanosec
= 0;
437 m_aWatchFiles
.push_back( aWatchFile
);
439 Config
aConfig( aFile
.PathToFileName() );
440 for( int nGroup
= 0; nGroup
< aConfig
.GetGroupCount(); nGroup
++ )
442 aConfig
.SetGroup( aConfig
.GetGroupName( nGroup
) );
443 ByteString aValue
= aConfig
.ReadKey( "Printer" );
446 OUString aPrinterName
;
448 int nNamePos
= aValue
.Search( '/' );
449 // check for valid value of "Printer"
450 if( nNamePos
== STRING_NOTFOUND
)
454 // initialize to global defaults
455 aPrinter
.m_aInfo
= m_aGlobalDefaults
;
456 // global settings do not default the printer substitution
457 // list ! the substitution list in there is only used for
458 // newly created printers
459 aPrinter
.m_aInfo
.m_aFontSubstitutes
.clear();
460 aPrinter
.m_aInfo
.m_aFontSubstitutions
.clear();
462 aPrinterName
= String( aValue
.Copy( nNamePos
+1 ), RTL_TEXTENCODING_UTF8
);
463 aPrinter
.m_aInfo
.m_aPrinterName
= aPrinterName
;
464 aPrinter
.m_aInfo
.m_aDriverName
= String( aValue
.Copy( 0, nNamePos
), RTL_TEXTENCODING_UTF8
);
466 // set parser, merge settings
467 // don't do this for CUPS printers as this is done
468 // by the CUPS system itself
469 if( aPrinter
.m_aInfo
.m_aDriverName
.compareToAscii( "CUPS:", 5 ) != 0 )
471 aPrinter
.m_aInfo
.m_pParser
= PPDParser::getParser( aPrinter
.m_aInfo
.m_aDriverName
);
472 aPrinter
.m_aInfo
.m_aContext
.setParser( aPrinter
.m_aInfo
.m_pParser
);
473 // note: setParser also purges the context
475 // ignore this printer if its driver is not found
476 if( ! aPrinter
.m_aInfo
.m_pParser
)
479 // merge the ppd context keys if the printer has the same keys and values
480 // this is a bit tricky, since it involves mixing two PPDs
481 // without constraints which might end up badly
482 // this feature should be use with caution
483 // it is mainly to select default paper sizes for new printers
484 for( int nPPDValueModified
= 0; nPPDValueModified
< m_aGlobalDefaults
.m_aContext
.countValuesModified(); nPPDValueModified
++ )
486 const PPDKey
* pDefKey
= m_aGlobalDefaults
.m_aContext
.getModifiedKey( nPPDValueModified
);
487 const PPDValue
* pDefValue
= m_aGlobalDefaults
.m_aContext
.getValue( pDefKey
);
488 const PPDKey
* pPrinterKey
= pDefKey
? aPrinter
.m_aInfo
.m_pParser
->getKey( pDefKey
->getKey() ) : NULL
;
489 if( pDefKey
&& pPrinterKey
)
490 // at least the options exist in both PPDs
494 const PPDValue
* pPrinterValue
= pPrinterKey
->getValue( pDefValue
->m_aOption
);
496 // the printer has a corresponding option for the key
497 aPrinter
.m_aInfo
.m_aContext
.setValue( pPrinterKey
, pPrinterValue
);
500 aPrinter
.m_aInfo
.m_aContext
.setValue( pPrinterKey
, NULL
);
504 aValue
= aConfig
.ReadKey( "Command" );
505 // no printer without a command
509 * porters: please append your platform to the Solaris
510 * case if your platform has SystemV printing per default.
512 #if defined SOLARIS || defined(IRIX)
518 aPrinter
.m_aInfo
.m_aCommand
= String( aValue
, RTL_TEXTENCODING_UTF8
);
521 aValue
= aConfig
.ReadKey( "QuickCommand" );
522 aPrinter
.m_aInfo
.m_aQuickCommand
= String( aValue
, RTL_TEXTENCODING_UTF8
);
524 aValue
= aConfig
.ReadKey( "Features" );
525 aPrinter
.m_aInfo
.m_aFeatures
= String( aValue
, RTL_TEXTENCODING_UTF8
);
527 // override the settings in m_aGlobalDefaults if keys exist
528 aValue
= aConfig
.ReadKey( "DefaultPrinter" );
529 if( ! aValue
.Equals( "0" ) && ! aValue
.EqualsIgnoreCaseAscii( "false" ) )
530 aDefaultPrinter
= aPrinterName
;
532 aValue
= aConfig
.ReadKey( "Location" );
533 aPrinter
.m_aInfo
.m_aLocation
= String( aValue
, RTL_TEXTENCODING_UTF8
);
535 aValue
= aConfig
.ReadKey( "Comment" );
536 aPrinter
.m_aInfo
.m_aComment
= String( aValue
, RTL_TEXTENCODING_UTF8
);
538 aValue
= aConfig
.ReadKey( "Copies" );
540 aPrinter
.m_aInfo
.m_nCopies
= aValue
.ToInt32();
542 aValue
= aConfig
.ReadKey( "Orientation" );
544 aPrinter
.m_aInfo
.m_eOrientation
= aValue
.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape
: orientation::Portrait
;
546 aValue
= aConfig
.ReadKey( "MarginAdjust" );
549 aPrinter
.m_aInfo
.m_nLeftMarginAdjust
= aValue
.GetToken( 0, ',' ).ToInt32();
550 aPrinter
.m_aInfo
.m_nRightMarginAdjust
= aValue
.GetToken( 1, ',' ).ToInt32();
551 aPrinter
.m_aInfo
.m_nTopMarginAdjust
= aValue
.GetToken( 2, ',' ).ToInt32();
552 aPrinter
.m_aInfo
.m_nBottomMarginAdjust
= aValue
.GetToken( 3, ',' ).ToInt32();
555 aValue
= aConfig
.ReadKey( "ColorDepth" );
557 aPrinter
.m_aInfo
.m_nColorDepth
= aValue
.ToInt32();
559 aValue
= aConfig
.ReadKey( "ColorDevice" );
561 aPrinter
.m_aInfo
.m_nColorDevice
= aValue
.ToInt32();
563 aValue
= aConfig
.ReadKey( "PSLevel" );
565 aPrinter
.m_aInfo
.m_nPSLevel
= aValue
.ToInt32();
567 aValue
= aConfig
.ReadKey( "PerformFontSubstitution" );
568 if( ! aValue
.Equals( "0" ) && ! aValue
.EqualsIgnoreCaseAscii( "false" ) )
569 aPrinter
.m_aInfo
.m_bPerformFontSubstitution
= true;
571 aPrinter
.m_aInfo
.m_bPerformFontSubstitution
= false;
573 // now iterate over all keys to extract multi key information:
574 // 1. PPDContext information
575 // 2. Font substitution table
576 for( int nKey
= 0; nKey
< aConfig
.GetKeyCount(); nKey
++ )
578 ByteString
aKey( aConfig
.GetKeyName( nKey
) );
579 if( aKey
.CompareTo( "PPD_", 4 ) == COMPARE_EQUAL
&& aPrinter
.m_aInfo
.m_pParser
)
581 aValue
= aConfig
.ReadKey( aKey
);
582 const PPDKey
* pKey
= aPrinter
.m_aInfo
.m_pParser
->getKey( String( aKey
.Copy( 4 ), RTL_TEXTENCODING_ISO_8859_1
) );
585 aPrinter
.m_aInfo
.m_aContext
.
587 aValue
.Equals( "*nil" ) ? NULL
: pKey
->getValue( String( aValue
, RTL_TEXTENCODING_ISO_8859_1
) ),
591 else if( aKey
.Len() > 10 && aKey
.CompareTo("SubstFont_", 10 ) == COMPARE_EQUAL
)
593 aValue
= aConfig
.ReadKey( aKey
);
594 aPrinter
.m_aInfo
.m_aFontSubstitutes
[ OStringToOUString( aKey
.Copy( 10 ), RTL_TEXTENCODING_ISO_8859_1
) ] = OStringToOUString( aValue
, RTL_TEXTENCODING_ISO_8859_1
);
598 setDefaultPaper( aPrinter
.m_aInfo
.m_aContext
);
599 fillFontSubstitutions( aPrinter
.m_aInfo
);
601 // finally insert printer
602 FileBase::getFileURLFromSystemPath( aFile
.PathToFileName(), aPrinter
.m_aFile
);
603 aPrinter
.m_bModified
= false;
604 aPrinter
.m_aGroup
= aConfig
.GetGroupName( nGroup
);
605 std::hash_map
< OUString
, Printer
, OUStringHash
>::const_iterator find_it
=
606 m_aPrinters
.find( aPrinterName
);
607 if( find_it
!= m_aPrinters
.end() )
609 aPrinter
.m_aAlternateFiles
= find_it
->second
.m_aAlternateFiles
;
610 aPrinter
.m_aAlternateFiles
.push_front( find_it
->second
.m_aFile
);
612 m_aPrinters
[ aPrinterName
] = aPrinter
;
617 // set default printer
618 if( m_aPrinters
.size() )
620 if( m_aPrinters
.find( aDefaultPrinter
) == m_aPrinters
.end() )
621 aDefaultPrinter
= m_aPrinters
.begin()->first
;
624 aDefaultPrinter
= OUString();
625 m_aDefaultPrinter
= aDefaultPrinter
;
627 if( m_eType
!= Default
)
630 // add a default printer for every available print queue
631 // merge paper and font substitution from default printer,
632 // all else from global defaults
633 PrinterInfo
aMergeInfo( m_aGlobalDefaults
);
634 aMergeInfo
.m_aDriverName
= String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) );
635 aMergeInfo
.m_aFeatures
= String( RTL_CONSTASCII_USTRINGPARAM( "autoqueue" ) );
637 if( m_aDefaultPrinter
.getLength() )
639 PrinterInfo
aDefaultInfo( getPrinterInfo( m_aDefaultPrinter
) );
640 aMergeInfo
.m_bPerformFontSubstitution
= aDefaultInfo
.m_bPerformFontSubstitution
;
641 fillFontSubstitutions( aMergeInfo
);
643 const PPDKey
* pDefKey
= aDefaultInfo
.m_pParser
->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
644 const PPDKey
* pMergeKey
= aMergeInfo
.m_pParser
->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
645 const PPDValue
* pDefValue
= aDefaultInfo
.m_aContext
.getValue( pDefKey
);
646 const PPDValue
* pMergeValue
= pMergeKey
? pMergeKey
->getValue( pDefValue
->m_aOption
) : NULL
;
647 if( pMergeKey
&& pMergeValue
)
648 aMergeInfo
.m_aContext
.setValue( pMergeKey
, pMergeValue
);
651 getSystemPrintQueues();
652 for( ::std::list
< SystemPrintQueue
>::iterator it
= m_aSystemPrintQueues
.begin(); it
!= m_aSystemPrintQueues
.end(); ++it
)
654 String
aPrinterName( RTL_CONSTASCII_USTRINGPARAM( "<" ) );
655 aPrinterName
+= String( it
->m_aQueue
);
656 aPrinterName
.Append( '>' );
658 if( m_aPrinters
.find( aPrinterName
) != m_aPrinters
.end() )
659 // probably user made this one permanent in padmin
662 String
aCmd( m_aSystemPrintCommand
);
663 aCmd
.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PRINTER)" ) ), it
->m_aQueue
);
667 // initialize to merged defaults
668 aPrinter
.m_aInfo
= aMergeInfo
;
669 aPrinter
.m_aInfo
.m_aPrinterName
= aPrinterName
;
670 aPrinter
.m_aInfo
.m_aCommand
= aCmd
;
671 aPrinter
.m_aInfo
.m_aComment
= it
->m_aComment
;
672 aPrinter
.m_aInfo
.m_aLocation
= it
->m_aLocation
;
673 aPrinter
.m_bModified
= false;
674 aPrinter
.m_aGroup
= ByteString( aPrinterName
, aEncoding
); //provide group name in case user makes this one permanent in padmin
676 m_aPrinters
[ aPrinterName
] = aPrinter
;
680 // -----------------------------------------------------------------
682 void PrinterInfoManager::listPrinters( ::std::list
< OUString
>& rList
) const
684 ::std::hash_map
< OUString
, Printer
, OUStringHash
>::const_iterator it
;
686 for( it
= m_aPrinters
.begin(); it
!= m_aPrinters
.end(); ++it
)
687 rList
.push_back( it
->first
);
690 // -----------------------------------------------------------------
692 const PrinterInfo
& PrinterInfoManager::getPrinterInfo( const OUString
& rPrinter
) const
694 static PrinterInfo aEmptyInfo
;
695 ::std::hash_map
< OUString
, Printer
, OUStringHash
>::const_iterator it
= m_aPrinters
.find( rPrinter
);
697 DBG_ASSERT( it
!= m_aPrinters
.end(), "Do not ask for info about nonexistant printers" );
699 return it
!= m_aPrinters
.end() ? it
->second
.m_aInfo
: aEmptyInfo
;
702 // -----------------------------------------------------------------
704 void PrinterInfoManager::changePrinterInfo( const OUString
& rPrinter
, const PrinterInfo
& rNewInfo
)
706 ::std::hash_map
< OUString
, Printer
, OUStringHash
>::iterator it
= m_aPrinters
.find( rPrinter
);
708 DBG_ASSERT( it
!= m_aPrinters
.end(), "Do not change nonexistant printers" );
710 if( it
!= m_aPrinters
.end() )
712 it
->second
.m_aInfo
= rNewInfo
;
713 // recalculate font substitutions
714 fillFontSubstitutions( it
->second
.m_aInfo
);
715 it
->second
.m_bModified
= true;
716 writePrinterConfig();
720 // -----------------------------------------------------------------
722 // need to check writeability / creatability of config files
723 static bool checkWriteability( const OUString
& rUniPath
)
727 FileBase::getSystemPathFromFileURL( rUniPath
, aSysPath
);
728 SvFileStream
aStream( aSysPath
, STREAM_READ
| STREAM_WRITE
);
729 if( aStream
.IsOpen() && aStream
.IsWritable() )
734 bool PrinterInfoManager::writePrinterConfig()
736 // find at least one writeable config
737 ::std::hash_map
< OUString
, Config
*, OUStringHash
> files
;
738 ::std::hash_map
< OUString
, int, OUStringHash
> rofiles
;
739 ::std::hash_map
< OUString
, Config
*, OUStringHash
>::iterator file_it
;
741 for( ::std::list
< WatchFile
>::const_iterator wit
= m_aWatchFiles
.begin(); wit
!= m_aWatchFiles
.end(); ++wit
)
743 if( checkWriteability( wit
->m_aFilePath
) )
745 files
[ wit
->m_aFilePath
] = new Config( wit
->m_aFilePath
);
753 Config
* pGlobal
= files
.begin()->second
;
754 pGlobal
->SetGroup( GLOBAL_DEFAULTS_GROUP
);
755 pGlobal
->WriteKey( "DisableCUPS", m_bDisableCUPS
? "true" : "false" );
757 ::std::hash_map
< OUString
, Printer
, OUStringHash
>::iterator it
;
758 for( it
= m_aPrinters
.begin(); it
!= m_aPrinters
.end(); ++it
)
760 if( ! it
->second
.m_bModified
)
761 // printer was not changed, do nothing
764 // don't save autoqueue printers
765 sal_Int32 nIndex
= 0;
766 bool bAutoQueue
= false;
767 while( nIndex
!= -1 && ! bAutoQueue
)
769 OUString
aToken( it
->second
.m_aInfo
.m_aFeatures
.getToken( 0, ',', nIndex
) );
770 if( aToken
.getLength() && aToken
.compareToAscii( "autoqueue" ) == 0 )
776 if( it
->second
.m_aFile
.getLength() )
778 // check if file is writable
779 if( files
.find( it
->second
.m_aFile
) == files
.end() )
781 bool bInsertToNewFile
= false;
782 // maybe it is simply not inserted yet
783 if( rofiles
.find( it
->second
.m_aFile
) == rofiles
.end() )
785 if( checkWriteability( it
->second
.m_aFile
) )
786 files
[ it
->second
.m_aFile
] = new Config( it
->second
.m_aFile
);
788 bInsertToNewFile
= true;
791 bInsertToNewFile
= true;
792 // original file is read only, insert printer in a new writeable file
793 if( bInsertToNewFile
)
795 rofiles
[ it
->second
.m_aFile
] = 1;
796 // update alternate file list
797 // the remove operation ensures uniqueness of each alternate
798 it
->second
.m_aAlternateFiles
.remove( it
->second
.m_aFile
);
799 it
->second
.m_aAlternateFiles
.remove( files
.begin()->first
);
800 it
->second
.m_aAlternateFiles
.push_front( it
->second
.m_aFile
);
802 it
->second
.m_aFile
= files
.begin()->first
;
806 else // a new printer, write it to the first file available
807 it
->second
.m_aFile
= files
.begin()->first
;
809 if( ! it
->second
.m_aGroup
.getLength() ) // probably a new printer
810 it
->second
.m_aGroup
= OString( it
->first
.getStr(), it
->first
.getLength(), RTL_TEXTENCODING_UTF8
);
812 if( files
.find( it
->second
.m_aFile
) != files
.end() )
814 Config
* pConfig
= files
[ it
->second
.m_aFile
];
815 pConfig
->DeleteGroup( it
->second
.m_aGroup
); // else some old keys may remain
816 pConfig
->SetGroup( it
->second
.m_aGroup
);
818 ByteString
aValue( String( it
->second
.m_aInfo
.m_aDriverName
), RTL_TEXTENCODING_UTF8
);
820 aValue
+= ByteString( String( it
->first
), RTL_TEXTENCODING_UTF8
);
821 pConfig
->WriteKey( "Printer", aValue
);
822 pConfig
->WriteKey( "DefaultPrinter", it
->first
== m_aDefaultPrinter
? "1" : "0" );
823 pConfig
->WriteKey( "Location", ByteString( String( it
->second
.m_aInfo
.m_aLocation
), RTL_TEXTENCODING_UTF8
) );
824 pConfig
->WriteKey( "Comment", ByteString( String( it
->second
.m_aInfo
.m_aComment
), RTL_TEXTENCODING_UTF8
) );
825 pConfig
->WriteKey( "Command", ByteString( String( it
->second
.m_aInfo
.m_aCommand
), RTL_TEXTENCODING_UTF8
) );
826 pConfig
->WriteKey( "QuickCommand", ByteString( String( it
->second
.m_aInfo
.m_aQuickCommand
), RTL_TEXTENCODING_UTF8
) );
827 pConfig
->WriteKey( "Features", ByteString( String( it
->second
.m_aInfo
.m_aFeatures
), RTL_TEXTENCODING_UTF8
) );
828 pConfig
->WriteKey( "Copies", ByteString::CreateFromInt32( it
->second
.m_aInfo
.m_nCopies
) );
829 pConfig
->WriteKey( "Orientation", it
->second
.m_aInfo
.m_eOrientation
== orientation::Landscape
? "Landscape" : "Portrait" );
830 pConfig
->WriteKey( "PSLevel", ByteString::CreateFromInt32( it
->second
.m_aInfo
.m_nPSLevel
) );
831 pConfig
->WriteKey( "ColorDevice", ByteString::CreateFromInt32( it
->second
.m_aInfo
.m_nColorDevice
) );
832 pConfig
->WriteKey( "ColorDepth", ByteString::CreateFromInt32( it
->second
.m_aInfo
.m_nColorDepth
) );
833 aValue
= ByteString::CreateFromInt32( it
->second
.m_aInfo
.m_nLeftMarginAdjust
);
835 aValue
+= ByteString::CreateFromInt32( it
->second
.m_aInfo
.m_nRightMarginAdjust
);
837 aValue
+= ByteString::CreateFromInt32( it
->second
.m_aInfo
.m_nTopMarginAdjust
);
839 aValue
+= ByteString::CreateFromInt32( it
->second
.m_aInfo
.m_nBottomMarginAdjust
);
840 pConfig
->WriteKey( "MarginAdjust", aValue
);
842 if( it
->second
.m_aInfo
.m_aDriverName
.compareToAscii( "CUPS:", 5 ) != 0 )
844 // write PPDContext (not for CUPS)
845 for( int i
= 0; i
< it
->second
.m_aInfo
.m_aContext
.countValuesModified(); i
++ )
847 const PPDKey
* pKey
= it
->second
.m_aInfo
.m_aContext
.getModifiedKey( i
);
848 ByteString
aKey( "PPD_" );
849 aKey
+= ByteString( pKey
->getKey(), RTL_TEXTENCODING_ISO_8859_1
);
851 const PPDValue
* pValue
= it
->second
.m_aInfo
.m_aContext
.getValue( pKey
);
852 aValue
= pValue
? ByteString( pValue
->m_aOption
, RTL_TEXTENCODING_ISO_8859_1
) : ByteString( "*nil" );
853 pConfig
->WriteKey( aKey
, aValue
);
857 // write font substitution table
858 pConfig
->WriteKey( "PerformFontSubstitution", it
->second
.m_aInfo
.m_bPerformFontSubstitution
? "true" : "false" );
859 for( ::std::hash_map
< OUString
, OUString
, OUStringHash
>::const_iterator subst
= it
->second
.m_aInfo
.m_aFontSubstitutes
.begin();
860 subst
!= it
->second
.m_aInfo
.m_aFontSubstitutes
.end(); ++subst
)
862 ByteString
aKey( "SubstFont_" );
863 aKey
.Append( OUStringToOString( subst
->first
, RTL_TEXTENCODING_ISO_8859_1
).getStr() );
864 pConfig
->WriteKey( aKey
, OUStringToOString( subst
->second
, RTL_TEXTENCODING_ISO_8859_1
) );
869 // get rid of Config objects. this also writes any changes
870 for( file_it
= files
.begin(); file_it
!= files
.end(); ++file_it
)
871 delete file_it
->second
;
876 // -----------------------------------------------------------------
878 bool PrinterInfoManager::addPrinter( const OUString
& rPrinterName
, const OUString
& rDriverName
)
880 bool bSuccess
= false;
882 const PPDParser
* pParser
= NULL
;
883 if( m_aPrinters
.find( rPrinterName
) == m_aPrinters
.end() && ( pParser
= PPDParser::getParser( rDriverName
) ) )
886 aPrinter
.m_bModified
= true;
887 aPrinter
.m_aInfo
= m_aGlobalDefaults
;
888 aPrinter
.m_aInfo
.m_aDriverName
= rDriverName
;
889 aPrinter
.m_aInfo
.m_pParser
= pParser
;
890 aPrinter
.m_aInfo
.m_aContext
.setParser( pParser
);
891 aPrinter
.m_aInfo
.m_aPrinterName
= rPrinterName
;
893 fillFontSubstitutions( aPrinter
.m_aInfo
);
894 // merge PPD values with global defaults
895 for( int nPPDValueModified
= 0; nPPDValueModified
< m_aGlobalDefaults
.m_aContext
.countValuesModified(); nPPDValueModified
++ )
897 const PPDKey
* pDefKey
= m_aGlobalDefaults
.m_aContext
.getModifiedKey( nPPDValueModified
);
898 const PPDValue
* pDefValue
= m_aGlobalDefaults
.m_aContext
.getValue( pDefKey
);
899 const PPDKey
* pPrinterKey
= pDefKey
? aPrinter
.m_aInfo
.m_pParser
->getKey( pDefKey
->getKey() ) : NULL
;
900 if( pDefKey
&& pPrinterKey
)
901 // at least the options exist in both PPDs
905 const PPDValue
* pPrinterValue
= pPrinterKey
->getValue( pDefValue
->m_aOption
);
907 // the printer has a corresponding option for the key
908 aPrinter
.m_aInfo
.m_aContext
.setValue( pPrinterKey
, pPrinterValue
);
911 aPrinter
.m_aInfo
.m_aContext
.setValue( pPrinterKey
, NULL
);
915 m_aPrinters
[ rPrinterName
] = aPrinter
;
917 #if OSL_DEBUG_LEVEL > 1
918 fprintf( stderr
, "new printer %s, level = %d, colordevice = %d, depth = %d\n",
919 OUStringToOString( rPrinterName
, osl_getThreadTextEncoding() ).getStr(),
920 m_aPrinters
[rPrinterName
].m_aInfo
.m_nPSLevel
,
921 m_aPrinters
[rPrinterName
].m_aInfo
.m_nColorDevice
,
922 m_aPrinters
[rPrinterName
].m_aInfo
.m_nColorDepth
);
924 // comment: logically one should writePrinterConfig() here
925 // but immediately after addPrinter() a changePrinterInfo()
926 // will follow (see padmin code), which writes it again,
927 // so we can currently save some performance here
932 // -----------------------------------------------------------------
934 bool PrinterInfoManager::removePrinter( const OUString
& rPrinterName
, bool bCheckOnly
)
936 bool bSuccess
= true;
938 ::std::hash_map
< OUString
, Printer
, OUStringHash
>::iterator it
= m_aPrinters
.find( rPrinterName
);
939 if( it
!= m_aPrinters
.end() )
941 if( it
->second
.m_aFile
.getLength() )
943 // this printer already exists in a config file
946 // check writeability of config file(s)
947 if( ! checkWriteability( it
->second
.m_aFile
) )
951 for( std::list
< OUString
>::const_iterator file_it
= it
->second
.m_aAlternateFiles
.begin();
952 file_it
!= it
->second
.m_aAlternateFiles
.end() && bSuccess
; ++file_it
)
954 if( ! checkWriteability( *file_it
) )
958 if( bSuccess
&& ! bCheckOnly
)
961 Config
aConfig( it
->second
.m_aFile
);
962 aConfig
.DeleteGroup( it
->second
.m_aGroup
);
964 for( std::list
< OUString
>::const_iterator file_it
= it
->second
.m_aAlternateFiles
.begin();
965 file_it
!= it
->second
.m_aAlternateFiles
.end() && bSuccess
; ++file_it
)
967 Config
aAltConfig( *file_it
);
968 aAltConfig
.DeleteGroup( it
->second
.m_aGroup
);
973 if( bSuccess
&& ! bCheckOnly
)
975 m_aPrinters
.erase( it
);
976 // need this here because someone may call
977 // checkPrintersChanged after the removal
978 // but then other added printers were not flushed
979 // to disk, so they are discarded
980 writePrinterConfig();
986 // -----------------------------------------------------------------
988 bool PrinterInfoManager::setDefaultPrinter( const OUString
& rPrinterName
)
990 bool bSuccess
= false;
992 ::std::hash_map
< OUString
, Printer
, OUStringHash
>::iterator it
= m_aPrinters
.find( rPrinterName
);
993 if( it
!= m_aPrinters
.end() )
996 it
->second
.m_bModified
= true;
997 if( ( it
= m_aPrinters
.find( m_aDefaultPrinter
) ) != m_aPrinters
.end() )
998 it
->second
.m_bModified
= true;
999 m_aDefaultPrinter
= rPrinterName
;
1000 writePrinterConfig();
1005 // -----------------------------------------------------------------
1006 bool PrinterInfoManager::addOrRemovePossible() const
1011 // -----------------------------------------------------------------
1013 void PrinterInfoManager::fillFontSubstitutions( PrinterInfo
& rInfo
) const
1015 PrintFontManager
& rFontManager( PrintFontManager::get() );
1016 rInfo
.m_aFontSubstitutions
.clear();
1018 if( ! rInfo
.m_bPerformFontSubstitution
||
1019 ! rInfo
.m_aFontSubstitutes
.size() )
1022 ::std::list
< FastPrintFontInfo
> aFonts
;
1023 ::std::hash_map
< OUString
, ::std::list
< FastPrintFontInfo
>, OUStringHash
> aPrinterFonts
;
1024 rFontManager
.getFontListWithFastInfo( aFonts
, rInfo
.m_pParser
);
1026 // get builtin fonts
1027 ::std::list
< FastPrintFontInfo
>::const_iterator it
;
1028 for( it
= aFonts
.begin(); it
!= aFonts
.end(); ++it
)
1029 if( it
->m_eType
== fonttype::Builtin
)
1030 aPrinterFonts
[ it
->m_aFamilyName
.toAsciiLowerCase() ].push_back( *it
);
1032 // map lower case, so build a local copy of the font substitutions
1033 ::std::hash_map
< OUString
, OUString
, OUStringHash
> aSubstitutions
;
1034 ::std::hash_map
< OUString
, OUString
, OUStringHash
>::const_iterator subst
;
1035 for( subst
= rInfo
.m_aFontSubstitutes
.begin(); subst
!= rInfo
.m_aFontSubstitutes
.end(); ++subst
)
1037 OUString
aFamily( subst
->first
.toAsciiLowerCase() );
1038 // first look if there is a builtin of this family
1039 // in this case override the substitution table
1040 if( aPrinterFonts
.find( aFamily
) != aPrinterFonts
.end() )
1041 aSubstitutions
[ aFamily
] = aFamily
;
1043 aSubstitutions
[ aFamily
] = subst
->second
.toAsciiLowerCase();
1047 // now find substitutions
1048 for( it
= aFonts
.begin(); it
!= aFonts
.end(); ++it
)
1050 if( it
->m_eType
!= fonttype::Builtin
)
1052 OUString
aFamily( it
->m_aFamilyName
.toAsciiLowerCase() );
1053 subst
= aSubstitutions
.find( aFamily
);
1054 if( subst
!= aSubstitutions
.end() )
1056 // search a substitution
1057 const ::std::list
< FastPrintFontInfo
>& rBuiltins( aPrinterFonts
[ aSubstitutions
[ aFamily
] ] );
1058 ::std::list
< FastPrintFontInfo
>::const_iterator builtin
;
1059 int nLastMatch
= -10000;
1060 fontID nSubstitute
= -1;
1061 for( builtin
= rBuiltins
.begin(); builtin
!= rBuiltins
.end(); ++builtin
)
1065 if( builtin
->m_eItalic
== it
->m_eItalic
)
1068 nDiff
= builtin
->m_eWeight
- it
->m_eWeight
;
1069 nDiff
= nDiff
< 0 ? -nDiff
: nDiff
;
1070 nMatch
+= 4000 - 1000*nDiff
;
1072 nDiff
= builtin
->m_eWidth
- it
->m_eWidth
;
1073 nDiff
= nDiff
< 0 ? -nDiff
: nDiff
;
1074 nMatch
+= 2000 - 500*nDiff
;
1076 if( nMatch
> nLastMatch
)
1078 nLastMatch
= nMatch
;
1079 nSubstitute
= builtin
->m_nID
;
1082 if( nSubstitute
!= -1 )
1084 rInfo
.m_aFontSubstitutions
[ it
->m_nID
] = nSubstitute
;
1085 #if OSL_DEBUG_LEVEL > 2
1086 FastPrintFontInfo aInfo
;
1087 rFontManager
.getFontFastInfo( nSubstitute
, aInfo
);
1089 "substitute %s %s %d %d\n"
1090 " -> %s %s %d %d\n",
1091 OUStringToOString( it
->m_aFamilyName
, RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1092 it
->m_eItalic
== italic::Upright
? "r" : it
->m_eItalic
== italic::Oblique
? "o" : it
->m_eItalic
== italic::Italic
? "i" : "u",
1096 OUStringToOString( aInfo
.m_aFamilyName
, RTL_TEXTENCODING_ISO_8859_1
).getStr(),
1097 aInfo
.m_eItalic
== italic::Upright
? "r" : aInfo
.m_eItalic
== italic::Oblique
? "o" : aInfo
.m_eItalic
== italic::Italic
? "i" : "u",
1108 // -----------------------------------------------------------------
1110 void PrinterInfoManager::getSystemPrintCommands( std::list
< OUString
>& rCommands
)
1112 if( m_pQueueInfo
&& m_pQueueInfo
->hasChanged() )
1114 m_aSystemPrintCommand
= m_pQueueInfo
->getCommand();
1115 m_pQueueInfo
->getSystemQueues( m_aSystemPrintQueues
);
1116 delete m_pQueueInfo
, m_pQueueInfo
= NULL
;
1119 std::list
< SystemPrintQueue
>::const_iterator it
;
1121 String
aPrinterConst( RTL_CONSTASCII_USTRINGPARAM( "(PRINTER)" ) );
1122 for( it
= m_aSystemPrintQueues
.begin(); it
!= m_aSystemPrintQueues
.end(); ++it
)
1124 String
aCmd( m_aSystemPrintCommand
);
1125 aCmd
.SearchAndReplace( aPrinterConst
, it
->m_aQueue
);
1126 rCommands
.push_back( aCmd
);
1130 const std::list
< PrinterInfoManager::SystemPrintQueue
>& PrinterInfoManager::getSystemPrintQueues()
1132 if( m_pQueueInfo
&& m_pQueueInfo
->hasChanged() )
1134 m_aSystemPrintCommand
= m_pQueueInfo
->getCommand();
1135 m_pQueueInfo
->getSystemQueues( m_aSystemPrintQueues
);
1136 delete m_pQueueInfo
, m_pQueueInfo
= NULL
;
1139 return m_aSystemPrintQueues
;
1142 bool PrinterInfoManager::checkFeatureToken( const rtl::OUString
& rPrinterName
, const char* pToken
) const
1144 const PrinterInfo
& rPrinterInfo( getPrinterInfo( rPrinterName
) );
1145 sal_Int32 nIndex
= 0;
1146 while( nIndex
!= -1 )
1148 OUString aOuterToken
= rPrinterInfo
.m_aFeatures
.getToken( 0, ',', nIndex
);
1149 sal_Int32 nInnerIndex
= 0;
1150 OUString aInnerToken
= aOuterToken
.getToken( 0, '=', nInnerIndex
);
1151 if( aInnerToken
.equalsIgnoreAsciiCaseAscii( pToken
) )
1157 FILE* PrinterInfoManager::startSpool( const OUString
& rPrintername
, bool bQuickCommand
)
1159 const PrinterInfo
& rPrinterInfo
= getPrinterInfo (rPrintername
);
1160 const rtl::OUString
& rCommand
= (bQuickCommand
&& rPrinterInfo
.m_aQuickCommand
.getLength() ) ?
1161 rPrinterInfo
.m_aQuickCommand
: rPrinterInfo
.m_aCommand
;
1162 rtl::OString aShellCommand
= OUStringToOString (rCommand
, RTL_TEXTENCODING_ISO_8859_1
);
1163 aShellCommand
+= rtl::OString( " 2>/dev/null" );
1165 return popen (aShellCommand
.getStr(), "w");
1168 int PrinterInfoManager::endSpool( const OUString
& /*rPrintername*/, const OUString
& /*rJobTitle*/, FILE* pFile
, const JobData
& /*rDocumentJobData*/ )
1170 return (0 == pclose( pFile
));
1173 void PrinterInfoManager::setupJobContextData( JobData
& rData
)
1175 std::hash_map
< OUString
, Printer
, OUStringHash
>::iterator it
=
1176 m_aPrinters
.find( rData
.m_aPrinterName
);
1177 if( it
!= m_aPrinters
.end() )
1179 rData
.m_pParser
= it
->second
.m_aInfo
.m_pParser
;
1180 rData
.m_aContext
= it
->second
.m_aInfo
.m_aContext
;
1184 void PrinterInfoManager::setDefaultPaper( PPDContext
& rContext
) const
1186 if( ! rContext
.getParser() )
1189 const PPDKey
* pPageSizeKey
= rContext
.getParser()->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
1190 if( ! pPageSizeKey
)
1193 int nModified
= rContext
.countValuesModified();
1194 while( nModified
-- &&
1195 rContext
.getModifiedKey( nModified
) != pPageSizeKey
)
1198 if( nModified
>= 0 ) // paper was set already, do not modify
1200 #if OSL_DEBUG_LEVEL > 1
1201 fprintf( stderr
, "not setting default paper, already set %s\n",
1202 OUStringToOString( rContext
.getValue( pPageSizeKey
)->m_aOption
, RTL_TEXTENCODING_ISO_8859_1
).getStr() );
1207 // paper not set, fill in default value
1208 const PPDValue
* pPaperVal
= NULL
;
1209 int nValues
= pPageSizeKey
->countValues();
1210 for( int i
= 0; i
< nValues
&& ! pPaperVal
; i
++ )
1212 const PPDValue
* pVal
= pPageSizeKey
->getValue( i
);
1213 if( pVal
->m_aOption
.EqualsIgnoreCaseAscii( m_aSystemDefaultPaper
.getStr() ) )
1218 #if OSL_DEBUG_LEVEL > 1
1219 fprintf( stderr
, "setting default paper %s\n", OUStringToOString( pPaperVal
->m_aOption
, RTL_TEXTENCODING_ISO_8859_1
).getStr() );
1221 rContext
.setValue( pPageSizeKey
, pPaperVal
);
1222 #if OSL_DEBUG_LEVEL > 1
1223 pPaperVal
= rContext
.getValue( pPageSizeKey
);
1224 fprintf( stderr
, "-> got paper %s\n", OUStringToOString( pPaperVal
->m_aOption
, RTL_TEXTENCODING_ISO_8859_1
).getStr() );
1229 // -----------------------------------------------------------------
1231 SystemQueueInfo::SystemQueueInfo() :
1237 SystemQueueInfo::~SystemQueueInfo()
1242 bool SystemQueueInfo::hasChanged() const
1244 MutexGuard
aGuard( m_aMutex
);
1245 bool bChanged
= m_bChanged
;
1249 void SystemQueueInfo::getSystemQueues( std::list
< PrinterInfoManager::SystemPrintQueue
>& rQueues
)
1251 MutexGuard
aGuard( m_aMutex
);
1252 rQueues
= m_aQueues
;
1256 OUString
SystemQueueInfo::getCommand() const
1258 MutexGuard
aGuard( m_aMutex
);
1259 OUString aRet
= m_aCommand
;
1263 struct SystemCommandParameters
;
1264 typedef void(* tokenHandler
)(const std::list
< rtl::OString
>&,
1265 std::list
< PrinterInfoManager::SystemPrintQueue
>&,
1266 const SystemCommandParameters
*);
1268 struct SystemCommandParameters
1270 const char* pQueueCommand
;
1271 const char* pPrintCommand
;
1272 const char* pForeToken
;
1273 const char* pAftToken
;
1274 unsigned int nForeTokenCount
;
1275 tokenHandler pHandler
;
1278 #if ! (defined(LINUX) || defined(NETBSD) || defined(FREEBSD) || defined(MACOSX))
1279 static void lpgetSysQueueTokenHandler(
1280 const std::list
< rtl::OString
>& i_rLines
,
1281 std::list
< PrinterInfoManager::SystemPrintQueue
>& o_rQueues
,
1282 const SystemCommandParameters
* )
1284 rtl_TextEncoding aEncoding
= osl_getThreadTextEncoding();
1285 std::hash_set
< OUString
, OUStringHash
> aUniqueSet
;
1286 std::hash_set
< OUString
, OUStringHash
> aOnlySet
;
1287 aUniqueSet
.insert( OUString( RTL_CONSTASCII_USTRINGPARAM( "_all" ) ) );
1288 aUniqueSet
.insert( OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) );
1290 // the eventual "all" attribute of the "_all" queue tells us, which
1291 // printers are to be used for this user at all
1294 rtl::OString
aAllLine( "_all:" );
1295 rtl::OString
aAllAttr( "all=" );
1296 for( std::list
< rtl::OString
>::const_iterator it
= i_rLines
.begin();
1297 it
!= i_rLines
.end(); ++it
)
1299 if( it
->indexOf( aAllLine
, 0 ) == 0 )
1301 // now find the "all" attribute
1303 while( it
!= i_rLines
.end() )
1305 rtl::OString
aClean( WhitespaceToSpace( *it
) );
1306 if( aClean
.indexOf( aAllAttr
, 0 ) == 0 )
1308 // insert the comma separated entries into the set of printers to use
1309 sal_Int32 nPos
= aAllAttr
.getLength();
1312 OString
aTok( aClean
.getToken( 0, ',', nPos
) );
1313 if( aTok
.getLength() > 0 )
1314 aOnlySet
.insert( rtl::OStringToOUString( aTok
, aEncoding
) );
1323 bool bInsertAttribute
= false;
1324 rtl::OString
aDescrStr( "description=" );
1325 rtl::OString
aLocStr( "location=" );
1326 for( std::list
< rtl::OString
>::const_iterator it
= i_rLines
.begin();
1327 it
!= i_rLines
.end(); ++it
)
1330 // find the begin of a new printer section
1331 nPos
= it
->indexOf( ':', 0 );
1334 OUString
aSysQueue( rtl::OStringToOUString( it
->copy( 0, nPos
), aEncoding
) );
1335 // do not insert duplicates (e.g. lpstat tends to produce such lines)
1336 // in case there was a "_all" section, insert only those printer explicitly
1337 // set in the "all" attribute
1338 if( aUniqueSet
.find( aSysQueue
) == aUniqueSet
.end() &&
1339 ( aOnlySet
.empty() || aOnlySet
.find( aSysQueue
) != aOnlySet
.end() )
1342 o_rQueues
.push_back( PrinterInfoManager::SystemPrintQueue() );
1343 o_rQueues
.back().m_aQueue
= aSysQueue
;
1344 o_rQueues
.back().m_aLocation
= aSysQueue
;
1345 aUniqueSet
.insert( aSysQueue
);
1346 bInsertAttribute
= true;
1349 bInsertAttribute
= false;
1352 if( bInsertAttribute
&& ! o_rQueues
.empty() )
1354 // look for "description" attribute, insert as comment
1355 nPos
= it
->indexOf( aDescrStr
, 0 );
1358 ByteString
aComment( WhitespaceToSpace( it
->copy(nPos
+12) ) );
1359 if( aComment
.Len() > 0 )
1360 o_rQueues
.back().m_aComment
= String( aComment
, aEncoding
);
1363 // look for "location" attribute, inser as location
1364 nPos
= it
->indexOf( aLocStr
, 0 );
1367 ByteString
aLoc( WhitespaceToSpace( it
->copy(nPos
+9) ) );
1368 if( aLoc
.Len() > 0 )
1369 o_rQueues
.back().m_aLocation
= String( aLoc
, aEncoding
);
1376 static void standardSysQueueTokenHandler(
1377 const std::list
< rtl::OString
>& i_rLines
,
1378 std::list
< PrinterInfoManager::SystemPrintQueue
>& o_rQueues
,
1379 const SystemCommandParameters
* i_pParms
)
1381 rtl_TextEncoding aEncoding
= osl_getThreadTextEncoding();
1382 std::hash_set
< OUString
, OUStringHash
> aUniqueSet
;
1383 rtl::OString
aForeToken( i_pParms
->pForeToken
);
1384 rtl::OString
aAftToken( i_pParms
->pAftToken
);
1385 /* Normal Unix print queue discovery, also used for Darwin 5 LPR printing
1387 for( std::list
< rtl::OString
>::const_iterator it
= i_rLines
.begin();
1388 it
!= i_rLines
.end(); ++it
)
1392 // search for a line describing a printer:
1393 // find if there are enough tokens before the name
1394 for( unsigned int i
= 0; i
< i_pParms
->nForeTokenCount
&& nPos
!= -1; i
++ )
1396 nPos
= it
->indexOf( aForeToken
, nPos
);
1397 if( nPos
!= -1 && it
->getLength() >= nPos
+aForeToken
.getLength() )
1398 nPos
+= aForeToken
.getLength();
1402 // find if there is the token after the queue
1403 sal_Int32 nAftPos
= it
->indexOf( aAftToken
, nPos
);
1406 // get the queue name between fore and aft tokens
1407 OUString
aSysQueue( rtl::OStringToOUString( it
->copy( nPos
, nAftPos
- nPos
), aEncoding
) );
1408 // do not insert duplicates (e.g. lpstat tends to produce such lines)
1409 if( aUniqueSet
.find( aSysQueue
) == aUniqueSet
.end() )
1411 o_rQueues
.push_back( PrinterInfoManager::SystemPrintQueue() );
1412 o_rQueues
.back().m_aQueue
= aSysQueue
;
1413 o_rQueues
.back().m_aLocation
= aSysQueue
;
1414 aUniqueSet
.insert( aSysQueue
);
1421 static const struct SystemCommandParameters aParms
[] =
1423 #if defined(LINUX) || defined(NETBSD) || defined(FREEBSD) || defined(MACOSX)
1424 { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler
},
1425 { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler
},
1426 { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler
}
1428 { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpget list", "lp -d \"(PRINTER)\"", "", ":", 0, lpgetSysQueueTokenHandler
},
1429 { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler
},
1430 { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler
},
1431 { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler
}
1435 void SystemQueueInfo::run()
1439 std::list
< rtl::OString
> aLines
;
1441 /* Discover which command we can use to get a list of all printer queues */
1442 for( unsigned int i
= 0; i
< sizeof(aParms
)/sizeof(aParms
[0]); i
++ )
1445 rtl::OStringBuffer
aCmdLine( 128 );
1446 aCmdLine
.append( aParms
[i
].pQueueCommand
);
1447 #if OSL_DEBUG_LEVEL > 1
1448 fprintf( stderr
, "trying print queue command \"%s\" ... ", aParms
[i
].pQueueCommand
);
1450 aCmdLine
.append( " 2>/dev/null" );
1451 if( (pPipe
= popen( aCmdLine
.getStr(), "r" )) )
1453 while( fgets( pBuffer
, 1024, pPipe
) )
1454 aLines
.push_back( rtl::OString( pBuffer
) );
1455 if( ! pclose( pPipe
) )
1457 std::list
< PrinterInfoManager::SystemPrintQueue
> aSysPrintQueues
;
1458 aParms
[i
].pHandler( aLines
, aSysPrintQueues
, &(aParms
[i
]) );
1459 MutexGuard
aGuard( m_aMutex
);
1461 m_aQueues
= aSysPrintQueues
;
1462 m_aCommand
= rtl::OUString::createFromAscii( aParms
[i
].pPrintCommand
);
1463 #if OSL_DEBUG_LEVEL > 1
1464 fprintf( stderr
, "success\n" );
1469 #if OSL_DEBUG_LEVEL > 1
1470 fprintf( stderr
, "failed\n" );