1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26
27 #include <unistd.h>
28 #include <sys/stat.h>
29 #include <sys/wait.h>
30
31 #include "vcl/svapp.hxx"
32 #include "vcl/timer.hxx"
33 #include "vcl/printerinfomanager.hxx"
34
35 #include "jobset.h"
36 #include "print.h"
37 #include "salptype.hxx"
38
39 #include "svpprn.hxx"
40 #include "svppspgraphics.hxx"
41 #include "svpinst.hxx"
42
43 using namespace psp;
44 using namespace rtl;
45
46 /*
47 * static helpers
48 */
49
getPdfDir(const PrinterInfo & rInfo)50 static String getPdfDir( const PrinterInfo& rInfo )
51 {
52 String aDir;
53 sal_Int32 nIndex = 0;
54 while( nIndex != -1 )
55 {
56 OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
57 if( ! aToken.compareToAscii( "pdf=", 4 ) )
58 {
59 sal_Int32 nPos = 0;
60 aDir = aToken.getToken( 1, '=', nPos );
61 if( ! aDir.Len() )
62 aDir = String( ByteString( getenv( "HOME" ) ), osl_getThreadTextEncoding() );
63 break;
64 }
65 }
66 return aDir;
67 }
68
PtTo10Mu(int nPoints)69 inline int PtTo10Mu( int nPoints ) { return (int)((((double)nPoints)*35.27777778)+0.5); }
70
TenMuToPt(int nUnits)71 inline int TenMuToPt( int nUnits ) { return (int)((((double)nUnits)/35.27777778)+0.5); }
72
copyJobDataToJobSetup(ImplJobSetup * pJobSetup,JobData & rData)73 static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData )
74 {
75 pJobSetup->meOrientation = (Orientation)(rData.m_eOrientation == orientation::Landscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT);
76
77 // copy page size
78 String aPaper;
79 int width, height;
80
81 rData.m_aContext.getPageSize( aPaper, width, height );
82 pJobSetup->mePaperFormat = PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 ));
83 pJobSetup->mnPaperWidth = 0;
84 pJobSetup->mnPaperHeight = 0;
85 if( pJobSetup->mePaperFormat == PAPER_USER )
86 {
87 // transform to 100dth mm
88 width = PtTo10Mu( width );
89 height = PtTo10Mu( height );
90
91 if( rData.m_eOrientation == psp::orientation::Portrait )
92 {
93 pJobSetup->mnPaperWidth = width;
94 pJobSetup->mnPaperHeight= height;
95 }
96 else
97 {
98 pJobSetup->mnPaperWidth = height;
99 pJobSetup->mnPaperHeight= width;
100 }
101 }
102
103 // copy input slot
104 const PPDKey* pKey = NULL;
105 const PPDValue* pValue = NULL;
106
107 pJobSetup->mnPaperBin = 0xffff;
108 if( rData.m_pParser )
109 pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
110 if( pKey )
111 pValue = rData.m_aContext.getValue( pKey );
112 if( pKey && pValue )
113 {
114 for( pJobSetup->mnPaperBin = 0;
115 pValue != pKey->getValue( pJobSetup->mnPaperBin ) &&
116 pJobSetup->mnPaperBin < pKey->countValues();
117 pJobSetup->mnPaperBin++ )
118 ;
119 if( pJobSetup->mnPaperBin >= pKey->countValues() || pValue == pKey->getDefaultValue() )
120 pJobSetup->mnPaperBin = 0xffff;
121 }
122
123 // copy duplex
124 pKey = NULL;
125 pValue = NULL;
126
127 pJobSetup->meDuplexMode = DUPLEX_UNKNOWN;
128 if( rData.m_pParser )
129 pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
130 if( pKey )
131 pValue = rData.m_aContext.getValue( pKey );
132 if( pKey && pValue )
133 {
134 if( pValue->m_aOption.EqualsIgnoreCaseAscii( "None" ) ||
135 pValue->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 )
136 )
137 {
138 pJobSetup->meDuplexMode = DUPLEX_OFF;
139 }
140 else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexNoTumble" ) )
141 {
142 pJobSetup->meDuplexMode = DUPLEX_LONGEDGE;
143 }
144 else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexTumble" ) )
145 {
146 pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE;
147 }
148 }
149
150 // copy the whole context
151 if( pJobSetup->mpDriverData )
152 rtl_freeMemory( pJobSetup->mpDriverData );
153
154 int nBytes;
155 void* pBuffer = NULL;
156 if( rData.getStreamBuffer( pBuffer, nBytes ) )
157 {
158 pJobSetup->mnDriverDataLen = nBytes;
159 pJobSetup->mpDriverData = (sal_uInt8*)pBuffer;
160 }
161 else
162 {
163 pJobSetup->mnDriverDataLen = 0;
164 pJobSetup->mpDriverData = NULL;
165 }
166 }
167
passFileToCommandLine(const String & rFilename,const String & rCommandLine,bool bRemoveFile=true)168 static bool passFileToCommandLine( const String& rFilename, const String& rCommandLine, bool bRemoveFile = true )
169 {
170 bool bSuccess = false;
171
172 rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
173 ByteString aCmdLine( rCommandLine, aEncoding );
174 ByteString aFilename( rFilename, aEncoding );
175
176 bool bPipe = aCmdLine.Search( "(TMP)" ) != STRING_NOTFOUND ? false : true;
177
178 // setup command line for exec
179 if( ! bPipe )
180 while( aCmdLine.SearchAndReplace( "(TMP)", aFilename ) != STRING_NOTFOUND )
181 ;
182
183 #if OSL_DEBUG_LEVEL > 1
184 fprintf( stderr, "%s commandline: \"%s\"\n",
185 bPipe ? "piping to" : "executing",
186 aCmdLine.GetBuffer() );
187 struct stat aStat;
188 if( stat( aFilename.GetBuffer(), &aStat ) )
189 fprintf( stderr, "stat( %s ) failed\n", aFilename.GetBuffer() );
190 fprintf( stderr, "Tmp file %s has modes: 0%03lo\n", aFilename.GetBuffer(), (long)aStat.st_mode );
191 #endif
192 const char* argv[4];
193 if( ! ( argv[ 0 ] = getenv( "SHELL" ) ) )
194 argv[ 0 ] = "/bin/sh";
195 argv[ 1 ] = "-c";
196 argv[ 2 ] = aCmdLine.GetBuffer();
197 argv[ 3 ] = 0;
198
199 bool bHavePipes = false;
200 int pid, fd[2];
201
202 if( bPipe )
203 bHavePipes = pipe( fd ) ? false : true;
204 if( ( pid = fork() ) > 0 )
205 {
206 if( bPipe && bHavePipes )
207 {
208 close( fd[0] );
209 char aBuffer[ 2048 ];
210 FILE* fp = fopen( aFilename.GetBuffer(), "r" );
211 while( fp && ! feof( fp ) )
212 {
213 int nBytes = fread( aBuffer, 1, sizeof( aBuffer ), fp );
214 if( nBytes )
215 write( fd[ 1 ], aBuffer, nBytes );
216 }
217 fclose( fp );
218 close( fd[ 1 ] );
219 }
220 int status = 0;
221 waitpid( pid, &status, 0 );
222 if( ! status )
223 bSuccess = true;
224 }
225 else if( ! pid )
226 {
227 if( bPipe && bHavePipes )
228 {
229 close( fd[1] );
230 if( fd[0] != STDIN_FILENO ) // not probable, but who knows :)
231 dup2( fd[0], STDIN_FILENO );
232 }
233 execv( argv[0], const_cast<char**>(argv) );
234 fprintf( stderr, "failed to execute \"%s\"\n", aCmdLine.GetBuffer() );
235 _exit( 1 );
236 }
237 else
238 fprintf( stderr, "failed to fork\n" );
239
240 // clean up the mess
241 if( bRemoveFile )
242 unlink( aFilename.GetBuffer() );
243
244 return bSuccess;
245 }
246
sendAFax(const String & rFaxNumber,const String & rFileName,const String & rCommand)247 static bool sendAFax( const String& rFaxNumber, const String& rFileName, const String& rCommand )
248 {
249 std::list< OUString > aFaxNumbers;
250
251 if( ! rFaxNumber.Len() )
252 return false;
253
254 sal_Int32 nIndex = 0;
255 OUString aFaxes( rFaxNumber );
256 OUString aBeginToken( RTL_CONSTASCII_USTRINGPARAM("<Fax#>") );
257 OUString aEndToken( RTL_CONSTASCII_USTRINGPARAM("</Fax#>") );
258 while( nIndex != -1 )
259 {
260 nIndex = aFaxes.indexOf( aBeginToken, nIndex );
261 if( nIndex != -1 )
262 {
263 sal_Int32 nBegin = nIndex + aBeginToken.getLength();
264 nIndex = aFaxes.indexOf( aEndToken, nIndex );
265 if( nIndex != -1 )
266 {
267 aFaxNumbers.push_back( aFaxes.copy( nBegin, nIndex-nBegin ) );
268 nIndex += aEndToken.getLength();
269 }
270 }
271 }
272
273 bool bSuccess = true;
274 if( aFaxNumbers.begin() != aFaxNumbers.end() )
275 {
276 while( aFaxNumbers.begin() != aFaxNumbers.end() && bSuccess )
277 {
278 String aCmdLine( rCommand );
279 String aFaxNumber( aFaxNumbers.front() );
280 aFaxNumbers.pop_front();
281 while( aCmdLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PHONE)" ) ), aFaxNumber ) != STRING_NOTFOUND )
282 ;
283 #if OSL_DEBUG_LEVEL > 1
284 fprintf( stderr, "sending fax to \"%s\"\n", OUStringToOString( aFaxNumber, osl_getThreadTextEncoding() ).getStr() );
285 #endif
286 bSuccess = passFileToCommandLine( rFileName, aCmdLine, false );
287 }
288 }
289 else
290 bSuccess = false;
291
292 // clean up temp file
293 unlink( ByteString( rFileName, osl_getThreadTextEncoding() ).GetBuffer() );
294
295 return bSuccess;
296 }
297
createPdf(const String & rToFile,const String & rFromFile,const String & rCommandLine)298 static bool createPdf( const String& rToFile, const String& rFromFile, const String& rCommandLine )
299 {
300 String aCommandLine( rCommandLine );
301 while( aCommandLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(OUTFILE)" ) ), rToFile ) != STRING_NOTFOUND )
302 ;
303 return passFileToCommandLine( rFromFile, aCommandLine );
304 }
305
306 /*
307 * SalInstance
308 */
309
310 // -----------------------------------------------------------------------
311
CreateInfoPrinter(SalPrinterQueueInfo * pQueueInfo,ImplJobSetup * pJobSetup)312 SalInfoPrinter* SvpSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* pQueueInfo,
313 ImplJobSetup* pJobSetup )
314 {
315 // create and initialize SalInfoPrinter
316 PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter;
317
318 if( pJobSetup )
319 {
320 PrinterInfoManager& rManager( PrinterInfoManager::get() );
321 PrinterInfo aInfo( rManager.getPrinterInfo( pQueueInfo->maPrinterName ) );
322 pPrinter->m_aJobData = aInfo;
323 pPrinter->m_aPrinterGfx.Init( pPrinter->m_aJobData );
324
325 if( pJobSetup->mpDriverData )
326 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
327
328 pJobSetup->mnSystem = JOBSETUP_SYSTEM_UNIX;
329 pJobSetup->maPrinterName = pQueueInfo->maPrinterName;
330 pJobSetup->maDriver = aInfo.m_aDriverName;
331 copyJobDataToJobSetup( pJobSetup, aInfo );
332
333 // set/clear backwards compatibility flag
334 bool bStrictSO52Compatibility = false;
335 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
336 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
337 if( compat_it != pJobSetup->maValueMap.end() )
338 {
339 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
340 bStrictSO52Compatibility = true;
341 }
342 pPrinter->m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
343 }
344
345
346 return pPrinter;
347 }
348
349 // -----------------------------------------------------------------------
350
DestroyInfoPrinter(SalInfoPrinter * pPrinter)351 void SvpSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
352 {
353 delete pPrinter;
354 }
355
356 // -----------------------------------------------------------------------
357
CreatePrinter(SalInfoPrinter * pInfoPrinter)358 SalPrinter* SvpSalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
359 {
360 // create and initialize SalPrinter
361 PspSalPrinter* pPrinter = new PspSalPrinter( pInfoPrinter );
362 pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData;
363
364 return pPrinter;
365 }
366
367 // -----------------------------------------------------------------------
368
DestroyPrinter(SalPrinter * pPrinter)369 void SvpSalInstance::DestroyPrinter( SalPrinter* pPrinter )
370 {
371 delete pPrinter;
372 }
373
374 // -----------------------------------------------------------------------
375
GetPrinterQueueInfo(ImplPrnQueueList * pList)376 void SvpSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
377 {
378 PrinterInfoManager& rManager( PrinterInfoManager::get() );
379 static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
380 if( ! pNoSyncDetection || ! *pNoSyncDetection )
381 {
382 // #i62663# synchronize possible asynchronouse printer detection now
383 rManager.checkPrintersChanged( true );
384 }
385 ::std::list< OUString > aPrinters;
386 rManager.listPrinters( aPrinters );
387
388 for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it )
389 {
390 const PrinterInfo& rInfo( rManager.getPrinterInfo( *it ) );
391 // Neuen Eintrag anlegen
392 SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
393 pInfo->maPrinterName = *it;
394 pInfo->maDriver = rInfo.m_aDriverName;
395 pInfo->maLocation = rInfo.m_aLocation;
396 pInfo->maComment = rInfo.m_aComment;
397 pInfo->mpSysData = NULL;
398
399 sal_Int32 nIndex = 0;
400 while( nIndex != -1 )
401 {
402 String aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
403 if( aToken.CompareToAscii( "pdf=", 4 ) == COMPARE_EQUAL )
404 {
405 pInfo->maLocation = getPdfDir( rInfo );
406 break;
407 }
408 }
409
410 pList->Add( pInfo );
411 }
412 }
413
414 // -----------------------------------------------------------------------
415
DeletePrinterQueueInfo(SalPrinterQueueInfo * pInfo)416 void SvpSalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
417 {
418 delete pInfo;
419 }
420
421 // -----------------------------------------------------------------------
422
GetPrinterQueueState(SalPrinterQueueInfo *)423 void SvpSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* )
424 {
425 }
426
427 // -----------------------------------------------------------------------
428
GetDefaultPrinter()429 String SvpSalInstance::GetDefaultPrinter()
430 {
431 PrinterInfoManager& rManager( PrinterInfoManager::get() );
432 return rManager.getDefaultPrinter();
433 }
434
435 // =======================================================================
436
PspSalInfoPrinter()437 PspSalInfoPrinter::PspSalInfoPrinter()
438 {
439 m_pGraphics = NULL;
440 m_bPapersInit = false;
441 }
442
443 // -----------------------------------------------------------------------
444
~PspSalInfoPrinter()445 PspSalInfoPrinter::~PspSalInfoPrinter()
446 {
447 if( m_pGraphics )
448 {
449 delete m_pGraphics;
450 m_pGraphics = NULL;
451 }
452 }
453
454 // -----------------------------------------------------------------------
455
InitPaperFormats(const ImplJobSetup *)456 void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* )
457 {
458 m_aPaperFormats.clear();
459 m_bPapersInit = true;
460
461 if( m_aJobData.m_pParser )
462 {
463 const PPDKey* pKey = m_aJobData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
464 if( pKey )
465 {
466 int nValues = pKey->countValues();
467 for( int i = 0; i < nValues; i++ )
468 {
469 const PPDValue* pValue = pKey->getValue( i );
470 int nWidth = 0, nHeight = 0;
471 m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight );
472 PaperInfo aInfo(PtTo10Mu( nWidth ), PtTo10Mu( nHeight ));
473 m_aPaperFormats.push_back( aInfo );
474 }
475 }
476 }
477 }
478
479 // -----------------------------------------------------------------------
480
GetLandscapeAngle(const ImplJobSetup *)481 int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* )
482 {
483 return 900;
484 }
485
486 // -----------------------------------------------------------------------
487
GetGraphics()488 SalGraphics* PspSalInfoPrinter::GetGraphics()
489 {
490 // return a valid pointer only once
491 // the reasoning behind this is that we could have different
492 // SalGraphics that can run in multiple threads
493 // (future plans)
494 SalGraphics* pRet = NULL;
495 if( ! m_pGraphics )
496 {
497 m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, NULL, false, this );
498 m_pGraphics->SetLayout( 0 );
499 pRet = m_pGraphics;
500 }
501 return pRet;
502 }
503
504 // -----------------------------------------------------------------------
505
ReleaseGraphics(SalGraphics * pGraphics)506 void PspSalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics )
507 {
508 if( pGraphics == m_pGraphics )
509 {
510 delete pGraphics;
511 m_pGraphics = NULL;
512 }
513 return;
514 }
515
516 // -----------------------------------------------------------------------
517
Setup(SalFrame *,ImplJobSetup *)518 sal_Bool PspSalInfoPrinter::Setup( SalFrame*, ImplJobSetup* )
519 {
520 return sal_False;
521 }
522
523 // -----------------------------------------------------------------------
524
525 // This function gets the driver data and puts it into pJobSetup
526 // If pJobSetup->mpDriverData is NOT NULL, then the independend
527 // data should be merged into the driver data
528 // If pJobSetup->mpDriverData IS NULL, then the driver defaults
529 // should be merged into the independent data
SetPrinterData(ImplJobSetup * pJobSetup)530 sal_Bool PspSalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup )
531 {
532 if( pJobSetup->mpDriverData )
533 return SetData( ~0, pJobSetup );
534
535 copyJobDataToJobSetup( pJobSetup, m_aJobData );
536
537 // set/clear backwards compatibility flag
538 bool bStrictSO52Compatibility = false;
539 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
540 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
541 if( compat_it != pJobSetup->maValueMap.end() )
542 {
543 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
544 bStrictSO52Compatibility = true;
545 }
546 m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
547
548 return sal_True;
549 }
550
551 // -----------------------------------------------------------------------
552
553 // This function merges the independ driver data
554 // and sets the new independ data in pJobSetup
555 // Only the data must be changed, where the bit
556 // in nGetDataFlags is set
SetData(sal_uLong nSetDataFlags,ImplJobSetup * pJobSetup)557 sal_Bool PspSalInfoPrinter::SetData(
558 sal_uLong nSetDataFlags,
559 ImplJobSetup* pJobSetup )
560 {
561 JobData aData;
562 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
563
564 if( aData.m_pParser )
565 {
566 const PPDKey* pKey;
567 const PPDValue* pValue;
568
569 // merge papersize if necessary
570 if( nSetDataFlags & SAL_JOBSET_PAPERSIZE )
571 {
572 int nWidth, nHeight;
573 if( pJobSetup->meOrientation == ORIENTATION_PORTRAIT )
574 {
575 nWidth = pJobSetup->mnPaperWidth;
576 nHeight = pJobSetup->mnPaperHeight;
577 }
578 else
579 {
580 nWidth = pJobSetup->mnPaperHeight;
581 nHeight = pJobSetup->mnPaperWidth;
582 }
583 String aPaper;
584
585 if( pJobSetup->mePaperFormat == PAPER_USER )
586 aPaper = aData.m_pParser->matchPaper(
587 TenMuToPt( pJobSetup->mnPaperWidth ),
588 TenMuToPt( pJobSetup->mnPaperHeight ) );
589 else
590 aPaper = rtl::OStringToOUString(PaperInfo::toPSName(pJobSetup->mePaperFormat), RTL_TEXTENCODING_ISO_8859_1);
591
592 pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
593 pValue = pKey ? pKey->getValue( aPaper ) : NULL;
594 if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) )
595 return sal_False;
596 }
597
598 // merge paperbin if necessary
599 if( nSetDataFlags & SAL_JOBSET_PAPERBIN )
600 {
601 pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
602 if( pKey )
603 {
604 int nPaperBin = pJobSetup->mnPaperBin;
605 if( nPaperBin == 0xffff )
606 pValue = pKey->getDefaultValue();
607 else
608 pValue = pKey->getValue( pJobSetup->mnPaperBin );
609
610 // may fail due to constraints;
611 // real paper bin is copied back to jobsetup in that case
612 aData.m_aContext.setValue( pKey, pValue );
613 }
614 // if printer has no InputSlot key simply ignore this setting
615 // (e.g. SGENPRT has no InputSlot)
616 }
617
618 // merge orientation if necessary
619 if( nSetDataFlags & SAL_JOBSET_ORIENTATION )
620 aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait;
621
622 // merge duplex if necessary
623 if( nSetDataFlags & SAL_JOBSET_DUPLEXMODE )
624 {
625 pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
626 if( pKey )
627 {
628 pValue = NULL;
629 switch( pJobSetup->meDuplexMode )
630 {
631 case DUPLEX_OFF:
632 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
633 if( pValue == NULL )
634 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "SimplexNoTumble" ) ) );
635 break;
636 case DUPLEX_SHORTEDGE:
637 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexTumble" ) ) );
638 break;
639 case DUPLEX_LONGEDGE:
640 pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexNoTumble" ) ) );
641 break;
642 case DUPLEX_UNKNOWN:
643 default:
644 pValue = 0;
645 break;
646 }
647 if( ! pValue )
648 pValue = pKey->getDefaultValue();
649 aData.m_aContext.setValue( pKey, pValue );
650 }
651 }
652
653 m_aJobData = aData;
654 copyJobDataToJobSetup( pJobSetup, aData );
655 return sal_True;
656 }
657
658 return sal_False;
659 }
660
661 // -----------------------------------------------------------------------
662
GetPageInfo(const ImplJobSetup * pJobSetup,long & rOutWidth,long & rOutHeight,long & rPageOffX,long & rPageOffY,long & rPageWidth,long & rPageHeight)663 void PspSalInfoPrinter::GetPageInfo(
664 const ImplJobSetup* pJobSetup,
665 long& rOutWidth, long& rOutHeight,
666 long& rPageOffX, long& rPageOffY,
667 long& rPageWidth, long& rPageHeight )
668 {
669 if( ! pJobSetup )
670 return;
671
672 JobData aData;
673 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
674
675 // get the selected page size
676 if( aData.m_pParser )
677 {
678
679 String aPaper;
680 int width, height;
681 int left = 0, top = 0, right = 0, bottom = 0;
682 int nDPI = aData.m_aContext.getRenderResolution();
683
684
685 if( aData.m_eOrientation == psp::orientation::Portrait )
686 {
687 aData.m_aContext.getPageSize( aPaper, width, height );
688 aData.m_pParser->getMargins( aPaper, left, right, top, bottom );
689 }
690 else
691 {
692 aData.m_aContext.getPageSize( aPaper, height, width );
693 aData.m_pParser->getMargins( aPaper, top, bottom, right, left );
694 }
695
696 rPageWidth = width * nDPI / 72;
697 rPageHeight = height * nDPI / 72;
698 rPageOffX = left * nDPI / 72;
699 rPageOffY = top * nDPI / 72;
700 rOutWidth = ( width - left - right ) * nDPI / 72;
701 rOutHeight = ( height - top - bottom ) * nDPI / 72;
702 }
703 }
704
705 // -----------------------------------------------------------------------
706
GetPaperBinCount(const ImplJobSetup * pJobSetup)707 sal_uLong PspSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup )
708 {
709 if( ! pJobSetup )
710 return 0;
711
712 JobData aData;
713 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
714
715 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
716 return pKey ? pKey->countValues() : 0;
717 }
718
719 // -----------------------------------------------------------------------
720
GetPaperBinName(const ImplJobSetup * pJobSetup,sal_uLong nPaperBin)721 String PspSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, sal_uLong nPaperBin )
722 {
723 JobData aData;
724 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
725
726 String aRet;
727 if( aData.m_pParser )
728 {
729 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
730 if( nPaperBin == 0xffff || ! pKey )
731 aRet = aData.m_pParser->getDefaultInputSlot();
732 else
733 {
734 const PPDValue* pValue = pKey->getValue( nPaperBin );
735 if( pValue )
736 aRet = aData.m_pParser->translateOption( pKey->getKey(), pValue->m_aOption );
737 }
738 }
739
740 return aRet;
741 }
742
743 // -----------------------------------------------------------------------
744
GetCapabilities(const ImplJobSetup * pJobSetup,sal_uInt16 nType)745 sal_uLong PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, sal_uInt16 nType )
746 {
747 switch( nType )
748 {
749 case PRINTER_CAPABILITIES_SUPPORTDIALOG:
750 return 1;
751 case PRINTER_CAPABILITIES_COPIES:
752 return 0xffff;
753 case PRINTER_CAPABILITIES_COLLATECOPIES:
754 {
755 // see if the PPD contains a value to set Collate to True
756 JobData aData;
757 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
758
759 const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ) : NULL;
760 const PPDValue* pVal = pKey ? pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) ) : NULL;
761
762 // PPDs don't mention the number of possible collated copies.
763 // so let's guess as many as we want ?
764 return pVal ? 0xffff : 0;
765 }
766 case PRINTER_CAPABILITIES_SETORIENTATION:
767 return 1;
768 case PRINTER_CAPABILITIES_SETDUPLEX:
769 return 1;
770 case PRINTER_CAPABILITIES_SETPAPERBIN:
771 return 1;
772 case PRINTER_CAPABILITIES_SETPAPERSIZE:
773 return 1;
774 case PRINTER_CAPABILITIES_SETPAPER:
775 return 0;
776 case PRINTER_CAPABILITIES_FAX:
777 {
778 PrinterInfoManager& rManager = PrinterInfoManager::get();
779 PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) );
780 String aFeatures( aInfo.m_aFeatures );
781 int nTokenCount = aFeatures.GetTokenCount( ',' );
782 for( int i = 0; i < nTokenCount; i++ )
783 {
784 if( aFeatures.GetToken( i ).CompareToAscii( "fax", 3 ) == COMPARE_EQUAL )
785 return 1;
786 }
787 return 0;
788 }
789 case PRINTER_CAPABILITIES_PDF:
790 {
791 PrinterInfoManager& rManager = PrinterInfoManager::get();
792 PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) );
793 String aFeatures( aInfo.m_aFeatures );
794 int nTokenCount = aFeatures.GetTokenCount( ',' );
795 for( int i = 0; i < nTokenCount; i++ )
796 {
797 if( aFeatures.GetToken( i ).CompareToAscii( "pdf=", 4 ) == COMPARE_EQUAL )
798 return 1;
799 }
800 return 0;
801 }
802 default: break;
803 };
804 return 0;
805 }
806
807 // =======================================================================
808
809 /*
810 * SalPrinter
811 */
812
PspSalPrinter(SalInfoPrinter * pInfoPrinter)813 PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter )
814 : m_bFax( false ),
815 m_bPdf( false ),
816 m_bSwallowFaxNo( false ),
817 m_pGraphics( NULL ),
818 m_nCopies( 1 ),
819 m_bCollate( false ),
820 m_pInfoPrinter( pInfoPrinter )
821 {
822 }
823
824 // -----------------------------------------------------------------------
825
~PspSalPrinter()826 PspSalPrinter::~PspSalPrinter()
827 {
828 }
829
830 // -----------------------------------------------------------------------
831
getTmpName()832 static String getTmpName()
833 {
834 rtl::OUString aTmp, aSys;
835 osl_createTempFile( NULL, NULL, &aTmp.pData );
836 osl_getSystemPathFromFileURL( aTmp.pData, &aSys.pData );
837
838 return aSys;
839 }
840
StartJob(const XubString * pFileName,const XubString & rJobName,const XubString & rAppName,sal_uLong nCopies,bool bCollate,bool,ImplJobSetup * pJobSetup)841 sal_Bool PspSalPrinter::StartJob(
842 const XubString* pFileName,
843 const XubString& rJobName,
844 const XubString& rAppName,
845 sal_uLong nCopies,
846 bool bCollate,
847 bool /*bDirect*/,
848 ImplJobSetup* pJobSetup )
849 {
850 vcl_sal::PrinterUpdate::jobStarted();
851
852 m_bFax = false;
853 m_bPdf = false;
854 m_aFileName = pFileName ? *pFileName : String();
855 m_aTmpFile = String();
856 m_nCopies = nCopies;
857 m_bCollate = bCollate;
858
859 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
860 if( m_nCopies > 1 )
861 {
862 // in case user did not do anything (m_nCopies=1)
863 // take the default from jobsetup
864 m_aJobData.m_nCopies = m_nCopies;
865 m_aJobData.setCollate( bCollate );
866 }
867
868 // check whether this printer is configured as fax
869 int nMode = 0;
870 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
871 sal_Int32 nIndex = 0;
872 while( nIndex != -1 )
873 {
874 OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
875 if( ! aToken.compareToAscii( "fax", 3 ) )
876 {
877 m_bFax = true;
878 m_aTmpFile = getTmpName();
879 nMode = S_IRUSR | S_IWUSR;
880
881 ::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >::const_iterator it;
882 it = pJobSetup->maValueMap.find( ::rtl::OUString::createFromAscii( "FAX#" ) );
883 if( it != pJobSetup->maValueMap.end() )
884 m_aFaxNr = it->second;
885
886 sal_Int32 nPos = 0;
887 m_bSwallowFaxNo = ! aToken.getToken( 1, '=', nPos ).compareToAscii( "swallow", 7 ) ? true : false;
888
889 break;
890 }
891 if( ! aToken.compareToAscii( "pdf=", 4 ) )
892 {
893 m_bPdf = true;
894 m_aTmpFile = getTmpName();
895 nMode = S_IRUSR | S_IWUSR;
896
897 if( ! m_aFileName.Len() )
898 {
899 m_aFileName = getPdfDir( rInfo );
900 m_aFileName.Append( '/' );
901 m_aFileName.Append( rJobName );
902 m_aFileName.AppendAscii( ".pdf" );
903 }
904 break;
905 }
906 }
907 m_aPrinterGfx.Init( m_aJobData );
908
909 // set/clear backwards compatibility flag
910 bool bStrictSO52Compatibility = false;
911 std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
912 pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
913 if( compat_it != pJobSetup->maValueMap.end() )
914 {
915 if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
916 bStrictSO52Compatibility = true;
917 }
918 m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
919
920 return m_aPrintJob.StartJob( m_aTmpFile.Len() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, false ) ? sal_True : sal_False;
921 }
922
923 // -----------------------------------------------------------------------
924
EndJob()925 sal_Bool PspSalPrinter::EndJob()
926 {
927 sal_Bool bSuccess = m_aPrintJob.EndJob();
928
929 if( bSuccess )
930 {
931 // check for fax
932 if( m_bFax )
933 {
934
935 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
936 // sendAFax removes the file after use
937 bSuccess = sendAFax( m_aFaxNr, m_aTmpFile, rInfo.m_aCommand );
938 }
939 else if( m_bPdf )
940 {
941 const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
942 bSuccess = createPdf( m_aFileName, m_aTmpFile, rInfo.m_aCommand );
943 }
944 }
945 vcl_sal::PrinterUpdate::jobEnded();
946 return bSuccess;
947 }
948
949 // -----------------------------------------------------------------------
950
AbortJob()951 sal_Bool PspSalPrinter::AbortJob()
952 {
953 sal_Bool bAbort = m_aPrintJob.AbortJob() ? sal_True : sal_False;
954 vcl_sal::PrinterUpdate::jobEnded();
955 return bAbort;
956 }
957
958 // -----------------------------------------------------------------------
959
StartPage(ImplJobSetup * pJobSetup,sal_Bool)960 SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, sal_Bool )
961 {
962 JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
963 m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, m_bFax ? &m_aFaxNr : NULL, m_bSwallowFaxNo, m_pInfoPrinter );
964 m_pGraphics->SetLayout( 0 );
965 if( m_nCopies > 1 )
966 {
967 // in case user did not do anything (m_nCopies=1)
968 // take the default from jobsetup
969 m_aJobData.m_nCopies = m_nCopies;
970 m_aJobData.setCollate( m_nCopies > 1 && m_bCollate );
971 }
972
973 m_aPrintJob.StartPage( m_aJobData );
974 m_aPrinterGfx.Init( m_aPrintJob );
975
976 return m_pGraphics;
977 }
978
979 // -----------------------------------------------------------------------
980
EndPage()981 sal_Bool PspSalPrinter::EndPage()
982 {
983 sal_Bool bResult = m_aPrintJob.EndPage();
984 m_aPrinterGfx.Clear();
985 return bResult ? sal_True : sal_False;
986 }
987
988 // -----------------------------------------------------------------------
989
GetErrorCode()990 sal_uLong PspSalPrinter::GetErrorCode()
991 {
992 return 0;
993 }
994
995 /*
996 * vcl::PrinterUpdate
997 */
998
999 Timer* vcl_sal::PrinterUpdate::pPrinterUpdateTimer = NULL;
1000 int vcl_sal::PrinterUpdate::nActiveJobs = 0;
1001
doUpdate()1002 void vcl_sal::PrinterUpdate::doUpdate()
1003 {
1004 ::psp::PrinterInfoManager& rManager( ::psp::PrinterInfoManager::get() );
1005 if( rManager.checkPrintersChanged( false ) && SvpSalInstance::s_pDefaultInstance )
1006 {
1007 const std::list< SalFrame* >& rList = SvpSalInstance::s_pDefaultInstance->getFrames();
1008 for( std::list< SalFrame* >::const_iterator it = rList.begin();
1009 it != rList.end(); ++it )
1010 SvpSalInstance::s_pDefaultInstance->PostEvent( *it, NULL, SALEVENT_PRINTERCHANGED );
1011 }
1012 }
1013
1014 // -----------------------------------------------------------------------
1015
1016 IMPL_STATIC_LINK_NOINSTANCE( vcl_sal::PrinterUpdate, UpdateTimerHdl, void*, )
1017 {
1018 if( nActiveJobs < 1 )
1019 {
1020 doUpdate();
1021 delete pPrinterUpdateTimer;
1022 pPrinterUpdateTimer = NULL;
1023 }
1024 else
1025 pPrinterUpdateTimer->Start();
1026
1027 return 0;
1028 }
1029
1030 // -----------------------------------------------------------------------
1031
update()1032 void vcl_sal::PrinterUpdate::update()
1033 {
1034 if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
1035 return;
1036
1037 static bool bOnce = false;
1038 if( ! bOnce )
1039 {
1040 bOnce = true;
1041 // start background printer detection
1042 psp::PrinterInfoManager::get();
1043 return;
1044 }
1045
1046 if( nActiveJobs < 1 )
1047 doUpdate();
1048 else if( ! pPrinterUpdateTimer )
1049 {
1050 pPrinterUpdateTimer = new Timer();
1051 pPrinterUpdateTimer->SetTimeout( 500 );
1052 pPrinterUpdateTimer->SetTimeoutHdl( STATIC_LINK( NULL, vcl_sal::PrinterUpdate, UpdateTimerHdl ) );
1053 pPrinterUpdateTimer->Start();
1054 }
1055 }
1056
1057 // -----------------------------------------------------------------------
1058
jobEnded()1059 void vcl_sal::PrinterUpdate::jobEnded()
1060 {
1061 nActiveJobs--;
1062 if( nActiveJobs < 1 )
1063 {
1064 if( pPrinterUpdateTimer )
1065 {
1066 pPrinterUpdateTimer->Stop();
1067 delete pPrinterUpdateTimer;
1068 pPrinterUpdateTimer = NULL;
1069 doUpdate();
1070 }
1071 }
1072 }
1073