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
get()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
release()110 void PrinterInfoManager::release()
111 {
112 SalData* pSalData = GetSalData();
113 delete pSalData->m_pPIManager;
114 pSalData->m_pPIManager = NULL;
115 }
116
117 // -----------------------------------------------------------------
118
PrinterInfoManager(Type eType)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
~PrinterInfoManager()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
isCUPSDisabled() const144 bool PrinterInfoManager::isCUPSDisabled() const
145 {
146 return m_bDisableCUPS;
147 }
148
149 // -----------------------------------------------------------------
150
setCUPSDisabled(bool bDisable)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
initSystemDefaultPaper()162 void PrinterInfoManager::initSystemDefaultPaper()
163 {
164 m_aSystemDefaultPaper = rtl::OStringToOUString(
165 PaperInfo::toPSName(PaperInfo::getSystemDefaultPaper().getPaper()),
166 RTL_TEXTENCODING_UTF8);
167 }
168
169 // -----------------------------------------------------------------
170
checkPrintersChanged(bool bWait)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
initialize()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
listPrinters(::std::list<OUString> & rList) const627 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
getPrinterInfo(const OUString & rPrinter) const637 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
changePrinterInfo(const OUString & rPrinter,const PrinterInfo & rNewInfo)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
checkWriteability(const OUString & rUniPath)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
writePrinterConfig()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
addPrinter(const OUString & rPrinterName,const OUString & rDriverName)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
removePrinter(const OUString & rPrinterName,bool bCheckOnly)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
setDefaultPrinter(const OUString & rPrinterName)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 // -----------------------------------------------------------------
addOrRemovePossible() const953 bool PrinterInfoManager::addOrRemovePossible() const
954 {
955 return true;
956 }
957
958 // -----------------------------------------------------------------
959
fillFontSubstitutions(PrinterInfo & rInfo) const960 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
getSystemPrintCommands(std::list<OUString> & rCommands)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
getSystemPrintQueues()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
checkFeatureToken(const rtl::OUString & rPrinterName,const char * pToken) const1089 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
startSpool(const OUString & rPrintername,bool bQuickCommand)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
endSpool(const OUString &,const OUString &,FILE * pFile,const JobData &,bool)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
setupJobContextData(JobData & rData)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
setDefaultPaper(PPDContext & rContext) const1131 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
SystemQueueInfo()1178 SystemQueueInfo::SystemQueueInfo() :
1179 m_bChanged( false )
1180 {
1181 create();
1182 }
1183
~SystemQueueInfo()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
hasChanged() const1193 bool SystemQueueInfo::hasChanged() const
1194 {
1195 MutexGuard aGuard( m_aMutex );
1196 bool bChanged = m_bChanged;
1197 return bChanged;
1198 }
1199
getSystemQueues(std::list<PrinterInfoManager::SystemPrintQueue> & rQueues)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
getCommand() const1207 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))
lpgetSysQueueTokenHandler(const std::list<rtl::OString> & i_rLines,std::list<PrinterInfoManager::SystemPrintQueue> & o_rQueues,const SystemCommandParameters *)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
standardSysQueueTokenHandler(const std::list<rtl::OString> & i_rLines,std::list<PrinterInfoManager::SystemPrintQueue> & o_rQueues,const SystemCommandParameters * i_pParms)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
run()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