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