diff options
author | Rüdiger Timm <rt@openoffice.org> | 2004-07-23 09:08:56 +0000 |
---|---|---|
committer | Rüdiger Timm <rt@openoffice.org> | 2004-07-23 09:08:56 +0000 |
commit | 7d6c646ec244f9ea1db9b5bd160ecfc43ac27f13 (patch) | |
tree | e9378bc7e090ef2ddef558de4139e52885499afb | |
parent | 45551df64a4072446dd8686c172f104f0cd64f4b (diff) |
INTEGRATION: CWS vcl24 (1.3.14); FILE MERGED
2004/07/12 16:03:43 pl 1.3.14.3: fix a crash
2004/07/08 15:50:51 pl 1.3.14.2: #i28763# workaround possibly hanging CUPS calls
2004/06/30 17:35:57 pl 1.3.14.1: #i30914# #i30917# handle queue instances correctly
-rw-r--r-- | psprint/source/printer/cupsmgr.cxx | 393 |
1 files changed, 264 insertions, 129 deletions
diff --git a/psprint/source/printer/cupsmgr.cxx b/psprint/source/printer/cupsmgr.cxx index 191ed8ca8336..145ba7313ba4 100644 --- a/psprint/source/printer/cupsmgr.cxx +++ b/psprint/source/printer/cupsmgr.cxx @@ -2,9 +2,9 @@ * * $RCSfile: cupsmgr.cxx,v $ * - * $Revision: 1.3 $ + * $Revision: 1.4 $ * - * last change: $Author: kz $ $Date: 2004-05-18 10:46:09 $ + * last change: $Author: rt $ $Date: 2004-07-23 10:08:56 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -70,6 +70,8 @@ typedef void cups_option_t; #include <osl/thread.h> #include <osl/diagnose.h> +#include <osl/conditn.hxx> +#include <rtl/ustrbuf.hxx> #include <cupsmgr.hxx> namespace psp @@ -77,20 +79,21 @@ namespace psp class CUPSWrapper { oslModule m_pLib; + osl::Mutex m_aGetPPDMutex; 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*); + 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)(); + const char* (*m_pcupsServer)(); void (*m_pcupsSetPasswordCB)(const char*(cb)(const char*)); - const char* (*m_pcupsUser)(); + const char* (*m_pcupsUser)(); void (*m_pcupsSetUser)(const char*); void* loadSymbol( const char* ); @@ -116,8 +119,7 @@ public: cups_option_t* pOptions ) { return m_pcupsPrintFile( pPrinter, pFileName, pTitle, nOptions, pOptions ); } - const char* cupsGetPPD( const char* pPrinter ) - { return m_pcupsGetPPD( pPrinter ); } + const char* cupsGetPPD( const char* pPrinter ); int cupsMarkOptions(ppd_file_t* pPPD, int nOptions, cups_option_t* pOptions ) { return m_pcupsMarkOptions(pPPD, nOptions, pOptions); } @@ -250,6 +252,70 @@ bool CUPSWrapper::isValid() return m_pLib != NULL; } +static struct GetPPDAttribs +{ + const char* (*pFunction)(const char*); + osl::Condition m_aCondition; + const char* m_pParameter; + const char* m_pResult; + oslThread m_aThread; +} *pAttribs = NULL; + +extern "C" { + static void getPPDWorker(void*) + { + pAttribs->m_pResult = pAttribs->pFunction( pAttribs->m_pParameter ); + if( pAttribs->m_aCondition.check() ) + { + // timed out, unlink file + if( pAttribs->m_pResult ) + unlink( pAttribs->m_pResult ); + delete pAttribs; + pAttribs = NULL; + } + else + pAttribs->m_aCondition.set(); + } +} + +const char* CUPSWrapper::cupsGetPPD( const char* pPrinter ) +{ + const char* pResult = NULL; + + // if one thread hangs in cupsGetPPD already, don't start another + if( ! pAttribs ) + { + pAttribs = new GetPPDAttribs(); + pAttribs->pFunction = m_pcupsGetPPD; + pAttribs->m_aCondition.reset(); + pAttribs->m_pParameter = pPrinter; + pAttribs->m_pResult = NULL; + pAttribs->m_aThread = osl_createThread( getPPDWorker, NULL ); + + TimeValue aValue; + aValue.Seconds = 5; + aValue.Nanosec = 0; + if( pAttribs->m_aCondition.wait( &aValue ) == Condition::result_ok ) + { + osl_destroyThread( pAttribs->m_aThread ); + pResult = pAttribs->m_pResult; + delete pAttribs; + pAttribs = NULL; + } + else + { +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "cupsGetPPD %s timed out\n", pPrinter ); +#endif + // should the thread awake again notify it to clean up itself + pAttribs->m_aCondition.set(); + osl_destroyThread( pAttribs->m_aThread ); + } + } + + return pResult; +} + static const char* setPasswordCallback( const char* pIn ) { const char* pRet = NULL; @@ -275,66 +341,91 @@ CUPSManager* CUPSManager::tryLoadCUPS() // try to load CUPS CUPSWrapper* pWrapper = new CUPSWrapper(); if( pWrapper->isValid() ) - { - // check if there are any dests; if not - // CUPS is unconfigured (at least) and - // should not be used - cups_dest_t* pDests = NULL; - int nDests = pWrapper->cupsGetDests( &pDests ); - if( nDests && pDests ) - pManager = new CUPSManager( pWrapper, nDests, pDests ); -#if OSL_DEBUG_LEVEL > 1 - else - fprintf( stderr, "CUPS loaded but no dests -> CUPS disabled\n" ); -#endif - } - // something failed, don't use CUPS - if( ! pManager ) + pManager = new CUPSManager( pWrapper ); + else delete pWrapper; } #endif return pManager; } -CUPSManager::CUPSManager( CUPSWrapper* pWrapper, int nDests, void* pDests ) : +CUPSManager::CUPSManager( CUPSWrapper* pWrapper ) : PrinterInfoManager( CUPS ), m_pCUPSWrapper( pWrapper ), - m_nDests( nDests ), - m_pDests( pDests ) + m_nDests( 0 ), + m_pDests( NULL ), + m_bNewDests( false ) { - m_bFirstDest = (nDests && pDests); + m_aDestThread = osl_createThread( runDestThread, 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(); +} + +void CUPSManager::runDests() +{ +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "starting cupsGetDests\n" ); +#endif + osl::MutexGuard aGuard( m_aCUPSMutex ); + + m_nDests = m_pCUPSWrapper->cupsGetDests( (cups_dest_t**)&m_pDests ); + m_bNewDests = true; +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "finished cupsGetDests\n" ); +#endif +} + void CUPSManager::initialize() { + // get normal printers, clear printer list + PrinterInfoManager::initialize(); + #ifdef ENABLE_CUPS - // there may have been a previous run - if( m_nDests && m_pDests && !m_bFirstDest ) - m_pCUPSWrapper->cupsFreeDests( m_nDests, (cups_dest_t*)m_pDests ); - m_aPrinters.clear(); - m_aCUPSDestMap.clear(); + // check whether thread has completed + // if not behave like old printing system + osl::MutexGuard aGuard( m_aCUPSMutex ); - // get normal printers - PrinterInfoManager::initialize(); + if( ! (m_nDests && m_pDests ) ) + return; - rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); - int nPrinter = 0; + // dest thread has run, clean up + if( m_aDestThread ) + { + osl_joinWithThread( m_aDestThread ); + osl_destroyThread( m_aDestThread ); + m_aDestThread = NULL; + } - // get CUPS dests if this is not the first run after the constructor - // in which case m_pDests was already intialized - if( m_bFirstDest && m_nDests && m_pDests ) - nPrinter = m_nDests; - else - m_nDests = nPrinter = m_pCUPSWrapper->cupsGetDests( (cups_dest_t**)&m_pDests ); + // clear old stuff + m_aCUPSDestMap.clear(); + +#if 0 + // update dests + m_pCUPSWrapper->cupsFreeDests( m_nDests, (cups_dest_t*)m_pDests ); + m_nDests = m_pCUPSWrapper->cupsGetDests( (cups_dest_t**)&m_pDests ); +#endif + m_bNewDests = false; - m_bFirstDest = false; + rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); + int nPrinter = m_nDests; // add CUPS printers, should there be a printer // with the same name as a CUPS printer, overwrite it @@ -342,18 +433,25 @@ void CUPSManager::initialize() { cups_dest_t* 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 Printer aPrinter = m_aPrinters[ aPrinterName ]; aPrinter.m_aInfo.m_aPrinterName = aPrinterName; - if( pDest->instance && *pDest->instance ) - aPrinter.m_aInfo.m_aLocation = OStringToOUString( pDest->instance, aEncoding ); if( pDest->is_default ) m_aDefaultPrinter = aPrinterName; - OUString aPPD( RTL_CONSTASCII_USTRINGPARAM( "CUPS:" ) ); - aPPD = aPPD + aPrinterName; + 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. @@ -363,7 +461,7 @@ void CUPSManager::initialize() // behaviour aPrinter.m_aInfo.m_pParser = NULL; aPrinter.m_aInfo.m_aContext.setParser( NULL ); - aPrinter.m_aInfo.m_aDriverName = aPPD; + aPrinter.m_aInfo.m_aDriverName = aBuf.makeStringAndClear(); aPrinter.m_bModified = false; m_aPrinters[ aPrinter.m_aInfo.m_aPrinterName ] = aPrinter; @@ -456,55 +554,60 @@ const PPDParser* CUPSManager::createCUPSParser( const OUString& rPrinter ) aPrinter = rPrinter; #ifdef ENABLE_CUPS - rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); - OString aPrinterName( OUStringToOString( aPrinter, aEncoding ) ); - - const char* pPPDFile = m_pCUPSWrapper->cupsGetPPD( aPrinterName.getStr() ); -#if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "PPD for %s is %s\n", aPrinterName.getStr(), pPPDFile ); -#endif - if( pPPDFile ) + if( m_aCUPSMutex.tryToAcquire() && m_nDests && m_pDests ) { - OUString aFileName( OStringToOUString( pPPDFile, aEncoding ) ); - // create the new parser - pNewParser = new PPDParser( aFileName ); - std::hash_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; - // update the printer info with context information - ppd_file_t* pPPD = m_pCUPSWrapper->ppdOpenFile( pPPDFile ); - /*int nConflicts =*/ m_pCUPSWrapper->cupsMarkOptions( pPPD, pDest->num_options, pDest->options ); + const char* pPPDFile = m_pCUPSWrapper->cupsGetPPD( pDest->name ); +#if OSL_DEBUG_LEVEL > 1 + fprintf( stderr, "PPD for %s is %s\n", OUStringToOString( aPrinter, osl_getThreadTextEncoding() ).getStr(), pPPDFile ); +#endif + if( pPPDFile ) + { + rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); + OUString aFileName( OStringToOUString( pPPDFile, aEncoding ) ); + // create the new parser + PPDParser* pCUPSParser = new PPDParser( aFileName ); + pCUPSParser->m_aFile = rPrinter; + pNewParser = pCUPSParser; + + // update the printer info with context information + ppd_file_t* pPPD = m_pCUPSWrapper->ppdOpenFile( pPPDFile ); + /*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 ); + 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; + PrinterInfo& rInfo = m_aPrinters[ aPrinter ].m_aInfo; - rInfo.m_pParser = pNewParser; - rInfo.m_aContext.setParser( pNewParser ); - for( int i = 0; i < pPPD->num_groups; i++ ) - updatePrinterContextInfo( pPPD->groups + i, rInfo ); + rInfo.m_pParser = pNewParser; + rInfo.m_aContext.setParser( pNewParser ); + for( int i = 0; i < pPPD->num_groups; i++ ) + updatePrinterContextInfo( pPPD->groups + i, rInfo ); - // clean up the mess - m_pCUPSWrapper->ppdClose( pPPD ); - } + // clean up the mess + m_pCUPSWrapper->ppdClose( pPPD ); + + // remove temporary PPD file + unlink( pPPDFile ); + } #if OSL_DEBUG_LEVEL > 1 - else - fprintf( stderr, "no dest found for printer %s\n", aPrinterName.getStr() ); + else + fprintf( stderr, "no dest found for printer %s\n", OUStringToOString( aPrinter, osl_getThreadTextEncoding() ).getStr() ); #endif - // remove temporary PPD file - unlink( pPPDFile ); + } + m_aCUPSMutex.release(); } - else #endif // ENABLE_CUPS + + if( ! pNewParser ) { // get the default PPD pNewParser = PPDParser::getParser( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ); @@ -577,20 +680,32 @@ int CUPSManager::endSpool( const OUString& rPrintername, const OUString& rJobTit fclose( pFile ); rtl_TextEncoding aEnc = osl_getThreadTextEncoding(); - nJobID = m_pCUPSWrapper->cupsPrintFile( OUStringToOString( rPrintername, aEnc ).getStr(), - it->second.getStr(), - OUStringToOString( rJobTitle, aEnc ).getStr(), - 0, NULL ); + osl::MutexGuard aGuard( m_aCUPSMutex ); + + std::hash_map< OUString, int, OUStringHash >::iterator dest_it = + m_aCUPSDestMap.find( rPrintername ); + if( dest_it != m_aCUPSDestMap.end() ) + { + 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(), + 0, NULL ); #if OSL_DEBUG_LEVEL > 1 - fprintf( stderr, "cupsPrintFile( %s, %s, %s, 0, 0 ) returns %d\n", - OUStringToOString( rPrintername, aEnc ).getStr(), - it->second.getStr(), - OUStringToOString( rJobTitle, aEnc ).getStr(), - nJobID ); - OString aCmd( "cp " ); - aCmd = aCmd + it->second; - aCmd = aCmd + OString( " $HOME/cupsprint.ps" ); - system( aCmd.getStr() ); + fprintf( stderr, "cupsPrintFile( %s, %s, %s, 0, 0 ) returns %d\n", + pDest->name, + it->second.getStr(), + OUStringToOString( rJobTitle, aEnc ).getStr(), + nJobID ); + OString aCmd( "cp " ); + aCmd = aCmd + it->second; + aCmd = aCmd + OString( " $HOME/cupsprint.ps" ); + system( aCmd.getStr() ); +#endif + } +#if OSL_DEBUG_LEVEL > 1 + else + fprintf( stderr, "Error: no CUPS dest for %s found, discarding job\n", OUStringToOString( rPrintername, aEnc ).getStr() ); #endif unlink( it->second.getStr() ); @@ -609,7 +724,18 @@ void CUPSManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo bool CUPSManager::checkPrintersChanged() { - return PrinterInfoManager::checkPrintersChanged(); + bool bChanged = false; + if( m_aCUPSMutex.tryToAcquire() ) + { + bChanged = m_bNewDests; + m_aCUPSMutex.release(); + initialize(); + } + + if( ! bChanged ) + bChanged = PrinterInfoManager::checkPrintersChanged(); + + return bChanged; } bool CUPSManager::addPrinter( const OUString& rName, const OUString& rDriver ) @@ -632,23 +758,23 @@ bool CUPSManager::removePrinter( const OUString& rName, bool bCheck ) bool CUPSManager::setDefaultPrinter( const OUString& rName ) { + bool bSuccess = false; #ifdef ENABLE_CUPS std::hash_map< OUString, int, OUStringHash >::iterator nit = m_aCUPSDestMap.find( rName ); - if( nit == m_aCUPSDestMap.end() ) - return false; - - 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; - - return true; -#else - return false; + 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; + } #endif + return bSuccess; } bool CUPSManager::writePrinterConfig() @@ -668,32 +794,39 @@ bool CUPSManager::writePrinterConfig() if( ! prt->second.m_bModified ) continue; - 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++ ) + if( m_aCUPSMutex.tryToAcquire() ) { - const PPDKey* pKey = rInfo.m_aContext.getModifiedKey( i ); - const PPDValue* pValue = rInfo.m_aContext.getValue( pKey ); - if( pKey && pValue ) // sanity check + 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++ ) { - OString aName = OUStringToOString( pKey->getKey(), aEncoding ); - OString aValue = OUStringToOString( pValue->m_aOption, aEncoding ); - nNewOptions = m_pCUPSWrapper->cupsAddOption( aName.getStr(), aValue.getStr(), nNewOptions, &pNewOptions ); + 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(); } - // set PPD options on CUPS dest - m_pCUPSWrapper->cupsFreeOptions( pDest->num_options, pDest->options ); - pDest->num_options = nNewOptions; - pDest->options = pNewOptions; } - if( bDestModified ) + if( bDestModified && m_aCUPSMutex.tryToAcquire() ) + { m_pCUPSWrapper->cupsSetDests( m_nDests, (cups_dest_t*)m_pDests ); + m_aCUPSMutex.release(); + } #endif // ENABLE_CUPS return PrinterInfoManager::writePrinterConfig(); @@ -715,6 +848,8 @@ const char* CUPSManager::authenticateUser( const char* pIn ) (bool(*)(const OString&,OString&,OString&))osl_getSymbol( pLib, aSym.pData ); if( getpw ) { + osl::MutexGuard aGuard( m_aCUPSMutex ); + OString aUser = m_pCUPSWrapper->cupsUser(); OString aServer = m_pCUPSWrapper->cupsServer(); OString aPassword; |