Implemented loading and saving of recent docs, folders, and apps lists

from and to disk in the ~/config/settings/Roster/RosterSettings format.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1876 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Tyler Dauwalder 2002-11-08 00:43:58 +00:00
parent e28d9c0efe
commit 4f03f5d268
9 changed files with 883 additions and 37 deletions

View File

@ -18,6 +18,7 @@ Server obos_registrar :
RecentEntries.cpp
Registrar.cpp
RosterAppInfo.cpp
RosterSettingsCharStream.cpp
TRoster.cpp
Watcher.cpp
WatchingService.cpp

View File

@ -37,8 +37,6 @@
#include <Roster.h>
#include <storage_support.h>
#include <stdio.h>
#define DBG(x) (x)
//#define DBG(x)
#define OUT printf
@ -189,6 +187,45 @@ RecentApps::Clear()
return B_OK;
}
// Print
/*! \brief Dumps the the current list of apps to stdout.
*/
status_t
RecentApps::Print()
{
std::list<std::string>::iterator item;
int counter = 1;
for (item = fAppList.begin();
item != fAppList.end();
item++)
{
printf("%d: '%s'\n", counter++, item->c_str());
}
}
// Save
/*! \brief Outputs a textual representation of the current recent
apps list to the given file stream.
*/
status_t
RecentApps::Save(FILE* file)
{
status_t error = file ? B_OK : B_BAD_VALUE;
if (!error) {
fprintf(file, "# Recent applications\n");
std::list<std::string>::iterator item;
for (item = fAppList.begin();
item != fAppList.end();
item++)
{
fprintf(file, "RecentApp %s\n", item->c_str());
}
fprintf(file, "\n");
}
return error;
}
// GetRefForApp
/*! \brief Fetches an \c entry_ref for the application with the
given signature.
@ -211,18 +248,3 @@ RecentApps::GetRefForApp(const char *appSig, entry_ref *result)
return err;
}
// Print
/*! \brief Dumps the the current list of apps to stdout.
*/
status_t
RecentApps::Print()
{
std::list<std::string>::iterator item;
int counter = 1;
for (item = fAppList.begin();
item != fAppList.end();
item++)
{
printf("%d: '%s'\n", counter++, item->c_str());
}
}

View File

