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/wait.h> 33 #include <signal.h> 34 35 #include "cupsmgr.hxx" 36 #include "vcl/fontmanager.hxx" 37 #include "vcl/strhelper.hxx" 38 39 #include "unx/saldata.hxx" 40 41 #include "tools/urlobj.hxx" 42 #include "tools/stream.hxx" 43 #include "tools/debug.hxx" 44 #include "tools/config.hxx" 45 46 #include "i18npool/paper.hxx" 47 48 #include "rtl/strbuf.hxx" 49 50 #include "osl/thread.hxx" 51 #include "osl/mutex.hxx" 52 #include "osl/process.h" 53 54 // filename of configuration files 55 #define PRINT_FILENAME "psprint.conf" 56 // the group of the global defaults 57 #define GLOBAL_DEFAULTS_GROUP "__Global_Printer_Defaults__" 58 59 #include <hash_set> 60 61 using namespace psp; 62 using namespace rtl; 63 using namespace osl; 64 65 namespace psp 66 { 67 class SystemQueueInfo : public Thread 68 { 69 mutable Mutex m_aMutex; 70 bool m_bChanged; 71 std::list< PrinterInfoManager::SystemPrintQueue > 72 m_aQueues; 73 OUString m_aCommand; 74 75 virtual void run(); 76 77 public: 78 SystemQueueInfo(); 79 ~SystemQueueInfo(); 80 81 bool hasChanged() const; 82 OUString getCommand() const; 83 84 // sets changed status to false; therefore not const 85 void getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues ); 86 }; 87 } // namespace 88 89 /* 90 * class PrinterInfoManager 91 */ 92 93 // ----------------------------------------------------------------- 94 95 PrinterInfoManager& PrinterInfoManager::get() 96 { 97 SalData* pSalData = GetSalData(); 98 99 if( ! pSalData->m_pPIManager ) 100 { 101 pSalData->m_pPIManager = CUPSManager::tryLoadCUPS(); 102 if( ! pSalData->m_pPIManager ) 103 pSalData->m_pPIManager = new PrinterInfoManager(); 104 105 pSalData->m_pPIManager->initialize(); 106 #if OSL_DEBUG_LEVEL > 1 107 fprintf( stderr, "PrinterInfoManager::get create Manager of type %d\n", pSalData->m_pPIManager->getType() ); 108 #endif 109 } 110 111 return *pSalData->m_pPIManager; 112 } 113 114 void PrinterInfoManager::release() 115 { 116 SalData* pSalData = GetSalData(); 117 delete pSalData->m_pPIManager; 118 pSalData->m_pPIManager = NULL; 119 } 120 121 // ----------------------------------------------------------------- 122 123 PrinterInfoManager::PrinterInfoManager( Type eType ) : 124 m_pQueueInfo( NULL ), 125 m_eType( eType ), 126 m_bUseIncludeFeature( false ), 127 m_bUseJobPatch( true ), 128 m_aSystemDefaultPaper( RTL_CONSTASCII_USTRINGPARAM( "A4" ) ), 129 m_bDisableCUPS( false ) 130 { 131 if( eType == Default ) 132 m_pQueueInfo = new SystemQueueInfo(); 133 initSystemDefaultPaper(); 134 } 135 136 // ----------------------------------------------------------------- 137 138 PrinterInfoManager::~PrinterInfoManager() 139 { 140 delete m_pQueueInfo; 141 #if OSL_DEBUG_LEVEL > 1 142 fprintf( stderr, "PrinterInfoManager: destroyed Manager of type %d\n", getType() ); 143 #endif 144 } 145 146 // ----------------------------------------------------------------- 147 148 bool PrinterInfoManager::isCUPSDisabled() const 149 { 150 return m_bDisableCUPS; 151 } 152 153 // ----------------------------------------------------------------- 154 155 void PrinterInfoManager::setCUPSDisabled( bool bDisable ) 156 { 157 m_bDisableCUPS = bDisable; 158 writePrinterConfig(); 159 // actually we know the printers changed 160 // however this triggers reinitialization the right way 161 checkPrintersChanged( true ); 162 } 163 164 // ----------------------------------------------------------------- 165 166 void PrinterInfoManager::initSystemDefaultPaper() 167 { 168 m_aSystemDefaultPaper = rtl::OStringToOUString( 169 PaperInfo::toPSName(PaperInfo::getSystemDefaultPaper().getPaper()), 170 RTL_TEXTENCODING_UTF8); 171 } 172 173 // ----------------------------------------------------------------- 174 175 bool PrinterInfoManager::checkPrintersChanged( bool bWait ) 176 { 177 // check if files were created, deleted or modified since initialize() 178 ::std::list< WatchFile >::const_iterator it; 179 bool bChanged = false; 180 for( it = m_aWatchFiles.begin(); it != m_aWatchFiles.end() && ! bChanged; ++it ) 181 { 182 DirectoryItem aItem; 183 if( DirectoryItem::get( it->m_aFilePath, aItem ) ) 184 { 185 if( it->m_aModified.Seconds != 0 ) 186 bChanged = true; // file probably has vanished 187 } 188 else 189 { 190 FileStatus aStatus( FileStatusMask_ModifyTime ); 191 if( aItem.getFileStatus( aStatus ) ) 192 bChanged = true; // unlikely but not impossible 193 else 194 { 195 TimeValue aModified = aStatus.getModifyTime(); 196 if( aModified.Seconds != it->m_aModified.Seconds ) 197 bChanged = true; 198 } 199 } 200 } 201 202 if( bWait && m_pQueueInfo ) 203 { 204 #if OSL_DEBUG_LEVEL > 1 205 fprintf( stderr, "syncing printer discovery thread\n" ); 206 #endif 207 m_pQueueInfo->join(); 208 #if OSL_DEBUG_LEVEL > 1 209 fprintf( stderr, "done: syncing printer discovery thread\n" ); 210 #endif 211 } 212 213 if( ! bChanged && m_pQueueInfo ) 214 bChanged = m_pQueueInfo->hasChanged(); 215 if( bChanged ) 216 { 217 initialize(); 218 } 219 220 return bChanged; 221 } 222 223 // ----------------------------------------------------------------- 224 225 void PrinterInfoManager::initialize() 226 { 227 m_bUseIncludeFeature = false; 228 rtl_TextEncoding aEncoding = gsl_getSystemTextEncoding(); 229 m_aPrinters.clear(); 230 m_aWatchFiles.clear(); 231 OUString aDefaultPrinter; 232 233 // first initialize the global defaults 234 // have to iterate over all possible files 235 // there should be only one global setup section in all 236 // available config files 237 m_aGlobalDefaults = PrinterInfo(); 238 239 // need a parser for the PPDContext. generic printer should do. 240 m_aGlobalDefaults.m_pParser = PPDParser::getParser( String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ) ); 241 m_aGlobalDefaults.m_aContext.setParser( m_aGlobalDefaults.m_pParser ); 242 m_aGlobalDefaults.m_bPerformFontSubstitution = true; 243 m_bDisableCUPS = false; 244 245 if( ! m_aGlobalDefaults.m_pParser ) 246 { 247 #if OSL_DEBUG_LEVEL > 1 248 fprintf( stderr, "Error: no default PPD file SGENPRT available, shutting down psprint...\n" ); 249 #endif 250 return; 251 } 252 253 std::list< OUString > aDirList; 254 psp::getPrinterPathList( aDirList, NULL ); 255 std::list< OUString >::const_iterator print_dir_it; 256 for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it ) 257 { 258 INetURLObject aFile( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL ); 259 aFile.Append( String( RTL_CONSTASCII_USTRINGPARAM( PRINT_FILENAME ) ) ); 260 Config aConfig( aFile.PathToFileName() ); 261 if( aConfig.HasGroup( GLOBAL_DEFAULTS_GROUP ) ) 262 { 263 #if OSL_DEBUG_LEVEL > 1 264 fprintf( stderr, "found global defaults in %s\n", OUStringToOString( aFile.PathToFileName(), RTL_TEXTENCODING_ISO_8859_1 ).getStr() ); 265 #endif 266 aConfig.SetGroup( GLOBAL_DEFAULTS_GROUP ); 267 268 ByteString aValue( aConfig.ReadKey( "Copies" ) ); 269 if( aValue.Len() ) 270 m_aGlobalDefaults.m_nCopies = aValue.ToInt32(); 271 272 aValue = aConfig.ReadKey( "Orientation" ); 273 if( aValue.Len() ) 274 m_aGlobalDefaults.m_eOrientation = aValue.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape : orientation::Portrait; 275 276 aValue = aConfig.ReadKey( "MarginAdjust" ); 277 if( aValue.Len() ) 278 { 279 m_aGlobalDefaults.m_nLeftMarginAdjust = aValue.GetToken( 0, ',' ).ToInt32(); 280 m_aGlobalDefaults.m_nRightMarginAdjust = aValue.GetToken( 1, ',' ).ToInt32(); 281 m_aGlobalDefaults.m_nTopMarginAdjust = aValue.GetToken( 2, ',' ).ToInt32(); 282 m_aGlobalDefaults.m_nBottomMarginAdjust = aValue.GetToken( 3, ',' ).ToInt32(); 283 } 284 285 aValue = aConfig.ReadKey( "ColorDepth", "24" ); 286 if( aValue.Len() ) 287 m_aGlobalDefaults.m_nColorDepth = aValue.ToInt32(); 288 289 aValue = aConfig.ReadKey( "ColorDevice" ); 290 if( aValue.Len() ) 291 m_aGlobalDefaults.m_nColorDevice = aValue.ToInt32(); 292 293 aValue = aConfig.ReadKey( "PSLevel" ); 294 if( aValue.Len() ) 295 m_aGlobalDefaults.m_nPSLevel = aValue.ToInt32(); 296 297 aValue = aConfig.ReadKey( "PDFDevice" ); 298 if( aValue.Len() ) 299 m_aGlobalDefaults.m_nPDFDevice = aValue.ToInt32(); 300 301 aValue = aConfig.ReadKey( "PerformFontSubstitution" ); 302 if( aValue.Len() ) 303 { 304 if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) ) 305 m_aGlobalDefaults.m_bPerformFontSubstitution = true; 306 else 307 m_aGlobalDefaults.m_bPerformFontSubstitution = false; 308 } 309 310 aValue = aConfig.ReadKey( "DisableCUPS" ); 311 if( aValue.Len() ) 312 { 313 if( aValue.Equals( "1" ) || aValue.EqualsIgnoreCaseAscii( "true" ) ) 314 m_bDisableCUPS = true; 315 else 316 m_bDisableCUPS = false; 317 } 318 319 // get the PPDContext of global JobData 320 for( int nKey = 0; nKey < aConfig.GetKeyCount(); nKey++ ) 321 { 322 ByteString aKey( aConfig.GetKeyName( nKey ) ); 323 if( aKey.CompareTo( "PPD_", 4 ) == COMPARE_EQUAL ) 324 { 325 aValue = aConfig.ReadKey( aKey ); 326 const PPDKey* pKey = m_aGlobalDefaults.m_pParser->getKey( String( aKey.Copy( 4 ), RTL_TEXTENCODING_ISO_8859_1 ) ); 327 if( pKey ) 328 { 329 m_aGlobalDefaults.m_aContext. 330 setValue( pKey, 331 aValue.Equals( "*nil" ) ? NULL : pKey->getValue( String( aValue, RTL_TEXTENCODING_ISO_8859_1 ) ), 332 sal_True ); 333 } 334 } 335 else if( aKey.Len() > 10 && aKey.CompareTo("SubstFont_", 10 ) == COMPARE_EQUAL ) 336 { 337 aValue = aConfig.ReadKey( aKey ); 338 m_aGlobalDefaults.m_aFontSubstitutes[ OStringToOUString( aKey.Copy( 10 ), RTL_TEXTENCODING_ISO_8859_1 ) ] = OStringToOUString( aValue, RTL_TEXTENCODING_ISO_8859_1 ); 339 } 340 } 341 #if OSL_DEBUG_LEVEL > 1 342 fprintf( stderr, "global settings: fontsubst = %s, %d substitutes\n", m_aGlobalDefaults.m_bPerformFontSubstitution ? "true" : "false", (int)m_aGlobalDefaults.m_aFontSubstitutes.size() ); 343 #endif 344 } 345 } 346 setDefaultPaper( m_aGlobalDefaults.m_aContext ); 347 fillFontSubstitutions( m_aGlobalDefaults ); 348 349 // now collect all available printers 350 for( print_dir_it = aDirList.begin(); print_dir_it != aDirList.end(); ++print_dir_it ) 351 { 352 INetURLObject aDir( *print_dir_it, INET_PROT_FILE, INetURLObject::ENCODE_ALL ); 353 INetURLObject aFile( aDir ); 354 aFile.Append( String( RTL_CONSTASCII_USTRINGPARAM( PRINT_FILENAME ) ) ); 355 356 // check directory validity 357 OUString aUniPath; 358 FileBase::getFileURLFromSystemPath( aDir.PathToFileName(), aUniPath ); 359 Directory aDirectory( aUniPath ); 360 if( aDirectory.open() ) 361 continue; 362 aDirectory.close(); 363 364 365 FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aUniPath ); 366 FileStatus aStatus( FileStatusMask_ModifyTime ); 367 DirectoryItem aItem; 368 369 // setup WatchFile list 370 WatchFile aWatchFile; 371 aWatchFile.m_aFilePath = aUniPath; 372 if( ! DirectoryItem::get( aUniPath, aItem ) && 373 ! aItem.getFileStatus( aStatus ) ) 374 { 375 aWatchFile.m_aModified = aStatus.getModifyTime(); 376 } 377 else 378 { 379 aWatchFile.m_aModified.Seconds = 0; 380 aWatchFile.m_aModified.Nanosec = 0; 381 } 382 m_aWatchFiles.push_back( aWatchFile ); 383 384 Config aConfig( aFile.PathToFileName() ); 385 for( int nGroup = 0; nGroup < aConfig.GetGroupCount(); nGroup++ ) 386 { 387 aConfig.SetGroup( aConfig.GetGroupName( nGroup ) ); 388 ByteString aValue = aConfig.ReadKey( "Printer" ); 389 if( aValue.Len() ) 390 { 391 OUString aPrinterName; 392 393 int nNamePos = aValue.Search( '/' ); 394 // check for valid value of "Printer" 395 if( nNamePos == STRING_NOTFOUND ) 396 continue; 397 398 Printer aPrinter; 399 // initialize to global defaults 400 aPrinter.m_aInfo = m_aGlobalDefaults; 401 // global settings do not default the printer substitution 402 // list ! the substitution list in there is only used for 403 // newly created printers 404 aPrinter.m_aInfo.m_aFontSubstitutes.clear(); 405 aPrinter.m_aInfo.m_aFontSubstitutions.clear(); 406 407 aPrinterName = String( aValue.Copy( nNamePos+1 ), RTL_TEXTENCODING_UTF8 ); 408 aPrinter.m_aInfo.m_aPrinterName = aPrinterName; 409 aPrinter.m_aInfo.m_aDriverName = String( aValue.Copy( 0, nNamePos ), RTL_TEXTENCODING_UTF8 ); 410 411 // set parser, merge settings 412 // don't do this for CUPS printers as this is done 413 // by the CUPS system itself 414 if( aPrinter.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) != 0 ) 415 { 416 aPrinter.m_aInfo.m_pParser = PPDParser::getParser( aPrinter.m_aInfo.m_aDriverName ); 417 aPrinter.m_aInfo.m_aContext.setParser( aPrinter.m_aInfo.m_pParser ); 418 // note: setParser also purges the context 419 420 // ignore this printer if its driver is not found 421 if( ! aPrinter.m_aInfo.m_pParser ) 422 continue; 423 424 // merge the ppd context keys if the printer has the same keys and values 425 // this is a bit tricky, since it involves mixing two PPDs 426 // without constraints which might end up badly 427 // this feature should be use with caution 428 // it is mainly to select default paper sizes for new printers 429 for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ ) 430 { 431 const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified ); 432 const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey ); 433 const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL; 434 if( pDefKey && pPrinterKey ) 435 // at least the options exist in both PPDs 436 { 437 if( pDefValue ) 438 { 439 const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption ); 440 if( pPrinterValue ) 441 // the printer has a corresponding option for the key 442 aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue ); 443 } 444 else 445 aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL ); 446 } 447 } 448 449 aValue = aConfig.ReadKey( "Command" ); 450 // no printer without a command 451 if( ! aValue.Len() ) 452 { 453 /* TODO: 454 * porters: please append your platform to the Solaris 455 * case if your platform has SystemV printing per default. 456 */ 457 #if defined SOLARIS 458 aValue = "lp"; 459 #else 460 aValue = "lpr"; 461 #endif 462 } 463 aPrinter.m_aInfo.m_aCommand = String( aValue, RTL_TEXTENCODING_UTF8 ); 464 } 465 466 aValue = aConfig.ReadKey( "QuickCommand" ); 467 aPrinter.m_aInfo.m_aQuickCommand = String( aValue, RTL_TEXTENCODING_UTF8 ); 468 469 aValue = aConfig.ReadKey( "Features" ); 470 aPrinter.m_aInfo.m_aFeatures = String( aValue, RTL_TEXTENCODING_UTF8 ); 471 472 // override the settings in m_aGlobalDefaults if keys exist 473 aValue = aConfig.ReadKey( "DefaultPrinter" ); 474 if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) ) 475 aDefaultPrinter = aPrinterName; 476 477 aValue = aConfig.ReadKey( "Location" ); 478 aPrinter.m_aInfo.m_aLocation = String( aValue, RTL_TEXTENCODING_UTF8 ); 479 480 aValue = aConfig.ReadKey( "Comment" ); 481 aPrinter.m_aInfo.m_aComment = String( aValue, RTL_TEXTENCODING_UTF8 ); 482 483 aValue = aConfig.ReadKey( "Copies" ); 484 if( aValue.Len() ) 485 aPrinter.m_aInfo.m_nCopies = aValue.ToInt32(); 486 487 aValue = aConfig.ReadKey( "Orientation" ); 488 if( aValue.Len() ) 489 aPrinter.m_aInfo.m_eOrientation = aValue.EqualsIgnoreCaseAscii( "Landscape" ) ? orientation::Landscape : orientation::Portrait; 490 491 aValue = aConfig.ReadKey( "MarginAdjust" ); 492 if( aValue.Len() ) 493 { 494 aPrinter.m_aInfo.m_nLeftMarginAdjust = aValue.GetToken( 0, ',' ).ToInt32(); 495 aPrinter.m_aInfo.m_nRightMarginAdjust = aValue.GetToken( 1, ',' ).ToInt32(); 496 aPrinter.m_aInfo.m_nTopMarginAdjust = aValue.GetToken( 2, ',' ).ToInt32(); 497 aPrinter.m_aInfo.m_nBottomMarginAdjust = aValue.GetToken( 3, ',' ).ToInt32(); 498 } 499 500 aValue = aConfig.ReadKey( "ColorDepth" ); 501 if( aValue.Len() ) 502 aPrinter.m_aInfo.m_nColorDepth = aValue.ToInt32(); 503 504 aValue = aConfig.ReadKey( "ColorDevice" ); 505 if( aValue.Len() ) 506 aPrinter.m_aInfo.m_nColorDevice = aValue.ToInt32(); 507 508 aValue = aConfig.ReadKey( "PSLevel" ); 509 if( aValue.Len() ) 510 aPrinter.m_aInfo.m_nPSLevel = aValue.ToInt32(); 511 512 aValue = aConfig.ReadKey( "PDFDevice" ); 513 if( aValue.Len() ) 514 aPrinter.m_aInfo.m_nPDFDevice = aValue.ToInt32(); 515 516 aValue = aConfig.ReadKey( "PerformFontSubstitution" ); 517 if( ! aValue.Equals( "0" ) && ! aValue.EqualsIgnoreCaseAscii( "false" ) ) 518 aPrinter.m_aInfo.m_bPerformFontSubstitution = true; 519 else 520 aPrinter.m_aInfo.m_bPerformFontSubstitution = false; 521 522 // now iterate over all keys to extract multi key information: 523 // 1. PPDContext information 524 // 2. Font substitution table 525 for( int nKey = 0; nKey < aConfig.GetKeyCount(); nKey++ ) 526 { 527 ByteString aKey( aConfig.GetKeyName( nKey ) ); 528 if( aKey.CompareTo( "PPD_", 4 ) == COMPARE_EQUAL && aPrinter.m_aInfo.m_pParser ) 529 { 530 aValue = aConfig.ReadKey( aKey ); 531 const PPDKey* pKey = aPrinter.m_aInfo.m_pParser->getKey( String( aKey.Copy( 4 ), RTL_TEXTENCODING_ISO_8859_1 ) ); 532 if( pKey ) 533 { 534 aPrinter.m_aInfo.m_aContext. 535 setValue( pKey, 536 aValue.Equals( "*nil" ) ? NULL : pKey->getValue( String( aValue, RTL_TEXTENCODING_ISO_8859_1 ) ), 537 sal_True ); 538 } 539 } 540 else if( aKey.Len() > 10 && aKey.CompareTo("SubstFont_", 10 ) == COMPARE_EQUAL ) 541 { 542 aValue = aConfig.ReadKey( aKey ); 543 aPrinter.m_aInfo.m_aFontSubstitutes[ OStringToOUString( aKey.Copy( 10 ), RTL_TEXTENCODING_ISO_8859_1 ) ] = OStringToOUString( aValue, RTL_TEXTENCODING_ISO_8859_1 ); 544 } 545 } 546 547 setDefaultPaper( aPrinter.m_aInfo.m_aContext ); 548 fillFontSubstitutions( aPrinter.m_aInfo ); 549 550 // finally insert printer 551 FileBase::getFileURLFromSystemPath( aFile.PathToFileName(), aPrinter.m_aFile ); 552 aPrinter.m_bModified = false; 553 aPrinter.m_aGroup = aConfig.GetGroupName( nGroup ); 554 std::hash_map< OUString, Printer, OUStringHash >::const_iterator find_it = 555 m_aPrinters.find( aPrinterName ); 556 if( find_it != m_aPrinters.end() ) 557 { 558 aPrinter.m_aAlternateFiles = find_it->second.m_aAlternateFiles; 559 aPrinter.m_aAlternateFiles.push_front( find_it->second.m_aFile ); 560 } 561 m_aPrinters[ aPrinterName ] = aPrinter; 562 } 563 } 564 } 565 566 // set default printer 567 if( m_aPrinters.size() ) 568 { 569 if( m_aPrinters.find( aDefaultPrinter ) == m_aPrinters.end() ) 570 aDefaultPrinter = m_aPrinters.begin()->first; 571 } 572 else 573 aDefaultPrinter = OUString(); 574 m_aDefaultPrinter = aDefaultPrinter; 575 576 if( m_eType != Default ) 577 return; 578 579 // add a default printer for every available print queue 580 // merge paper and font substitution from default printer, 581 // all else from global defaults 582 PrinterInfo aMergeInfo( m_aGlobalDefaults ); 583 aMergeInfo.m_aDriverName = String( RTL_CONSTASCII_USTRINGPARAM( "SGENPRT" ) ); 584 aMergeInfo.m_aFeatures = String( RTL_CONSTASCII_USTRINGPARAM( "autoqueue" ) ); 585 586 if( m_aDefaultPrinter.getLength() ) 587 { 588 PrinterInfo aDefaultInfo( getPrinterInfo( m_aDefaultPrinter ) ); 589 aMergeInfo.m_bPerformFontSubstitution = aDefaultInfo.m_bPerformFontSubstitution; 590 fillFontSubstitutions( aMergeInfo ); 591 592 const PPDKey* pDefKey = aDefaultInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); 593 const PPDKey* pMergeKey = aMergeInfo.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); 594 const PPDValue* pDefValue = aDefaultInfo.m_aContext.getValue( pDefKey ); 595 const PPDValue* pMergeValue = pMergeKey ? pMergeKey->getValue( pDefValue->m_aOption ) : NULL; 596 if( pMergeKey && pMergeValue ) 597 aMergeInfo.m_aContext.setValue( pMergeKey, pMergeValue ); 598 } 599 600 getSystemPrintQueues(); 601 for( ::std::list< SystemPrintQueue >::iterator it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it ) 602 { 603 String aPrinterName( RTL_CONSTASCII_USTRINGPARAM( "<" ) ); 604 aPrinterName += String( it->m_aQueue ); 605 aPrinterName.Append( '>' ); 606 607 if( m_aPrinters.find( aPrinterName ) != m_aPrinters.end() ) 608 // probably user made this one permanent in padmin 609 continue; 610 611 String aCmd( m_aSystemPrintCommand ); 612 aCmd.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PRINTER)" ) ), it->m_aQueue ); 613 614 Printer aPrinter; 615 616 // initialize to merged defaults 617 aPrinter.m_aInfo = aMergeInfo; 618 aPrinter.m_aInfo.m_aPrinterName = aPrinterName; 619 aPrinter.m_aInfo.m_aCommand = aCmd; 620 aPrinter.m_aInfo.m_aComment = it->m_aComment; 621 aPrinter.m_aInfo.m_aLocation = it->m_aLocation; 622 aPrinter.m_bModified = false; 623 aPrinter.m_aGroup = ByteString( aPrinterName, aEncoding ); //provide group name in case user makes this one permanent in padmin 624 625 m_aPrinters[ aPrinterName ] = aPrinter; 626 } 627 } 628 629 // ----------------------------------------------------------------- 630 631 void PrinterInfoManager::listPrinters( ::std::list< OUString >& rList ) const 632 { 633 ::std::hash_map< OUString, Printer, OUStringHash >::const_iterator it; 634 rList.clear(); 635 for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it ) 636 rList.push_back( it->first ); 637 } 638 639 // ----------------------------------------------------------------- 640 641 const PrinterInfo& PrinterInfoManager::getPrinterInfo( const OUString& rPrinter ) const 642 { 643 static PrinterInfo aEmptyInfo; 644 ::std::hash_map< OUString, Printer, OUStringHash >::const_iterator it = m_aPrinters.find( rPrinter ); 645 646 DBG_ASSERT( it != m_aPrinters.end(), "Do not ask for info about nonexistent printers" ); 647 648 return it != m_aPrinters.end() ? it->second.m_aInfo : aEmptyInfo; 649 } 650 651 // ----------------------------------------------------------------- 652 653 void PrinterInfoManager::changePrinterInfo( const OUString& rPrinter, const PrinterInfo& rNewInfo ) 654 { 655 ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinter ); 656 657 DBG_ASSERT( it != m_aPrinters.end(), "Do not change nonexistant printers" ); 658 659 if( it != m_aPrinters.end() ) 660 { 661 it->second.m_aInfo = rNewInfo; 662 // recalculate font substitutions 663 fillFontSubstitutions( it->second.m_aInfo ); 664 it->second.m_bModified = true; 665 writePrinterConfig(); 666 } 667 } 668 669 // ----------------------------------------------------------------- 670 671 // need to check writeability / creatability of config files 672 static bool checkWriteability( const OUString& rUniPath ) 673 { 674 bool bRet = false; 675 OUString aSysPath; 676 FileBase::getSystemPathFromFileURL( rUniPath, aSysPath ); 677 SvFileStream aStream( aSysPath, STREAM_READ | STREAM_WRITE ); 678 if( aStream.IsOpen() && aStream.IsWritable() ) 679 bRet = true; 680 return bRet; 681 } 682 683 bool PrinterInfoManager::writePrinterConfig() 684 { 685 // find at least one writeable config 686 ::std::hash_map< OUString, Config*, OUStringHash > files; 687 ::std::hash_map< OUString, int, OUStringHash > rofiles; 688 ::std::hash_map< OUString, Config*, OUStringHash >::iterator file_it; 689 690 for( ::std::list< WatchFile >::const_iterator wit = m_aWatchFiles.begin(); wit != m_aWatchFiles.end(); ++wit ) 691 { 692 if( checkWriteability( wit->m_aFilePath ) ) 693 { 694 files[ wit->m_aFilePath ] = new Config( wit->m_aFilePath ); 695 break; 696 } 697 } 698 699 if( files.empty() ) 700 return false; 701 702 Config* pGlobal = files.begin()->second; 703 pGlobal->SetGroup( GLOBAL_DEFAULTS_GROUP ); 704 pGlobal->WriteKey( "DisableCUPS", m_bDisableCUPS ? "true" : "false" ); 705 706 ::std::hash_map< OUString, Printer, OUStringHash >::iterator it; 707 for( it = m_aPrinters.begin(); it != m_aPrinters.end(); ++it ) 708 { 709 if( ! it->second.m_bModified ) 710 // printer was not changed, do nothing 711 continue; 712 713 // don't save autoqueue printers 714 sal_Int32 nIndex = 0; 715 bool bAutoQueue = false; 716 while( nIndex != -1 && ! bAutoQueue ) 717 { 718 OUString aToken( it->second.m_aInfo.m_aFeatures.getToken( 0, ',', nIndex ) ); 719 if( aToken.getLength() && aToken.compareToAscii( "autoqueue" ) == 0 ) 720 bAutoQueue = true; 721 } 722 if( bAutoQueue ) 723 continue; 724 725 if( it->second.m_aFile.getLength() ) 726 { 727 // check if file is writable 728 if( files.find( it->second.m_aFile ) == files.end() ) 729 { 730 bool bInsertToNewFile = false; 731 // maybe it is simply not inserted yet 732 if( rofiles.find( it->second.m_aFile ) == rofiles.end() ) 733 { 734 if( checkWriteability( it->second.m_aFile ) ) 735 files[ it->second.m_aFile ] = new Config( it->second.m_aFile ); 736 else 737 bInsertToNewFile = true; 738 } 739 else 740 bInsertToNewFile = true; 741 // original file is read only, insert printer in a new writeable file 742 if( bInsertToNewFile ) 743 { 744 rofiles[ it->second.m_aFile ] = 1; 745 // update alternate file list 746 // the remove operation ensures uniqueness of each alternate 747 it->second.m_aAlternateFiles.remove( it->second.m_aFile ); 748 it->second.m_aAlternateFiles.remove( files.begin()->first ); 749 it->second.m_aAlternateFiles.push_front( it->second.m_aFile ); 750 // update file 751 it->second.m_aFile = files.begin()->first; 752 } 753 } 754 } 755 else // a new printer, write it to the first file available 756 it->second.m_aFile = files.begin()->first; 757 758 if( ! it->second.m_aGroup.getLength() ) // probably a new printer 759 it->second.m_aGroup = OString( it->first.getStr(), it->first.getLength(), RTL_TEXTENCODING_UTF8 ); 760 761 if( files.find( it->second.m_aFile ) != files.end() ) 762 { 763 Config* pConfig = files[ it->second.m_aFile ]; 764 pConfig->DeleteGroup( it->second.m_aGroup ); // else some old keys may remain 765 pConfig->SetGroup( it->second.m_aGroup ); 766 767 ByteString aValue( String( it->second.m_aInfo.m_aDriverName ), RTL_TEXTENCODING_UTF8 ); 768 aValue += '/'; 769 aValue += ByteString( String( it->first ), RTL_TEXTENCODING_UTF8 ); 770 pConfig->WriteKey( "Printer", aValue ); 771 pConfig->WriteKey( "DefaultPrinter", it->first == m_aDefaultPrinter ? "1" : "0" ); 772 pConfig->WriteKey( "Location", ByteString( String( it->second.m_aInfo.m_aLocation ), RTL_TEXTENCODING_UTF8 ) ); 773 pConfig->WriteKey( "Comment", ByteString( String( it->second.m_aInfo.m_aComment ), RTL_TEXTENCODING_UTF8 ) ); 774 pConfig->WriteKey( "Command", ByteString( String( it->second.m_aInfo.m_aCommand ), RTL_TEXTENCODING_UTF8 ) ); 775 pConfig->WriteKey( "QuickCommand", ByteString( String( it->second.m_aInfo.m_aQuickCommand ), RTL_TEXTENCODING_UTF8 ) ); 776 pConfig->WriteKey( "Features", ByteString( String( it->second.m_aInfo.m_aFeatures ), RTL_TEXTENCODING_UTF8 ) ); 777 pConfig->WriteKey( "Copies", ByteString::CreateFromInt32( it->second.m_aInfo.m_nCopies ) ); 778 pConfig->WriteKey( "Orientation", it->second.m_aInfo.m_eOrientation == orientation::Landscape ? "Landscape" : "Portrait" ); 779 pConfig->WriteKey( "PSLevel", ByteString::CreateFromInt32( it->second.m_aInfo.m_nPSLevel ) ); 780 pConfig->WriteKey( "PDFDevice", ByteString::CreateFromInt32( it->second.m_aInfo.m_nPDFDevice ) ); 781 pConfig->WriteKey( "ColorDevice", ByteString::CreateFromInt32( it->second.m_aInfo.m_nColorDevice ) ); 782 pConfig->WriteKey( "ColorDepth", ByteString::CreateFromInt32( it->second.m_aInfo.m_nColorDepth ) ); 783 aValue = ByteString::CreateFromInt32( it->second.m_aInfo.m_nLeftMarginAdjust ); 784 aValue += ','; 785 aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nRightMarginAdjust ); 786 aValue += ','; 787 aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nTopMarginAdjust ); 788 aValue += ','; 789 aValue += ByteString::CreateFromInt32( it->second.m_aInfo.m_nBottomMarginAdjust ); 790 pConfig->WriteKey( "MarginAdjust", aValue ); 791 792 if( it->second.m_aInfo.m_aDriverName.compareToAscii( "CUPS:", 5 ) != 0 ) 793 { 794 // write PPDContext (not for CUPS) 795 for( int i = 0; i < it->second.m_aInfo.m_aContext.countValuesModified(); i++ ) 796 { 797 const PPDKey* pKey = it->second.m_aInfo.m_aContext.getModifiedKey( i ); 798 ByteString aKey( "PPD_" ); 799 aKey += ByteString( pKey->getKey(), RTL_TEXTENCODING_ISO_8859_1 ); 800 801 const PPDValue* pValue = it->second.m_aInfo.m_aContext.getValue( pKey ); 802 aValue = pValue ? ByteString( pValue->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ) : ByteString( "*nil" ); 803 pConfig->WriteKey( aKey, aValue ); 804 } 805 } 806 807 // write font substitution table 808 pConfig->WriteKey( "PerformFontSubstitution", it->second.m_aInfo.m_bPerformFontSubstitution ? "true" : "false" ); 809 for( ::std::hash_map< OUString, OUString, OUStringHash >::const_iterator subst = it->second.m_aInfo.m_aFontSubstitutes.begin(); 810 subst != it->second.m_aInfo.m_aFontSubstitutes.end(); ++subst ) 811 { 812 ByteString aKey( "SubstFont_" ); 813 aKey.Append( OUStringToOString( subst->first, RTL_TEXTENCODING_ISO_8859_1 ).getStr() ); 814 pConfig->WriteKey( aKey, OUStringToOString( subst->second, RTL_TEXTENCODING_ISO_8859_1 ) ); 815 } 816 } 817 } 818 819 // get rid of Config objects. this also writes any changes 820 for( file_it = files.begin(); file_it != files.end(); ++file_it ) 821 delete file_it->second; 822 823 return true; 824 } 825 826 // ----------------------------------------------------------------- 827 828 bool PrinterInfoManager::addPrinter( const OUString& rPrinterName, const OUString& rDriverName ) 829 { 830 bool bSuccess = false; 831 832 const PPDParser* pParser = NULL; 833 if( m_aPrinters.find( rPrinterName ) == m_aPrinters.end() && ( pParser = PPDParser::getParser( rDriverName ) ) ) 834 { 835 Printer aPrinter; 836 aPrinter.m_bModified = true; 837 aPrinter.m_aInfo = m_aGlobalDefaults; 838 aPrinter.m_aInfo.m_aDriverName = rDriverName; 839 aPrinter.m_aInfo.m_pParser = pParser; 840 aPrinter.m_aInfo.m_aContext.setParser( pParser ); 841 aPrinter.m_aInfo.m_aPrinterName = rPrinterName; 842 843 fillFontSubstitutions( aPrinter.m_aInfo ); 844 // merge PPD values with global defaults 845 for( int nPPDValueModified = 0; nPPDValueModified < m_aGlobalDefaults.m_aContext.countValuesModified(); nPPDValueModified++ ) 846 { 847 const PPDKey* pDefKey = m_aGlobalDefaults.m_aContext.getModifiedKey( nPPDValueModified ); 848 const PPDValue* pDefValue = m_aGlobalDefaults.m_aContext.getValue( pDefKey ); 849 const PPDKey* pPrinterKey = pDefKey ? aPrinter.m_aInfo.m_pParser->getKey( pDefKey->getKey() ) : NULL; 850 if( pDefKey && pPrinterKey ) 851 // at least the options exist in both PPDs 852 { 853 if( pDefValue ) 854 { 855 const PPDValue* pPrinterValue = pPrinterKey->getValue( pDefValue->m_aOption ); 856 if( pPrinterValue ) 857 // the printer has a corresponding option for the key 858 aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, pPrinterValue ); 859 } 860 else 861 aPrinter.m_aInfo.m_aContext.setValue( pPrinterKey, NULL ); 862 } 863 } 864 865 m_aPrinters[ rPrinterName ] = aPrinter; 866 bSuccess = true; 867 #if OSL_DEBUG_LEVEL > 1 868 fprintf( stderr, "new printer %s, level = %d, pdfdevice = %d, colordevice = %d, depth = %d\n", 869 OUStringToOString( rPrinterName, osl_getThreadTextEncoding() ).getStr(), 870 m_aPrinters[rPrinterName].m_aInfo.m_nPSLevel, 871 m_aPrinters[rPrinterName].m_aInfo.m_nPDFDevice, 872 m_aPrinters[rPrinterName].m_aInfo.m_nColorDevice, 873 m_aPrinters[rPrinterName].m_aInfo.m_nColorDepth ); 874 #endif 875 // comment: logically one should writePrinterConfig() here 876 // but immediately after addPrinter() a changePrinterInfo() 877 // will follow (see padmin code), which writes it again, 878 // so we can currently save some performance here 879 } 880 return bSuccess; 881 } 882 883 // ----------------------------------------------------------------- 884 885 bool PrinterInfoManager::removePrinter( const OUString& rPrinterName, bool bCheckOnly ) 886 { 887 bool bSuccess = true; 888 889 ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName ); 890 if( it != m_aPrinters.end() ) 891 { 892 if( it->second.m_aFile.getLength() ) 893 { 894 // this printer already exists in a config file 895 896 897 // check writeability of config file(s) 898 if( ! checkWriteability( it->second.m_aFile ) ) 899 bSuccess = false; 900 else 901 { 902 for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin(); 903 file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it ) 904 { 905 if( ! checkWriteability( *file_it ) ) 906 bSuccess = false; 907 } 908 } 909 if( bSuccess && ! bCheckOnly ) 910 { 911 912 Config aConfig( it->second.m_aFile ); 913 aConfig.DeleteGroup( it->second.m_aGroup ); 914 aConfig.Flush(); 915 for( std::list< OUString >::const_iterator file_it = it->second.m_aAlternateFiles.begin(); 916 file_it != it->second.m_aAlternateFiles.end() && bSuccess; ++file_it ) 917 { 918 Config aAltConfig( *file_it ); 919 aAltConfig.DeleteGroup( it->second.m_aGroup ); 920 aAltConfig.Flush(); 921 } 922 } 923 } 924 if( bSuccess && ! bCheckOnly ) 925 { 926 m_aPrinters.erase( it ); 927 // need this here because someone may call 928 // checkPrintersChanged after the removal 929 // but then other added printers were not flushed 930 // to disk, so they are discarded 931 writePrinterConfig(); 932 } 933 } 934 return bSuccess; 935 } 936 937 // ----------------------------------------------------------------- 938 939 bool PrinterInfoManager::setDefaultPrinter( const OUString& rPrinterName ) 940 { 941 bool bSuccess = false; 942 943 ::std::hash_map< OUString, Printer, OUStringHash >::iterator it = m_aPrinters.find( rPrinterName ); 944 if( it != m_aPrinters.end() ) 945 { 946 bSuccess = true; 947 it->second.m_bModified = true; 948 if( ( it = m_aPrinters.find( m_aDefaultPrinter ) ) != m_aPrinters.end() ) 949 it->second.m_bModified = true; 950 m_aDefaultPrinter = rPrinterName; 951 writePrinterConfig(); 952 } 953 return bSuccess; 954 } 955 956 // ----------------------------------------------------------------- 957 bool PrinterInfoManager::addOrRemovePossible() const 958 { 959 return true; 960 } 961 962 // ----------------------------------------------------------------- 963 964 void PrinterInfoManager::fillFontSubstitutions( PrinterInfo& rInfo ) const 965 { 966 PrintFontManager& rFontManager( PrintFontManager::get() ); 967 rInfo.m_aFontSubstitutions.clear(); 968 969 if( ! rInfo.m_bPerformFontSubstitution || 970 ! rInfo.m_aFontSubstitutes.size() ) 971 return; 972 973 ::std::list< FastPrintFontInfo > aFonts; 974 ::std::hash_map< OUString, ::std::list< FastPrintFontInfo >, OUStringHash > aPrinterFonts; 975 rFontManager.getFontListWithFastInfo( aFonts, rInfo.m_pParser ); 976 977 // get builtin fonts 978 ::std::list< FastPrintFontInfo >::const_iterator it; 979 for( it = aFonts.begin(); it != aFonts.end(); ++it ) 980 if( it->m_eType == fonttype::Builtin ) 981 aPrinterFonts[ it->m_aFamilyName.toAsciiLowerCase() ].push_back( *it ); 982 983 // map lower case, so build a local copy of the font substitutions 984 ::std::hash_map< OUString, OUString, OUStringHash > aSubstitutions; 985 ::std::hash_map< OUString, OUString, OUStringHash >::const_iterator subst; 986 for( subst = rInfo.m_aFontSubstitutes.begin(); subst != rInfo.m_aFontSubstitutes.end(); ++subst ) 987 { 988 OUString aFamily( subst->first.toAsciiLowerCase() ); 989 // first look if there is a builtin of this family 990 // in this case override the substitution table 991 if( aPrinterFonts.find( aFamily ) != aPrinterFonts.end() ) 992 aSubstitutions[ aFamily ] = aFamily; 993 else 994 aSubstitutions[ aFamily ] = subst->second.toAsciiLowerCase(); 995 } 996 997 998 // now find substitutions 999 for( it = aFonts.begin(); it != aFonts.end(); ++it ) 1000 { 1001 if( it->m_eType != fonttype::Builtin ) 1002 { 1003 OUString aFamily( it->m_aFamilyName.toAsciiLowerCase() ); 1004 subst = aSubstitutions.find( aFamily ); 1005 if( subst != aSubstitutions.end() ) 1006 { 1007 // search a substitution 1008 const ::std::list< FastPrintFontInfo >& rBuiltins( aPrinterFonts[ aSubstitutions[ aFamily ] ] ); 1009 ::std::list< FastPrintFontInfo >::const_iterator builtin; 1010 int nLastMatch = -10000; 1011 fontID nSubstitute = -1; 1012 for( builtin = rBuiltins.begin(); builtin != rBuiltins.end(); ++builtin ) 1013 { 1014 int nMatch = 0; 1015 int nDiff; 1016 if( builtin->m_eItalic == it->m_eItalic ) 1017 nMatch += 8000; 1018 1019 nDiff = builtin->m_eWeight - it->m_eWeight; 1020 nDiff = nDiff < 0 ? -nDiff : nDiff; 1021 nMatch += 4000 - 1000*nDiff; 1022 1023 nDiff = builtin->m_eWidth - it->m_eWidth; 1024 nDiff = nDiff < 0 ? -nDiff : nDiff; 1025 nMatch += 2000 - 500*nDiff; 1026 1027 if( nMatch > nLastMatch ) 1028 { 1029 nLastMatch = nMatch; 1030 nSubstitute = builtin->m_nID; 1031 } 1032 } 1033 if( nSubstitute != -1 ) 1034 { 1035 rInfo.m_aFontSubstitutions[ it->m_nID ] = nSubstitute; 1036 #if OSL_DEBUG_LEVEL > 2 1037 FastPrintFontInfo aInfo; 1038 rFontManager.getFontFastInfo( nSubstitute, aInfo ); 1039 fprintf( stderr, 1040 "substitute %s %s %d %d\n" 1041 " -> %s %s %d %d\n", 1042 OUStringToOString( it->m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr(), 1043 it->m_eItalic == italic::Upright ? "r" : it->m_eItalic == italic::Oblique ? "o" : it->m_eItalic == italic::Italic ? "i" : "u", 1044 it->m_eWeight, 1045 it->m_eWidth, 1046 1047 OUStringToOString( aInfo.m_aFamilyName, RTL_TEXTENCODING_ISO_8859_1 ).getStr(), 1048 aInfo.m_eItalic == italic::Upright ? "r" : aInfo.m_eItalic == italic::Oblique ? "o" : aInfo.m_eItalic == italic::Italic ? "i" : "u", 1049 aInfo.m_eWeight, 1050 aInfo.m_eWidth 1051 ); 1052 #endif 1053 } 1054 } 1055 } 1056 } 1057 } 1058 1059 // ----------------------------------------------------------------- 1060 1061 void PrinterInfoManager::getSystemPrintCommands( std::list< OUString >& rCommands ) 1062 { 1063 if( m_pQueueInfo && m_pQueueInfo->hasChanged() ) 1064 { 1065 m_aSystemPrintCommand = m_pQueueInfo->getCommand(); 1066 m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues ); 1067 delete m_pQueueInfo, m_pQueueInfo = NULL; 1068 } 1069 1070 std::list< SystemPrintQueue >::const_iterator it; 1071 rCommands.clear(); 1072 String aPrinterConst( RTL_CONSTASCII_USTRINGPARAM( "(PRINTER)" ) ); 1073 for( it = m_aSystemPrintQueues.begin(); it != m_aSystemPrintQueues.end(); ++it ) 1074 { 1075 String aCmd( m_aSystemPrintCommand ); 1076 aCmd.SearchAndReplace( aPrinterConst, it->m_aQueue ); 1077 rCommands.push_back( aCmd ); 1078 } 1079 } 1080 1081 const std::list< PrinterInfoManager::SystemPrintQueue >& PrinterInfoManager::getSystemPrintQueues() 1082 { 1083 if( m_pQueueInfo && m_pQueueInfo->hasChanged() ) 1084 { 1085 m_aSystemPrintCommand = m_pQueueInfo->getCommand(); 1086 m_pQueueInfo->getSystemQueues( m_aSystemPrintQueues ); 1087 delete m_pQueueInfo, m_pQueueInfo = NULL; 1088 } 1089 1090 return m_aSystemPrintQueues; 1091 } 1092 1093 bool PrinterInfoManager::checkFeatureToken( const rtl::OUString& rPrinterName, const char* pToken ) const 1094 { 1095 const PrinterInfo& rPrinterInfo( getPrinterInfo( rPrinterName ) ); 1096 sal_Int32 nIndex = 0; 1097 while( nIndex != -1 ) 1098 { 1099 OUString aOuterToken = rPrinterInfo.m_aFeatures.getToken( 0, ',', nIndex ); 1100 sal_Int32 nInnerIndex = 0; 1101 OUString aInnerToken = aOuterToken.getToken( 0, '=', nInnerIndex ); 1102 if( aInnerToken.equalsIgnoreAsciiCaseAscii( pToken ) ) 1103 return true; 1104 } 1105 return false; 1106 } 1107 1108 FILE* PrinterInfoManager::startSpool( const OUString& rPrintername, bool bQuickCommand ) 1109 { 1110 const PrinterInfo& rPrinterInfo = getPrinterInfo (rPrintername); 1111 const rtl::OUString& rCommand = (bQuickCommand && rPrinterInfo.m_aQuickCommand.getLength() ) ? 1112 rPrinterInfo.m_aQuickCommand : rPrinterInfo.m_aCommand; 1113 rtl::OString aShellCommand = OUStringToOString (rCommand, RTL_TEXTENCODING_ISO_8859_1); 1114 aShellCommand += rtl::OString( " 2>/dev/null" ); 1115 1116 return popen (aShellCommand.getStr(), "w"); 1117 } 1118 1119 int PrinterInfoManager::endSpool( const OUString& /*rPrintername*/, const OUString& /*rJobTitle*/, FILE* pFile, const JobData& /*rDocumentJobData*/, bool /*bBanner*/ ) 1120 { 1121 return (0 == pclose( pFile )); 1122 } 1123 1124 void PrinterInfoManager::setupJobContextData( JobData& rData ) 1125 { 1126 std::hash_map< OUString, Printer, OUStringHash >::iterator it = 1127 m_aPrinters.find( rData.m_aPrinterName ); 1128 if( it != m_aPrinters.end() ) 1129 { 1130 rData.m_pParser = it->second.m_aInfo.m_pParser; 1131 rData.m_aContext = it->second.m_aInfo.m_aContext; 1132 } 1133 } 1134 1135 void PrinterInfoManager::setDefaultPaper( PPDContext& rContext ) const 1136 { 1137 if( ! rContext.getParser() ) 1138 return; 1139 1140 const PPDKey* pPageSizeKey = rContext.getParser()->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) ); 1141 if( ! pPageSizeKey ) 1142 return; 1143 1144 int nModified = rContext.countValuesModified(); 1145 while( nModified-- && 1146 rContext.getModifiedKey( nModified ) != pPageSizeKey ) 1147 ; 1148 1149 if( nModified >= 0 ) // paper was set already, do not modify 1150 { 1151 #if OSL_DEBUG_LEVEL > 1 1152 fprintf( stderr, "not setting default paper, already set %s\n", 1153 OUStringToOString( rContext.getValue( pPageSizeKey )->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() ); 1154 #endif 1155 return; 1156 } 1157 1158 // paper not set, fill in default value 1159 const PPDValue* pPaperVal = NULL; 1160 int nValues = pPageSizeKey->countValues(); 1161 for( int i = 0; i < nValues && ! pPaperVal; i++ ) 1162 { 1163 const PPDValue* pVal = pPageSizeKey->getValue( i ); 1164 if( pVal->m_aOption.EqualsIgnoreCaseAscii( m_aSystemDefaultPaper.getStr() ) ) 1165 pPaperVal = pVal; 1166 } 1167 if( pPaperVal ) 1168 { 1169 #if OSL_DEBUG_LEVEL > 1 1170 fprintf( stderr, "setting default paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() ); 1171 #endif 1172 rContext.setValue( pPageSizeKey, pPaperVal ); 1173 #if OSL_DEBUG_LEVEL > 1 1174 pPaperVal = rContext.getValue( pPageSizeKey ); 1175 fprintf( stderr, "-> got paper %s\n", OUStringToOString( pPaperVal->m_aOption, RTL_TEXTENCODING_ISO_8859_1 ).getStr() ); 1176 #endif 1177 } 1178 } 1179 1180 // ----------------------------------------------------------------- 1181 1182 SystemQueueInfo::SystemQueueInfo() : 1183 m_bChanged( false ) 1184 { 1185 create(); 1186 } 1187 1188 SystemQueueInfo::~SystemQueueInfo() 1189 { 1190 static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" ); 1191 if( ! pNoSyncDetection || !*pNoSyncDetection ) 1192 join(); 1193 else 1194 terminate(); 1195 } 1196 1197 bool SystemQueueInfo::hasChanged() const 1198 { 1199 MutexGuard aGuard( m_aMutex ); 1200 bool bChanged = m_bChanged; 1201 return bChanged; 1202 } 1203 1204 void SystemQueueInfo::getSystemQueues( std::list< PrinterInfoManager::SystemPrintQueue >& rQueues ) 1205 { 1206 MutexGuard aGuard( m_aMutex ); 1207 rQueues = m_aQueues; 1208 m_bChanged = false; 1209 } 1210 1211 OUString SystemQueueInfo::getCommand() const 1212 { 1213 MutexGuard aGuard( m_aMutex ); 1214 OUString aRet = m_aCommand; 1215 return aRet; 1216 } 1217 1218 struct SystemCommandParameters; 1219 typedef void(* tokenHandler)(const std::list< rtl::OString >&, 1220 std::list< PrinterInfoManager::SystemPrintQueue >&, 1221 const SystemCommandParameters*); 1222 1223 struct SystemCommandParameters 1224 { 1225 const char* pQueueCommand; 1226 const char* pPrintCommand; 1227 const char* pForeToken; 1228 const char* pAftToken; 1229 unsigned int nForeTokenCount; 1230 tokenHandler pHandler; 1231 }; 1232 1233 #if ! (defined(LINUX) || defined(NETBSD) || defined(FREEBSD)) 1234 static void lpgetSysQueueTokenHandler( 1235 const std::list< rtl::OString >& i_rLines, 1236 std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues, 1237 const SystemCommandParameters* ) 1238 { 1239 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); 1240 std::hash_set< OUString, OUStringHash > aUniqueSet; 1241 std::hash_set< OUString, OUStringHash > aOnlySet; 1242 aUniqueSet.insert( OUString( RTL_CONSTASCII_USTRINGPARAM( "_all" ) ) ); 1243 aUniqueSet.insert( OUString( RTL_CONSTASCII_USTRINGPARAM( "_default" ) ) ); 1244 1245 // the eventual "all" attribute of the "_all" queue tells us, which 1246 // printers are to be used for this user at all 1247 1248 // find _all: line 1249 rtl::OString aAllLine( "_all:" ); 1250 rtl::OString aAllAttr( "all=" ); 1251 for( std::list< rtl::OString >::const_iterator it = i_rLines.begin(); 1252 it != i_rLines.end(); ++it ) 1253 { 1254 if( it->indexOf( aAllLine, 0 ) == 0 ) 1255 { 1256 // now find the "all" attribute 1257 ++it; 1258 while( it != i_rLines.end() ) 1259 { 1260 rtl::OString aClean( WhitespaceToSpace( *it ) ); 1261 if( aClean.indexOf( aAllAttr, 0 ) == 0 ) 1262 { 1263 // insert the comma separated entries into the set of printers to use 1264 sal_Int32 nPos = aAllAttr.getLength(); 1265 while( nPos != -1 ) 1266 { 1267 OString aTok( aClean.getToken( 0, ',', nPos ) ); 1268 if( aTok.getLength() > 0 ) 1269 aOnlySet.insert( rtl::OStringToOUString( aTok, aEncoding ) ); 1270 } 1271 break; 1272 } 1273 } 1274 break; 1275 } 1276 } 1277 1278 bool bInsertAttribute = false; 1279 rtl::OString aDescrStr( "description=" ); 1280 rtl::OString aLocStr( "location=" ); 1281 for( std::list< rtl::OString >::const_iterator it = i_rLines.begin(); 1282 it != i_rLines.end(); ++it ) 1283 { 1284 sal_Int32 nPos = 0; 1285 // find the begin of a new printer section 1286 nPos = it->indexOf( ':', 0 ); 1287 if( nPos != -1 ) 1288 { 1289 OUString aSysQueue( rtl::OStringToOUString( it->copy( 0, nPos ), aEncoding ) ); 1290 // do not insert duplicates (e.g. lpstat tends to produce such lines) 1291 // in case there was a "_all" section, insert only those printer explicitly 1292 // set in the "all" attribute 1293 if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() && 1294 ( aOnlySet.empty() || aOnlySet.find( aSysQueue ) != aOnlySet.end() ) 1295 ) 1296 { 1297 o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() ); 1298 o_rQueues.back().m_aQueue = aSysQueue; 1299 o_rQueues.back().m_aLocation = aSysQueue; 1300 aUniqueSet.insert( aSysQueue ); 1301 bInsertAttribute = true; 1302 } 1303 else 1304 bInsertAttribute = false; 1305 continue; 1306 } 1307 if( bInsertAttribute && ! o_rQueues.empty() ) 1308 { 1309 // look for "description" attribute, insert as comment 1310 nPos = it->indexOf( aDescrStr, 0 ); 1311 if( nPos != -1 ) 1312 { 1313 ByteString aComment( WhitespaceToSpace( it->copy(nPos+12) ) ); 1314 if( aComment.Len() > 0 ) 1315 o_rQueues.back().m_aComment = String( aComment, aEncoding ); 1316 continue; 1317 } 1318 // look for "location" attribute, inser as location 1319 nPos = it->indexOf( aLocStr, 0 ); 1320 if( nPos != -1 ) 1321 { 1322 ByteString aLoc( WhitespaceToSpace( it->copy(nPos+9) ) ); 1323 if( aLoc.Len() > 0 ) 1324 o_rQueues.back().m_aLocation = String( aLoc, aEncoding ); 1325 continue; 1326 } 1327 } 1328 } 1329 } 1330 #endif 1331 static void standardSysQueueTokenHandler( 1332 const std::list< rtl::OString >& i_rLines, 1333 std::list< PrinterInfoManager::SystemPrintQueue >& o_rQueues, 1334 const SystemCommandParameters* i_pParms) 1335 { 1336 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); 1337 std::hash_set< OUString, OUStringHash > aUniqueSet; 1338 rtl::OString aForeToken( i_pParms->pForeToken ); 1339 rtl::OString aAftToken( i_pParms->pAftToken ); 1340 /* Normal Unix print queue discovery, also used for Darwin 5 LPR printing 1341 */ 1342 for( std::list< rtl::OString >::const_iterator it = i_rLines.begin(); 1343 it != i_rLines.end(); ++it ) 1344 { 1345 sal_Int32 nPos = 0; 1346 1347 // search for a line describing a printer: 1348 // find if there are enough tokens before the name 1349 for( unsigned int i = 0; i < i_pParms->nForeTokenCount && nPos != -1; i++ ) 1350 { 1351 nPos = it->indexOf( aForeToken, nPos ); 1352 if( nPos != -1 && it->getLength() >= nPos+aForeToken.getLength() ) 1353 nPos += aForeToken.getLength(); 1354 } 1355 if( nPos != -1 ) 1356 { 1357 // find if there is the token after the queue 1358 sal_Int32 nAftPos = it->indexOf( aAftToken, nPos ); 1359 if( nAftPos != -1 ) 1360 { 1361 // get the queue name between fore and aft tokens 1362 OUString aSysQueue( rtl::OStringToOUString( it->copy( nPos, nAftPos - nPos ), aEncoding ) ); 1363 // do not insert duplicates (e.g. lpstat tends to produce such lines) 1364 if( aUniqueSet.find( aSysQueue ) == aUniqueSet.end() ) 1365 { 1366 o_rQueues.push_back( PrinterInfoManager::SystemPrintQueue() ); 1367 o_rQueues.back().m_aQueue = aSysQueue; 1368 o_rQueues.back().m_aLocation = aSysQueue; 1369 aUniqueSet.insert( aSysQueue ); 1370 } 1371 } 1372 } 1373 } 1374 } 1375 1376 static const struct SystemCommandParameters aParms[] = 1377 { 1378 #if defined(LINUX) || defined(NETBSD) || defined(FREEBSD) 1379 { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler }, 1380 { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler }, 1381 { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler } 1382 #else 1383 { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpget list", "lp -d \"(PRINTER)\"", "", ":", 0, lpgetSysQueueTokenHandler }, 1384 { "LANG=C;LC_ALL=C;export LANG LC_ALL;lpstat -s", "lp -d \"(PRINTER)\"", "system for ", ": ", 1, standardSysQueueTokenHandler }, 1385 { "/usr/sbin/lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler }, 1386 { "lpc status", "lpr -P \"(PRINTER)\"", "", ":", 0, standardSysQueueTokenHandler } 1387 #endif 1388 }; 1389 1390 void SystemQueueInfo::run() 1391 { 1392 char pBuffer[1024]; 1393 FILE *pPipe; 1394 std::list< rtl::OString > aLines; 1395 1396 /* Discover which command we can use to get a list of all printer queues */ 1397 for( unsigned int i = 0; i < sizeof(aParms)/sizeof(aParms[0]); i++ ) 1398 { 1399 aLines.clear(); 1400 rtl::OStringBuffer aCmdLine( 128 ); 1401 aCmdLine.append( aParms[i].pQueueCommand ); 1402 #if OSL_DEBUG_LEVEL > 1 1403 fprintf( stderr, "trying print queue command \"%s\" ... ", aParms[i].pQueueCommand ); 1404 #endif 1405 aCmdLine.append( " 2>/dev/null" ); 1406 if( (pPipe = popen( aCmdLine.getStr(), "r" )) ) 1407 { 1408 while( fgets( pBuffer, 1024, pPipe ) ) 1409 aLines.push_back( rtl::OString( pBuffer ) ); 1410 if( ! pclose( pPipe ) ) 1411 { 1412 std::list< PrinterInfoManager::SystemPrintQueue > aSysPrintQueues; 1413 aParms[i].pHandler( aLines, aSysPrintQueues, &(aParms[i]) ); 1414 MutexGuard aGuard( m_aMutex ); 1415 m_bChanged = true; 1416 m_aQueues = aSysPrintQueues; 1417 m_aCommand = rtl::OUString::createFromAscii( aParms[i].pPrintCommand ); 1418 #if OSL_DEBUG_LEVEL > 1 1419 fprintf( stderr, "success\n" ); 1420 #endif 1421 break; 1422 } 1423 } 1424 #if OSL_DEBUG_LEVEL > 1 1425 fprintf( stderr, "failed\n" ); 1426 #endif 1427 } 1428 } 1429 1430