LCOV - code coverage report
Current view: top level - libreoffice/vcl/unx/generic/printer - cupsmgr.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 52 389 13.4 %
Date: 2012-12-17 Functions: 7 31 22.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             : 
      21             : #include <cups/cups.h>
      22             : #include <cups/http.h>
      23             : #include <cups/ipp.h>
      24             : #include <cups/ppd.h>
      25             : 
      26             : #include <unistd.h>
      27             : 
      28             : #include "cupsmgr.hxx"
      29             : 
      30             : #include "osl/thread.h"
      31             : #include "osl/diagnose.h"
      32             : #include "osl/conditn.hxx"
      33             : 
      34             : #include "rtl/ustrbuf.hxx"
      35             : 
      36             : #include <officecfg/Office/Common.hxx>
      37             : 
      38             : #include <algorithm>
      39             : 
      40             : using namespace psp;
      41             : using namespace osl;
      42             : 
      43             : using ::rtl::OUString;
      44             : using ::rtl::OUStringBuffer;
      45             : using ::rtl::OUStringToOString;
      46             : using ::rtl::OStringToOUString;
      47             : using ::rtl::OUStringHash;
      48             : using ::rtl::OString;
      49             : 
      50             : struct GetPPDAttribs
      51             : {
      52             :     osl::Condition      m_aCondition;
      53             :     OString             m_aParameter;
      54             :     OString             m_aResult;
      55             :     oslThread           m_aThread;
      56             :     int                 m_nRefs;
      57             :     bool*               m_pResetRunning;
      58             :     osl::Mutex*         m_pSyncMutex;
      59             : 
      60           0 :     GetPPDAttribs( const char * m_pParameter,
      61             :                    bool* pResetRunning, osl::Mutex* pSyncMutex )
      62             :             : m_aParameter( m_pParameter ),
      63             :               m_pResetRunning( pResetRunning ),
      64           0 :               m_pSyncMutex( pSyncMutex )
      65             :     {
      66           0 :         m_nRefs = 2;
      67           0 :         m_aCondition.reset();
      68           0 :     }
      69             : 
      70           0 :     ~GetPPDAttribs()
      71           0 :     {
      72           0 :         if( !m_aResult.isEmpty() )
      73           0 :             unlink( m_aResult.getStr() );
      74           0 :     }
      75             : 
      76           0 :     void unref()
      77             :     {
      78           0 :         if( --m_nRefs == 0 )
      79             :         {
      80           0 :             *m_pResetRunning = false;
      81           0 :             delete this;
      82             :         }
      83           0 :     }
      84             : 
      85           0 :     void executeCall()
      86             :     {
      87             :         // This CUPS method is not at all thread-safe we need
      88             :         // to dup the pointer to a static buffer it returns ASAP
      89           0 :         OString aResult = cupsGetPPD(m_aParameter.getStr());
      90           0 :         MutexGuard aGuard( *m_pSyncMutex );
      91           0 :         m_aResult = aResult;
      92           0 :         m_aCondition.set();
      93           0 :         unref();
      94           0 :     }
      95             : 
      96           0 :     OString waitResult( TimeValue *pDelay )
      97             :     {
      98           0 :         m_pSyncMutex->release();
      99             : 
     100           0 :         if (m_aCondition.wait( pDelay ) != Condition::result_ok
     101             :             )
     102             :         {
     103             :             #if OSL_DEBUG_LEVEL > 1
     104             :             fprintf( stderr, "cupsGetPPD %s timed out\n", m_aParameter.getStr() );
     105             :             #endif
     106             :         }
     107           0 :         m_pSyncMutex->acquire();
     108             : 
     109           0 :         OString aRetval = m_aResult;
     110           0 :         m_aResult = OString();
     111           0 :         unref();
     112             : 
     113           0 :         return aRetval;
     114             :     }
     115             : };
     116             : 
     117             : extern "C" {
     118           0 :     static void getPPDWorker(void* pData)
     119             :     {
     120           0 :         GetPPDAttribs* pAttribs = (GetPPDAttribs*)pData;
     121           0 :         pAttribs->executeCall();
     122           0 :     }
     123             : }
     124             : 
     125           0 : OString CUPSManager::threadedCupsGetPPD( const char* pPrinter )
     126             : {
     127           0 :     OString aResult;
     128             : 
     129           0 :     m_aGetPPDMutex.acquire();
     130             :     // if one thread hangs in cupsGetPPD already, don't start another
     131           0 :     if( ! m_bPPDThreadRunning )
     132             :     {
     133           0 :         m_bPPDThreadRunning = true;
     134             :         GetPPDAttribs* pAttribs = new GetPPDAttribs( pPrinter,
     135             :                                                      &m_bPPDThreadRunning,
     136           0 :                                                      &m_aGetPPDMutex );
     137             : 
     138           0 :         oslThread aThread = osl_createThread( getPPDWorker, pAttribs );
     139             : 
     140             :         TimeValue aValue;
     141           0 :         aValue.Seconds = 5;
     142           0 :         aValue.Nanosec = 0;
     143             : 
     144             :         // NOTE: waitResult release and acquires the GetPPD mutex
     145           0 :         aResult = pAttribs->waitResult( &aValue );
     146           0 :         osl_destroyThread( aThread );
     147             :     }
     148           0 :     m_aGetPPDMutex.release();
     149             : 
     150           0 :     return aResult;
     151             : }
     152             : 
     153           0 : static const char* setPasswordCallback( const char* pIn )
     154             : {
     155           0 :     const char* pRet = NULL;
     156             : 
     157           0 :     PrinterInfoManager& rMgr = PrinterInfoManager::get();
     158           0 :     if( rMgr.getType() == PrinterInfoManager::CUPS ) // sanity check
     159           0 :         pRet = static_cast<CUPSManager&>(rMgr).authenticateUser( pIn );
     160           0 :     return pRet;
     161             : }
     162             : 
     163             : /*
     164             :  *  CUPSManager class
     165             :  */
     166             : 
     167          40 : CUPSManager* CUPSManager::tryLoadCUPS()
     168             : {
     169          40 :     CUPSManager* pManager = NULL;
     170          40 :     static const char* pEnv = getenv("SAL_DISABLE_CUPS");
     171             : 
     172          40 :     if (!pEnv || !*pEnv)
     173          40 :         pManager = new CUPSManager();
     174          40 :     return pManager;
     175             : }
     176             : 
     177             : extern "C"
     178             : {
     179          40 : static void run_dest_thread_stub( void* pThis )
     180             : {
     181          40 :     CUPSManager::runDestThread( pThis );
     182          40 : }
     183             : }
     184             : 
     185          40 : CUPSManager::CUPSManager() :
     186             :         PrinterInfoManager( CUPS ),
     187             :         m_nDests( 0 ),
     188             :         m_pDests( NULL ),
     189             :         m_bNewDests( false ),
     190          40 :         m_bPPDThreadRunning( false )
     191             : {
     192          40 :     m_aDestThread = osl_createThread( run_dest_thread_stub, this );
     193          40 : }
     194             : 
     195           0 : CUPSManager::~CUPSManager()
     196             : {
     197           0 :     if( m_aDestThread )
     198             :     {
     199             :         // if the thread is still running here, then
     200             :         // cupsGetDests is hung; terminate the thread instead of joining
     201           0 :         osl_terminateThread( m_aDestThread );
     202           0 :         osl_destroyThread( m_aDestThread );
     203             :     }
     204             : 
     205           0 :     if (m_nDests && m_pDests)
     206           0 :         cupsFreeDests( m_nDests, (cups_dest_t*)m_pDests );
     207           0 : }
     208             : 
     209          40 : void CUPSManager::runDestThread( void* pThis )
     210             : {
     211          40 :     ((CUPSManager*)pThis)->runDests();
     212          40 : }
     213             : 
     214          40 : void CUPSManager::runDests()
     215             : {
     216             : #if OSL_DEBUG_LEVEL > 1
     217             :     fprintf( stderr, "starting cupsGetDests\n" );
     218             : #endif
     219          40 :     cups_dest_t* pDests = NULL;
     220             : 
     221             :     // n#722902 - do a fast-failing check for cups working *at all* first
     222             :     http_t* p_http;
     223          40 :     if( (p_http=httpConnectEncrypt(
     224             :              cupsServer(),
     225             :              ippPort(),
     226          40 :              cupsEncryption())) != NULL )
     227             :     {
     228             :         // neat, cups is up, clean up the canary
     229          40 :         httpClose(p_http);
     230             : 
     231          40 :         int nDests = cupsGetDests( &pDests );
     232             : #if OSL_DEBUG_LEVEL > 1
     233             :         fprintf( stderr, "came out of cupsGetDests\n" );
     234             : #endif
     235             : 
     236          40 :         osl::MutexGuard aGuard( m_aCUPSMutex );
     237          40 :         m_nDests = nDests;
     238          40 :         m_pDests = pDests;
     239          40 :         m_bNewDests = true;
     240             : #if OSL_DEBUG_LEVEL > 1
     241             :         fprintf( stderr, "finished cupsGetDests\n" );
     242             : #endif
     243             :     }
     244          40 : }
     245             : 
     246          78 : void CUPSManager::initialize()
     247             : {
     248             :     // get normal printers, clear printer list
     249          78 :     PrinterInfoManager::initialize();
     250             : 
     251             :     // check whether thread has completed
     252             :     // if not behave like old printing system
     253          78 :     osl::MutexGuard aGuard( m_aCUPSMutex );
     254             : 
     255          78 :     if( ! m_bNewDests )
     256             :         return;
     257             : 
     258             :     // dest thread has run, clean up
     259          40 :     if( m_aDestThread )
     260             :     {
     261           2 :         osl_joinWithThread( m_aDestThread );
     262           2 :         osl_destroyThread( m_aDestThread );
     263           2 :         m_aDestThread = NULL;
     264             :     }
     265          40 :     m_bNewDests = false;
     266             : 
     267             :     // clear old stuff
     268          40 :     m_aCUPSDestMap.clear();
     269             : 
     270          40 :     if( ! (m_nDests && m_pDests ) )
     271             :         return;
     272             : 
     273           0 :     if( isCUPSDisabled() )
     274             :         return;
     275             : 
     276             :     // check for CUPS server(?) > 1.2
     277             :     // since there is no API to query, check for options that were
     278             :     // introduced in dests with 1.2
     279             :     // this is needed to check for %%IncludeFeature support
     280             :     // (#i65684#, #i65491#)
     281           0 :     bool bUsePDF = false;
     282           0 :     cups_dest_t* pDest = ((cups_dest_t*)m_pDests);
     283             :     const char* pOpt = cupsGetOption( "printer-info",
     284             :                                                       pDest->num_options,
     285           0 :                                                       pDest->options );
     286           0 :     if( pOpt )
     287             :     {
     288           0 :         m_bUseIncludeFeature = true;
     289           0 :         bUsePDF = officecfg::Office::Common::Print::Option::Printer::PDFAsStandardPrintJobFormat::get();
     290             :     }
     291             : 
     292           0 :     m_aGlobalDefaults.setDefaultBackend(bUsePDF);
     293             : 
     294             :     // do not send include JobPatch; CUPS will insert that itself
     295             :     // TODO: currently unknown which versions of CUPS insert JobPatches
     296             :     // so currently it is assumed CUPS = don't insert JobPatch files
     297           0 :     m_bUseJobPatch = false;
     298             : 
     299           0 :     rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
     300           0 :     int nPrinter = m_nDests;
     301             : 
     302             :     // reset global default PPD options; these are queried on demand from CUPS
     303           0 :     m_aGlobalDefaults.m_pParser = NULL;
     304           0 :     m_aGlobalDefaults.m_aContext = PPDContext();
     305             : 
     306             :     // add CUPS printers, should there be a printer
     307             :     // with the same name as a CUPS printer, overwrite it
     308           0 :     while( nPrinter-- )
     309             :     {
     310           0 :         pDest = ((cups_dest_t*)m_pDests)+nPrinter;
     311           0 :         OUString aPrinterName = OStringToOUString( pDest->name, aEncoding );
     312           0 :         if( pDest->instance && *pDest->instance )
     313             :         {
     314           0 :             OUStringBuffer aBuf( 256 );
     315           0 :             aBuf.append( aPrinterName );
     316           0 :             aBuf.append( sal_Unicode( '/' ) );
     317           0 :             aBuf.append( OStringToOUString( pDest->instance, aEncoding ) );
     318           0 :             aPrinterName = aBuf.makeStringAndClear();
     319             :         }
     320             : 
     321             :         // initialize printer with possible configuration from psprint.conf
     322           0 :         bool bSetToGlobalDefaults = m_aPrinters.find( aPrinterName ) == m_aPrinters.end();
     323           0 :         Printer aPrinter = m_aPrinters[ aPrinterName ];
     324           0 :         if( bSetToGlobalDefaults )
     325           0 :             aPrinter.m_aInfo = m_aGlobalDefaults;
     326           0 :         aPrinter.m_aInfo.m_aPrinterName = aPrinterName;
     327           0 :         if( pDest->is_default )
     328           0 :             m_aDefaultPrinter = aPrinterName;
     329             : 
     330           0 :         for( int k = 0; k < pDest->num_options; k++ )
     331             :         {
     332           0 :             if(!strcmp(pDest->options[k].name, "printer-info"))
     333           0 :                 aPrinter.m_aInfo.m_aComment=OStringToOUString(pDest->options[k].value, aEncoding);
     334           0 :             if(!strcmp(pDest->options[k].name, "printer-location"))
     335           0 :                 aPrinter.m_aInfo.m_aLocation=OStringToOUString(pDest->options[k].value, aEncoding);
     336             :         }
     337             : 
     338             : 
     339           0 :         OUStringBuffer aBuf( 256 );
     340           0 :         aBuf.appendAscii( "CUPS:" );
     341           0 :         aBuf.append( aPrinterName );
     342             :         // note: the parser that goes with the PrinterInfo
     343             :         // is created implicitly by the JobData::operator=()
     344             :         // when it detects the NULL ptr m_pParser.
     345             :         // if we wanted to fill in the parser here this
     346             :         // would mean we'd have to download PPDs for each and
     347             :         // every printer - which would be really bad runtime
     348             :         // behaviour
     349           0 :         aPrinter.m_aInfo.m_pParser = NULL;
     350           0 :         aPrinter.m_aInfo.m_aContext.setParser( NULL );
     351           0 :         boost::unordered_map< OUString, PPDContext, OUStringHash >::const_iterator c_it = m_aDefaultContexts.find( aPrinterName );
     352           0 :         if( c_it != m_aDefaultContexts.end() )
     353             :         {
     354           0 :             aPrinter.m_aInfo.m_pParser = c_it->second.getParser();
     355           0 :             aPrinter.m_aInfo.m_aContext = c_it->second;
     356             :         }
     357           0 :         aPrinter.m_aInfo.setDefaultBackend(bUsePDF);
     358           0 :         aPrinter.m_aInfo.m_aDriverName = aBuf.makeStringAndClear();
     359           0 :         aPrinter.m_bModified = false;
     360             : 
     361           0 :         m_aPrinters[ aPrinter.m_aInfo.m_aPrinterName ] = aPrinter;
     362           0 :         m_aCUPSDestMap[ aPrinter.m_aInfo.m_aPrinterName ] = nPrinter;
     363           0 :     }
     364             : 
     365             :     // remove everything that is not a CUPS printer and not
     366             :     // a special purpose printer (PDF, Fax)
     367           0 :     std::list< OUString > aRemovePrinters;
     368           0 :     for( boost::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.begin();
     369           0 :          it != m_aPrinters.end(); ++it )
     370             :     {
     371           0 :         if( m_aCUPSDestMap.find( it->first ) != m_aCUPSDestMap.end() )
     372           0 :             continue;
     373             : 
     374           0 :         if( !it->second.m_aInfo.m_aFeatures.isEmpty() )
     375           0 :             continue;
     376           0 :         aRemovePrinters.push_back( it->first );
     377             :     }
     378           0 :     while( aRemovePrinters.begin() != aRemovePrinters.end() )
     379             :     {
     380           0 :         m_aPrinters.erase( aRemovePrinters.front() );
     381           0 :         aRemovePrinters.pop_front();
     382             :     }
     383             : 
     384           0 :     cupsSetPasswordCB( setPasswordCallback );
     385             : }
     386             : 
     387           0 : static void updatePrinterContextInfo( ppd_group_t* pPPDGroup, PPDContext& rContext )
     388             : {
     389           0 :     rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
     390           0 :     for( int i = 0; i < pPPDGroup->num_options; i++ )
     391             :     {
     392           0 :         ppd_option_t* pOption = pPPDGroup->options + i;
     393           0 :         for( int n = 0; n < pOption->num_choices; n++ )
     394             :         {
     395           0 :             ppd_choice_t* pChoice = pOption->choices + n;
     396           0 :             if( pChoice->marked )
     397             :             {
     398           0 :                 const PPDKey* pKey = rContext.getParser()->getKey( OStringToOUString( pOption->keyword, aEncoding ) );
     399           0 :                 if( pKey )
     400             :                 {
     401           0 :                     const PPDValue* pValue = pKey->getValue( OStringToOUString( pChoice->choice, aEncoding ) );
     402           0 :                     if( pValue )
     403             :                     {
     404           0 :                         if( pValue != pKey->getDefaultValue() )
     405             :                         {
     406           0 :                             rContext.setValue( pKey, pValue, true );
     407             : #if OSL_DEBUG_LEVEL > 1
     408             :                             fprintf( stderr, "key %s is set to %s\n", pOption->keyword, pChoice->choice );
     409             : #endif
     410             : 
     411             :                         }
     412             : #if OSL_DEBUG_LEVEL > 1
     413             :                         else
     414             :                             fprintf( stderr, "key %s is defaulted to %s\n", pOption->keyword, pChoice->choice );
     415             : #endif
     416             :                     }
     417             : #if OSL_DEBUG_LEVEL > 1
     418             :                     else
     419             :                         fprintf( stderr, "caution: value %s not found in key %s\n", pChoice->choice, pOption->keyword );
     420             : #endif
     421             :                 }
     422             : #if OSL_DEBUG_LEVEL > 1
     423             :                 else
     424             :                     fprintf( stderr, "caution: key %s not found in parser\n", pOption->keyword );
     425             : #endif
     426             :             }
     427             :         }
     428             :     }
     429             : 
     430             :     // recurse through subgroups
     431           0 :     for( int g = 0; g < pPPDGroup->num_subgroups; g++ )
     432             :     {
     433           0 :         updatePrinterContextInfo( pPPDGroup->subgroups + g, rContext );
     434             :     }
     435           0 : }
     436             : 
     437           0 : const PPDParser* CUPSManager::createCUPSParser( const OUString& rPrinter )
     438             : {
     439           0 :     const PPDParser* pNewParser = NULL;
     440           0 :     OUString aPrinter;
     441             : 
     442           0 :     if( rPrinter.compareToAscii( "CUPS:", 5 ) == 0 )
     443           0 :         aPrinter = rPrinter.copy( 5 );
     444             :     else
     445           0 :         aPrinter = rPrinter;
     446             : 
     447           0 :     if( m_aCUPSMutex.tryToAcquire() )
     448             :     {
     449           0 :         if( m_nDests && m_pDests && ! isCUPSDisabled() )
     450             :         {
     451             :             boost::unordered_map< OUString, int, OUStringHash >::iterator dest_it =
     452           0 :             m_aCUPSDestMap.find( aPrinter );
     453           0 :             if( dest_it != m_aCUPSDestMap.end() )
     454             :             {
     455           0 :                 cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second;
     456           0 :                 OString aPPDFile = threadedCupsGetPPD( pDest->name );
     457             :                 #if OSL_DEBUG_LEVEL > 1
     458             :                 fprintf( stderr, "PPD for %s is %s\n", OUStringToOString( aPrinter, osl_getThreadTextEncoding() ).getStr(), aPPDFile.getStr() );
     459             :                 #endif
     460           0 :                 if( !aPPDFile.isEmpty() )
     461             :                 {
     462           0 :                     rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
     463           0 :                     OUString aFileName( OStringToOUString( aPPDFile, aEncoding ) );
     464             :                     // update the printer info with context information
     465           0 :                     ppd_file_t* pPPD = ppdOpenFile( aPPDFile.getStr() );
     466           0 :                     if( pPPD )
     467             :                     {
     468             :                         // create the new parser
     469           0 :                         PPDParser* pCUPSParser = new PPDParser( aFileName );
     470           0 :                         pCUPSParser->m_aFile = rPrinter;
     471           0 :                         pNewParser = pCUPSParser;
     472             : 
     473           0 :                         /*int nConflicts =*/ cupsMarkOptions( pPPD, pDest->num_options, pDest->options );
     474             :                         #if OSL_DEBUG_LEVEL > 1
     475             :                         fprintf( stderr, "processing the following options for printer %s (instance %s):\n",
     476             :                         pDest->name, pDest->instance );
     477             :                         for( int k = 0; k < pDest->num_options; k++ )
     478             :                             fprintf( stderr, "   \"%s\" = \"%s\"\n",
     479             :                         pDest->options[k].name,
     480             :                         pDest->options[k].value );
     481             :                         #endif
     482           0 :                         PrinterInfo& rInfo = m_aPrinters[ aPrinter ].m_aInfo;
     483             : 
     484             :                         // remember the default context for later use
     485           0 :                         PPDContext& rContext = m_aDefaultContexts[ aPrinter ];
     486           0 :                         rContext.setParser( pNewParser );
     487             :                         // set system default paper; printer CUPS PPD options
     488             :                         // may overwrite it
     489           0 :                         setDefaultPaper( rContext );
     490           0 :                         for( int i = 0; i < pPPD->num_groups; i++ )
     491           0 :                             updatePrinterContextInfo( pPPD->groups + i, rContext );
     492             : 
     493           0 :                         rInfo.m_pParser = pNewParser;
     494           0 :                         rInfo.m_aContext = rContext;
     495             : 
     496             :                         // clean up the mess
     497           0 :                         ppdClose( pPPD );
     498             :                     }
     499             :                     #if OSL_DEBUG_LEVEL > 1
     500             :                     else
     501             :                         fprintf( stderr, "ppdOpenFile failed, falling back to generic driver\n" );
     502             :                     #endif
     503             : 
     504             :                     // remove temporary PPD file
     505           0 :                     unlink( aPPDFile.getStr() );
     506           0 :                 }
     507             :                 #if OSL_DEBUG_LEVEL > 1
     508             :                 else
     509             :                     fprintf( stderr, "cupsGetPPD failed, falling back to generic driver\n" );
     510             :                 #endif
     511             :             }
     512             :             #if OSL_DEBUG_LEVEL > 1
     513             :             else
     514             :                 fprintf( stderr, "no dest found for printer %s\n", OUStringToOString( aPrinter, osl_getThreadTextEncoding() ).getStr() );
     515             :             #endif
     516             :         }
     517           0 :         m_aCUPSMutex.release();
     518             :     }
     519             :     #if OSL_DEBUG_LEVEL >1
     520             :     else
     521             :         fprintf( stderr, "could not acquire CUPS mutex !!!\n" );
     522             :     #endif
     523             : 
     524           0 :     if( ! pNewParser )
     525             :     {
     526             :         // get the default PPD
     527           0 :         pNewParser = PPDParser::getParser( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) );
     528             : 
     529           0 :         PrinterInfo& rInfo = m_aPrinters[ aPrinter ].m_aInfo;
     530             : 
     531           0 :         rInfo.m_pParser = pNewParser;
     532           0 :         rInfo.m_aContext.setParser( pNewParser );
     533             :     }
     534             : 
     535           0 :     return pNewParser;
     536             : }
     537             : 
     538           0 : void CUPSManager::setupJobContextData( JobData& rData )
     539             : {
     540             :     boost::unordered_map< OUString, int, OUStringHash >::iterator dest_it =
     541           0 :         m_aCUPSDestMap.find( rData.m_aPrinterName );
     542             : 
     543           0 :     if( dest_it == m_aCUPSDestMap.end() )
     544           0 :         return PrinterInfoManager::setupJobContextData( rData );
     545             : 
     546             :     boost::unordered_map< OUString, Printer, OUStringHash >::iterator p_it =
     547           0 :         m_aPrinters.find( rData.m_aPrinterName );
     548           0 :     if( p_it == m_aPrinters.end() ) // huh ?
     549             :     {
     550             : #if OSL_DEBUG_LEVEL > 1
     551             :         fprintf( stderr, "CUPS printer list in disorder, no dest for printer %s !\n", OUStringToOString( rData.m_aPrinterName, osl_getThreadTextEncoding() ).getStr() );
     552             : #endif
     553             :         return;
     554             :     }
     555             : 
     556           0 :     if( p_it->second.m_aInfo.m_pParser == NULL )
     557             :     {
     558             :         // in turn calls createCUPSParser
     559             :         // which updates the printer info
     560           0 :         p_it->second.m_aInfo.m_pParser = PPDParser::getParser( p_it->second.m_aInfo.m_aDriverName );
     561             :     }
     562           0 :     if( p_it->second.m_aInfo.m_aContext.getParser() == NULL )
     563             :     {
     564           0 :         OUString aPrinter;
     565           0 :         if( p_it->second.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) == 0 )
     566           0 :             aPrinter = p_it->second.m_aInfo.m_aDriverName.copy( 5 );
     567             :         else
     568           0 :             aPrinter = p_it->second.m_aInfo.m_aDriverName;
     569             : 
     570           0 :         p_it->second.m_aInfo.m_aContext = m_aDefaultContexts[ aPrinter ];
     571             :     }
     572             : 
     573           0 :     rData.m_pParser     = p_it->second.m_aInfo.m_pParser;
     574           0 :     rData.m_aContext    = p_it->second.m_aInfo.m_aContext;
     575             : }
     576             : 
     577           0 : FILE* CUPSManager::startSpool( const OUString& rPrintername, bool bQuickCommand )
     578             : {
     579             :     OSL_TRACE( "endSpool: %s, %s",
     580             :                rtl::OUStringToOString( rPrintername, RTL_TEXTENCODING_UTF8 ).getStr(),
     581             :               bQuickCommand ? "true" : "false" );
     582             : 
     583           0 :     if( m_aCUPSDestMap.find( rPrintername ) == m_aCUPSDestMap.end() )
     584             :     {
     585             :         OSL_TRACE( "defer to PrinterInfoManager::startSpool" );
     586           0 :         return PrinterInfoManager::startSpool( rPrintername, bQuickCommand );
     587             :     }
     588             : 
     589           0 :     OUString aTmpURL, aTmpFile;
     590           0 :     osl_createTempFile( NULL, NULL, &aTmpURL.pData );
     591           0 :     osl_getSystemPathFromFileURL( aTmpURL.pData, &aTmpFile.pData );
     592           0 :     OString aSysFile = OUStringToOString( aTmpFile, osl_getThreadTextEncoding() );
     593           0 :     FILE* fp = fopen( aSysFile.getStr(), "w" );
     594           0 :     if( fp )
     595           0 :         m_aSpoolFiles[fp] = aSysFile;
     596             : 
     597           0 :     return fp;
     598             : }
     599             : 
     600             : struct less_ppd_key : public ::std::binary_function<double, double, bool>
     601             : {
     602           0 :     bool operator()(const PPDKey* left, const PPDKey* right)
     603           0 :     { return left->getOrderDependency() < right->getOrderDependency(); }
     604             : };
     605             : 
     606           0 : void CUPSManager::getOptionsFromDocumentSetup( const JobData& rJob, bool bBanner, int& rNumOptions, void** rOptions ) const
     607             : {
     608           0 :     rNumOptions = 0;
     609           0 :     *rOptions = NULL;
     610             : 
     611             :     // emit features ordered to OrderDependency
     612             :     // ignore features that are set to default
     613             : 
     614             :     // sanity check
     615           0 :     if( rJob.m_pParser == rJob.m_aContext.getParser() && rJob.m_pParser )
     616             :     {
     617             :         int i;
     618           0 :         int nKeys = rJob.m_aContext.countValuesModified();
     619           0 :         ::std::vector< const PPDKey* > aKeys( nKeys );
     620           0 :         for(  i = 0; i < nKeys; i++ )
     621           0 :             aKeys[i] = rJob.m_aContext.getModifiedKey( i );
     622           0 :         ::std::sort( aKeys.begin(), aKeys.end(), less_ppd_key() );
     623             : 
     624           0 :         for( i = 0; i < nKeys; i++ )
     625             :         {
     626           0 :             const PPDKey* pKey = aKeys[i];
     627           0 :             const PPDValue* pValue = rJob.m_aContext.getValue( pKey );
     628           0 :             if(pValue && pValue->m_eType == eInvocation && pValue->m_aValue.Len() )
     629             :             {
     630           0 :                 OString aKey = OUStringToOString( pKey->getKey(), RTL_TEXTENCODING_ASCII_US );
     631           0 :                 OString aValue = OUStringToOString( pValue->m_aOption, RTL_TEXTENCODING_ASCII_US );
     632           0 :                 rNumOptions = cupsAddOption( aKey.getStr(), aValue.getStr(), rNumOptions, (cups_option_t**)rOptions );
     633             :             }
     634           0 :         }
     635             :     }
     636             : 
     637           0 :     if( rJob.m_nPDFDevice > 0 && rJob.m_nCopies > 1 )
     638             :     {
     639           0 :         rtl::OString aVal( rtl::OString::valueOf( sal_Int32( rJob.m_nCopies ) ) );
     640           0 :         rNumOptions = cupsAddOption( "copies", aVal.getStr(), rNumOptions, (cups_option_t**)rOptions );
     641             :     }
     642           0 :     if( ! bBanner )
     643             :     {
     644           0 :         rNumOptions = cupsAddOption( "job-sheets", "none", rNumOptions, (cups_option_t**)rOptions );
     645             :     }
     646           0 : }
     647             : 
     648           0 : int CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData, bool bBanner )
     649             : {
     650             :     OSL_TRACE( "endSpool: %s, %s, copy count = %d",
     651             :                rtl::OUStringToOString( rPrintername, RTL_TEXTENCODING_UTF8 ).getStr(),
     652             :                rtl::OUStringToOString( rJobTitle, RTL_TEXTENCODING_UTF8 ).getStr(),
     653             :                rDocumentJobData.m_nCopies
     654             :                );
     655             : 
     656           0 :     int nJobID = 0;
     657             : 
     658           0 :     osl::MutexGuard aGuard( m_aCUPSMutex );
     659             : 
     660             :     boost::unordered_map< OUString, int, OUStringHash >::iterator dest_it =
     661           0 :         m_aCUPSDestMap.find( rPrintername );
     662           0 :     if( dest_it == m_aCUPSDestMap.end() )
     663             :     {
     664             :         OSL_TRACE( "defer to PrinterInfoManager::endSpool" );
     665           0 :         return PrinterInfoManager::endSpool( rPrintername, rJobTitle, pFile, rDocumentJobData, bBanner );
     666             :     }
     667             : 
     668           0 :     boost::unordered_map< FILE*, OString, FPtrHash >::const_iterator it = m_aSpoolFiles.find( pFile );
     669           0 :     if( it != m_aSpoolFiles.end() )
     670             :     {
     671           0 :         fclose( pFile );
     672           0 :         rtl_TextEncoding aEnc = osl_getThreadTextEncoding();
     673             : 
     674             :         // setup cups options
     675           0 :         int nNumOptions = 0;
     676           0 :         cups_option_t* pOptions = NULL;
     677           0 :         getOptionsFromDocumentSetup( rDocumentJobData, bBanner, nNumOptions, (void**)&pOptions );
     678             : 
     679           0 :         cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second;
     680             :         nJobID = cupsPrintFile( pDest->name,
     681           0 :         it->second.getStr(),
     682             :         OUStringToOString( rJobTitle, aEnc ).getStr(),
     683           0 :         nNumOptions, pOptions );
     684             : #if OSL_DEBUG_LEVEL > 1
     685             :         fprintf( stderr, "cupsPrintFile( %s, %s, %s, %d, %p ) returns %d\n",
     686             :                     pDest->name,
     687             :                     it->second.getStr(),
     688             :                     OUStringToOString( rJobTitle, aEnc ).getStr(),
     689             :                     nNumOptions,
     690             :                     pOptions,
     691             :                     nJobID
     692             :                     );
     693             :         for( int n = 0; n < nNumOptions; n++ )
     694             :             fprintf( stderr, "    option %s=%s\n", pOptions[n].name, pOptions[n].value );
     695             :         OString aCmd( "cp " );
     696             :         aCmd = aCmd + it->second;
     697             :         aCmd = aCmd + OString( " $HOME/cupsprint.ps" );
     698             :         system( aCmd.getStr() );
     699             : #endif
     700             : 
     701           0 :         unlink( it->second.getStr() );
     702           0 :         m_aSpoolFiles.erase( pFile );
     703           0 :         if( pOptions )
     704           0 :             cupsFreeOptions( nNumOptions, pOptions );
     705             :     }
     706             : 
     707           0 :     return nJobID;
     708             : }
     709             : 
     710             : 
     711           0 : void CUPSManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo )
     712             : {
     713           0 :     PrinterInfoManager::changePrinterInfo( rPrinter, rNewInfo );
     714           0 : }
     715             : 
     716          38 : bool CUPSManager::checkPrintersChanged( bool bWait )
     717             : {
     718          38 :     bool bChanged = false;
     719          38 :     if( bWait )
     720             :     {
     721          38 :         if(  m_aDestThread )
     722             :         {
     723             :             // initial asynchronous detection still running
     724             :             #if OSL_DEBUG_LEVEL > 1
     725             :             fprintf( stderr, "syncing cups discovery thread\n" );
     726             :             #endif
     727          38 :             osl_joinWithThread( m_aDestThread );
     728          38 :             osl_destroyThread( m_aDestThread );
     729          38 :             m_aDestThread = NULL;
     730             :             #if OSL_DEBUG_LEVEL > 1
     731             :             fprintf( stderr, "done: syncing cups discovery thread\n" );
     732             :             #endif
     733             :         }
     734             :         else
     735             :         {
     736             :             // #i82321# check for cups printer updates
     737             :             // with this change the whole asynchronous detection in a thread is
     738             :             // almost useless. The only relevance left is for some stalled systems
     739             :             // where the user can set SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION
     740             :             // (see vcl/unx/source/gdi/salprnpsp.cxx)
     741             :             // so that checkPrintersChanged( true ) will never be called
     742             : 
     743             :             // there is no way to query CUPS whether the printer list has changed
     744             :             // so get the dest list anew
     745           0 :             if( m_nDests && m_pDests )
     746           0 :                 cupsFreeDests( m_nDests, (cups_dest_t*)m_pDests );
     747           0 :             m_nDests = 0;
     748           0 :             m_pDests = NULL;
     749           0 :             runDests();
     750             :         }
     751             :     }
     752          38 :     if( m_aCUPSMutex.tryToAcquire() )
     753             :     {
     754          38 :         bChanged = m_bNewDests;
     755          38 :         m_aCUPSMutex.release();
     756             :     }
     757             : 
     758          38 :     if( ! bChanged )
     759             :     {
     760           0 :         bChanged = PrinterInfoManager::checkPrintersChanged( bWait );
     761             :         // #i54375# ensure new merging with CUPS list in :initialize
     762           0 :         if( bChanged )
     763           0 :             m_bNewDests = true;
     764             :     }
     765             : 
     766          38 :     if( bChanged )
     767          38 :         initialize();
     768             : 
     769          38 :     return bChanged;
     770             : }
     771             : 
     772           0 : bool CUPSManager::addPrinter( const OUString& rName, const OUString& rDriver )
     773             : {
     774             :     // don't touch the CUPS printers
     775           0 :     if( m_aCUPSDestMap.find( rName ) != m_aCUPSDestMap.end() ||
     776           0 :         rDriver.compareToAscii( "CUPS:", 5 ) == 0
     777             :         )
     778           0 :         return false;
     779           0 :     return PrinterInfoManager::addPrinter( rName, rDriver );
     780             : }
     781             : 
     782           0 : bool CUPSManager::removePrinter( const OUString& rName, bool bCheck )
     783             : {
     784             :     // don't touch the CUPS printers
     785           0 :     if( m_aCUPSDestMap.find( rName ) != m_aCUPSDestMap.end() )
     786           0 :         return false;
     787           0 :     return PrinterInfoManager::removePrinter( rName, bCheck );
     788             : }
     789             : 
     790           0 : bool CUPSManager::setDefaultPrinter( const OUString& rName )
     791             : {
     792           0 :     bool bSuccess = false;
     793             :     boost::unordered_map< OUString, int, OUStringHash >::iterator nit =
     794           0 :         m_aCUPSDestMap.find( rName );
     795           0 :     if( nit != m_aCUPSDestMap.end() && m_aCUPSMutex.tryToAcquire() )
     796             :     {
     797           0 :         cups_dest_t* pDests = (cups_dest_t*)m_pDests;
     798           0 :         for( int i = 0; i < m_nDests; i++ )
     799           0 :             pDests[i].is_default = 0;
     800           0 :         pDests[ nit->second ].is_default = 1;
     801           0 :         cupsSetDests( m_nDests, (cups_dest_t*)m_pDests );
     802           0 :         m_aDefaultPrinter = rName;
     803           0 :         m_aCUPSMutex.release();
     804           0 :         bSuccess = true;
     805             :     }
     806             :     else
     807           0 :         bSuccess = PrinterInfoManager::setDefaultPrinter( rName );
     808             : 
     809           0 :     return bSuccess;
     810             : }
     811             : 
     812           0 : bool CUPSManager::writePrinterConfig()
     813             : {
     814           0 :     bool bDestModified = false;
     815           0 :     rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
     816             : 
     817           0 :     for( boost::unordered_map< OUString, Printer, OUStringHash >::iterator prt =
     818           0 :              m_aPrinters.begin(); prt != m_aPrinters.end(); ++prt )
     819             :     {
     820             :         boost::unordered_map< OUString, int, OUStringHash >::iterator nit =
     821           0 :             m_aCUPSDestMap.find( prt->first );
     822           0 :         if( nit == m_aCUPSDestMap.end() )
     823           0 :             continue;
     824             : 
     825           0 :         if( ! prt->second.m_bModified )
     826           0 :             continue;
     827             : 
     828           0 :         if( m_aCUPSMutex.tryToAcquire() )
     829             :         {
     830           0 :             bDestModified = true;
     831           0 :             cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + nit->second;
     832           0 :             PrinterInfo& rInfo = prt->second.m_aInfo;
     833             : 
     834             :             // create new option list
     835           0 :             int nNewOptions = 0;
     836           0 :             cups_option_t* pNewOptions = NULL;
     837           0 :             int nValues = rInfo.m_aContext.countValuesModified();
     838           0 :             for( int i = 0; i < nValues; i++ )
     839             :             {
     840           0 :                 const PPDKey* pKey = rInfo.m_aContext.getModifiedKey( i );
     841           0 :                 const PPDValue* pValue = rInfo.m_aContext.getValue( pKey );
     842           0 :                 if( pKey && pValue ) // sanity check
     843             :                 {
     844           0 :                     OString aName = OUStringToOString( pKey->getKey(), aEncoding );
     845           0 :                     OString aValue = OUStringToOString( pValue->m_aOption, aEncoding );
     846           0 :                     nNewOptions = cupsAddOption( aName.getStr(), aValue.getStr(), nNewOptions, &pNewOptions );
     847             :                 }
     848             :             }
     849             :             // set PPD options on CUPS dest
     850           0 :             cupsFreeOptions( pDest->num_options, pDest->options );
     851           0 :             pDest->num_options = nNewOptions;
     852           0 :             pDest->options = pNewOptions;
     853           0 :             m_aCUPSMutex.release();
     854             :         }
     855             :     }
     856           0 :     if( bDestModified && m_aCUPSMutex.tryToAcquire() )
     857             :     {
     858           0 :         cupsSetDests( m_nDests, (cups_dest_t*)m_pDests );
     859           0 :         m_aCUPSMutex.release();
     860             :     }
     861             : 
     862           0 :     return PrinterInfoManager::writePrinterConfig();
     863             : }
     864             : 
     865           0 : bool CUPSManager::addOrRemovePossible() const
     866             : {
     867           0 :     return (m_nDests && m_pDests && ! isCUPSDisabled())? false : PrinterInfoManager::addOrRemovePossible();
     868             : }
     869             : 
     870           0 : const char* CUPSManager::authenticateUser( const char* /*pIn*/ )
     871             : {
     872           0 :     const char* pRet = NULL;
     873             : 
     874           0 :     OUString aLib(_XSALSET_LIBNAME );
     875           0 :     oslModule pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY );
     876           0 :     if( pLib )
     877             :     {
     878           0 :         OUString aSym( "Sal_authenticateQuery"  );
     879             :         bool (*getpw)( const OString& rServer, OString& rUser, OString& rPw) =
     880           0 :             (bool(*)(const OString&,OString&,OString&))osl_getFunctionSymbol( pLib, aSym.pData );
     881           0 :         if( getpw )
     882             :         {
     883           0 :             osl::MutexGuard aGuard( m_aCUPSMutex );
     884             : 
     885           0 :             OString aUser = cupsUser();
     886           0 :             OString aServer = cupsServer();
     887           0 :             OString aPassword;
     888           0 :             if( getpw( aServer, aUser, aPassword ) )
     889             :             {
     890           0 :                 m_aPassword = aPassword;
     891           0 :                 m_aUser = aUser;
     892           0 :                 cupsSetUser( m_aUser.getStr() );
     893           0 :                 pRet = m_aPassword.getStr();
     894           0 :             }
     895             :         }
     896           0 :         osl_unloadModule( pLib );
     897             :     }
     898             : #if OSL_DEBUG_LEVEL > 1
     899             :     else fprintf( stderr, "loading of module %s failed\n", OUStringToOString( aLib, osl_getThreadTextEncoding() ).getStr() );
     900             : #endif
     901             : 
     902           0 :     return pRet;
     903             : }
     904             : 
     905             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10