1/*
2 * Copyright 2008 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Julun, <host.haiku@gmx.de
7 */
8
9#include <Printer.h>
10
11#include <FindDirectory.h>
12#include <NodeInfo.h>
13#include <NodeMonitor.h>
14
15
16#include <new>
17
18
19namespace BPrivate {
20	namespace Print {
21
22
23// TODO: remove, after pr_server.h cleanup
24
25// mime file types
26#define PSRV_PRINTER_MIMETYPE					"application/x-vnd.Be.printer"
27
28
29// printer attributes
30#define PSRV_PRINTER_ATTR_STATE					"state"
31#define PSRV_PRINTER_ATTR_COMMENTS				"Comments"
32#define PSRV_PRINTER_ATTR_TRANSPORT				"transport"
33#define PSRV_PRINTER_ATTR_DRIVER_NAME			"Driver Name"
34#define PSRV_PRINTER_ATTR_PRINTER_NAME			"Printer Name"
35#define PSRV_PRINTER_ATTR_DEFAULT_PRINTER		"Default Printer"
36#define PSRV_PRINTER_ATTR_TRANSPORT_ADDRESS		"transport_address"
37
38
39// message fields
40#define PSRV_FIELD_CURRENT_PRINTER				"current_printer"
41
42
43BPrinter::BPrinter()
44	: fListener(NULL)
45{
46	memset(&fPrinterEntryRef, 0, sizeof(entry_ref));
47}
48
49
50BPrinter::BPrinter(const BEntry& entry)
51	: fListener(NULL)
52{
53	SetTo(entry);
54}
55
56
57BPrinter::BPrinter(const BPrinter& printer)
58{
59	*this = printer;
60}
61
62
63BPrinter::BPrinter(const node_ref& nodeRef)
64	: fListener(NULL)
65{
66	SetTo(nodeRef);
67}
68
69
70BPrinter::BPrinter(const entry_ref& entryRef)
71	: fListener(NULL)
72	, fPrinterEntryRef(entryRef)
73{
74}
75
76
77BPrinter::BPrinter(const BDirectory& directory)
78	: fListener(NULL)
79{
80	SetTo(directory);
81}
82
83
84BPrinter::~BPrinter()
85{
86	StopWatching();
87}
88
89
90status_t
91BPrinter::SetTo(const BEntry& entry)
92{
93	StopWatching();
94	entry.GetRef(&fPrinterEntryRef);
95
96	return InitCheck();
97}
98
99
100status_t
101BPrinter::SetTo(const node_ref& nodeRef)
102{
103	SetTo(BDirectory(&nodeRef));
104	return InitCheck();
105}
106
107
108status_t
109BPrinter::SetTo(const entry_ref& entryRef)
110{
111	StopWatching();
112	fPrinterEntryRef = entryRef;
113
114	return InitCheck();
115}
116
117
118status_t
119BPrinter::SetTo(const BDirectory& directory)
120{
121	StopWatching();
122
123	BEntry entry;
124	directory.GetEntry(&entry);
125	entry.GetRef(&fPrinterEntryRef);
126
127	return InitCheck();
128}
129
130
131void
132BPrinter::Unset()
133{
134	StopWatching();
135	memset(&fPrinterEntryRef, 0, sizeof(entry_ref));
136}
137
138
139bool
140BPrinter::IsValid() const
141{
142	BDirectory spoolDir(&fPrinterEntryRef);
143	if (spoolDir.InitCheck() != B_OK)
144		return false;
145
146	BNode node(spoolDir);
147	char type[B_MIME_TYPE_LENGTH];
148	BNodeInfo(&node).GetType(type);
149
150	if (strcmp(type, PSRV_PRINTER_MIMETYPE) != 0)
151		return false;
152
153	return true;
154}
155
156
157status_t
158BPrinter::InitCheck() const
159{
160	BDirectory spoolDir(&fPrinterEntryRef);
161	return spoolDir.InitCheck();
162}
163
164
165bool
166BPrinter::IsFree() const
167{
168	return (State() == "free");
169}
170
171
172bool
173BPrinter::IsDefault() const
174{
175	bool isDefault = false;
176
177	BDirectory spoolDir(&fPrinterEntryRef);
178	if (spoolDir.InitCheck() == B_OK)
179		spoolDir.ReadAttr(PSRV_PRINTER_ATTR_DEFAULT_PRINTER, B_BOOL_TYPE, 0,
180			&isDefault, sizeof(bool));
181
182	return isDefault;
183}
184
185
186bool
187BPrinter::IsShareable() const
188{
189	if (Name() == "Preview")
190		return true;
191
192	return false;
193}
194
195
196BString
197BPrinter::Name() const
198{
199	return _ReadAttribute(PSRV_PRINTER_ATTR_PRINTER_NAME);
200}
201
202
203BString
204BPrinter::State() const
205{
206	return _ReadAttribute(PSRV_PRINTER_ATTR_STATE);
207}
208
209
210BString
211BPrinter::Driver() const
212{
213	return _ReadAttribute(PSRV_PRINTER_ATTR_DRIVER_NAME);
214}
215
216
217BString
218BPrinter::Comments() const
219{
220	return _ReadAttribute(PSRV_PRINTER_ATTR_COMMENTS);
221}
222
223
224BString
225BPrinter::Transport() const
226{
227	return _ReadAttribute(PSRV_PRINTER_ATTR_TRANSPORT);
228}
229
230
231BString
232BPrinter::TransportAddress() const
233{
234	return _ReadAttribute(PSRV_PRINTER_ATTR_TRANSPORT_ADDRESS);
235}
236
237
238status_t
239BPrinter::DefaultSettings(BMessage& settings)
240{
241	status_t status = B_ERROR;
242	image_id id = _LoadDriver();
243	if (id < 0)
244		return status;
245
246	typedef BMessage* (*default_settings_func_t)(BNode*);
247	default_settings_func_t default_settings;
248	if (get_image_symbol(id, "default_settings", B_SYMBOL_TYPE_TEXT
249		, (void**)&default_settings) == B_OK) {
250		BNode printerNode(&fPrinterEntryRef);
251		BMessage *newSettings = default_settings(&printerNode);
252		if (newSettings) {
253			status = B_OK;
254			settings = *newSettings;
255			_AddPrinterName(settings);
256		}
257		delete newSettings;
258	}
259	unload_add_on(id);
260	return status;
261}
262
263
264status_t
265BPrinter::StartWatching(const BMessenger& listener)
266{
267	StopWatching();
268
269	if (!listener.IsValid())
270		return B_BAD_VALUE;
271
272	fListener = new(std::nothrow) BMessenger(listener);
273	if (!fListener)
274		return B_NO_MEMORY;
275
276	node_ref nodeRef;
277	nodeRef.device = fPrinterEntryRef.device;
278	nodeRef.node = fPrinterEntryRef.directory;
279
280	return watch_node(&nodeRef, B_WATCH_DIRECTORY, *fListener);
281}
282
283
284void
285BPrinter::StopWatching()
286{
287	if (fListener) {
288		stop_watching(*fListener);
289		delete fListener;
290		fListener = NULL;
291	}
292}
293
294
295BPrinter&
296BPrinter::operator=(const BPrinter& printer)
297{
298	if (this != &printer) {
299		Unset();
300		fPrinterEntryRef = printer.fPrinterEntryRef;
301		if (printer.fListener)
302			StartWatching(*printer.fListener);
303	}
304	return *this;
305}
306
307
308bool
309BPrinter::operator==(const BPrinter& printer) const
310{
311	return (fPrinterEntryRef == printer.fPrinterEntryRef);
312}
313
314
315bool
316BPrinter::operator!=(const BPrinter& printer) const
317{
318	return (fPrinterEntryRef != printer.fPrinterEntryRef);
319}
320
321
322status_t
323BPrinter::_Configure() const
324{
325	status_t status = B_ERROR;
326	image_id id = _LoadDriver();
327	if (id < 0)
328		return status;
329
330	BString printerName(_ReadAttribute(PSRV_PRINTER_ATTR_PRINTER_NAME));
331	if (printerName.Length() > 0) {
332		typedef char* (*add_printer_func_t)(const char*);
333		add_printer_func_t add_printer;
334		if (get_image_symbol(id, "add_printer", B_SYMBOL_TYPE_TEXT
335			, (void**)&add_printer) == B_OK) {
336				if (add_printer(printerName.String()) != NULL)
337					status = B_OK;
338		}
339	} else {
340		status = B_ERROR;
341	}
342	unload_add_on(id);
343	return status;
344}
345
346
347status_t
348BPrinter::_ConfigureJob(BMessage& settings)
349{
350	status_t status = B_ERROR;
351	image_id id = _LoadDriver();
352	if (id < 0)
353		return status;
354
355	typedef BMessage* (*config_job_func_t)(BNode*, const BMessage*);
356	config_job_func_t configure_job;
357	if (get_image_symbol(id, "config_job", B_SYMBOL_TYPE_TEXT
358		, (void**)&configure_job) == B_OK) {
359		BNode printerNode(&fPrinterEntryRef);
360		BMessage *newSettings = configure_job(&printerNode, &settings);
361		if (newSettings && (newSettings->what == 'okok')) {
362			status = B_OK;
363			settings = *newSettings;
364			_AddPrinterName(settings);
365		}
366		delete newSettings;
367	}
368	unload_add_on(id);
369	return status;
370}
371
372
373status_t
374BPrinter::_ConfigurePage(BMessage& settings)
375{
376	status_t status = B_ERROR;
377	image_id id = _LoadDriver();
378	if (id < 0)
379		return status;
380
381	typedef BMessage* (*config_page_func_t)(BNode*, const BMessage*);
382	config_page_func_t configure_page;
383	if (get_image_symbol(id, "config_page", B_SYMBOL_TYPE_TEXT
384		, (void**)&configure_page) == B_OK) {
385		BNode printerNode(&fPrinterEntryRef);
386		BMessage *newSettings = configure_page(&printerNode, &settings);
387		if (newSettings && (newSettings->what == 'okok')) {
388			status = B_OK;
389			settings = *newSettings;
390			_AddPrinterName(settings);
391		}
392		delete newSettings;
393	}
394	unload_add_on(id);
395	return status;
396}
397
398
399BPath
400BPrinter::_DriverPath() const
401{
402	BString driverName(_ReadAttribute(PSRV_PRINTER_ATTR_DRIVER_NAME));
403	if (driverName.Length() <= 0)
404		return BPath();
405
406	directory_which directories[] = {
407		B_USER_NONPACKAGED_ADDONS_DIRECTORY,
408		B_USER_ADDONS_DIRECTORY,
409		B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
410		B_SYSTEM_ADDONS_DIRECTORY
411	};
412
413	BPath path;
414	driverName.Prepend("Print/");
415	for (int32 i = 0; i < sizeof(directories) / sizeof(directories[0]); ++i) {
416		if (find_directory(directories[i], &path) == B_OK) {
417			path.Append(driverName.String());
418
419			BEntry driver(path.Path());
420			if (driver.InitCheck() == B_OK && driver.Exists() && driver.IsFile())
421				return path;
422		}
423	}
424	return BPath();
425}
426
427
428image_id
429BPrinter::_LoadDriver() const
430{
431	BPath driverPath(_DriverPath());
432	if (driverPath.InitCheck() != B_OK)
433		return -1;
434
435	return load_add_on(driverPath.Path());
436}
437
438
439void
440BPrinter::_AddPrinterName(BMessage& settings)
441{
442	settings.RemoveName(PSRV_FIELD_CURRENT_PRINTER);
443	settings.AddString(PSRV_FIELD_CURRENT_PRINTER, Name());
444}
445
446
447BString
448BPrinter::_ReadAttribute(const char* attribute) const
449{
450	BString value;
451
452	BDirectory spoolDir(&fPrinterEntryRef);
453	if (spoolDir.InitCheck() == B_OK)
454		spoolDir.ReadAttrString(attribute, &value);
455
456	return value;
457}
458
459
460	}	// namespace Print
461}	// namespace BPrivate
462