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