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

Generated by: LCOV version 1.10