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
19 namespace 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
BPrinter()43 BPrinter::BPrinter()
44 : fListener(NULL)
45 {
46 memset(&fPrinterEntryRef, 0, sizeof(entry_ref));
47 }
48
49
BPrinter(const BEntry & entry)50 BPrinter::BPrinter(const BEntry& entry)
51 : fListener(NULL)
52 {
53 SetTo(entry);
54 }
55
56
BPrinter(const BPrinter & printer)57 BPrinter::BPrinter(const BPrinter& printer)
58 {
59 *this = printer;
60 }
61
62
BPrinter(const node_ref & nodeRef)63 BPrinter::BPrinter(const node_ref& nodeRef)
64 : fListener(NULL)
65 {
66 SetTo(nodeRef);
67 }
68
69
BPrinter(const entry_ref & entryRef)70 BPrinter::BPrinter(const entry_ref& entryRef)
71 : fListener(NULL)
72 , fPrinterEntryRef(entryRef)
73 {
74 }
75
76
BPrinter(const BDirectory & directory)77 BPrinter::BPrinter(const BDirectory& directory)
78 : fListener(NULL)
79 {
80 SetTo(directory);
81 }
82
83
~BPrinter()84 BPrinter::~BPrinter()
85 {
86 StopWatching();
87 }
88
89
90 status_t
SetTo(const BEntry & entry)91 BPrinter::SetTo(const BEntry& entry)
92 {
93 StopWatching();
94 entry.GetRef(&fPrinterEntryRef);
95
96 return InitCheck();
97 }
98
99
100 status_t
SetTo(const node_ref & nodeRef)101 BPrinter::SetTo(const node_ref& nodeRef)
102 {
103 SetTo(BDirectory(&nodeRef));
104 return InitCheck();
105 }
106
107
108 status_t
SetTo(const entry_ref & entryRef)109 BPrinter::SetTo(const entry_ref& entryRef)
110 {
111 StopWatching();
112 fPrinterEntryRef = entryRef;
113
114 return InitCheck();
115 }
116
117
118 status_t
SetTo(const BDirectory & directory)119 BPrinter::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
131 void
Unset()132 BPrinter::Unset()
133 {
134 StopWatching();
135 memset(&fPrinterEntryRef, 0, sizeof(entry_ref));
136 }
137
138
139 bool
IsValid() const140 BPrinter::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
157 status_t
InitCheck() const158 BPrinter::InitCheck() const
159 {
160 BDirectory spoolDir(&fPrinterEntryRef);
161 return spoolDir.InitCheck();
162 }
163
164
165 bool
IsFree() const166 BPrinter::IsFree() const
167 {
168 return (State() == "free");
169 }
170
171
172 bool
IsDefault() const173 BPrinter::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
186 bool
IsShareable() const187 BPrinter::IsShareable() const
188 {
189 if (Name() == "Preview")
190 return true;
191
192 return false;
193 }
194
195
196 BString
Name() const197 BPrinter::Name() const
198 {
199 return _ReadAttribute(PSRV_PRINTER_ATTR_PRINTER_NAME);
200 }
201
202
203 BString
State() const204 BPrinter::State() const
205 {
206 return _ReadAttribute(PSRV_PRINTER_ATTR_STATE);
207 }
208
209
210 BString
Driver() const211 BPrinter::Driver() const
212 {
213 return _ReadAttribute(PSRV_PRINTER_ATTR_DRIVER_NAME);
214 }
215
216
217 BString
Comments() const218 BPrinter::Comments() const
219 {
220 return _ReadAttribute(PSRV_PRINTER_ATTR_COMMENTS);
221 }
222
223
224 BString
Transport() const225 BPrinter::Transport() const
226 {
227 return _ReadAttribute(PSRV_PRINTER_ATTR_TRANSPORT);
228 }
229
230
231 BString
TransportAddress() const232 BPrinter::TransportAddress() const
233 {
234 return _ReadAttribute(PSRV_PRINTER_ATTR_TRANSPORT_ADDRESS);
235 }
236
237
238 status_t
DefaultSettings(BMessage & settings)239 BPrinter::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
264 status_t
StartWatching(const BMessenger & listener)265 BPrinter::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
284 void
StopWatching()285 BPrinter::StopWatching()
286 {
287 if (fListener) {
288 stop_watching(*fListener);
289 delete fListener;
290 fListener = NULL;
291 }
292 }
293
294
295 BPrinter&
operator =(const BPrinter & printer)296 BPrinter::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
308 bool
operator ==(const BPrinter & printer) const309 BPrinter::operator==(const BPrinter& printer) const
310 {
311 return (fPrinterEntryRef == printer.fPrinterEntryRef);
312 }
313
314
315 bool
operator !=(const BPrinter & printer) const316 BPrinter::operator!=(const BPrinter& printer) const
317 {
318 return (fPrinterEntryRef != printer.fPrinterEntryRef);
319 }
320
321
322 status_t
_Configure() const323 BPrinter::_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
347 status_t
_ConfigureJob(BMessage & settings)348 BPrinter::_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
373 status_t
_ConfigurePage(BMessage & settings)374 BPrinter::_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
399 BPath
_DriverPath() const400 BPrinter::_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
428 image_id
_LoadDriver() const429 BPrinter::_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
439 void
_AddPrinterName(BMessage & settings)440 BPrinter::_AddPrinterName(BMessage& settings)
441 {
442 settings.RemoveName(PSRV_FIELD_CURRENT_PRINTER);
443 settings.AddString(PSRV_FIELD_CURRENT_PRINTER, Name());
444 }
445
446
447 BString
_ReadAttribute(const char * attribute) const448 BPrinter::_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