1 /* 2 * Copyright 2002-2006, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Tyler Dauwalder 7 * Ingo Weinhold, bonefish@users.sf.net 8 * Axel Dörfler, axeld@pinc-software.de 9 */ 10 11 12 #include <mime/SupportingApps.h> 13 14 #include <stdio.h> 15 16 #include <new> 17 #include <iostream> 18 19 #include <Directory.h> 20 #include <Message.h> 21 #include <MimeType.h> 22 #include <Path.h> 23 #include <String.h> 24 25 #include <mime/database_support.h> 26 #include <mime/DatabaseDirectory.h> 27 #include <mime/DatabaseLocation.h> 28 #include <storage_support.h> 29 30 31 #define DBG(x) x 32 //#define DBG(x) 33 #define OUT printf 34 35 namespace BPrivate { 36 namespace Storage { 37 namespace Mime { 38 39 /*! 40 \class SupportingApps 41 \brief Supporting apps information for the entire database 42 */ 43 44 // Constructor 45 //! Constructs a new SupportingApps object 46 SupportingApps::SupportingApps(DatabaseLocation* databaseLocation) 47 : 48 fDatabaseLocation(databaseLocation), 49 fHaveDoneFullBuild(false) 50 { 51 } 52 53 // Destructor 54 //! Destroys the SupportingApps object 55 SupportingApps::~SupportingApps() 56 { 57 } 58 59 // GetSupportingApps 60 /*! \brief Returns a list of signatures of supporting applications for the 61 given type in the pre-allocated \c BMessage pointed to by \c apps. 62 63 See \c BMimeType::GetSupportingApps() for more information. 64 */ 65 status_t 66 SupportingApps::GetSupportingApps(const char *type, BMessage *apps) 67 { 68 status_t err = type && apps ? B_OK : B_BAD_VALUE; 69 // See if we need to do our initial build still 70 if (!err && !fHaveDoneFullBuild) 71 err = BuildSupportingAppsTable(); 72 73 if (!err) { 74 // Clear the message, as we're just going to add to it 75 apps->MakeEmpty(); 76 77 BMimeType mime(type); 78 err = mime.InitCheck(); 79 if (!err) { 80 if (mime.IsSupertypeOnly()) { 81 // Add the apps that support this supertype (plus their count) 82 std::set<std::string> &superApps = fSupportingApps[type]; 83 int32 count = 0; 84 std::set<std::string>::const_iterator i; 85 for (i = superApps.begin(); i != superApps.end() && !err; i++) { 86 err = apps->AddString(kApplicationsField, (*i).c_str()); 87 count++; 88 } 89 if (!err) 90 err = apps->AddInt32(kSupportingAppsSuperCountField, count); 91 } else { 92 // Add the apps that support this subtype (plus their count) 93 std::set<std::string> &subApps = fSupportingApps[type]; 94 int32 count = 0; 95 std::set<std::string>::const_iterator i; 96 for (i = subApps.begin(); i != subApps.end() && !err; i++) { 97 err = apps->AddString(kApplicationsField, (*i).c_str()); 98 count++; 99 } 100 if (!err) 101 err = apps->AddInt32(kSupportingAppsSubCountField, count); 102 103 // Now add any apps that support the supertype, but not the 104 // subtype (plus their count). 105 BMimeType superMime; 106 err = mime.GetSupertype(&superMime); 107 if (!err) 108 err = superMime.InitCheck(); 109 if (!err) { 110 std::set<std::string> &superApps = fSupportingApps[superMime.Type()]; 111 count = 0; 112 for (i = superApps.begin(); i != superApps.end() && !err; i++) { 113 if (subApps.find(*i) == subApps.end()) { 114 err = apps->AddString(kApplicationsField, (*i).c_str()); 115 count++; 116 } 117 } 118 if (!err) 119 err = apps->AddInt32(kSupportingAppsSuperCountField, count); 120 } 121 } 122 } 123 } 124 return err; 125 } 126 127 // SetSupportedTypes 128 /*! \brief Sets the list of supported types for the given application and 129 updates the supporting apps mappings. 130 131 All types listed as being supported types will including the given 132 app signature in their list of supporting apps following this call. 133 134 If \a fullSync is true, all types previously but no longer supported 135 by this application with no longer list this application as a 136 supporting app. 137 138 If \a fullSync is false, said previously supported types will be 139 saved to a "stranded types" mapping and appropriately synchronized 140 the next time SetSupportedTypes() is called with a \c true \a fullSync 141 parameter. 142 143 The stranded types mapping is properly maintained even in the event 144 of types being removed and then re-added to the list of supporting 145 types with consecutive \c false \a fullSync parameters. 146 147 \param app The application whose supported types you are setting 148 \param types Pointer to a \c BMessage containing an array of supported 149 mime types in its \c Mime::kTypesField field. 150 \param fullSync If \c true, \c app is removed as a supporting application 151 for any types for which it is no longer a supporting application 152 (including types which were removed as supporting types with 153 previous callsto SetSupportedTypes(..., false)). If \c false, 154 said mappings are not updated until the next SetSupportedTypes(..., true) 155 call. 156 */ 157 status_t 158 SupportingApps::SetSupportedTypes(const char *app, const BMessage *types, bool fullSync) 159 { 160 status_t err = app && types ? B_OK : B_BAD_VALUE; 161 if (!fHaveDoneFullBuild) 162 return err; 163 164 std::set<std::string> oldTypes; 165 std::set<std::string> &newTypes = fSupportedTypes[app]; 166 std::set<std::string> &strandedTypes = fStrandedTypes[app]; 167 // Make a copy of the previous types if we're doing a full sync 168 if (!err) { 169 oldTypes = newTypes; 170 171 // Read through the list of new supported types, creating the new 172 // supported types list and adding the app as a supporting app for 173 // each type. 174 newTypes.clear(); 175 const char *type; 176 for (int32 i = 0; types->FindString(kTypesField, i, &type) == B_OK; 177 i++) { 178 newTypes.insert(type); 179 AddSupportingApp(type, app); 180 } 181 182 // Update the list of stranded types by removing any types that are newly 183 // re-supported and adding any types that are newly un-supported 184 for (std::set<std::string>::const_iterator i = newTypes.begin(); 185 i != newTypes.end(); i++) { 186 strandedTypes.erase(*i); 187 } 188 for (std::set<std::string>::const_iterator i = oldTypes.begin(); 189 i != oldTypes.end(); i++) { 190 if (newTypes.find(*i) == newTypes.end()) 191 strandedTypes.insert(*i); 192 } 193 194 // Now, if we're doing a full sync, remove the app as a supporting 195 // app for any of its stranded types and then clear said list of 196 // stranded types. 197 if (fullSync) { 198 for (std::set<std::string>::const_iterator i = strandedTypes.begin(); 199 i != strandedTypes.end(); i++) { 200 RemoveSupportingApp((*i).c_str(), app); 201 } 202 strandedTypes.clear(); 203 } 204 } 205 return err; 206 } 207 208 209 /*! \brief Clears the given application's supported types list and optionally 210 removes the application from each of said types' supporting apps list. 211 \param app The application whose supported types you are clearing 212 \param fullSync See SupportingApps::SetSupportedTypes() 213 */ 214 status_t 215 SupportingApps::DeleteSupportedTypes(const char *app, bool fullSync) 216 { 217 BMessage types; 218 return SetSupportedTypes(app, &types, fullSync); 219 } 220 221 // AddSupportingApp 222 /*! \brief Adds the given application signature to the set of supporting 223 apps for the given type. 224 225 \param type The full mime type 226 \param app The full application signature (i.e. "application/app-subtype") 227 \return 228 - B_OK: success, even if the app was already in the supporting apps list 229 - "error code": failure 230 */ 231 status_t 232 SupportingApps::AddSupportingApp(const char *type, const char *app) 233 { 234 status_t err = type && app ? B_OK : B_BAD_VALUE; 235 if (!err) 236 fSupportingApps[type].insert(app); 237 return err; 238 } 239 240 // RemoveSupportingApp 241 /*! \brief Removes the given application signature from the set of supporting 242 apps for the given type. 243 244 \param type The full mime type 245 \param app The full application signature (i.e. "application/app-subtype") 246 \return 247 - B_OK: success, even if the app was not found in the supporting apps list 248 - "error code": failure 249 */ 250 status_t 251 SupportingApps::RemoveSupportingApp(const char *type, const char *app) 252 { 253 status_t err = type && app ? B_OK : B_BAD_VALUE; 254 if (!err) 255 fSupportingApps[type].erase(app); 256 return err; 257 } 258 259 // BuildSupportingAppsTable 260 /*! \brief Crawls the mime database and builds a list of supporting application 261 signatures for every supported type. 262 */ 263 status_t 264 SupportingApps::BuildSupportingAppsTable() 265 { 266 fSupportedTypes.clear(); 267 fSupportingApps.clear(); 268 fStrandedTypes.clear(); 269 270 DatabaseDirectory dir; 271 status_t status = dir.Init(fDatabaseLocation, "application"); 272 273 // Build the supporting apps table based on the mime database 274 if (status == B_OK) { 275 dir.Rewind(); 276 277 // Handle each application type 278 while (true) { 279 entry_ref ref; 280 status = dir.GetNextRef(&ref); 281 if (status < B_OK) { 282 // If we've come to the end of list, it's not an error 283 if (status == B_ENTRY_NOT_FOUND) 284 status = B_OK; 285 break; 286 } 287 288 // read application signature from file 289 BString appSignature; 290 BNode node(&ref); 291 if (node.InitCheck() == B_OK && node.ReadAttrString(kTypeAttr, 292 &appSignature) >= B_OK) { 293 // Read in the list of supported types 294 BMessage msg; 295 if (fDatabaseLocation->ReadMessageAttribute(appSignature, 296 kSupportedTypesAttr, msg) == B_OK) { 297 // Iterate through the supported types, adding them to the list of 298 // supported types for the application and adding the application's 299 // signature to the list of supporting apps for each type 300 BString type; 301 std::set<std::string> &supportedTypes = fSupportedTypes[appSignature.String()]; 302 for (int i = 0; msg.FindString(kTypesField, i, &type) == B_OK; i++) { 303 type.ToLower(); 304 // MIME types are case insensitive, so we lowercase everything 305 supportedTypes.insert(type.String()); 306 AddSupportingApp(type.String(), appSignature.String()); 307 } 308 } 309 } 310 } 311 } 312 313 if (status == B_OK) 314 fHaveDoneFullBuild = true; 315 else 316 DBG(OUT("SupportingApps::BuildSupportingAppsTable() failed: %s\n", strerror(status))); 317 318 return status; 319 } 320 321 } // namespace Mime 322 } // namespace Storage 323 } // namespace BPrivate 324 325