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