2010-05-07 04:47:10 -05:00
|
|
|
/*
|
2011-12-03 16:38:03 -06:00
|
|
|
* Copyright 2009-2011, Pier Luigi Fiorini. All rights reserved.
|
2021-06-06 12:02:26 -05:00
|
|
|
* Copyright 2014, Funky Idea Software
|
2021-06-12 21:42:10 -05:00
|
|
|
* Copyright 2021, Jaidyn Levesque
|
2010-05-07 04:47:10 -05:00
|
|
|
* Distributed under the terms of the MIT License.
|
|
|
|
*/
|
|
|
|
#include <memory.h>
|
|
|
|
|
|
|
|
#include <Bitmap.h>
|
2021-06-04 13:57:04 -05:00
|
|
|
#include <InterfaceDefs.h>
|
2010-05-09 04:38:30 -05:00
|
|
|
#include <Directory.h>
|
|
|
|
#include <FindDirectory.h>
|
2015-06-24 11:23:04 -05:00
|
|
|
#include <IconUtils.h>
|
2021-06-18 18:42:10 -05:00
|
|
|
#include <Menu.h>
|
|
|
|
#include <MenuItem.h>
|
2010-05-09 04:38:30 -05:00
|
|
|
#include <Path.h>
|
2021-06-15 00:19:52 -05:00
|
|
|
#include <StringList.h>
|
2010-05-07 04:47:10 -05:00
|
|
|
|
2021-06-06 12:02:26 -05:00
|
|
|
#include <kernel/fs_attr.h>
|
|
|
|
|
2021-06-22 01:06:00 -05:00
|
|
|
#include "Cardie.h"
|
2021-06-20 12:44:20 -05:00
|
|
|
#include "Utils.h"
|
2010-05-07 04:47:10 -05:00
|
|
|
|
|
|
|
|
|
|
|
const char*
|
2021-06-20 12:44:20 -05:00
|
|
|
UserStatusToString(UserStatus status)
|
2010-05-07 04:47:10 -05:00
|
|
|
{
|
|
|
|
switch (status) {
|
2021-06-20 12:44:20 -05:00
|
|
|
case STATUS_ONLINE:
|
2010-05-07 04:47:10 -05:00
|
|
|
return "Available";
|
2021-06-20 12:44:20 -05:00
|
|
|
case STATUS_AWAY:
|
2010-05-07 04:47:10 -05:00
|
|
|
return "Away";
|
2021-06-20 12:44:20 -05:00
|
|
|
case STATUS_DO_NOT_DISTURB:
|
2010-05-07 04:47:10 -05:00
|
|
|
return "Busy";
|
2021-06-20 12:44:20 -05:00
|
|
|
case STATUS_CUSTOM_STATUS:
|
2012-05-15 12:20:11 -05:00
|
|
|
return "Custom Status";
|
2021-06-20 12:44:20 -05:00
|
|
|
case STATUS_INVISIBLE:
|
2012-05-15 12:20:11 -05:00
|
|
|
return "Invisible";
|
2021-06-20 12:44:20 -05:00
|
|
|
case STATUS_OFFLINE:
|
2012-05-15 12:20:11 -05:00
|
|
|
return "Offline";
|
2010-05-07 04:47:10 -05:00
|
|
|
default:
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-09 03:23:53 -05:00
|
|
|
|
2021-06-15 00:19:52 -05:00
|
|
|
bool
|
|
|
|
IsCommand(BString line)
|
|
|
|
{
|
|
|
|
return line.StartsWith("/");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BString
|
|
|
|
CommandName(BString line)
|
|
|
|
{
|
|
|
|
BStringList words;
|
|
|
|
line.Split(" ", true, words);
|
|
|
|
return words.StringAt(0).RemoveFirst("/");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BString
|
|
|
|
CommandArgs(BString line)
|
|
|
|
{
|
|
|
|
BString remove("/");
|
2021-06-15 00:45:51 -05:00
|
|
|
remove << CommandName(line) << "";
|
|
|
|
line.RemoveFirst(remove);
|
|
|
|
return line.Trim();
|
2021-06-15 00:19:52 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-09 03:23:53 -05:00
|
|
|
BResources*
|
2021-06-20 12:44:20 -05:00
|
|
|
ChatResources()
|
2010-05-09 03:23:53 -05:00
|
|
|
{
|
|
|
|
image_info info;
|
|
|
|
if (our_image(info) != B_OK)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
BFile file(info.name, B_READ_ONLY);
|
|
|
|
if (file.InitCheck() != B_OK)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
BResources* res = new BResources(&file);
|
|
|
|
if (res->InitCheck() != B_OK) {
|
|
|
|
delete res;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2010-05-09 04:38:30 -05:00
|
|
|
|
2021-06-18 18:42:10 -05:00
|
|
|
BMenu*
|
|
|
|
CreateAccountMenu(AccountInstances accounts, BMessage msg, BMessage* allMsg)
|
|
|
|
{
|
|
|
|
BMenu* menu = new BMenu("accountMenu");
|
|
|
|
|
|
|
|
if (allMsg != NULL)
|
|
|
|
menu->AddItem(new BMenuItem("All", new BMessage(*allMsg)));
|
|
|
|
|
|
|
|
for (int i = 0; i < accounts.CountItems(); i++)
|
|
|
|
menu->AddItem(new BMenuItem(accounts.KeyAt(i).String(), new BMessage(msg)));
|
|
|
|
menu->SetRadioMode(true);
|
|
|
|
menu->SetLabelFromMarked(true);
|
|
|
|
menu->ItemAt(0)->SetMarked(true);
|
|
|
|
|
|
|
|
if (accounts.CountItems() == 0)
|
|
|
|
menu->SetEnabled(false);
|
|
|
|
return menu;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-09 04:38:30 -05:00
|
|
|
const char*
|
2021-06-20 12:44:20 -05:00
|
|
|
AccountsPath()
|
2010-05-09 04:38:30 -05:00
|
|
|
{
|
|
|
|
BPath path;
|
|
|
|
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
|
|
|
|
return NULL;
|
|
|
|
|
Reorganize settings directory, custom purple paths
The settings file-hierarchy has been changed a bit:
* Cardie/
* preferences
* Accounts/
* Cache/
* Accounts/
* Add-Ons/
`Cardie/Protocols` is now `Cardie/Accounts`, and the cache directory
has been split into two. `Cache/Accounts/` is for account-specific
cached data (e.g., cached roster icons, data, etc.), and
`Cache/Protocols` is for protocol-wide settings/data.
For purple, this will be used as the user's libpurple directory,
which has been moved from the default of `~/.purple` (yikes!)
Some plugin search-paths have been given to purple, too― lib
directories + "/purple2/", and Cardie/Cache/Add-Ons/purple/plugins/.
2021-06-30 20:29:30 -05:00
|
|
|
path.Append(APP_NAME "/Accounts");
|
2010-05-09 04:38:30 -05:00
|
|
|
if (create_directory(path.Path(), 0755) != B_OK)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return path.Path();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const char*
|
Reorganize settings directory, custom purple paths
The settings file-hierarchy has been changed a bit:
* Cardie/
* preferences
* Accounts/
* Cache/
* Accounts/
* Add-Ons/
`Cardie/Protocols` is now `Cardie/Accounts`, and the cache directory
has been split into two. `Cache/Accounts/` is for account-specific
cached data (e.g., cached roster icons, data, etc.), and
`Cache/Protocols` is for protocol-wide settings/data.
For purple, this will be used as the user's libpurple directory,
which has been moved from the default of `~/.purple` (yikes!)
Some plugin search-paths have been given to purple, too― lib
directories + "/purple2/", and Cardie/Cache/Add-Ons/purple/plugins/.
2021-06-30 20:29:30 -05:00
|
|
|
AccountPath(const char* signature, const char* subsignature)
|
2010-05-09 04:38:30 -05:00
|
|
|
{
|
2021-06-20 12:44:20 -05:00
|
|
|
BPath path(AccountsPath());
|
2010-05-09 04:38:30 -05:00
|
|
|
if (path.InitCheck() != B_OK)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
path.Append(signature);
|
Reorganize settings directory, custom purple paths
The settings file-hierarchy has been changed a bit:
* Cardie/
* preferences
* Accounts/
* Cache/
* Accounts/
* Add-Ons/
`Cardie/Protocols` is now `Cardie/Accounts`, and the cache directory
has been split into two. `Cache/Accounts/` is for account-specific
cached data (e.g., cached roster icons, data, etc.), and
`Cache/Protocols` is for protocol-wide settings/data.
For purple, this will be used as the user's libpurple directory,
which has been moved from the default of `~/.purple` (yikes!)
Some plugin search-paths have been given to purple, too― lib
directories + "/purple2/", and Cardie/Cache/Add-Ons/purple/plugins/.
2021-06-30 20:29:30 -05:00
|
|
|
if (BString(signature) != BString(subsignature)
|
|
|
|
&& BString(subsignature).IsEmpty() == false)
|
|
|
|
path.Append(subsignature);
|
2010-05-09 04:38:30 -05:00
|
|
|
|
Allow multiple protocols per add-on
Now an add-on can contain multiple protocols, and the protocol API has
changed. An add-on must now export protocol_count() and protocol_at(),
with the latter replacing protocol(). protocol_count() returning the
amount of protocols in a given add-on, and protocol_at(i) giving a
new CayaProtocol* "at" the given index.
CayaProtocol has also been changed, adding Signature(),
FriendlySignature(), Icon(), Path(), and SetPath(). The reasoning is
that different protocols (even within a single add-on) will have
different signatures and icons, so this data should be accessible from
the protocol itself.
CayaProtocolAddOn now has CountProtocols() and ProtocolAt(i), allowing
the accessing of multiple protocols. A CayaProtocolAddOn can be given a
default protocol index in the constructor, whose protocol will be
returned with Protocol(). Version() was also moved from CayaProtocol to
CayaProtocolAddOn.
2021-05-21 13:33:43 -05:00
|
|
|
if (create_directory(path.Path(), 0755) != B_OK)
|
|
|
|
return NULL;
|
|
|
|
return path.Path();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-05-24 14:20:57 -05:00
|
|
|
const char*
|
2021-06-20 12:44:20 -05:00
|
|
|
CachePath()
|
2021-05-24 14:20:57 -05:00
|
|
|
{
|
|
|
|
BPath path;
|
|
|
|
if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
|
|
|
|
return NULL;
|
2021-06-22 01:06:00 -05:00
|
|
|
path.Append(APP_NAME "/Cache");
|
2021-05-24 14:20:57 -05:00
|
|
|
if (create_directory(path.Path(), 0755) != B_OK)
|
|
|
|
return NULL;
|
|
|
|
return path.Path();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const char*
|
2021-06-20 12:44:20 -05:00
|
|
|
AccountCachePath(const char* accountName)
|
2021-05-24 14:20:57 -05:00
|
|
|
{
|
2021-06-20 12:44:20 -05:00
|
|
|
BPath path(CachePath());
|
Reorganize settings directory, custom purple paths
The settings file-hierarchy has been changed a bit:
* Cardie/
* preferences
* Accounts/
* Cache/
* Accounts/
* Add-Ons/
`Cardie/Protocols` is now `Cardie/Accounts`, and the cache directory
has been split into two. `Cache/Accounts/` is for account-specific
cached data (e.g., cached roster icons, data, etc.), and
`Cache/Protocols` is for protocol-wide settings/data.
For purple, this will be used as the user's libpurple directory,
which has been moved from the default of `~/.purple` (yikes!)
Some plugin search-paths have been given to purple, too― lib
directories + "/purple2/", and Cardie/Cache/Add-Ons/purple/plugins/.
2021-06-30 20:29:30 -05:00
|
|
|
path.Append("Accounts");
|
2021-06-12 21:42:10 -05:00
|
|
|
if (path.InitCheck() != B_OK)
|
2021-06-06 12:02:26 -05:00
|
|
|
return NULL;
|
2021-06-09 11:40:27 -05:00
|
|
|
path.Append(accountName);
|
2021-05-24 14:20:57 -05:00
|
|
|
if (create_directory(path.Path(), 0755) != B_OK)
|
|
|
|
return NULL;
|
2021-06-12 21:42:10 -05:00
|
|
|
return path.Path();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const char*
|
2021-06-20 12:44:20 -05:00
|
|
|
RoomsCachePath(const char* accountName)
|
2021-06-12 21:42:10 -05:00
|
|
|
{
|
2021-06-20 12:44:20 -05:00
|
|
|
BPath path(AccountCachePath(accountName));
|
2021-06-12 21:42:10 -05:00
|
|
|
if (path.InitCheck() != B_OK)
|
|
|
|
return NULL;
|
|
|
|
path.Append("Rooms");
|
|
|
|
if (create_directory(path.Path(), 0755) != B_OK)
|
|
|
|
return NULL;
|
|
|
|
return path.Path();
|
|
|
|
}
|
2021-05-24 14:20:57 -05:00
|
|
|
|
2021-06-12 21:42:10 -05:00
|
|
|
|
|
|
|
const char*
|
2021-06-20 12:44:20 -05:00
|
|
|
RoomCachePath(const char* accountName, const char* roomIdentifier)
|
2021-06-12 21:42:10 -05:00
|
|
|
{
|
2021-06-20 12:44:20 -05:00
|
|
|
BPath path(RoomsCachePath(accountName));
|
2021-06-13 17:34:30 -05:00
|
|
|
if (path.InitCheck() != B_OK) return NULL;
|
2021-06-12 21:42:10 -05:00
|
|
|
path.Append(roomIdentifier);
|
2021-05-24 14:20:57 -05:00
|
|
|
return path.Path();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-13 17:34:30 -05:00
|
|
|
const char*
|
2021-06-20 12:44:20 -05:00
|
|
|
UserCachePath(const char* accountName, const char* userIdentifier)
|
2021-06-13 17:34:30 -05:00
|
|
|
{
|
2021-06-20 12:44:20 -05:00
|
|
|
BPath path(AccountCachePath(accountName));
|
2021-06-13 17:34:30 -05:00
|
|
|
if (path.InitCheck() != B_OK) return NULL;
|
|
|
|
path.Append("Users");
|
|
|
|
if (create_directory(path.Path(), 0755) != B_OK) return NULL;
|
|
|
|
path.Append(userIdentifier);
|
|
|
|
return path.Path();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const char*
|
2021-06-20 12:44:20 -05:00
|
|
|
ContactCachePath(const char* accountName, const char* userIdentifier)
|
2021-06-13 17:34:30 -05:00
|
|
|
{
|
2021-06-20 12:44:20 -05:00
|
|
|
BPath path(AccountCachePath(accountName));
|
2021-06-13 17:34:30 -05:00
|
|
|
if (path.InitCheck() != B_OK) return NULL;
|
|
|
|
path.Append("People");
|
|
|
|
if (create_directory(path.Path(), 0755) != B_OK) return NULL;
|
|
|
|
path.Append(userIdentifier);
|
|
|
|
return path.Path();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-04 13:57:04 -05:00
|
|
|
rgb_color
|
2021-06-20 12:44:20 -05:00
|
|
|
TintColor(rgb_color color, int severity)
|
2021-06-04 13:57:04 -05:00
|
|
|
{
|
|
|
|
bool dark = false;
|
|
|
|
if (color.Brightness() < 127)
|
|
|
|
dark = true;
|
|
|
|
|
|
|
|
switch (severity)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
if (dark == true)
|
|
|
|
return tint_color(color, B_LIGHTEN_1_TINT + 0.2f);
|
|
|
|
else
|
|
|
|
return tint_color(color, B_DARKEN_1_TINT);
|
|
|
|
case 2:
|
|
|
|
if (dark == true)
|
|
|
|
return tint_color(color, B_LIGHTEN_1_TINT);
|
|
|
|
else
|
|
|
|
return tint_color(color, B_DARKEN_2_TINT);
|
|
|
|
case 3:
|
|
|
|
if (dark == true)
|
|
|
|
return tint_color(color, B_LIGHTEN_2_TINT + 0.1f);
|
|
|
|
else
|
|
|
|
return tint_color(color, B_DARKEN_3_TINT);
|
|
|
|
}
|
|
|
|
return color;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-07 00:56:26 -05:00
|
|
|
rgb_color
|
2021-06-20 12:44:20 -05:00
|
|
|
ForegroundColor(rgb_color background)
|
2021-06-07 00:56:26 -05:00
|
|
|
{
|
|
|
|
rgb_color foreground;
|
|
|
|
int32 brighter;
|
|
|
|
int32 darker;
|
|
|
|
float ratio;
|
|
|
|
|
|
|
|
do {
|
|
|
|
foreground.set_to(rand() % 255, rand() % 255, rand() %255);
|
|
|
|
if (foreground.Brightness() > background.Brightness()) {
|
|
|
|
brighter = foreground.Brightness();
|
|
|
|
darker = background.Brightness();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
brighter = background.Brightness();
|
|
|
|
darker = foreground.Brightness();
|
|
|
|
}
|
|
|
|
ratio = (brighter + .05) / (darker + .05);
|
|
|
|
}
|
|
|
|
while (ratio > 5 || ratio < 4);
|
|
|
|
|
|
|
|
return foreground;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-06-06 12:02:26 -05:00
|
|
|
status_t
|
|
|
|
ReadAttributeData(BNode* node, const char* name, char** buffer, int32 *size) {
|
|
|
|
attr_info info;
|
|
|
|
status_t ret = node->GetAttrInfo(name, &info);
|
|
|
|
|
|
|
|
if (ret == B_OK) {
|
|
|
|
*buffer = (char *)calloc(info.size, sizeof(char));
|
|
|
|
ret = node->ReadAttr(name, info.type, 0, *buffer, info.size);
|
|
|
|
|
|
|
|
if (ret > B_OK) {
|
|
|
|
*size = ret;
|
|
|
|
ret = B_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
free(*buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
WriteAttributeMessage(BNode* node, const char* name, BMessage* data)
|
|
|
|
{
|
|
|
|
BMallocIO malloc;
|
|
|
|
status_t ret=data->Flatten(&malloc);
|
|
|
|
|
|
|
|
if( ret == B_OK) {
|
|
|
|
ret = node->WriteAttr(name,B_ANY_TYPE,0,malloc.Buffer(),malloc.BufferLength());
|
|
|
|
|
|
|
|
if(ret > B_OK)
|
|
|
|
ret=B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
status_t
|
|
|
|
ReadAttributeMessage(BNode* node, const char* name, BMessage* data)
|
|
|
|
{
|
|
|
|
char *buffer = NULL;
|
|
|
|
int32 size = 0;
|
|
|
|
|
|
|
|
status_t ret = ReadAttributeData(node,name,&buffer,&size);
|
|
|
|
|
|
|
|
if(size>0 && buffer!=NULL) {
|
|
|
|
BMemoryIO mem(buffer,size);
|
|
|
|
ret = data->Unflatten(&mem);
|
|
|
|
free(buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-07 04:47:10 -05:00
|
|
|
extern "C" {
|
|
|
|
|
|
|
|
status_t
|
|
|
|
our_image(image_info& image)
|
|
|
|
{
|
|
|
|
team_id team = B_CURRENT_TEAM;
|
|
|
|
|
|
|
|
int32 cookie = 0;
|
|
|
|
while (get_next_image_info(team, &cookie, &image) == B_OK) {
|
2010-05-20 16:31:55 -05:00
|
|
|
if ((char*)our_image >= (char*)image.text
|
|
|
|
&& (char*)our_image <= (char*)image.text + image.text_size)
|
2010-05-07 04:47:10 -05:00
|
|
|
return B_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return B_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|