#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 {
SupportingApps::SupportingApps(DatabaseLocation* databaseLocation)
:
fDatabaseLocation(databaseLocation),
fHaveDoneFullBuild(false)
{
}
SupportingApps::~SupportingApps()
{
}
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;
}
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;
}
status_t
SupportingApps::DeleteSupportedTypes(const char *app, bool fullSync)
{
BMessage types;
return SetSupportedTypes(app, &types, fullSync);
}
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;
}
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;
}
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;
}
}
}
}