@ -33,8 +33,13 @@
#include <SupportDefs.h>
#include <list>
#include <stdio.h>
#include <string>
namespace BPrivate {
class TRoster;
}
struct entry_ref;
class RecentApps {
@ -47,7 +52,11 @@ public:
status_t Get(int32 maxCount, BMessage *list);
status_t Clear();
status_t Print();
status_t Save(FILE* file);
private:
friend class BPrivate::TRoster;
// For loading from disk
static status_t GetRefForApp(const char *appSig, entry_ref *result);
std::list<std::string> fAppList;

View File

@ -32,6 +32,7 @@
#include <AppFileInfo.h>
#include <Entry.h>
#include <File.h>
#include <kernel_interface.h> // From the Storage Kit
#include <Message.h>
#include <Mime.h>
#include <Roster.h>
@ -39,8 +40,7 @@
#include <storage_support.h>
#include <new>
#include <stdio.h>
#include <string>
#include <map>
#define DBG(x) (x)
//#define DBG(x)
@ -50,20 +50,22 @@
// recent_entry
//------------------------------------------------------------------------------
/*! \brief An recent entry and the corresponding signature of the application
that launched/used/opened/viewed/whatevered it.
*/
struct recent_entry {
recent_entry(const entry_ref *ref, const char *appSig);
entry_ref ref;
std::string sig;
private:
recent_entry();
};
/*! \struct recent_entry
recent_entry::recent_entry(const entry_ref *ref, const char *appSig)
\brief A recent entry, the corresponding signature of the application
that launched/used/opened/viewed/whatevered it, and an index used for
keeping track of orderings when loading/storing the recent entries list
from/to disk.
*/
/*! \brief Creates a new recent_entry object.
*/
recent_entry::recent_entry(const entry_ref *ref, const char *appSig,
uint32 index)
: ref(ref ? *ref : entry_ref())
, sig(appSig)
, index(index)
{
}
@ -136,7 +138,7 @@ RecentEntries::Add(const entry_ref *ref, const char *appSig)
}
// Add this entry to the front of the list
recent_entry *entry = new(nothrow) recent_entry(ref, appSig);
recent_entry *entry = new(nothrow) recent_entry(ref, appSig, 0);
error = entry ? B_OK : B_NO_MEMORY;
if (!error)
fEntryList.push_front(entry);
@ -229,13 +231,95 @@ RecentEntries::Print()
item != fEntryList.end();
item++)
{
printf("%d: device == '%ld', dir == '%lld', name == '%s', app == '%s'\n",
printf("%d: device == '%ld', dir == '%lld', name == '%s', app == '%s', index == %ld\n",
counter++, (*item)->ref.device, (*item)->ref.directory, (*item)->ref.name,
(*item)->sig.c_str());
(*item)->sig.c_str(), (*item)->index);
}
}
// RecentEntries
// Save
status_t
RecentEntries::Save(FILE* file, const char *description, const char *tag)
{
status_t error = file ? B_OK : B_BAD_VALUE;
if (!error) {
fprintf(file, "# %s\n", description);
/* In order to write our entries out in the format used by the
Roster settings file, we need to collect all the signatures
for each entry in one place, while at the same time updating
the index values for each entry/sig pair to reflect the current
ordering of the list. I believe this is the data structure
R5 actually maintains all the time, as their indices do not
change over time (whereas ours will). If our implementation
proves to be slower that R5, we may want to consider using
the data structure pervasively.
*/
std::map<entry_ref, std::list<recent_entry*> > map;
uint32 count = fEntryList.size();
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 {
DBG(OUT("WARNING: RecentEntries::Save(): The entry %ld entries "
"from the front of fEntryList was found to be NULL\n",
fEntryList.size() - count));
}
}
for (std::map<entry_ref, std::list<recent_entry*> >::iterator mapItem
= map.begin();
mapItem != map.end();
mapItem++)
{
// We're going to need to properly escape the path name we
// get, which will at absolute worst double the length of
// the string.
char path[B_PATH_NAME_LENGTH];
char escapedPath[B_PATH_NAME_LENGTH*2];
status_t outputError = BPrivate::Storage::entry_ref_to_path(&mapItem->first,
path, B_PATH_NAME_LENGTH);
if (!outputError) {
BPrivate::Storage::escape_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\" %ld", entry->sig.c_str(), entry->index);
else {
DBG(OUT("WARNING: RecentEntries::Save(): The entry %ld entries "
"from the front of the compiled recent_entry* list for the "
"entry ref (%ld, %lld, '%s') was found to be NULL\n",
i, mapItem->first.device, mapItem->first.directory,
mapItem->first.name));
}
}
fprintf(file, "\n");
} else {
DBG(OUT("WARNING: RecentEntries::Save(): entry_ref_to_path() failed on "
"the entry_ref (%ld, %lld, '%s') with error 0x%lx\n",
mapItem->first.device, mapItem->first.directory,
mapItem->first.name, outputError));
}
}
fprintf(file, "\n");
}
return error;
}
// GetTypeForRef
/*! \brief Fetches the file type of the given file.
If the file has no type, an empty string is returned. The file

View File

@ -30,12 +30,25 @@
#ifndef RECENT_ENTRIES_H
#define RECENT_ENTRIES_H
#include <Entry.h>
#include <SupportDefs.h>
#include <list>
#include <stdio.h>
#include <string>
struct entry_ref;
struct recent_entry;
namespace BPrivate {
class TRoster;
}
struct recent_entry {
recent_entry(const entry_ref *ref, const char *appSig, uint32 index);
entry_ref ref;
std::string sig;
uint32 index;
private:
recent_entry();
};
class RecentEntries {
public:
@ -47,7 +60,10 @@ public:
const char *appSig, BMessage *result);
status_t Clear();
status_t Print();
status_t Save(FILE* file, const char *description, const char *tag);
private:
friend class BPrivate::TRoster;
static status_t GetTypeForRef(const entry_ref *ref, char *result);
std::list<recent_entry*> fEntryList;

View File

@ -0,0 +1,405 @@
#include "RosterSettingsCharStream.h"
#include <sniffer/Err.h>
#include <StorageDefs.h>
#include <stdio.h>
using namespace BPrivate::Storage::Sniffer;
//------------------------------------------------------------------------------
// CharStream
//------------------------------------------------------------------------------
RosterSettingsCharStream::RosterSettingsCharStream(const std::string &string)
: CharStream(string)
{
}
RosterSettingsCharStream::RosterSettingsCharStream()
: CharStream()
{
}
RosterSettingsCharStream::~RosterSettingsCharStream()
{
}
/*! \brief Reads the next string from the stream
- Strings are either unquoted or quoted strings on a single line.
- Whitespace is either spaces or tabs.
- Newlines separate lines and are never included in strings.
- Comments extend to the end of the line and must begin the line
with #. Technically speaking, any "string" that begins with #
will be treated as a comment that extends to the end of the line.
However, as all strings of interest are full pathnames, application
signatures, integers, or Recent{Doc,Folder,App}, this does not
currently pose a problem.
- Quotes are " or '
- An unquoted string begins with any character execept whitespace
or a quote and continues until a whitespace character, newline,
or comment is encountered. Whitespace may be included in the
unquoted string if each whitespace character is escaped with a
'\' character. Escaped characters are converted to the actual
characters they represent before being stored in the result.
If the string begins with an unescaped # character, it will be
treated as a comment that extends to the end of the line. #
characters may appear unescaped anywhere else in the string.
- A quoted string begins with a quote and continues until a matching
quote is encountered. If a newline is found before that point,
kEndOfLine is returned. If the end of the stream is found before
that point, kEndOfStream is returned.
\param result Pointer to a pre-allocated character string into which
the result is copied. Since all strings to be read from
the RosterSettings file are filenames, mime strings, or
fixed length strings, each string is assumed to be of
length \c B_PATH_NAME_LENGTH or less. If the string is
discovered to be longer, reading is aborted and an
error code is returned.
\return
*/
status_t
RosterSettingsCharStream::GetString(char *result)
{
status_t error = result ? B_OK : B_BAD_VALUE;
if (!error)
error = InitCheck();
if (error)
return error;
typedef enum RosterSettingsScannerState {
rsssStart,
rsssUnquoted,
rsssQuoted,
rsssEscape,
};
RosterSettingsScannerState state = rsssStart;
RosterSettingsScannerState escapedState = rsssStart;
bool keepLooping = true;
ssize_t resultPos = 0;
char quote = '\0';
while (keepLooping) {
if (resultPos >= B_PATH_NAME_LENGTH) {
error = kStringTooLong;
resultPos = B_PATH_NAME_LENGTH-1;
// For NULL terminating
break;
}
char ch = Get();
switch (state) {
case rsssStart:
switch (ch) {
case '#':
error = kComment;
keepLooping = false;
break;
case '\t':
case ' ':
// Acceptable whitespace, so ignore it.
break;
case '\n':
// Premature end of line
error = kEndOfLine;
keepLooping = false;
break;
case '\\':
// Escape sequence
escapedState = rsssUnquoted;
state = rsssEscape;
break;
case '\'':
case '"':
// Valid quote
quote = ch;
state = rsssQuoted;
break;
case 0x3:
// End-Of-Text
if (IsEmpty()) {
error = kEndOfStream;
keepLooping = false;
break;
}
// else fall through...
default:
// Valid unquoted character
result[resultPos++] = ch;
state = rsssUnquoted;
break;
}
break;
case rsssUnquoted:
switch (ch) {
case '\t':
case ' ':
// Terminating whitespace
keepLooping = false;
break;
case '\n':
// End of line
error = kEndOfLine;
keepLooping = false;
break;
case '\\':
// Escape sequence
escapedState = state;
state = rsssEscape;
break;
case 0x3:
// End-Of-Text
if (IsEmpty()) {
error = kEndOfStream;
keepLooping = false;
break;
}
// else fall through...
case '#':
// comments must begin the string, thus
// this char also falls through...
default:
// Valid unquoted character
result[resultPos++] = ch;
break;
}
break;
case rsssQuoted:
if (ch == quote) {
// Terminating quote
keepLooping = false;
} else {
switch (ch) {
case '\n':
// End of line
error = kUnterminatedQuotedString;
keepLooping = false;
break;
case '\\':
// Escape sequence
escapedState = state;
state = rsssEscape;
break;
case 0x3:
// End-Of-Text
if (IsEmpty()) {
error = kEndOfStream;
keepLooping = false;
break;
}
// else fall through...
default:
// Valid quoted character
result[resultPos++] = ch;
break;
}
}
break;
case rsssEscape:
switch (ch) {
case '\n':
// End of line cannot be escaped
error = kInvalidEscape;
keepLooping = false;
break;
case 0x3:
// End-Of-Text
if (IsEmpty()) {
error = kInvalidEscape;
keepLooping = false;
break;
}
// else fall through...
default:
// Valid unquoted character
result[resultPos++] = ch;
state = escapedState;
break;
}
break;
default:
error = kUnexpectedState;
keepLooping = false;
break;
}
}
// Read past any comments
if (error == kComment) {
// Read to the end of the line. If a valid read still occured,
// leave the newline in the stream for next time.
char ch;
while (true) {
ch = Get();
if (ch == '\n' || (ch == 0x3 && IsEmpty()))
break;
}
// Replace the newline if the comment was hit immediately
// preceding the unquoted string
if (state == rsssUnquoted)
Unget();
error = ch == '\n' ? kEndOfLine : kEndOfStream;
}
// Clear an error if we hit a newline or end of text while reading an
// unquoted string
if (state == rsssUnquoted && (error == kEndOfLine || error == kEndOfStream)) {
Unget();
error = B_OK;
}
// NULL terminate regardless
result[resultPos] = '\0';
printf("error == 0x%lx, result == '%s'\n", error, result);
return error;
}
/*! \brief Reads past any remaining characters on the current line.
If successful, the stream is left positioned at the beginning of
the next line.
\return
- \c B_OK: success
- kEndOfStream: The end of the stream was reached.
*/
status_t
RosterSettingsCharStream::SkipLine()
{
while (true) {
char ch = Get();
if (ch == '\n')
return B_OK;
else if (ch == 0x3 && IsEmpty())
return kEndOfStream;
}
}
const char *roster_settings_icons =
"\xa1\xa5\x9d\xd6\xac\x98\x83\xaa\x5f\xcb\x9b\x9a\xa3\xb1\xaa\xa7"
"\xb1\xb2\x58\xca\xb2\xa0\xa9\x57\xde\xc7\xc4\xc6\x59\xb5\xbd\xa5"
"\x9b\x9f\x97\xd0\xa6\x92\x7d\xa4\x59\xb5\x8f\x99\x95\xae\x5d\xab"
"\xac\x65\x9a\xb5\x6b\x9b\x4e\xa4\xcd\xbb\xaf\xb4\x9c\xb5\xba\x9f"
"\x88\x8c\x84\xbd\x93\x7f\x63\x87\x99\x60\x75\x89\x8b\x9e\x9c\x9e"
"\x4a\x98\x8e\xaf\x51\x83\x80\x95\x6c\xac\x9f\xa8\x85\xa7\xbe\x2f"
"\xb9\xbd\xb5\xee\xc4\xb0\x94\xb8\xca\x91\xa6\xa6\xc4\xd1\xc9\xbd"
"\x7b\xc4\x70\xd0\xc3\xb1\xb1\x6f\xf0\xd1\xd3\xd1\xcf\x86\x92\x60"
"\x9e\xa2\x9a\xd3\xa9\x95\x79\xa7\xaa\xbf\x89\x90\xa6\x6d\xb3\xaa"
"\x60\xbd\x55\xb7\xb6\x99\xa5\x54\xca\xb6\xc2\xb6\x56\x7c\xd4\x45"
"\x7d\x81\x79\xb2\x88\x74\x58\x7f\x8a\xab\x67\x7c\x32\xa1\x8d\x8e"
"\x98\x97\x79\x96\x46\x70\x79\x7f\xa6\xa7\xa9\x51\x36\x4a\x56\x24"
"\xb3\xb7\xaf\xe8\xbe\xaa\x8e\xb1\xb2\xde\x58\xab\xb7\xd5\xc9\x70"
"\xbd\xc6\xbd\x88\xce\xa5\xaa\x69\xea\xde\xc2\xd6\xb7\xc4\xdd\xb7"
"\x8e\x92\x8a\xc3\x99\x85\x69\x8c\x8d\xb9\x33\x7b\x43\xb0\x9e\x94"
"\x96\x9e\x8e\xb1\x9e\x3b\x89\x89\xb3\xa9\x9d\xa4\x8e\x9f\xc4\x35"
"\x96\x9a\x92\xcb\xa1\x8d\x71\x95\xa7\x6e\x7d\x97\x9e\xbe\x58\xa6"
"\xa6\xa9\x93\xb1\xa8\x91\x90\x4c\xd3\xbc\xb9\xbb\x4e\xaa\xb2\x9a"
"\xb0\xb4\xac\xe5\xbb\xa7\x8b\xaf\xc1\x88\xa1\xa5\xb8\xd3\xb7\xbb"
"\xbb\xc8\xae\x85\xcd\xac\x63\xb3\xd9\xdb\xbf\xcf\xc6\x7d\x89\x57"
"\x7d\x81\x79\xb2\x88\x74\x58\x7b\x7c\xa8\x22\x71\x73\x90\x3f\x82"
"\x88\x9a\x34\xa4\x8b\x80\x75\x81\xa8\x99\xa9\x51\x36\x4a\x56\x24"
"\x84\x88\x80\xb9\x8f\x7b\x5f\x83\x95\x5c\x6e\x7e\x7a\xa0\x95\x93"
"\x8b\x92\x3b\xb0\x96\x85\x7f\x3a\xc1\xaa\xa7\xa9\x3c\x98\xa0\x88"
"\xa5\x9f\x8c\xbd\xa2\x81\xb7\x92\x9a\xb4\x81\x88\x91\xab\x9e\x99"
"\x9e\xa6\x93\xb1\xa5\x89\x8f\x92\xc0\xb3\xaa\xaf\x94\xa8\xb4\x82"
"\xa7\xab\xa3\xdc\xb2\x9e\x82\xa6\xb8\x7f\x8d\x53\xb0\xcb\xb7\xa5"
"\xc7\x72\x5f\x7d\x71\x55\x5b\x5e\x8c\x7f\x76\x7b\x60\x74\x80\x4e"
"\x9a\x9e\x96\xcf\xa5\x91\x75\x99\xab\x72\x80\x46\xa3\xbb\xab\xac"
"\xb0\xc2\x52\x70\x64\x48\x4e\x51\x7f\x72\x69\x6e\x53\x67\x73\x41"
"\x95\x99\x91\xca\xa0\x8c\x70\x9e\xa0\xb2\x86\x8d\x9d\x64\xaa\xa1"
"\xa4\xa4\xa0\xb2\xa7\x90\x8f\x4b\xbf\xb5\xb6\xb0\xa6\xbf\x6e\x3c"
"\x84\x6e\x64\x7b\x8e\x8e\xc9\x50\xac\xc7\x8d\x87\x4f\xb7\xab\xa9"
"\x5c\xb8\xa3\xbe\xb8\x9b\xab\x51\x7f\x72\x69\x6e\x53\x67\x73\x41"
"\x8c\x77\x6c\x83\x96\x96\xcf\x58\xa1\x7a\x8a\x8f\xab\xb9\xb3\xab"
"\xad\xaf\x59\xbb\xb0\xa5\xa4\xad\xda\xd7\x71\x76\x5b\x6f\x7b\x49"
"\x79\x65\x59\x70\x8c\x75\xb6\x99\x92\xb9\x34\x84\x97\x5e\xa5\x94"
"\x96\x59\x88\xa9\xab\x90\xa0\x46\x74\x67\x5e\x63\x48\x5c\x68\x36"
"\x98\x81\x77\x8e\x94\x52\xdc\xb5\xba\xda\xa6\xac\xae\xbd\xbf\x6a"
"\xbc\xd0\x64\xc8\xc8\xa3\xa5\xb1\xd5\xe2\x7c\x81\x66\x7a\x86\x54"
"\x8c\x76\x6b\x82\x8d\x95\xce\x57\xb8\xc8\x9b\x9f\x56\xb7\xb8\xb2"
"\xb6\xc4\x58\xbf\xb8\xa1\xa3\xa3\xca\xc6\xb2\xb9\xb7\x6e\x7a\x48"
"\x70\x5b\x4f\x66\x74\x2a\xb3\x88\x8c\xb1\x6f\x31\x93\xa3\x9c\x42"
"\x9e\x98\x90\xa2\x4e\x78\x8d\x8d\xc2\xba\x54\x59\x3e\x52\x5e\x2c"
"\x77\x5f\x55\x6c\x7a\x83\x66\x9a\x98\xb8\x82\x37\x62\x9f\x7c\x7b"
"\xab\x56\x43\x61\x55\x39\x3f\x42\x70\x63\x5a\x5f\x44\x58\x64\x32"
"\x7a\x63\x58\x6f\x88\x7b\xae\x44\x8d\xa8\x86\x89\x8f\xb2\xa4\x90"
"\x50\x9a\x86\xb5\x64\x89\x90\x92\xb7\x65\x9e\xa6\x99\xae\x85\x92"
"\xa8\x92\x86\x9d\xb6\xa9\xdc\xc4\xbf\x94\xaa\xbb\x71\xcd\xd3\xcd"
"\x7e\xd5\xc1\xd6\x9f\x69\x97\xb3\xe9\xde\xdf\xed\x75\x89\x95\x63"
"\xaf\xb3\xab\xe4\xba\xa6\x91\xb8\x6d\xce\xa3\xa9\xb2\xbf\x71\xc0"
"\xc3\xc8\xbb\xd8\xcb\xa8\xa3\xb5\x93\xdb\xcf\x82\xaf\xbf\xe5\x56"
"\xa6\xaa\xa2\xdb\xb1\x9d\x88\xaf\x64\xc5\x9a\xa0\xa9\xb6\x68\xb7"
"\xba\xbf\xb2\xcf\xc2\x9f\x9a\xac\x8a\xd6\xc3\xce\xbc\x73\x7f\x4d"
"\xab\xaf\xa7\xe0\xb6\xa2\x86\xb3\xb8\xc6\x9b\xaa\x60\xce\xb5\xad"
"\x6d\xb8\xa3\xd3\xb6\x99\xa6\xbf\x90\x83\x7a\x7f\x64\x78\x84\x52"
"\x90\x94\x8c\xc5\x9b\x87\x6b\x92\x97\xbe\x7a\x8f\x45\xa8\xa0\x4d"
"\x74\xac\x9c\xb3\xa8\x90\x43\x88\xb5\xba\xa3\xb0\x8d\xaa\xbc\x94"
"\xa4\xa8\xa0\xd9\xaf\x9b\x86\xad\x62\xc5\x96\xa0\xab\xb8\xb9\xb4"
"\xab\xb2\x5b\xbb\xc6\x51\xb0\xa9\xdd\xcd\x72\xc4\xac\x83\xcf\xa8"
"\xb0\xb4\xac\xe5\xbb\xa7\x92\xb9\x6e\xd7\xab\xa1\xb7\xd6\xc1\xbf"
"\xbd\xbf\xab\x85\x7f\x5d\xb8\xb4\xd8\xcc\xd0\xd3\xa9\xc5\xcc\xb4"
"\x7e\x82\x7a\xb3\x89\x75\x59\x7d\x8f\x56\x66\x79\x80\x9d\x8f\x8e"
"\x89\x96\x7c\x53\x8f\x6c\x7a\x7f\xb7\xa8\xaa\x52\x37\x4b\x57\x25"
"\xa1\xa5\x9d\xd6\xac\x98\x7c\xa0\xb2\x79\x9b\x9b\x9a\xc9\xac\xac"
"\xaa\xb7\xb1\x76\xb6\x9d\xad\x98\xd1\xd6\x70\x75\x5a\x6e\x7a\x48"
"\x97\xac\x94\xc2\xa7\x40\xc9\x9f\xa2\xb9\x86\x47\xa3\xb8\xa6\x9e"
"\xa3\x65\x99\xbf\xa9\x9b\x4e\x88\xc0\xbe\xbd\xb3\xa5\xc5\x74\x42"
"\x88\x8c\x84\xbd\x93\x7f\x6a\x91\x46\xa8\x6e\x8a\x86\xa5\x91\x45"
"\x8b\x52\x96\xac\x9f\x79\x80\x90\xb2\xb4\xa2\x5b\x84\x95\xb9\x8c"
"\xb9\xbd\xb5\xee\xc4\xb0\x94\xb8\xca\x91\xb5\xb7\xb7\xdc\xc4\xc4"
"\xc2\x83\xb1\x8e\xd2\xb5\xb1\xbc\xfb\x91\x88\x8d\x72\x86\x92\x60"
"\x9e\xa2\x9a\xd3\xa9\x95\x79\xa7\x9d\xcf\x96\x4a\x7b\xae\xa9\xa6"
"\xb5\x68\xa7\xc2\xaa\x96\xa4\xb2\x83\x76\x6d\x72\x57\x6b\x77\x45"
"\x7d\x81\x79\xb2\x88\x74\x58\x85\x8a\x98\x6d\x7c\x32\xa1\x3f\x86"
"\x88\x92\x79\x52\x87\x2a\x78\x88\xb3\xa6\x94\x93\x76\x97\x9a\x81"
"\xb3\xb7\xaf\xe8\xbe\xaa\x8e\xb2\xc4\x8b\x9c\xa4\xb4\xd8\xbe\xbe"
"\xbc\x7d\xbe\xd0\xce\xb5\x66\xc2\xe6\xdf\xd3\x86\xb3\xc3\xe9\x5a"
"\x8e\x92\x8a\xc3\x99\x85\x69\x8d\x9f\x66\x7f\x89\x96\xb1\x50\x94"
"\x9e\x58\x9e\xb2\xac\x8d\x41\x8c\xb6\xc3\x5d\x62\x47\x5b\x67\x35"
"\x96\x9a\x92\xcb\xa1\x8d\x78\x9f\x54\xbb\x90\x90\x8e\xad\xa1\xa1"
"\x9f\x60\x9c\xb9\x5f\x9c\x98\xa1\xcc\x6d\xaa\xb2\x9a\xa7\xc1\x9a"
"\xb0\xb4\xac\xe5\xbb\xa7\x8b\x85\x6e\xda\x96\xac\xb9\xd4\xc4\xb2"
"\x72\x94\x67\xc9\xbe\xad\xb5\xab\xe7\xda\xc7\xd2\xb6\xda\x89\x57"
"\x7d\x81\x79\xb2\x88\x74\x58\x52\x3b\xa2\x6b\x7b\x86\x94\x3f\x54"
"\x3f\x8b\x79\xa2\x98\x6b\x86\x7c\xb5\xad\xa9\x51\x36\x4a\x56\x24"
"\x71\x96\x34\xb3\x99\x7d\x5f\x80\x87\xa1\x6d\x30\x8d\x9b\x8b\x41"
"\x7d\x8f\x87\xad\x92\x83\x95\x3b\x69\x5c\x53\x58\x3d\x51\x5d\x2b"
"\x8d\x91\x69\xa2\x98\x64\x68\x50\x68\xae\x8c\x7a\x5f\x69\x4f\x61"
"\x62\x6a\x98\x62\xa3\x4d\x56\x84\x7e\xac\x7c\xb8\x55\xab\xc3\x34"
"\xa7\xab\xa3\xdc\xb2\x9e\xb9\x9e\xb1\xd3\x91\xa5\x93\xb7\xb5\xb8"
"\xae\xc3\x95\xbd\xbc\xa8\x9f\xaf\xc2\xbf\xc1\xce\xa4\xc5\xdd\x4e"
"\x9a\x9e\x96\xcf\xa5\x91\x75\x99\xab\x72\x72\x9a\xa4\xaa\xae\xab"
"\x63\xb7\x51\xb1\xa8\x9a\xa1\x50\xc4\xc3\xb1\xb2\xa0\xaa\xd0\x41"
"\x7f\xa4\x91\x76\xb0\x8c\x70\x82\x94\xb9\x8e\x86\x9c\xb7\x57\x93"
"\xa9\xa4\x4c\xac\xa3\x8e\x97\x99\xc0\x6c\xb7\xb7\x4d\xb6\xc0\x99"
;

