Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F132125
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
61 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/util/funcs.cpp b/util/funcs.cpp
index 88bcee11..7004176e 100644
--- a/util/funcs.cpp
+++ b/util/funcs.cpp
@@ -1,362 +1,387 @@
#ifdef USE_ALLEGRO
#include <allegro.h>
#endif
#ifdef USE_SDL
#include <SDL.h>
#endif
#ifdef USE_ALLEGRO5
#include <allegro5/allegro.h>
#endif
#include "funcs.h"
#include "debug.h"
#include <vector>
#include <string>
#include <string.h>
#include <algorithm>
#include "file-system.h"
#include "graphics/bitmap.h"
#include "font.h"
#include "init.h"
#include <sstream>
#include "file-system.h"
#include <math.h>
#ifndef USE_ALLEGRO
/* FIXME: move this to the filesystem module */
#include "sfl/sfl.h"
#include "sfl/sflfile.h"
#endif
#ifndef WINDOWS
#include <unistd.h>
#endif
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
using namespace std;
/* remove this once cmake and scons properly set DATA_PATH */
#ifndef DATA_PATH
#define DATA_PATH "data"
#endif
/* the build system should define DATA_PATH */
static string dataPath = DATA_PATH;
const double Util::pi = 3.14159265358979323846;
double Util::radians(double degree){
return degree * pi / 180.0;
}
double Util::degrees(double radians){
return radians * 180.0 / pi;
}
/*
inline int rnd( int q ){
if ( q <= 0 ) return 0;
return (int)( rand() % q );
}
*/
int Util::max(int a, int b){
if (a>b){
return a;
}
return b;
}
double Util::min(double a, double b){
if (a < b){
return a;
}
return b;
}
double Util::max(double a, double b){
if (a > b){
return a;
}
return b;
}
/*
int Util::min(int a, int b){
if (a<b){
return a;
}
return b;
}
*/
int Util::clamp(int value, int min, int max){
return Util::min(Util::max(value, min), max);
}
double Util::clamp(double value, double min, double max){
return Util::min(Util::max(value, min), max);
}
int Util::rnd( int q, int min, int range ){
return q - min + rnd( range );
}
int Util::rnd( int min, int max ){
return rnd( max - min ) + min;
}
/* sleep for `x' milliseconds */
void Util::rest( int x ){
#ifdef USE_ALLEGRO
::rest(x);
#endif
#ifdef USE_SDL
SDL_Delay(x);
#endif
#ifdef USE_ALLEGRO5
al_rest((double) x / 1000.0);
#endif
}
void Util::restSeconds(double x){
Util::rest((int)(x * 1000));
}
#if 0
bool Util::checkVersion(int version){
if (version == Global::getVersion()){
return true;
}
/* when an incompatible version is made, add a check here, like
* version < getVersion(3, 5)
* would mean any client below version 3.5 is incompatible.
*
* assume versions of client's greater than ourself is compatible, but
* this may not be true. There is no way to check this.
*/
if (version < 0){
return false;
}
return true;
}
#endif
void Util::setDataPath( const string & str ){
dataPath = str;
}
Filesystem::AbsolutePath Util::getDataPath2(){
return Filesystem::AbsolutePath(dataPath + "/");
}
/* FIXME: remove this method */
bool Util::exists( const string & file ){
return Storage::instance().exists(Filesystem::AbsolutePath(file));
/*
#ifdef USE_ALLEGRO
return ::exists(file.c_str()) != 0;
#else
return file_exists(file.c_str());
#endif
*/
}
/*
vector<Filesystem::AbsolutePath> Util::getFiles(const Filesystem::AbsolutePath & dataPath, const string & find){
return Filesystem::getFiles(dataPath, find);
}
*/
string Util::trim(const std::string & str){
string s;
size_t startpos = str.find_first_not_of(" \t");
size_t endpos = str.find_last_not_of(" \t");
// if all spaces or empty return an empty string
if ((string::npos == startpos) ||
(string::npos == endpos)){
return "";
} else {
return str.substr(startpos, endpos-startpos+1);
}
return str;
}
/* makes the first letter of a string upper case */
string Util::upcase(std::string str){
if ( str.length() > 0 && (str[0] >= 'a' && str[0] <= 'z') ){
str[0] = str[0] - 'a' + 'A';
}
return str;
}
static int lowerCase(int c){
return tolower(c);
}
static int upperCase(int c){
return toupper(c);
}
string Util::upperCaseAll(std::string str){
std::transform(str.begin(), str.end(), str.begin(), upperCase);
return str;
}
string Util::lowerCaseAll(std::string str){
std::transform(str.begin(), str.end(), str.begin(), lowerCase);
/*
for (unsigned int i = 0; i < str.length(); i++){
if (str[0] >= 'A' && str[0] <= 'Z'){
str[0] = str[0] - 'A' + 'a';
}
}
*/
return str;
}
+// Split string
+std::vector<std::string> Util::splitString(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;
+}
+
+// Join strings
+std::string Util::joinStrings(const std::vector< std::string > & message, unsigned int start){
+ std::string all;
+ for (unsigned int i = start; i < message.size(); ++i){
+ all+=message.at(i) + (i < message.size()-1 ? " " : "");
+ }
+ return all;
+}
+
/*Gets the minimum of three values*/
static int minimum(int a,int b,int c){
int min=a;
if(b<min)
min=b;
if(c<min)
min=c;
return min;
}
/* Compute levenshtein distance between s and t
* from: http://www.merriampark.com/ldc.htm
*/
static int levenshtein_distance(const char *s, const char *t){
//Step 1
int k,i,j,n,m,cost,distance;
int * d;
n=strlen(s);
m=strlen(t);
if(n!=0&&m!=0){
d = (int*) malloc((sizeof(int))*(m+1)*(n+1));
m++;
n++;
//Step 2
for(k=0;k<n;k++)
d[k]=k;
for(k=0;k<m;k++)
d[k*n]=k;
//Step 3 and 4
for(i=1;i<n;i++)
for(j=1;j<m;j++)
{
//Step 5
if(s[i-1]==t[j-1])
cost=0;
else
cost=1;
//Step 6
d[j*n+i]=minimum(d[(j-1)*n+i]+1,d[j*n+i-1]+1,d[(j-1)*n+i-1]+cost);
}
distance=d[n*m-1];
free(d);
return distance;
} else {
return -1; //a negative return value means that one or both strings are empty.
}
}
int Util::levenshtein(const std::string & str1, const std::string & str2){
return levenshtein_distance(str1.c_str(), str2.c_str());
}
void Util::limitPrintf(char * buffer, int size, const char * format, va_list args){
#ifdef USE_ALLEGRO
uvszprintf(buffer, size, format, args);
#else
vsnprintf(buffer, size, format, args);
#endif
}
/*
#ifndef WINDOWS
int Util::getPipe(int files[2]){
#ifdef PS3
return 0;
#else
return pipe(files);
#endif
}
#endif
*/
void Util::showError(const Graphics::Bitmap & screen, const Exception::Base & exception, const string & info){
// screen.BlitFromScreen(0, 0);
Graphics::Bitmap error(screen.getWidth() - 100, screen.getHeight() - 100);
error.fill(Graphics::darken(Graphics::makeColor(160, 0, 0), 3));
error.border(1, 2, Graphics::makeColor(240, 0, 0));
const Font & font = Font::getDefaultFont(17, 17);
int y = 10;
std::ostringstream out;
out << info;
out << " " << exception.getTrace();
Global::debug(0) << out.str() << std::endl;
font.printfWrap(10, 10, Graphics::makeColor(240, 240, 240), error, error.getWidth() - 20, out.str(), 0);
Graphics::Bitmap::transBlender(0, 0, 0, 220);
error.translucent().draw(50, 50, screen);
screen.BlitToScreen();
}
void Util::showError(const Exception::Base & exception, const std::string & info){
Graphics::Bitmap screen(*Graphics::screenParameter.current());
showError(screen, exception, info);
}
static double twoDigits(double x){
return (int) (x * 100) / 100.0;
}
string Util::niceSize(unsigned long size){
const char sizes[] = {'b', 'k', 'm', 'g', 't'};
double real = size;
for (unsigned int i = 0; i < sizeof(sizes) / sizeof(const char); i++){
if (real > 1024){
real /= 1024.0;
} else {
ostringstream in;
in << twoDigits(real) << sizes[i];
return in.str();
}
}
ostringstream in;
in << twoDigits(real) << "t";
return in.str();
}
std::string Util::join(const std::vector<std::string> & list, const std::string & middle){
ostringstream out;
bool first = true;
for (std::vector<std::string>::const_iterator it = list.begin(); it != list.end(); it++){
if (!first){
out << middle;
}
out << *it;
first = false;
}
return out.str();
}
double Util::distance(double x1, double y1, double x2, double y2){
double xs = x1 - x2;
double ys = y1 - y2;
return sqrt(xs * xs + ys * ys);
}
diff --git a/util/funcs.h b/util/funcs.h
index ab59c3e8..17b6f3eb 100644
--- a/util/funcs.h
+++ b/util/funcs.h
@@ -1,110 +1,116 @@
#ifndef _paintown_funcs_h
#define _paintown_funcs_h
#include <stdlib.h>
#include <vector>
#include <string>
#include <stdarg.h>
#include "regex.h"
#include "file-system.h"
namespace Exception{
class Base;
}
namespace Graphics{
class Bitmap;
}
namespace Util{
extern const double pi;
/* returns a number between 0 and q-1. you will never get `q'. if
* you wanted to get `q' then pass in q+1
*/
inline int rnd( int q ){
if (q <= 0){
return 0;
}
return (int)(rand() % q);
}
// std::vector< std::string > getFiles(const Filesystem::AbsolutePath & dataPath, const std::string & find );
double radians(double degree);
double degrees(double radians);
Filesystem::AbsolutePath getDataPath2();
void setDataPath( const std::string & str );
bool exists( const std::string & file );
/* check that `version' is compatible with this program, mostly used
* for network clients.
*/
// bool checkVersion(int version);
/* return a random number + some range between min/max */
int rnd( int q, int min, int max );
int max(int a, int b);
inline int min(int a, int b){
if (a<b){
return a;
}
return b;
}
double min(double a, double b);
double max(double a, double b);
double distance(double x1, double y1, double x2, double y2);
int clamp(int value, int min, int max);
double clamp(double value, double min, double max);
/* return a number between min/max */
int rnd( int min, int max );
/* rest in milliseconds */
void rest( int x );
/* rest in seconds */
void restSeconds(double x);
std::string trim(const std::string & str);
/* only upper cases the first letter of a string */
std::string upcase(std::string str);
/* lower cases the entire string */
std::string lowerCaseAll(std::string str);
/* upper cases the entire string */
std::string upperCaseAll(std::string str);
+// Split string
+std::vector<std::string> splitString(std::string str, char splitter);
+
+// Join strings
+std::string joinStrings(const std::vector< std::string > & message, unsigned int start = 0);
+
/* convert a size in bytes into human readable form.
* 234823592 = 223.94m
*/
std::string niceSize(unsigned long size);
int levenshtein(const std::string & str1, const std::string & str2);
// int getPipe(int files[2]);
void limitPrintf(char * buffer, int size, const char * format, va_list args);
void showError(const Graphics::Bitmap & screen, const Exception::Base & exception, const std::string & info);
/* will create a screen of size GFX_X, GFX_Y */
void showError(const Exception::Base & exception, const std::string & info);
std::string join(const std::vector<std::string> & list, const std::string & middle);
}
#endif
diff --git a/util/gui/tab-container.cpp b/util/gui/tab-container.cpp
index e0cb91e0..3885c699 100644
--- a/util/gui/tab-container.cpp
+++ b/util/gui/tab-container.cpp
@@ -1,173 +1,177 @@
#include "tab-container.h"
#include "util/font.h"
#include "util/debug.h"
namespace Gui{
TabItem::TabItem():
active(false){
}
TabItem::TabItem(const std::string & name):
active(false),
name(name){
}
TabItem::~TabItem(){
}
+void TabItem::inspectBody(const Graphics::Bitmap &){
+}
+
DummyTab::DummyTab(const std::string & name):
TabItem(name){
}
DummyTab::~DummyTab(){
}
-void DummyTab::act(){
+void DummyTab::act(const Font &){
}
-void DummyTab::draw(const Font&, const Graphics::Bitmap & work){
+void DummyTab::draw(const Font &, const Graphics::Bitmap & work){
work.fill(Graphics::makeColor(220, 220, 220));
}
TabContainer::TabContainer():
current(0),
body(640,480){
}
TabContainer::TabContainer(const TabContainer & copy):
tabs(copy.tabs),
current(copy.current),
body(copy.body){
}
TabContainer::~TabContainer(){
}
TabContainer & TabContainer::operator=(const TabContainer & copy){
tabs = copy.tabs;
current = copy.current;
body = copy.body;
return *this;
}
void TabContainer::act(const Font & font){
for (std::vector< Util::ReferenceCount<TabItem> >::iterator i = tabs.begin(); i != tabs.end(); ++i){
Util::ReferenceCount<TabItem> tab = *i;
- tab->act();
+ tab->inspectBody(body);
+ tab->act(font);
}
}
void TabContainer::render(const Graphics::Bitmap &){
}
static void drawBox(int radius, int x1, int y1, int x2, int y2, Gui::ColorInfo colors, const Graphics::Bitmap & work){
// rounded body?
if (radius > 0){
if (colors.bodyAlpha < 255){
Graphics::Bitmap::transBlender(0,0,0,colors.bodyAlpha);
work.translucent().roundRectFill(radius, x1, y1, x2, y2, colors.body);
Graphics::Bitmap::transBlender(0,0,0,colors.borderAlpha);
work.translucent().roundRect(radius, x1, y1, x2-1, y2-1, colors.border);
} else {
work.roundRectFill(radius, x1, y1, x2, y2, colors.body);
work.roundRect(radius, x1, y1, x2-1, y2-1, colors.border);
}
} else {
if (colors.bodyAlpha < 255){
Graphics::Bitmap::transBlender(0,0,0,colors.bodyAlpha);
work.translucent().rectangleFill(x1, y1, x2, y2, colors.body );
Graphics::Bitmap::transBlender(0,0,0,colors.borderAlpha);
work.translucent().vLine(y1,x1,y2-1,colors.border);
work.translucent().hLine(x1,y2-1,x2,colors.border);
work.translucent().vLine(y1,x2-1,y2-1,colors.border);
} else {
work.rectangleFill(x1, y1, x2, y2, colors.body );
work.vLine(y1,x1,y2-1,colors.border);
work.hLine(x1,y2-1,x2,colors.border);
work.vLine(y1,x2-1,y2-1,colors.border);
}
}
}
void TabContainer::draw(const Font & font, const Graphics::Bitmap & work){
const int tabHeight = font.getHeight();
const int height = location.getHeight() - tabHeight+1;
// Draw tabs
drawTabs(font, Graphics::Bitmap(work, location.getX(), location.getY(), location.getWidth(), tabHeight+1));
// Draw body
Graphics::Bitmap area(work, location.getX(), location.getY() + tabHeight+1, location.getWidth(), height);
drawBox(transforms.getRadius(), 0, -(tabHeight+1), location.getWidth(), height, colors, area);
// Draw body content
const int modifier = (area.getWidth() * (transforms.getRadius()*.001)) == 0 ? 2 : area.getWidth() * (transforms.getRadius()*.001);
body.drawStretched(modifier, modifier, area.getWidth() - modifier*2, area.getHeight() - modifier*2, area);
}
void TabContainer::add(Util::ReferenceCount<TabItem> tab){
tabs.push_back(tab);
if (tabs.size() == 1){
tab->toggleActive();
}
}
void TabContainer::setBodySize(int width, int height){
if (body.getWidth() == width && body.getHeight() == height){
return;
}
body = Graphics::Bitmap(width, height);
}
void TabContainer::next(){
tabs[current]->toggleActive();
current = (current + 1) % tabs.size();
tabs[current]->toggleActive();
}
void TabContainer::previous(){
tabs[current]->toggleActive();
if (current == 0){
current = tabs.size()-1;
} else {
current--;
}
tabs[current]->toggleActive();
}
void TabContainer::drawTabs(const Font & font, const Graphics::Bitmap & work){
if (tabs.empty()){
drawBox(transforms.getRadius(), 0, 0, work.getWidth(), work.getHeight()*2, colors, work);
font.printf((work.getWidth()/2) - (font.textLength("Empty")/2), 0, Graphics::makeColor(255,255,255), work, "Empty", 0);
return;
}
const int width = work.getWidth() / tabs.size();
const int inactiveY = work.getHeight() * .25;
const int modifier = (width * (transforms.getRadius()*.005)) == 0 ? 2 : (width * (transforms.getRadius()*.005));
int currentX = 0;
for (std::vector< Util::ReferenceCount<TabItem> >::iterator i = tabs.begin(); i != tabs.end(); ++i){
Util::ReferenceCount<TabItem> tab = *i;
if (tab->isActive()){
drawBox(transforms.getRadius(), currentX, 0, currentX + width, work.getHeight()*2, colors, work);
Graphics::Bitmap fontArea(work, currentX + modifier, 0, width - (modifier*2), work.getHeight());
font.printf((fontArea.getWidth()/2) - (font.textLength(tab->getName().c_str())/2), 0, Graphics::makeColor(255,255,255), fontArea, tab->getName(), 0);
tab->draw(font, body);
} else {
drawBox(transforms.getRadius(), currentX, inactiveY, currentX + width, work.getHeight()*2, colors, work);
if (colors.bodyAlpha < 255){
Graphics::Bitmap::transBlender(0,0,0,colors.borderAlpha);
work.translucent().hLine(currentX,work.getHeight()-1,currentX + width,colors.border);
} else {
work.hLine(currentX,work.getHeight()-1,currentX + width,colors.border);
}
Graphics::Bitmap fontArea(work, currentX + modifier, inactiveY, width - (modifier*2), work.getHeight());
font.printf((fontArea.getWidth()/2) - (font.textLength(tab->getName().c_str())/2), 0, Graphics::makeColor(255,255,255), fontArea, tab->getName(), 0);
}
currentX += width;
}
}
}
diff --git a/util/gui/tab-container.h b/util/gui/tab-container.h
index ad945345..b2053590 100644
--- a/util/gui/tab-container.h
+++ b/util/gui/tab-container.h
@@ -1,103 +1,104 @@
#ifndef _gui_tab_container_h
#define _gui_tab_container_h
#include <string>
#include <vector>
#include "widget.h"
#include "util/file-system.h"
#include "util/pointer.h"
#include "util/graphics/gradient.h"
namespace Gui{
class TabItem{
public:
TabItem();
TabItem(const std::string &);
virtual ~TabItem();
- virtual void act() = 0;
- virtual void draw(const Font&, const Graphics::Bitmap &) = 0;
+ virtual void inspectBody(const Graphics::Bitmap &);
+ virtual void act(const Font &) = 0;
+ virtual void draw(const Font &, const Graphics::Bitmap &) = 0;
virtual inline void setName(const std::string & name) {
this->name = name;
}
virtual inline const std::string & getName() const {
return this->name;
}
virtual inline bool isActive() const {
return this->active;
}
virtual inline void toggleActive() {
this->active = !this->active;
}
protected:
bool active;
std::string name;
};
class DummyTab: public TabItem{
public:
DummyTab(const std::string &);
virtual ~DummyTab();
- virtual void act();
- virtual void draw(const Font&, const Graphics::Bitmap &);
+ virtual void act(const Font &);
+ virtual void draw(const Font &, const Graphics::Bitmap &);
};
class TabContainer: public Widget {
public:
TabContainer();
TabContainer(const TabContainer &);
virtual ~TabContainer();
// copy
TabContainer & operator=(const TabContainer &);
// Logic
virtual void act(const Font &);
// Render
using Widget::render;
virtual void render(const Graphics::Bitmap &);
virtual void draw(const Font &, const Graphics::Bitmap &);
// Add
virtual void add(Util::ReferenceCount<TabItem> tab);
// Set size of Content Body Area
virtual void setBodySize(int width, int height);
// Next
virtual void next();
// Previous
virtual void previous();
// Get the Content Body Area
virtual inline const Graphics::Bitmap & getBody() const {
return this->body;
}
// Empty
virtual inline bool empty() const {
return this->tabs.empty();
}
protected:
virtual void drawTabs(const Font &, const Graphics::Bitmap &);
std::vector< Util::ReferenceCount<TabItem> > tabs;
unsigned int current;
// Body defaults to 640x480
Graphics::Bitmap body;
/*! Gradient for active selection */
Effects::Gradient * activeColor;
};
}
#endif
diff --git a/util/network/irc.cpp b/util/network/irc.cpp
index 9476861a..b7c8119f 100644
--- a/util/network/irc.cpp
+++ b/util/network/irc.cpp
@@ -1,665 +1,861 @@
#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 <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){
}
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!
joinChannel("#paintown");
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){
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;
}
}
}
+class ChannelTab: public Gui::TabItem{
+public:
+ ChannelTab(const std::string & name):
+ TabItem(name),
+ width(0),
+ height(0),
+ changed(false){
+ }
+ virtual ~ChannelTab(){
+ }
+ void act(const Font & font){
+ processMessages(font);
+ }
+ 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 processMessages(const Font & font){
+ 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 (font.textLength(message.c_str()) > 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 (font.textLength(message.substr(marker, length).c_str()) < 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() * (font.getHeight()+2)) > (unsigned int)height){
+ buffer.pop_back();
+ }
+ }
+ }
+ void inspectBody(const Graphics::Bitmap & body){
+ width = body.getWidth();
+ height = body.getHeight();
+ }
+ void toggleActive(){
+ if (!active){
+ active = true;
+ changed = false;
+ } else {
+ active = false;
+ }
+ }
+private:
+ std::queue<std::string> messages;
+ std::deque<std::string> buffer;
+ int width;
+ int height;
+ bool changed;
+};
+
+
ChatInterface::ChatInterface(const std::string & host, int port):
widthRatio(.8),
-heightRatio(.95){
- //client = Util::ReferenceCount< Client >(new Client(host, port));
- //client->connect();
+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(Util::ReferenceCount<Gui::TabItem>(new Gui::DummyTab("Test")));
- chatBox.add(Util::ReferenceCount<Gui::TabItem>(new Gui::DummyTab("ABCDEFGHIJKLMNOPQRSTUVWXYZ")));
- chatBox.add(Util::ReferenceCount<Gui::TabItem>(new Gui::DummyTab("Test3")));
+ 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));
// 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(){
//client->nextChannel();
chatBox.next();
}
void ChatInterface::previousChannel(){
//client->previousChannel();
chatBox.previous();
}
Util::ReferenceCount<Client> ChatInterface::getClient(){
return client;
}
+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
+ //panel.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) + ".");
+ } 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){
+ }
+ }
+ }
+}
+
}
}
diff --git a/util/network/irc.h b/util/network/irc.h
index a3d70982..232a7a33 100644
--- a/util/network/irc.h
+++ b/util/network/irc.h
@@ -1,291 +1,297 @@
#ifndef _util_network_irc_h
#define _util_network_irc_h
#include "network.h"
#include "chat.h"
#include "util/pointer.h"
#include "util/thread.h"
#include "util/gui/tab-container.h"
#include "util/gui/lineedit.h"
#include <string>
#include <vector>
#include <queue>
+#include <map>
namespace Network{
namespace IRC{
class Command{
public:
enum Type{
Unknown,
Pass,
Nick,
User,
Server,
Oper,
Quit,
Squit,
Join,
Part,
Mode,
Topic,
Names,
List,
Invite,
Kick,
Version,
Stats,
Links,
Time,
Connect,
Trace,
Admin,
Info,
PrivateMessage,
Notice,
Who,
Whois,
Whowas,
Kill,
Ping,
Pong,
Error,
ErrorNickInUse,
ErrorNoSuchNick,
ErrorNoSuchChannel,
ErrorNeedMoreParams,
ErrorBannedFromChannel,
ErrorInviteOnlyChannel,
ErrorBadChannelKey,
ErrorChannelIsFull,
ReplyNames,
ReplyNamesEndOf,
ReplyNoTopic,
ReplyTopic,
ReplyTopicAuthor,
ReplyMOTD,
ReplyMOTDStart,
ReplyMOTDEndOf,
};
// Initializes it from an incoming message off of socket
Command(const std::string &);
// Create a message with owner and type
Command(const std::string &, const Type &);
Command(const Command &);
virtual ~Command();
virtual const Command & operator=(const Command &);
virtual std::string getSendable() const;
virtual inline const std::string & getOwner() const {
return this->owner;
}
virtual inline const Type & getType() const {
return this->type;
}
virtual inline void setParameters(const std::string & param1){
this->parameters.clear();
this->parameters.push_back(param1);
}
virtual inline void setParameters(const std::string & param1, const std::string & param2){
this->parameters.clear();
this->parameters.push_back(param1);
this->parameters.push_back(param2);
}
virtual inline void setParameters(const std::string & param1, const std::string & param2, const std::string & param3){
this->parameters.clear();
this->parameters.push_back(param1);
this->parameters.push_back(param2);
this->parameters.push_back(param3);
}
virtual inline void setParameters(const std::string & param1, const std::string & param2, const std::string & param3, const std::string & param4){
this->parameters.clear();
this->parameters.push_back(param1);
this->parameters.push_back(param2);
this->parameters.push_back(param3);
this->parameters.push_back(param4);
}
virtual inline void setParameters(const std::vector< std::string > & params){
this->parameters = params;
}
virtual inline const std::vector< std::string > & getParameters() const {
return this->parameters;
}
virtual inline bool hasCtcp() {
return !this->ctcp.empty();
}
virtual inline const std::vector< std::string > & getCtcp() const {
return this->ctcp;
}
protected:
std::string owner;
Type type;
std::vector< std::string > parameters;
std::vector< std::string > ctcp;
};
class Channel{
public:
Channel();
Channel(const std::string &);
Channel(const Channel &);
~Channel();
const Channel & operator=(const Channel &);
void addUser(const std::string &);
void removeUser(const std::string &);
void addUsers(const std::vector<std::string> &);
inline const std::vector<std::string> & getUsers() const{
return this->users;
}
inline const std::string & getName() const {
return this->name;
}
inline void setTopic(const std::string & topic){
this->topic = topic;
}
inline void setTopicAuthor(const std::string & topicAuthor, uint64_t topicDate){
this->topicAuthor = topicAuthor;
this->topicDate = topicDate;
}
protected:
std::string name;
std::string topic;
std::string topicAuthor;
uint64_t topicDate;
std::vector<std::string> users;
};
// Channel ReferenceCount
typedef Util::ReferenceCount<Channel> ChannelPointer;
class Client : public Chat::Threadable{
public:
Client(const std::string &, int port);
virtual ~Client();
virtual void connect();
virtual void run();
virtual bool hasCommands() const;
virtual Command nextCommand() const;
virtual void sendCommand(const Command &);
virtual void sendCommand(const Command::Type &);
virtual void sendCommand(const Command::Type &, const std::string &);
virtual void sendCommand(const Command::Type &, const std::string &, const std::string &);
virtual void sendCommand(const Command::Type &, const std::string &, const std::string &, const std::string &);
virtual void sendCommand(const Command::Type &, const std::string &, const std::string &, const std::string &, const std::string &);
virtual void setName(const std::string &);
virtual inline const std::string & getName() const {
return this->username;
}
virtual void joinChannel(const std::string &);
virtual inline ChannelPointer getChannel() const {
return this->activeChannels[this->currentChannel];
}
virtual inline std::vector< ChannelPointer > & channelList(){
return this->activeChannels;
}
virtual std::string channelListAsString();
virtual unsigned int getChannelIndex(const std::string &);
virtual bool isCurrentChannel(const std::string &);
virtual void setChannel(unsigned int channel);
virtual void nextChannel();
virtual void previousChannel();
virtual void sendMessage(const std::string &);
virtual void sendPong(const Command &);
protected:
void removeChannel(const std::string &);
ChannelPointer findChannel(const std::string &);
std::string readMessage();
//! Doesn't do anything to the command just handle some internal changes like username and channel stuff
void checkResponseAndHandle(const Command &);
Network::Socket socket;
std::string previousUsername;
std::string username;
unsigned int previousActiveChannel;
unsigned int currentChannel;
std::vector< ChannelPointer > activeChannels;
std::string hostname;
int port;
bool end;
mutable std::queue< Command > commands;
};
// Create a tabbed chatter to implement in games
class ChatInterface{
public:
ChatInterface(const std::string &, int port);
virtual ~ChatInterface();
void act();
void draw(const Graphics::Bitmap &);
void nextChannel();
void previousChannel();
Util::ReferenceCount<Client> getClient();
inline void setWidthRatio(double ratio){
this->widthRatio = ratio;
}
inline void setHeightRatio(double ratio){
this->heightRatio = ratio;
}
inline Gui::LineEdit & getInputBox() {
return this->inputBox;
}
protected:
+ void processMessages();
Util::ReferenceCount<Client> client;
Gui::TabContainer chatBox;
Gui::LineEdit inputBox;
double widthRatio;
double heightRatio;
+ Util::ReferenceCount<Gui::TabItem> serverTab;
+ // check ctcp reply
+ std::map<std::string, uint64_t> pingReply;
+ std::map< std::string, std::vector<std::string> > namesRequest;
};
}// end irc
}
#endif
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Tue, Jun 16, 12:28 AM (2 w, 1 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
71304
Default Alt Text
(61 KB)
Attached To
Mode
R75 R-Tech1
Attached
Detach File
Event Timeline