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 if (!err) { 172 // Read through the list of new supported types, creating the new 173 // supported types list and adding the app as a supporting app for 174 // each type. 175 newTypes.clear(); 176 const char *type; 177 for (int32 i = 0; types->FindString(kTypesField, i, &type) == B_OK; 178 i++) { 179 newTypes.insert(type); 180 AddSupportingApp(type, app); 181 } 182 183 // Update the list of stranded types by removing any types that are newly 184 // re-supported and adding any types that are newly un-supported 185 for (std::set<std::string>::const_iterator i = newTypes.begin(); 186 i != newTypes.end(); i++) { 187 strandedTypes.erase(*i); 188 } 189 for (std::set<std::string>::const_iterator i = oldTypes.begin(); 190 i != oldTypes.end(); i++) { 191 if (newTypes.find(*i) == newTypes.end()) 192 strandedTypes.insert(*i); 193 } 194 195 // Now, if we're doing a full sync, remove the app as a supporting 196 // app for any of its stranded types and then clear said list of 197 // stranded types. 198 if (fullSync) { 199 for (std::set<std::string>::const_iterator i = strandedTypes.begin(); 200 i != strandedTypes.end(); i++) { 201 RemoveSupportingApp((*i).c_str(), app); 202 } 203 strandedTypes.clear(); 204 } 205 } 206 return err; 207 } 208 209 210 /*! \brief Clears the given application's supported types list and optionally 211 removes the application from each of said types' supporting apps list. 212 \param app The application whose supported types you are clearing 213 \param fullSync See SupportingApps::SetSupportedTypes() 214 */ 215 status_t 216 SupportingApps::DeleteSupportedTypes(const char *app, bool fullSync) 217 { 218 BMessage types; 219 return SetSupportedTypes(app, &types, fullSync); 220 } 221 222 // AddSupportingApp 223 /*! \brief Adds the given application signature to the set of supporting 224 apps for the given type. 225 226 \param type The full mime type 227 \param app The full application signature (i.e. "application/app-subtype") 228 \return 229 - B_OK: success, even if the app was already in the supporting apps list 230 - "error code": failure 231 */ 232 status_t 233 SupportingApps::AddSupportingApp(const char *type, const char *app) 234 { 235 status_t err = type && app ? B_OK : B_BAD_VALUE; 236 if (!err) 237 fSupportingApps[type].insert(app); 238 return err; 239 } 240 241 // RemoveSupportingApp 242 /*! \brief Removes the given application signature from the set of supporting 243 apps for the given type. 244 245 \param type The full mime type 246 \param app The full application signature (i.e. "application/app-subtype") 247 \return 248 - B_OK: success, even if the app was not found in the supporting apps list 249 - "error code": failure 250 */ 251 status_t 252 SupportingApps::RemoveSupportingApp(const char *type, const char *app) 253 { 254 status_t err = type && app ? B_OK : B_BAD_VALUE; 255 if (!err) 256 fSupportingApps[type].erase(app); 257 return err; 258 } 259 260 // BuildSupportingAppsTable 261 /*! \brief Crawls the mime database and builds a list of supporting application 262 signatures for every supported type. 263 */ 264 status_t 265 SupportingApps::BuildSupportingAppsTable() 266 { 267 fSupportedTypes.clear(); 268 fSupportingApps.clear(); 269 fStrandedTypes.clear(); 270 271 DatabaseDirectory dir; 272 status_t status = dir.Init(fDatabaseLocation, "application"); 273 274 // Build the supporting apps table based on the mime database 275 if (status == B_OK) { 276 dir.Rewind(); 277 278 // Handle each application type 279 while (true) { 280 entry_ref ref; 281 status = dir.GetNextRef(&ref); 282 if (status < B_OK) { 283 // If we've come to the end of list, it's not an error 284 if (status == B_ENTRY_NOT_FOUND) 285 status = B_OK; 286 break; 287 } 288 289 // read application signature from file 290 BString appSignature; 291 BNode node(&ref); 292 if (node.InitCheck() == B_OK && node.ReadAttrString(kTypeAttr, 293 &appSignature) >= B_OK) { 294 // Read in the list of supported types 295 BMessage msg; 296 if (fDatabaseLocation->ReadMessageAttribute(appSignature, 297 kSupportedTypesAttr, msg) == B_OK) { 298 // Iterate through the supported types, adding them to the list of 299 // supported types for the application and adding the application's 300 // signature to the list of supporting apps for each type 301 BString type; 302 std::set<std::string> &supportedTypes = fSupportedTypes[appSignature.String()]; 303 for (int i = 0; msg.FindString(kTypesField, i, &type) == B_OK; i++) { 304 type.ToLower(); 305 // MIME types are case insensitive, so we lowercase everything 306 supportedTypes.insert(type.String()); 307 AddSupportingApp(type.String(), appSignature.String()); 308 } 309 } 310 } 311 } 312 } 313 314 if (status == B_OK) 315 fHaveDoneFullBuild = true; 316 else 317 DBG(OUT("SupportingApps::BuildSupportingAppsTable() failed: %s\n", strerror(status))); 318 319 return status; 320 } 321 322 } // namespace Mime 323 } // namespace Storage 324 } // namespace BPrivate 325 326