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