View File

@ -0,0 +1,74 @@
//------------------------------------------------------------------------------
// Copyright (c) 2001-2002, OpenBeOS
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: RecentApps.cpp
// Author: Tyler Dauwalder (tyler@dauwalder.net)
// Description: Recently launched apps list
//------------------------------------------------------------------------------
/*!
\file sniffer/RosterSettingsCharStream.h
Character stream class
*/
#ifndef _ROSTER_SETTINGS_CHAR_STREAM_H
#define _ROSTER_SETTINGS_CHAR_STREAM_H
#include <sniffer/CharStream.h>
#include <SupportDefs.h>
#include <string>
//! A character stream manager designed for use with RosterSettings files
/*! The purpose for this class is to make reading through RosterSettings files,
which contain a number of different types of strings (some with escapes),
as well as comments, as painless as possible.
The main idea is that GetString() will return \c B_OK and a new string
until it hits an error or the end of the line, at which point an error
code is returned. The next call to GetString() starts the cycle over on
the next line. When the end of the stream is finally hit, kEndOfStream is
returned.
SkipLine() simply moves the position of the stream to the next line, and is
used when a valid string containing invalid data is discovered in the middle
of a line.
*/
class RosterSettingsCharStream : public BPrivate::Storage::Sniffer::CharStream {
public:
RosterSettingsCharStream(const std::string &string);
RosterSettingsCharStream();
virtual ~RosterSettingsCharStream();
status_t GetString(char *result);
status_t SkipLine();
static const status_t kEndOfLine = B_ERRORS_END+1;
static const status_t kEndOfStream = B_ERRORS_END+2;
static const status_t kInvalidEscape = B_ERRORS_END+3;
static const status_t kUnterminatedQuotedString = B_ERRORS_END+4;
static const status_t kComment = B_ERRORS_END+5;
static const status_t kUnexpectedState = B_ERRORS_END+6;
static const status_t kStringTooLong = B_ERRORS_END+7;
private:
RosterSettingsCharStream(const RosterSettingsCharStream &ref);
RosterSettingsCharStream& operator=(const RosterSettingsCharStream &ref);
};
#endif // _ROSTER_SETTINGS_CHAR_STREAM_H

