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

Generated by: LCOV version 1.10