diff options
Diffstat (limited to 'vcl/unx/source/printer/cupsmgr.cxx')
-rw-r--r-- | vcl/unx/source/printer/cupsmgr.cxx | 1183 |
1 files changed, 0 insertions, 1183 deletions
diff --git a/vcl/unx/source/printer/cupsmgr.cxx b/vcl/unx/source/printer/cupsmgr.cxx deleted file mode 100644 index 655181294190..000000000000 --- a/vcl/unx/source/printer/cupsmgr.cxx +++ /dev/null @@ -1,1183 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_vcl.hxx" - -#ifdef ENABLE_CUPS -#include <cups/cups.h> -#include <cups/ppd.h> - -#else // !ENABLE_CUPS -typedef void ppd_file_t; -typedef void cups_dest_t; -typedef void cups_option_t; -#endif - -#include <unistd.h> - -#include "cupsmgr.hxx" - -#include "osl/thread.h" -#include "osl/diagnose.h" -#include "osl/conditn.hxx" - -#include "rtl/ustrbuf.hxx" - -#include <algorithm> -#include <setjmp.h> -#include <signal.h> - -#define CUPS_LIB_NAME "libcups.so.2" - -namespace psp -{ -class CUPSWrapper -{ - oslModule m_pLib; - osl::Mutex m_aGetPPDMutex; - bool m_bPPDThreadRunning; - - int (*m_pcupsPrintFile)(const char*, const char*, const char*, int, cups_option_t*); - int (*m_pcupsGetDests)(cups_dest_t**); - void (*m_pcupsSetDests)(int,cups_dest_t*); - void (*m_pcupsFreeDests)(int,cups_dest_t*); - const char* (*m_pcupsGetPPD)(const char*); - int (*m_pcupsMarkOptions)(ppd_file_t*,int,cups_option_t*); - int (*m_pcupsAddOption)(const char*,const char*,int,cups_option_t**); - void (*m_pcupsFreeOptions)(int,cups_option_t*); - ppd_file_t* (*m_pppdOpenFile)(const char* pFile); - void (*m_pppdClose)(ppd_file_t*); - const char* (*m_pcupsServer)(); - void (*m_pcupsSetPasswordCB)(const char*(cb)(const char*)); - const char* (*m_pcupsUser)(); - void (*m_pcupsSetUser)(const char*); - const char* (*m_pcupsGetOption)(const char*,int,cups_option_t*); - - oslGenericFunction loadSymbol( const char* ); -public: - CUPSWrapper(); - ~CUPSWrapper(); - - bool isValid(); - - int cupsGetDests(cups_dest_t** pDests) - { return m_pcupsGetDests(pDests); } - - void cupsSetDests( int nDests, cups_dest_t* pDests ) - { m_pcupsSetDests( nDests, pDests ); } - - void cupsFreeDests(int nDests, cups_dest_t* pDests) - { m_pcupsFreeDests(nDests, pDests); } - - int cupsPrintFile( const char* pPrinter, - const char* pFileName, - const char* pTitle, - int nOptions, - cups_option_t* pOptions ) - { return m_pcupsPrintFile( pPrinter, pFileName, pTitle, nOptions, pOptions ); } - - rtl::OString cupsGetPPD( const char* pPrinter ); - - int cupsMarkOptions(ppd_file_t* pPPD, int nOptions, cups_option_t* pOptions ) - { return m_pcupsMarkOptions(pPPD, nOptions, pOptions); } - - int cupsAddOption( const char* pName, const char* pValue, int nOptions, cups_option_t** pOptions ) - { return m_pcupsAddOption( pName, pValue, nOptions, pOptions ); } - - void cupsFreeOptions( int nOptions, cups_option_t* pOptions ) - { m_pcupsFreeOptions( nOptions, pOptions ); } - - ppd_file_t* ppdOpenFile( const char* pFileName ) - { return m_pppdOpenFile( pFileName ); } - - void ppdClose( ppd_file_t* pPPD ) - { m_pppdClose( pPPD ); } - - const char *cupsServer(void) - { return m_pcupsServer(); } - - const char *cupsUser(void) - { return m_pcupsUser(); } - - void cupsSetPasswordCB(const char *(*cb)(const char *)) - { m_pcupsSetPasswordCB( cb ); } - - void cupsSetUser(const char *user) - { m_pcupsSetUser( user ); } - - const char* cupsGetOption(const char* name, int num_options, cups_option_t* options) - { return m_pcupsGetOption( name, num_options, options ); } - -}; -} - -using namespace psp; -using namespace osl; - -using ::rtl::OUString; -using ::rtl::OUStringBuffer; -using ::rtl::OUStringToOString; -using ::rtl::OStringToOUString; -using ::rtl::OUStringHash; -using ::rtl::OString; - -/* - * CUPSWrapper class - */ - -oslGenericFunction CUPSWrapper::loadSymbol( const char* pSymbol ) -{ - OUString aSym( OUString::createFromAscii( pSymbol ) ); - oslGenericFunction pSym = osl_getFunctionSymbol( m_pLib, aSym.pData ); -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "%s %s\n", pSymbol, pSym ? "found" : "not found" ); -#endif - return pSym; -} - -CUPSWrapper::CUPSWrapper() - : m_pLib( NULL ), - m_bPPDThreadRunning( false ) -{ -#ifdef ENABLE_CUPS - OUString aLib( RTL_CONSTASCII_USTRINGPARAM( CUPS_LIB_NAME ) ); - m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY ); - if( ! m_pLib ) - { - aLib = OUString( RTL_CONSTASCII_USTRINGPARAM( SAL_MODULENAME( "cups" ) ) ); - m_pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY ); - } -#endif - - if( ! m_pLib ) - { -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "no cups library found\n" ); -#endif - return; - } - - m_pcupsPrintFile = (int(*)(const char*,const char*,const char*,int,cups_option_t*)) - loadSymbol( "cupsPrintFile" ); - m_pcupsGetDests = (int(*)(cups_dest_t**)) - loadSymbol( "cupsGetDests" ); - m_pcupsSetDests = (void(*)(int,cups_dest_t*)) - loadSymbol( "cupsSetDests" ); - m_pcupsFreeDests = (void(*)(int,cups_dest_t*)) - loadSymbol( "cupsFreeDests" ); - m_pcupsGetPPD = (const char*(*)(const char*)) - loadSymbol( "cupsGetPPD" ); - m_pcupsMarkOptions = (int(*)(ppd_file_t*,int,cups_option_t*)) - loadSymbol( "cupsMarkOptions" ); - m_pcupsAddOption = (int(*)(const char*,const char*,int,cups_option_t**)) - loadSymbol( "cupsAddOption" ); - m_pcupsFreeOptions = (void(*)(int,cups_option_t*)) - loadSymbol( "cupsFreeOptions" ); - m_pppdOpenFile = (ppd_file_t*(*)(const char*)) - loadSymbol( "ppdOpenFile" ); - m_pppdClose = (void(*)(ppd_file_t*)) - loadSymbol( "ppdClose" ); - m_pcupsServer = (const char*(*)()) - loadSymbol( "cupsServer" ); - m_pcupsUser = (const char*(*)()) - loadSymbol( "cupsUser" ); - m_pcupsSetPasswordCB = (void(*)(const char*(*)(const char*))) - loadSymbol( "cupsSetPasswordCB" ); - m_pcupsSetUser = (void(*)(const char*)) - loadSymbol( "cupsSetUser" ); - m_pcupsGetOption = (const char*(*)(const char*,int,cups_option_t*)) - loadSymbol( "cupsGetOption" ); - - if( ! ( - m_pcupsPrintFile && - m_pcupsGetDests && - m_pcupsSetDests && - m_pcupsFreeDests && - m_pcupsGetPPD && - m_pcupsMarkOptions && - m_pcupsAddOption && - m_pcupsServer && - m_pcupsUser && - m_pcupsSetPasswordCB && - m_pcupsSetUser && - m_pcupsFreeOptions && - m_pppdOpenFile && - m_pppdClose && - m_pcupsGetOption - ) ) - { - osl_unloadModule( m_pLib ); - m_pLib = NULL; - } -} - -CUPSWrapper::~CUPSWrapper() -{ - if( m_pLib ) - osl_unloadModule( m_pLib ); -} - -bool CUPSWrapper::isValid() -{ - return m_pLib != NULL; -} - -typedef const char*(*PPDFunction)(const char*); -struct GetPPDAttribs -{ - PPDFunction m_pFunction; - osl::Condition m_aCondition; - OString m_aParameter; - OString m_aResult; - oslThread m_aThread; - int m_nRefs; - bool* m_pResetRunning; - osl::Mutex* m_pSyncMutex; - - GetPPDAttribs( PPDFunction pFn, const char * m_pParameter, - bool* pResetRunning, osl::Mutex* pSyncMutex ) - : m_pFunction( pFn ), - m_aParameter( m_pParameter ), - m_pResetRunning( pResetRunning ), - m_pSyncMutex( pSyncMutex ) - { - m_nRefs = 2; - m_aCondition.reset(); - } - - ~GetPPDAttribs() - { - if( m_aResult.getLength() ) - unlink( m_aResult.getStr() ); - } - - void unref() - { - if( --m_nRefs == 0 ) - { - *m_pResetRunning = false; - delete this; - } - } - - void executeCall() - { - // This CUPS method is not at all thread-safe we need - // to dup the pointer to a static buffer it returns ASAP - OString aResult = m_pFunction( m_aParameter ); - MutexGuard aGuard( *m_pSyncMutex ); - m_aResult = aResult; - m_aCondition.set(); - unref(); - } - - OString waitResult( TimeValue *pDelay ) - { - m_pSyncMutex->release(); - - if (m_aCondition.wait( pDelay ) != Condition::result_ok - ) - { - #if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "cupsGetPPD %s timed out\n", - (const sal_Char *) m_aParameter - ); - #endif - } - m_pSyncMutex->acquire(); - - OString aRetval = m_aResult; - m_aResult = OString(); - unref(); - - return aRetval; - } -}; - -extern "C" { - static void getPPDWorker(void* pData) - { - GetPPDAttribs* pAttribs = (GetPPDAttribs*)pData; - pAttribs->executeCall(); - } -} - -OString CUPSWrapper::cupsGetPPD( const char* pPrinter ) -{ - OString aResult; - - m_aGetPPDMutex.acquire(); - // if one thread hangs in cupsGetPPD already, don't start another - if( ! m_bPPDThreadRunning ) - { - m_bPPDThreadRunning = true; - GetPPDAttribs* pAttribs = new GetPPDAttribs( m_pcupsGetPPD, - pPrinter, - &m_bPPDThreadRunning, - &m_aGetPPDMutex ); - - oslThread aThread = osl_createThread( getPPDWorker, pAttribs ); - - TimeValue aValue; - aValue.Seconds = 5; - aValue.Nanosec = 0; - - // NOTE: waitResult release and acquires the GetPPD mutex - aResult = pAttribs->waitResult( &aValue ); - osl_destroyThread( aThread ); - } - m_aGetPPDMutex.release(); - - return aResult; -} - -#ifdef ENABLE_CUPS -static const char* setPasswordCallback( const char* pIn ) -{ - const char* pRet = NULL; - - PrinterInfoManager& rMgr = PrinterInfoManager::get(); - if( rMgr.getType() == PrinterInfoManager::CUPS ) // sanity check - pRet = static_cast<CUPSManager&>(rMgr).authenticateUser( pIn ); - return pRet; -} -#endif - -/* - * CUPSManager class - */ - -CUPSManager* CUPSManager::tryLoadCUPS() -{ - CUPSManager* pManager = NULL; -#ifdef ENABLE_CUPS - static const char* pEnv = getenv( "SAL_DISABLE_CUPS" ); - - if( ! pEnv || ! *pEnv ) - { - // try to load CUPS - CUPSWrapper* pWrapper = new CUPSWrapper(); - if( pWrapper->isValid() ) - pManager = new CUPSManager( pWrapper ); - else - delete pWrapper; - } -#endif - return pManager; -} - -extern "C" -{ -static void run_dest_thread_stub( void* pThis ) -{ - CUPSManager::runDestThread( pThis ); -} -} - -CUPSManager::CUPSManager( CUPSWrapper* pWrapper ) : - PrinterInfoManager( CUPS ), - m_pCUPSWrapper( pWrapper ), - m_nDests( 0 ), - m_pDests( NULL ), - m_bNewDests( false ) -{ - m_aDestThread = osl_createThread( run_dest_thread_stub, this ); -} - -CUPSManager::~CUPSManager() -{ - if( m_aDestThread ) - { - // if the thread is still running here, then - // cupsGetDests is hung; terminate the thread instead of joining - osl_terminateThread( m_aDestThread ); - osl_destroyThread( m_aDestThread ); - } - - if( m_nDests && m_pDests ) - m_pCUPSWrapper->cupsFreeDests( m_nDests, (cups_dest_t*)m_pDests ); - delete m_pCUPSWrapper; -} - -void CUPSManager::runDestThread( void* pThis ) -{ - ((CUPSManager*)pThis)->runDests(); -} - -static sigjmp_buf aViolationBuffer; - -extern "C" -{ - static void lcl_signal_action(int nSignal) - { - fprintf( stderr, "Signal %d during fontconfig initialization called, ignoring fontconfig\n", nSignal ); - siglongjmp( aViolationBuffer, 1 ); - } -} - -void CUPSManager::runDests() -{ -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "starting cupsGetDests\n" ); -#endif - cups_dest_t* pDests = NULL; - - // #i86306# prepare against really broken CUPS installations / missing servers - - // install signal handler for SEGV, BUS and ABRT - struct sigaction act; - struct sigaction oact[3]; - - act.sa_handler = lcl_signal_action; - act.sa_flags = 0; - sigemptyset(&(act.sa_mask)); - - int nSegvSignalInstalled = sigaction(SIGSEGV, &act, &oact[0]); - int nBusSignalInstalled = sigaction(SIGBUS, &act, &oact[1]); - int nAbortSignalInstalled = sigaction(SIGABRT, &act, &oact[2]); - - // prepare against a signal during FcInit or FcConfigGetCurrent - if( sigsetjmp( aViolationBuffer, ~0 ) == 0 ) - { - int nDests = m_pCUPSWrapper->cupsGetDests( &pDests ); - #if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "came out of cupsGetDests\n" ); - #endif - - osl::MutexGuard aGuard( m_aCUPSMutex ); - m_nDests = nDests; - m_pDests = pDests; - m_bNewDests = true; - #if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "finished cupsGetDests\n" ); - #endif - } - else - { - #if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "cupsGetDests crashed, not using CUPS\n" ); - #endif - } - - // restore old signal handlers - if( nSegvSignalInstalled == 0 ) - sigaction( SIGSEGV, &oact[0], NULL ); - if( nBusSignalInstalled == 0 ) - sigaction( SIGBUS, &oact[1], NULL ); - if( nAbortSignalInstalled == 0 ) - sigaction( SIGABRT, &oact[2], NULL ); -} - -void CUPSManager::initialize() -{ - // get normal printers, clear printer list - PrinterInfoManager::initialize(); - -#ifdef ENABLE_CUPS - // check whether thread has completed - // if not behave like old printing system - osl::MutexGuard aGuard( m_aCUPSMutex ); - - if( ! m_bNewDests ) - return; - - // dest thread has run, clean up - if( m_aDestThread ) - { - osl_joinWithThread( m_aDestThread ); - osl_destroyThread( m_aDestThread ); - m_aDestThread = NULL; - } - m_bNewDests = false; - - // clear old stuff - m_aCUPSDestMap.clear(); - - if( ! (m_nDests && m_pDests ) ) - return; - - if( isCUPSDisabled() ) - return; - - // check for CUPS server(?) > 1.2 - // since there is no API to query, check for options that were - // introduced in dests with 1.2 - // this is needed to check for %%IncludeFeature support - // (#i65684#, #i65491#) - bool bUsePDF = false; - cups_dest_t* pDest = ((cups_dest_t*)m_pDests); - const char* pOpt = m_pCUPSWrapper->cupsGetOption( "printer-info", - pDest->num_options, - pDest->options ); - if( pOpt ) - { - m_bUseIncludeFeature = true; - bUsePDF = true; - if( m_aGlobalDefaults.m_nPSLevel == 0 && m_aGlobalDefaults.m_nPDFDevice == 0 ) - m_aGlobalDefaults.m_nPDFDevice = 1; - } - // do not send include JobPatch; CUPS will insert that itself - // TODO: currently unknwon which versions of CUPS insert JobPatches - // so currently it is assumed CUPS = don't insert JobPatch files - m_bUseJobPatch = false; - - rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); - int nPrinter = m_nDests; - - // reset global default PPD options; these are queried on demand from CUPS - m_aGlobalDefaults.m_pParser = NULL; - m_aGlobalDefaults.m_aContext = PPDContext(); - - // add CUPS printers, should there be a printer - // with the same name as a CUPS printer, overwrite it - while( nPrinter-- ) - { - pDest = ((cups_dest_t*)m_pDests)+nPrinter; - OUString aPrinterName = OStringToOUString( pDest->name, aEncoding ); - if( pDest->instance && *pDest->instance ) - { - OUStringBuffer aBuf( 256 ); - aBuf.append( aPrinterName ); - aBuf.append( sal_Unicode( '/' ) ); - aBuf.append( OStringToOUString( pDest->instance, aEncoding ) ); - aPrinterName = aBuf.makeStringAndClear(); - } - - // initialize printer with possible configuration from psprint.conf - bool bSetToGlobalDefaults = m_aPrinters.find( aPrinterName ) == m_aPrinters.end(); - Printer aPrinter = m_aPrinters[ aPrinterName ]; - if( bSetToGlobalDefaults ) - aPrinter.m_aInfo = m_aGlobalDefaults; - aPrinter.m_aInfo.m_aPrinterName = aPrinterName; - if( pDest->is_default ) - m_aDefaultPrinter = aPrinterName; - - for( int k = 0; k < pDest->num_options; k++ ) - { - if(!strcmp(pDest->options[k].name, "printer-info")) - aPrinter.m_aInfo.m_aComment=OStringToOUString(pDest->options[k].value, aEncoding); - if(!strcmp(pDest->options[k].name, "printer-location")) - aPrinter.m_aInfo.m_aLocation=OStringToOUString(pDest->options[k].value, aEncoding); - } - - - OUStringBuffer aBuf( 256 ); - aBuf.appendAscii( "CUPS:" ); - aBuf.append( aPrinterName ); - // note: the parser that goes with the PrinterInfo - // is created implicitly by the JobData::operator=() - // when it detects the NULL ptr m_pParser. - // if we wanted to fill in the parser here this - // would mean we'd have to download PPDs for each and - // every printer - which would be really bad runtime - // behaviour - aPrinter.m_aInfo.m_pParser = NULL; - aPrinter.m_aInfo.m_aContext.setParser( NULL ); - boost::unordered_map< OUString, PPDContext, OUStringHash >::const_iterator c_it = m_aDefaultContexts.find( aPrinterName ); - if( c_it != m_aDefaultContexts.end() ) - { - aPrinter.m_aInfo.m_pParser = c_it->second.getParser(); - aPrinter.m_aInfo.m_aContext = c_it->second; - } - if( bUsePDF && aPrinter.m_aInfo.m_nPSLevel == 0 && aPrinter.m_aInfo.m_nPDFDevice == 0 ) - aPrinter.m_aInfo.m_nPDFDevice = 1; - aPrinter.m_aInfo.m_aDriverName = aBuf.makeStringAndClear(); - aPrinter.m_bModified = false; - - m_aPrinters[ aPrinter.m_aInfo.m_aPrinterName ] = aPrinter; - m_aCUPSDestMap[ aPrinter.m_aInfo.m_aPrinterName ] = nPrinter; - } - - // remove everything that is not a CUPS printer and not - // a special purpose printer (PDF, Fax) - std::list< OUString > aRemovePrinters; - for( boost::unordered_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.begin(); - it != m_aPrinters.end(); ++it ) - { - if( m_aCUPSDestMap.find( it->first ) != m_aCUPSDestMap.end() ) - continue; - - if( it->second.m_aInfo.m_aFeatures.getLength() > 0 ) - continue; - aRemovePrinters.push_back( it->first ); - } - while( aRemovePrinters.begin() != aRemovePrinters.end() ) - { - m_aPrinters.erase( aRemovePrinters.front() ); - aRemovePrinters.pop_front(); - } - - m_pCUPSWrapper->cupsSetPasswordCB( setPasswordCallback ); -#endif // ENABLE_CUPS -} - -#ifdef ENABLE_CUPS -static void updatePrinterContextInfo( ppd_group_t* pPPDGroup, PPDContext& rContext ) -{ - rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); - for( int i = 0; i < pPPDGroup->num_options; i++ ) - { - ppd_option_t* pOption = pPPDGroup->options + i; - for( int n = 0; n < pOption->num_choices; n++ ) - { - ppd_choice_t* pChoice = pOption->choices + n; - if( pChoice->marked ) - { - const PPDKey* pKey = rContext.getParser()->getKey( OStringToOUString( pOption->keyword, aEncoding ) ); - if( pKey ) - { - const PPDValue* pValue = pKey->getValue( OStringToOUString( pChoice->choice, aEncoding ) ); - if( pValue ) - { - if( pValue != pKey->getDefaultValue() ) - { - rContext.setValue( pKey, pValue, true ); -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "key %s is set to %s\n", pOption->keyword, pChoice->choice ); -#endif - - } -#if OSL_DEBUG_LEVEL > 1 - else - fprintf( stderr, "key %s is defaulted to %s\n", pOption->keyword, pChoice->choice ); -#endif - } -#if OSL_DEBUG_LEVEL > 1 - else - fprintf( stderr, "caution: value %s not found in key %s\n", pChoice->choice, pOption->keyword ); -#endif - } -#if OSL_DEBUG_LEVEL > 1 - else - fprintf( stderr, "caution: key %s not found in parser\n", pOption->keyword ); -#endif - } - } - } - - // recurse through subgroups - for( int g = 0; g < pPPDGroup->num_subgroups; g++ ) - { - updatePrinterContextInfo( pPPDGroup->subgroups + g, rContext ); - } -} -#endif // ENABLE_CUPS - -const PPDParser* CUPSManager::createCUPSParser( const OUString& rPrinter ) -{ - const PPDParser* pNewParser = NULL; - OUString aPrinter; - - if( rPrinter.compareToAscii( "CUPS:", 5 ) == 0 ) - aPrinter = rPrinter.copy( 5 ); - else - aPrinter = rPrinter; - -#ifdef ENABLE_CUPS - if( m_aCUPSMutex.tryToAcquire() ) - { - if( m_nDests && m_pDests && ! isCUPSDisabled() ) - { - boost::unordered_map< OUString, int, OUStringHash >::iterator dest_it = - m_aCUPSDestMap.find( aPrinter ); - if( dest_it != m_aCUPSDestMap.end() ) - { - cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second; - OString aPPDFile = m_pCUPSWrapper->cupsGetPPD( pDest->name ); - #if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "PPD for %s is %s\n", OUStringToOString( aPrinter, osl_getThreadTextEncoding() ).getStr(), aPPDFile.getStr() ); - #endif - if( aPPDFile.getLength() ) - { - rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); - OUString aFileName( OStringToOUString( aPPDFile, aEncoding ) ); - // update the printer info with context information - ppd_file_t* pPPD = m_pCUPSWrapper->ppdOpenFile( aPPDFile.getStr() ); - if( pPPD ) - { - // create the new parser - PPDParser* pCUPSParser = new PPDParser( aFileName ); - pCUPSParser->m_aFile = rPrinter; - pNewParser = pCUPSParser; - - /*int nConflicts =*/ m_pCUPSWrapper->cupsMarkOptions( pPPD, pDest->num_options, pDest->options ); - #if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "processing the following options for printer %s (instance %s):\n", - pDest->name, pDest->instance ); - for( int k = 0; k < pDest->num_options; k++ ) - fprintf( stderr, " \"%s\" = \"%s\"\n", - pDest->options[k].name, - pDest->options[k].value ); - #endif - PrinterInfo& rInfo = m_aPrinters[ aPrinter ].m_aInfo; - - // remember the default context for later use - PPDContext& rContext = m_aDefaultContexts[ aPrinter ]; - rContext.setParser( pNewParser ); - // set system default paper; printer CUPS PPD options - // may overwrite it - setDefaultPaper( rContext ); - for( int i = 0; i < pPPD->num_groups; i++ ) - updatePrinterContextInfo( pPPD->groups + i, rContext ); - - rInfo.m_pParser = pNewParser; - rInfo.m_aContext = rContext; - - // clean up the mess - m_pCUPSWrapper->ppdClose( pPPD ); - } - #if OSL_DEBUG_LEVEL > 1 - else - fprintf( stderr, "ppdOpenFile failed, falling back to generic driver\n" ); - #endif - - // remove temporary PPD file - unlink( aPPDFile.getStr() ); - } - #if OSL_DEBUG_LEVEL > 1 - else - fprintf( stderr, "cupsGetPPD failed, falling back to generic driver\n" ); - #endif - } - #if OSL_DEBUG_LEVEL > 1 - else - fprintf( stderr, "no dest found for printer %s\n", OUStringToOString( aPrinter, osl_getThreadTextEncoding() ).getStr() ); - #endif - } - m_aCUPSMutex.release(); - } - #if OSL_DEBUG_LEVEL >1 - else - fprintf( stderr, "could not acquire CUPS mutex !!!\n" ); - #endif - #endif // ENABLE_CUPS - - if( ! pNewParser ) - { - // get the default PPD - pNewParser = PPDParser::getParser( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ); - - PrinterInfo& rInfo = m_aPrinters[ aPrinter ].m_aInfo; - - rInfo.m_pParser = pNewParser; - rInfo.m_aContext.setParser( pNewParser ); - } - - return pNewParser; -} - -void CUPSManager::setupJobContextData( - JobData& -#ifdef ENABLE_CUPS - rData -#endif -) -{ -#ifdef ENABLE_CUPS - boost::unordered_map< OUString, int, OUStringHash >::iterator dest_it = - m_aCUPSDestMap.find( rData.m_aPrinterName ); - - if( dest_it == m_aCUPSDestMap.end() ) - return PrinterInfoManager::setupJobContextData( rData ); - - boost::unordered_map< OUString, Printer, OUStringHash >::iterator p_it = - m_aPrinters.find( rData.m_aPrinterName ); - if( p_it == m_aPrinters.end() ) // huh ? - { -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "CUPS printer list in disorder, no dest for printer %s !\n", OUStringToOString( rData.m_aPrinterName, osl_getThreadTextEncoding() ).getStr() ); -#endif - return; - } - - if( p_it->second.m_aInfo.m_pParser == NULL ) - { - // in turn calls createCUPSParser - // which updates the printer info - p_it->second.m_aInfo.m_pParser = PPDParser::getParser( p_it->second.m_aInfo.m_aDriverName ); - } - if( p_it->second.m_aInfo.m_aContext.getParser() == NULL ) - { - OUString aPrinter; - if( p_it->second.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) == 0 ) - aPrinter = p_it->second.m_aInfo.m_aDriverName.copy( 5 ); - else - aPrinter = p_it->second.m_aInfo.m_aDriverName; - - p_it->second.m_aInfo.m_aContext = m_aDefaultContexts[ aPrinter ]; - } - - rData.m_pParser = p_it->second.m_aInfo.m_pParser; - rData.m_aContext = p_it->second.m_aInfo.m_aContext; -#endif -} - -FILE* CUPSManager::startSpool( const OUString& rPrintername, bool bQuickCommand ) -{ - OSL_TRACE( "endSpool: %s, %s", - rtl::OUStringToOString( rPrintername, RTL_TEXTENCODING_UTF8 ).getStr(), - bQuickCommand ? "true" : "false" ); - - if( m_aCUPSDestMap.find( rPrintername ) == m_aCUPSDestMap.end() ) - { - OSL_TRACE( "defer to PrinterInfoManager::startSpool" ); - return PrinterInfoManager::startSpool( rPrintername, bQuickCommand ); - } - -#ifdef ENABLE_CUPS - OUString aTmpURL, aTmpFile; - osl_createTempFile( NULL, NULL, &aTmpURL.pData ); - osl_getSystemPathFromFileURL( aTmpURL.pData, &aTmpFile.pData ); - OString aSysFile = OUStringToOString( aTmpFile, osl_getThreadTextEncoding() ); - FILE* fp = fopen( aSysFile.getStr(), "w" ); - if( fp ) - m_aSpoolFiles[fp] = aSysFile; - - return fp; -#else - return NULL; -#endif -} - -struct less_ppd_key : public ::std::binary_function<double, double, bool> -{ - bool operator()(const PPDKey* left, const PPDKey* right) - { return left->getOrderDependency() < right->getOrderDependency(); } -}; - -void CUPSManager::getOptionsFromDocumentSetup( const JobData& rJob, bool bBanner, int& rNumOptions, void** rOptions ) const -{ - rNumOptions = 0; - *rOptions = NULL; - - // emit features ordered to OrderDependency - // ignore features that are set to default - - // sanity check - if( rJob.m_pParser == rJob.m_aContext.getParser() && rJob.m_pParser ) - { - int i; - int nKeys = rJob.m_aContext.countValuesModified(); - ::std::vector< const PPDKey* > aKeys( nKeys ); - for( i = 0; i < nKeys; i++ ) - aKeys[i] = rJob.m_aContext.getModifiedKey( i ); - ::std::sort( aKeys.begin(), aKeys.end(), less_ppd_key() ); - - for( i = 0; i < nKeys; i++ ) - { - const PPDKey* pKey = aKeys[i]; - const PPDValue* pValue = rJob.m_aContext.getValue( pKey ); - if(pValue && pValue->m_eType == eInvocation && pValue->m_aValue.Len() ) - { - OString aKey = OUStringToOString( pKey->getKey(), RTL_TEXTENCODING_ASCII_US ); - OString aValue = OUStringToOString( pValue->m_aOption, RTL_TEXTENCODING_ASCII_US ); - rNumOptions = m_pCUPSWrapper->cupsAddOption( aKey.getStr(), aValue.getStr(), rNumOptions, (cups_option_t**)rOptions ); - } - } - } - - if( rJob.m_nPDFDevice > 0 && rJob.m_nCopies > 1 ) - { - rtl::OString aVal( rtl::OString::valueOf( sal_Int32( rJob.m_nCopies ) ) ); - rNumOptions = m_pCUPSWrapper->cupsAddOption( "copies", aVal.getStr(), rNumOptions, (cups_option_t**)rOptions ); - } - if( ! bBanner ) - { - rNumOptions = m_pCUPSWrapper->cupsAddOption( "job-sheets", "none", rNumOptions, (cups_option_t**)rOptions ); - } -} - -int CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTitle, FILE* pFile, const JobData& rDocumentJobData, bool bBanner ) -{ - OSL_TRACE( "endSpool: %s, %s, copy count = %d", - rtl::OUStringToOString( rPrintername, RTL_TEXTENCODING_UTF8 ).getStr(), - rtl::OUStringToOString( rJobTitle, RTL_TEXTENCODING_UTF8 ).getStr(), - rDocumentJobData.m_nCopies - ); - - int nJobID = 0; - - osl::MutexGuard aGuard( m_aCUPSMutex ); - - boost::unordered_map< OUString, int, OUStringHash >::iterator dest_it = - m_aCUPSDestMap.find( rPrintername ); - if( dest_it == m_aCUPSDestMap.end() ) - { - OSL_TRACE( "defer to PrinterInfoManager::endSpool" ); - return PrinterInfoManager::endSpool( rPrintername, rJobTitle, pFile, rDocumentJobData, bBanner ); - } - - #ifdef ENABLE_CUPS - boost::unordered_map< FILE*, OString, FPtrHash >::const_iterator it = m_aSpoolFiles.find( pFile ); - if( it != m_aSpoolFiles.end() ) - { - fclose( pFile ); - rtl_TextEncoding aEnc = osl_getThreadTextEncoding(); - - // setup cups options - int nNumOptions = 0; - cups_option_t* pOptions = NULL; - getOptionsFromDocumentSetup( rDocumentJobData, bBanner, nNumOptions, (void**)&pOptions ); - - cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + dest_it->second; - nJobID = m_pCUPSWrapper->cupsPrintFile( pDest->name, - it->second.getStr(), - OUStringToOString( rJobTitle, aEnc ).getStr(), - nNumOptions, pOptions ); -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "cupsPrintFile( %s, %s, %s, %d, %p ) returns %d\n", - pDest->name, - it->second.getStr(), - OUStringToOString( rJobTitle, aEnc ).getStr(), - nNumOptions, - pOptions, - nJobID - ); - for( int n = 0; n < nNumOptions; n++ ) - fprintf( stderr, " option %s=%s\n", pOptions[n].name, pOptions[n].value ); - OString aCmd( "cp " ); - aCmd = aCmd + it->second; - aCmd = aCmd + OString( " $HOME/cupsprint.ps" ); - system( aCmd.getStr() ); -#endif - - unlink( it->second.getStr() ); - m_aSpoolFiles.erase( pFile ); - if( pOptions ) - m_pCUPSWrapper->cupsFreeOptions( nNumOptions, pOptions ); - } -#endif // ENABLE_CUPS - - return nJobID; -} - - -void CUPSManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo ) -{ - PrinterInfoManager::changePrinterInfo( rPrinter, rNewInfo ); -} - -bool CUPSManager::checkPrintersChanged( bool bWait ) -{ - bool bChanged = false; - if( bWait ) - { - if( m_aDestThread ) - { - // initial asynchronous detection still running - #if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "syncing cups discovery thread\n" ); - #endif - osl_joinWithThread( m_aDestThread ); - osl_destroyThread( m_aDestThread ); - m_aDestThread = NULL; - #if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "done: syncing cups discovery thread\n" ); - #endif - } - else - { - // #i82321# check for cups printer updates - // with this change the whole asynchronous detection in a thread is - // almost useless. The only relevance left is for some stalled systems - // where the user can set SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION - // (see vcl/unx/source/gdi/salprnpsp.cxx) - // so that checkPrintersChanged( true ) will never be called - - // there is no way to query CUPS whether the printer list has changed - // so get the dest list anew - if( m_nDests && m_pDests ) - m_pCUPSWrapper->cupsFreeDests( m_nDests, (cups_dest_t*)m_pDests ); - m_nDests = 0; - m_pDests = NULL; - runDests(); - } - } - if( m_aCUPSMutex.tryToAcquire() ) - { - bChanged = m_bNewDests; - m_aCUPSMutex.release(); - } - - if( ! bChanged ) - { - bChanged = PrinterInfoManager::checkPrintersChanged( bWait ); - // #i54375# ensure new merging with CUPS list in :initialize - if( bChanged ) - m_bNewDests = true; - } - - if( bChanged ) - initialize(); - - return bChanged; -} - -bool CUPSManager::addPrinter( const OUString& rName, const OUString& rDriver ) -{ - // don't touch the CUPS printers - if( m_aCUPSDestMap.find( rName ) != m_aCUPSDestMap.end() || - rDriver.compareToAscii( "CUPS:", 5 ) == 0 - ) - return false; - return PrinterInfoManager::addPrinter( rName, rDriver ); -} - -bool CUPSManager::removePrinter( const OUString& rName, bool bCheck ) -{ - // don't touch the CUPS printers - if( m_aCUPSDestMap.find( rName ) != m_aCUPSDestMap.end() ) - return false; - return PrinterInfoManager::removePrinter( rName, bCheck ); -} - -bool CUPSManager::setDefaultPrinter( const OUString& rName ) -{ - bool bSuccess = false; -#ifdef ENABLE_CUPS - boost::unordered_map< OUString, int, OUStringHash >::iterator nit = - m_aCUPSDestMap.find( rName ); - if( nit != m_aCUPSDestMap.end() && m_aCUPSMutex.tryToAcquire() ) - { - cups_dest_t* pDests = (cups_dest_t*)m_pDests; - for( int i = 0; i < m_nDests; i++ ) - pDests[i].is_default = 0; - pDests[ nit->second ].is_default = 1; - m_pCUPSWrapper->cupsSetDests( m_nDests, (cups_dest_t*)m_pDests ); - m_aDefaultPrinter = rName; - m_aCUPSMutex.release(); - bSuccess = true; - } - else -#endif - bSuccess = PrinterInfoManager::setDefaultPrinter( rName ); - - return bSuccess; -} - -bool CUPSManager::writePrinterConfig() -{ -#ifdef ENABLE_CUPS - bool bDestModified = false; - rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); - - for( boost::unordered_map< OUString, Printer, OUStringHash >::iterator prt = - m_aPrinters.begin(); prt != m_aPrinters.end(); ++prt ) - { - boost::unordered_map< OUString, int, OUStringHash >::iterator nit = - m_aCUPSDestMap.find( prt->first ); - if( nit == m_aCUPSDestMap.end() ) - continue; - - if( ! prt->second.m_bModified ) - continue; - - if( m_aCUPSMutex.tryToAcquire() ) - { - bDestModified = true; - cups_dest_t* pDest = ((cups_dest_t*)m_pDests) + nit->second; - PrinterInfo& rInfo = prt->second.m_aInfo; - - // create new option list - int nNewOptions = 0; - cups_option_t* pNewOptions = NULL; - int nValues = rInfo.m_aContext.countValuesModified(); - for( int i = 0; i < nValues; i++ ) - { - const PPDKey* pKey = rInfo.m_aContext.getModifiedKey( i ); - const PPDValue* pValue = rInfo.m_aContext.getValue( pKey ); - if( pKey && pValue ) // sanity check - { - OString aName = OUStringToOString( pKey->getKey(), aEncoding ); - OString aValue = OUStringToOString( pValue->m_aOption, aEncoding ); - nNewOptions = m_pCUPSWrapper->cupsAddOption( aName.getStr(), aValue.getStr(), nNewOptions, &pNewOptions ); - } - } - // set PPD options on CUPS dest - m_pCUPSWrapper->cupsFreeOptions( pDest->num_options, pDest->options ); - pDest->num_options = nNewOptions; - pDest->options = pNewOptions; - m_aCUPSMutex.release(); - } - } - if( bDestModified && m_aCUPSMutex.tryToAcquire() ) - { - m_pCUPSWrapper->cupsSetDests( m_nDests, (cups_dest_t*)m_pDests ); - m_aCUPSMutex.release(); - } -#endif // ENABLE_CUPS - - return PrinterInfoManager::writePrinterConfig(); -} - -bool CUPSManager::addOrRemovePossible() const -{ - return (m_nDests && m_pDests && ! isCUPSDisabled())? false : PrinterInfoManager::addOrRemovePossible(); -} - -#include <rtsname.hxx> - -const char* CUPSManager::authenticateUser( const char* /*pIn*/ ) -{ - const char* pRet = NULL; - -#ifdef ENABLE_CUPS - OUString aLib(RTL_CONSTASCII_USTRINGPARAM( _XSALSET_LIBNAME )); - oslModule pLib = osl_loadModule( aLib.pData, SAL_LOADMODULE_LAZY ); - if( pLib ) - { - OUString aSym( RTL_CONSTASCII_USTRINGPARAM( "Sal_authenticateQuery" ) ); - bool (*getpw)( const OString& rServer, OString& rUser, OString& rPw) = - (bool(*)(const OString&,OString&,OString&))osl_getFunctionSymbol( pLib, aSym.pData ); - if( getpw ) - { - osl::MutexGuard aGuard( m_aCUPSMutex ); - - OString aUser = m_pCUPSWrapper->cupsUser(); - OString aServer = m_pCUPSWrapper->cupsServer(); - OString aPassword; - if( getpw( aServer, aUser, aPassword ) ) - { - m_aPassword = aPassword; - m_aUser = aUser; - m_pCUPSWrapper->cupsSetUser( m_aUser.getStr() ); - pRet = m_aPassword.getStr(); - } - } - osl_unloadModule( pLib ); - } -#if OSL_DEBUG_LEVEL > 1 - else fprintf( stderr, "loading of module %s failed\n", OUStringToOString( aLib, osl_getThreadTextEncoding() ).getStr() ); -#endif -#endif // ENABLE_CUPS - - return pRet; -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |