xref: /trunk/main/vcl/unx/headless/svpprn.cxx (revision 74cbd1f1)
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