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