1 /* 2 * Copyright 2002-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Tyler Dauwalder 7 * Axel Dörfler, axeld@pinc-software.de 8 */ 9 10 11 #include <mime/Database.h> 12 13 #include <mime/database_access.h> 14 #include <mime/database_support.h> 15 #include <storage_support.h> 16 17 #include <Application.h> 18 #include <Bitmap.h> 19 #include <DataIO.h> 20 #include <Directory.h> 21 #include <Entry.h> 22 #include <Locker.h> 23 #include <Message.h> 24 #include <MimeType.h> 25 #include <Node.h> 26 #include <Path.h> 27 #include <String.h> 28 #include <TypeConstants.h> 29 30 #include <fs_attr.h> 31 32 #include <iostream> 33 #include <new> 34 #include <stdio.h> 35 #include <string> 36 37 38 //#define DBG(x) x 39 #define DBG(x) 40 #define OUT printf 41 42 43 namespace BPrivate { 44 namespace Storage { 45 namespace Mime { 46 47 /*! 48 \class Database 49 \brief Mime::Database is the master of the MIME data base. 50 51 All write and non-atomic read accesses are carried out by this class. 52 53 \note No error checking (other than checks for NULL pointers) is performed 54 by this class on the mime type strings passed to it. It's assumed 55 that this sort of checking has been done beforehand. 56 */ 57 58 // constructor 59 /*! \brief Creates and initializes a Mime::Database object. 60 */ 61 Database::Database() 62 : fStatus(B_NO_INIT) 63 { 64 // Do some really minor error checking 65 BEntry entry(kDatabaseDir.c_str()); 66 fStatus = entry.Exists() ? B_OK : B_BAD_VALUE; 67 } 68 69 // destructor 70 /*! \brief Frees all resources associated with this object. 71 */ 72 Database::~Database() 73 { 74 } 75 76 // InitCheck 77 /*! \brief Returns the initialization status of the object. 78 \return 79 - B_OK: success 80 - "error code": failure 81 */ 82 status_t 83 Database::InitCheck() const 84 { 85 return fStatus; 86 } 87 88 // Install 89 /*! \brief Installs the given type in the database 90 \note The R5 version of this call returned an unreliable result if the 91 MIME type was already installed. Ours simply returns B_OK. 92 \param type Pointer to a NULL-terminated string containing the MIME type of interest 93 \param decsription Pointer to a NULL-terminated string containing the new long description 94 \return 95 - B_OK: success 96 - B_FILE_EXISTS: the type is already installed 97 - "error code": failure 98 */ 99 status_t 100 Database::Install(const char *type) 101 { 102 if (type == NULL) 103 return B_BAD_VALUE; 104 105 BEntry entry; 106 status_t err = entry.SetTo(type_to_filename(type).c_str()); 107 if (!err) { 108 if (entry.Exists()) 109 err = B_FILE_EXISTS; 110 else { 111 bool didCreate = false; 112 BNode node; 113 err = open_or_create_type(type, &node, &didCreate); 114 if (!err && didCreate) { 115 fInstalledTypes.AddType(type); 116 _SendInstallNotification(type); 117 } 118 } 119 } 120 return err; 121 } 122 123 // Delete 124 /*! \brief Removes the given type from the database 125 \param type Pointer to a NULL-terminated string containing the MIME type of interest 126 \return 127 - B_OK: success 128 - "error code": failure 129 */ 130 status_t 131 Database::Delete(const char *type) 132 { 133 if (type == NULL) 134 return B_BAD_VALUE; 135 136 // Open the type 137 BEntry entry; 138 status_t status = entry.SetTo(type_to_filename(type).c_str()); 139 if (status != B_OK) 140 return status; 141 142 // Remove it 143 if (entry.IsDirectory()) { 144 // We need to remove all files in this directory 145 BDirectory directory(&entry); 146 if (directory.InitCheck() == B_OK) { 147 size_t length = strlen(type); 148 char subType[B_PATH_NAME_LENGTH]; 149 memcpy(subType, type, length); 150 subType[length++] = '/'; 151 152 BEntry subEntry; 153 while (directory.GetNextEntry(&subEntry) == B_OK) { 154 // Construct MIME type and remove it 155 if (subEntry.GetName(subType + length) == B_OK) { 156 status = Delete(subType); 157 if (status != B_OK) 158 return status; 159 } 160 } 161 } 162 } 163 164 status = entry.Remove(); 165 166 if (status == B_OK) { 167 // Notify the installed types database 168 fInstalledTypes.RemoveType(type); 169 // Notify the supporting apps database 170 fSupportingApps.DeleteSupportedTypes(type, true); 171 // Notify the monitor service 172 _SendDeleteNotification(type); 173 } 174 175 return status; 176 } 177 178 179 status_t 180 Database::_SetStringValue(const char *type, int32 what, const char* attribute, 181 type_code attributeType, size_t maxLength, const char *value) 182 { 183 size_t length = value != NULL ? strlen(value) : 0; 184 if (type == NULL || value == NULL || length >= maxLength) 185 return B_BAD_VALUE; 186 187 char oldValue[maxLength]; 188 status_t status = read_mime_attr(type, attribute, oldValue, 189 maxLength, attributeType); 190 if (status >= B_OK && !strcmp(value, oldValue)) { 191 // nothing has changed, no need to write back the data 192 return B_OK; 193 } 194 195 bool didCreate = false; 196 status = write_mime_attr(type, attribute, value, length + 1, 197 attributeType, &didCreate); 198 199 if (status == B_OK) { 200 if (didCreate) 201 _SendInstallNotification(type); 202 203 _SendMonitorUpdate(what, type, B_META_MIME_MODIFIED); 204 } 205 206 return status; 207 } 208 209 210 // SetAppHint 211 /*! \brief Sets the application hint for the given MIME type 212 \param type Pointer to a NULL-terminated string containing the MIME type of interest 213 \param decsription Pointer to an entry_ref containing the location of an application 214 that should be used when launching an application with this signature. 215 */ 216 status_t 217 Database::SetAppHint(const char *type, const entry_ref *ref) 218 { 219 DBG(OUT("Database::SetAppHint()\n")); 220 221 if (type == NULL || ref == NULL) 222 return B_BAD_VALUE; 223 224 BPath path; 225 status_t status = path.SetTo(ref); 226 if (status < B_OK) 227 return status; 228 229 return _SetStringValue(type, B_APP_HINT_CHANGED, kAppHintAttr, 230 kAppHintType, B_PATH_NAME_LENGTH, path.Path()); 231 } 232 233 // SetAttrInfo 234 /*! \brief Stores a BMessage describing the format of attributes typically associated with 235 files of the given MIME type 236 237 See BMimeType::SetAttrInfo() for description of the expected message format. 238 239 The \c BMessage::what value is ignored. 240 241 \param info Pointer to a pre-allocated and properly formatted BMessage containing 242 information about the file attributes typically associated with the 243 MIME type. 244 \return 245 - \c B_OK: Success 246 - "error code": Failure 247 */ 248 status_t 249 Database::SetAttrInfo(const char *type, const BMessage *info) 250 { 251 DBG(OUT("Database::SetAttrInfo()\n")); 252 253 if (type == NULL || info == NULL) 254 return B_BAD_VALUE; 255 256 bool didCreate = false; 257 status_t status = write_mime_attr_message(type, kAttrInfoAttr, info, &didCreate); 258 if (status == B_OK) { 259 if (didCreate) 260 _SendInstallNotification(type); 261 _SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_MODIFIED); 262 } 263 264 return status; 265 } 266 267 268 // SetShortDescription 269 /*! \brief Sets the short description for the given MIME type 270 \param type Pointer to a NULL-terminated string containing the MIME type of interest 271 \param decsription Pointer to a NULL-terminated string containing the new short description 272 */ 273 status_t 274 Database::SetShortDescription(const char *type, const char *description) 275 { 276 DBG(OUT("Database::SetShortDescription()\n")); 277 278 return _SetStringValue(type, B_SHORT_DESCRIPTION_CHANGED, kShortDescriptionAttr, 279 kShortDescriptionType, B_MIME_TYPE_LENGTH, description); 280 } 281 282 // SetLongDescription 283 /*! \brief Sets the long description for the given MIME type 284 \param type Pointer to a NULL-terminated string containing the MIME type of interest 285 \param decsription Pointer to a NULL-terminated string containing the new long description 286 */ 287 status_t 288 Database::SetLongDescription(const char *type, const char *description) 289 { 290 DBG(OUT("Database::SetLongDescription()\n")); 291 292 size_t length = description != NULL ? strlen(description) : 0; 293 if (type == NULL || description == NULL || length >= B_MIME_TYPE_LENGTH) 294 return B_BAD_VALUE; 295 296 return _SetStringValue(type, B_LONG_DESCRIPTION_CHANGED, kLongDescriptionAttr, 297 kLongDescriptionType, B_MIME_TYPE_LENGTH, description); 298 } 299 300 301 /*! 302 \brief Sets the list of filename extensions associated with the MIME type 303 304 The list of extensions is given in a pre-allocated BMessage pointed to by 305 the \c extensions parameter. Please see BMimeType::SetFileExtensions() 306 for a description of the expected message format. 307 308 \param extensions Pointer to a pre-allocated, properly formatted BMessage containing 309 the new list of file extensions to associate with this MIME type. 310 \return 311 - \c B_OK: Success 312 - "error code": Failure 313 */ 314 status_t 315 Database::SetFileExtensions(const char *type, const BMessage *extensions) 316 { 317 DBG(OUT("Database::SetFileExtensions()\n")); 318 319 if (type == NULL || extensions == NULL) 320 return B_BAD_VALUE; 321 322 bool didCreate = false; 323 status_t status = write_mime_attr_message(type, kFileExtensionsAttr, 324 extensions, &didCreate); 325 326 if (status == B_OK) { 327 if (didCreate) 328 _SendInstallNotification(type); 329 _SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type, B_META_MIME_MODIFIED); 330 } 331 332 return status; 333 } 334 335 336 /*! 337 \brief Sets the icon for the given mime type 338 339 This is the version I would have used if I could have gotten a BBitmap 340 to the registrar somehow. Since R5::BBitmap::Instantiate is causing a 341 violent crash, I've copied most of the icon color conversion code into 342 Mime::get_icon_data() so BMimeType::SetIcon() can get at it. 343 344 Once we have a sufficiently complete OBOS::BBitmap implementation, we 345 ought to be able to use this version of SetIcon() again. At that point, 346 I'll add some real documentation. 347 */ 348 status_t 349 Database::SetIcon(const char *type, const void *data, size_t dataSize, 350 icon_size which) 351 { 352 return SetIconForType(type, NULL, data, dataSize, which); 353 } 354 355 // SetIconForType 356 /*! \brief Sets the large or mini icon used by an application of this type for 357 files of the given type. 358 359 The type of the \c BMimeType object is not required to actually be a subtype of 360 \c "application/"; that is the intended use however, and application-specific 361 icons are not expected to be present for non-application types. 362 363 The bitmap data pointed to by \c data must be of the proper size (\c 32x32 364 for \c B_LARGE_ICON, \c 16x16 for \c B_MINI_ICON) and the proper color 365 space (B_CMAP8). 366 367 \param type The MIME type 368 \param fileType The MIME type whose custom icon you wish to set. 369 \param data Pointer to an array of bitmap data of proper dimensions and color depth 370 \param dataSize The length of the array pointed to by \c data 371 \param size The size icon you're expecting (\c B_LARGE_ICON or \c B_MINI_ICON) 372 \return 373 - \c B_OK: Success 374 - "error code": Failure 375 376 */ 377 status_t 378 Database::SetIconForType(const char *type, const char *fileType, 379 const void *data, size_t dataSize, icon_size which) 380 { 381 DBG(OUT("Database::SetIconForType()\n")); 382 383 if (type == NULL || data == NULL) 384 return B_BAD_VALUE; 385 386 int32 attrType = 0; 387 388 // Figure out what kind of data we *should* have 389 switch (which) { 390 case B_MINI_ICON: 391 attrType = kMiniIconType; 392 break; 393 case B_LARGE_ICON: 394 attrType = kLargeIconType; 395 break; 396 397 default: 398 return B_BAD_VALUE; 399 } 400 401 size_t attrSize = (size_t)which * (size_t)which; 402 // Double check the data we've been given 403 if (dataSize != attrSize) 404 return B_BAD_VALUE; 405 406 // Construct our attribute name 407 std::string attr; 408 if (fileType) { 409 attr = (which == B_MINI_ICON 410 ? kMiniIconAttrPrefix : kLargeIconAttrPrefix) 411 + BPrivate::Storage::to_lower(fileType); 412 } else 413 attr = which == B_MINI_ICON ? kMiniIconAttr : kLargeIconAttr; 414 415 // Write the icon data 416 BNode node; 417 bool didCreate = false; 418 419 status_t err = open_or_create_type(type, &node, &didCreate); 420 if (!err && didCreate) 421 _SendInstallNotification(type); 422 423 if (!err) 424 err = node.WriteAttr(attr.c_str(), attrType, 0, data, attrSize); 425 if (err >= 0) 426 err = err == (ssize_t)attrSize ? (status_t)B_OK : (status_t)B_FILE_ERROR; 427 if (!err) { 428 if (fileType) { 429 _SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType, 430 (which == B_LARGE_ICON), B_META_MIME_MODIFIED); 431 } else { 432 _SendMonitorUpdate(B_ICON_CHANGED, type, (which == B_LARGE_ICON), 433 B_META_MIME_MODIFIED); 434 } 435 } 436 return err; 437 } 438 439 // SetPreferredApp 440 /*! \brief Sets the signature of the preferred application for the given app verb 441 442 Currently, the only supported app verb is \c B_OPEN 443 \param type Pointer to a NULL-terminated string containing the MIME type of interest 444 \param signature Pointer to a NULL-terminated string containing the MIME signature 445 of the new preferred application 446 \param verb \c app_verb action for which the new preferred application is applicable 447 */ 448 status_t 449 Database::SetPreferredApp(const char *type, const char *signature, app_verb verb) 450 { 451 DBG(OUT("Database::SetPreferredApp()\n")); 452 453 // TODO: use "verb" some day! 454 455 return _SetStringValue(type, B_PREFERRED_APP_CHANGED, kPreferredAppAttr, 456 kPreferredAppType, B_MIME_TYPE_LENGTH, signature); 457 } 458 459 // SetSnifferRule 460 /*! \brief Sets the mime sniffer rule for the given mime type 461 */ 462 status_t 463 Database::SetSnifferRule(const char *type, const char *rule) 464 { 465 DBG(OUT("Database::SetSnifferRule()\n")); 466 467 if (type == NULL || rule == NULL) 468 return B_BAD_VALUE; 469 470 bool didCreate = false; 471 status_t status = write_mime_attr(type, kSnifferRuleAttr, rule, strlen(rule) + 1, 472 kSnifferRuleType, &didCreate); 473 474 if (status == B_OK) 475 status = fSnifferRules.SetSnifferRule(type, rule); 476 477 if (status == B_OK) { 478 if (didCreate) 479 _SendInstallNotification(type); 480 _SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type, B_META_MIME_MODIFIED); 481 } 482 483 return status; 484 } 485 486 // SetSupportedTypes 487 /*! \brief Sets the list of MIME types supported by the MIME type and 488 syncs the internal supporting apps database either partially or 489 completely. 490 491 Please see BMimeType::SetSupportedTypes() for details. 492 \param type The mime type of interest 493 \param types The supported types to be assigned to the file. 494 \param syncAll \c true to also synchronize the previously supported 495 types, \c false otherwise. 496 \return 497 - \c B_OK: success 498 - other error codes: failure 499 */ 500 status_t 501 Database::SetSupportedTypes(const char *type, const BMessage *types, bool fullSync) 502 { 503 DBG(OUT("Database::SetSupportedTypes()\n")); 504 505 if (type == NULL || types == NULL) 506 return B_BAD_VALUE; 507 508 // Install the types 509 const char *supportedType; 510 for (int32 i = 0; types->FindString("types", i, &supportedType) == B_OK; i++) { 511 if (!is_installed(supportedType)) { 512 if (Install(supportedType) != B_OK) 513 break; 514 515 // Since the type has been introduced by this application 516 // we take the liberty and make it the preferred handler 517 // for them, too. 518 SetPreferredApp(supportedType, type, B_OPEN); 519 } 520 } 521 522 // Write the attr 523 bool didCreate = false; 524 status_t status = write_mime_attr_message(type, kSupportedTypesAttr, types, 525 &didCreate); 526 527 // Notify the monitor if we created the type when we opened it 528 if (status == B_OK && didCreate) 529 _SendInstallNotification(type); 530 531 // Update the supporting apps map 532 if (status == B_OK) 533 status = fSupportingApps.SetSupportedTypes(type, types, fullSync); 534 535 // Notify the monitor 536 if (status == B_OK) 537 _SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type, B_META_MIME_MODIFIED); 538 539 return status; 540 } 541 542 543 // GetInstalledSupertypes 544 /*! \brief Fetches a BMessage listing all the MIME supertypes currently 545 installed in the MIME database. 546 547 The types are copied into the \c "super_types" field of the passed-in \c BMessage. 548 The \c BMessage must be pre-allocated. 549 550 \param super_types Pointer to a pre-allocated \c BMessage into which the 551 MIME supertypes will be copied. 552 \return 553 - \c B_OK: Success 554 - "error code": Failure 555 */ 556 status_t 557 Database::GetInstalledSupertypes(BMessage *supertypes) 558 { 559 return fInstalledTypes.GetInstalledSupertypes(supertypes); 560 } 561 562 // GetInstalledTypes 563 /*! \brief Fetches a BMessage listing all the MIME types currently installed 564 in the MIME database. 565 566 The types are copied into the \c "types" field of the passed-in \c BMessage. 567 The \c BMessage must be pre-allocated. 568 569 \param types Pointer to a pre-allocated \c BMessage into which the 570 MIME types will be copied. 571 \return 572 - \c B_OK: Success 573 - "error code": Failure 574 */ 575 status_t 576 Database::GetInstalledTypes(BMessage *types) 577 { 578 return fInstalledTypes.GetInstalledTypes(types); 579 } 580 581 // GetInstalledTypes 582 /*! \brief Fetches a BMessage listing all the MIME subtypes of the given 583 supertype currently installed in the MIME database. 584 585 The types are copied into the \c "types" field of the passed-in \c BMessage. 586 The \c BMessage must be pre-allocated. 587 588 \param super_type Pointer to a string containing the MIME supertype whose 589 subtypes you wish to retrieve. 590 \param subtypes Pointer to a pre-allocated \c BMessage into which the appropriate 591 MIME subtypes will be copied. 592 \return 593 - \c B_OK: Success 594 - "error code": Failure 595 */ 596 status_t 597 Database::GetInstalledTypes(const char *supertype, BMessage *subtypes) 598 { 599 return fInstalledTypes.GetInstalledTypes(supertype, subtypes); 600 } 601 602 // GetSupportingApps 603 /*! \brief Fetches a \c BMessage containing a list of MIME signatures of 604 applications that are able to handle files of this MIME type. 605 606 Please see BMimeType::GetSupportingApps() for more details. 607 */ 608 status_t 609 Database::GetSupportingApps(const char *type, BMessage *signatures) 610 { 611 return fSupportingApps.GetSupportingApps(type, signatures); 612 } 613 614 // GetAssociatedTypes 615 /*! \brief Returns a list of mime types associated with the given file extension 616 617 Please see BMimeType::GetAssociatedTypes() for more details. 618 */ 619 status_t 620 Database::GetAssociatedTypes(const char *extension, BMessage *types) 621 { 622 return B_ERROR; 623 } 624 625 // GuessMimeType 626 /*! \brief Guesses a MIME type for the entry referred to by the given 627 \c entry_ref. 628 629 This version of GuessMimeType() combines the features of the other 630 versions, plus adds a few tricks of its own: 631 - If the entry is a meta mime entry (i.e. has a \c "META:TYPE" attribute), 632 the type returned is \c "application/x-vnd.be-meta-mime". 633 - If the entry is a directory, the type returned is 634 \c "application/x-vnd.be-directory". 635 - If the entry is a symlink, the type returned is 636 \c "application/x-vnd.be-symlink". 637 - If the entry is a regular file, the file data is sniffed and, the 638 type returned is the mime type with the matching rule of highest 639 priority. 640 - If sniffing fails, the filename is checked for known extensions. 641 - If the extension check fails, the type returned is 642 \c "application/octet-stream". 643 644 \param ref Pointer to the entry_ref referring to the entry. 645 \param type Pointer to a pre-allocated BString which is set to the 646 resulting MIME type. 647 \return 648 - \c B_OK: success (even if the guess returned is "application/octet-stream") 649 - other error code: failure 650 */ 651 status_t 652 Database::GuessMimeType(const entry_ref *ref, BString *result) 653 { 654 if (ref == NULL || result == NULL) 655 return B_BAD_VALUE; 656 657 BNode node; 658 struct stat statData; 659 status_t status = node.SetTo(ref); 660 if (status < B_OK) 661 return status; 662 663 attr_info info; 664 if (node.GetAttrInfo(kTypeAttr, &info) == B_OK) { 665 // Check for a META:TYPE attribute 666 result->SetTo(kMetaMimeType); 667 return B_OK; 668 } 669 670 // See if we have a directory, a symlink, or a vanilla file 671 status = node.GetStat(&statData); 672 if (status < B_OK) 673 return status; 674 675 if (S_ISDIR(statData.st_mode)) { 676 // Directory 677 result->SetTo(kDirectoryType); 678 } else if (S_ISLNK(statData.st_mode)) { 679 // Symlink 680 result->SetTo(kSymlinkType); 681 } else if (S_ISREG(statData.st_mode)) { 682 // Vanilla file: sniff first 683 status = fSnifferRules.GuessMimeType(ref, result); 684 685 // If that fails, check extensions 686 if (status == kMimeGuessFailureError) 687 status = fAssociatedTypes.GuessMimeType(ref, result); 688 689 // If that fails, return the generic file type 690 if (status == kMimeGuessFailureError) { 691 result->SetTo(kGenericFileType); 692 status = B_OK; 693 } 694 } else { 695 // TODO: we could filter out devices, ... 696 return B_BAD_TYPE; 697 } 698 699 return status; 700 } 701 702 // GuessMimeType 703 /*! \brief Guesses a MIME type for the supplied chunk of data. 704 705 See \c SnifferRules::GuessMimeType(BPositionIO*, BString*) 706 for more details. 707 708 \param buffer Pointer to the data buffer. 709 \param length Size of the buffer in bytes. 710 \param type Pointer to a pre-allocated BString which is set to the 711 resulting MIME type. 712 \return 713 - \c B_OK: success 714 - error code: failure 715 */ 716 status_t 717 Database::GuessMimeType(const void *buffer, int32 length, BString *result) 718 { 719 if (buffer == NULL || result == NULL) 720 return B_BAD_VALUE; 721 722 status_t status = fSnifferRules.GuessMimeType(buffer, length, result); 723 if (status == kMimeGuessFailureError) { 724 result->SetTo(kGenericFileType); 725 return B_OK; 726 } 727 728 return status; 729 } 730 731 // GuessMimeType 732 /*! \brief Guesses a MIME type for the given filename. 733 734 Only the filename itself is taken into consideration (in particular its 735 name extension), not the entry or corresponding data it refers to (in fact, 736 an entry with that name need not exist at all. 737 738 \param filename The filename. 739 \param type Pointer to a pre-allocated BString which is set to the 740 resulting MIME type. 741 \return 742 - \c B_OK: success 743 - error code: failure 744 */ 745 status_t 746 Database::GuessMimeType(const char *filename, BString *result) 747 { 748 if (filename == NULL || result == NULL) 749 return B_BAD_VALUE; 750 751 status_t status = fAssociatedTypes.GuessMimeType(filename, result); 752 if (status == kMimeGuessFailureError) { 753 result->SetTo(kGenericFileType); 754 return B_OK; 755 } 756 757 return status; 758 } 759 760 761 /*! \brief Subscribes the given BMessenger to the MIME monitor service 762 763 Notification messages will be sent with a \c BMessage::what value 764 of \c B_META_MIME_CHANGED. Notification messages have the following 765 fields: 766 767 <table> 768 <tr> 769 <td> Name </td> 770 <td> Type </td> 771 <td> Description </td> 772 </tr> 773 <tr> 774 <td> \c be:type </td> 775 <td> \c B_STRING_TYPE </td> 776 <td> The MIME type that was changed </td> 777 </tr> 778 <tr> 779 <td> \c be:which </td> 780 <td> \c B_INT32_TYPE </td> 781 <td> Bitmask describing which attributes were changed (see below) </td> 782 </tr> 783 <tr> 784 <td> \c be:extra_type </td> 785 <td> \c B_STRING_TYPE </td> 786 <td> Additional MIME type string (applicable to B_ICON_FOR_TYPE_CHANGED notifications only)</td> 787 </tr> 788 <tr> 789 <td> \c be:large_icon </td> 790 <td> \c B_BOOL_TYPE </td> 791 <td> \c true if the large icon was changed, \c false if the small icon 792 was changed (applicable to B_ICON_[FOR_TYPE_]CHANGED updates only) </td> 793 </tr> 794 </table> 795 796 The \c be:which field of the message describes which attributes were updated, and 797 may be the bitwise \c OR of any of the following values: 798 799 <table> 800 <tr> 801 <td> Value </td> 802 <td> Triggered By </td> 803 </tr> 804 <tr> 805 <td> \c B_ICON_CHANGED </td> 806 <td> \c BMimeType::SetIcon() </td> 807 </tr> 808 <tr> 809 <td> \c B_PREFERRED_APP_CHANGED </td> 810 <td> \c BMimeType::SetPreferredApp() </td> 811 </tr> 812 <tr> 813 <td> \c B_ATTR_INFO_CHANGED </td> 814 <td> \c BMimeType::SetAttrInfo() </td> 815 </tr> 816 <tr> 817 <td> \c B_FILE_EXTENSIONS_CHANGED </td> 818 <td> \c BMimeType::SetFileExtensions() </td> 819 </tr> 820 <tr> 821 <td> \c B_SHORT_DESCRIPTION_CHANGED </td> 822 <td> \c BMimeType::SetShortDescription() </td> 823 </tr> 824 <tr> 825 <td> \c B_LONG_DESCRIPTION_CHANGED </td> 826 <td> \c BMimeType::SetLongDescription() </td> 827 </tr> 828 <tr> 829 <td> \c B_ICON_FOR_TYPE_CHANGED </td> 830 <td> \c BMimeType::SetIconForType() </td> 831 </tr> 832 <tr> 833 <td> \c B_APP_HINT_CHANGED </td> 834 <td> \c BMimeType::SetAppHint() </td> 835 </tr> 836 </table> 837 838 \param target The \c BMessenger to subscribe to the MIME monitor service 839 */ 840 status_t 841 Database::StartWatching(BMessenger target) 842 { 843 DBG(OUT("Database::StartWatching()\n")); 844 845 if (!target.IsValid()) 846 return B_BAD_VALUE; 847 848 fMonitorMessengers.insert(target); 849 return B_OK; 850 } 851 852 853 /*! 854 Unsubscribes the given BMessenger from the MIME monitor service 855 \param target The \c BMessenger to unsubscribe 856 */ 857 status_t 858 Database::StopWatching(BMessenger target) 859 { 860 DBG(OUT("Database::StopWatching()\n")); 861 862 if (!target.IsValid()) 863 return B_BAD_VALUE; 864 865 status_t status = fMonitorMessengers.find(target) != fMonitorMessengers.end() 866 ? (status_t)B_OK : (status_t)B_ENTRY_NOT_FOUND; 867 if (status == B_OK) 868 fMonitorMessengers.erase(target); 869 870 return status; 871 } 872 873 874 /*! \brief Deletes the app hint attribute for the given type 875 876 A \c B_APP_HINT_CHANGED notification is sent to the mime monitor service. 877 \param type The mime type of interest 878 \return 879 - B_OK: success 880 - B_ENTRY_NOT_FOUND: no such attribute existed 881 - "error code": failure 882 */ 883 status_t 884 Database::DeleteAppHint(const char *type) 885 { 886 status_t status = delete_attribute(type, kAppHintAttr); 887 if (status == B_OK) 888 _SendMonitorUpdate(B_APP_HINT_CHANGED, type, B_META_MIME_DELETED); 889 890 return status; 891 } 892 893 894 /*! \brief Deletes the attribute info attribute for the given type 895 896 A \c B_ATTR_INFO_CHANGED notification is sent to the mime monitor service. 897 \param type The mime type of interest 898 \return 899 - B_OK: success 900 - B_ENTRY_NOT_FOUND: no such attribute existed 901 - "error code": failure 902 */ 903 status_t 904 Database::DeleteAttrInfo(const char *type) 905 { 906 status_t status = delete_attribute(type, kAttrInfoAttr); 907 if (status == B_OK) 908 _SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_DELETED); 909 910 return status; 911 } 912 913 914 /*! \brief Deletes the short description attribute for the given type 915 916 A \c B_SHORT_DESCRIPTION_CHANGED notification is sent to the mime monitor service. 917 \param type The mime type of interest 918 \return 919 - B_OK: success 920 - B_ENTRY_NOT_FOUND: no such attribute existed 921 - "error code": failure 922 */ 923 status_t 924 Database::DeleteShortDescription(const char *type) 925 { 926 status_t status = delete_attribute(type, kShortDescriptionAttr); 927 if (status == B_OK) 928 _SendMonitorUpdate(B_SHORT_DESCRIPTION_CHANGED, type, B_META_MIME_DELETED); 929 930 return status; 931 } 932 933 934 /*! \brief Deletes the long description attribute for the given type 935 936 A \c B_LONG_DESCRIPTION_CHANGED notification is sent to the mime monitor service. 937 \param type The mime type of interest 938 \return 939 - B_OK: success 940 - B_ENTRY_NOT_FOUND: no such attribute existed 941 - "error code": failure 942 */ 943 status_t 944 Database::DeleteLongDescription(const char *type) 945 { 946 status_t status = delete_attribute(type, kLongDescriptionAttr); 947 if (status == B_OK) 948 _SendMonitorUpdate(B_LONG_DESCRIPTION_CHANGED, type, B_META_MIME_DELETED); 949 950 return status; 951 } 952 953 954 /*! \brief Deletes the associated file extensions attribute for the given type 955 956 A \c B_FILE_EXTENSIONS_CHANGED notification is sent to the mime monitor service. 957 \param type The mime type of interest 958 \return 959 - B_OK: success 960 - B_ENTRY_NOT_FOUND: no such attribute existed 961 - "error code": failure 962 */ 963 status_t 964 Database::DeleteFileExtensions(const char *type) 965 { 966 status_t status = delete_attribute(type, kFileExtensionsAttr); 967 if (status == B_OK) 968 _SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type, B_META_MIME_DELETED); 969 970 return status; 971 } 972 973 974 /*! \brief Deletes the icon of the given size for the given type 975 976 A \c B_ICON_CHANGED notification is sent to the mime monitor service. 977 \param type The mime type of interest 978 \param which The icon size of interest 979 \return 980 - B_OK: success 981 - B_ENTRY_NOT_FOUND: no such attribute existed 982 - "error code": failure 983 */ 984 status_t 985 Database::DeleteIcon(const char *type, icon_size which) 986 { 987 const char *attr = which == B_MINI_ICON ? kMiniIconAttr : kLargeIconAttr; 988 status_t status = delete_attribute(type, attr); 989 if (status == B_OK) 990 _SendMonitorUpdate(B_ICON_CHANGED, type, which, B_META_MIME_DELETED); 991 992 return status; 993 } 994 995 996 /*! \brief Deletes the icon of the given size associated with the given file 997 type for the given application signature. 998 999 (If this function seems confusing, please see BMimeType::GetIconForType() for a 1000 better description of what the *IconForType() functions are used for.) 1001 1002 A \c B_ICON_FOR_TYPE_CHANGED notification is sent to the mime monitor service. 1003 \param type The mime type of the application whose custom icon you are deleting. 1004 \param which The mime type for which you no longer wish \c type to have a custom icon. 1005 \param which The icon size of interest 1006 \return 1007 - B_OK: success 1008 - B_ENTRY_NOT_FOUND: no such attribute existed 1009 - "error code": failure 1010 */ 1011 status_t 1012 Database::DeleteIconForType(const char *type, const char *fileType, icon_size which) 1013 { 1014 if (fileType == NULL) 1015 return B_BAD_VALUE; 1016 1017 std::string attr = (which == B_MINI_ICON 1018 ? kMiniIconAttrPrefix : kLargeIconAttrPrefix) + BPrivate::Storage::to_lower(fileType); 1019 1020 status_t status = delete_attribute(type, attr.c_str()); 1021 if (status == B_OK) { 1022 _SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType, 1023 which == B_LARGE_ICON, B_META_MIME_DELETED); 1024 } 1025 1026 return status; 1027 } 1028 1029 // DeletePreferredApp 1030 //! Deletes the preferred app for the given app verb for the given type 1031 /*! A \c B_PREFERRED_APP_CHANGED notification is sent to the mime monitor service. 1032 \param type The mime type of interest 1033 \param which The app verb of interest 1034 \return 1035 - B_OK: success 1036 - B_ENTRY_NOT_FOUND: no such attribute existed 1037 - "error code": failure 1038 */ 1039 status_t 1040 Database::DeletePreferredApp(const char *type, app_verb verb) 1041 { 1042 status_t status; 1043 1044 switch (verb) { 1045 case B_OPEN: 1046 status = delete_attribute(type, kPreferredAppAttr); 1047 break; 1048 1049 default: 1050 return B_BAD_VALUE; 1051 } 1052 1053 /*! \todo The R5 monitor makes no note of which app_verb value was updated. If 1054 additional app_verb values besides \c B_OPEN are someday added, the format 1055 of the MIME monitor messages will need to be augmented. 1056 */ 1057 if (status == B_OK) 1058 _SendMonitorUpdate(B_PREFERRED_APP_CHANGED, type, B_META_MIME_DELETED); 1059 1060 return status; 1061 } 1062 1063 // DeleteSnifferRule 1064 //! Deletes the sniffer rule for the given type 1065 /*! A \c B_SNIFFER_RULE_CHANGED notification is sent to the mime monitor service, 1066 and the corresponding rule is removed from the internal database of sniffer 1067 rules. 1068 \param type The mime type of interest 1069 \return 1070 - B_OK: success 1071 - B_ENTRY_NOT_FOUND: no such attribute existed 1072 - "error code": failure 1073 */ 1074 status_t 1075 Database::DeleteSnifferRule(const char *type) 1076 { 1077 status_t status = delete_attribute(type, kSnifferRuleAttr); 1078 if (status == B_OK) 1079 status = fSnifferRules.DeleteSnifferRule(type); 1080 if (status == B_OK) 1081 _SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type, B_META_MIME_DELETED); 1082 1083 return status; 1084 } 1085 1086 // DeleteSupportedTypes 1087 //! Deletes the supported types list for the given type 1088 /*! A \c B_SUPPORTED_TYPES_CHANGED notification is sent to the mime monitor service. 1089 If \c fullSync is \c true, the given type is removed from the internal list 1090 of supporting applictions for each previously supported type. If \c fullSync 1091 is \c false, the said removal will occur the next time SetSupportedTypes() or 1092 DeleteSupportedTypes() is called with a \c true \c fullSync paramter, or 1093 \c Delete() is called for the given type. 1094 \param type The mime type of interest 1095 \param fullSync Whether or not to remove the type as a supporting app for 1096 all previously supported types 1097 \return 1098 - B_OK: success 1099 - B_ENTRY_NOT_FOUND: no such attribute existed 1100 - "error code": failure 1101 */ 1102 status_t 1103 Database::DeleteSupportedTypes(const char *type, bool fullSync) 1104 { 1105 status_t status = delete_attribute(type, kSupportedTypesAttr); 1106 1107 // Update the supporting apps database. If fullSync is specified, 1108 // do so even if the supported types attribute didn't exist, as 1109 // stranded types *may* exist in the database due to previous 1110 // calls to {Set,Delete}SupportedTypes() with fullSync == false. 1111 if (status == B_OK) 1112 status = fSupportingApps.DeleteSupportedTypes(type, fullSync); 1113 else if (fullSync && status == B_ENTRY_NOT_FOUND) 1114 fSupportingApps.DeleteSupportedTypes(type, fullSync); 1115 1116 // Send a monitor notification 1117 if (status == B_OK) 1118 _SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type, B_META_MIME_DELETED); 1119 1120 return status; 1121 } 1122 1123 1124 //! \brief Sends a \c B_MIME_TYPE_CREATED notification to the mime monitor service 1125 status_t 1126 Database::_SendInstallNotification(const char *type) 1127 { 1128 return _SendMonitorUpdate(B_MIME_TYPE_CREATED, type, B_META_MIME_MODIFIED); 1129 } 1130 1131 1132 //! \brief Sends a \c B_MIME_TYPE_DELETED notification to the mime monitor service 1133 status_t 1134 Database::_SendDeleteNotification(const char *type) 1135 { 1136 // Tell the backend first 1137 return _SendMonitorUpdate(B_MIME_TYPE_DELETED, type, B_META_MIME_MODIFIED); 1138 } 1139 1140 // _SendMonitorUpdate 1141 /*! \brief Sends an update notification to all BMessengers that have 1142 subscribed to the MIME Monitor service 1143 \param type The MIME type that was updated 1144 \param which Bitmask describing which attribute was updated 1145 \param extraType The MIME type to which the change is applies 1146 \param largeIcon \true if the the large icon was updated, \false if the 1147 small icon was updated 1148 */ 1149 status_t 1150 Database::_SendMonitorUpdate(int32 which, const char *type, const char *extraType, 1151 bool largeIcon, int32 action) 1152 { 1153 BMessage msg(B_META_MIME_CHANGED); 1154 status_t err; 1155 1156 err = msg.AddInt32("be:which", which); 1157 if (!err) 1158 err = msg.AddString("be:type", type); 1159 if (!err) 1160 err = msg.AddString("be:extra_type", extraType); 1161 if (!err) 1162 err = msg.AddBool("be:large_icon", largeIcon); 1163 if (!err) 1164 err = msg.AddInt32("be:action", action); 1165 if (!err) 1166 err = _SendMonitorUpdate(msg); 1167 return err; 1168 } 1169 1170 // _SendMonitorUpdate 1171 /*! \brief Sends an update notification to all BMessengers that have 1172 subscribed to the MIME Monitor service 1173 \param type The MIME type that was updated 1174 \param which Bitmask describing which attribute was updated 1175 \param extraType The MIME type to which the change is applies 1176 */ 1177 status_t 1178 Database::_SendMonitorUpdate(int32 which, const char *type, const char *extraType, 1179 int32 action) 1180 { 1181 BMessage msg(B_META_MIME_CHANGED); 1182 1183 status_t err = msg.AddInt32("be:which", which); 1184 if (!err) 1185 err = msg.AddString("be:type", type); 1186 if (!err) 1187 err = msg.AddString("be:extra_type", extraType); 1188 if (!err) 1189 err = msg.AddInt32("be:action", action); 1190 if (!err) 1191 err = _SendMonitorUpdate(msg); 1192 return err; 1193 } 1194 1195 // _SendMonitorUpdate 1196 /*! \brief Sends an update notification to all BMessengers that have 1197 subscribed to the MIME Monitor service 1198 \param type The MIME type that was updated 1199 \param which Bitmask describing which attribute was updated 1200 \param largeIcon \true if the the large icon was updated, \false if the 1201 small icon was updated 1202 */ 1203 status_t 1204 Database::_SendMonitorUpdate(int32 which, const char *type, bool largeIcon, int32 action) 1205 { 1206 BMessage msg(B_META_MIME_CHANGED); 1207 1208 status_t err = msg.AddInt32("be:which", which); 1209 if (!err) 1210 err = msg.AddString("be:type", type); 1211 if (!err) 1212 err = msg.AddBool("be:large_icon", largeIcon); 1213 if (!err) 1214 err = msg.AddInt32("be:action", action); 1215 if (!err) 1216 err = _SendMonitorUpdate(msg); 1217 return err; 1218 } 1219 1220 // _SendMonitorUpdate 1221 /*! \brief Sends an update notification to all BMessengers that have 1222 subscribed to the MIME Monitor service 1223 \param type The MIME type that was updated 1224 \param which Bitmask describing which attribute was updated 1225 */ 1226 status_t 1227 Database::_SendMonitorUpdate(int32 which, const char *type, int32 action) 1228 { 1229 BMessage msg(B_META_MIME_CHANGED); 1230 1231 status_t err = msg.AddInt32("be:which", which); 1232 if (!err) 1233 err = msg.AddString("be:type", type); 1234 if (!err) 1235 err = msg.AddInt32("be:action", action); 1236 if (!err) 1237 err = _SendMonitorUpdate(msg); 1238 return err; 1239 } 1240 1241 // _SendMonitorUpdate 1242 /*! \brief Sends an update notification to all BMessengers that have subscribed to 1243 the MIME Monitor service 1244 \param BMessage A preformatted MIME monitor message to be sent to all subscribers 1245 */ 1246 status_t 1247 Database::_SendMonitorUpdate(BMessage &msg) 1248 { 1249 // DBG(OUT("Database::_SendMonitorUpdate(BMessage&)\n")); 1250 status_t err; 1251 std::set<BMessenger>::const_iterator i; 1252 for (i = fMonitorMessengers.begin(); i != fMonitorMessengers.end(); i++) { 1253 status_t err = (*i).SendMessage(&msg, (BHandler*)NULL); 1254 if (err) { 1255 DBG(OUT("Database::_SendMonitorUpdate(BMessage&): BMessenger::SendMessage failed, 0x%lx\n", err)); 1256 } 1257 } 1258 // DBG(OUT("Database::_SendMonitorUpdate(BMessage&) done\n")); 1259 err = B_OK; 1260 return err; 1261 } 1262 1263 } // namespace Mime 1264 } // namespace Storage 1265 } // namespace BPrivate 1266 1267