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

Generated by: LCOV version 1.10