LCOV - code coverage report
Current view: top level - vcl/unx/generic/printer - printerinfomanager.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 193 546 35.3 %
Date: 2015-06-13 12:38:46 Functions: 10 35 28.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11