1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_vcl.hxx" 30 31 #include <unistd.h> 32 #include <sys/stat.h> 33 #include <sys/wait.h> 34 35 #include "vcl/svapp.hxx" 36 #include "vcl/timer.hxx" 37 #include "vcl/printerinfomanager.hxx" 38 39 #include "jobset.h" 40 #include "print.h" 41 #include "salptype.hxx" 42 43 #include "svpprn.hxx" 44 #include "svppspgraphics.hxx" 45 #include "svpinst.hxx" 46 47 using namespace psp; 48 using namespace rtl; 49 50 /* 51 * static helpers 52 */ 53 54 static String getPdfDir( const PrinterInfo& rInfo ) 55 { 56 String aDir; 57 sal_Int32 nIndex = 0; 58 while( nIndex != -1 ) 59 { 60 OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); 61 if( ! aToken.compareToAscii( "pdf=", 4 ) ) 62 { 63 sal_Int32 nPos = 0; 64 aDir = aToken.getToken( 1, '=', nPos ); 65 if( ! aDir.Len() ) 66 aDir = String( ByteString( getenv( "HOME" ) ), osl_getThreadTextEncoding() ); 67 break; 68 } 69 } 70 return aDir; 71 } 72 73 inline int PtTo10Mu( int nPoints ) { return (int)((((double)nPoints)*35.27777778)+0.5); } 74 75 inline int TenMuToPt( int nUnits ) { return (int)((((double)nUnits)/35.27777778)+0.5); } 76 77 static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData ) 78 { 79 pJobSetup->meOrientation = (Orientation)(rData.m_eOrientation == orientation::Landscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT); 80 81 // copy page size 82 String aPaper; 83 int width, height; 84 85 rData.m_aContext.getPageSize( aPaper, width, height ); 86 pJobSetup->mePaperFormat = PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 )); 87 pJobSetup->mnPaperWidth = 0; 88 pJobSetup->mnPaperHeight = 0; 89 if( pJobSetup->mePaperFormat == PAPER_USER ) 90 { 91 // transform to 100dth mm 92 width = PtTo10Mu( width ); 93 height = PtTo10Mu( height ); 94 95 if( rData.m_eOrientation == psp::orientation::Portrait ) 96 { 97 pJobSetup->mnPaperWidth = width; 98 pJobSetup->mnPaperHeight= height; 99 } 100 else 101 { 102 pJobSetup->mnPaperWidth = height; 103 pJobSetup->mnPaperHeight= width; 104 } 105 } 106 107 // copy input slot 108 const PPDKey* pKey = NULL; 109 const PPDValue* pValue = NULL; 110 111 pJobSetup->mnPaperBin = 0xffff; 112 if( rData.m_pParser ) 113 pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ); 114 if( pKey ) 115 pValue = rData.m_aContext.getValue( pKey ); 116 if( pKey && pValue ) 117 { 118 for( pJobSetup->mnPaperBin = 0; 119 pValue != pKey->getValue( pJobSetup->mnPaperBin ) && 120 pJobSetup->mnPaperBin < pKey->countValues(); 121 pJobSetup->mnPaperBin++ ) 122 ; 123 if( pJobSetup->mnPaperBin >= pKey->countValues() || pValue == pKey->getDefaultValue() ) 124 pJobSetup->mnPaperBin = 0xffff; 125 } 126 127 // copy duplex 128 pKey = NULL; 129 pValue = NULL; 130 131 pJobSetup->meDuplexMode = DUPLEX_UNKNOWN; 132 if( rData.m_pParser ) 133 pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); 134 if( pKey ) 135 pValue = rData.m_aContext.getValue( pKey ); 136 if( pKey && pValue ) 137 { 138 if( pValue->m_aOption.EqualsIgnoreCaseAscii( "None" ) || 139 pValue->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 ) 140 ) 141 { 142 pJobSetup->meDuplexMode = DUPLEX_OFF; 143 } 144 else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexNoTumble" ) ) 145 { 146 pJobSetup->meDuplexMode = DUPLEX_LONGEDGE; 147 } 148 else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexTumble" ) ) 149 { 150 pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE; 151 } 152 } 153 154 // copy the whole context 155 if( pJobSetup->mpDriverData ) 156 rtl_freeMemory( pJobSetup->mpDriverData ); 157 158 int nBytes; 159 void* pBuffer = NULL; 160 if( rData.getStreamBuffer( pBuffer, nBytes ) ) 161 { 162 pJobSetup->mnDriverDataLen = nBytes; 163 pJobSetup->mpDriverData = (sal_uInt8*)pBuffer; 164 } 165 else 166 { 167 pJobSetup->mnDriverDataLen = 0; 168 pJobSetup->mpDriverData = NULL; 169 } 170 } 171 172 static bool passFileToCommandLine( const String& rFilename, const String& rCommandLine, bool bRemoveFile = true ) 173 { 174 bool bSuccess = false; 175 176 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); 177 ByteString aCmdLine( rCommandLine, aEncoding ); 178 ByteString aFilename( rFilename, aEncoding ); 179 180 bool bPipe = aCmdLine.Search( "(TMP)" ) != STRING_NOTFOUND ? false : true; 181 182 // setup command line for exec 183 if( ! bPipe ) 184 while( aCmdLine.SearchAndReplace( "(TMP)", aFilename ) != STRING_NOTFOUND ) 185 ; 186 187 #if OSL_DEBUG_LEVEL > 1 188 fprintf( stderr, "%s commandline: \"%s\"\n", 189 bPipe ? "piping to" : "executing", 190 aCmdLine.GetBuffer() ); 191 struct stat aStat; 192 if( stat( aFilename.GetBuffer(), &aStat ) ) 193 fprintf( stderr, "stat( %s ) failed\n", aFilename.GetBuffer() ); 194 fprintf( stderr, "Tmp file %s has modes: 0%03lo\n", aFilename.GetBuffer(), (long)aStat.st_mode ); 195 #endif 196 const char* argv[4]; 197 if( ! ( argv[ 0 ] = getenv( "SHELL" ) ) ) 198 argv[ 0 ] = "/bin/sh"; 199 argv[ 1 ] = "-c"; 200 argv[ 2 ] = aCmdLine.GetBuffer(); 201 argv[ 3 ] = 0; 202 203 bool bHavePipes = false; 204 int pid, fd[2]; 205 206 if( bPipe ) 207 bHavePipes = pipe( fd ) ? false : true; 208 if( ( pid = fork() ) > 0 ) 209 { 210 if( bPipe && bHavePipes ) 211 { 212 close( fd[0] ); 213 char aBuffer[ 2048 ]; 214 FILE* fp = fopen( aFilename.GetBuffer(), "r" ); 215 while( fp && ! feof( fp ) ) 216 { 217 int nBytes = fread( aBuffer, 1, sizeof( aBuffer ), fp ); 218 if( nBytes ) 219 write( fd[ 1 ], aBuffer, nBytes ); 220 } 221 fclose( fp ); 222 close( fd[ 1 ] ); 223 } 224 int status = 0; 225 waitpid( pid, &status, 0 ); 226 if( ! status ) 227 bSuccess = true; 228 } 229 else if( ! pid ) 230 { 231 if( bPipe && bHavePipes ) 232 { 233 close( fd[1] ); 234 if( fd[0] != STDIN_FILENO ) // not probable, but who knows :) 235 dup2( fd[0], STDIN_FILENO ); 236 } 237 execv( argv[0], const_cast<char**>(argv) ); 238 fprintf( stderr, "failed to execute \"%s\"\n", aCmdLine.GetBuffer() ); 239 _exit( 1 ); 240 } 241 else 242 fprintf( stderr, "failed to fork\n" ); 243 244 // clean up the mess 245 if( bRemoveFile ) 246 unlink( aFilename.GetBuffer() ); 247 248 return bSuccess; 249 } 250 251 static bool sendAFax( const String& rFaxNumber, const String& rFileName, const String& rCommand ) 252 { 253 std::list< OUString > aFaxNumbers; 254 255 if( ! rFaxNumber.Len() ) 256 return false; 257 258 sal_Int32 nIndex = 0; 259 OUString aFaxes( rFaxNumber ); 260 OUString aBeginToken( RTL_CONSTASCII_USTRINGPARAM("<Fax#>") ); 261 OUString aEndToken( RTL_CONSTASCII_USTRINGPARAM("</Fax#>") ); 262 while( nIndex != -1 ) 263 { 264 nIndex = aFaxes.indexOf( aBeginToken, nIndex ); 265 if( nIndex != -1 ) 266 { 267 sal_Int32 nBegin = nIndex + aBeginToken.getLength(); 268 nIndex = aFaxes.indexOf( aEndToken, nIndex ); 269 if( nIndex != -1 ) 270 { 271 aFaxNumbers.push_back( aFaxes.copy( nBegin, nIndex-nBegin ) ); 272 nIndex += aEndToken.getLength(); 273 } 274 } 275 } 276 277 bool bSuccess = true; 278 if( aFaxNumbers.begin() != aFaxNumbers.end() ) 279 { 280 while( aFaxNumbers.begin() != aFaxNumbers.end() && bSuccess ) 281 { 282 String aCmdLine( rCommand ); 283 String aFaxNumber( aFaxNumbers.front() ); 284 aFaxNumbers.pop_front(); 285 while( aCmdLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PHONE)" ) ), aFaxNumber ) != STRING_NOTFOUND ) 286 ; 287 #if OSL_DEBUG_LEVEL > 1 288 fprintf( stderr, "sending fax to \"%s\"\n", OUStringToOString( aFaxNumber, osl_getThreadTextEncoding() ).getStr() ); 289 #endif 290 bSuccess = passFileToCommandLine( rFileName, aCmdLine, false ); 291 } 292 } 293 else 294 bSuccess = false; 295 296 // clean up temp file 297 unlink( ByteString( rFileName, osl_getThreadTextEncoding() ).GetBuffer() ); 298 299 return bSuccess; 300 } 301 302 static bool createPdf( const String& rToFile, const String& rFromFile, const String& rCommandLine ) 303 { 304 String aCommandLine( rCommandLine ); 305 while( aCommandLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(OUTFILE)" ) ), rToFile ) != STRING_NOTFOUND ) 306 ; 307 return passFileToCommandLine( rFromFile, aCommandLine ); 308 } 309 310 /* 311 * SalInstance 312 */ 313 314 // ----------------------------------------------------------------------- 315 316 SalInfoPrinter* SvpSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo, 317 ImplJobSetup* pJobSetup ) 318 { 319 // create and initialize SalInfoPrinter 320 PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter; 321 322 if( pJobSetup ) 323 { 324 PrinterInfoManager& rManager( PrinterInfoManager::get() ); 325 PrinterInfo aInfo( rManager.getPrinterInfo( pQueueInfo->maPrinterName ) ); 326 pPrinter->m_aJobData = aInfo; 327 pPrinter->m_aPrinterGfx.Init( pPrinter->m_aJobData ); 328 329 if( pJobSetup->mpDriverData ) 330 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo ); 331 332 pJobSetup->mnSystem = JOBSETUP_SYSTEM_UNIX; 333 pJobSetup->maPrinterName = pQueueInfo->maPrinterName; 334 pJobSetup->maDriver = aInfo.m_aDriverName; 335 copyJobDataToJobSetup( pJobSetup, aInfo ); 336 337 // set/clear backwards compatibility flag 338 bool bStrictSO52Compatibility = false; 339 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it = 340 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) ); 341 if( compat_it != pJobSetup->maValueMap.end() ) 342 { 343 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) ) 344 bStrictSO52Compatibility = true; 345 } 346 pPrinter->m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility ); 347 } 348 349 350 return pPrinter; 351 } 352 353 // ----------------------------------------------------------------------- 354 355 void SvpSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter ) 356 { 357 delete pPrinter; 358 } 359 360 // ----------------------------------------------------------------------- 361 362 SalPrinter* SvpSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter ) 363 { 364 // create and initialize SalPrinter 365 PspSalPrinter* pPrinter = new PspSalPrinter( pInfoPrinter ); 366 pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData; 367 368 return pPrinter; 369 } 370 371 // ----------------------------------------------------------------------- 372 373 void SvpSalInstance::DestroyPrinter( SalPrinter* pPrinter ) 374 { 375 delete pPrinter; 376 } 377 378 // ----------------------------------------------------------------------- 379 380 void SvpSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList ) 381 { 382 PrinterInfoManager& rManager( PrinterInfoManager::get() ); 383 static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" ); 384 if( ! pNoSyncDetection || ! *pNoSyncDetection ) 385 { 386 // #i62663# synchronize possible asynchronouse printer detection now 387 rManager.checkPrintersChanged( true ); 388 } 389 ::std::list< OUString > aPrinters; 390 rManager.listPrinters( aPrinters ); 391 392 for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it ) 393 { 394 const PrinterInfo& rInfo( rManager.getPrinterInfo( *it ) ); 395 // Neuen Eintrag anlegen 396 SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo; 397 pInfo->maPrinterName = *it; 398 pInfo->maDriver = rInfo.m_aDriverName; 399 pInfo->maLocation = rInfo.m_aLocation; 400 pInfo->maComment = rInfo.m_aComment; 401 pInfo->mpSysData = NULL; 402 403 sal_Int32 nIndex = 0; 404 while( nIndex != -1 ) 405 { 406 String aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); 407 if( aToken.CompareToAscii( "pdf=", 4 ) == COMPARE_EQUAL ) 408 { 409 pInfo->maLocation = getPdfDir( rInfo ); 410 break; 411 } 412 } 413 414 pList->Add( pInfo ); 415 } 416 } 417 418 // ----------------------------------------------------------------------- 419 420 void SvpSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo ) 421 { 422 delete pInfo; 423 } 424 425 // ----------------------------------------------------------------------- 426 427 void SvpSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* ) 428 { 429 } 430 431 // ----------------------------------------------------------------------- 432 433 String SvpSalInstance::GetDefaultPrinter() 434 { 435 PrinterInfoManager& rManager( PrinterInfoManager::get() ); 436 return rManager.getDefaultPrinter(); 437 } 438 439 // ======================================================================= 440 441 PspSalInfoPrinter::PspSalInfoPrinter() 442 { 443 m_pGraphics = NULL; 444 m_bPapersInit = false; 445 } 446 447 // ----------------------------------------------------------------------- 448 449 PspSalInfoPrinter::~PspSalInfoPrinter() 450 { 451 if( m_pGraphics ) 452 { 453 delete m_pGraphics; 454 m_pGraphics = NULL; 455 } 456 } 457 458 // ----------------------------------------------------------------------- 459 460 void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* ) 461 { 462 m_aPaperFormats.clear(); 463 m_bPapersInit = true; 464 465 if( m_aJobData.m_pParser ) 466 { 467 const PPDKey* pKey = m_aJobData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); 468 if( pKey ) 469 { 470 int nValues = pKey->countValues(); 471 for( int i = 0; i < nValues; i++ ) 472 { 473 const PPDValue* pValue = pKey->getValue( i ); 474 int nWidth = 0, nHeight = 0; 475 m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight ); 476 PaperInfo aInfo(PtTo10Mu( nWidth ), PtTo10Mu( nHeight )); 477 m_aPaperFormats.push_back( aInfo ); 478 } 479 } 480 } 481 } 482 483 // ----------------------------------------------------------------------- 484 485 int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* ) 486 { 487 return 900; 488 } 489 490 // ----------------------------------------------------------------------- 491 492 SalGraphics* PspSalInfoPrinter::GetGraphics() 493 { 494 // return a valid pointer only once 495 // the reasoning behind this is that we could have different 496 // SalGraphics that can run in multiple threads 497 // (future plans) 498 SalGraphics* pRet = NULL; 499 if( ! m_pGraphics ) 500 { 501 m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, NULL, false, this ); 502 m_pGraphics->SetLayout( 0 ); 503 pRet = m_pGraphics; 504 } 505 return pRet; 506 } 507 508 // ----------------------------------------------------------------------- 509 510 void PspSalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics ) 511 { 512 if( pGraphics == m_pGraphics ) 513 { 514 delete pGraphics; 515 m_pGraphics = NULL; 516 } 517 return; 518 } 519 520 // ----------------------------------------------------------------------- 521 522 sal_Bool PspSalInfoPrinter::Setup( SalFrame*, ImplJobSetup* ) 523 { 524 return sal_False; 525 } 526 527 // ----------------------------------------------------------------------- 528 529 // This function gets the driver data and puts it into pJobSetup 530 // If pJobSetup->mpDriverData is NOT NULL, then the independend 531 // data should be merged into the driver data 532 // If pJobSetup->mpDriverData IS NULL, then the driver defaults 533 // should be merged into the independent data 534 sal_Bool PspSalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup ) 535 { 536 if( pJobSetup->mpDriverData ) 537 return SetData( ~0, pJobSetup ); 538 539 copyJobDataToJobSetup( pJobSetup, m_aJobData ); 540 541 // set/clear backwards compatibility flag 542 bool bStrictSO52Compatibility = false; 543 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it = 544 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) ); 545 if( compat_it != pJobSetup->maValueMap.end() ) 546 { 547 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) ) 548 bStrictSO52Compatibility = true; 549 } 550 m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility ); 551 552 return sal_True; 553 } 554 555 // ----------------------------------------------------------------------- 556 557 // This function merges the independ driver data 558 // and sets the new independ data in pJobSetup 559 // Only the data must be changed, where the bit 560 // in nGetDataFlags is set 561 sal_Bool PspSalInfoPrinter::SetData( 562 sal_uLong nSetDataFlags, 563 ImplJobSetup* pJobSetup ) 564 { 565 JobData aData; 566 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 567 568 if( aData.m_pParser ) 569 { 570 const PPDKey* pKey; 571 const PPDValue* pValue; 572 573 // merge papersize if necessary 574 if( nSetDataFlags & SAL_JOBSET_PAPERSIZE ) 575 { 576 int nWidth, nHeight; 577 if( pJobSetup->meOrientation == ORIENTATION_PORTRAIT ) 578 { 579 nWidth = pJobSetup->mnPaperWidth; 580 nHeight = pJobSetup->mnPaperHeight; 581 } 582 else 583 { 584 nWidth = pJobSetup->mnPaperHeight; 585 nHeight = pJobSetup->mnPaperWidth; 586 } 587 String aPaper; 588 589 if( pJobSetup->mePaperFormat == PAPER_USER ) 590 aPaper = aData.m_pParser->matchPaper( 591 TenMuToPt( pJobSetup->mnPaperWidth ), 592 TenMuToPt( pJobSetup->mnPaperHeight ) ); 593 else 594 aPaper = rtl::OStringToOUString(PaperInfo::toPSName(pJobSetup->mePaperFormat), RTL_TEXTENCODING_ISO_8859_1); 595 596 pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); 597 pValue = pKey ? pKey->getValue( aPaper ) : NULL; 598 if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) ) 599 return sal_False; 600 } 601 602 // merge paperbin if necessary 603 if( nSetDataFlags & SAL_JOBSET_PAPERBIN ) 604 { 605 pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ); 606 if( pKey ) 607 { 608 int nPaperBin = pJobSetup->mnPaperBin; 609 if( nPaperBin == 0xffff ) 610 pValue = pKey->getDefaultValue(); 611 else 612 pValue = pKey->getValue( pJobSetup->mnPaperBin ); 613 614 // may fail due to constraints; 615 // real paper bin is copied back to jobsetup in that case 616 aData.m_aContext.setValue( pKey, pValue ); 617 } 618 // if printer has no InputSlot key simply ignore this setting 619 // (e.g. SGENPRT has no InputSlot) 620 } 621 622 // merge orientation if necessary 623 if( nSetDataFlags & SAL_JOBSET_ORIENTATION ) 624 aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait; 625 626 // merge duplex if necessary 627 if( nSetDataFlags & SAL_JOBSET_DUPLEXMODE ) 628 { 629 pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) ); 630 if( pKey ) 631 { 632 pValue = NULL; 633 switch( pJobSetup->meDuplexMode ) 634 { 635 case DUPLEX_OFF: 636 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) ); 637 if( pValue == NULL ) 638 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "SimplexNoTumble" ) ) ); 639 break; 640 case DUPLEX_SHORTEDGE: 641 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexTumble" ) ) ); 642 break; 643 case DUPLEX_LONGEDGE: 644 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexNoTumble" ) ) ); 645 break; 646 case DUPLEX_UNKNOWN: 647 default: 648 pValue = 0; 649 break; 650 } 651 if( ! pValue ) 652 pValue = pKey->getDefaultValue(); 653 aData.m_aContext.setValue( pKey, pValue ); 654 } 655 } 656 657 m_aJobData = aData; 658 copyJobDataToJobSetup( pJobSetup, aData ); 659 return sal_True; 660 } 661 662 return sal_False; 663 } 664 665 // ----------------------------------------------------------------------- 666 667 void PspSalInfoPrinter::GetPageInfo( 668 const ImplJobSetup* pJobSetup, 669 long& rOutWidth, long& rOutHeight, 670 long& rPageOffX, long& rPageOffY, 671 long& rPageWidth, long& rPageHeight ) 672 { 673 if( ! pJobSetup ) 674 return; 675 676 JobData aData; 677 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 678 679 // get the selected page size 680 if( aData.m_pParser ) 681 { 682 683 String aPaper; 684 int width, height; 685 int left = 0, top = 0, right = 0, bottom = 0; 686 int nDPI = aData.m_aContext.getRenderResolution(); 687 688 689 if( aData.m_eOrientation == psp::orientation::Portrait ) 690 { 691 aData.m_aContext.getPageSize( aPaper, width, height ); 692 aData.m_pParser->getMargins( aPaper, left, right, top, bottom ); 693 } 694 else 695 { 696 aData.m_aContext.getPageSize( aPaper, height, width ); 697 aData.m_pParser->getMargins( aPaper, top, bottom, right, left ); 698 } 699 700 rPageWidth = width * nDPI / 72; 701 rPageHeight = height * nDPI / 72; 702 rPageOffX = left * nDPI / 72; 703 rPageOffY = top * nDPI / 72; 704 rOutWidth = ( width - left - right ) * nDPI / 72; 705 rOutHeight = ( height - top - bottom ) * nDPI / 72; 706 } 707 } 708 709 // ----------------------------------------------------------------------- 710 711 sal_uLong PspSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup ) 712 { 713 if( ! pJobSetup ) 714 return 0; 715 716 JobData aData; 717 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 718 719 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL; 720 return pKey ? pKey->countValues() : 0; 721 } 722 723 // ----------------------------------------------------------------------- 724 725 String PspSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, sal_uLong nPaperBin ) 726 { 727 JobData aData; 728 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 729 730 String aRet; 731 if( aData.m_pParser ) 732 { 733 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL; 734 if( nPaperBin == 0xffff || ! pKey ) 735 aRet = aData.m_pParser->getDefaultInputSlot(); 736 else 737 { 738 const PPDValue* pValue = pKey->getValue( nPaperBin ); 739 if( pValue ) 740 aRet = aData.m_pParser->translateOption( pKey->getKey(), pValue->m_aOption ); 741 } 742 } 743 744 return aRet; 745 } 746 747 // ----------------------------------------------------------------------- 748 749 sal_uLong PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, sal_uInt16 nType ) 750 { 751 switch( nType ) 752 { 753 case PRINTER_CAPABILITIES_SUPPORTDIALOG: 754 return 1; 755 case PRINTER_CAPABILITIES_COPIES: 756 return 0xffff; 757 case PRINTER_CAPABILITIES_COLLATECOPIES: 758 { 759 // see if the PPD contains a value to set Collate to True 760 JobData aData; 761 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData ); 762 763 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ) : NULL; 764 const PPDValue* pVal = pKey ? pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) ) : NULL; 765 766 // PPDs don't mention the number of possible collated copies. 767 // so let's guess as many as we want ? 768 return pVal ? 0xffff : 0; 769 } 770 case PRINTER_CAPABILITIES_SETORIENTATION: 771 return 1; 772 case PRINTER_CAPABILITIES_SETDUPLEX: 773 return 1; 774 case PRINTER_CAPABILITIES_SETPAPERBIN: 775 return 1; 776 case PRINTER_CAPABILITIES_SETPAPERSIZE: 777 return 1; 778 case PRINTER_CAPABILITIES_SETPAPER: 779 return 0; 780 case PRINTER_CAPABILITIES_FAX: 781 { 782 PrinterInfoManager& rManager = PrinterInfoManager::get(); 783 PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) ); 784 String aFeatures( aInfo.m_aFeatures ); 785 int nTokenCount = aFeatures.GetTokenCount( ',' ); 786 for( int i = 0; i < nTokenCount; i++ ) 787 { 788 if( aFeatures.GetToken( i ).CompareToAscii( "fax", 3 ) == COMPARE_EQUAL ) 789 return 1; 790 } 791 return 0; 792 } 793 case PRINTER_CAPABILITIES_PDF: 794 { 795 PrinterInfoManager& rManager = PrinterInfoManager::get(); 796 PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) ); 797 String aFeatures( aInfo.m_aFeatures ); 798 int nTokenCount = aFeatures.GetTokenCount( ',' ); 799 for( int i = 0; i < nTokenCount; i++ ) 800 { 801 if( aFeatures.GetToken( i ).CompareToAscii( "pdf=", 4 ) == COMPARE_EQUAL ) 802 return 1; 803 } 804 return 0; 805 } 806 default: break; 807 }; 808 return 0; 809 } 810 811 // ======================================================================= 812 813 /* 814 * SalPrinter 815 */ 816 817 PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter ) 818 : m_bFax( false ), 819 m_bPdf( false ), 820 m_bSwallowFaxNo( false ), 821 m_pGraphics( NULL ), 822 m_nCopies( 1 ), 823 m_bCollate( false ), 824 m_pInfoPrinter( pInfoPrinter ) 825 { 826 } 827 828 // ----------------------------------------------------------------------- 829 830 PspSalPrinter::~PspSalPrinter() 831 { 832 } 833 834 // ----------------------------------------------------------------------- 835 836 static String getTmpName() 837 { 838 rtl::OUString aTmp, aSys; 839 osl_createTempFile( NULL, NULL, &aTmp.pData ); 840 osl_getSystemPathFromFileURL( aTmp.pData, &aSys.pData ); 841 842 return aSys; 843 } 844 845 sal_Bool PspSalPrinter::StartJob( 846 const XubString* pFileName, 847 const XubString& rJobName, 848 const XubString& rAppName, 849 sal_uLong nCopies, 850 bool bCollate, 851 bool /*bDirect*/, 852 ImplJobSetup* pJobSetup ) 853 { 854 vcl_sal::PrinterUpdate::jobStarted(); 855 856 m_bFax = false; 857 m_bPdf = false; 858 m_aFileName = pFileName ? *pFileName : String(); 859 m_aTmpFile = String(); 860 m_nCopies = nCopies; 861 m_bCollate = bCollate; 862 863 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData ); 864 if( m_nCopies > 1 ) 865 { 866 // in case user did not do anything (m_nCopies=1) 867 // take the default from jobsetup 868 m_aJobData.m_nCopies = m_nCopies; 869 m_aJobData.setCollate( bCollate ); 870 } 871 872 // check wether this printer is configured as fax 873 int nMode = 0; 874 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) ); 875 sal_Int32 nIndex = 0; 876 while( nIndex != -1 ) 877 { 878 OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); 879 if( ! aToken.compareToAscii( "fax", 3 ) ) 880 { 881 m_bFax = true; 882 m_aTmpFile = getTmpName(); 883 nMode = S_IRUSR | S_IWUSR; 884 885 ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >::const_iterator it; 886 it = pJobSetup->maValueMap.find( ::rtl::OUString::createFromAscii( "FAX#" ) ); 887 if( it != pJobSetup->maValueMap.end() ) 888 m_aFaxNr = it->second; 889 890 sal_Int32 nPos = 0; 891 m_bSwallowFaxNo = ! aToken.getToken( 1, '=', nPos ).compareToAscii( "swallow", 7 ) ? true : false; 892 893 break; 894 } 895 if( ! aToken.compareToAscii( "pdf=", 4 ) ) 896 { 897 m_bPdf = true; 898 m_aTmpFile = getTmpName(); 899 nMode = S_IRUSR | S_IWUSR; 900 901 if( ! m_aFileName.Len() ) 902 { 903 m_aFileName = getPdfDir( rInfo ); 904 m_aFileName.Append( '/' ); 905 m_aFileName.Append( rJobName ); 906 m_aFileName.AppendAscii( ".pdf" ); 907 } 908 break; 909 } 910 } 911 m_aPrinterGfx.Init( m_aJobData ); 912 913 // set/clear backwards compatibility flag 914 bool bStrictSO52Compatibility = false; 915 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it = 916 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) ); 917 if( compat_it != pJobSetup->maValueMap.end() ) 918 { 919 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) ) 920 bStrictSO52Compatibility = true; 921 } 922 m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility ); 923 924 return m_aPrintJob.StartJob( m_aTmpFile.Len() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, false ) ? sal_True : sal_False; 925 } 926 927 // ----------------------------------------------------------------------- 928 929 sal_Bool PspSalPrinter::EndJob() 930 { 931 sal_Bool bSuccess = m_aPrintJob.EndJob(); 932 933 if( bSuccess ) 934 { 935 // check for fax 936 if( m_bFax ) 937 { 938 939 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) ); 940 // sendAFax removes the file after use 941 bSuccess = sendAFax( m_aFaxNr, m_aTmpFile, rInfo.m_aCommand ); 942 } 943 else if( m_bPdf ) 944 { 945 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) ); 946 bSuccess = createPdf( m_aFileName, m_aTmpFile, rInfo.m_aCommand ); 947 } 948 } 949 vcl_sal::PrinterUpdate::jobEnded(); 950 return bSuccess; 951 } 952 953 // ----------------------------------------------------------------------- 954 955 sal_Bool PspSalPrinter::AbortJob() 956 { 957 sal_Bool bAbort = m_aPrintJob.AbortJob() ? sal_True : sal_False; 958 vcl_sal::PrinterUpdate::jobEnded(); 959 return bAbort; 960 } 961 962 // ----------------------------------------------------------------------- 963 964 SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, sal_Bool ) 965 { 966 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData ); 967 m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, m_bFax ? &m_aFaxNr : NULL, m_bSwallowFaxNo, m_pInfoPrinter ); 968 m_pGraphics->SetLayout( 0 ); 969 if( m_nCopies > 1 ) 970 { 971 // in case user did not do anything (m_nCopies=1) 972 // take the default from jobsetup 973 m_aJobData.m_nCopies = m_nCopies; 974 m_aJobData.setCollate( m_nCopies > 1 && m_bCollate ); 975 } 976 977 m_aPrintJob.StartPage( m_aJobData ); 978 m_aPrinterGfx.Init( m_aPrintJob ); 979 980 return m_pGraphics; 981 } 982 983 // ----------------------------------------------------------------------- 984 985 sal_Bool PspSalPrinter::EndPage() 986 { 987 sal_Bool bResult = m_aPrintJob.EndPage(); 988 m_aPrinterGfx.Clear(); 989 return bResult ? sal_True : sal_False; 990 } 991 992 // ----------------------------------------------------------------------- 993 994 sal_uLong PspSalPrinter::GetErrorCode() 995 { 996 return 0; 997 } 998 999 /* 1000 * vcl::PrinterUpdate 1001 */ 1002 1003 Timer* vcl_sal::PrinterUpdate::pPrinterUpdateTimer = NULL; 1004 int vcl_sal::PrinterUpdate::nActiveJobs = 0; 1005 1006 void vcl_sal::PrinterUpdate::doUpdate() 1007 { 1008 ::psp::PrinterInfoManager& rManager( ::psp::PrinterInfoManager::get() ); 1009 if( rManager.checkPrintersChanged( false ) && SvpSalInstance::s_pDefaultInstance ) 1010 { 1011 const std::list< SalFrame* >& rList = SvpSalInstance::s_pDefaultInstance->getFrames(); 1012 for( std::list< SalFrame* >::const_iterator it = rList.begin(); 1013 it != rList.end(); ++it ) 1014 SvpSalInstance::s_pDefaultInstance->PostEvent( *it, NULL, SALEVENT_PRINTERCHANGED ); 1015 } 1016 } 1017 1018 // ----------------------------------------------------------------------- 1019 1020 IMPL_STATIC_LINK_NOINSTANCE( vcl_sal::PrinterUpdate, UpdateTimerHdl, void*, ) 1021 { 1022 if( nActiveJobs < 1 ) 1023 { 1024 doUpdate(); 1025 delete pPrinterUpdateTimer; 1026 pPrinterUpdateTimer = NULL; 1027 } 1028 else 1029 pPrinterUpdateTimer->Start(); 1030 1031 return 0; 1032 } 1033 1034 // ----------------------------------------------------------------------- 1035 1036 void vcl_sal::PrinterUpdate::update() 1037 { 1038 if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() ) 1039 return; 1040 1041 static bool bOnce = false; 1042 if( ! bOnce ) 1043 { 1044 bOnce = true; 1045 // start background printer detection 1046 psp::PrinterInfoManager::get(); 1047 return; 1048 } 1049 1050 if( nActiveJobs < 1 ) 1051 doUpdate(); 1052 else if( ! pPrinterUpdateTimer ) 1053 { 1054 pPrinterUpdateTimer = new Timer(); 1055 pPrinterUpdateTimer->SetTimeout( 500 ); 1056 pPrinterUpdateTimer->SetTimeoutHdl( STATIC_LINK( NULL, vcl_sal::PrinterUpdate, UpdateTimerHdl ) ); 1057 pPrinterUpdateTimer->Start(); 1058 } 1059 } 1060 1061 // ----------------------------------------------------------------------- 1062 1063 void vcl_sal::PrinterUpdate::jobEnded() 1064 { 1065 nActiveJobs--; 1066 if( nActiveJobs < 1 ) 1067 { 1068 if( pPrinterUpdateTimer ) 1069 { 1070 pPrinterUpdateTimer->Stop(); 1071 delete pPrinterUpdateTimer; 1072 pPrinterUpdateTimer = NULL; 1073 doUpdate(); 1074 } 1075 } 1076 } 1077