View File

@ -31,12 +31,27 @@
#include <AppMisc.h>
#include <storage_support.h>
#include <errno.h>
#include <stdio.h>
#include "Debug.h"
#include "RegistrarDefs.h"
#include "RosterAppInfo.h"
#include "RosterSettingsCharStream.h"
#include "TRoster.h"
#include "EventMaskWatcher.h"
//------------------------------------------------------------------------------
// Private local function declarations
//------------------------------------------------------------------------------
static bool larger_index(const recent_entry *entry1, const recent_entry *entry2);
//------------------------------------------------------------------------------
// TRoster
//------------------------------------------------------------------------------
/*!
\class TRoster
\brief Implements the application roster.
@ -66,6 +81,9 @@
//! The maximal period of time an app may be early pre-registered (60 s).
const bigtime_t kMaximalEarlyPreRegistrationPeriod = 60000000LL;
const char *TRoster::kDefaultRosterSettingsFile =
"/boot/home/config/settings/Roster/OpenBeOSRosterSettings";
// constructor
/*! \brief Creates a new roster.
@ -77,8 +95,12 @@ TRoster::TRoster()
fIAPRRequests(),
fActiveApp(NULL),
fWatchingService(),
fRecentApps(),
fRecentDocuments(),
fRecentFolders(),
fLastToken(0)
{
_LoadRosterSettings();
}
// destructor
@ -1302,3 +1324,212 @@ TRoster::_HandleGetRecentEntries(BMessage *request)
FUNCTION_END();
}
status_t
TRoster::_LoadRosterSettings(const char *path)
{
const char *settingsPath = path ? path : kDefaultRosterSettingsFile;
RosterSettingsCharStream stream;
status_t error;
BFile file;
error = file.SetTo(settingsPath, B_READ_ONLY);
off_t size;
if (!error)
error = file.GetSize(&size);
char *data;
if (!error) {
data = new(nothrow) char[size];
error = data ? B_OK : B_NO_MEMORY;
}
if (!error) {
ssize_t bytes = file.Read(data, size);
error = bytes < 0 ? bytes : (bytes == size ? B_OK : B_FILE_ERROR);
}
if (!error)
error = stream.SetTo(std::string(data));
if (!error) {
// Clear the current lists as
// we'll be manually building them up
fRecentDocuments.Clear();
fRecentFolders.Clear();
fRecentApps.Clear();
// Now we just walk through the file and read in the info
while (true) {
status_t streamError;
char str[B_PATH_NAME_LENGTH];
// (RecentDoc | RecentFolder | RecentApp)
streamError = stream.GetString(str);
if (!streamError) {
enum EntryType {
etDoc,
etFolder,
etApp,
etSomethingIsAmiss,
} type;
if (strcmp(str, "RecentDoc") == 0) {
type = etDoc;
} else if (strcmp(str, "RecentFolder") == 0) {
type = etFolder;
} else if (strcmp(str, "RecentApp") == 0) {
type = etApp;
} else {
type = etSomethingIsAmiss;
}
switch (type) {
case etDoc:
case etFolder:
{
// For curing laziness
std::list<recent_entry*> *list = (type == etDoc)
? &fRecentDocuments.fEntryList
: &fRecentFolders.fEntryList;
char path[B_PATH_NAME_LENGTH];
char app[B_PATH_NAME_LENGTH];
char rank[B_PATH_NAME_LENGTH];
entry_ref ref;
uint32 index = 0;
// Convert the given path to an entry ref
streamError = stream.GetString(path);
if (!streamError)
streamError = get_ref_for_path(path, &ref);
// Add a new entry to the list for each application
// signature and rank we find
while (!streamError) {
if (!streamError)
streamError = stream.GetString(app);
if (!streamError) {
BPrivate::Storage::to_lower(app);
streamError = stream.GetString(rank);
}
if (!streamError) {
index = strtoul(rank, NULL, 10);
if (index == ULONG_MAX)
streamError = errno;
}
recent_entry *entry = NULL;
if (!streamError) {
entry = new(nothrow) recent_entry(&ref, app, index);
streamError = entry ? B_OK : B_NO_MEMORY;
}
if (!streamError) {
printf("pushing entry, leaf == '%s', app == '%s', index == %ld\n",
entry->ref.name, entry->sig.c_str(), entry->index);
list->push_back(entry);
}
}
if (streamError) {
printf("entry error 0x%lx\n", streamError);
if (streamError != RosterSettingsCharStream::kEndOfLine
&& streamError != RosterSettingsCharStream::kEndOfStream)
stream.SkipLine();
}
break;
}
case etApp:
{
char app[B_PATH_NAME_LENGTH];
streamError = stream.GetString(app);
if (!streamError) {
BPrivate::Storage::to_lower(app);
fRecentApps.fAppList.push_back(app);
} else
stream.SkipLine();
break;
}
default:
// Something was amiss; skip to the next line
stream.SkipLine();
break;
}
}
if (streamError == RosterSettingsCharStream::kEndOfStream)
break;
}
// Now we must sort our lists of documents and folders by the
// indicies we read for each entry (largest index first)
fRecentDocuments.fEntryList.sort(larger_index);
fRecentFolders.fEntryList.sort(larger_index);
printf("----------------------------------------------------------------------\n");
fRecentDocuments.Print();
printf("----------------------------------------------------------------------\n");
fRecentFolders.Print();
printf("----------------------------------------------------------------------\n");
fRecentApps.Print();
printf("----------------------------------------------------------------------\n");
}
if (error)
D(PRINT(("WARNING: TRoster::_LoadRosterSettings(): error loading roster settings "
"from '%s', 0x%lx\n", settingsPath, error)));
return error;
}
status_t
TRoster::_SaveRosterSettings(const char *path)
{
const char *settingsPath = path ? path : kDefaultRosterSettingsFile;
status_t error;
FILE* file;
file = fopen(settingsPath, "w+");
error = file ? B_OK : errno;
if (!error) {
status_t saveError;
saveError = fRecentDocuments.Save(file, "Recent documents", "RecentDoc");
if (saveError)
D(PRINT(("TRoster::_SaveRosterSettings(): recent documents save failed "
"with error 0x%lx\n", saveError)));
saveError = fRecentFolders.Save(file, "Recent folders", "RecentFolder");
if (saveError)
D(PRINT(("TRoster::_SaveRosterSettings(): recent folders save failed "
"with error 0x%lx\n", saveError)));
saveError = fRecentApps.Save(file);
if (saveError)
D(PRINT(("TRoster::_SaveRosterSettings(): recent folders save failed "
"with error 0x%lx\n", saveError)));
fclose(file);
}
return error;
}
//------------------------------------------------------------------------------
// Private local functions
//------------------------------------------------------------------------------
/*! \brief Returns true if entry1's index is larger than entry2's index.
Also returns true if either entry is \c NULL.
Used for sorting the recent entry lists loaded from disk into the
proper order.
*/
bool
larger_index(const recent_entry *entry1, const recent_entry *entry2)
{
if (entry1 && entry2)
return entry1->index > entry2->index;
else
return true;
}

View File

@ -103,7 +103,11 @@ private:
void _ReplyToIAPRRequest(BMessage *request, const RosterAppInfo *info);
void _HandleGetRecentEntries(BMessage *request);
status_t _LoadRosterSettings(const char *path = NULL);
status_t _SaveRosterSettings(const char *path = NULL);
static const char *kDefaultRosterSettingsFile;
private:
AppInfoList fRegisteredApps;
AppInfoList fEarlyPreRegisteredApps;