1/*
2 * Copyright 2001-2009, Haiku.
3 * Distributed under the terms of the MIT license.
4 *
5 * Authors:
6 *		I.R. Adema
7 *		Stefano Ceccherini (burton666@libero.it)
8 *		Michael Pfeiffer
9 *		julun <host.haiku@gmx.de>
10 */
11
12
13#include <PrintJob.h>
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18
19#include <Alert.h>
20#include <Application.h>
21#include <Button.h>
22#include <Debug.h>
23#include <Entry.h>
24#include <File.h>
25#include <FindDirectory.h>
26#include <Messenger.h>
27#include <NodeInfo.h>
28#include <OS.h>
29#include <Path.h>
30#include <Region.h>
31#include <Roster.h>
32#include <SystemCatalog.h>
33#include <View.h>
34
35#include <AutoDeleter.h>
36#include <pr_server.h>
37#include <ViewPrivate.h>
38
39using BPrivate::gSystemCatalog;
40
41#undef B_TRANSLATION_CONTEXT
42#define B_TRANSLATION_CONTEXT "PrintJob"
43
44#undef B_TRANSLATE
45#define B_TRANSLATE(str) \
46	gSystemCatalog.GetString(B_TRANSLATE_MARK(str), "PrintJob")
47
48
49/*!	Summary of spool file:
50
51		|-----------------------------------|
52		|         print_file_header         |
53		|-----------------------------------|
54		|    BMessage print_job_settings    |
55		|-----------------------------------|
56		|                                   |
57		| ********** (first page) ********* |
58		| *                               * |
59		| *         _page_header_         * |
60		| * ----------------------------- * |
61		| * |---------------------------| * |
62		| * |       BPoint where        | * |
63		| * |       BRect bounds        | * |
64		| * |       BPicture pic        | * |
65		| * |---------------------------| * |
66		| * |---------------------------| * |
67		| * |       BPoint where        | * |
68		| * |       BRect bounds        | * |
69		| * |       BPicture pic        | * |
70		| * |---------------------------| * |
71		| ********************************* |
72		|                                   |
73		| ********* (second page) ********* |
74		| *                               * |
75		| *         _page_header_         * |
76		| * ----------------------------- * |
77		| * |---------------------------| * |
78		| * |       BPoint where        | * |
79		| * |       BRect bounds        | * |
80		| * |       BPicture pic        | * |
81		| * |---------------------------| * |
82		| ********************************* |
83		|-----------------------------------|
84
85	BeOS R5 print_file_header.version is 1 << 16
86	BeOS R5 print_file_header.first_page is -1
87
88	each page can consist of a collection of picture structures
89	remaining pages start at _page_header_.next_page of previous _page_header_
90
91	See also: "How to Write a BeOS R5 Printer Driver" for description of spool
92	file format: http://haiku-os.org/documents/dev/how_to_write_a_printer_driver
93*/
94
95
96struct _page_header_ {
97	int32 number_of_pictures;
98	off_t next_page;
99	int32 reserved[10];
100} _PACKED;
101
102
103static void
104ShowError(const char* message)
105{
106	BAlert* alert = new BAlert(B_TRANSLATE("Error"), message, B_TRANSLATE("OK"));
107	alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
108	alert->Go();
109}
110
111
112// #pragma mark -- PrintServerMessenger
113
114
115namespace BPrivate {
116
117
118class PrintServerMessenger {
119public:
120							PrintServerMessenger(uint32 what, BMessage* input);
121							~PrintServerMessenger();
122
123			BMessage*		Request();
124			status_t		SendRequest();
125
126			void			SetResult(BMessage* result);
127			BMessage*		Result() const { return fResult; }
128
129	static	status_t		GetPrintServerMessenger(BMessenger& messenger);
130
131private:
132			void			RejectUserInput();
133			void			AllowUserInput();
134			void			DeleteSemaphore();
135	static	status_t		MessengerThread(void* data);
136
137			uint32			fWhat;
138			BMessage*		fInput;
139			BMessage*		fRequest;
140			BMessage*		fResult;
141			sem_id			fThreadCompleted;
142			BAlert*			fHiddenApplicationModalWindow;
143};
144
145
146}	// namespace BPrivate
147
148
149using namespace BPrivate;
150
151
152// #pragma mark -- BPrintJob
153
154
155BPrintJob::BPrintJob(const char* jobName)
156	:
157	fPrintJobName(NULL),
158	fSpoolFile(NULL),
159	fError(B_NO_INIT),
160	fSetupMessage(NULL),
161	fDefaultSetupMessage(NULL),
162	fAbort(0),
163	fCurrentPageHeader(NULL)
164{
165	memset(&fSpoolFileHeader, 0, sizeof(print_file_header));
166
167	if (jobName != NULL && jobName[0])
168		fPrintJobName = strdup(jobName);
169
170	fCurrentPageHeader = new _page_header_;
171	if (fCurrentPageHeader != NULL)
172		memset(fCurrentPageHeader, 0, sizeof(_page_header_));
173}
174
175
176BPrintJob::~BPrintJob()
177{
178	CancelJob();
179
180	free(fPrintJobName);
181	delete fSetupMessage;
182	delete fDefaultSetupMessage;
183	delete fCurrentPageHeader;
184}
185
186
187status_t
188BPrintJob::ConfigPage()
189{
190	PrintServerMessenger messenger(PSRV_SHOW_PAGE_SETUP, fSetupMessage);
191	status_t status = messenger.SendRequest();
192	if (status != B_OK)
193		return status;
194
195	delete fSetupMessage;
196	fSetupMessage = messenger.Result();
197	_HandlePageSetup(fSetupMessage);
198
199	return B_OK;
200}
201
202
203status_t
204BPrintJob::ConfigJob()
205{
206	PrintServerMessenger messenger(PSRV_SHOW_PRINT_SETUP, fSetupMessage);
207	status_t status = messenger.SendRequest();
208	if (status != B_OK)
209		return status;
210
211	delete fSetupMessage;
212	fSetupMessage = messenger.Result();
213	if (!_HandlePrintSetup(fSetupMessage))
214		return B_ERROR;
215
216	fError = B_OK;
217	return B_OK;
218}
219
220
221void
222BPrintJob::BeginJob()
223{
224	fError = B_ERROR;
225
226	// can not start a new job until it has been commited or cancelled
227	if (fSpoolFile != NULL || fCurrentPageHeader == NULL)
228		return;
229
230	// TODO show alert, setup message is required
231	if (fSetupMessage == NULL)
232		return;
233
234	// create spool file
235	BPath path;
236	status_t status = find_directory(B_USER_PRINTERS_DIRECTORY, &path);
237	if (status != B_OK)
238		return;
239
240	char *printer = _GetCurrentPrinterName();
241	if (printer == NULL)
242		return;
243	MemoryDeleter _(printer);
244
245	path.Append(printer);
246
247	char mangledName[B_FILE_NAME_LENGTH];
248	_GetMangledName(mangledName, B_FILE_NAME_LENGTH);
249
250	path.Append(mangledName);
251	if (path.InitCheck() != B_OK)
252		return;
253
254	// TODO: fSpoolFileName should store the name only (not path which can be
255	// 1024 bytes long)
256	strlcpy(fSpoolFileName, path.Path(), sizeof(fSpoolFileName));
257	fSpoolFile = new BFile(fSpoolFileName, B_READ_WRITE | B_CREATE_FILE);
258
259	if (fSpoolFile->InitCheck() != B_OK) {
260		CancelJob();
261		return;
262	}
263
264	// add print_file_header
265	// page_count is updated in CommitJob()
266	// on BeOS R5 the offset to the first page was always -1
267	fSpoolFileHeader.version = 1 << 16;
268	fSpoolFileHeader.page_count = 0;
269	fSpoolFileHeader.first_page = (off_t)-1;
270
271	if (fSpoolFile->Write(&fSpoolFileHeader, sizeof(print_file_header))
272			!= sizeof(print_file_header)) {
273		CancelJob();
274		return;
275	}
276
277	// add printer settings message
278	if (!fSetupMessage->HasString(PSRV_FIELD_CURRENT_PRINTER))
279		fSetupMessage->AddString(PSRV_FIELD_CURRENT_PRINTER, printer);
280
281	_AddSetupSpec();
282	_NewPage();
283
284	// state variables
285	fAbort = 0;
286	fError = B_OK;
287}
288
289
290void
291BPrintJob::CommitJob()
292{
293	if (fSpoolFile == NULL)
294		return;
295
296	if (fSpoolFileHeader.page_count == 0) {
297		ShowError(B_TRANSLATE("No pages to print!"));
298		CancelJob();
299		return;
300	}
301
302	// update spool file
303	_EndLastPage();
304
305	// write spool file header
306	fSpoolFile->Seek(0, SEEK_SET);
307	fSpoolFile->Write(&fSpoolFileHeader, sizeof(print_file_header));
308
309	// set file attributes
310	app_info appInfo;
311	be_app->GetAppInfo(&appInfo);
312	const char* printerName = "";
313	fSetupMessage->FindString(PSRV_FIELD_CURRENT_PRINTER, &printerName);
314
315	BNodeInfo info(fSpoolFile);
316	info.SetType(PSRV_SPOOL_FILETYPE);
317
318	fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_PAGECOUNT, B_INT32_TYPE, 0,
319		&fSpoolFileHeader.page_count, sizeof(int32));
320	fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_DESCRIPTION, B_STRING_TYPE, 0,
321		fPrintJobName, strlen(fPrintJobName) + 1);
322	fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_PRINTER, B_STRING_TYPE, 0,
323		printerName, strlen(printerName) + 1);
324	fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_STATUS, B_STRING_TYPE, 0,
325		PSRV_JOB_STATUS_WAITING, strlen(PSRV_JOB_STATUS_WAITING) + 1);
326	fSpoolFile->WriteAttr(PSRV_SPOOL_ATTR_MIMETYPE, B_STRING_TYPE, 0,
327		appInfo.signature, strlen(appInfo.signature) + 1);
328
329	delete fSpoolFile;
330	fSpoolFile = NULL;
331	fError = B_ERROR;
332
333	// notify print server
334	BMessenger printServer;
335	if (PrintServerMessenger::GetPrintServerMessenger(printServer) != B_OK)
336		return;
337
338	BMessage request(PSRV_PRINT_SPOOLED_JOB);
339	request.AddString("JobName", fPrintJobName);
340	request.AddString("Spool File", fSpoolFileName);
341
342	BMessage reply;
343	printServer.SendMessage(&request, &reply);
344}
345
346
347void
348BPrintJob::CancelJob()
349{
350	if (fSpoolFile == NULL)
351		return;
352
353	fAbort = 1;
354	BEntry(fSpoolFileName).Remove();
355	delete fSpoolFile;
356	fSpoolFile = NULL;
357}
358
359
360void
361BPrintJob::SpoolPage()
362{
363	if (fSpoolFile == NULL)
364		return;
365
366	if (fCurrentPageHeader->number_of_pictures == 0)
367		return;
368
369	fSpoolFileHeader.page_count++;
370	fSpoolFile->Seek(0, SEEK_END);
371	if (fCurrentPageHeaderOffset) {
372		// update last written page_header
373		fCurrentPageHeader->next_page = fSpoolFile->Position();
374		fSpoolFile->Seek(fCurrentPageHeaderOffset, SEEK_SET);
375		fSpoolFile->Write(fCurrentPageHeader, sizeof(_page_header_));
376		fSpoolFile->Seek(fCurrentPageHeader->next_page, SEEK_SET);
377	}
378
379	_NewPage();
380}
381
382
383bool
384BPrintJob::CanContinue()
385{
386	// Check if our local error storage is still B_OK
387	return fError == B_OK && !fAbort;
388}
389
390
391void
392BPrintJob::DrawView(BView* view, BRect rect, BPoint where)
393{
394	if (fSpoolFile == NULL)
395		return;
396
397	if (view == NULL)
398		return;
399
400	if (view->LockLooper()) {
401		BPicture picture;
402		_RecurseView(view, B_ORIGIN - rect.LeftTop(), &picture, rect);
403		_AddPicture(picture, rect, where);
404		view->UnlockLooper();
405	}
406}
407
408
409BMessage*
410BPrintJob::Settings()
411{
412	if (fSetupMessage == NULL)
413		return NULL;
414
415	return new BMessage(*fSetupMessage);
416}
417
418
419void
420BPrintJob::SetSettings(BMessage* message)
421{
422	if (message != NULL)
423		_HandlePrintSetup(message);
424
425	delete fSetupMessage;
426	fSetupMessage = message;
427}
428
429
430bool
431BPrintJob::IsSettingsMessageValid(BMessage* message) const
432{
433	char* printerName = _GetCurrentPrinterName();
434	if (printerName == NULL)
435		return false;
436
437	const char* name = NULL;
438	// The passed message is valid if it contains the right printer name.
439	bool valid = message != NULL
440		&& message->FindString("printer_name", &name) == B_OK
441		&& strcmp(printerName, name) == 0;
442
443	free(printerName);
444	return valid;
445}
446
447
448// Either SetSettings() or ConfigPage() has to be called prior
449// to any of the getters otherwise they return undefined values.
450BRect
451BPrintJob::PaperRect()
452{
453	if (fDefaultSetupMessage == NULL)
454		_LoadDefaultSettings();
455
456	return fPaperSize;
457}
458
459
460BRect
461BPrintJob::PrintableRect()
462{
463	if (fDefaultSetupMessage == NULL)
464		_LoadDefaultSettings();
465
466	return fUsableSize;
467}
468
469
470void
471BPrintJob::GetResolution(int32* xdpi, int32* ydpi)
472{
473	if (fDefaultSetupMessage == NULL)
474		_LoadDefaultSettings();
475
476	if (xdpi != NULL)
477		*xdpi = fXResolution;
478
479	if (ydpi != NULL)
480		*ydpi = fYResolution;
481}
482
483
484int32
485BPrintJob::FirstPage()
486{
487	return fFirstPage;
488}
489
490
491int32
492BPrintJob::LastPage()
493{
494	return fLastPage;
495}
496
497
498int32
499BPrintJob::PrinterType(void*) const
500{
501	BMessenger printServer;
502	if (PrintServerMessenger::GetPrintServerMessenger(printServer) != B_OK)
503		return B_COLOR_PRINTER; // default
504
505	BMessage reply;
506	BMessage message(PSRV_GET_ACTIVE_PRINTER);
507	printServer.SendMessage(&message, &reply);
508
509	int32 type;
510	if (reply.FindInt32("color", &type) != B_OK)
511		return B_COLOR_PRINTER; // default
512
513	return type;
514}
515
516
517// #pragma mark - private
518
519
520void
521BPrintJob::_RecurseView(BView* view, BPoint origin, BPicture* picture,
522	BRect rect)
523{
524	ASSERT(picture != NULL);
525
526	BRegion region;
527	region.Set(BRect(rect.left, rect.top, rect.right, rect.bottom));
528	view->fState->print_rect = rect;
529
530	view->AppendToPicture(picture);
531	view->PushState();
532	view->SetOrigin(origin);
533	view->ConstrainClippingRegion(&region);
534
535	if (view->ViewColor() != B_TRANSPARENT_COLOR) {
536		rgb_color highColor = view->HighColor();
537		view->SetHighColor(view->ViewColor());
538		view->FillRect(rect);
539		view->SetHighColor(highColor);
540	}
541
542	if ((view->Flags() & B_WILL_DRAW) != 0) {
543		view->fIsPrinting = true;
544		view->Draw(rect);
545		view->fIsPrinting = false;
546	}
547
548	view->PopState();
549	view->EndPicture();
550
551	BView* child = view->ChildAt(0);
552	while (child != NULL) {
553		if (!child->IsHidden()) {
554			BPoint leftTop(view->Bounds().LeftTop() + child->Frame().LeftTop());
555			BRect printRect(rect.OffsetToCopy(rect.LeftTop() - leftTop)
556				& child->Bounds());
557			if (printRect.IsValid())
558				_RecurseView(child, origin + leftTop, picture, printRect);
559		}
560		child = child->NextSibling();
561	}
562
563	if ((view->Flags() & B_DRAW_ON_CHILDREN) != 0) {
564		view->AppendToPicture(picture);
565		view->PushState();
566		view->SetOrigin(origin);
567		view->ConstrainClippingRegion(&region);
568		view->fIsPrinting = true;
569		view->DrawAfterChildren(rect);
570		view->fIsPrinting = false;
571		view->PopState();
572		view->EndPicture();
573	}
574}
575
576
577void
578BPrintJob::_GetMangledName(char* buffer, size_t bufferSize) const
579{
580	snprintf(buffer, bufferSize, "%s@%" B_PRId64, fPrintJobName,
581		system_time() / 1000);
582}
583
584
585void
586BPrintJob::_HandlePageSetup(BMessage* setup)
587{
588	setup->FindRect(PSRV_FIELD_PRINTABLE_RECT, &fUsableSize);
589	setup->FindRect(PSRV_FIELD_PAPER_RECT, &fPaperSize);
590
591	// TODO verify data type (taken from libprint)
592	int64 valueInt64;
593	if (setup->FindInt64(PSRV_FIELD_XRES, &valueInt64) == B_OK)
594		fXResolution = (short)valueInt64;
595
596	if (setup->FindInt64(PSRV_FIELD_YRES, &valueInt64) == B_OK)
597		fYResolution = (short)valueInt64;
598}
599
600
601bool
602BPrintJob::_HandlePrintSetup(BMessage* message)
603{
604	_HandlePageSetup(message);
605
606	bool valid = true;
607	if (message->FindInt32(PSRV_FIELD_FIRST_PAGE, &fFirstPage) != B_OK)
608		valid = false;
609
610	if (message->FindInt32(PSRV_FIELD_LAST_PAGE, &fLastPage) != B_OK)
611		valid = false;
612
613	return valid;
614}
615
616
617void
618BPrintJob::_NewPage()
619{
620	// init, write new page_header
621	fCurrentPageHeader->next_page = 0;
622	fCurrentPageHeader->number_of_pictures = 0;
623	fCurrentPageHeaderOffset = fSpoolFile->Position();
624	fSpoolFile->Write(fCurrentPageHeader, sizeof(_page_header_));
625}
626
627
628void
629BPrintJob::_EndLastPage()
630{
631	if (!fSpoolFile)
632		return;
633
634	if (fCurrentPageHeader->number_of_pictures == 0)
635		return;
636
637	fSpoolFileHeader.page_count++;
638	fSpoolFile->Seek(0, SEEK_END);
639	if (fCurrentPageHeaderOffset) {
640		fCurrentPageHeader->next_page = 0;
641		fSpoolFile->Seek(fCurrentPageHeaderOffset, SEEK_SET);
642		fSpoolFile->Write(fCurrentPageHeader, sizeof(_page_header_));
643		fSpoolFile->Seek(0, SEEK_END);
644	}
645}
646
647
648void
649BPrintJob::_AddSetupSpec()
650{
651	fSetupMessage->Flatten(fSpoolFile);
652}
653
654
655void
656BPrintJob::_AddPicture(BPicture& picture, BRect& rect, BPoint& where)
657{
658	ASSERT(fSpoolFile != NULL);
659
660	fCurrentPageHeader->number_of_pictures++;
661	fSpoolFile->Write(&where, sizeof(BRect));
662	fSpoolFile->Write(&rect, sizeof(BPoint));
663	picture.Flatten(fSpoolFile);
664}
665
666
667/*!	Returns a copy of the applications default printer name or NULL if it
668	could not be obtained. Caller is responsible to free the string using
669	free().
670*/
671char*
672BPrintJob::_GetCurrentPrinterName() const
673{
674	BMessenger printServer;
675	if (PrintServerMessenger::GetPrintServerMessenger(printServer) != B_OK)
676		return NULL;
677
678	const char* printerName = NULL;
679
680	BMessage reply;
681	BMessage message(PSRV_GET_ACTIVE_PRINTER);
682	if (printServer.SendMessage(&message, &reply) == B_OK)
683		reply.FindString("printer_name", &printerName);
684
685	if (printerName == NULL)
686		return NULL;
687
688	return strdup(printerName);
689}
690
691
692void
693BPrintJob::_LoadDefaultSettings()
694{
695	BMessenger printServer;
696	if (PrintServerMessenger::GetPrintServerMessenger(printServer) != B_OK)
697		return;
698
699	BMessage message(PSRV_GET_DEFAULT_SETTINGS);
700	BMessage* reply = new BMessage;
701
702	printServer.SendMessage(&message, reply);
703
704	// Only override our settings if we don't have any settings yet
705	if (fSetupMessage == NULL)
706		_HandlePrintSetup(reply);
707
708	delete fDefaultSetupMessage;
709	fDefaultSetupMessage = reply;
710}
711
712
713void BPrintJob::_ReservedPrintJob1() {}
714void BPrintJob::_ReservedPrintJob2() {}
715void BPrintJob::_ReservedPrintJob3() {}
716void BPrintJob::_ReservedPrintJob4() {}
717
718
719// #pragma mark -- PrintServerMessenger
720
721
722namespace BPrivate {
723
724
725PrintServerMessenger::PrintServerMessenger(uint32 what, BMessage *input)
726	:
727	fWhat(what),
728	fInput(input),
729	fRequest(NULL),
730	fResult(NULL),
731	fThreadCompleted(-1),
732	fHiddenApplicationModalWindow(NULL)
733{
734	RejectUserInput();
735}
736
737
738PrintServerMessenger::~PrintServerMessenger()
739{
740	DeleteSemaphore();
741		// in case SendRequest could not start the thread
742	delete fRequest; fRequest = NULL;
743	AllowUserInput();
744}
745
746
747void
748PrintServerMessenger::RejectUserInput()
749{
750	fHiddenApplicationModalWindow = new BAlert("bogus", "app_modal", "OK");
751	fHiddenApplicationModalWindow->DefaultButton()->SetEnabled(false);
752	fHiddenApplicationModalWindow->SetDefaultButton(NULL);
753	fHiddenApplicationModalWindow->SetFlags(fHiddenApplicationModalWindow->Flags() | B_CLOSE_ON_ESCAPE);
754	fHiddenApplicationModalWindow->MoveTo(-65000, -65000);
755	fHiddenApplicationModalWindow->Go(NULL);
756}
757
758
759void
760PrintServerMessenger::AllowUserInput()
761{
762	fHiddenApplicationModalWindow->Lock();
763	fHiddenApplicationModalWindow->Quit();
764}
765
766
767void
768PrintServerMessenger::DeleteSemaphore()
769{
770	if (fThreadCompleted >= B_OK) {
771		sem_id id = fThreadCompleted;
772		fThreadCompleted = -1;
773		delete_sem(id);
774	}
775}
776
777
778status_t
779PrintServerMessenger::SendRequest()
780{
781	fThreadCompleted = create_sem(0, "print_server_messenger_sem");
782	if (fThreadCompleted < B_OK)
783		return B_ERROR;
784
785	thread_id id = spawn_thread(MessengerThread, "async_request",
786		B_NORMAL_PRIORITY, this);
787	if (id <= 0 || resume_thread(id) != B_OK)
788		return B_ERROR;
789
790	// Get the originating window, if it exists
791	BWindow* window = dynamic_cast<BWindow*>(
792		BLooper::LooperForThread(find_thread(NULL)));
793	if (window != NULL) {
794		status_t err;
795		while (true) {
796			do {
797				err = acquire_sem_etc(fThreadCompleted, 1, B_RELATIVE_TIMEOUT,
798					50000);
799			// We've (probably) had our time slice taken away from us
800			} while (err == B_INTERRUPTED);
801
802			// Semaphore was finally nuked in SetResult(BMessage *)
803			if (err == B_BAD_SEM_ID)
804				break;
805			window->UpdateIfNeeded();
806		}
807	} else {
808		// No window to update, so just hang out until we're done.
809		while (acquire_sem(fThreadCompleted) == B_INTERRUPTED);
810	}
811
812	status_t status;
813	wait_for_thread(id, &status);
814
815	return Result() != NULL ? B_OK : B_ERROR;
816}
817
818
819BMessage*
820PrintServerMessenger::Request()
821{
822	if (fRequest != NULL)
823		return fRequest;
824
825	if (fInput != NULL) {
826		fRequest = new BMessage(*fInput);
827		fRequest->what = fWhat;
828	} else
829		fRequest = new BMessage(fWhat);
830
831	return fRequest;
832}
833
834
835void
836PrintServerMessenger::SetResult(BMessage* result)
837{
838	fResult = result;
839	DeleteSemaphore();
840	// terminate loop in thread spawned by SendRequest
841}
842
843
844status_t
845PrintServerMessenger::GetPrintServerMessenger(BMessenger& messenger)
846{
847	messenger = BMessenger(PSRV_SIGNATURE_TYPE);
848	return messenger.IsValid() ? B_OK : B_ERROR;
849}
850
851
852status_t
853PrintServerMessenger::MessengerThread(void* data)
854{
855	PrintServerMessenger* messenger = static_cast<PrintServerMessenger*>(data);
856
857	BMessenger printServer;
858	if (messenger->GetPrintServerMessenger(printServer) != B_OK) {
859		ShowError(B_TRANSLATE("Print Server is not responding."));
860		messenger->SetResult(NULL);
861		return B_ERROR;
862	}
863
864	BMessage* request = messenger->Request();
865	if (request == NULL) {
866		messenger->SetResult(NULL);
867		return B_ERROR;
868	}
869
870
871	BMessage reply;
872	if (printServer.SendMessage(request, &reply) != B_OK
873		|| reply.what != 'okok' ) {
874		messenger->SetResult(NULL);
875		return B_ERROR;
876	}
877
878	messenger->SetResult(new BMessage(reply));
879	return B_OK;
880}
881
882
883}	// namespace BPrivate
884