1 /* 2 * Copyright 2002-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Tyler Dauwalder 7 * Axel Dörfler, axeld@pinc-software.de 8 */ 9 10 11 #include <mime/Database.h> 12 13 #include <stdio.h> 14 #include <string> 15 16 #include <iostream> 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->OpenOrCreateType(type, node, &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 the icon for the given mime type 359 360 This is the version I would have used if I could have gotten a BBitmap 361 to the registrar somehow. Since R5::BBitmap::Instantiate is causing a 362 violent crash, I've copied most of the icon color conversion code into 363 Mime::get_icon_data() so BMimeType::SetIcon() can get at it. 364 365 Once we have a sufficiently complete OBOS::BBitmap implementation, we 366 ought to be able to use this version of SetIcon() again. At that point, 367 I'll add some real documentation. 368 */ 369 status_t 370 Database::SetIcon(const char *type, const void *data, size_t dataSize, 371 icon_size which) 372 { 373 return SetIconForType(type, NULL, data, dataSize, which); 374 } 375 376 status_t 377 Database::SetIcon(const char *type, const void *data, size_t dataSize) 378 { 379 return SetIconForType(type, NULL, data, dataSize); 380 } 381 382 // SetIconForType 383 /*! \brief Sets the large or mini icon used by an application of this type for 384 files of the given type. 385 386 The type of the \c BMimeType object is not required to actually be a subtype of 387 \c "application/"; that is the intended use however, and application-specific 388 icons are not expected to be present for non-application types. 389 390 The bitmap data pointed to by \c data must be of the proper size (\c 32x32 391 for \c B_LARGE_ICON, \c 16x16 for \c B_MINI_ICON) and the proper color 392 space (B_CMAP8). 393 394 \param type The MIME type 395 \param fileType The MIME type whose custom icon you wish to set. 396 \param data Pointer to an array of bitmap data of proper dimensions and color depth 397 \param dataSize The length of the array pointed to by \c data 398 \param size The size icon you're expecting (\c B_LARGE_ICON or \c B_MINI_ICON) 399 \return 400 - \c B_OK: Success 401 - "error code": Failure 402 403 */ 404 status_t 405 Database::SetIconForType(const char *type, const char *fileType, 406 const void *data, size_t dataSize, icon_size which) 407 { 408 DBG(OUT("Database::SetIconForType()\n")); 409 410 if (type == NULL || data == NULL) 411 return B_BAD_VALUE; 412 413 int32 attrType = 0; 414 415 // Figure out what kind of data we *should* have 416 switch (which) { 417 case B_MINI_ICON: 418 attrType = kMiniIconType; 419 break; 420 case B_LARGE_ICON: 421 attrType = kLargeIconType; 422 break; 423 424 default: 425 return B_BAD_VALUE; 426 } 427 428 size_t attrSize = (size_t)which * (size_t)which; 429 // Double check the data we've been given 430 if (dataSize != attrSize) 431 return B_BAD_VALUE; 432 433 // Construct our attribute name 434 std::string attr; 435 if (fileType) { 436 attr = (which == B_MINI_ICON 437 ? kMiniIconAttrPrefix : kLargeIconAttrPrefix) 438 + BPrivate::Storage::to_lower(fileType); 439 } else 440 attr = which == B_MINI_ICON ? kMiniIconAttr : kLargeIconAttr; 441 442 // Write the icon data 443 BNode node; 444 bool didCreate = false; 445 446 status_t err = fLocation->OpenOrCreateType(type, node, &didCreate); 447 if (err != B_OK) 448 return err; 449 450 if (!err) 451 err = node.WriteAttr(attr.c_str(), attrType, 0, data, attrSize); 452 if (err >= 0) 453 err = err == (ssize_t)attrSize ? (status_t)B_OK : (status_t)B_FILE_ERROR; 454 if (didCreate) { 455 _SendInstallNotification(type); 456 } else if (!err) { 457 if (fileType) { 458 _SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType, 459 (which == B_LARGE_ICON), B_META_MIME_MODIFIED); 460 } else { 461 _SendMonitorUpdate(B_ICON_CHANGED, type, 462 (which == B_LARGE_ICON), B_META_MIME_MODIFIED); 463 } 464 } 465 return err; 466 } 467 468 // SetIconForType 469 /*! \brief Sets the vector icon used by an application of this type for 470 files of the given type. 471 472 The type of the \c BMimeType object is not required to actually be a subtype of 473 \c "application/"; that is the intended use however, and application-specific 474 icons are not expected to be present for non-application types. 475 476 \param type The MIME type 477 \param fileType The MIME type whose custom icon you wish to set. 478 \param data Pointer to an array of vector data 479 \param dataSize The length of the array pointed to by \c data 480 \return 481 - \c B_OK: Success 482 - "error code": Failure 483 484 */ 485 status_t 486 Database::SetIconForType(const char *type, const char *fileType, 487 const void *data, size_t dataSize) 488 { 489 DBG(OUT("Database::SetIconForType()\n")); 490 491 if (type == NULL || data == NULL) 492 return B_BAD_VALUE; 493 494 int32 attrType = B_VECTOR_ICON_TYPE; 495 496 // Construct our attribute name 497 std::string attr; 498 if (fileType) { 499 attr = kIconAttrPrefix + BPrivate::Storage::to_lower(fileType); 500 } else 501 attr = kIconAttr; 502 503 // Write the icon data 504 BNode node; 505 bool didCreate = false; 506 507 status_t err = fLocation->OpenOrCreateType(type, node, &didCreate); 508 if (err != B_OK) 509 return err; 510 511 if (!err) 512 err = node.WriteAttr(attr.c_str(), attrType, 0, data, dataSize); 513 if (err >= 0) 514 err = err == (ssize_t)dataSize ? (status_t)B_OK : (status_t)B_FILE_ERROR; 515 if (didCreate) { 516 _SendInstallNotification(type); 517 } else if (!err) { 518 // TODO: extra notification for vector icons (currently 519 // passing "true" for B_LARGE_ICON)? 520 if (fileType) { 521 _SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType, 522 true, B_META_MIME_MODIFIED); 523 } else { 524 _SendMonitorUpdate(B_ICON_CHANGED, type, true, 525 B_META_MIME_MODIFIED); 526 } 527 } 528 return err; 529 } 530 531 // SetPreferredApp 532 /*! \brief Sets the signature of the preferred application for the given app verb 533 534 Currently, the only supported app verb is \c B_OPEN 535 \param type Pointer to a NULL-terminated string containing the MIME type of interest 536 \param signature Pointer to a NULL-terminated string containing the MIME signature 537 of the new preferred application 538 \param verb \c app_verb action for which the new preferred application is applicable 539 */ 540 status_t 541 Database::SetPreferredApp(const char *type, const char *signature, app_verb verb) 542 { 543 DBG(OUT("Database::SetPreferredApp()\n")); 544 545 // TODO: use "verb" some day! 546 547 return _SetStringValue(type, B_PREFERRED_APP_CHANGED, kPreferredAppAttr, 548 kPreferredAppType, B_MIME_TYPE_LENGTH, signature); 549 } 550 551 // SetSnifferRule 552 /*! \brief Sets the mime sniffer rule for the given mime type 553 */ 554 status_t 555 Database::SetSnifferRule(const char *type, const char *rule) 556 { 557 DBG(OUT("Database::SetSnifferRule()\n")); 558 559 if (type == NULL || rule == NULL) 560 return B_BAD_VALUE; 561 562 bool didCreate = false; 563 status_t status = fLocation->WriteAttribute(type, kSnifferRuleAttr, rule, 564 strlen(rule) + 1, kSnifferRuleType, &didCreate); 565 566 if (status == B_OK) 567 status = fSnifferRules.SetSnifferRule(type, rule); 568 569 if (didCreate) { 570 _SendInstallNotification(type); 571 } else if (status == B_OK) { 572 _SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type, 573 B_META_MIME_MODIFIED); 574 } 575 576 return status; 577 } 578 579 // SetSupportedTypes 580 /*! \brief Sets the list of MIME types supported by the MIME type and 581 syncs the internal supporting apps database either partially or 582 completely. 583 584 Please see BMimeType::SetSupportedTypes() for details. 585 \param type The mime type of interest 586 \param types The supported types to be assigned to the file. 587 \param syncAll \c true to also synchronize the previously supported 588 types, \c false otherwise. 589 \return 590 - \c B_OK: success 591 - other error codes: failure 592 */ 593 status_t 594 Database::SetSupportedTypes(const char *type, const BMessage *types, bool fullSync) 595 { 596 DBG(OUT("Database::SetSupportedTypes()\n")); 597 598 if (type == NULL || types == NULL) 599 return B_BAD_VALUE; 600 601 // Install the types 602 const char *supportedType; 603 for (int32 i = 0; types->FindString("types", i, &supportedType) == B_OK; i++) { 604 if (!fLocation->IsInstalled(supportedType)) { 605 if (Install(supportedType) != B_OK) 606 break; 607 608 // Since the type has been introduced by this application 609 // we take the liberty and make it the preferred handler 610 // for them, too. 611 SetPreferredApp(supportedType, type, B_OPEN); 612 } 613 } 614 615 // Write the attr 616 bool didCreate = false; 617 status_t status = fLocation->WriteMessageAttribute(type, 618 kSupportedTypesAttr, *types, &didCreate); 619 620 // Notify the monitor if we created the type when we opened it 621 if (status != B_OK) 622 return status; 623 624 // Update the supporting apps map 625 if (status == B_OK) 626 status = fSupportingApps.SetSupportedTypes(type, types, fullSync); 627 628 // Notify the monitor 629 if (didCreate) { 630 _SendInstallNotification(type); 631 } else if (status == B_OK) { 632 _SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type, 633 B_META_MIME_MODIFIED); 634 } 635 636 return status; 637 } 638 639 640 // GetInstalledSupertypes 641 /*! \brief Fetches a BMessage listing all the MIME supertypes currently 642 installed in the MIME database. 643 644 The types are copied into the \c "super_types" field of the passed-in \c BMessage. 645 The \c BMessage must be pre-allocated. 646 647 \param super_types Pointer to a pre-allocated \c BMessage into which the 648 MIME supertypes will be copied. 649 \return 650 - \c B_OK: Success 651 - "error code": Failure 652 */ 653 status_t 654 Database::GetInstalledSupertypes(BMessage *supertypes) 655 { 656 return fInstalledTypes.GetInstalledSupertypes(supertypes); 657 } 658 659 // GetInstalledTypes 660 /*! \brief Fetches a BMessage listing all the MIME types currently installed 661 in the MIME database. 662 663 The types are copied into the \c "types" field of the passed-in \c BMessage. 664 The \c BMessage must be pre-allocated. 665 666 \param types Pointer to a pre-allocated \c BMessage into which the 667 MIME types will be copied. 668 \return 669 - \c B_OK: Success 670 - "error code": Failure 671 */ 672 status_t 673 Database::GetInstalledTypes(BMessage *types) 674 { 675 return fInstalledTypes.GetInstalledTypes(types); 676 } 677 678 // GetInstalledTypes 679 /*! \brief Fetches a BMessage listing all the MIME subtypes of the given 680 supertype currently installed in the MIME database. 681 682 The types are copied into the \c "types" field of the passed-in \c BMessage. 683 The \c BMessage must be pre-allocated. 684 685 \param super_type Pointer to a string containing the MIME supertype whose 686 subtypes you wish to retrieve. 687 \param subtypes Pointer to a pre-allocated \c BMessage into which the appropriate 688 MIME subtypes will be copied. 689 \return 690 - \c B_OK: Success 691 - "error code": Failure 692 */ 693 status_t 694 Database::GetInstalledTypes(const char *supertype, BMessage *subtypes) 695 { 696 return fInstalledTypes.GetInstalledTypes(supertype, subtypes); 697 } 698 699 // GetSupportingApps 700 /*! \brief Fetches a \c BMessage containing a list of MIME signatures of 701 applications that are able to handle files of this MIME type. 702 703 Please see BMimeType::GetSupportingApps() for more details. 704 */ 705 status_t 706 Database::GetSupportingApps(const char *type, BMessage *signatures) 707 { 708 return fSupportingApps.GetSupportingApps(type, signatures); 709 } 710 711 // GetAssociatedTypes 712 /*! \brief Returns a list of mime types associated with the given file extension 713 714 Please see BMimeType::GetAssociatedTypes() for more details. 715 */ 716 status_t 717 Database::GetAssociatedTypes(const char *extension, BMessage *types) 718 { 719 return B_ERROR; 720 } 721 722 // GuessMimeType 723 /*! \brief Guesses a MIME type for the entry referred to by the given 724 \c entry_ref. 725 726 This version of GuessMimeType() combines the features of the other 727 versions, plus adds a few tricks of its own: 728 - If the entry is a meta mime entry (i.e. has a \c "META:TYPE" attribute), 729 the type returned is \c "application/x-vnd.be-meta-mime". 730 - If the entry is a directory, the type returned is 731 \c "application/x-vnd.be-directory". 732 - If the entry is a symlink, the type returned is 733 \c "application/x-vnd.be-symlink". 734 - If the entry is a regular file, the file data is sniffed and, the 735 type returned is the mime type with the matching rule of highest 736 priority. 737 - If sniffing fails, the filename is checked for known extensions. 738 - If the extension check fails, the type returned is 739 \c "application/octet-stream". 740 741 \param ref Pointer to the entry_ref referring to the entry. 742 \param type Pointer to a pre-allocated BString which is set to the 743 resulting MIME type. 744 \return 745 - \c B_OK: success (even if the guess returned is "application/octet-stream") 746 - other error code: failure 747 */ 748 status_t 749 Database::GuessMimeType(const entry_ref *ref, BString *result) 750 { 751 if (ref == NULL || result == NULL) 752 return B_BAD_VALUE; 753 754 BNode node; 755 struct stat statData; 756 status_t status = node.SetTo(ref); 757 if (status < B_OK) 758 return status; 759 760 attr_info info; 761 if (node.GetAttrInfo(kTypeAttr, &info) == B_OK) { 762 // Check for a META:TYPE attribute 763 result->SetTo(kMetaMimeType); 764 return B_OK; 765 } 766 767 // See if we have a directory, a symlink, or a vanilla file 768 status = node.GetStat(&statData); 769 if (status < B_OK) 770 return status; 771 772 if (S_ISDIR(statData.st_mode)) { 773 // Directory 774 result->SetTo(kDirectoryType); 775 } else if (S_ISLNK(statData.st_mode)) { 776 // Symlink 777 result->SetTo(kSymlinkType); 778 } else if (S_ISREG(statData.st_mode)) { 779 // Vanilla file: sniff first 780 status = fSnifferRules.GuessMimeType(ref, result); 781 782 // If that fails, check extensions 783 if (status == kMimeGuessFailureError) 784 status = fAssociatedTypes.GuessMimeType(ref, result); 785 786 // If that fails, return the generic file type 787 if (status == kMimeGuessFailureError) { 788 result->SetTo(kGenericFileType); 789 status = B_OK; 790 } 791 } else { 792 // TODO: we could filter out devices, ... 793 return B_BAD_TYPE; 794 } 795 796 return status; 797 } 798 799 // GuessMimeType 800 /*! \brief Guesses a MIME type for the supplied chunk of data. 801 802 See \c SnifferRules::GuessMimeType(BPositionIO*, BString*) 803 for more details. 804 805 \param buffer Pointer to the data buffer. 806 \param length Size of the buffer in bytes. 807 \param type Pointer to a pre-allocated BString which is set to the 808 resulting MIME type. 809 \return 810 - \c B_OK: success 811 - error code: failure 812 */ 813 status_t 814 Database::GuessMimeType(const void *buffer, int32 length, BString *result) 815 { 816 if (buffer == NULL || result == NULL) 817 return B_BAD_VALUE; 818 819 status_t status = fSnifferRules.GuessMimeType(buffer, length, result); 820 if (status == kMimeGuessFailureError) { 821 result->SetTo(kGenericFileType); 822 return B_OK; 823 } 824 825 return status; 826 } 827 828 // GuessMimeType 829 /*! \brief Guesses a MIME type for the given filename. 830 831 Only the filename itself is taken into consideration (in particular its 832 name extension), not the entry or corresponding data it refers to (in fact, 833 an entry with that name need not exist at all. 834 835 \param filename The filename. 836 \param type Pointer to a pre-allocated BString which is set to the 837 resulting MIME type. 838 \return 839 - \c B_OK: success 840 - error code: failure 841 */ 842 status_t 843 Database::GuessMimeType(const char *filename, BString *result) 844 { 845 if (filename == NULL || result == NULL) 846 return B_BAD_VALUE; 847 848 status_t status = fAssociatedTypes.GuessMimeType(filename, result); 849 if (status == kMimeGuessFailureError) { 850 result->SetTo(kGenericFileType); 851 return B_OK; 852 } 853 854 return status; 855 } 856 857 858 /*! \brief Subscribes the given BMessenger to the MIME monitor service 859 860 Notification messages will be sent with a \c BMessage::what value 861 of \c B_META_MIME_CHANGED. Notification messages have the following 862 fields: 863 864 <table> 865 <tr> 866 <td> Name </td> 867 <td> Type </td> 868 <td> Description </td> 869 </tr> 870 <tr> 871 <td> \c be:type </td> 872 <td> \c B_STRING_TYPE </td> 873 <td> The MIME type that was changed </td> 874 </tr> 875 <tr> 876 <td> \c be:which </td> 877 <td> \c B_INT32_TYPE </td> 878 <td> Bitmask describing which attributes were changed (see below) </td> 879 </tr> 880 <tr> 881 <td> \c be:extra_type </td> 882 <td> \c B_STRING_TYPE </td> 883 <td> Additional MIME type string (applicable to B_ICON_FOR_TYPE_CHANGED notifications only)</td> 884 </tr> 885 <tr> 886 <td> \c be:large_icon </td> 887 <td> \c B_BOOL_TYPE </td> 888 <td> \c true if the large icon was changed, \c false if the small icon 889 was changed (applicable to B_ICON_[FOR_TYPE_]CHANGED updates only) </td> 890 </tr> 891 </table> 892 893 The \c be:which field of the message describes which attributes were updated, and 894 may be the bitwise \c OR of any of the following values: 895 896 <table> 897 <tr> 898 <td> Value </td> 899 <td> Triggered By </td> 900 </tr> 901 <tr> 902 <td> \c B_ICON_CHANGED </td> 903 <td> \c BMimeType::SetIcon() </td> 904 </tr> 905 <tr> 906 <td> \c B_PREFERRED_APP_CHANGED </td> 907 <td> \c BMimeType::SetPreferredApp() </td> 908 </tr> 909 <tr> 910 <td> \c B_ATTR_INFO_CHANGED </td> 911 <td> \c BMimeType::SetAttrInfo() </td> 912 </tr> 913 <tr> 914 <td> \c B_FILE_EXTENSIONS_CHANGED </td> 915 <td> \c BMimeType::SetFileExtensions() </td> 916 </tr> 917 <tr> 918 <td> \c B_SHORT_DESCRIPTION_CHANGED </td> 919 <td> \c BMimeType::SetShortDescription() </td> 920 </tr> 921 <tr> 922 <td> \c B_LONG_DESCRIPTION_CHANGED </td> 923 <td> \c BMimeType::SetLongDescription() </td> 924 </tr> 925 <tr> 926 <td> \c B_ICON_FOR_TYPE_CHANGED </td> 927 <td> \c BMimeType::SetIconForType() </td> 928 </tr> 929 <tr> 930 <td> \c B_APP_HINT_CHANGED </td> 931 <td> \c BMimeType::SetAppHint() </td> 932 </tr> 933 </table> 934 935 \param target The \c BMessenger to subscribe to the MIME monitor service 936 */ 937 status_t 938 Database::StartWatching(BMessenger target) 939 { 940 DBG(OUT("Database::StartWatching()\n")); 941 942 if (!target.IsValid()) 943 return B_BAD_VALUE; 944 945 fMonitorMessengers.insert(target); 946 return B_OK; 947 } 948 949 950 /*! 951 Unsubscribes the given BMessenger from the MIME monitor service 952 \param target The \c BMessenger to unsubscribe 953 */ 954 status_t 955 Database::StopWatching(BMessenger target) 956 { 957 DBG(OUT("Database::StopWatching()\n")); 958 959 if (!target.IsValid()) 960 return B_BAD_VALUE; 961 962 status_t status = fMonitorMessengers.find(target) != fMonitorMessengers.end() 963 ? (status_t)B_OK : (status_t)B_ENTRY_NOT_FOUND; 964 if (status == B_OK) 965 fMonitorMessengers.erase(target); 966 967 return status; 968 } 969 970 971 /*! \brief Deletes the app hint attribute for the given type 972 973 A \c B_APP_HINT_CHANGED notification is sent to the mime monitor service. 974 \param type The mime type of interest 975 \return 976 - B_OK: success 977 - B_ENTRY_NOT_FOUND: no such attribute existed 978 - "error code": failure 979 */ 980 status_t 981 Database::DeleteAppHint(const char *type) 982 { 983 status_t status = fLocation->DeleteAttribute(type, kAppHintAttr); 984 if (status == B_OK) 985 _SendMonitorUpdate(B_APP_HINT_CHANGED, type, B_META_MIME_DELETED); 986 else if (status == B_ENTRY_NOT_FOUND) 987 status = B_OK; 988 989 return status; 990 } 991 992 993 /*! \brief Deletes the attribute info attribute for the given type 994 995 A \c B_ATTR_INFO_CHANGED notification is sent to the mime monitor service. 996 \param type The mime type of interest 997 \return 998 - B_OK: success 999 - B_ENTRY_NOT_FOUND: no such attribute existed 1000 - "error code": failure 1001 */ 1002 status_t 1003 Database::DeleteAttrInfo(const char *type) 1004 { 1005 status_t status = fLocation->DeleteAttribute(type, kAttrInfoAttr); 1006 if (status == B_OK) 1007 _SendMonitorUpdate(B_ATTR_INFO_CHANGED, type, B_META_MIME_DELETED); 1008 else if (status == B_ENTRY_NOT_FOUND) 1009 status = B_OK; 1010 1011 return status; 1012 } 1013 1014 1015 /*! \brief Deletes the short description attribute for the given type 1016 1017 A \c B_SHORT_DESCRIPTION_CHANGED notification is sent to the mime monitor service. 1018 \param type The mime type of interest 1019 \return 1020 - B_OK: success 1021 - B_ENTRY_NOT_FOUND: no such attribute existed 1022 - "error code": failure 1023 */ 1024 status_t 1025 Database::DeleteShortDescription(const char *type) 1026 { 1027 status_t status = fLocation->DeleteAttribute(type, kShortDescriptionAttr); 1028 if (status == B_OK) 1029 _SendMonitorUpdate(B_SHORT_DESCRIPTION_CHANGED, type, B_META_MIME_DELETED); 1030 else if (status == B_ENTRY_NOT_FOUND) 1031 status = B_OK; 1032 1033 return status; 1034 } 1035 1036 1037 /*! \brief Deletes the long description attribute for the given type 1038 1039 A \c B_LONG_DESCRIPTION_CHANGED notification is sent to the mime monitor service. 1040 \param type The mime type of interest 1041 \return 1042 - B_OK: success 1043 - B_ENTRY_NOT_FOUND: no such attribute existed 1044 - "error code": failure 1045 */ 1046 status_t 1047 Database::DeleteLongDescription(const char *type) 1048 { 1049 status_t status = fLocation->DeleteAttribute(type, kLongDescriptionAttr); 1050 if (status == B_OK) 1051 _SendMonitorUpdate(B_LONG_DESCRIPTION_CHANGED, type, B_META_MIME_DELETED); 1052 else if (status == B_ENTRY_NOT_FOUND) 1053 status = B_OK; 1054 1055 return status; 1056 } 1057 1058 1059 /*! \brief Deletes the associated file extensions attribute for the given type 1060 1061 A \c B_FILE_EXTENSIONS_CHANGED notification is sent to the mime monitor service. 1062 \param type The mime type of interest 1063 \return 1064 - B_OK: success 1065 - B_ENTRY_NOT_FOUND: no such attribute existed 1066 - "error code": failure 1067 */ 1068 status_t 1069 Database::DeleteFileExtensions(const char *type) 1070 { 1071 status_t status = fLocation->DeleteAttribute(type, kFileExtensionsAttr); 1072 if (status == B_OK) 1073 _SendMonitorUpdate(B_FILE_EXTENSIONS_CHANGED, type, B_META_MIME_DELETED); 1074 else if (status == B_ENTRY_NOT_FOUND) 1075 status = B_OK; 1076 1077 return status; 1078 } 1079 1080 1081 /*! \brief Deletes the icon of the given size for the given type 1082 1083 A \c B_ICON_CHANGED notification is sent to the mime monitor service. 1084 \param type The mime type of interest 1085 \param which The icon size of interest 1086 \return 1087 - B_OK: success 1088 - B_ENTRY_NOT_FOUND: no such attribute existed 1089 - "error code": failure 1090 */ 1091 status_t 1092 Database::DeleteIcon(const char *type, icon_size which) 1093 { 1094 const char *attr = which == B_MINI_ICON ? kMiniIconAttr : kLargeIconAttr; 1095 status_t status = fLocation->DeleteAttribute(type, attr); 1096 if (status == B_OK) 1097 _SendMonitorUpdate(B_ICON_CHANGED, type, which, B_META_MIME_DELETED); 1098 else if (status == B_ENTRY_NOT_FOUND) 1099 status = B_OK; 1100 1101 return status; 1102 } 1103 1104 1105 /*! \brief Deletes the vector icon for the given type 1106 1107 A \c B_ICON_CHANGED notification is sent to the mime monitor service. 1108 \param type The mime type of interest 1109 \return 1110 - B_OK: success 1111 - B_ENTRY_NOT_FOUND: no such attribute existed 1112 - "error code": failure 1113 */ 1114 status_t 1115 Database::DeleteIcon(const char *type) 1116 { 1117 // TODO: extra notification for vector icon (uses B_LARGE_ICON now) 1118 status_t status = fLocation->DeleteAttribute(type, kIconAttr); 1119 if (status == B_OK) { 1120 _SendMonitorUpdate(B_ICON_CHANGED, type, B_LARGE_ICON, 1121 B_META_MIME_DELETED); 1122 } else if (status == B_ENTRY_NOT_FOUND) 1123 status = B_OK; 1124 1125 return status; 1126 } 1127 1128 1129 /*! \brief Deletes the icon of the given size associated with the given file 1130 type for the given application signature. 1131 1132 (If this function seems confusing, please see BMimeType::GetIconForType() for a 1133 better description of what the *IconForType() functions are used for.) 1134 1135 A \c B_ICON_FOR_TYPE_CHANGED notification is sent to the mime monitor service. 1136 \param type The mime type of the application whose custom icon you are deleting. 1137 \param fileType The mime type for which you no longer wish \c type to have a custom icon. 1138 \param which The icon size of interest 1139 \return 1140 - B_OK: success 1141 - B_ENTRY_NOT_FOUND: no such attribute existed 1142 - "error code": failure 1143 */ 1144 status_t 1145 Database::DeleteIconForType(const char *type, const char *fileType, icon_size which) 1146 { 1147 if (fileType == NULL) 1148 return B_BAD_VALUE; 1149 1150 std::string attr = (which == B_MINI_ICON 1151 ? kMiniIconAttrPrefix : kLargeIconAttrPrefix) + BPrivate::Storage::to_lower(fileType); 1152 1153 status_t status = fLocation->DeleteAttribute(type, attr.c_str()); 1154 if (status == B_OK) { 1155 _SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType, 1156 which == B_LARGE_ICON, B_META_MIME_DELETED); 1157 } else if (status == B_ENTRY_NOT_FOUND) 1158 status = B_OK; 1159 1160 return status; 1161 } 1162 1163 1164 /*! \brief Deletes the vector icon associated with the given file 1165 type for the given application signature. 1166 1167 (If this function seems confusing, please see BMimeType::GetIconForType() for a 1168 better description of what the *IconForType() functions are used for.) 1169 1170 A \c B_ICON_FOR_TYPE_CHANGED notification is sent to the mime monitor service. 1171 \param type The mime type of the application whose custom icon you are deleting. 1172 \param fileType The mime type for which you no longer wish \c type to have a custom icon. 1173 \return 1174 - B_OK: success 1175 - B_ENTRY_NOT_FOUND: no such attribute existed 1176 - "error code": failure 1177 */ 1178 status_t 1179 Database::DeleteIconForType(const char *type, const char *fileType) 1180 { 1181 if (fileType == NULL) 1182 return B_BAD_VALUE; 1183 1184 std::string attr = kIconAttrPrefix + BPrivate::Storage::to_lower(fileType); 1185 1186 // TODO: introduce extra notification for vector icons? 1187 // (uses B_LARGE_ICON now) 1188 status_t status = fLocation->DeleteAttribute(type, attr.c_str()); 1189 if (status == B_OK) { 1190 _SendMonitorUpdate(B_ICON_FOR_TYPE_CHANGED, type, fileType, 1191 true, B_META_MIME_DELETED); 1192 } else if (status == B_ENTRY_NOT_FOUND) 1193 status = B_OK; 1194 1195 return status; 1196 } 1197 1198 1199 // DeletePreferredApp 1200 //! Deletes the preferred app for the given app verb for the given type 1201 /*! A \c B_PREFERRED_APP_CHANGED notification is sent to the mime monitor service. 1202 \param type The mime type of interest 1203 \param which The app verb of interest 1204 \return 1205 - B_OK: success 1206 - B_ENTRY_NOT_FOUND: no such attribute existed 1207 - "error code": failure 1208 */ 1209 status_t 1210 Database::DeletePreferredApp(const char *type, app_verb verb) 1211 { 1212 status_t status; 1213 1214 switch (verb) { 1215 case B_OPEN: 1216 status = fLocation->DeleteAttribute(type, kPreferredAppAttr); 1217 break; 1218 1219 default: 1220 return B_BAD_VALUE; 1221 } 1222 1223 /*! \todo The R5 monitor makes no note of which app_verb value was updated. If 1224 additional app_verb values besides \c B_OPEN are someday added, the format 1225 of the MIME monitor messages will need to be augmented. 1226 */ 1227 if (status == B_OK) 1228 _SendMonitorUpdate(B_PREFERRED_APP_CHANGED, type, B_META_MIME_DELETED); 1229 else if (status == B_ENTRY_NOT_FOUND) 1230 status = B_OK; 1231 1232 return status; 1233 } 1234 1235 // DeleteSnifferRule 1236 //! Deletes the sniffer rule for the given type 1237 /*! A \c B_SNIFFER_RULE_CHANGED notification is sent to the mime monitor service, 1238 and the corresponding rule is removed from the internal database of sniffer 1239 rules. 1240 \param type The mime type of interest 1241 \return 1242 - B_OK: success 1243 - B_ENTRY_NOT_FOUND: no such attribute existed 1244 - "error code": failure 1245 */ 1246 status_t 1247 Database::DeleteSnifferRule(const char *type) 1248 { 1249 status_t status = fLocation->DeleteAttribute(type, kSnifferRuleAttr); 1250 if (status == B_OK) { 1251 status = fSnifferRules.DeleteSnifferRule(type); 1252 if (status == B_OK) { 1253 _SendMonitorUpdate(B_SNIFFER_RULE_CHANGED, type, 1254 B_META_MIME_DELETED); 1255 } 1256 } else if (status == B_ENTRY_NOT_FOUND) 1257 status = B_OK; 1258 1259 return status; 1260 } 1261 1262 // DeleteSupportedTypes 1263 //! Deletes the supported types list for the given type 1264 /*! A \c B_SUPPORTED_TYPES_CHANGED notification is sent to the mime monitor service. 1265 If \c fullSync is \c true, the given type is removed from the internal list 1266 of supporting applictions for each previously supported type. If \c fullSync 1267 is \c false, the said removal will occur the next time SetSupportedTypes() or 1268 DeleteSupportedTypes() is called with a \c true \c fullSync paramter, or 1269 \c Delete() is called for the given type. 1270 \param type The mime type of interest 1271 \param fullSync Whether or not to remove the type as a supporting app for 1272 all previously supported types 1273 \return 1274 - B_OK: success 1275 - B_ENTRY_NOT_FOUND: no such attribute existed 1276 - "error code": failure 1277 */ 1278 status_t 1279 Database::DeleteSupportedTypes(const char *type, bool fullSync) 1280 { 1281 status_t status = fLocation->DeleteAttribute(type, kSupportedTypesAttr); 1282 1283 // Update the supporting apps database. If fullSync is specified, 1284 // do so even if the supported types attribute didn't exist, as 1285 // stranded types *may* exist in the database due to previous 1286 // calls to {Set,Delete}SupportedTypes() with fullSync == false. 1287 bool sendUpdate = true; 1288 if (status == B_OK) 1289 status = fSupportingApps.DeleteSupportedTypes(type, fullSync); 1290 else if (status == B_ENTRY_NOT_FOUND) { 1291 status = B_OK; 1292 if (fullSync) 1293 fSupportingApps.DeleteSupportedTypes(type, fullSync); 1294 else 1295 sendUpdate = false; 1296 } 1297 1298 // Send a monitor notification 1299 if (status == B_OK && sendUpdate) 1300 _SendMonitorUpdate(B_SUPPORTED_TYPES_CHANGED, type, B_META_MIME_DELETED); 1301 1302 return status; 1303 } 1304 1305 1306 void 1307 Database::DeferInstallNotification(const char* type) 1308 { 1309 AutoLocker<BLocker> _(fDeferredInstallNotificationsLocker); 1310 1311 // check, if already deferred 1312 if (_FindDeferredInstallNotification(type)) 1313 return; 1314 1315 // add new 1316 DeferredInstallNotification* notification 1317 = new(std::nothrow) DeferredInstallNotification; 1318 if (notification == NULL) 1319 return; 1320 1321 strlcpy(notification->type, type, sizeof(notification->type)); 1322 notification->notify = false; 1323 1324 if (!fDeferredInstallNotifications.AddItem(notification)) 1325 delete notification; 1326 } 1327 1328 1329 void 1330 Database::UndeferInstallNotification(const char* type) 1331 { 1332 AutoLocker<BLocker> locker(fDeferredInstallNotificationsLocker); 1333 1334 // check, if deferred at all 1335 DeferredInstallNotification* notification 1336 = _FindDeferredInstallNotification(type, true); 1337 1338 locker.Unlock(); 1339 1340 if (notification == NULL) 1341 return; 1342 1343 // notify, if requested 1344 if (notification->notify) 1345 _SendInstallNotification(notification->type); 1346 1347 delete notification; 1348 } 1349 1350 1351 //! \brief Sends a \c B_MIME_TYPE_CREATED notification to the mime monitor service 1352 status_t 1353 Database::_SendInstallNotification(const char *type) 1354 { 1355 return _SendMonitorUpdate(B_MIME_TYPE_CREATED, type, B_META_MIME_MODIFIED); 1356 } 1357 1358 1359 //! \brief Sends a \c B_MIME_TYPE_DELETED notification to the mime monitor service 1360 status_t 1361 Database::_SendDeleteNotification(const char *type) 1362 { 1363 // Tell the backend first 1364 return _SendMonitorUpdate(B_MIME_TYPE_DELETED, type, B_META_MIME_MODIFIED); 1365 } 1366 1367 // _SendMonitorUpdate 1368 /*! \brief Sends an update notification to all BMessengers that have 1369 subscribed to the MIME Monitor service 1370 \param type The MIME type that was updated 1371 \param which Bitmask describing which attribute was updated 1372 \param extraType The MIME type to which the change is applies 1373 \param largeIcon \true if the the large icon was updated, \false if the 1374 small icon was updated 1375 */ 1376 status_t 1377 Database::_SendMonitorUpdate(int32 which, const char *type, const char *extraType, 1378 bool largeIcon, int32 action) 1379 { 1380 BMessage msg(B_META_MIME_CHANGED); 1381 status_t err; 1382 1383 if (_CheckDeferredInstallNotification(which, type)) 1384 return B_OK; 1385 1386 err = msg.AddInt32("be:which", which); 1387 if (!err) 1388 err = msg.AddString("be:type", type); 1389 if (!err) 1390 err = msg.AddString("be:extra_type", extraType); 1391 if (!err) 1392 err = msg.AddBool("be:large_icon", largeIcon); 1393 if (!err) 1394 err = msg.AddInt32("be:action", action); 1395 if (!err) 1396 err = _SendMonitorUpdate(msg); 1397 return err; 1398 } 1399 1400 // _SendMonitorUpdate 1401 /*! \brief Sends an update notification to all BMessengers that have 1402 subscribed to the MIME Monitor service 1403 \param type The MIME type that was updated 1404 \param which Bitmask describing which attribute was updated 1405 \param extraType The MIME type to which the change is applies 1406 */ 1407 status_t 1408 Database::_SendMonitorUpdate(int32 which, const char *type, const char *extraType, 1409 int32 action) 1410 { 1411 if (_CheckDeferredInstallNotification(which, type)) 1412 return B_OK; 1413 1414 BMessage msg(B_META_MIME_CHANGED); 1415 1416 status_t err = msg.AddInt32("be:which", which); 1417 if (!err) 1418 err = msg.AddString("be:type", type); 1419 if (!err) 1420 err = msg.AddString("be:extra_type", extraType); 1421 if (!err) 1422 err = msg.AddInt32("be:action", action); 1423 if (!err) 1424 err = _SendMonitorUpdate(msg); 1425 return err; 1426 } 1427 1428 // _SendMonitorUpdate 1429 /*! \brief Sends an update notification to all BMessengers that have 1430 subscribed to the MIME Monitor service 1431 \param type The MIME type that was updated 1432 \param which Bitmask describing which attribute was updated 1433 \param largeIcon \true if the the large icon was updated, \false if the 1434 small icon was updated 1435 */ 1436 status_t 1437 Database::_SendMonitorUpdate(int32 which, const char *type, bool largeIcon, int32 action) 1438 { 1439 if (_CheckDeferredInstallNotification(which, type)) 1440 return B_OK; 1441 1442 BMessage msg(B_META_MIME_CHANGED); 1443 1444 status_t err = msg.AddInt32("be:which", which); 1445 if (!err) 1446 err = msg.AddString("be:type", type); 1447 if (!err) 1448 err = msg.AddBool("be:large_icon", largeIcon); 1449 if (!err) 1450 err = msg.AddInt32("be:action", action); 1451 if (!err) 1452 err = _SendMonitorUpdate(msg); 1453 return err; 1454 } 1455 1456 // _SendMonitorUpdate 1457 /*! \brief Sends an update notification to all BMessengers that have 1458 subscribed to the MIME Monitor service 1459 \param type The MIME type that was updated 1460 \param which Bitmask describing which attribute was updated 1461 */ 1462 status_t 1463 Database::_SendMonitorUpdate(int32 which, const char *type, int32 action) 1464 { 1465 if (_CheckDeferredInstallNotification(which, type)) 1466 return B_OK; 1467 1468 BMessage msg(B_META_MIME_CHANGED); 1469 1470 status_t err = msg.AddInt32("be:which", which); 1471 if (!err) 1472 err = msg.AddString("be:type", type); 1473 if (!err) 1474 err = msg.AddInt32("be:action", action); 1475 if (!err) 1476 err = _SendMonitorUpdate(msg); 1477 return err; 1478 } 1479 1480 // _SendMonitorUpdate 1481 /*! \brief Sends an update notification to all BMessengers that have subscribed to 1482 the MIME Monitor service 1483 \param BMessage A preformatted MIME monitor message to be sent to all subscribers 1484 */ 1485 status_t 1486 Database::_SendMonitorUpdate(BMessage &msg) 1487 { 1488 if (fNotificationListener == NULL) 1489 return B_OK; 1490 1491 status_t err; 1492 std::set<BMessenger>::const_iterator i; 1493 for (i = fMonitorMessengers.begin(); i != fMonitorMessengers.end(); i++) { 1494 status_t err = fNotificationListener->Notify(&msg, *i); 1495 if (err) { 1496 DBG(OUT("Database::_SendMonitorUpdate(BMessage&): DeliverMessage failed, 0x%lx\n", err)); 1497 } 1498 } 1499 err = B_OK; 1500 return err; 1501 } 1502 1503 1504 Database::DeferredInstallNotification* 1505 Database::_FindDeferredInstallNotification(const char* type, bool remove) 1506 { 1507 for (int32 i = 0; 1508 DeferredInstallNotification* notification 1509 = (DeferredInstallNotification*)fDeferredInstallNotifications 1510 .ItemAt(i); i++) { 1511 if (strcmp(type, notification->type) == 0) { 1512 if (remove) 1513 fDeferredInstallNotifications.RemoveItem(i); 1514 return notification; 1515 } 1516 } 1517 1518 return NULL; 1519 } 1520 1521 1522 bool 1523 Database::_CheckDeferredInstallNotification(int32 which, const char* type) 1524 { 1525 AutoLocker<BLocker> locker(fDeferredInstallNotificationsLocker); 1526 1527 // check, if deferred at all 1528 DeferredInstallNotification* notification 1529 = _FindDeferredInstallNotification(type); 1530 if (notification == NULL) 1531 return false; 1532 1533 if (which == B_MIME_TYPE_DELETED) { 1534 // MIME type deleted -- if the install notification had been 1535 // deferred, we don't send anything 1536 if (notification->notify) { 1537 fDeferredInstallNotifications.RemoveItem(notification); 1538 delete notification; 1539 return true; 1540 } 1541 } else if (which == B_MIME_TYPE_CREATED) { 1542 // MIME type created -- defer notification 1543 notification->notify = true; 1544 return true; 1545 } else { 1546 // MIME type update -- don't send update, if deferred 1547 if (notification->notify) 1548 return true; 1549 } 1550 1551 return false; 1552 } 1553 1554 1555 } // namespace Mime 1556 } // namespace Storage 1557 } // namespace BPrivate 1558