2 * Copyright 2002-2006, Haiku.
3 * Distributed under the terms of the MIT License.
7 * Ingo Weinhold, bonefish@users.sf.net
8 * Axel Dörfler, axeld@pinc-software.de
12 #include <mime/SupportingApps.h>
19 #include <Directory.h>
25 #include <mime/database_support.h>
26 #include <mime/DatabaseDirectory.h>
27 #include <mime/DatabaseLocation.h>
28 #include <storage_support.h>
41 \brief Supporting apps information for the entire database
45 //! Constructs a new SupportingApps object
46 SupportingApps::SupportingApps(DatabaseLocation
* databaseLocation
)
48 fDatabaseLocation(databaseLocation
),
49 fHaveDoneFullBuild(false)
54 //! Destroys the SupportingApps object
55 SupportingApps::~SupportingApps()
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.
63 See \c BMimeType::GetSupportingApps() for more information.
66 SupportingApps::GetSupportingApps(const char *type
, BMessage
*apps
)
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();
74 // Clear the message, as we're just going to add to it
78 err
= mime
.InitCheck();
80 if (mime
.IsSupertypeOnly()) {
81 // Add the apps that support this supertype (plus their count)
82 std::set
<std::string
> &superApps
= fSupportingApps
[type
];
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());
90 err
= apps
->AddInt32(kSupportingAppsSuperCountField
, count
);
92 // Add the apps that support this subtype (plus their count)
93 std::set
<std::string
> &subApps
= fSupportingApps
[type
];
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());
101 err
= apps
->AddInt32(kSupportingAppsSubCountField
, count
);
103 // Now add any apps that support the supertype, but not the
104 // subtype (plus their count).
106 err
= mime
.GetSupertype(&superMime
);
108 err
= superMime
.InitCheck();
110 std::set
<std::string
> &superApps
= fSupportingApps
[superMime
.Type()];
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());
119 err
= apps
->AddInt32(kSupportingAppsSuperCountField
, count
);
128 /*! \brief Sets the list of supported types for the given application and
129 updates the supporting apps mappings.
131 All types listed as being supported types will including the given
132 app signature in their list of supporting apps following this call.
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
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
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.
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)
158 SupportingApps::SetSupportedTypes(const char *app
, const BMessage
*types
, bool fullSync
)
160 status_t err
= app
&& types
? B_OK
: B_BAD_VALUE
;
161 if (!fHaveDoneFullBuild
)
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
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
176 for (int32 i
= 0; types
->FindString(kTypesField
, i
, &type
) == B_OK
;
178 newTypes
.insert(type
);
179 AddSupportingApp(type
, app
);
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
);
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
);
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
198 for (std::set
<std::string
>::const_iterator i
= strandedTypes
.begin();
199 i
!= strandedTypes
.end(); i
++) {
200 RemoveSupportingApp((*i
).c_str(), app
);
202 strandedTypes
.clear();
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()
215 SupportingApps::DeleteSupportedTypes(const char *app
, bool fullSync
)
218 return SetSupportedTypes(app
, &types
, fullSync
);
222 /*! \brief Adds the given application signature to the set of supporting
223 apps for the given type.
225 \param type The full mime type
226 \param app The full application signature (i.e. "application/app-subtype")
228 - B_OK: success, even if the app was already in the supporting apps list
229 - "error code": failure
232 SupportingApps::AddSupportingApp(const char *type
, const char *app
)
234 status_t err
= type
&& app
? B_OK
: B_BAD_VALUE
;
236 fSupportingApps
[type
].insert(app
);
240 // RemoveSupportingApp
241 /*! \brief Removes the given application signature from the set of supporting
242 apps for the given type.
244 \param type The full mime type
245 \param app The full application signature (i.e. "application/app-subtype")
247 - B_OK: success, even if the app was not found in the supporting apps list
248 - "error code": failure
251 SupportingApps::RemoveSupportingApp(const char *type
, const char *app
)
253 status_t err
= type
&& app
? B_OK
: B_BAD_VALUE
;
255 fSupportingApps
[type
].erase(app
);
259 // BuildSupportingAppsTable
260 /*! \brief Crawls the mime database and builds a list of supporting application
261 signatures for every supported type.
264 SupportingApps::BuildSupportingAppsTable()
266 fSupportedTypes
.clear();
267 fSupportingApps
.clear();
268 fStrandedTypes
.clear();
270 DatabaseDirectory dir
;
271 status_t status
= dir
.Init(fDatabaseLocation
, "application");
273 // Build the supporting apps table based on the mime database
274 if (status
== B_OK
) {
277 // Handle each application type
280 status
= dir
.GetNextRef(&ref
);
282 // If we've come to the end of list, it's not an error
283 if (status
== B_ENTRY_NOT_FOUND
)
288 // read application signature from file
289 BString appSignature
;
291 if (node
.InitCheck() == B_OK
&& node
.ReadAttrString(kTypeAttr
,
292 &appSignature
) >= B_OK
) {
293 // Read in the list of supported types
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
301 std::set
<std::string
> &supportedTypes
= fSupportedTypes
[appSignature
.String()];
302 for (int i
= 0; msg
.FindString(kTypesField
, i
, &type
) == B_OK
; i
++) {
304 // MIME types are case insensitive, so we lowercase everything
305 supportedTypes
.insert(type
.String());
306 AddSupportingApp(type
.String(), appSignature
.String());
314 fHaveDoneFullBuild
= true;
316 DBG(OUT("SupportingApps::BuildSupportingAppsTable() failed: %s\n", strerror(status
)));
322 } // namespace Storage
323 } // namespace BPrivate