📄 irc_connection_generic.cpp
字号:
/* $Id: irc_connection_generic.cpp,v 1.9 2004/01/03 23:02:09 mbn Exp $
**
** ClanLib Game SDK
** Copyright (C) 2003 The ClanLib Team
** For a total list of contributers see the file CREDITS.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "irc_connection_generic.h"
#include "API/Core/System/event_listener.h"
#include "API/Core/System/error.h"
#include "API/Core/System/log.h"
/////////////////////////////////////////////////////////////////////////////
// CL_IRCConnection_Generic construction:
CL_IRCConnection_Generic::CL_IRCConnection_Generic(const std::string &server, const std::string &port) :
sock(CL_Socket::tcp), signal_error(false), ref_count(0)
{
sock.connect(CL_IPAddress(server, port));
thread = CL_Thread(this);
thread.start();
}
CL_IRCConnection_Generic::~CL_IRCConnection_Generic()
{
thread.wait();
}
/////////////////////////////////////////////////////////////////////////////
// CL_IRCConnection_Generic attributes:
/////////////////////////////////////////////////////////////////////////////
// CL_IRCConnection_Generic operations:
void CL_IRCConnection_Generic::add_ref()
{
ref_count++;
}
void CL_IRCConnection_Generic::release_ref()
{
ref_count--;
if (ref_count == 0) delete this;
}
/////////////////////////////////////////////////////////////////////////////
// CL_IRCConnection_Generic implementation:
void CL_IRCConnection_Generic::run()
{
try
{
std::string last_line;
char buffer[512];
while (true)
{
CL_EventListener events;
events.add_trigger(sock.get_read_trigger());
events.add_trigger(&quit_trigger);
events.wait();
if (quit_trigger.get_flag()) break;
int received = sock.recv(buffer, 512);
if (received == 0) break;
int start = 0;
for (int i=0; i<received; i++)
{
if (buffer[i] == '\n')
{
last_line.append(buffer+start, i-start+1);
start = i+1;
CL_MutexSection mutex_lock(&mutex);
received_queue.push(last_line);
last_line = std::string();
}
}
last_line.append(buffer+start, received-start);
}
}
catch (CL_Error error)
{
signal_error = true;
error_message = error.message;
}
}
void CL_IRCConnection_Generic::keep_alive()
{
CL_MutexSection mutex_lock(&mutex);
while (!received_queue.empty())
{
std::string line = received_queue.front();
received_queue.pop();
// Parse line:
std::string prefix, command;
std::vector<std::string> args;
line = line.substr(0, line.length()-2); // cut off CR-LF
line.append(" "); // whitespace at end. Makes parsing easier.
CL_Log::log("debug", "%1", line);
// Find low level message escapes:
std::string::size_type pos = 0;
pos = 0;
while (pos != std::string::npos)
{
pos = line.find('\020', pos);
if (pos == std::string::npos || pos+1 == std::string::npos) break;
switch (line[pos+1])
{
case '\020':
line.replace( pos, 2, 1, '\020' );
break;
case '0':
line.replace( pos, 2, 1, '\0' );
break;
case 'n':
line.replace( pos, 2, 1, '\n' );
break;
case 'r':
line.replace( pos, 2, 1, '\r' );
break;
};
pos++;
}
// Split line prefix and command:
pos = 0;
std::string::size_type endpos;
if (line[0] == ':') // prefix
{
pos = line.find(" ", 1)+1;
prefix = line.substr(1, pos-2);
}
endpos = line.find(" ", pos);
command = line.substr(pos, endpos-pos);
pos = endpos+1;
while (pos != line.length())
{
if (line[pos] == ':')
{
args.push_back(line.substr(pos+1, line.length()-pos-2));
break;
}
endpos = line.find(" ", pos);
args.push_back(line.substr(pos, endpos-pos));
pos = endpos+1;
}
// Handle command:
int numeric_value = atoi(command.c_str());
if (numeric_value != 0)
{
sig_numeric_reply(prefix, numeric_value, args);
if (numeric_value == RPL_NAMREPLY)
{
const std::string &self = args[0];
const std::string &channel = args[2];
const std::string &users = args[3];
std::vector<std::string> nicks;
std::string::size_type pos = 0;
while (pos < users.length())
{
std::string::size_type new_pos = users.find(" ", pos);
if (new_pos == users.npos) new_pos = users.length();
nicks.push_back(users.substr(pos, new_pos-pos));
pos = new_pos+1;
}
sig_name_reply(self, channel, nicks);
}
continue;
}
sig_command_received(prefix, command, args);
int num_args = args.size();
if (command == "NICK" && num_args == 1) sig_nick(prefix, args[0]);
else if (command == "JOIN" && num_args == 1) sig_join(prefix, args[0]);
else if (command == "PART" && num_args >= 1)
{
if (num_args == 1) // No part reason
{
std::string empty;
sig_part(prefix, args[0], empty);
}
else // User made comment about why it left
{
sig_part(prefix, args[0], args[1]);
}
}
else if (command == "MODE")
{
std::vector<std::string> params;
for (int i=2; i<num_args; i++) params.push_back(args[i]);
sig_mode(prefix, args[0], args[1], params);
}
else if (command == "TOPIC" && num_args == 2) sig_topic(prefix, args[0], args[1]);
else if (command == "INVITE" && num_args == 2) sig_invite(prefix, args[0], args[1]);
else if (command == "KICK" && num_args == 2) sig_kick(prefix, args[0], args[1], "");
else if (command == "KICK" && num_args == 3) sig_kick(prefix, args[0], args[1], args[2]);
else if (command == "PRIVMSG" && num_args == 2)
{
if (args[1][0] == '\001') // ctcp
{
std::string line = args[1].substr(1, args[1].length()-2);
// Find ctcp level message escapes:
std::string::size_type pos = 0;
pos = 0;
while (pos != std::string::npos)
{
pos = line.find('\\', pos);
if (pos == std::string::npos || pos+1 == std::string::npos) break;
switch (line[pos+1])
{
case '\\':
line.replace( pos, 2, 1, '\\' );
break;
case 'a':
line.replace( pos, 2, 1, '\001' );
break;
};
pos++;
}
std::string command, data;
std::string::size_type data_pos = line.find(' ');
if (data_pos == std::string::npos)
{
command = line;
}
else
{
command = line.substr(0, data_pos);
data = line.substr(data_pos+1);
}
sig_privmsg_ctcp(prefix, args[0], command, data);
}
else
{
sig_privmsg(prefix, args[0], args[1]);
}
}
else if (command == "NOTICE" && num_args == 2)
{
if (args[1][0] == '\001') // ctcp
{
std::string line = args[1].substr(1, args[1].length()-2);
// Find ctcp level message escapes:
std::string::size_type pos = 0;
pos = 0;
while (pos != std::string::npos)
{
pos = line.find('\\', pos);
if (pos == std::string::npos || pos+1 == std::string::npos) break;
switch (line[pos+1])
{
case '\\':
line.replace( pos, 2, 1, '\\' );
break;
case 'a':
line.replace( pos, 2, 1, '\001' );
break;
};
pos++;
}
std::string command, data;
std::string::size_type data_pos = line.find(' ');
if (data_pos == std::string::npos)
{
command = line;
}
else
{
command = line.substr(0, data_pos);
data = line.substr(data_pos+1);
}
sig_notice_ctcp(prefix, args[0], command, data);
}
else
{
sig_notice(prefix, args[0], args[1]);
}
}
else if (command == "PING" && num_args == 1) sig_ping(args[0], "");
else if (command == "PING" && num_args == 2) sig_ping(args[0], args[1]);
else sig_unknown_command_received(prefix, command, args);
}
if (signal_error)
{
sig_socket_error(error_message);
signal_error = false;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -