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