#include "RecentEntries.h"
#include <new>
#include <map>
#include <strings.h>
#include <AppFileInfo.h>
#include <Entry.h>
#include <File.h>
#include <Message.h>
#include <Mime.h>
#include <Path.h>
#include <Roster.h>
#include <String.h>
#include <storage_support.h>
#include "Debug.h"
using namespace std;
recent_entry::recent_entry(const entry_ref *ref, const char *appSig,
uint32 index)
:
ref(ref ? *ref : entry_ref()),
sig(appSig),
index(index)
{
}
RecentEntries::RecentEntries()
{
}
RecentEntries::~RecentEntries()
{
Clear();
}
status_t
RecentEntries::Add(const entry_ref *ref, const char *appSig)
{
if (ref == NULL || appSig == NULL)
return B_BAD_VALUE;
std::list<recent_entry*>::iterator item;
for (item = fEntryList.begin(); item != fEntryList.end(); item++) {
if ((*item)->ref == *ref && !strcasecmp((*item)->sig.c_str(), appSig)) {
fEntryList.erase(item);
break;
}
}
recent_entry *entry = new (nothrow) recent_entry(ref, appSig, 0);
if (entry == NULL)
return B_NO_MEMORY;
try {
fEntryList.push_front(entry);
} catch (...) {
return B_NO_MEMORY;
}
int32 remove = fEntryList.size() - kMaxRecentEntries;
while (remove > 0) {
fEntryList.pop_back();
remove--;
}
return B_OK;
}
status_t
RecentEntries::Get(int32 maxCount, const char *fileTypes[],
int32 fileTypesCount, const char *appSig, BMessage *result)
{
if (result == NULL
|| fileTypesCount < 0
|| (fileTypesCount > 0 && fileTypes == NULL))
return B_BAD_VALUE;
result->MakeEmpty();
std::list<recent_entry*> duplicateList;
std::list<recent_entry*>::iterator item;
status_t error = B_OK;
int count = 0;
for (item = fEntryList.begin();
error == B_OK && count < maxCount && item != fEntryList.end();
item++) {
if (appSig != NULL && strcasecmp((*item)->sig.c_str(), appSig))
continue;
if (fileTypesCount > 0) {
char type[B_MIME_TYPE_LENGTH];
if (GetTypeForRef(&(*item)->ref, type) == B_OK) {
bool match = false;
for (int i = 0; i < fileTypesCount; i++) {
if (!strcasecmp(type, fileTypes[i])) {
match = true;
break;
}
}
if (!match)
continue;
}
}
bool duplicate = false;
for (std::list<recent_entry*>::iterator dupItem = duplicateList.begin();
dupItem != duplicateList.end(); dupItem++) {
if ((*dupItem)->ref == (*item)->ref) {
duplicate = true;
break;
}
}
if (duplicate)
continue;
try {
duplicateList.push_back(*item);
} catch (...) {
error = B_NO_MEMORY;
}
if (error == B_OK)
error = result->AddRef("refs", &(*item)->ref);
if (error == B_OK)
count++;
}
return error;
}
status_t
RecentEntries::Clear()
{
std::list<recent_entry*>::iterator i;
for (i = fEntryList.begin(); i != fEntryList.end(); i++) {
delete *i;
}
fEntryList.clear();
return B_OK;
}
status_t
RecentEntries::Print()
{
std::list<recent_entry*>::iterator item;
int counter = 1;
for (item = fEntryList.begin(); item != fEntryList.end(); item++) {
printf("%d: device == '%" B_PRIdDEV "', dir == '%" B_PRIdINO "', "
"name == '%s', app == '%s', index == %" B_PRId32 "\n", counter++,
(*item)->ref.device, (*item)->ref.directory, (*item)->ref.name,
(*item)->sig.c_str(), (*item)->index);
}
return B_OK;
}
status_t
RecentEntries::Save(FILE* file, const char *description, const char *tag)
{
if (file == NULL || description == NULL || tag == NULL)
return B_BAD_VALUE;
fprintf(file, "# %s\n", description);
std::map<entry_ref, std::list<recent_entry*> > map;
uint32 count = fEntryList.size();
try {
for (std::list<recent_entry*>::iterator item = fEntryList.begin();
item != fEntryList.end(); count--, item++) {
recent_entry *entry = *item;
if (entry) {
entry->index = count;
map[entry->ref].push_back(entry);
} else {
D(PRINT("WARNING: RecentEntries::Save(): The entry %ld entries "
"from the front of fEntryList was found to be NULL\n",
fEntryList.size() - count));
}
}
} catch (...) {
return B_NO_MEMORY;
}
for (std::map<entry_ref, std::list<recent_entry*> >::iterator mapItem = map.begin();
mapItem != map.end(); mapItem++) {
BPath path;
char escapedPath[B_PATH_NAME_LENGTH*2];
status_t outputError = path.SetTo(&mapItem->first);
if (!outputError) {
BPrivate::Storage::escape_path(path.Path(), escapedPath);
fprintf(file, "%s %s", tag, escapedPath);
std::list<recent_entry*> &list = mapItem->second;
int32 i = 0;
for (std::list<recent_entry*>::iterator item = list.begin();
item != list.end(); i++, item++) {
recent_entry *entry = *item;
if (entry) {
fprintf(file, " \"%s\" %" B_PRId32, entry->sig.c_str(),
entry->index);
} else {
D(PRINT("WARNING: RecentEntries::Save(): The entry %"
B_PRId32 " entries from the front of the compiled "
"recent_entry* list for the entry ref (%" B_PRId32 ", %"
B_PRId64 ", '%s') was found to be NULL\n", i,
mapItem->first.device, mapItem->first.directory,
mapItem->first.name));
}
}
fprintf(file, "\n");
} else {
D(PRINT("WARNING: RecentEntries::Save(): entry_ref_to_path() "
"failed on the entry_ref (%" B_PRId32", %" B_PRId64 ", '%s') "
"with error 0x%" B_PRIx32 "\n",
mapItem->first.device, mapItem->first.directory,
mapItem->first.name, outputError));
}
}
fprintf(file, "\n");
return B_OK;
}
status_t
RecentEntries::GetTypeForRef(const entry_ref *ref, char *result)
{
if (ref == NULL || result == NULL)
return B_BAD_VALUE;
BNode node;
status_t error = node.SetTo(ref);
if (error == B_OK) {
ssize_t bytes = node.ReadAttr("BEOS:TYPE", B_MIME_STRING_TYPE,
0, result, B_MIME_TYPE_LENGTH - 1);
if (bytes < B_OK)
error = bytes;
else
result[bytes] = '\0';
}
return error;
}