| /************************************************************** |
| * |
| * 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 <unistd.h> |
| #include <sys/wait.h> |
| #include <signal.h> |
| |
| #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 <hash_set> |
| |
| 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 |
| } |
| } |
| |