Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F134035
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
68 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/util/configuration.cpp b/util/configuration.cpp
index 8ca2d9b7..a43e74a6 100644
--- a/util/configuration.cpp
+++ b/util/configuration.cpp
@@ -1,1006 +1,1007 @@
#include "configuration.h"
#include "input/keyboard.h"
#include "exceptions/load_exception.h"
#include "tokenreader.h"
#include "token.h"
#include "file-system.h"
#include "input/input.h"
#include "debug.h"
#include <sstream>
#include <fstream>
#include <stdlib.h>
#include <string>
#include <map>
#ifdef USE_SDL
#if SDL_VERSION_ATLEAST(1, 3, 0)
static const std::string INPUT_TYPE = "SDL1.3";
#else
static const std::string INPUT_TYPE = "SDL";
#endif
#endif
#ifdef USE_ALLEGRO
static const std::string INPUT_TYPE = "Allegro";
#endif
#ifdef USE_ALLEGRO5
static const std::string INPUT_TYPE = "Allegro5";
#endif
bool Configuration::save = true;
Util::ReferenceCount<Token> Configuration::data;
/* text that appears in the config file */
#define define_config(n,str) static const char * config_##n = str
define_config(attack1, "attack1");
define_config(attack2, "attack2");
define_config(attack3, "attack3");
define_config(attack4, "attack4");
define_config(attack5, "attack5");
define_config(attack6, "attack6");
define_config(configuration, "configuration");
define_config(cooperative, "cooperative");
// define_config(current_game, "current-game");
define_config(down, "down");
define_config(free_for_all, "free-for-all");
define_config(fullscreen, "fullscreen");
define_config(game_speed, "game-speed");
define_config(invincible, "invincible");
define_config(jump, "jump");
define_config(quit, "quit");
define_config(keyboard_configuration, "keyboard-configuration");
define_config(input, "input");
define_config(joystick_configuration, "joystick-configuration");
define_config(left, "left");
define_config(lives, "lives");
define_config(menu_font, "menu-font");
define_config(menu_font_width, "menu-font-width");
define_config(menu_font_height, "menu-font-height");
define_config(npc_buddies, "npc-buddies");
define_config(number, "number");
define_config(play_mode, "play-mode");
define_config(right, "right");
define_config(screen_size, "screen-size");
define_config(sound, "sound");
define_config(music, "music");
define_config(up, "up");
define_config(quality_filter, "quality-filter");
define_config(fps, "frames-per-second");
define_config(language, "language");
define_config(mugen_motif, "mugen-motif");
/* version of the game: 3.3, 3.4, 4.24 */
define_config(version, "version");
#undef def_config
using namespace std;
static const int InvalidKey = 0;
static const Joystick::Key InvalidJoystick = Joystick::Invalid;
/* don't save the configuration while loading it */
class Disable{
public:
Disable(){
last = Configuration::getSave();
Configuration::disableSave();
}
~Disable(){
Configuration::setSave(last);
}
bool last;
};
/* FIXME: move this to some utils module */
static std::vector<std::string> split(std::string str, char splitter){
std::vector<std::string> strings;
size_t next = str.find(splitter);
while (next != std::string::npos){
strings.push_back(str.substr(0, next));
str = str.substr(next+1);
next = str.find(splitter);
}
if (str != ""){
strings.push_back(str);
}
return strings;
}
static std::string last(const vector<string> & what){
return what.at(what.size() - 1);
}
/* Create a token that contains the entire path.
* path = "foo/bar/baz"
* out = (foo (bar (baz)))
*/
static Token * createToken(const string & path){
vector<string> paths = split(path, '/');
Token * out = new Token();
Token * current = out;
for (vector<string>::iterator it = paths.begin(); it != paths.end(); it++){
current->addToken(new Token(*it, false));
if (paths.end() - it > 1){
Token * next = new Token();
current->addToken(next);
current = next;
}
}
return out;
}
/* Create a token with the given path and give it a value */
template <class Value>
static Token * createToken(const string & path, const Value & value){
Token * out = createToken(path);
*out << value;
return out;
}
template <class Value, class Value2>
static Token * createToken(const string & path, const Value & value, const Value2 & value2){
Token * out = createToken(path);
*out << value;
*out << value2;
return out;
}
/* remove a path if it exists */
static void removeToken(Token * data, const std::string & path){
Token * found = data->findToken(path);
/* See if the token already exists. If it does then remove it from its
* parent and add a new token to the parent with the updated value.
*/
if (found != NULL){
Token * parent = found->getParent();
parent->removeToken(found);
}
}
static void updateToken(Token * data, const std::string & path, Token * add){
if (data == NULL){
delete add;
}
Token * found = data->findToken(path);
/* See if the token already exists. If it does then remove it from its
* parent and add a new token to the parent with the updated value.
*/
if (found != NULL){
Token * parent = found->getParent();
parent->removeToken(found);
parent->addToken(add);
} else {
const vector<string> paths = split(path, '/');
Token * start = data;
- for (int index = 1; index < paths.size() - 1; index++){
+ for (unsigned int index = 1; index < paths.size() - 1; index++){
string where = paths[index];
Token * next = start->findToken(string("_/") + where);
if (next == NULL){
ostringstream out;
bool first = true;
for (int from = index; from < paths.size(); from++){
if (!first){
out << "/";
}
out << paths[from];
first = false;
}
/* If we run out of found paths then create a token with an empty
* value for the unfound paths we have so far and call updateToken
* again. This time the entire path will be there
* so the 'found = ...' logic will work.
*/
start->addToken(createToken(out.str(), string("")));
updateToken(data, path, add);
return;
} else {
start = next;
}
}
/* It probably shouldn't be possible to get here. If the entire
* path was there then the findToken() logic above should have worked.
*/
start->addToken(add);
}
}
template <class Value>
static void updateToken(Token * data, const string & path, const Value & value){
if (data == NULL){
return;
}
updateToken(data, path, createToken(last(split(path, '/')), value));
}
void Configuration::setProperty(const string & name, const string & value){
updateToken(getRawData(), string(config_configuration) + "/" + name, value);
saveConfiguration();
}
static Token * getPropertyX(Token * data, const std::string & path){
return data->findToken(string(config_configuration) + "/" + path);
}
template <class Out>
static Out getPropertyX(Token * data, const std::string & path, const Out & defaultValue){
if (data == NULL){
return defaultValue;
}
Out out;
if (data->match(string(config_configuration) + "/" + path, out)){
return out;
}
updateToken(data, string(config_configuration) + "/" + path, defaultValue);
return defaultValue;
}
void Configuration::setDefaultKeys(int config){
/* Set the keys token to an empty value */
ostringstream path;
path << config_input << "/" << config << "/keys";
setProperty(path.str(), createToken("keys"));
/* Call the get methods to reset the defaults */
int ignore;
ignore = getRight(config);
ignore = getLeft(config);
ignore = getUp(config);
ignore = getDown(config);
ignore = getAttack1(config);
ignore = getAttack2(config);
ignore = getAttack3(config);
ignore = getAttack4(config);
ignore = getAttack5(config);
ignore = getAttack6(config);
ignore = getJump(config);
}
/* hopefully this is only used right before setting all the values
* since the key mappings are bogus in here'
*/
Configuration::Configuration(){
}
Configuration::Configuration(const Configuration & config){
menuFont = config.menuFont;
}
Configuration & Configuration::operator=(const Configuration & config){
Disable disable;
setMenuFont(config.getMenuFont());
return *this;
}
Configuration::~Configuration(){
}
Util::ReferenceCount<Menu::FontInfo> Configuration::getMenuFont(){
return menuFont;
}
bool Configuration::hasMenuFont(){
return menuFont != NULL;
}
void Configuration::setMenuFont(const Util::ReferenceCount<Menu::FontInfo> & info){
menuFont = info;
saveConfiguration();
}
void Configuration::setMenuFontWidth(int x){
setProperty(config_menu_font_width, x);
saveConfiguration();
}
int Configuration::getMenuFontWidth(){
return getProperty(config_menu_font_width, 24);
}
void Configuration::setMenuFontHeight(int x){
setProperty(config_menu_font_height, x);
saveConfiguration();
}
int Configuration::getMenuFontHeight(){
return getProperty(config_menu_font_height, 24);
}
static string joystickKeyName(Joystick::Key key){
switch (key){
case Joystick::Up: return "up";
case Joystick::Down: return "down";
case Joystick::Left: return "left";
case Joystick::Right: return "right";
case Joystick::Button1: return "button1";
case Joystick::Button2: return "button2";
case Joystick::Button3: return "button3";
case Joystick::Button4: return "button4";
case Joystick::Button5: return "button5";
case Joystick::Button6: return "button6";
case Joystick::Start: return "start";
case Joystick::Quit: return "quit";
case Joystick::Invalid: return "invalid";
}
return "?";
}
static string removeQuotes(string input){
size_t find = input.find('"');
while (find != string::npos){
input.erase(find, 1);
}
return input;
}
static string joystickPath(Joystick::Key key, int config, const std::string & name){
ostringstream base;
base << config_configuration << "/" << config_input << "/" << INPUT_TYPE << "/";
base << "joystick" << "/" << config << "/";
base << removeQuotes(name) << "/" << joystickKeyName(key);
return base.str();
}
void Configuration::setCustomButton(Joystick::Key key, int config, const std::string & name, int button){
if (key != Joystick::Invalid){
std::string base = joystickPath(key, config, name);
removeToken(getRawData(), base);
updateToken(getRawData(), base + "/button", button);
saveConfiguration();
}
}
bool Configuration::getCustomButton(Joystick::Key key, int config, const std::string & name, int & button){
return getRawData()->match(joystickPath(key, config, name) + "/button", button);
}
bool Configuration::getCustomAxis(Joystick::Key key, int config, const std::string & name, int & stick, int & axis, double & low, double & high){
std::string base = joystickPath(key, config, name);
return getRawData()->match(base + "/stick", stick) &&
getRawData()->match(base + "/axis", axis) &&
getRawData()->match(base + "/low", low) &&
getRawData()->match(base + "/high", high);
}
void Configuration::setCustomAxis(Joystick::Key key, int config, const string & name, int stick, int axis, double low, double high){
if (key != Joystick::Invalid){
std::string base = joystickPath(key, config, name);
removeToken(getRawData(), base);
updateToken(getRawData(), base + "/stick", stick);
updateToken(getRawData(), base + "/axis", axis);
updateToken(getRawData(), base + "/low", low);
updateToken(getRawData(), base + "/high", high);
saveConfiguration();
}
}
void Configuration::setKey(int config, const string & name, int value){
if (value != InvalidKey){
ostringstream path;
path << config_configuration << "/" << config_input << "/" << config << "/keys/" << name;
updateToken(getRawData(), path.str(), value);
saveConfiguration();
}
}
void Configuration::setRight(int config, int i){
setKey(config, "right", i);
}
void Configuration::setLeft(int config, int i){
setKey(config, "left", i);
}
void Configuration::setUp(int config, int i){
setKey(config, "up", i);
}
void Configuration::setDown(int config, int i){
setKey(config, "down", i);
}
void Configuration::setAttack1(int config, int i){
setKey(config, "attack1", i);
}
void Configuration::setAttack2(int config, int i){
setKey(config, "attack2", i);
}
void Configuration::setAttack3(int config, int i){
setKey(config, "attack3", i);
}
void Configuration::setAttack4(int config, int i){
setKey(config, "attack4", i);
}
void Configuration::setAttack5(int config, int i){
setKey(config, "attack5", i);
}
void Configuration::setAttack6(int config, int i){
setKey(config, "attack6", i);
}
void Configuration::setJump(int config, int i){
setKey(config, "jump", i);
}
int Configuration::getKey(int config, const string & name, int defaultValue){
ostringstream path;
path << config_input << "/" << INPUT_TYPE << "/" << config << "/keys/" << name;
return getProperty(path.str(), defaultValue);
}
/* this nonsense is just to convert a regular integer into an enum */
/*
static Configuration::JoystickInput intToJoystick(int a){
switch (a){
case Joystick::Up : return Joystick::Up;
case Joystick::Down : return Joystick::Down;
case Joystick::Left : return Joystick::Left;
case Joystick::Right : return Joystick::Right;
case Joystick::Button1 : return Joystick::Button1;
case Joystick::Button2 : return Joystick::Button2;
case Joystick::Button3 : return Joystick::Button3;
case Joystick::Button4 : return Joystick::Button4;
case Joystick::Button5 : return Joystick::Button5;
case Joystick::Button6 : return Joystick::Button6;
case Joystick::Start : return Joystick::Start;
case Joystick::Quit : return Joystick::Quit;
}
return Joystick::Invalid;
}
*/
/*
Configuration::JoystickInput Configuration::getJoystickKey(int config, const string & name, JoystickInput defaultValue){
ostringstream path;
path << config_input << "/" << config << "/joystick/" << name;
return intToJoystick(getProperty(path.str(), defaultValue));
}
*/
int Configuration::getRight(int config){
int normal = 0;
switch (config){
case 0: normal = Keyboard::Key_RIGHT; break;
case 1: normal = Keyboard::Key_L; break;
}
return getKey(config, "right", normal);
}
int Configuration::getLeft(int config){
int normal = 0;
switch (config){
case 0: normal = Keyboard::Key_LEFT; break;
case 1: normal = Keyboard::Key_J; break;
}
return getKey(config, "left", normal);
}
int Configuration::getUp(int config){
int normal = 0;
switch (config){
case 0: normal = Keyboard::Key_UP; break;
case 1: normal = Keyboard::Key_I; break;
}
return getKey(config, "up", normal);
}
int Configuration::getDown(int config){
int normal = 0;
switch (config){
case 0: normal = Keyboard::Key_DOWN; break;
case 1: normal = Keyboard::Key_COMMA; break;
}
return getKey(config, "down", normal);
}
int Configuration::getAttack1(int config){
int normal = 0;
switch (config){
case 0: normal = Keyboard::Key_A; break;
case 1: normal = Keyboard::Key_R; break;
}
return getKey(config, "attack1", normal);
}
int Configuration::getAttack2(int config){
int normal = 0;
switch (config){
case 0: normal = Keyboard::Key_S; break;
case 1: normal = Keyboard::Key_T; break;
}
return getKey(config, "attack2", normal);
}
int Configuration::getAttack3(int config){
int normal = 0;
switch (config){
case 0: normal = Keyboard::Key_D; break;
case 1: normal = Keyboard::Key_Y; break;
}
return getKey(config, "attack3", normal);
}
int Configuration::getAttack4(int config){
int normal = 0;
switch (config){
case 0: normal = Keyboard::Key_Z; break;
case 1: normal = Keyboard::Key_F; break;
}
return getKey(config, "attack4", normal);
}
int Configuration::getAttack5(int config){
int normal = 0;
switch (config){
case 0: normal = Keyboard::Key_X; break;
case 1: normal = Keyboard::Key_G; break;
}
return getKey(config, "attack5", normal);
}
int Configuration::getAttack6(int config){
int normal = 0;
switch (config){
case 0: normal = Keyboard::Key_C; break;
case 1: normal = Keyboard::Key_H; break;
}
return getKey(config, "attack6", normal);
}
int Configuration::getJump(int config){
int normal = 0;
switch (config){
case 0: normal = Keyboard::Key_SPACE; break;
case 1: normal = Keyboard::Key_B; break;
}
return getKey(config, "jump", normal);
}
/*
void Configuration::setJoystickKey(int config, const std::string & name, const Configuration::JoystickInput & what){
if (what != Joystick::Invalid){
ostringstream path;
path << config_configuration << "/" << config_input << "/" << config << "/joystick/" << name;
updateToken(data.raw(), path.str(), what);
saveConfiguration();
}
}
void Configuration::setJoystickRight(int config, Configuration::JoystickInput i){
setJoystickKey(config, "right", i);
}
void Configuration::setJoystickLeft(int config, Configuration::JoystickInput i){
setJoystickKey(config, "left", i);
}
void Configuration::setJoystickUp(int config, Configuration::JoystickInput i){
setJoystickKey(config, "up", i);
}
void Configuration::setJoystickDown(int config, Configuration::JoystickInput i){
setJoystickKey(config, "down", i);
}
void Configuration::setJoystickAttack1(int config, Configuration::JoystickInput i){
setJoystickKey(config, "attack1", i);
}
void Configuration::setJoystickAttack2(int config, Configuration::JoystickInput i){
setJoystickKey(config, "attack2", i);
}
void Configuration::setJoystickAttack3(int config, Configuration::JoystickInput i){
setJoystickKey(config, "attack3", i);
}
void Configuration::setJoystickAttack4(int config, Configuration::JoystickInput i){
setJoystickKey(config, "attack4", i);
}
void Configuration::setJoystickAttack5(int config, Configuration::JoystickInput i){
setJoystickKey(config, "attack5", i);
}
void Configuration::setJoystickAttack6(int config, Configuration::JoystickInput i){
setJoystickKey(config, "attack6", i);
}
void Configuration::setJoystickJump(int config, Configuration::JoystickInput i){
setJoystickKey(config, "jump", i);
}
void Configuration::setJoystickQuit(int config, Configuration::JoystickInput i){
setJoystickKey(config, "quit", i);
}
void Configuration::setJoystickStart(int config, Configuration::JoystickInput i){
setJoystickKey(config, "start", i);
}
Configuration::JoystickInput Configuration::getJoystickRight(int config){
return getJoystickKey(config, "right", Joystick::Right);
}
Configuration::JoystickInput Configuration::getJoystickLeft(int config){
return getJoystickKey(config, "left", Joystick::Left);
}
Configuration::JoystickInput Configuration::getJoystickUp(int config){
return getJoystickKey(config, "up", Joystick::Up);
}
Configuration::JoystickInput Configuration::getJoystickDown(int config){
return getJoystickKey(config, "down", Joystick::Down);
}
Configuration::JoystickInput Configuration::getJoystickAttack1(int config){
return getJoystickKey(config, "attack1", Joystick::Button1);
}
Configuration::JoystickInput Configuration::getJoystickAttack2(int config){
return getJoystickKey(config, "attack2", Joystick::Button2);
}
Configuration::JoystickInput Configuration::getJoystickAttack3(int config){
return getJoystickKey(config, "attack3", Joystick::Button3);
}
Configuration::JoystickInput Configuration::getJoystickAttack4(int config){
return getJoystickKey(config, "attack4", Joystick::Button4);
}
Configuration::JoystickInput Configuration::getJoystickAttack5(int config){
return getJoystickKey(config, "attack5", Joystick::Button5);
}
Configuration::JoystickInput Configuration::getJoystickAttack6(int config){
return getJoystickKey(config, "attack6", Joystick::Button6);
}
Configuration::JoystickInput Configuration::getJoystickJump(int config){
return getJoystickKey(config, "jump", Joystick::Button4);
}
Configuration::JoystickInput Configuration::getJoystickQuit(int config){
return getJoystickKey(config, "quit", Joystick::Quit);
}
Configuration::JoystickInput Configuration::getJoystickStart(int config){
return getJoystickKey(config, "start", Joystick::Start);
}
*/
/*
string Configuration::getCurrentGame(){
return getProperty(config_current_game, string(""));
}
/ * assumes the directory is readable and has a dir/dir.txt in it * /
void Configuration::setCurrentGame(const std::string & str){
setProperty(config_current_game, str);
saveConfiguration();
}
*/
void Configuration::disableSave(){
save = false;
}
void Configuration::setSave(bool what){
save = what;
}
bool Configuration::getSave(){
return save;
}
static Token * removeDuplicates(Token * token){
/* TODO */
return token;
}
Token * Configuration::getRawData(){
if (data == NULL){
- data = new Token();
+ loadConfigurations();
+ // data = new Token();
}
return data.raw();
}
void Configuration::loadConfigurations(){
data = new Token();
*data << config_configuration;
try{
Filesystem::AbsolutePath file = Storage::instance().configFile();
TokenReader tr;
Token * head = tr.readTokenFromFile(file.path());
if (*head != config_configuration){
throw LoadException(__FILE__, __LINE__, string("Config file ") + Storage::instance().configFile().path() + " does not use the configuration format" );
}
/* Store the entire configuration tree */
data = removeDuplicates(head->copy());
} catch ( const LoadException & le ){
Global::debug( 0 ) << "Notice: Could not load configuration file " << Storage::instance().configFile().path() << ": " << le.getTrace() << endl;
} catch ( const TokenException & t ){
Global::debug( 0 ) << "Notice: could not open configuration file '" << Storage::instance().configFile().path() << "': " << t.getTrace() << endl;
}
}
void Configuration::saveConfiguration(){
if (!save){
return;
}
if (data != NULL){
ofstream out(Storage::instance().configFile().path().c_str(), ios::trunc | ios::out);
if (! out.bad()){
data->toString(out, string(""));
out << endl;
out.close();
}
}
}
Util::ReferenceCount<Menu::FontInfo> Configuration::menuFont;
bool Configuration::joystickEnabled = true;
int Configuration::getProperty(const std::string & path, int defaultValue){
return getPropertyX(getRawData(), path, defaultValue);
}
void Configuration::setProperty(const std::string & path, int value){
updateToken(getRawData(), string(config_configuration) + "/" + path, value);
saveConfiguration();
}
void Configuration::setProperty(const std::string & path, Token * value){
updateToken(getRawData(), string(config_configuration) + "/" + path, value);
saveConfiguration();
}
-
+
Token * Configuration::getProperty(const std::string & path){
return getPropertyX(getRawData(),path);
}
double Configuration::getProperty(const std::string & path, double defaultValue){
return getPropertyX(getRawData(), path, defaultValue);
}
void Configuration::setProperty(const std::string & path, double value){
updateToken(getRawData(), string(config_configuration) + "/" + path, value);
saveConfiguration();
}
bool Configuration::getProperty(const std::string & path, bool defaultValue){
return getPropertyX(getRawData(), path, defaultValue);
}
void Configuration::setProperty(const std::string & path, bool value){
updateToken(getRawData(), string(config_configuration) + "/" + path, value);
saveConfiguration();
}
std::string Configuration::getProperty(const std::string & path, const std::string & defaultValue){
return getPropertyX(getRawData(), path, defaultValue);
}
double Configuration::getGameSpeed(){
return getProperty(config_game_speed, 1.0);
}
void Configuration::setGameSpeed(double s){
setProperty(config_game_speed, s);
saveConfiguration();
}
bool Configuration::getInvincible(){
return getProperty(config_invincible, false);
}
void Configuration::setInvincible(bool i){
setProperty(config_invincible, i);
saveConfiguration();
}
bool Configuration::getFullscreen(){
/* Defaults for all configuration options */
#if defined(PS3) || defined(ANDROID) || defined(IPHONE)
return getProperty(config_fullscreen, true);
#else
return getProperty(config_fullscreen, false);
#endif
}
void Configuration::setFullscreen(bool f){
setProperty(config_fullscreen, f);
saveConfiguration();
}
int Configuration::getLives(){
return getProperty(config_lives, 4);
}
void Configuration::setLives(int l){
setProperty(config_lives, l);
saveConfiguration();
}
int Configuration::getNpcBuddies(){
return getProperty(config_npc_buddies, 1);
}
void Configuration::setNpcBuddies(int i){
setProperty(config_npc_buddies,i);
saveConfiguration();
}
Configuration::PlayMode Configuration::getPlayMode(){
string mode = getProperty("play-mode", string(config_cooperative));
if (mode == config_cooperative){
return Cooperative;
}
if (mode == config_free_for_all){
return FreeForAll;
}
return Cooperative;
}
void Configuration::setPlayMode(Configuration::PlayMode mode){
if (mode == Configuration::Cooperative){
setProperty("play-mode", string(config_cooperative));
} else if (mode == Configuration::FreeForAll){
setProperty("play-mode", string(config_free_for_all));
}
}
std::string Configuration::getLanguage(){
return getProperty("language", string());
}
void Configuration::setLanguage(const std::string & str){
setProperty("language", str);
saveConfiguration();
}
/* In case this is ever useful again */
/*
#ifdef MINPSPW
// default resolution for the psp is 480x272
int Configuration::screen_width = 480;
int Configuration::screen_height = 272;
#else
int Configuration::screen_width = 640;
int Configuration::screen_height = 480;
#endif
*/
#ifdef GCW0
static int DefaultWidth = 320;
static int DefaultHeight = 240;
#else
static int DefaultWidth = 640;
static int DefaultHeight = 480;
#endif
/* TODO: All the screen width/height stuff shares a lot of code. Refactor */
void Configuration::setScreenWidth(int i){
int width = DefaultWidth;
int height = DefaultHeight;
Token * screen = getPropertyX(getRawData(), config_screen_size);
if (screen != NULL){
try{
screen->view() >> width >> height;
} catch (const TokenException & fail){
}
}
width = i;
setProperty(config_screen_size, createToken(config_screen_size, width, height));
saveConfiguration();
}
int Configuration::getScreenWidth(){
int width = DefaultWidth;
int height = DefaultHeight;
Token * screen = getPropertyX(getRawData(), config_screen_size);
if (screen != NULL){
try{
screen->view() >> width >> height;
} catch (const TokenException & fail){
}
} else {
setProperty(config_screen_size, createToken(config_screen_size, width, height));
}
return width;
}
void Configuration::setScreenHeight(int i){
int width = DefaultWidth;
int height = DefaultHeight;
Token * screen = getPropertyX(getRawData(), config_screen_size);
if (screen != NULL){
try{
screen->view() >> width >> height;
} catch (const TokenException & fail){
}
}
height = i;
setProperty(config_screen_size, createToken(config_screen_size, width, height));
saveConfiguration();
}
int Configuration::getScreenHeight(){
int width = DefaultWidth;
int height = DefaultHeight;
Token * screen = getPropertyX(getRawData(), config_screen_size);
if (screen != NULL){
try{
screen->view() >> width >> height;
} catch (const TokenException & fail){
}
} else {
setProperty(config_screen_size, createToken(config_screen_size, width, height));
}
return height;
}
int Configuration::getSoundVolume(){
return getProperty(config_sound, 70);
}
void Configuration::setSoundVolume(int volume){
setProperty(config_sound, volume);
saveConfiguration();
}
int Configuration::getMusicVolume(){
return getProperty(config_music, 70);
}
void Configuration::setMusicVolume(int volume){
setProperty(config_music, volume);
saveConfiguration();
}
bool Configuration::isJoystickEnabled(){
return joystickEnabled;
}
void Configuration::setJoystickEnabled(bool enabled){
joystickEnabled = enabled;
saveConfiguration();
}
std::string Configuration::getQualityFilter(){
return getProperty(config_quality_filter, string("none"));
}
void Configuration::setQualityFilter(const std::string & filter){
setProperty(config_quality_filter, filter);
saveConfiguration();
}
int Configuration::getFps(){
return getProperty(config_fps, 50);
}
void Configuration::setFps(int what){
setProperty(config_fps, what);
saveConfiguration();
}
diff --git a/util/network/irc.cpp b/util/network/irc.cpp
index 14fbd4af..9e020355 100644
--- a/util/network/irc.cpp
+++ b/util/network/irc.cpp
@@ -1,1054 +1,1054 @@
#include "irc.h"
#include "util/funcs.h"
#include "util/font.h"
#include "util/regex.h"
#include "util/system.h"
#include "util/graphics/bitmap.h"
#include "util/configuration.h"
#include "util/gui/context-box.h"
#include "util/timedifference.h"
#include <stdexcept>
#include <queue>
namespace Network{
namespace IRC{
static Command::Type convertCommand(const std::string & cmd){
Command::Type command = Command::Unknown;
if (cmd == "PASS"){
command = Command::Pass;
} else if (cmd == "NICK"){
command = Command::Nick;
} else if (cmd == "USER"){
command = Command::User;
} else if (cmd == "SERVER"){
command = Command::Server;
} else if (cmd == "OPER"){
command = Command::Oper;
} else if (cmd == "QUIT"){
command = Command::Quit;
} else if (cmd == "SQUIT"){
command = Command::Squit;
} else if (cmd == "JOIN"){
command = Command::Join;
} else if (cmd == "PART"){
command = Command::Part;
} else if (cmd == "MODE"){
command = Command::Mode;
} else if (cmd == "TOPIC"){
command = Command::Topic;
} else if (cmd == "NAMES"){
command = Command::Names;
} else if (cmd == "LIST"){
command = Command::List;
} else if (cmd == "INVITE"){
command = Command::Invite;
} else if (cmd == "KICK"){
command = Command::Kick;
} else if (cmd == "VERSION"){
command = Command::Version;
} else if (cmd == "STATS"){
command = Command::Stats;
} else if (cmd == "LINKS"){
command = Command::Links;
} else if (cmd == "TIME"){
command = Command::Time;
} else if (cmd == "CONNECT"){
command = Command::Connect;
} else if (cmd == "TRACE"){
command = Command::Trace;
} else if (cmd == "ADMIN"){
command = Command::Admin;
} else if (cmd == "INFO"){
command = Command::Info;
} else if (cmd == "PRIVMSG"){
command = Command::PrivateMessage;
} else if (cmd == "NOTICE"){
command = Command::Notice;
} else if (cmd == "WHO"){
command = Command::Who;
} else if (cmd == "WHOIS"){
command = Command::Whois;
} else if (cmd == "WHOWAS"){
command = Command::Whowas;
} else if (cmd == "KILL"){
command = Command::Kill;
} else if (cmd == "PING"){
command = Command::Ping;
} else if (cmd == "PONG"){
command = Command::Pong;
} else if (cmd == "ERROR"){
command = Command::Error;
} else if (cmd == "433"){
command = Command::ErrorNickInUse;
} else if (cmd == "401"){
command = Command::ErrorNoSuchNick;
} else if (cmd == "403"){
command = Command::ErrorNoSuchChannel;
} else if (cmd == "461"){
command = Command::ErrorNeedMoreParams;
} else if (cmd == "473"){
command = Command::ErrorInviteOnlyChannel;
} else if (cmd == "474"){
command = Command::ErrorBannedFromChannel;
} else if (cmd == "475"){
command = Command::ErrorBadChannelKey;
} else if (cmd == "471"){
command = Command::ErrorChannelIsFull;
} else if (cmd == "331"){
command = Command::ReplyNoTopic;
} else if (cmd == "332"){
command = Command::ReplyTopic;
} else if (cmd == "333"){
command = Command::ReplyTopicAuthor;
} else if (cmd == "353"){
command = Command::ReplyNames;
} else if (cmd == "366"){
command = Command::ReplyNamesEndOf;
} else if (cmd == "372"){
command = Command::ReplyMOTD;
} else if (cmd == "375"){
command = Command::ReplyMOTDStart;
} else if (cmd == "376"){
command = Command::ReplyMOTDEndOf;
}
return command;
}
static std::string convertCommand(const Command::Type & cmd){
switch (cmd){
case Command::Pass: return "PASS";
case Command::Nick: return "NICK";
case Command::User: return "USER";
case Command::Server: return "SERVER";
case Command::Oper: return "OPER";
case Command::Quit: return "QUIT";
case Command::Squit: return "SQUIT";
case Command::Join: return "JOIN";
case Command::Part: return "PART";
case Command::Mode: return "MODE";
case Command::Topic: return "TOPIC";
case Command::Names: return "NAMES";
case Command::List: return "LIST";
case Command::Invite: return "INVITE";
case Command::Kick: return "KICK";
case Command::Version: return "VERSION";
case Command::Stats: return "STATS";
case Command::Links: return "LINKS";
case Command::Time: return "TIME";
case Command::Connect: return "CONNECT";
case Command::Trace: return "TRACE";
case Command::Admin: return "ADMIN";
case Command::Info: return "INFO";
case Command::PrivateMessage: return "PRIVMSG";
case Command::Notice: return "NOTICE";
case Command::Who: return "WHO";
case Command::Whois: return "WHOIS";
case Command::Whowas: return "WHOAS";
case Command::Kill: return "KILL";
case Command::Ping: return "PING";
case Command::Pong: return "PONG";
case Command::Error: return "ERROR";
case Command::Unknown:
default:
break;
}
return "";
}
static std::vector<std::string> split(std::string str, char splitter){
std::vector<std::string> strings;
size_t next = str.find(splitter);
while (next != std::string::npos){
strings.push_back(str.substr(0, next));
str = str.substr(next+1);
next = str.find(splitter);
}
if (str != ""){
strings.push_back(str);
}
return strings;
}
Command::Command(const std::string & message){
std::vector< std::string > messageSplit = split(message, ' ');
std::vector< std::string >::iterator current = messageSplit.begin();
if (Util::matchRegex(*current, Util::Regex("^:.*"))){
// Found owner (":") indicates the user, otherwise it's going to be the command
// Grab just the username, ignore everything else
try{
owner = split(*current, '!').at(0).substr(1);
} catch (const std::out_of_range & ex){
}
current++;
}
// Next is the actual command
type = convertCommand(*current);
if (type == Unknown){
Global::debug(0) << "Got unhandled response: " << message << std::endl;
}
current++;
// Parameters
bool foundCtcp = false;
bool concactenate = false;
std::string concactenated;
for (std::vector< std::string >::iterator i = current; i != messageSplit.end(); ++i){
const std::string & parameter = *i;
// If there is a colon in the parameter the rest of split string is the whole parameter rejoin
if (Util::matchRegex(parameter, Util::Regex("^:\001.*")) && !foundCtcp){
foundCtcp = true;
// Drop the ':\001'
ctcp.push_back(parameter.substr(2));
continue;
} else if (Util::matchRegex(parameter, Util::Regex(".*\001")) && foundCtcp){
foundCtcp = false;
// Drop the '\001'
ctcp.push_back(parameter.substr(0, parameter.size()-1));
continue;
} else if (Util::matchRegex(parameter, Util::Regex("^:.*")) && !concactenate){
concactenate = true;
// Drop the ':'
concactenated += parameter.substr(1) + " ";
continue;
} else if (Util::matchRegex(parameter, Util::Regex("=")) ||
Util::matchRegex(parameter, Util::Regex("@"))){
// Ignore
continue;
}
if (concactenate){
concactenated += parameter + " ";
} else {
if (!foundCtcp){
parameters.push_back(parameter);
} else {
ctcp.push_back(parameter);
}
}
}
if (concactenate){
parameters.push_back(concactenated);
}
}
Command::Command(const std::string & owner, const Type & type):
owner(owner),
type(type){
}
Command::Command(const Command & copy):
owner(copy.owner),
type(copy.type),
parameters(copy.parameters),
ctcp(copy.ctcp){
}
Command::~Command(){
}
const Command & Command::operator=(const Command & copy){
owner = copy.owner;
type = copy.type;
parameters = copy.parameters;
ctcp = copy.ctcp;
return *this;
}
std::string Command::getSendable() const {
std::string sendable;
// Name
if (!owner.empty()){
sendable += ":" + owner + " ";
}
// Command
sendable += convertCommand(type) + " ";
// Params
/*for (std::vector<std::string>::const_iterator i = parameters.begin(); i != parameters.end(); ++i){
sendable+= *i + " ";
}*/
for (unsigned int i = 0; i < parameters.size(); ++i){
sendable += parameters[i] + (i < parameters.size()-1 ? " " : "");
}
// End
sendable += "\r\n";
return sendable;
}
Channel::Channel(){
}
Channel::Channel(const std::string & name):
name(name){
}
Channel::Channel(const Channel & copy):
name(copy.name),
topic(copy.topic),
topicAuthor(copy.topicAuthor),
topicDate(copy.topicDate),
users(copy.users){
}
Channel::~Channel(){
}
const Channel & Channel::operator=(const Channel & copy){
name = copy.name;
topic = copy.topic;
topicAuthor = copy.topicAuthor;
topicDate = copy.topicDate;
users = copy.users;
return *this;
}
void Channel::addUser(const std::string & user){
// Can't add same user twice
for (std::vector<std::string>::iterator i = users.begin(); i != users.end(); ++i){
const std::string & name = *i;
if (name == user){
return;
}
}
users.push_back(user);
}
void Channel::removeUser(const std::string & user){
for (std::vector<std::string>::iterator i = users.begin(); i != users.end(); ++i){
const std::string & name = *i;
if (name == user){
users.erase(i);
break;
}
}
}
void Channel::addUsers(const std::vector<std::string> & list){
for (std::vector<std::string>::const_iterator i = list.begin(); i != list.end(); ++i){
const std::string & name = *i;
addUser(name);
}
}
Client::Client(const std::string & hostname, int port):
previousUsername("AUTH"),
username("AUTH"),
previousActiveChannel(0),
currentChannel(0),
hostname(hostname),
port(port),
end(false),
disableMessages(true){
}
Client::~Client(){
}
void Client::connect(){
if (username.empty()){
throw NetworkException("Set username first.");
}
Global::debug(0) << "Connecting to " << hostname << " on port " << port << std::endl;
socket = Network::connectReliable(hostname, port);
start();
setName("paintown-test");
Command user("AUTH", Command::User);
user.setParameters(username, "*", "0", ":auth");
sendCommand(user);
// ^^^^^^^^ Should get a response from this crap!
Global::debug(0) << "Connected" << std::endl;
}
bool Client::hasCommands() const{
::Util::Thread::ScopedLock scope(lock);
return !commands.empty();
}
Command Client::nextCommand() const {
::Util::Thread::ScopedLock scope(lock);
Command command = commands.front();
commands.pop();
return command;
}
void Client::sendCommand(const Command & command){
const std::string & sendable = command.getSendable();
Network::sendBytes(socket, (uint8_t *) sendable.c_str(), sendable.size());
}
void Client::sendCommand(const Command::Type & type){
Command command(username, type);
sendCommand(command);
}
void Client::sendCommand(const Command::Type & type, const std::string & param1){
Command command(username, type);
command.setParameters(param1);
sendCommand(command);
}
void Client::sendCommand(const Command::Type & type, const std::string & param1, const std::string & param2){
Command command(username, type);
command.setParameters(param1, param2);
sendCommand(command);
}
void Client::sendCommand(const Command::Type & type, const std::string & param1, const std::string & param2, const std::string & param3){
Command command(username, type);
command.setParameters(param1, param2, param3);
sendCommand(command);
}
void Client::sendCommand(const Command::Type & type, const std::string & param1, const std::string & param2, const std::string & param3, const std::string & param4){
Command command(username, type);
command.setParameters(param1, param2, param3, param4);
sendCommand(command);
}
void Client::setName(const std::string & name){
previousUsername = username;
// Update channel list
//channel.removeUser(username);
//channel.addUser(name);
for (std::vector< ChannelPointer >::iterator i = activeChannels.begin(); i != activeChannels.end(); ++i){
ChannelPointer activeChannel = *i;
activeChannel->removeUser(username);
activeChannel->addUser(name);
}
username = name;
sendCommand(Command::Nick, name);
}
void Client::joinChannel(const std::string & chan){
for (std::vector< ChannelPointer >::iterator i = activeChannels.begin(); i != activeChannels.end(); ++i){
ChannelPointer activeChannel = *i;
if (activeChannel->getName() == chan){
// Already belonging to this channel
return;
}
}
previousActiveChannel = currentChannel;
ChannelPointer newChannel = ChannelPointer(new Channel(chan));
/*if (!currentChannel.getName().empty()){
sendCommand(Command::Part, currentChannel.getName());
}*/
activeChannels.push_back(newChannel);
currentChannel = activeChannels.size()-1;
sendCommand(Command::Join, getChannel()->getName());
}
std::string Client::channelListAsString(){
std::string list;
for (std::vector<ChannelPointer>::iterator i = activeChannels.begin(); i != activeChannels.end(); ++i){
ChannelPointer activeChannel = *i;
list += activeChannel->getName() + ", ";
}
return list.substr(0, list.size()-2);
}
unsigned int Client::getChannelIndex(const std::string & channel){
for (unsigned int i = 0; i < activeChannels.size(); ++i){
if (activeChannels[i]->getName() == channel){
return i;
}
}
return 0;
}
bool Client::isCurrentChannel(const std::string & channel){
return (activeChannels[currentChannel]->getName() == channel);
}
void Client::setChannel(unsigned int channel){
if (channel >= activeChannels.size()){
return;
}
currentChannel = channel;
}
void Client::nextChannel(){
currentChannel = (currentChannel + 1) % activeChannels.size();
}
void Client::previousChannel(){
if (currentChannel == 0){
currentChannel = activeChannels.size()-1;
} else {
currentChannel--;
}
}
void Client::removeChannel(const std::string & name){
for (std::vector< ChannelPointer >::iterator i = activeChannels.begin(); i != activeChannels.end(); ++i){
ChannelPointer activeChannel = *i;
if (activeChannel->getName() == name){
activeChannels.erase(i);
return;
}
}
}
ChannelPointer Client::findChannel(const std::string & name){
for (std::vector< ChannelPointer >::iterator i = activeChannels.begin(); i != activeChannels.end(); ++i){
ChannelPointer activeChannel = *i;
if (activeChannel->getName() == name){
return activeChannel;
}
}
return ChannelPointer(NULL);
}
void Client::sendMessage(const std::string & msg){
if (!disableMessages){
sendCommand(Command::PrivateMessage, getChannel()->getName(), ":" + msg);
}
}
void Client::sendPong(const Command & ping){
Command pong(username, Command::Pong);
pong.setParameters(ping.getParameters());
sendCommand(pong);
}
std::string Client::readMessage(){
std::string received;
bool foundReturn = false;
while (true){
try {
char nextCharacter = Network::read8(socket);
/* NOTE the latest RFC says that either \r or \n is the end of the message
* http://www.irchelp.org/irchelp/rfc/chapter8.html
*/
if (nextCharacter == '\r'){
// Found return
foundReturn = true;
continue;
} else if ((nextCharacter == '\n') && foundReturn){
// Should be the end of the message assuming \r is before it
break;
}
received += nextCharacter;
} catch (const Network::MessageEnd & ex){
// end of message get out
throw ex;
}
}
//Global::debug(0) << "Read next string: " << received << std::endl;
return received;
}
void Client::checkResponseAndHandle(const Command & command){
// Checks for username or channel errors
if (command.getType() == Command::ErrorNickInUse){
::Util::Thread::ScopedLock scope(lock);
// Change the username back to what it was
getChannel()->removeUser(username);
username = previousUsername;
getChannel()->addUser(username);
} else if (command.getType() == Command::ErrorBannedFromChannel ||
command.getType() == Command::ErrorInviteOnlyChannel ||
command.getType() == Command::ErrorBadChannelKey ||
command.getType() == Command::ErrorChannelIsFull ||
command.getType() == Command::ErrorNoSuchChannel){
::Util::Thread::ScopedLock scope(lock);
// Revert old channel
removeChannel(getChannel()->getName());
currentChannel = previousActiveChannel;
} else if (command.getType() == Command::ReplyTopic){
::Util::Thread::ScopedLock scope(lock);
// Set topic
getChannel()->setTopic(command.getParameters().at(2));
} else if (command.getType() == Command::ReplyTopicAuthor){
::Util::Thread::ScopedLock scope(lock);
// Set topic and author
const std::vector<std::string> & params = command.getParameters();
getChannel()->setTopicAuthor(split(params.at(1), '!').at(0), atoi(params.at(2).c_str()));
} else if (command.getType() == Command::ReplyNames){
// Add names
const std::vector<std::string> & params = command.getParameters();
//if (params.at(1) == currentChannel->getName()){
const std::vector<std::string> & names = split(params.at(2), ' ');
::Util::Thread::ScopedLock scope(lock);
//currentChannel->addUsers(names);
ChannelPointer update = findChannel(params.at(1));
if (update != NULL){
update->addUsers(names);
}
//}
}
}
void Client::run(){
while (!end){
try {
const std::string & message = readMessage();
// Check if the message is empty it might be because of (\n)
if (!message.empty()){
Command command(message);
::Util::Thread::ScopedLock scope(lock);
checkResponseAndHandle(command);
commands.push(command);
} else {
}
} catch (const Network::MessageEnd & ex){
end = true;
}
}
}
Message::EventInterface::EventInterface(){
}
Message::EventInterface::~EventInterface(){
}
void Message::EventInterface::EventInterface::handleCommand(const std::vector<std::string> & command){
}
Message::HandlerInterface::HandlerInterface(){
}
Message::HandlerInterface::~HandlerInterface(){
}
Message::QueueInterface::QueueInterface(){
}
Message::QueueInterface::~QueueInterface(){
}
Message::QueueInterface::FontWrapper::FontWrapper(){
}
Message::QueueInterface::FontWrapper::~FontWrapper(){
}
void Message::QueueInterface::processMessages(Message::QueueInterface::FontWrapper & wrapper, int width, int height){
while (!messages.empty()){
const std::string message = messages.front();
messages.pop();
// Check message if it exceeds the length of the box so we can split it
if (wrapper.getWidth(message) > width-15){
unsigned int marker = 0;
unsigned int length = 0;
while ((marker+length) < message.size()){
//Global::debug(0) << "Substring: " << message.substr(marker, length) << " Marker: " << marker << " and Current length: " << length << std::endl;
if (wrapper.getWidth(message.substr(marker, length)) < width-15){
length++;
continue;
} else {
if (message[marker+length] == ' '){
buffer.push_front(message.substr(marker, length));
marker += length+1;
length = 0;
} else {
// Search for previous space
unsigned int cutoff = marker+length;
while ((marker+length) > marker){
if (message[marker+length] == ' '){
break;
}
length--;
}
if ((marker+length) > marker){
buffer.push_front(message.substr(marker, length));
marker += length+1;
length = 0;
} else {
buffer.push_front(message.substr(marker, cutoff));
marker = cutoff+1;
length = 0;
}
}
}
}
// Add last item
if ((marker+length) > marker){
buffer.push_front(message.substr(marker, length));
}
} else {
buffer.push_front(message);
}
// Drop out of sight
if ((buffer.size() * (wrapper.getHeight()+2)) > (unsigned int)height){
buffer.pop_back();
}
}
}
class ChannelTab: public Gui::TabItem, Message::QueueInterface{
public:
ChannelTab(const std::string & name):
TabItem(name),
width(0),
height(0),
changed(false){
}
virtual ~ChannelTab(){
}
void act(const Font & font){
class Wrapper: public Message::QueueInterface::FontWrapper{
public:
Wrapper(const Font & font):
font(font){
}
virtual ~Wrapper(){
}
const Font & font;
int getWidth(const std::string & text){
return font.textLength(text.c_str());
}
int getHeight(){
return font.getHeight();
}
};
Wrapper wrapper(font);
processMessages(wrapper, width, height);
}
void draw(const Font& font, const Graphics::Bitmap & work){
if (!isActive()){
return;
}
work.clear();
int mod = height-(font.getHeight()+2);
for (std::deque<std::string>::iterator i = buffer.begin(); i != buffer.end(); ++i){
const std::string & text = *i;
font.printf(0, mod, Graphics::makeColor(255,255,255), work, text, 0);
mod-=(font.getHeight()+2);
}
}
void addMessage(const std::string & message){
if (!isActive() && !changed){
changed = true;
}
messages.push(message);
}
void addMessage(const std::string & name, const std::string & message){
addMessage("<"+name+"> " + message);
}
void inspectBody(const Graphics::Bitmap & body){
width = body.getWidth();
height = body.getHeight();
}
void toggleActive(){
if (!active){
active = true;
changed = false;
} else {
active = false;
}
}
private:
int width;
int height;
bool changed;
};
static Util::ReferenceCount<ChannelTab> convertTab(ChatInterface * chat, std::string name = ""){
if (!name.empty()){
try{
return chat->getTabByName(name).convert<ChannelTab>();
} catch (const Gui::TabContainer::NoSuchName & ex){
}
}
return chat->getCurrentTab().convert<ChannelTab>();
}
static void submit(void * interface){
ChatInterface * chat = (ChatInterface *)interface;
if (!chat->getInputBox().getText().empty()){
const std::string & text = chat->getInputBox().getText();
// check if it's a command
if (Util::matchRegex(text, Util::Regex("^/.*"))){
const std::vector<std::string> & command = Util::splitString(text.substr(1), ' ');
chat->handleCommand(command);
} else {
convertTab(chat)->addMessage(chat->getClient()->getName(), text);
chat->getClient()->sendMessage(text);
chat->notify(text);
}
chat->getInputBox().clear();
}
}
ChatInterface::ChatInterface(const std::string & host, int port):
host(host),
widthRatio(.8),
heightRatio(.95),
serverTab(Util::ReferenceCount<Gui::TabItem>(new ChannelTab(host))){
client = Util::ReferenceCount< Client >(new Client(host, port));
client->connect();
// Setup window size and chat list
const int width = Configuration::getScreenWidth();
const int height = Configuration::getScreenHeight();
chatBox.transforms.setRadius(15);
Gui::ColorInfo tabbed;
tabbed.body = Graphics::makeColor(255,255,255);
tabbed.bodyAlpha = 128;
tabbed.border = Graphics::makeColor(0,0,255);
tabbed.borderAlpha = 255;
chatBox.colors = tabbed;
// chat panel widthRatio% heightRatio%
chatBox.location.setPosition(Gui::AbsolutePoint(0, 0));
chatBox.location.setDimensions(width * widthRatio, height * heightRatio);
chatBox.add(serverTab);
// edit box widthRatio% remaining (heightRatio + .01)%
const double inputStart = heightRatio + .01;
inputBox.transforms.setRadius(15);
inputBox.location.setPosition(Gui::AbsolutePoint(0, height * inputStart));
inputBox.location.setDimensions(width * widthRatio, height * (1 - inputStart));
inputBox.addHook(Keyboard::Key_ENTER, submit, this);
// Set the location of user list width * widthRatio and height
}
ChatInterface::~ChatInterface(){
}
void ChatInterface::act(){
// Default size of fonts
const int size = Configuration::getScreenHeight() * (1 - (heightRatio + .01));
// Size is important
+
const Font & font = Font::getDefaultFont(size, size);
processMessages();
-
chatBox.act(font);
inputBox.act(font);
}
void ChatInterface::draw(const Graphics::Bitmap & work){
const int size = Configuration::getScreenHeight() * (1 - (heightRatio + .01));
const Font & font = Font::getDefaultFont(size, size);
chatBox.draw(font, work);
inputBox.draw(font, work);
}
void ChatInterface::nextChannel(){
chatBox.next();
const std::string & name = chatBox.getCurrent()->getName();
if (name == host){
client->setMessagesDisabled(true);
} else {
client->setMessagesDisabled(false);
client->setChannel(client->getChannelIndex(name));
}
}
void ChatInterface::previousChannel(){
chatBox.previous();
const std::string & name = chatBox.getCurrent()->getName();
if (chatBox.getCurrent()->getName() == host){
client->setMessagesDisabled(true);
} else {
client->setMessagesDisabled(false);
client->setChannel(client->getChannelIndex(name));
}
}
Util::ReferenceCount<Client> ChatInterface::getClient(){
return client;
}
Util::ReferenceCount<Gui::TabItem> ChatInterface::getCurrentTab(){
return chatBox.getCurrent();
}
Util::ReferenceCount<Gui::TabItem> ChatInterface::getTabByName(const std::string & name){
return chatBox.getByName(name);
}
void ChatInterface::processMessages(){
while (client->hasCommands()){
::Network::IRC::Command command = client->nextCommand();
std::vector<std::string> params = command.getParameters();
//Global::debug(0) << "Got message: " << command.getSendable() << std::endl;
try {
if (command.getType() == ::Network::IRC::Command::Ping){
client->sendPong(command);
serverTab.convert<ChannelTab>()->addMessage(command.getOwner(), "*** Ping!");
} else if (command.getType() == ::Network::IRC::Command::PrivateMessage){
// Check channel
const std::string & channel = params.at(0);
if (client->isCurrentChannel(channel)){
// Username and message
convertTab(this, channel)->addMessage(command.getOwner(), params.at(1));
}
} else if (command.getType() == ::Network::IRC::Command::Notice){
// Username and message
serverTab.convert<ChannelTab>()->addMessage(command.getOwner(), params.at(1));
} else if (command.getType() == ::Network::IRC::Command::ReplyMOTD ||
command.getType() == ::Network::IRC::Command::ReplyMOTDStart ||
command.getType() == ::Network::IRC::Command::ReplyMOTDEndOf){
serverTab.convert<ChannelTab>()->addMessage("*** MOTD " + params.at(1));
} else if (command.getType() == ::Network::IRC::Command::Join){
serverTab.convert<ChannelTab>()->addMessage("*** You have joined the channel " + params.at(0) + ".");
chatBox.add(Util::ReferenceCount<Gui::TabItem>(new ChannelTab(params.at(0))));
} else if (command.getType() == ::Network::IRC::Command::ReplyNoTopic){
serverTab.convert<ChannelTab>()->addMessage("*** The channel " + params.at(1) + " has no topic set.");
} else if (command.getType() == ::Network::IRC::Command::ReplyTopic){
serverTab.convert<ChannelTab>()->addMessage("*** The channel topic for " + params.at(1) + " is: \"" + params.at(2) + "\".");
} else if (command.getType() == ::Network::IRC::Command::ReplyNames){
std::vector<std::string> names = split(params.at(2), ' ');
std::map<std::string, std::vector<std::string> >::iterator check = namesRequest.find(params.at(1));
if (check == namesRequest.end()){
namesRequest[params.at(1)] = std::vector<std::string>();
check = namesRequest.find(params.at(1));
}
check->second.insert(check->second.begin(), names.begin(), names.end());
} else if (command.getType() == ::Network::IRC::Command::ReplyNamesEndOf){
std::map<std::string, std::vector<std::string> >::iterator check = namesRequest.find(params.at(1));
if (check != namesRequest.end()){
serverTab.convert<ChannelTab>()->addMessage("*** Current users on " + params.at(1) + " \"" + Util::joinStrings(check->second) + "\".");
namesRequest.erase(check);
}
} else if (command.getType() == ::Network::IRC::Command::ErrorNickInUse){
serverTab.convert<ChannelTab>()->addMessage("[Error] " + params.at(1) + ": Nick already in use.");
} else if (command.getType() == ::Network::IRC::Command::ErrorNoSuchNick){
serverTab.convert<ChannelTab>()->addMessage("[Error] " + params.at(1) + ": No such nick.");
} else if (command.getType() == ::Network::IRC::Command::ErrorNoSuchChannel){
serverTab.convert<ChannelTab>()->addMessage("[Error] " + params.at(1) + ": No such channel.");
} else if (command.getType() == ::Network::IRC::Command::Error){
Global::debug(0) << "Received Error: " << command.getSendable() << "... Aborting." << std::endl;
throw Exception::Return(__FILE__, __LINE__);
}
} catch (const std::out_of_range & ex){
}
// Check if we got any CTCP delimited messages
if (command.hasCtcp()){
std::vector<std::string> ctcp = command.getCtcp();
try {
if (ctcp.at(0) == "PING"){
// Lets check if there is an existing query otherwise send off request
if (command.getType() == ::Network::IRC::Command::Notice){
std::map<std::string, uint64_t>::iterator check = pingReply.find(command.getOwner());
if (check != pingReply.end()){
// there is an existing entry lets display our ping
std::ostringstream difference;
difference << (double)((System::currentMilliseconds() - check->second)/1000000);
serverTab.convert<ChannelTab>()->addMessage("[CTCP] Received CTCP-PING reply from " + check->first + ": " + difference.str() + "second(s)" );
pingReply.erase(check);
}
} else if (command.getType() == ::Network::IRC::Command::PrivateMessage){
client->sendCommand(::Network::IRC::Command::Notice, command.getOwner(), ":\001PING " + ctcp.at(1) + "\001");
serverTab.convert<ChannelTab>()->addMessage("[CTCP] Received CTCP-PING request from " + command.getOwner() + ", sending answer.");
}
}
} catch (const std::out_of_range & ex){
}
}
}
}
void ChatInterface::notify(const std::string & message){
for (std::vector<NotifyCallback>::iterator i = callbacks.begin(); i != callbacks.end(); ++i){
(*i)(message);
}
for (std::vector<Message::EventInterface *>::iterator i = subscribers.begin(); i != subscribers.end(); ++i){
(*i)->notify(message);
}
}
void ChatInterface::handleCommand(const std::vector<std::string> & command){
if (command.at(0) == "help"){
convertTab(this)->addMessage("* commands: help, nick, whisper, ping, join, names, topic, previous, next, channels, quit");
} else if (command.at(0) == "nick"){
try {
const std::string & nick = command.at(1);
if (!nick.empty()){
client->setName(nick);
convertTab(this)->addMessage("* nick changed to " + nick);
}
} catch (const std::out_of_range & ex){
convertTab(this)->addMessage("* /nick [name]");
}
} else if (command.at(0) == "whisper"){
try {
const std::string & who = command.at(1);
const std::string & message = Util::joinStrings(command, 2);
if (!who.empty() && !message.empty()){
client->sendCommand(::Network::IRC::Command::PrivateMessage, who, ":" + message);
convertTab(this)->addMessage("-> " + who + " " + message);
}
} catch (const std::out_of_range & ex){
convertTab(this)->addMessage("* /whisper [nick] [message]");
}
} else if (command.at(0) == "ping"){
try {
const std::string & who = command.at(1);
if (!who.empty()){
std::ostringstream timestamp;
uint64_t time = System::currentMilliseconds();
timestamp << time;
client->sendCommand(::Network::IRC::Command::PrivateMessage, who, ":\001PING " + timestamp.str() + "\001");
convertTab(this)->addMessage("[CTCP] Sending CTCP-PING request to " + who);
// Log user
pingReply[who] = time;
}
} catch (const std::out_of_range & ex){
convertTab(this)->addMessage("* /ping [nick]");
}
} else if (command.at(0) == "join"){
try {
const std::string & channel = command.at(1);
if (!channel.empty()){
client->joinChannel(channel);
}
} catch (const std::out_of_range & ex){
convertTab(this)->addMessage("* /join [channel]");
}
} else if (command.at(0) == "names"){
try {
const std::string & channel = command.at(1);
if (!channel.empty()){
client->sendCommand(::Network::IRC::Command::Names, channel);
namesRequest[channel] = std::vector<std::string>();
}
} catch (const std::out_of_range & ex){
convertTab(this)->addMessage("* /names [channel]");
}
} else if (command.at(0) == "topic"){
try {
const std::string & channel = command.at(1);
if (!channel.empty()){
client->sendCommand(::Network::IRC::Command::Topic, channel);
}
} catch (const std::out_of_range & ex){
client->sendCommand(::Network::IRC::Command::Topic, client->getChannel()->getName());
}
} else if (command.at(0) == "previous"){
client->previousChannel();
} else if (command.at(0) == "next"){
client->nextChannel();
} else if (command.at(0) == "channels"){
convertTab(this)->addMessage("* Current Channels: " + client->channelListAsString());
} else if (command.at(0) == "quit"){
const std::string & message = Util::joinStrings(command, 1);
if (!message.empty()){
client->sendCommand(::Network::IRC::Command::Quit, ":" + message);
Global::debug(0) << "Quit (" + message + "). Waiting for server to close connection..." << std::endl;
} else {
client->sendCommand(::Network::IRC::Command::Quit);
Global::debug(0) << "Quit. Waiting for server to close connection..." << std::endl;
}
} else {
convertTab(this)->addMessage("* Uknown command.");
}
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Wed, Jun 17, 9:14 PM (1 w, 5 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
71226
Default Alt Text
(68 KB)
Attached To
Mode
R75 R-Tech1
Attached
Detach File
Event Timeline