LCOV - code coverage report
Current view: top level - vcl/unx/generic/printer - cupsmgr.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 43 418 10.3 %
Date: 2014-11-03 Functions: 9 38 23.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10