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