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