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