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