/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_vcl.hxx" #include #include #include #include "cupsmgr.hxx" #include "vcl/fontmanager.hxx" #include "vcl/strhelper.hxx" #include "unx/saldata.hxx" #include "tools/urlobj.hxx" #include "tools/stream.hxx" #include "tools/debug.hxx" #include "tools/config.hxx" #include "i18npool/paper.hxx" #include "rtl/strbuf.hxx" #include "osl/thread.hxx" #include "osl/mutex.hxx" #include "osl/process.h" // filename of configuration files #define PRINT_FILENAME "psprint.conf" // the group of the global defaults #define GLOBAL_DEFAULTS_GROUP "__Global_Printer_Defaults__" #include using namespace psp; using namespace rtl; using namespace osl; namespace psp { class SystemQueueInfo : public Thread { mutable Mutex m_aMutex; bool m_bChanged; std::list< PrinterInfoManager::SystemPrintQueue > m_aQueues; OUString m_aCommand; virtual void run(); public: SystemQueueInfo(); ~SystemQueueInfo(); bool hasChanged() const; OUString getCommand() const; // sets changed status to false; therefore not const void getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues ); }; } // namespace /* * class PrinterInfoManager */ // ----------------------------------------------------------------- PrinterInfoManager& PrinterInfoManager::get() { SalData* pSalData = GetSalData(); if( ! pSalData->m_pPIManager ) { pSalData->m_pPIManager = CUPSManager::tryLoadCUPS(); if( ! pSalData->m_pPIManager ) pSalData->m_pPIManager = new PrinterInfoManager(); pSalData->m_pPIManager->initialize(); #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "PrinterInfoManager::get create Manager of type %d\n", pSalData->m_pPIManager->getType() ); #endif } return *pSalData->m_pPIManager; } void PrinterInfoManager::release() { SalData* pSalData = GetSalData(); delete pSalData->m_pPIManager; pSalData->m_pPIManager = NULL; } // ----------------------------------------------------------------- PrinterInfoManager::PrinterInfoManager( Type eType ) : m_pQueueInfo( NULL ), m_eType( eType ), m_bUseIncludeFeature( false ), m_bUseJobPatch( true ), m_aSystemDefaultPaper( RTL_CONSTASCII_USTRINGPARAM( "A4" ) ), m_bDisableCUPS( false ) { if( eType == Default ) m_pQueueInfo = new SystemQueueInfo(); initSystemDefaultPaper(); } // ----------------------------------------------------------------- PrinterInfoManager::~PrinterInfoManager() { delete m_pQueueInfo; #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "PrinterInfoManager: destroyed Manager of type %d\n", getType() ); #endif } // ----------------------------------------------------------------- bool PrinterInfoManager::isCUPSDisabled() const { return m_bDisableCUPS; } // ----------------------------------------------------------------- void PrinterInfoManager::setCUPSDisabled( bool bDisable ) { m_bDisableCUPS = bDisable; writePrinterConfig(); // actually we know the printers changed // however this triggers reinitialization the right way checkPrintersChanged( true ); } // ----------------------------------------------------------------- void PrinterInfoManager::initSystemDefaultPaper() { m_aSystemDefaultPaper = rtl::OStringToOUString( PaperInfo::toPSName(PaperInfo::getSystemDefaultPaper().getPaper()), RTL_TEXTENCODING_UTF8); } // ----------------------------------------------------------------- bool PrinterInfoManager::checkPrintersChanged( bool bWait ) { // check if files were created, deleted or modified since initialize() ::std::list< WatchFile >::const_iterator it; bool bChanged = false; for( it = m_aWatchFiles.begin(); it != m_aWatchFiles.end() && ! bChanged; ++it ) { DirectoryItem aItem; if( DirectoryItem::get( it->m_aFilePath, aItem ) ) { if( it->m_aModified.Seconds != 0 ) bChanged = true; // file probably has vanished } else { FileStatus aStatus( FileStatusMask_ModifyTime ); if( aItem.getFileStatus( aStatus ) ) bChanged = true; // unlikely but not impossible else { TimeValue aModified = aStatus.getModifyTime(); if( aModified.Seconds != it->m_aModified.Seconds ) bChanged = true; } } } if( bWait && m_pQueueInfo ) { #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "syncing printer discovery thread\n" ); #endif m_pQueueInfo->join(); #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "done: syncing printer discovery thread\n" ); #endif } if( ! bChanged && m_pQueueInfo ) bChanged = m_pQueueInfo->hasChanged(); if( bChanged ) { initialize(); } return bChanged; } // ----------------------------------------------------------------- void PrinterInfoManager::initialize() { m_bUseIncludeFeature = false; rtl_TextEncoding aEncoding = gsl_getSystemTextEncoding(); m_aPrinters.clear(); m_aWatchFiles.clear(); OUString aDefaultPrinter; // first initialize the global defaults // have to iterate over all possible files // there should be only one global setup section in all // available config files m_aGlobalDefaults = PrinterInfo(); // need a parser for the PPDContext. generic printer should do. m_aGlobalDefaults.m_pParser = PPDParser::getParser( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ); m_aGlobalDefaults.m_aContext.setParser( m_aGlobalDefaults.m_pParser ); m_aGlobalDefaults.m_bPerformFontSubstitution = true; m_bDisableCUPS = false; if( ! m_aGlobalDefaults.m_pParser ) { #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "Error: no default PPD file SGENPRT available, shutting down psprint...\n" ); #endif return; } std::list< OUString > aDirList; psp::getPrinterPathList( aDirList, NULL ); std::list< OUString >::const_iterator print_dir_it; for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it ) { INetURLObject aFile( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL ); aFile.Append( String( RTL_CONSTASCII_USTRINGPARAM( PRINT_FILENAME ) ) ); Config aConfig( aFile.PathToFileName() ); if( aConfig.HasGroup( GLOBAL_DEFAULTS_GROUP ) ) { #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "found global defaults in %s\n", OUStringToOString( aFile.PathToFileName(), RTL_TEXTENCODING_ISO_8859_1 ).getStr() ); #endif aConfig.SetGroup( GLOBAL_DEFAULTS_GROUP ); ByteString aValue( aConfig.ReadKey( "Copies" ) ); if( aValue.Len() ) m_aGlobalDefaults.m_nCopies = aValue.ToInt32(); aValue = aConfig.ReadKey( "Orientation" ); if( aValue.Len() ) m_aGlobalDefaults.m_eOrientation = aValue.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape : orientation::Portrait; aValue = aConfig.ReadKey( "MarginAdjust" ); if( aValue.Len() ) { m_aGlobalDefaults.m_nLeftMarginAdjust = aValue.GetToken( 0, ',' ).ToInt32(); m_aGlobalDefaults.m_nRightMarginAdjust = aValue.GetToken( 1, ',' ).ToInt32(); m_aGlobalDefaults.m_nTopMarginAdjust = aValue.GetToken( 2, ',' ).ToInt32(); m_aGlobalDefaults.m_nBottomMarginAdjust = aValue.GetToken( 3, ',' ).ToInt32(); } aValue = aConfig.ReadKey( "ColorDepth", "24" ); if( aValue.Len() ) m_aGlobalDefaults.m_nColorDepth = aValue.ToInt32(); aValue = aConfig.ReadKey( "ColorDevice" ); if( aValue.Len() ) m_aGlobalDefaults.m_nColorDevice = aValue.ToInt32(); aValue = aConfig.ReadKey( "PSLevel" ); if( aValue.Len() ) m_aGlobalDefaults.m_nPSLevel = aValue.ToInt32(); aValue = aConfig.ReadKey( "PDFDevice" ); if( aValue.Len() ) m_aGlobalDefaults.m_nPDFDevice = aValue.ToInt32(); aValue = aConfig.ReadKey( "PerformFontSubstitution" ); if( aValue.Len() ) { if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) ) m_aGlobalDefaults.m_bPerformFontSubstitution = true; else m_aGlobalDefaults.m_bPerformFontSubstitution = false; } aValue = aConfig.ReadKey( "DisableCUPS" ); if( aValue.Len() ) { if( aValue.Equals( "1" ) || aValue.EqualsIgnoreCaseAscii( "true" ) ) m_bDisableCUPS = true; else m_bDisableCUPS = false; } // get the PPDContext of global JobData for( int nKey = 0; nKey < aConfig.GetKeyCount(); nKey++ ) { ByteString aKey( aConfig.GetKeyName( nKey ) ); if( aKey.CompareTo( "PPD_", 4 ) == COMPARE_EQUAL ) { aValue = aConfig.ReadKey( aKey ); const PPDKey* pKey = m_aGlobalDefaults.m_pParser->getKey( String( aKey.Copy( 4 ), RTL_TEXTENCODING_ISO_8859_1 ) ); if( pKey ) { m_aGlobalDefaults.m_aContext. setValue( pKey, aValue.Equals( "*nil" ) ? NULL : pKey->getValue( String( aValue, RTL_TEXTENCODING_ISO_8859_1 ) ), sal_True ); } } else if( aKey.Len() > 10 && aKey.CompareTo("SubstFont_", 10 ) == COMPARE_EQUAL ) { aValue = aConfig.ReadKey( aKey ); m_aGlobalDefaults.m_aFontSubstitutes[ OStringToOUString( aKey.Copy( 10 ), RTL_TEXTENCODING_ISO_8859_1 ) ] = OStringToOUString( aValue, RTL_TEXTENCODING_ISO_8859_1 ); } } #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "global settings: fontsubst = %s, %d substitutes\n", m_aGlobalDefaults.m_bPerformFontSubstitution ? "true" : "false", (int)m_aGlobalDefaults.m_aFontSubstitutes.size() ); #endif } } setDefaultPaper( m_aGlobalDefaults.m_aContext ); fillFontSubstitutions( m_aGlobalDefaults ); // now collect all available printers for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it ) { INetURLObject aDir( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL ); INetURLObject aFile( aDir ); aFile.Append( String( RTL_CONSTASCII_USTRINGPARAM( PRINT_FILENAME ) ) ); // check directory validity OUString aUniPath; FileBase::getFileURLFromSystemPath( aDir.PathToFileName(), aUniPath ); Directory aDirectory( aUniPath ); if( aDirectory.open() ) continue; aDirectory.close(); FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aUniPath ); FileStatus aStatus( FileStatusMask_ModifyTime ); DirectoryItem aItem; // setup WatchFile list WatchFile aWatchFile; aWatchFile.m_aFilePath = aUniPath; if( ! DirectoryItem::get( aUniPath, aItem ) && ! aItem.getFileStatus( aStatus ) ) { aWatchFile.m_aModified = aStatus.getModifyTime(); } else { aWatchFile.m_aModified.Seconds = 0; aWatchFile.m_aModified.Nanosec = 0; } m_aWatchFiles.push_back( aWatchFile ); Config aConfig( aFile.PathToFileName() ); for( int nGroup = 0; nGroup < aConfig.GetGroupCount(); nGroup++ ) { aConfig.SetGroup( aConfig.GetGroupName( nGroup ) ); ByteString aValue = aConfig.ReadKey( "Printer" ); if( aValue.Len() ) { OUString aPrinterName; int nNamePos = aValue.Search( '/' ); // check for valid value of "Printer" if( nNamePos == STRING_NOTFOUND ) continue; Printer aPrinter; // initialize to global defaults aPrinter.m_aInfo = m_aGlobalDefaults; // global settings do not default the printer substitution // list ! the substitution list in there is only used for // newly created printers aPrinter.m_aInfo.m_aFontSubstitutes.clear(); aPrinter.m_aInfo.m_aFontSubstitutions.clear(); aPrinterName = String( aValue.Copy( nNamePos+1 ), RTL_TEXTENCODING_UTF8 ); aPrinter.m_aInfo.m_aPrinterName = aPrinterName; aPrinter.m_aInfo.m_aDriverName = String( aValue.Copy( 0, nNamePos ), RTL_TEXTENCODING_UTF8 ); // set parser, merge settings // don't do this for CUPS printers as this is done // by the CUPS system itself if( aPrinter.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) != 0 ) { aPrinter.m_aInfo.m_pParser = PPDParser::getParser( aPrinter.m_aInfo.m_aDriverName ); aPrinter.m_aInfo.m_aContext.setParser( aPrinter.m_aInfo.m_pParser ); // note: setParser also purges the context // ignore this printer if its driver is not found if( ! aPrinter.m_aInfo.m_pParser ) continue; // merge the ppd context keys if the printer has the same keys and values // this is a bit tricky, since it involves mixing two PPDs // without constraints which might end up badly // this feature should be use with caution // it is mainly to select default paper sizes for new printers for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ ) { const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified ); const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey ); const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL; if( pDefKey && pPrinterKey ) // at least the options exist in both PPDs { if( pDefValue ) { const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption ); if( pPrinterValue ) // the printer has a corresponding option for the key aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue ); } else aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL ); } } aValue = aConfig.ReadKey( "Command" ); // no printer without a command if( ! aValue.Len() ) { /* TODO: * porters: please append your platform to the Solaris * case if your platform has SystemV printing per default. */ #if defined SOLARIS aValue = "lp"; #else aValue = "lpr"; #endif } aPrinter.m_aInfo.m_aCommand = String( aValue, RTL_TEXTENCODING_UTF8 ); } aValue = aConfig.ReadKey( "QuickCommand" ); aPrinter.m_aInfo.m_aQuickCommand = String( aValue, RTL_TEXTENCODING_UTF8 ); aValue = aConfig.ReadKey( "Features" ); aPrinter.m_aInfo.m_aFeatures = String( aValue, RTL_TEXTENCODING_UTF8 ); // override the settings in m_aGlobalDefaults if keys exist aValue = aConfig.ReadKey( "DefaultPrinter" ); if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) ) aDefaultPrinter = aPrinterName; aValue = aConfig.ReadKey( "Location" ); aPrinter.m_aInfo.m_aLocation = String( aValue, RTL_TEXTENCODING_UTF8 ); aValue = aConfig.ReadKey( "Comment" ); aPrinter.m_aInfo.m_aComment = String( aValue, RTL_TEXTENCODING_UTF8 ); aValue = aConfig.ReadKey( "Copies" ); if( aValue.Len() ) aPrinter.m_aInfo.m_nCopies = aValue.ToInt32(); aValue = aConfig.ReadKey( "Orientation" ); if( aValue.Len() ) aPrinter.m_aInfo.m_eOrientation = aValue.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape : orientation::Portrait; aValue = aConfig.ReadKey( "MarginAdjust" ); if( aValue.Len() ) { aPrinter.m_aInfo.m_nLeftMarginAdjust = aValue.GetToken( 0, ',' ).ToInt32(); aPrinter.m_aInfo.m_nRightMarginAdjust = aValue.GetToken( 1, ',' ).ToInt32(); aPrinter.m_aInfo.m_nTopMarginAdjust = aValue.GetToken( 2, ',' ).ToInt32(); aPrinter.m_aInfo.m_nBottomMarginAdjust = aValue.GetToken( 3, ',' ).ToInt32(); } aValue = aConfig.ReadKey( "ColorDepth" ); if( aValue.Len() ) aPrinter.m_aInfo.m_nColorDepth = aValue.ToInt32(); aValue = aConfig.ReadKey( "ColorDevice" ); if( aValue.Len() ) aPrinter.m_aInfo.m_nColorDevice = aValue.ToInt32(); aValue = aConfig.ReadKey( "PSLevel" ); if( aValue.Len() ) aPrinter.m_aInfo.m_nPSLevel = aValue.ToInt32(); aValue = aConfig.ReadKey( "PDFDevice" ); if( aValue.Len() ) aPrinter.m_aInfo.m_nPDFDevice = aValue.ToInt32(); aValue = aConfig.ReadKey( "PerformFontSubstitution" ); if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) ) aPrinter.m_aInfo.m_bPerformFontSubstitution = true; else aPrinter.m_aInfo.m_bPerformFontSubstitution = false; // now iterate over all keys to extract multi key information: // 1. PPDContext information // 2. Font substitution table for( int nKey = 0; nKey < aConfig.GetKeyCount(); nKey++ ) { ByteString aKey( aConfig.GetKeyName( nKey ) ); if( aKey.CompareTo( "PPD_", 4 ) == COMPARE_EQUAL && aPrinter.m_aInfo.m_pParser ) { aValue = aConfig.ReadKey( aKey ); const PPDKey* pKey = aPrinter.m_aInfo.m_pParser->getKey( String( aKey.Copy( 4 ), RTL_TEXTENCODING_ISO_8859_1 ) ); if( pKey ) { aPrinter.m_aInfo.m_aContext. setValue( pKey, aValue.Equals( "*nil" ) ? NULL : pKey->getValue( String( aValue, RTL_TEXTENCODING_ISO_8859_1 ) ), sal_True ); } } else if( aKey.Len() > 10 && aKey.CompareTo("SubstFont_", 10 ) == COMPARE_EQUAL ) { aValue = aConfig.ReadKey( aKey ); aPrinter.m_aInfo.m_aFontSubstitutes[ OStringToOUString( aKey.Copy( 10 ), RTL_TEXTENCODING_ISO_8859_1 ) ] = OStringToOUString( aValue, RTL_TEXTENCODING_ISO_8859_1 ); } } setDefaultPaper( aPrinter.m_aInfo.m_aContext ); fillFontSubstitutions( aPrinter.m_aInfo ); // finally insert printer FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aPrinter.m_aFile ); aPrinter.m_bModified = false; aPrinter.m_aGroup = aConfig.GetGroupName( nGroup ); std::hash_map< OUString, Printer, OUStringHash >::const_iterator find_it = m_aPrinters.find( aPrinterName ); if( find_it != m_aPrinters.end() ) { aPrinter.m_aAlternateFiles = find_it->second.m_aAlternateFiles; aPrinter.m_aAlternateFiles.push_front( find_it->second.m_aFile ); } m_aPrinters[ aPrinterName ] = aPrinter; } } } // set default printer if( m_aPrinters.size() ) { if( m_aPrinters.find( aDefaultPrinter ) == m_aPrinters.end() ) aDefaultPrinter = m_aPrinters.begin()->first; } else aDefaultPrinter = OUString(); m_aDefaultPrinter = aDefaultPrinter; if( m_eType != Default ) return; // add a default printer for every available print queue // merge paper and font substitution from default printer, // all else from global defaults PrinterInfo aMergeInfo( m_aGlobalDefaults ); aMergeInfo.m_aDriverName = String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ); aMergeInfo.m_aFeatures = String( RTL_CONSTASCII_USTRINGPARAM( "autoqueue" ) ); if( m_aDefaultPrinter.getLength() ) { PrinterInfo aDefaultInfo( getPrinterInfo( m_aDefaultPrinter ) ); aMergeInfo.m_bPerformFontSubstitution = aDefaultInfo.m_bPerformFontSubstitution; fillFontSubstitutions( aMergeInfo ); const PPDKey* pDefKey = aDefaultInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); const PPDKey* pMergeKey = aMergeInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); const PPDValue* pDefValue = aDefaultInfo.m_aContext.getValue( pDefKey ); const PPDValue* pMergeValue = pMergeKey ? pMergeKey->getValue( pDefValue->m_aOption ) : NULL; if( pMergeKey && pMergeValue ) aMergeInfo.m_aContext.setValue( pMergeKey, pMergeValue ); } getSystemPrintQueues(); for( ::std::list< SystemPrintQueue >::iterator it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it ) { String aPrinterName( RTL_CONSTASCII_USTRINGPARAM( "<" ) ); aPrinterName += String( it->m_aQueue ); aPrinterName.Append( '>' ); if( m_aPrinters.find( aPrinterName ) != m_aPrinters.end() ) // probably user made this one permanent in padmin continue; String aCmd( m_aSystemPrintCommand ); aCmd.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PRINTER)" ) ), it->m_aQueue ); Printer aPrinter; // initialize to merged defaults aPrinter.m_aInfo = aMergeInfo; aPrinter.m_aInfo.m_aPrinterName = aPrinterName; aPrinter.m_aInfo.m_aCommand = aCmd; aPrinter.m_aInfo.m_aComment = it->m_aComment; aPrinter.m_aInfo.m_aLocation = it->m_aLocation; aPrinter.m_bModified = false; aPrinter.m_aGroup = ByteString( aPrinterName, aEncoding ); //provide group name in case user makes this one permanent in padmin m_aPrinters[ aPrinterName ] = aPrinter; } } // ----------------------------------------------------------------- void PrinterInfoManager::listPrinters( ::std::list< OUString >& rList ) const { ::std::hash_map< OUString, Printer, OUStringHash >::const_iterator it; rList.clear(); for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it ) rList.push_back( it->first ); } // ----------------------------------------------------------------- const PrinterInfo& PrinterInfoManager::getPrinterInfo( const OUString& rPrinter ) const { static PrinterInfo aEmptyInfo; ::std::hash_map< OUString, Printer, OUStringHash >::const_iterator it = m_aPrinters.find( rPrinter ); DBG_ASSERT( it != m_aPrinters.end(), "Do not ask for info about nonexistent printers" ); return it != m_aPrinters.end() ? it->second.m_aInfo : aEmptyInfo; } // ----------------------------------------------------------------- void PrinterInfoManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo ) { ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinter ); DBG_ASSERT( it != m_aPrinters.end(), "Do not change nonexistant printers" ); if( it != m_aPrinters.end() ) { it->second.m_aInfo = rNewInfo; // recalculate font substitutions fillFontSubstitutions( it->second.m_aInfo ); it->second.m_bModified = true; writePrinterConfig(); } } // ----------------------------------------------------------------- // need to check writeability / creatability of config files static bool checkWriteability( const OUString& rUniPath ) { bool bRet = false; OUString aSysPath; FileBase::getSystemPathFromFileURL( rUniPath, aSysPath ); SvFileStream aStream( aSysPath, STREAM_READ | STREAM_WRITE ); if( aStream.IsOpen() && aStream.IsWritable() ) bRet = true; return bRet; } bool PrinterInfoManager::writePrinterConfig() { // find at least one writeable config ::std::hash_map< OUString, Config*, OUStringHash > files; ::std::hash_map< OUString, int, OUStringHash > rofiles; ::std::hash_map< OUString, Config*, OUStringHash >::iterator file_it; for( ::std::list< WatchFile >::const_iterator wit = m_aWatchFiles.begin(); wit != m_aWatchFiles.end(); ++wit ) { if( checkWriteability( wit->m_aFilePath ) ) { files[ wit->m_aFilePath ] = new Config( wit->m_aFilePath ); break; } } if( files.empty() ) return false; Config* pGlobal = files.begin()->second; pGlobal->SetGroup( GLOBAL_DEFAULTS_GROUP ); pGlobal->WriteKey( "DisableCUPS", m_bDisableCUPS ? "true" : "false" ); ::std::hash_map< OUString, Printer, OUStringHash >::iterator it; for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it ) { if( ! it->second.m_bModified ) // printer was not changed, do nothing continue; // don't save autoqueue printers sal_Int32 nIndex = 0; bool bAutoQueue = false; while( nIndex != -1 && ! bAutoQueue ) { OUString aToken( it->second.m_aInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); if( aToken.getLength() && aToken.compareToAscii( "autoqueue" ) == 0 ) bAutoQueue = true; } if( bAutoQueue ) continue; if( it->second.m_aFile.getLength() ) { // check if file is writable if( files.find( it->second.m_aFile ) == files.end() ) { bool bInsertToNewFile = false; // maybe it is simply not inserted yet if( rofiles.find( it->second.m_aFile ) == rofiles.end() ) { if( checkWriteability( it->second.m_aFile ) ) files[ it->second.m_aFile ] = new Config( it->second.m_aFile ); else bInsertToNewFile = true; } else bInsertToNewFile = true; // original file is read only, insert printer in a new writeable file if( bInsertToNewFile ) { rofiles[ it->second.m_aFile ] = 1; // update alternate file list // the remove operation ensures uniqueness of each alternate it->second.m_aAlternateFiles.remove( it->second.m_aFile ); it->second.m_aAlternateFiles.remove( files.begin()->first ); it->second.m_aAlternateFiles.push_front( it->second.m_aFile ); // update file it->second.m_aFile = files.begin()->first; } } } else // a new printer, write it to the first file available it->second.m_aFile = files.begin()->first; if( ! it->second.m_aGroup.getLength() ) // probably a new printer it->second.m_aGroup = OString( it->first.getStr(), it->first.getLength(), RTL_TEXTENCODING_UTF8 ); if( files.find( it->second.m_aFile ) != files.end() ) { Config* pConfig = files[ it->second.m_aFile ]; pConfig->DeleteGroup( it->second.m_aGroup ); // else some old keys may remain pConfig->SetGroup( it->second.m_aGroup ); ByteString aValue( String( it->second.m_aInfo.m_aDriverName ), RTL_TEXTENCODING_UTF8 ); aValue += '/'; aValue += ByteString( String( it->first ), RTL_TEXTENCODING_UTF8 ); pConfig->WriteKey( "Printer", aValue ); pConfig->WriteKey( "DefaultPrinter", it->first == m_aDefaultPrinter ? "1" : "0" ); pConfig->WriteKey( "Location", ByteString( String( it->second.m_aInfo.m_aLocation ), RTL_TEXTENCODING_UTF8 ) ); pConfig->WriteKey( "Comment", ByteString( String( it->second.m_aInfo.m_aComment ), RTL_TEXTENCODING_UTF8 ) ); pConfig->WriteKey( "Command", ByteString( String( it->second.m_aInfo.m_aCommand ), RTL_TEXTENCODING_UTF8 ) ); pConfig->WriteKey( "QuickCommand", ByteString( String( it->second.m_aInfo.m_aQuickCommand ), RTL_TEXTENCODING_UTF8 ) ); pConfig->WriteKey( "Features", ByteString( String( it->second.m_aInfo.m_aFeatures ), RTL_TEXTENCODING_UTF8 ) ); pConfig->WriteKey( "Copies", ByteString::CreateFromInt32( it->second.m_aInfo.m_nCopies ) ); pConfig->WriteKey( "Orientation", it->second.m_aInfo.m_eOrientation == orientation::Landscape ? "Landscape" : "Portrait" ); pConfig->WriteKey( "PSLevel", ByteString::CreateFromInt32( it->second.m_aInfo.m_nPSLevel ) ); pConfig->WriteKey( "PDFDevice", ByteString::CreateFromInt32( it->second.m_aInfo.m_nPDFDevice ) ); pConfig->WriteKey( "ColorDevice", ByteString::CreateFromInt32( it->second.m_aInfo.m_nColorDevice ) ); pConfig->WriteKey( "ColorDepth", ByteString::CreateFromInt32( it->second.m_aInfo.m_nColorDepth ) ); aValue = ByteString::CreateFromInt32( it->second.m_aInfo.m_nLeftMarginAdjust ); aValue += ','; aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nRightMarginAdjust ); aValue += ','; aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nTopMarginAdjust ); aValue += ','; aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nBottomMarginAdjust ); pConfig->WriteKey( "MarginAdjust", aValue ); if( it->second.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) != 0 ) { // write PPDContext (not for CUPS) for( int i = 0; i < it->second.m_aInfo.m_aContext.countValuesModified(); i++ ) { const PPDKey* pKey = it->second.m_aInfo.m_aContext.getModifiedKey( i ); ByteString aKey( "PPD_" ); aKey += ByteString( pKey->getKey(), RTL_TEXTENCODING_ISO_8859_1 ); const PPDValue* pValue = it->second.m_aInfo.m_aContext.getValue( pKey ); aValue = pValue ? ByteString( pValue->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ) : ByteString( "*nil" ); pConfig->WriteKey( aKey, aValue ); } } // write font substitution table pConfig->WriteKey( "PerformFontSubstitution", it->second.m_aInfo.m_bPerformFontSubstitution ? "true" : "false" ); for( ::std::hash_map< OUString, OUString, OUStringHash >::const_iterator subst = it->second.m_aInfo.m_aFontSubstitutes.begin(); subst != it->second.m_aInfo.m_aFontSubstitutes.end(); ++subst ) { ByteString aKey( "SubstFont_" ); aKey.Append( OUStringToOString( subst->first, RTL_TEXTENCODING_ISO_8859_1 ).getStr() ); pConfig->WriteKey( aKey, OUStringToOString( subst->second, RTL_TEXTENCODING_ISO_8859_1 ) ); } } } // get rid of Config objects. this also writes any changes for( file_it = files.begin(); file_it != files.end(); ++file_it ) delete file_it->second; return true; } // ----------------------------------------------------------------- bool PrinterInfoManager::addPrinter( const OUString& rPrinterName, const OUString& rDriverName ) { bool bSuccess = false; const PPDParser* pParser = NULL; if( m_aPrinters.find( rPrinterName ) == m_aPrinters.end() && ( pParser = PPDParser::getParser( rDriverName ) ) ) { Printer aPrinter; aPrinter.m_bModified = true; aPrinter.m_aInfo = m_aGlobalDefaults; aPrinter.m_aInfo.m_aDriverName = rDriverName; aPrinter.m_aInfo.m_pParser = pParser; aPrinter.m_aInfo.m_aContext.setParser( pParser ); aPrinter.m_aInfo.m_aPrinterName = rPrinterName; fillFontSubstitutions( aPrinter.m_aInfo ); // merge PPD values with global defaults for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ ) { const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified ); const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey ); const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL; if( pDefKey && pPrinterKey ) // at least the options exist in both PPDs { if( pDefValue ) { const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption ); if( pPrinterValue ) // the printer has a corresponding option for the key aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue ); } else aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL ); } } m_aPrinters[ rPrinterName ] = aPrinter; bSuccess = true; #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "new printer %s, level = %d, pdfdevice = %d, colordevice = %d, depth = %d\n", OUStringToOString( rPrinterName, osl_getThreadTextEncoding() ).getStr(), m_aPrinters[rPrinterName].m_aInfo.m_nPSLevel, m_aPrinters[rPrinterName].m_aInfo.m_nPDFDevice, m_aPrinters[rPrinterName].m_aInfo.m_nColorDevice, m_aPrinters[rPrinterName].m_aInfo.m_nColorDepth ); #endif // comment: logically one should writePrinterConfig() here // but immediately after addPrinter() a changePrinterInfo() // will follow (see padmin code), which writes it again, // so we can currently save some performance here } return bSuccess; } // ----------------------------------------------------------------- bool PrinterInfoManager::removePrinter( const OUString& rPrinterName, bool bCheckOnly ) { bool bSuccess = true; ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName ); if( it != m_aPrinters.end() ) { if( it->second.m_aFile.getLength() ) { // this printer already exists in a config file // check writeability of config file(s) if( ! checkWriteability( it->second.m_aFile ) ) bSuccess = false; else { for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin(); file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it ) { if( ! checkWriteability( *file_it ) ) bSuccess = false; } } if( bSuccess && ! bCheckOnly ) { Config aConfig( it->second.m_aFile ); aConfig.DeleteGroup( it->second.m_aGroup ); aConfig.Flush(); for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin(); file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it ) { Config aAltConfig( *file_it ); aAltConfig.DeleteGroup( it->second.m_aGroup ); aAltConfig.Flush(); } } } if( bSuccess && ! bCheckOnly ) { m_aPrinters.erase( it ); // need this here because someone may call // checkPrintersChanged after the removal // but then other added printers were not flushed // to disk, so they are discarded writePrinterConfig(); } } return bSuccess; } // ----------------------------------------------------------------- bool PrinterInfoManager::setDefaultPrinter( const OUString& rPrinterName ) { bool bSuccess = false; ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName ); if( it != m_aPrinters.end() ) { bSuccess = true; it->second.m_bModified = true; if( ( it = m_aPrinters.find( m_aDefaultPrinter ) ) != m_aPrinters.end() ) it->second.m_bModified = true; m_aDefaultPrinter = rPrinterName; writePrinterConfig(); } return bSuccess; } // ----------------------------------------------------------------- bool PrinterInfoManager::addOrRemovePossible() const { return true; } // ----------------------------------------------------------------- void PrinterInfoManager::fillFontSubstitutions( PrinterInfo& rInfo ) const { PrintFontManager& rFontManager( PrintFontManager::get() ); rInfo.m_aFontSubstitutions.clear(); if( ! rInfo.m_bPerformFontSubstitution || ! rInfo.m_aFontSubstitutes.size() ) return; ::std::list< FastPrintFontInfo > aFonts; ::std::hash_map< OUString, ::std::list< FastPrintFontInfo >, OUStringHash > aPrinterFonts; rFontManager.getFontListWithFastInfo( aFonts, rInfo.m_pParser ); // get builtin fonts ::std::list< FastPrintFontInfo >::const_iterator it; for( it = aFonts.begin(); it != aFonts.end(); ++it ) if( it->m_eType == fonttype::Builtin ) aPrinterFonts[ it->m_aFamilyName.toAsciiLowerCase() ].push_back( *it ); // map lower case, so build a local copy of the font substitutions ::std::hash_map< OUString, OUString, OUStringHash > aSubstitutions; ::std::hash_map< OUString, OUString, OUStringHash >::const_iterator subst; for( subst = rInfo.m_aFontSubstitutes.begin(); subst != rInfo.m_aFontSubstitutes.end(); ++subst ) { OUString aFamily( subst->first.toAsciiLowerCase() ); // first look if there is a builtin of this family // in this case override the substitution table if( aPrinterFonts.find( aFamily ) != aPrinterFonts.end() ) aSubstitutions[ aFamily ] = aFamily; else aSubstitutions[ aFamily ] = subst->second.toAsciiLowerCase(); } // now find substitutions for( it = aFonts.begin(); it != aFonts.end(); ++it ) { if( it->m_eType != fonttype::Builtin ) { OUString aFamily( it->m_aFamilyName.toAsciiLowerCase() ); subst = aSubstitutions.find( aFamily ); if( subst != aSubstitutions.end() ) { // search a substitution const ::std::list< FastPrintFontInfo >& rBuiltins( aPrinterFonts[ aSubstitutions[ aFamily ] ] ); ::std::list< FastPrintFontInfo >::const_iterator builtin; int nLastMatch = -10000; fontID nSubstitute = -1; for( builtin = rBuiltins.begin(); builtin != rBuiltins.end(); ++builtin ) { int nMatch = 0; int nDiff; if( builtin->m_eItalic == it->m_eItalic ) nMatch += 8000; nDiff = builtin->m_eWeight - it->m_eWeight; nDiff = nDiff < 0 ? -nDiff : nDiff; nMatch += 4000 - 1000*nDiff; nDiff = builtin->m_eWidth - it->m_eWidth; nDiff = nDiff < 0 ? -nDiff : nDiff; nMatch += 2000 - 500*nDiff; if( nMatch > nLastMatch ) { nLastMatch = nMatch; nSubstitute = builtin->m_nID; } } if( nSubstitute != -1 ) { rInfo.m_aFontSubstitutions[ it->m_nID ] = nSubstitute; #if OSL_DEBUG_LEVEL > 2 FastPrintFontInfo aInfo; rFontManager.getFontFastInfo( nSubstitute, aInfo ); fprintf( stderr, "substitute %s %s %d %d\n" " -> %s %s %d %d\n", OUStringToOString( it->m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr(), it->m_eItalic == italic::Upright ? "r" : it->m_eItalic == italic::Oblique ? "o" : it->m_eItalic == italic::Italic ? "i" : "u", it->m_eWeight, it->m_eWidth, OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr(), aInfo.m_eItalic == italic::Upright ? "r" : aInfo.m_eItalic == italic::Oblique ? "o" : aInfo.m_eItalic == italic::Italic ? "i" : "u", aInfo.m_eWeight, aInfo.m_eWidth ); #endif } } } } } // ----------------------------------------------------------------- void PrinterInfoManager::getSystemPrintCommands( std::list< OUString >& rCommands ) { if( m_pQueueInfo && m_pQueueInfo->hasChanged() ) { m_aSystemPrintCommand = m_pQueueInfo->getCommand(); m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues ); delete m_pQueueInfo, m_pQueueInfo = NULL; } std::list< SystemPrintQueue >::const_iterator it; rCommands.clear(); String aPrinterConst( RTL_CONSTASCII_USTRINGPARAM( "(PRINTER)" ) ); for( it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it ) { String aCmd( m_aSystemPrintCommand ); aCmd.SearchAndReplace( aPrinterConst, it->m_aQueue ); rCommands.push_back( aCmd ); } } const std::list< PrinterInfoManager::SystemPrintQueue >& PrinterInfoManager::getSystemPrintQueues() { if( m_pQueueInfo && m_pQueueInfo->hasChanged() ) { m_aSystemPrintCommand = m_pQueueInfo->getCommand(); m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues ); delete m_pQueueInfo, m_pQueueInfo = NULL; } return m_aSystemPrintQueues; } bool PrinterInfoManager::checkFeatureToken( const rtl::OUString& rPrinterName, const char* pToken ) const { const PrinterInfo& rPrinterInfo( getPrinterInfo( rPrinterName ) ); sal_Int32 nIndex = 0; while( nIndex != -1 ) { OUString aOuterToken = rPrinterInfo.m_aFeatures.getToken( 0, ',', nIndex ); sal_Int32 nInnerIndex = 0; OUString aInnerToken = aOuterToken.getToken( 0, '=', nInnerIndex ); if( aInnerToken.equalsIgnoreAsciiCaseAscii( pToken ) ) return true; } return false; } FILE* PrinterInfoManager::startSpool( const OUString& rPrintername, bool bQuickCommand ) { const PrinterInfo& rPrinterInfo = getPrinterInfo (rPrintername); const rtl::OUString& rCommand = (bQuickCommand && rPrinterInfo.m_aQuickCommand.getLength() ) ? rPrinterInfo.m_aQuickCommand : rPrinterInfo.m_aCommand; rtl::OString aShellCommand = OUStringToOString (rCommand, RTL_TEXTENCODING_ISO_8859_1); aShellCommand += rtl::OString( " 2>/dev/null" ); return popen (aShellCommand.getStr(), "w"); } int PrinterInfoManager::endSpool( const OUString& /*rPrintername*/, const OUString& /*rJobTitle*/, FILE* pFile, const JobData& /*rDocumentJobData*/, bool /*bBanner*/ ) { return (0 == pclose( pFile )); } void PrinterInfoManager::setupJobContextData( JobData& rData ) { std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rData.m_aPrinterName ); if( it != m_aPrinters.end() ) { rData.m_pParser = it->second.m_aInfo.m_pParser; rData.m_aContext = it->second.m_aInfo.m_aContext; } } void PrinterInfoManager::setDefaultPaper( PPDContext& rContext ) const { if( ! rContext.getParser() ) return; const PPDKey* pPageSizeKey = rContext.getParser()->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); if( ! pPageSizeKey ) return; int nModified = rContext.countValuesModified(); while( nModified-- && rContext.getModifiedKey( nModified ) != pPageSizeKey ) ; if( nModified >= 0 ) // paper was set already, do not modify { #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "not setting default paper, already set %s\n", OUStringToOString( rContext.getValue( pPageSizeKey )->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() ); #endif return; } // paper not set, fill in default value const PPDValue* pPaperVal = NULL; int nValues = pPageSizeKey->countValues(); for( int i = 0; i < nValues && ! pPaperVal; i++ ) { const PPDValue* pVal = pPageSizeKey->getValue( i ); if( pVal->m_aOption.EqualsIgnoreCaseAscii( m_aSystemDefaultPaper.getStr() ) ) pPaperVal = pVal; } if( pPaperVal ) { #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "setting default paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() ); #endif rContext.setValue( pPageSizeKey, pPaperVal ); #if OSL_DEBUG_LEVEL > 1 pPaperVal = rContext.getValue( pPageSizeKey ); fprintf( stderr, "-> got paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() ); #endif } } // ----------------------------------------------------------------- SystemQueueInfo::SystemQueueInfo() : m_bChanged( false ) { create(); } SystemQueueInfo::~SystemQueueInfo() { static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" ); if( ! pNoSyncDetection || !*pNoSyncDetection ) join(); else terminate(); } bool SystemQueueInfo::hasChanged() const { MutexGuard aGuard( m_aMutex ); bool bChanged = m_bChanged; return bChanged; } void SystemQueueInfo::getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues ) { MutexGuard aGuard( m_aMutex ); rQueues = m_aQueues; m_bChanged = false; } OUString SystemQueueInfo::getCommand() const { MutexGuard aGuard( m_aMutex ); OUString aRet = m_aCommand; return aRet; } struct SystemCommandParameters; typedef void(* tokenHandler)(const std::list< rtl::OString >&, std::list< PrinterInfoManager::SystemPrintQueue >&, const SystemCommandParameters*); struct SystemCommandParameters { const char* pQueueCommand; const char* pPrintCommand; const char* pForeToken; const char* pAftToken; unsigned int nForeTokenCount; tokenHandler pHandler; }; #if ! (defined(LINUX) || defined(NETBSD) || defined(FREEBSD)) static void lpgetSysQueueTokenHandler( const std::list< rtl::OString >& i_rLines, std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues, const SystemCommandParameters* ) { rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); std::hash_set< OUString, OUStringHash > aUniqueSet; std::hash_set< OUString, OUStringHash > aOnlySet; aUniqueSet.insert( OUString( RTL_CONSTASCII_USTRINGPARAM( "_all" ) ) ); aUniqueSet.insert( OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) ); // the eventual "all" attribute of the "_all" queue tells us, which // printers are to be used for this user at all // find _all: line rtl::OString aAllLine( "_all:" ); rtl::OString aAllAttr( "all=" ); for( std::list< rtl::OString >::const_iterator it = i_rLines.begin(); it != i_rLines.end(); ++it ) { if( it->indexOf( aAllLine, 0 ) == 0 ) { // now find the "all" attribute ++it; while( it != i_rLines.end() ) { rtl::OString aClean( WhitespaceToSpace( *it ) ); if( aClean.indexOf( aAllAttr, 0 ) == 0 ) { // insert the comma separated entries into the set of printers to use sal_Int32 nPos = aAllAttr.getLength(); while( nPos != -1 ) { OString aTok( aClean.getToken( 0, ',', nPos ) ); if( aTok.getLength() > 0 ) aOnlySet.insert( rtl::OStringToOUString( aTok, aEncoding ) ); } break; } } break; } } bool bInsertAttribute = false; rtl::OString aDescrStr( "description=" ); rtl::OString aLocStr( "location=" ); for( std::list< rtl::OString >::const_iterator it = i_rLines.begin(); it != i_rLines.end(); ++it ) { sal_Int32 nPos = 0; // find the begin of a new printer section nPos = it->indexOf( ':', 0 ); if( nPos != -1 ) { OUString aSysQueue( rtl::OStringToOUString( it->copy( 0, nPos ), aEncoding ) ); // do not insert duplicates (e.g. lpstat tends to produce such lines) // in case there was a "_all" section, insert only those printer explicitly // set in the "all" attribute if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() && ( aOnlySet.empty() || aOnlySet.find( aSysQueue ) != aOnlySet.end() ) ) { o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() ); o_rQueues.back().m_aQueue = aSysQueue; o_rQueues.back().m_aLocation = aSysQueue; aUniqueSet.insert( aSysQueue ); bInsertAttribute = true; } else bInsertAttribute = false; continue; } if( bInsertAttribute && ! o_rQueues.empty() ) { // look for "description" attribute, insert as comment nPos = it->indexOf( aDescrStr, 0 ); if( nPos != -1 ) { ByteString aComment( WhitespaceToSpace( it->copy(nPos+12) ) ); if( aComment.Len() > 0 ) o_rQueues.back().m_aComment = String( aComment, aEncoding ); continue; } // look for "location" attribute, inser as location nPos = it->indexOf( aLocStr, 0 ); if( nPos != -1 ) { ByteString aLoc( WhitespaceToSpace( it->copy(nPos+9) ) ); if( aLoc.Len() > 0 ) o_rQueues.back().m_aLocation = String( aLoc, aEncoding ); continue; } } } } #endif static void standardSysQueueTokenHandler( const std::list< rtl::OString >& i_rLines, std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues, const SystemCommandParameters* i_pParms) { rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); std::hash_set< OUString, OUStringHash > aUniqueSet; rtl::OString aForeToken( i_pParms->pForeToken ); rtl::OString aAftToken( i_pParms->pAftToken ); /* Normal Unix print queue discovery, also used for Darwin 5 LPR printing */ for( std::list< rtl::OString >::const_iterator it = i_rLines.begin(); it != i_rLines.end(); ++it ) { sal_Int32 nPos = 0; // search for a line describing a printer: // find if there are enough tokens before the name for( unsigned int i = 0; i < i_pParms->nForeTokenCount && nPos != -1; i++ ) { nPos = it->indexOf( aForeToken, nPos ); if( nPos != -1 && it->getLength() >= nPos+aForeToken.getLength() ) nPos += aForeToken.getLength(); } if( nPos != -1 ) { // find if there is the token after the queue sal_Int32 nAftPos = it->indexOf( aAftToken, nPos ); if( nAftPos != -1 ) { // get the queue name between fore and aft tokens OUString aSysQueue( rtl::OStringToOUString( it->copy( nPos, nAftPos - nPos ), aEncoding ) ); // do not insert duplicates (e.g. lpstat tends to produce such lines) if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() ) { o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() ); o_rQueues.back().m_aQueue = aSysQueue; o_rQueues.back().m_aLocation = aSysQueue; aUniqueSet.insert( aSysQueue ); } } } } } static const struct SystemCommandParameters aParms[] = { #if defined(LINUX) || defined(NETBSD) || defined(FREEBSD) { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler }, { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler }, { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler } #else { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpget list", "lp -d \"(PRINTER)\"", "", ":", 0, lpgetSysQueueTokenHandler }, { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler }, { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler }, { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler } #endif }; void SystemQueueInfo::run() { char pBuffer[1024]; FILE *pPipe; std::list< rtl::OString > aLines; /* Discover which command we can use to get a list of all printer queues */ for( unsigned int i = 0; i < sizeof(aParms)/sizeof(aParms[0]); i++ ) { aLines.clear(); rtl::OStringBuffer aCmdLine( 128 ); aCmdLine.append( aParms[i].pQueueCommand ); #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "trying print queue command \"%s\" ... ", aParms[i].pQueueCommand ); #endif aCmdLine.append( " 2>/dev/null" ); if( (pPipe = popen( aCmdLine.getStr(), "r" )) ) { while( fgets( pBuffer, 1024, pPipe ) ) aLines.push_back( rtl::OString( pBuffer ) ); if( ! pclose( pPipe ) ) { std::list< PrinterInfoManager::SystemPrintQueue > aSysPrintQueues; aParms[i].pHandler( aLines, aSysPrintQueues, &(aParms[i]) ); MutexGuard aGuard( m_aMutex ); m_bChanged = true; m_aQueues = aSysPrintQueues; m_aCommand = rtl::OUString::createFromAscii( aParms[i].pPrintCommand ); #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "success\n" ); #endif break; } } #if OSL_DEBUG_LEVEL > 1 fprintf( stderr, "failed\n" ); #endif } }