* Copyright 2002-2024, Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Tyler Dauwalder
* Ingo Weinhold, bonefish@users.sf.net
* Axel Dörfler, axeld@pinc-software.de
*/
#include <mime/SupportingApps.h>
#include <stdio.h>
#include <new>
#include <Directory.h>
#include <Message.h>
#include <MimeType.h>
#include <Path.h>
#include <String.h>
#include <mime/database_support.h>
#include <mime/DatabaseDirectory.h>
#include <mime/DatabaseLocation.h>
#include <storage_support.h>
#define DBG(x) x
#define OUT printf
namespace BPrivate {
namespace Storage {
namespace Mime {
\class SupportingApps
\brief Supporting apps information for the entire MIME database
*/
SupportingApps::SupportingApps(DatabaseLocation* databaseLocation)
:
fDatabaseLocation(databaseLocation),
fHaveDoneFullBuild(false)
{
}
SupportingApps::~SupportingApps()
{
}
given type in the pre-allocated \c BMessage pointed to by \c apps.
See \c BMimeType::GetSupportingApps() for more information.
*/
status_t
SupportingApps::GetSupportingApps(const char *type, BMessage *apps)
{
if (type == NULL || apps == NULL)
return B_BAD_VALUE;
if (!fHaveDoneFullBuild) {
status_t status = BuildSupportingAppsTable();
if (status != B_OK)
return status;
}
apps->MakeEmpty();
BString typeString(type);
typeString.ToLower();
BMimeType mime(type);
status_t status = mime.InitCheck();
if (status != B_OK)
return status;
if (mime.IsSupertypeOnly()) {
std::set<std::string> &superApps = fSupportingApps[typeString.String()];
int32 count = 0;
std::set<std::string>::const_iterator i;
for (i = superApps.begin(); i != superApps.end() && status == B_OK; i++) {
status = apps->AddString(kApplicationsField, (*i).c_str());
count++;
}
if (status == B_OK)
status = apps->AddInt32(kSupportingAppsSuperCountField, count);
} else {
std::set<std::string> &subApps = fSupportingApps[typeString.String()];
int32 count = 0;
std::set<std::string>::const_iterator i;
for (i = subApps.begin(); i != subApps.end() && status == B_OK; i++) {
status = apps->AddString(kApplicationsField, (*i).c_str());
count++;
}
if (status == B_OK)
status = apps->AddInt32(kSupportingAppsSubCountField, count);
BMimeType superMime;
status = mime.GetSupertype(&superMime);
if (status == B_OK)
status = superMime.InitCheck();
if (status == B_OK) {
std::set<std::string> &superApps = fSupportingApps[superMime.Type()];
count = 0;
for (i = superApps.begin(); i != superApps.end() && status == B_OK; i++) {
if (subApps.find(*i) == subApps.end()) {
status = apps->AddString(kApplicationsField, (*i).c_str());
count++;
}
}
if (status == B_OK)
status = apps->AddInt32(kSupportingAppsSuperCountField, count);
}
}
return status;
}
updates the supporting apps mappings.
All types listed as being supported types will including the given
app signature in their list of supporting apps following this call.
If \a fullSync is true, all types previously but no longer supported
by this application with no longer list this application as a
supporting app.
If \a fullSync is false, said previously supported types will be
saved to a "stranded types" mapping and appropriately synchronized
the next time SetSupportedTypes() is called with a \c true \a fullSync
parameter.
The stranded types mapping is properly maintained even in the event
of types being removed and then re-added to the list of supporting
types with consecutive \c false \a fullSync parameters.
\param app The application whose supported types you are setting
\param types Pointer to a \c BMessage containing an array of supported
mime types in its \c Mime::kTypesField field.
\param fullSync If \c true, \c app is removed as a supporting application
for any types for which it is no longer a supporting application
(including types which were removed as supporting types with
previous callsto SetSupportedTypes(..., false)). If \c false,
said mappings are not updated until the next SetSupportedTypes(..., true)
call.
*/
status_t
SupportingApps::SetSupportedTypes(const char *app, const BMessage *types, bool fullSync)
{
if (app == NULL || types == NULL)
return B_BAD_VALUE;
if (!fHaveDoneFullBuild)
return B_OK;
std::set<std::string> oldTypes;
std::set<std::string> &newTypes = fSupportedTypes[app];
std::set<std::string> &strandedTypes = fStrandedTypes[app];
oldTypes = newTypes;
newTypes.clear();
BString type;
for (int32 i = 0; types->FindString(kTypesField, i, &type) == B_OK; i++) {
type.ToLower();
newTypes.insert(type.String());
AddSupportingApp(type.String(), app);
}
for (std::set<std::string>::const_iterator i = newTypes.begin();
i != newTypes.end(); i++) {
strandedTypes.erase(*i);
}
for (std::set<std::string>::const_iterator i = oldTypes.begin();
i != oldTypes.end(); i++) {
if (newTypes.find(*i) == newTypes.end())
strandedTypes.insert(*i);
}
if (fullSync) {
for (std::set<std::string>::const_iterator i = strandedTypes.begin();
i != strandedTypes.end(); i++) {
RemoveSupportingApp((*i).c_str(), app);
}
strandedTypes.clear();
}
return B_OK;
}
removes the application from each of said types' supporting apps list.
\param app The application whose supported types you are clearing
\param fullSync See SupportingApps::SetSupportedTypes()
*/
status_t
SupportingApps::DeleteSupportedTypes(const char *app, bool fullSync)
{
BMessage types;
return SetSupportedTypes(app, &types, fullSync);
}
apps for the given type.
\param type The full mime type
\param app The full application signature (i.e. "application/app-subtype")
\return
- B_OK: success, even if the app was already in the supporting apps list
- "error code": failure
*/
status_t
SupportingApps::AddSupportingApp(const char *type, const char *app)
{
if (type == NULL || app == NULL)
return B_BAD_VALUE;
fSupportingApps[type].insert(app);
return B_OK;
}
apps for the given type.
\param type The full mime type
\param app The full application signature (i.e. "application/app-subtype")
\return
- B_OK: success, even if the app was not found in the supporting apps list
- "error code": failure
*/
status_t
SupportingApps::RemoveSupportingApp(const char *type, const char *app)
{
if (type == NULL || app == NULL)
return B_BAD_VALUE;
fSupportingApps[type].erase(app);
return B_OK;
}
signatures for every supported type.
*/
status_t
SupportingApps::BuildSupportingAppsTable()
{
fSupportedTypes.clear();
fSupportingApps.clear();
fStrandedTypes.clear();
DatabaseDirectory dir;
status_t status = dir.Init(fDatabaseLocation, "application");
if (status != B_OK)
return status;
dir.Rewind();
while (true) {
entry_ref ref;
status = dir.GetNextRef(&ref);
if (status < B_OK) {
if (status == B_ENTRY_NOT_FOUND)
status = B_OK;
break;
}
BString appSignature;
BNode node(&ref);
if (node.InitCheck() == B_OK && node.ReadAttrString(kTypeAttr,
&appSignature) >= B_OK) {
BMessage msg;
if (fDatabaseLocation->ReadMessageAttribute(appSignature,
kSupportedTypesAttr, msg) == B_OK) {
BString type;
std::set<std::string> &supportedTypes = fSupportedTypes[appSignature.String()];
for (int i = 0; msg.FindString(kTypesField, i, &type) == B_OK; i++) {
type.ToLower();
supportedTypes.insert(type.String());
AddSupportingApp(type.String(), appSignature.String());
}
}
}
}
if (status == B_OK)
fHaveDoneFullBuild = true;
else
DBG(OUT("SupportingApps::BuildSupportingAppsTable() failed: %s\n", strerror(status)));
return status;
}
}
}
}