Page Menu
Home
Phabricator (Chris)
Search
Configure Global Search
Log In
Files
F131395
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
76 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/util/gui/list.cpp b/util/gui/list.cpp
index b9a14005..86733150 100644
--- a/util/gui/list.cpp
+++ b/util/gui/list.cpp
@@ -1,80 +1,90 @@
#include "list.h"
namespace Gui{
ListItem::ListItem(){
}
ListItem::~ListItem(){
}
ListInterface::ListInterface(){
}
ListInterface::~ListInterface(){
}
void ListInterface::render(const Graphics::Bitmap &){
}
void ListInterface::render(const Graphics::Bitmap &, const Font &){
}
SimpleList::SimpleList(){
}
SimpleList::~SimpleList(){
}
void SimpleList::act(const Font &){
}
void SimpleList::draw(const Font & font, const Graphics::Bitmap & work){
Graphics::Bitmap temp = Graphics::Bitmap(work, location.getX(), location.getY(), location.getWidth(), location.getHeight());
drawBox(transforms.getRadius(), 0, 0, location.getWidth(), location.getHeight(), colors, temp);
const int modifier = (temp.getWidth() * (transforms.getRadius()*.001)) == 0 ? 2 : (temp.getWidth() * (transforms.getRadius()*.001));
int y = 2;
for (std::vector< Util::ReferenceCount<ListItem> >::iterator i = list.begin(); i != list.end(); ++i){
Graphics::Bitmap listTemp = Graphics::Bitmap(temp, modifier, y, temp.getWidth()-(modifier*2), y);
Util::ReferenceCount<ListItem> item = *i;
item->draw(font, listTemp);
y += font.getHeight()+2;
}
}
void SimpleList::add(const Util::ReferenceCount<ListItem> item){
- list.push_back(item);
+ //list.push_back(item);
+ // Keep list sorted
+ std::vector< Util::ReferenceCount<ListItem> >::iterator position = list.begin();
+ while (position != list.end() && (*position)->compareTo(item) < 0){
+ position++;
+ }
+ list.insert(position, item);
}
void SimpleList::add(const std::vector< Util::ReferenceCount<ListItem> > & more){
- list.insert(list.end(),more.begin(),more.end());
+ /*list.insert(list.end(),more.begin(),more.end());*/
+ for (std::vector< Util::ReferenceCount<ListItem> >::const_iterator i = more.begin(); i != more.end(); i++){
+ Util::ReferenceCount<ListItem> item = *i;
+ add(item);
+ }
}
void SimpleList::remove(const Util::ReferenceCount<ListItem> removable){
for (std::vector< Util::ReferenceCount<ListItem> >::iterator i = list.begin(); i != list.end(); i++){
Util::ReferenceCount<ListItem> item = *i;
- if (removable == item){
+ if (removable->equals(item)){
list.erase(i);
return;
}
}
}
void SimpleList::replace(const std::vector< Util::ReferenceCount<ListItem> > & newList){
list = newList;
}
void SimpleList::clear(){
list.clear();
}
const std::vector< Util::ReferenceCount<ListItem> > & SimpleList::getList() const{
return list;
}
}
diff --git a/util/gui/list.h b/util/gui/list.h
index b58ae57c..d524588e 100644
--- a/util/gui/list.h
+++ b/util/gui/list.h
@@ -1,57 +1,59 @@
#ifndef _gui_list_h
#define _gui_list_h
#include "widget.h"
#include "util/pointer.h"
#include "util/font.h"
namespace Gui{
class ListItem{
public:
ListItem();
virtual ~ListItem();
virtual bool operator==(const ListItem &) = 0;
+ virtual bool equals(Util::ReferenceCount<ListItem>) = 0;
+ virtual int compareTo(Util::ReferenceCount<ListItem>) = 0;
virtual void act() = 0;
virtual void draw(const Font &, const Graphics::Bitmap &) = 0;
};
class ListInterface : public Gui::Widget{
public:
ListInterface();
virtual ~ListInterface();
virtual void act(const Font &) = 0;
virtual void draw(const Font &, const Graphics::Bitmap &) = 0;
virtual void add(const Util::ReferenceCount<ListItem>) = 0;
virtual void add(const std::vector< Util::ReferenceCount<ListItem> > &) = 0;
virtual void remove(const Util::ReferenceCount<ListItem>) = 0;
virtual void replace(const std::vector< Util::ReferenceCount<ListItem> > &) = 0;
virtual void clear() = 0;
virtual const std::vector< Util::ReferenceCount<ListItem> > & getList() const = 0;
private:
void render(const Graphics::Bitmap &);
void render(const Graphics::Bitmap &, const Font &);
};
class SimpleList : public ListInterface{
public:
SimpleList();
virtual ~SimpleList();
void act(const Font &);
void draw(const Font &, const Graphics::Bitmap &);
void add(const Util::ReferenceCount<ListItem>);
void add(const std::vector< Util::ReferenceCount<ListItem> > &);
void remove(const Util::ReferenceCount<ListItem>);
void replace(const std::vector< Util::ReferenceCount<ListItem> > &);
void clear();
const std::vector< Util::ReferenceCount<ListItem> > & getList() const;
protected:
std::vector< Util::ReferenceCount<ListItem> > list;
};
}
#endif
diff --git a/util/gui/tab-container.cpp b/util/gui/tab-container.cpp
index 7f5ae6d9..591f9aaf 100644
--- a/util/gui/tab-container.cpp
+++ b/util/gui/tab-container.cpp
@@ -1,210 +1,228 @@
#include "tab-container.h"
#include "util/font.h"
#include "util/debug.h"
#include <stdexcept>
#include <sstream>
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(const Font &){
}
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->inspectBody(body);
tab->act(font);
}
}
void TabContainer::render(const Graphics::Bitmap &){
}
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();
}
}
+Util::ReferenceCount<TabItem> TabContainer::remove(unsigned int index){
+ try {
+ // Check
+ Util::ReferenceCount<TabItem> tab = tabs.at(index);
+ tabs.erase(tabs.begin() + index);
+ return tab;
+ } catch (const std::out_of_range & ex){
+ throw new TabContainer::NoSuchTab(index);
+ }
+}
+
+void TabContainer::removeCurrent(){
+ tabs.erase(tabs.begin() + current);
+ if (current > 0){
+ current--;
+ }
+}
+
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::gotoTab(unsigned int index){
try {
// Check
Util::ReferenceCount<TabItem> tab = tabs.at(index);
tabs[current]->toggleActive();
current = index;
tabs[current]->toggleActive();
} catch (const std::out_of_range & ex){
throw new TabContainer::NoSuchTab(index);
}
}
void TabContainer::gotoTabByName(const std::string & name){
try {
gotoTab(findTab(name));
} catch (const TabContainer::NoSuchTab & ex){
throw ex;
}
}
TabContainer::NoSuchTab::NoSuchTab(const std::string & name) throw():
name(name){
}
TabContainer::NoSuchTab::NoSuchTab(unsigned int index) throw(){
std::ostringstream os;
os << index;
name = os.str();
}
TabContainer::NoSuchTab::~NoSuchTab() throw() {
}
const char* TabContainer::NoSuchTab::what() const throw() {
return name.c_str();
}
Util::ReferenceCount<TabItem> TabContainer::getTab(unsigned int index){
try {
return tabs.at(index);
} catch (const std::out_of_range & ex){
throw new TabContainer::NoSuchTab(index);
}
}
unsigned int TabContainer::findTab(const std::string & name){
for (unsigned int i = 0; i < tabs.size(); i++){
Util::ReferenceCount<TabItem> tab = tabs[i];
if (name == tab->getName()){
return i;
}
}
throw TabContainer::NoSuchTab(name);
}
Util::ReferenceCount<TabItem> TabContainer::getByName(const std::string & name){
return tabs[findTab(name)];
}
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 379df301..e1469aa2 100644
--- a/util/gui/tab-container.h
+++ b/util/gui/tab-container.h
@@ -1,130 +1,134 @@
#ifndef _gui_tab_container_h
#define _gui_tab_container_h
#include <string>
#include <vector>
#include <exception>
#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 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(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);
+ // Remove
+ virtual Util::ReferenceCount<TabItem> remove(unsigned int tab);
+ void removeCurrent();
+
// Set size of Content Body Area
virtual void setBodySize(int width, int height);
// Next
virtual void next();
// Previous
virtual void previous();
// Go to specific tab
virtual void gotoTab(unsigned int index);
// Go to specific tab by name
virtual void gotoTabByName(const std::string &);
// 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();
}
// Get current tab
virtual inline Util::ReferenceCount<TabItem> getCurrent() {
return this->tabs[current];
}
class NoSuchTab: public std::exception{
public:
NoSuchTab(const std::string &) throw();
NoSuchTab(unsigned int index) throw();
virtual ~NoSuchTab() throw();
virtual const char* what() const throw();
private:
std::string name;
};
virtual unsigned int findTab(const std::string &);
virtual Util::ReferenceCount<TabItem> getTab(unsigned int index);
virtual Util::ReferenceCount<TabItem> getByName(const std::string &);
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 e7c89625..9aa2fb21 100644
--- a/util/network/irc.cpp
+++ b/util/network/irc.cpp
@@ -1,1220 +1,1309 @@
#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 == "USERHOST"){
command = Command::Userhost;
} 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 == "302"){
command = Command::ReplyUserhost;
} 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::Userhost: return "USERHOST";
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;
}
+std::string Command::getCTCPSendable() const {
+ std::string sendable;
+ // Name
+ if (!owner.empty()){
+ sendable += ":" + owner + " ";
+ }
+ // Command
+ sendable += convertCommand(type) + " ";
+ // Params
+ for (unsigned int i = 0; i < ctcp.size(); ++i){
+ sendable += ctcp[i] + (i < ctcp.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(const std::string & name){
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(name);
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());
}
+void Client::partChannel(const std::string & channel){
+ for (std::vector< ChannelPointer >::iterator i = activeChannels.begin(); i != activeChannels.end(); ++i){
+ ChannelPointer activeChannel = *i;
+ if (activeChannel->getName() == channel){
+ // Remove channel
+ activeChannels.erase(i);
+ break;
+ }
+ }
+ currentChannel = previousActiveChannel;
+ sendCommand(Command::Part, channel);
+}
+
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::localNotify(const std::string &){
}
void Message::EventInterface::EventInterface::localCommand(const std::vector<std::string> &){
}
void Message::EventInterface::EventInterface::remoteNotify(const std::string &){
}
void Message::EventInterface::EventInterface::remoteCommand(const 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 UserItem : public Gui::ListItem{
public:
UserItem(const std::string & name, const Util::ReferenceCount<Client> client):
name(name),
client(client){
}
virtual ~UserItem(){
}
virtual bool operator==(const ListItem & comparable){
return (name == ((UserItem *)&comparable)->name);
}
- virtual bool compareTo(const std::string & comparable){
+ virtual bool equals(Util::ReferenceCount<Gui::ListItem> comparable){
+ return (name == comparable.convert<UserItem>()->name);
+ }
+
+ bool equals(const std::string & comparable){
return (name == comparable);
}
+ virtual int compareTo(Util::ReferenceCount<Gui::ListItem> comparable){
+ return name.compare(comparable.convert<UserItem>()->name);
+ }
+
void act(){
}
void draw(const Font & font, const Graphics::Bitmap & work){
if (client->getName() == name){
font.printf(0, 0, Graphics::makeColor(0,255,255), work, name, 0);
} else {
font.printf(0, 0, Graphics::makeColor(255,255,255), work, name, 0);
}
}
private:
const std::string name;
const Util::ReferenceCount<Client> client;
};
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::NoSuchTab & ex){
}
}
return chat->getCurrentTab().convert<ChannelTab>();
}
void ChatInterface::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->localCommand(command);
} else {
convertTab(chat)->addMessage(chat->getClient()->getName(), text);
chat->getClient()->sendMessage(text);
chat->localNotify(text);
}
chat->getInputBox().clear();
}
}
ChatInterface::ChatInterface(const std::string & host, int port, const std::string & username):
host(host),
widthRatio(.8),
heightRatio(.95),
width(0),
height(0),
checkWidth(Configuration::getScreenWidth()),
checkHeight(Configuration::getScreenHeight()),
serverTab(Util::ReferenceCount<Gui::TabItem>(new ChannelTab(host))){
client = Util::ReferenceCount< Client >(new Client(host, port));
client->connect(username);
// Setup window size and chat list
updateDimensions();
// Add server tab
chatBox.add(serverTab);
}
ChatInterface::~ChatInterface(){
}
void ChatInterface::act(){
updateDimensions();
// Default size of fonts
const int size = height * (1 - (heightRatio + .01));
// Size is important
const Font & font = Font::getDefaultFont(size, size);
processRemoteCommands();
// Check user list
updateUserList();
chatBox.act(font);
inputBox.act(font);
listBox.act(font);
}
void ChatInterface::draw(const Graphics::Bitmap & work){
checkWidth = work.getWidth();
checkHeight = work.getHeight();
if (width == checkWidth && height == checkHeight){
const int size = height * (1 - (heightRatio + .01));
const Font & font = Font::getDefaultFont(size, size);
chatBox.draw(font, work);
inputBox.draw(font, work);
listBox.draw(font, work);
}
}
void ChatInterface::nextChannel(){
chatBox.next();
const std::string & name = chatBox.getCurrent()->getName();
if (name == host){
client->setMessagesDisabled(true);
listBox.clear();
} else {
client->setMessagesDisabled(false);
client->setChannel(client->getChannelIndex(name));
updateUserList();
}
}
void ChatInterface::previousChannel(){
chatBox.previous();
const std::string & name = chatBox.getCurrent()->getName();
if (chatBox.getCurrent()->getName() == host){
client->setMessagesDisabled(true);
listBox.clear();
} else {
client->setMessagesDisabled(false);
client->setChannel(client->getChannelIndex(name));
updateUserList();
}
}
void ChatInterface::gotoChannel(const std::string & channel){
chatBox.gotoTabByName(channel);
const std::string & name = chatBox.getCurrent()->getName();
if (chatBox.getCurrent()->getName() == host){
client->setMessagesDisabled(true);
listBox.clear();
} else {
client->setMessagesDisabled(false);
client->setChannel(client->getChannelIndex(name));
updateUserList();
}
}
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::addMessageToTab(const std::string & message){
convertTab(this)->addMessage(message);
}
void ChatInterface::addMessageToTab(const std::string & name, const std::string & message){
convertTab(this)->addMessage(name, message);
}
void ChatInterface::updateDimensions(){
if (width == checkWidth && height == checkHeight){
return;
}
width = checkWidth;
height = checkHeight;
chatBox.transforms.setRadius(15);
Gui::ColorInfo colors;
colors.body = Graphics::makeColor(255,255,255);
colors.bodyAlpha = 128;
colors.border = Graphics::makeColor(0,0,255);
colors.borderAlpha = 255;
// chat panel widthRatio% heightRatio%
chatBox.location.setPosition(Gui::AbsolutePoint(0, 0));
chatBox.location.setDimensions(width * widthRatio, height * heightRatio);
chatBox.colors = colors;
// 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);
inputBox.colors = colors;
// Set the location of user list width * widthRatio and height
const int listStart = width * widthRatio + .01;
listBox.transforms.setRadius(15);
listBox.location.setPosition(Gui::AbsolutePoint(listStart, 1));
listBox.location.setDimensions(width - listStart, height-2);
listBox.colors = colors;
}
void ChatInterface::remoteNotify(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)->localNotify(message);
}
}
void ChatInterface::processRemoteCommands(){
while (client->hasCommands()){
::Network::IRC::Command command = client->nextCommand();
const std::vector<std::string> & params = command.getParameters();
- //Global::debug(0) << "Got message: " << command.getSendable() << std::endl;
+ if (params.size() > 0){
+ 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 (channel == client->getName()){
// Private message to user (not channel)
convertTab(this, channel)->addMessage("\""+command.getOwner() + "\" whispered: " + params.at(1));
} else {
// Username and message
convertTab(this, channel)->addMessage(command.getOwner(), params.at(1));
}
// notify
remoteNotify(params.at(1));
} else if (command.getType() == ::Network::IRC::Command::Notice){
// Username and message
serverTab.convert<ChannelTab>()->addMessage(command.getOwner(), params.at(1));
// notify
remoteNotify(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::Nick){
+ // Check if user is the owner
+ if (command.getOwner() == client->getName()){
+ convertTab(this)->addMessage("*** Nick changed to " + params.at(0) + ".");
+
+ } else {
+ convertTab(this)->addMessage("*** " + command.getOwner() + " is now known as " + params.at(0) + ".");
+ }
+ changeUserName(command.getOwner(), params.at(0));
} 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))));
- gotoChannel(params.at(0));
+ // Check if user is the owner otherwise display to that channel
+ if (command.getOwner() == client->getName()){
+ serverTab.convert<ChannelTab>()->addMessage("*** You have joined the channel " + params.at(0) + ".");
+ chatBox.add(Util::ReferenceCount<Gui::TabItem>(new ChannelTab(params.at(0))));
+ gotoChannel(params.at(0));
+ } else {
+ convertTab(this, params.at(0))->addMessage("*** " + command.getOwner() + " has joined the channel.");
+ listBox.add(Util::ReferenceCount<Gui::ListItem>(new UserItem(command.getOwner(), client)));
+ }
+ } else if (command.getType() == ::Network::IRC::Command::Part){
+ // Check if user is the owner otherwise display to that channel
+ if (command.getOwner() == client->getName()){
+ serverTab.convert<ChannelTab>()->addMessage("*** You have parted the channel " + params.at(0) + ".");
+ } else {
+ convertTab(this, params.at(0))->addMessage("*** " + command.getOwner() + " has parted the channel.");
+ removeUser(command.getOwner());
+ }
} 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()){
const std::vector<std::string> & ctcp = command.getCtcp();
+ if (ctcp.size() > 0){
+ //Global::debug(0) << "Got CTCP: " << command.getCTCPSendable() << std::endl;
+ }
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){
}
}
// Pass out the command to listeners
for (std::vector<Message::EventInterface *>::iterator i = subscribers.begin(); i != subscribers.end(); ++i){
(*i)->remoteCommand(command);
}
}
}
void ChatInterface::localNotify(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)->localNotify(message);
}
}
void ChatInterface::localCommand(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");
+ convertTab(this)->addMessage("* commands: help, nick, whisper, ping, join, part, 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) == "part"){
+ if (client->getChannel() != NULL){
+ chatBox.removeCurrent();
+ gotoChannel(host);
+ client->partChannel(client->getChannel()->getName());
+ }
} 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.");
}
// pass local commands out to listeners
for (std::vector<Message::EventInterface *>::iterator i = subscribers.begin(); i != subscribers.end(); ++i){
(*i)->localCommand(command);
}
}
static bool inList(const std::vector< Util::ReferenceCount<Gui::ListItem> > & list, const std::string & name){
for (std::vector< Util::ReferenceCount<Gui::ListItem> >::const_iterator i = list.begin(); i != list.end(); i++){
Util::ReferenceCount<UserItem> item = (*i).convert<UserItem>();
- if (item->compareTo(name)){
+ if (item->equals(name)){
return true;
}
}
return false;
}
void ChatInterface::updateUserList(){
const ChannelPointer channel = client->getChannel();
if (channel == NULL){
return;
}
const std::vector<std::string> & users = channel->getUsers();
if (listBox.getList().empty() && chatBox.getCurrent()->getName() != host){
// populate
for (std::vector<std::string>::const_iterator i = users.begin(); i != users.end(); i++){
listBox.add(Util::ReferenceCount<Gui::ListItem>(new UserItem(*i, client)));
}
} else if (chatBox.getCurrent()->getName() != host){
- // Update
- /*bool update = false;
- for (std::vector<std::string>::const_iterator i = users.begin(); i != users.end(); i++){
- update = !inList(listBox.getList(), *i);
- }*/
if (listBox.getList().size() != users.size()){
listBox.clear();
for (std::vector<std::string>::const_iterator i = users.begin(); i != users.end(); i++){
listBox.add(Util::ReferenceCount<Gui::ListItem>(new UserItem(*i, client)));
}
}
}
}
+void ChatInterface::removeUser(const std::string & name){
+ const std::vector< Util::ReferenceCount<Gui::ListItem> > & userlist = listBox.getList();
+ for (std::vector< Util::ReferenceCount<Gui::ListItem> >::const_iterator i = userlist.begin(); i != userlist.end(); i++){
+ Util::ReferenceCount<UserItem> user = (*i).convert<UserItem>();
+ if (user->equals(name)){
+ // remove him from list
+ listBox.remove(*i);
+ break;
+ }
+ }
+}
+
+void ChatInterface::changeUserName(const std::string & name, const std::string & newName){
+ const std::vector< Util::ReferenceCount<Gui::ListItem> > & userlist = listBox.getList();
+ for (std::vector< Util::ReferenceCount<Gui::ListItem> >::const_iterator i = userlist.begin(); i != userlist.end(); i++){
+ Util::ReferenceCount<UserItem> user = (*i).convert<UserItem>();
+ if (user->equals(name)){
+ // remove him from list
+ listBox.remove(*i);
+ listBox.add(Util::ReferenceCount<Gui::ListItem>(new UserItem(newName, client)));
+ break;
+ }
+ }
+}
+
}
}
diff --git a/util/network/irc.h b/util/network/irc.h
index 5142edc9..789bb133 100644
--- a/util/network/irc.h
+++ b/util/network/irc.h
@@ -1,392 +1,396 @@
#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 "util/gui/list.h"
#include <string>
#include <vector>
#include <queue>
#include <map>
namespace Network{
namespace IRC{
class Command{
public:
enum Type{
Unknown,
Pass,
Nick,
User,
Userhost,
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,
ReplyUserhost,
};
// 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 std::string getCTCPSendable() 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() const {
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(const std::string & name = "paintown-test");
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 void partChannel(const std::string &);
virtual inline ChannelPointer getChannel() const {
if (this->activeChannels.empty()){
return ChannelPointer(NULL);
}
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 &);
virtual inline void setMessagesDisabled(bool disabled){
this->disableMessages = disabled;
}
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;
bool disableMessages;
};
namespace Message{
class EventInterface{
public:
EventInterface();
virtual ~EventInterface();
// Notify by message from local user
virtual void localNotify(const std::string &);
// Notify by command from local user
virtual void localCommand(const std::vector<std::string> &);
// Notify by message from remote
virtual void remoteNotify(const std::string &);
// Notify by command from remote
virtual void remoteCommand(const Command &);
};
class HandlerInterface{
public:
HandlerInterface();
virtual ~HandlerInterface();
typedef void *(*NotifyCallback)(const std::string &);
virtual inline void subscribe(NotifyCallback subscriber){
this->callbacks.push_back(subscriber);
}
virtual inline void subscribe(EventInterface * subscriber){
this->subscribers.push_back(subscriber);
}
protected:
// Callbacks for events and messages
std::vector<NotifyCallback> callbacks;
std::vector<EventInterface *> subscribers;
};
class QueueInterface{
public:
QueueInterface();
virtual ~QueueInterface();
virtual void addMessage(const std::string &) = 0;
class FontWrapper{
public:
FontWrapper();
virtual ~FontWrapper();
virtual int getWidth(const std::string &)=0;
virtual int getHeight()=0;
};
virtual void processMessages(FontWrapper &, int width, int height);
protected:
std::queue<std::string> messages;
std::deque<std::string> buffer;
};
}
// Create a tabbed chatter to implement in games
class ChatInterface: public Message::HandlerInterface{
public:
ChatInterface(const std::string &, int port, const std::string &);
virtual ~ChatInterface();
void act();
void draw(const Graphics::Bitmap &);
void nextChannel();
void previousChannel();
void gotoChannel(const std::string &);
Util::ReferenceCount<Client> getClient();
Util::ReferenceCount<Gui::TabItem> getCurrentTab();
Util::ReferenceCount<Gui::TabItem> getTabByName(const std::string &);
void addMessageToTab(const std::string &);
void addMessageToTab(const std::string &, const std::string &);
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 updateDimensions();
void remoteNotify(const std::string &);
void processRemoteCommands();
static void submit(void *);
// Notifications and commands for submit
void localNotify(const std::string &);
void localCommand(const std::vector<std::string> &);
// Update user list
void updateUserList();
+ void removeUser(const std::string &);
+ void changeUserName(const std::string &, const std::string &);
Util::ReferenceCount<Client> client;
const std::string & host;
Gui::TabContainer chatBox;
Gui::LineEdit inputBox;
Gui::SimpleList listBox;
double widthRatio;
double heightRatio;
int width;
int height;
int checkWidth;
int checkHeight;
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:12 AM (2 w, 2 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
71003
Default Alt Text
(76 KB)
Attached To
Mode
R75 R-Tech1
Attached
Detach File
Event Timeline