mirror of https://github.com/JAJames/Jupiter.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1725 lines
50 KiB
1725 lines
50 KiB
11 years ago
|
/**
|
||
8 years ago
|
* Copyright (C) 2013-2017 Jessica James.
|
||
9 years ago
|
*
|
||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||
|
* purpose with or without fee is hereby granted, provided that the above
|
||
|
* copyright notice and this permission notice appear in all copies.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
|
*
|
||
9 years ago
|
* Written by Jessica James <jessica.aj@outlook.com>
|
||
11 years ago
|
*/
|
||
|
|
||
|
#include <cstring>
|
||
|
#include <cstdio>
|
||
|
#include <ctime>
|
||
|
#include "Jupiter.h"
|
||
|
#include "Functions.h"
|
||
|
#include "IRC_Client.h"
|
||
|
#include "TCPSocket.h"
|
||
|
#include "CString.h"
|
||
6 years ago
|
#include "String.hpp"
|
||
11 years ago
|
#include "Plugin.h"
|
||
|
#include "Base64.h"
|
||
|
|
||
|
//#define SHORT_IRC_MACROS
|
||
|
#include "IRC_Numerics.h"
|
||
|
|
||
|
#if defined _WIN32
|
||
|
#include <WinSock2.h>
|
||
|
#else // _WIN32
|
||
|
#include <unistd.h>
|
||
|
#endif // _WIN32
|
||
|
|
||
10 years ago
|
using namespace Jupiter::literals;
|
||
|
|
||
8 years ago
|
Jupiter::IRC::Client::Client(Jupiter::Config *in_primary_section, Jupiter::Config *in_secondary_section)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_primary_section = in_primary_section;
|
||
|
m_secondary_section = in_secondary_section;
|
||
9 years ago
|
|
||
8 years ago
|
if (m_primary_section != nullptr)
|
||
|
m_primary_section_name = m_primary_section->getName();
|
||
9 years ago
|
|
||
8 years ago
|
m_server_hostname = Jupiter::IRC::Client::readConfigValue("Hostname"_jrs, "irc.cncirc.net"_jrs);
|
||
11 years ago
|
|
||
8 years ago
|
m_log_file_name = Jupiter::IRC::Client::readConfigValue("LogFile"_jrs);
|
||
|
m_nickname = Jupiter::IRC::Client::readConfigValue("Nick"_jrs, "Jupiter"_jrs);
|
||
11 years ago
|
|
||
8 years ago
|
m_realname = Jupiter::IRC::Client::readConfigValue("RealName"_jrs, "Jupiter IRC Client"_jrs);
|
||
11 years ago
|
|
||
8 years ago
|
m_sasl_password = Jupiter::IRC::Client::readConfigValue("SASL.Password"_jrs);
|
||
|
if (m_sasl_password.isEmpty())
|
||
|
m_sasl_password = Jupiter::IRC::Client::readConfigValue("SASL.Pass"_jrs);
|
||
11 years ago
|
|
||
8 years ago
|
m_sasl_account = Jupiter::IRC::Client::readConfigValue("SASL.Account"_jrs);
|
||
|
if (m_sasl_account.isEmpty())
|
||
|
m_sasl_account = m_nickname;
|
||
11 years ago
|
|
||
8 years ago
|
m_auto_part_message = Jupiter::IRC::Client::readConfigValue("AutoPartMessage"_jrs);
|
||
11 years ago
|
|
||
8 years ago
|
m_ssl = Jupiter::IRC::Client::readConfigBool("SSL"_jrs);
|
||
|
m_ssl_certificate = Jupiter::IRC::Client::readConfigValue("Certificate"_jrs);
|
||
|
m_ssl_key = Jupiter::IRC::Client::readConfigValue("Key"_jrs);
|
||
|
if (m_ssl_certificate.isEmpty())
|
||
11 years ago
|
{
|
||
8 years ago
|
m_ssl_certificate = Jupiter::IRC::Client::readConfigValue("Cert"_jrs);
|
||
|
if (m_ssl_certificate.isEmpty())
|
||
|
m_ssl_certificate = m_ssl_key;
|
||
11 years ago
|
}
|
||
8 years ago
|
if (m_ssl_key.isEmpty())
|
||
|
m_ssl_key = m_ssl_certificate;
|
||
11 years ago
|
|
||
8 years ago
|
m_join_on_kick = Jupiter::IRC::Client::readConfigBool("AutoJoinOnKick"_jrs);
|
||
|
m_reconnect_delay = Jupiter::IRC::Client::readConfigInt("AutoReconnectDelay"_jrs);
|
||
|
m_max_reconnect_attempts = Jupiter::IRC::Client::readConfigInt("MaxReconnectAttempts"_jrs);
|
||
|
m_server_port = (unsigned short)Jupiter::IRC::Client::readConfigInt("Port"_jrs, m_ssl ? 994 : 194);
|
||
|
m_default_chan_type = Jupiter::IRC::Client::readConfigInt("Channel.Type"_jrs);
|
||
11 years ago
|
|
||
10 years ago
|
if (Jupiter::IRC::Client::readConfigBool("PrintOutput"_jrs, true))
|
||
8 years ago
|
m_output = stdout;
|
||
10 years ago
|
else
|
||
8 years ago
|
m_output = nullptr;
|
||
|
if (m_log_file_name.isNotEmpty())
|
||
|
m_log_file = fopen(m_log_file_name.c_str(), "a+b");
|
||
|
else m_log_file = nullptr;
|
||
11 years ago
|
|
||
8 years ago
|
if (m_ssl)
|
||
11 years ago
|
{
|
||
|
Jupiter::SecureTCPSocket *t = new Jupiter::SecureTCPSocket();
|
||
8 years ago
|
if (m_ssl_certificate.isNotEmpty())
|
||
|
t->setCertificate(m_ssl_certificate, m_ssl_key);
|
||
|
m_socket = t;
|
||
11 years ago
|
}
|
||
8 years ago
|
else m_socket = new Jupiter::TCPSocket();
|
||
11 years ago
|
|
||
8 years ago
|
m_connection_status = 0;
|
||
11 years ago
|
}
|
||
|
|
||
|
Jupiter::IRC::Client::~Client()
|
||
|
{
|
||
8 years ago
|
m_socket->close();
|
||
11 years ago
|
|
||
8 years ago
|
if (m_socket != nullptr)
|
||
|
delete m_socket;
|
||
11 years ago
|
|
||
8 years ago
|
if (m_log_file != nullptr)
|
||
|
fclose(m_log_file);
|
||
11 years ago
|
}
|
||
|
|
||
|
void Jupiter::IRC::Client::OnConnect()
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void Jupiter::IRC::Client::OnDisconnect()
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void Jupiter::IRC::Client::OnReconnectAttempt(bool)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnRaw(const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnNumeric(long int, const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnError(const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnChat(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnNotice(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnServerNotice(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnCTCP(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnAction(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnInvite(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnJoin(const Jupiter::ReadableString &, const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnPart(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnNick(const Jupiter::ReadableString &, const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnKick(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnQuit(const Jupiter::ReadableString &, const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::OnMode(const Jupiter::ReadableString &, const Jupiter::ReadableString &, const Jupiter::ReadableString &)
|
||
11 years ago
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::getConfigSection() const
|
||
11 years ago
|
{
|
||
8 years ago
|
if (m_primary_section != nullptr)
|
||
|
return m_primary_section_name;
|
||
9 years ago
|
|
||
|
return Jupiter::ReferenceString::empty;
|
||
|
}
|
||
|
|
||
8 years ago
|
Jupiter::Config *Jupiter::IRC::Client::getPrimaryConfigSection() const
|
||
9 years ago
|
{
|
||
8 years ago
|
return m_primary_section;
|
||
9 years ago
|
}
|
||
|
|
||
8 years ago
|
Jupiter::Config *Jupiter::IRC::Client::getSecondaryConfigSection() const
|
||
9 years ago
|
{
|
||
8 years ago
|
return m_secondary_section;
|
||
9 years ago
|
}
|
||
|
|
||
8 years ago
|
void Jupiter::IRC::Client::setPrimaryConfigSection(Jupiter::Config *in_primary_section)
|
||
9 years ago
|
{
|
||
8 years ago
|
m_primary_section = in_primary_section;
|
||
9 years ago
|
|
||
8 years ago
|
if (m_primary_section != nullptr)
|
||
|
m_primary_section_name = m_primary_section->getName();
|
||
9 years ago
|
else
|
||
8 years ago
|
m_primary_section_name.erase();
|
||
9 years ago
|
}
|
||
|
|
||
8 years ago
|
void Jupiter::IRC::Client::setSecondaryConfigSection(Jupiter::Config *in_secondary_section)
|
||
9 years ago
|
{
|
||
8 years ago
|
m_secondary_section = in_secondary_section;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::getLogFile() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_log_file_name;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::getPrefixes() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_prefixes;
|
||
11 years ago
|
}
|
||
|
|
||
10 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::getPrefixModes() const
|
||
|
{
|
||
8 years ago
|
return m_prefix_modes;
|
||
10 years ago
|
}
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::getNickname() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_nickname;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::getRealname() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_realname;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::getServerName() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_server_name;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::getServerHostname() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_server_hostname;
|
||
11 years ago
|
}
|
||
|
|
||
|
unsigned short Jupiter::IRC::Client::getServerPort() const
|
||
|
{
|
||
8 years ago
|
return m_server_port;
|
||
11 years ago
|
}
|
||
|
|
||
|
time_t Jupiter::IRC::Client::getReconnectDelay() const
|
||
|
{
|
||
8 years ago
|
return m_reconnect_delay;
|
||
11 years ago
|
}
|
||
|
|
||
|
time_t Jupiter::IRC::Client::getReconnectTime() const
|
||
|
{
|
||
8 years ago
|
return m_reconnect_time;
|
||
11 years ago
|
}
|
||
|
|
||
|
int Jupiter::IRC::Client::getReconnectAttempts() const
|
||
|
{
|
||
8 years ago
|
return m_reconnect_attempts;
|
||
11 years ago
|
}
|
||
|
|
||
|
int Jupiter::IRC::Client::getMaxReconnectAttempts() const
|
||
|
{
|
||
8 years ago
|
return m_max_reconnect_attempts;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
int Jupiter::IRC::Client::getDefaultChanType() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_default_chan_type;
|
||
11 years ago
|
}
|
||
|
|
||
|
FILE *Jupiter::IRC::Client::getPrintOutput() const
|
||
|
{
|
||
8 years ago
|
return m_output;
|
||
11 years ago
|
}
|
||
|
|
||
|
void Jupiter::IRC::Client::setPrintOutput(FILE *f)
|
||
|
{
|
||
8 years ago
|
m_output = f;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
inline Jupiter::ReferenceString getSender(const Jupiter::ReadableString &line)
|
||
11 years ago
|
{
|
||
11 years ago
|
return Jupiter::ReferenceString::getWord(line, 0, ":! ");
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
int Jupiter::IRC::Client::getAccessLevel(const Channel &in_channel, const Jupiter::ReadableString &in_nickname) const
|
||
|
{
|
||
|
char prefix = in_channel.getUserPrefix(in_nickname);
|
||
8 years ago
|
|
||
8 years ago
|
if (prefix != 0)
|
||
|
return static_cast<int>(m_prefixes.size() - m_prefixes.find(prefix));
|
||
8 years ago
|
|
||
|
return 0;
|
||
8 years ago
|
}
|
||
|
|
||
8 years ago
|
int Jupiter::IRC::Client::getAccessLevel(const Jupiter::ReadableString &in_channel, const Jupiter::ReadableString &in_nickname) const
|
||
11 years ago
|
{
|
||
8 years ago
|
Jupiter::IRC::Client::Channel *channel = m_channels.get(in_channel);
|
||
|
|
||
|
if (channel != nullptr)
|
||
8 years ago
|
return this->getAccessLevel(*channel, in_nickname);
|
||
8 years ago
|
|
||
11 years ago
|
return 0;
|
||
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::send(const Jupiter::ReadableString &rawMessage)
|
||
11 years ago
|
{
|
||
11 years ago
|
Jupiter::StringS out = rawMessage;
|
||
11 years ago
|
out += ENDL;
|
||
11 years ago
|
|
||
8 years ago
|
m_socket->send(out);
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
const Jupiter::IRC::Client::UserTableType &Jupiter::IRC::Client::getUsers() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_users;
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
size_t Jupiter::IRC::Client::getUserCount() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_users.size();
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
Jupiter::IRC::Client::User *Jupiter::IRC::Client::getUser(const Jupiter::ReadableString &in_nickname) const
|
||
|
{
|
||
|
return m_users.get(in_nickname);
|
||
|
}
|
||
|
|
||
|
const Jupiter::IRC::Client::ChannelTableType &Jupiter::IRC::Client::getChannels() const
|
||
|
{
|
||
|
return m_channels;
|
||
|
}
|
||
|
|
||
8 years ago
|
size_t Jupiter::IRC::Client::getChannelCount() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_channels.size();
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
Jupiter::IRC::Client::Channel *Jupiter::IRC::Client::getChannel(const Jupiter::ReadableString &in_channel) const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_channels.get(in_channel);
|
||
11 years ago
|
}
|
||
|
|
||
|
bool Jupiter::IRC::Client::isAutoReconnect() const
|
||
|
{
|
||
8 years ago
|
return m_max_reconnect_attempts != 0;
|
||
11 years ago
|
}
|
||
|
|
||
|
void Jupiter::IRC::Client::setAutoReconnect(int val)
|
||
|
{
|
||
8 years ago
|
m_max_reconnect_attempts = val;
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
void Jupiter::IRC::Client::joinChannel(const Jupiter::ReadableString &in_channel)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_socket->send(Jupiter::StringS::Format("JOIN %.*s" ENDL, in_channel.size(), in_channel.ptr()));
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
void Jupiter::IRC::Client::joinChannel(const Jupiter::ReadableString &in_channel, const Jupiter::ReadableString &in_password)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_socket->send(Jupiter::StringS::Format("JOIN %.*s %.*s" ENDL, in_channel.size(), in_channel.ptr(), in_password.size(), in_password.ptr()));
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
void Jupiter::IRC::Client::partChannel(const Jupiter::ReadableString &in_channel)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_socket->send(Jupiter::StringS::Format("PART %.*s" ENDL, in_channel.size(), in_channel.ptr()));
|
||
|
|
||
|
m_channels.get(in_channel)->setType(-2);
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
void Jupiter::IRC::Client::partChannel(const Jupiter::ReadableString &in_channel, const Jupiter::ReadableString &in_message)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_socket->send(Jupiter::StringS::Format("PART %.*s :%.*s" ENDL, in_channel.size(), in_channel.ptr(), in_message.size(), in_message.ptr()));
|
||
|
|
||
|
m_channels.get(in_channel)->setType(-2);
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::sendMessage(const Jupiter::ReadableString &dest, const Jupiter::ReadableString &message)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_socket->send(Jupiter::StringS::Format("PRIVMSG %.*s :%.*s" ENDL, dest.size(), dest.ptr(), message.size(), message.ptr()));
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::sendNotice(const Jupiter::ReadableString &dest, const Jupiter::ReadableString &message)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_socket->send(Jupiter::StringS::Format("NOTICE %.*s :%.*s" ENDL, dest.size(), dest.ptr(), message.size(), message.ptr()));
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
size_t Jupiter::IRC::Client::messageChannels(int type, const Jupiter::ReadableString &message)
|
||
11 years ago
|
{
|
||
8 years ago
|
auto message_channel_callback = [this, type, &message](ChannelTableType::Bucket::Entry &in_entry)
|
||
11 years ago
|
{
|
||
8 years ago
|
if (in_entry.value.getType() == type)
|
||
|
this->sendMessage(in_entry.value.getName(), message);
|
||
|
};
|
||
|
|
||
|
m_channels.callback(message_channel_callback);
|
||
|
|
||
|
return m_channels.size();
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
size_t Jupiter::IRC::Client::messageChannels(const Jupiter::ReadableString &message)
|
||
11 years ago
|
{
|
||
8 years ago
|
auto message_channel_callback = [this, &message](ChannelTableType::Bucket::Entry &in_entry)
|
||
11 years ago
|
{
|
||
8 years ago
|
this->sendMessage(in_entry.value.getName(), message);
|
||
|
};
|
||
|
|
||
|
m_channels.callback(message_channel_callback);
|
||
|
|
||
|
return m_channels.size();
|
||
11 years ago
|
}
|
||
|
|
||
9 years ago
|
int Jupiter::IRC::Client::process_line(const Jupiter::ReadableString &line)
|
||
11 years ago
|
{
|
||
9 years ago
|
if (line.isNotEmpty())
|
||
11 years ago
|
{
|
||
9 years ago
|
Jupiter::IRC::Client::writeToLogs(line);
|
||
8 years ago
|
if (m_output != nullptr)
|
||
|
line.println(m_output);
|
||
9 years ago
|
|
||
|
Jupiter::ReferenceString w1 = Jupiter::ReferenceString::getWord(line, 0, WHITESPACE);
|
||
|
if (w1.isNotEmpty())
|
||
11 years ago
|
{
|
||
9 years ago
|
Jupiter::ReferenceString w2 = Jupiter::ReferenceString::getWord(line, 1, WHITESPACE);
|
||
|
int numeric = w2.asInt(10);
|
||
|
if (w1[0] == ':') //Messages
|
||
11 years ago
|
{
|
||
9 years ago
|
if (w2.isNotEmpty())
|
||
11 years ago
|
{
|
||
9 years ago
|
switch (numeric) // Numerics that don't rely on a specific connectionStatus.
|
||
11 years ago
|
{
|
||
8 years ago
|
case Reply::BOUNCE: // 010
|
||
9 years ago
|
{
|
||
|
Jupiter::ReferenceString portToken = Jupiter::ReferenceString::getWord(line, 4, " ");
|
||
|
unsigned short port;
|
||
|
if (portToken[0] == '+') // This is most likely not used anywhere.
|
||
11 years ago
|
{
|
||
9 years ago
|
port = (unsigned short)portToken.asUnsignedInt(10);
|
||
8 years ago
|
if (m_ssl == false)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_ssl = true;
|
||
|
delete m_socket;
|
||
|
m_socket = new Jupiter::SecureTCPSocket();
|
||
9 years ago
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
port = (unsigned short)portToken.asUnsignedInt(10);
|
||
8 years ago
|
if (m_ssl == true)
|
||
9 years ago
|
{
|
||
8 years ago
|
m_ssl = false;
|
||
|
delete m_socket;
|
||
|
m_socket = new Jupiter::TCPSocket();
|
||
9 years ago
|
}
|
||
|
}
|
||
|
if (port != 0) // Don't default -- could be non-compliant input.
|
||
|
{
|
||
8 years ago
|
m_server_hostname = Jupiter::ReferenceString::getWord(line, 3, WHITESPACE);
|
||
|
m_server_port = port;
|
||
9 years ago
|
puts("Reconnecting due to old bounce.");
|
||
|
this->reconnect();
|
||
|
}
|
||
|
else puts("Error: Failed to parse bounce token.");
|
||
|
}
|
||
|
break;
|
||
|
} // numeric switch
|
||
8 years ago
|
switch (m_connection_status)
|
||
9 years ago
|
{
|
||
|
case 1: // Socket established -- attempting STARTTLS
|
||
|
switch (numeric)
|
||
|
{
|
||
8 years ago
|
case Reply::BOUNCEOLD: // 005
|
||
9 years ago
|
if (line.matchi("*:Try server *, port *"))
|
||
11 years ago
|
{
|
||
9 years ago
|
Jupiter::ReferenceString portToken = Jupiter::ReferenceString::getWord(line, 6, " ");
|
||
|
unsigned short bouncePort = (unsigned short)Jupiter::ReferenceString::getWord(line, 6, " ").asInt(10);
|
||
|
|
||
|
if (portToken[0] == '+') // This is almost certainly not used anywhere.
|
||
11 years ago
|
{
|
||
9 years ago
|
bouncePort = (unsigned short)portToken.asInt(10);
|
||
8 years ago
|
if (m_ssl == false)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_ssl = true;
|
||
|
delete m_socket;
|
||
|
m_socket = new Jupiter::SecureTCPSocket();
|
||
11 years ago
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
9 years ago
|
bouncePort = (unsigned short)portToken.asInt(10);
|
||
8 years ago
|
if (m_ssl == true)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_ssl = false;
|
||
|
delete m_socket;
|
||
|
m_socket = new Jupiter::TCPSocket();
|
||
11 years ago
|
}
|
||
|
}
|
||
9 years ago
|
if (bouncePort != 0)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_server_hostname = Jupiter::ReferenceString::getWord(line, 4, " ");
|
||
|
m_server_hostname.truncate(1); // trailing comma
|
||
|
m_server_port = bouncePort;
|
||
11 years ago
|
puts("Reconnecting due to old bounce.");
|
||
|
this->reconnect();
|
||
|
}
|
||
9 years ago
|
else puts("Error: Failed to parse old bounce token.");
|
||
11 years ago
|
}
|
||
9 years ago
|
break;
|
||
8 years ago
|
|
||
8 years ago
|
case Error::UNKNOWNCOMMAND: // 421
|
||
9 years ago
|
{
|
||
|
Jupiter::ReferenceString command = Jupiter::ReferenceString::getWord(line, 2, " ");
|
||
|
if (command.equalsi("STARTTLS")) // Server doesn't support STARTTLS
|
||
8 years ago
|
Client::startCAP();
|
||
9 years ago
|
}
|
||
|
break;
|
||
8 years ago
|
|
||
8 years ago
|
case Reply::STARTTLS: // 670
|
||
9 years ago
|
{
|
||
8 years ago
|
Jupiter::SecureTCPSocket *t = new Jupiter::SecureTCPSocket(std::move(*m_socket));
|
||
|
delete m_socket;
|
||
|
m_socket = t;
|
||
|
m_ssl = true;
|
||
9 years ago
|
// toggle blocking to prevent error
|
||
8 years ago
|
if (m_ssl_certificate.isNotEmpty())
|
||
|
t->setCertificate(m_ssl_certificate, m_ssl_key);
|
||
9 years ago
|
|
||
|
bool goodSSL;
|
||
|
if (t->getBlockingMode() == false)
|
||
|
{
|
||
|
t->setBlocking(true);
|
||
|
goodSSL = t->initSSL();
|
||
|
t->setBlocking(false);
|
||
|
}
|
||
|
else goodSSL = t->initSSL();
|
||
|
|
||
8 years ago
|
if (goodSSL)
|
||
|
Client::startCAP();
|
||
9 years ago
|
else
|
||
|
{
|
||
|
// Something went wrong. Kill the socket.
|
||
|
t->close();
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
8 years ago
|
|
||
8 years ago
|
case Error::STARTTLS: // 691
|
||
8 years ago
|
Client::startCAP();
|
||
9 years ago
|
break;
|
||
8 years ago
|
|
||
9 years ago
|
default:
|
||
|
break;
|
||
|
} // numeric switch
|
||
|
break;
|
||
|
|
||
|
case 2: // Capability negotiation
|
||
|
switch (numeric)
|
||
|
{
|
||
|
case 0:
|
||
|
if (w2.equalsi("CAP"))
|
||
|
{
|
||
|
Jupiter::ReferenceString w4 = Jupiter::ReferenceString::getWord(line, 3, WHITESPACE);
|
||
|
if (w4.equals("LS"))
|
||
11 years ago
|
{
|
||
9 years ago
|
Jupiter::ReferenceString listParams = Jupiter::ReferenceString::gotoWord(line, 4, WHITESPACE);
|
||
|
if (listParams[0] == ':') listParams.shiftRight(1);
|
||
|
unsigned int len = listParams.wordCount(WHITESPACE);
|
||
|
Jupiter::ReferenceString curr;
|
||
|
Jupiter::StringL req = "CAP REQ :";
|
||
|
bool sasl = false;
|
||
|
for (unsigned int i = 0; i < len; i++)
|
||
11 years ago
|
{
|
||
9 years ago
|
curr = listParams.getWord(i, WHITESPACE);
|
||
|
if (curr.equalsi("multi-prefix")) req += "multi-prefix ";
|
||
|
else if (curr.equalsi("userhost-in-names")) req += "userhost-in-names ";
|
||
|
else if (curr.equalsi("sasl"))
|
||
11 years ago
|
{
|
||
8 years ago
|
if (m_sasl_password.isNotEmpty())
|
||
11 years ago
|
{
|
||
8 years ago
|
req += "sasl "_jrs;
|
||
9 years ago
|
sasl = true;
|
||
11 years ago
|
}
|
||
|
}
|
||
9 years ago
|
// else; // We don't know what this is!
|
||
11 years ago
|
}
|
||
9 years ago
|
if (req.size() > 9)
|
||
11 years ago
|
{
|
||
9 years ago
|
req -= 1; // Trim off the extra space byte.
|
||
|
req += ENDL;
|
||
8 years ago
|
m_socket->send(req);
|
||
9 years ago
|
if (sasl)
|
||
8 years ago
|
m_socket->send("AUTHENTICATE PLAIN"_jrs ENDL);
|
||
11 years ago
|
}
|
||
9 years ago
|
if (!sasl)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_socket->send("CAP END"_jrs ENDL);
|
||
|
Client::registerClient();
|
||
11 years ago
|
}
|
||
9 years ago
|
}
|
||
|
}
|
||
|
break;
|
||
8 years ago
|
case Error::UNKNOWNCOMMAND: // 421
|
||
9 years ago
|
if (w2.equalsi("CAP")) // Server doesn't support CAP
|
||
|
{
|
||
8 years ago
|
Client::registerClient();
|
||
9 years ago
|
}
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
} // numeric switch
|
||
|
break;
|
||
11 years ago
|
|
||
9 years ago
|
case 3: // Registration sent, but not verified.
|
||
|
{
|
||
8 years ago
|
bool erroneous_nickname = false;
|
||
9 years ago
|
switch (numeric)
|
||
|
{
|
||
|
// We'll take any of these 4, just in-case any of them are missing. In general, this will trigger on 001.
|
||
8 years ago
|
case Reply::MYINFO: // 004
|
||
8 years ago
|
m_server_name = Jupiter::ReferenceString::getWord(line, 3, " ");
|
||
8 years ago
|
case Reply::WELCOME: // 001
|
||
|
case Reply::YOURHOST: // 002
|
||
|
case Reply::CREATED: // 003
|
||
8 years ago
|
m_connection_status = 4;
|
||
9 years ago
|
break;
|
||
|
|
||
|
// You have a bad nickname! Try the alt.
|
||
8 years ago
|
//case Error::NONICKNAMEGIVEN: // 431 -- Not consistently usable due to lack of command field.
|
||
|
case Error::ERRONEOUSNICKNAME: // 432
|
||
8 years ago
|
erroneous_nickname = true;
|
||
8 years ago
|
case Error::NICKNAMEINUSE: // 433
|
||
|
case Error::NICKCOLLISION: // 436
|
||
|
case Error::BANNICKCHANGE: // 437 -- Note: This conflicts with another token.
|
||
8 years ago
|
const Jupiter::ReadableString &altNick = Jupiter::IRC::Client::readConfigValue("AltNick"_jrs);
|
||
9 years ago
|
const Jupiter::ReadableString &configNick = Jupiter::IRC::Client::readConfigValue("Nick"_jrs, "Jupiter"_jrs);
|
||
8 years ago
|
|
||
8 years ago
|
if (altNick.isNotEmpty() && m_nickname.equalsi(altNick)) // The alternate nick failed.
|
||
9 years ago
|
{
|
||
8 years ago
|
m_nickname = configNick;
|
||
|
m_nickname += "1";
|
||
8 years ago
|
|
||
8 years ago
|
m_socket->send("NICK "_jrs + m_nickname + ENDL);
|
||
9 years ago
|
}
|
||
8 years ago
|
else if (m_nickname.equalsi(configNick)) // The config nick failed
|
||
9 years ago
|
{
|
||
8 years ago
|
if (altNick.isEmpty())
|
||
|
{
|
||
|
if (erroneous_nickname)
|
||
|
break; // If this nick is invalid, adding numbers won't help.
|
||
|
|
||
8 years ago
|
m_nickname += '1';
|
||
8 years ago
|
}
|
||
|
else
|
||
8 years ago
|
m_nickname = altNick;
|
||
8 years ago
|
|
||
8 years ago
|
m_socket->send("NICK "_jrs + m_nickname + ENDL);
|
||
9 years ago
|
}
|
||
|
// Note: Add a series of contains() functions to String_Type.
|
||
|
else
|
||
11 years ago
|
{
|
||
8 years ago
|
if (erroneous_nickname == false) // If this nick is invalid, adding numbers won't help.
|
||
11 years ago
|
{
|
||
8 years ago
|
if (m_nickname.size() > configNick.size())
|
||
11 years ago
|
{
|
||
8 years ago
|
int n = Jupiter_strtoi_nospace_s(m_nickname.ptr() + configNick.size(), m_nickname.size() - configNick.size(), 10);
|
||
|
m_nickname.format("%.*s%d", configNick.size(), configNick.ptr(), n + 1);
|
||
8 years ago
|
|
||
8 years ago
|
m_socket->send("NICK "_jrs + m_nickname + ENDL);
|
||
11 years ago
|
}
|
||
11 years ago
|
else
|
||
11 years ago
|
{
|
||
9 years ago
|
// Something strange is going on -- did somebody rehash?
|
||
|
// This can be somewhat edgy -- this will only trigger if someone rehashes AND the new nickname is shorter.
|
||
|
// However, it won't be fatal even if the new nickname's length is >= the old.
|
||
8 years ago
|
m_nickname = configNick;
|
||
|
m_socket->send("NICK "_jrs + m_nickname + ENDL);
|
||
11 years ago
|
}
|
||
9 years ago
|
}
|
||
|
else
|
||
|
{
|
||
|
// Disconnect and don't try again.
|
||
|
// Consider passing this to plugins so that they can figure it out (i.e: a plugin could display a prompt and ask for input).
|
||
11 years ago
|
}
|
||
|
}
|
||
9 years ago
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
11 years ago
|
|
||
9 years ago
|
case 4: // Registration verified, but connection process in progress.
|
||
|
switch (numeric)
|
||
|
{
|
||
8 years ago
|
case Reply::ISUPPORT: // 005
|
||
9 years ago
|
{
|
||
|
size_t pos = line.find("PREFIX=("_jrs);
|
||
|
if (pos != Jupiter::INVALID_INDEX)
|
||
|
{
|
||
|
Jupiter::ReferenceString ref = Jupiter::ReferenceString::substring(line, pos + 8);
|
||
8 years ago
|
m_prefix_modes = Jupiter::ReferenceString::getWord(ref, 0, ")");
|
||
9 years ago
|
ref.shiftRight(ref.find(')') + 1);
|
||
8 years ago
|
m_prefixes = Jupiter::ReferenceString::getWord(ref, 0, " " ENDL);
|
||
9 years ago
|
}
|
||
|
pos = line.find("CHANMODES="_jrs);
|
||
|
if (pos != Jupiter::INVALID_INDEX)
|
||
|
{
|
||
|
Jupiter::ReferenceString ref = Jupiter::ReferenceString::substring(line, pos + 10);
|
||
|
ref = ref.getWord(0, " ");
|
||
|
size_t pos2 = ref.find(',', 0);
|
||
|
if (pos != INVALID_INDEX)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_modeA = ref.getWord(0, ", ");
|
||
9 years ago
|
ref.shiftRight(pos + 1);
|
||
|
pos2 = ref.find(',', 0);
|
||
|
if (pos != INVALID_INDEX)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_modeB = ref.getWord(0, ", ");
|
||
9 years ago
|
ref.shiftRight(pos + 1);
|
||
|
pos2 = ref.find(',', 0);
|
||
11 years ago
|
if (pos != INVALID_INDEX)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_modeC = ref.getWord(0, ", ");
|
||
11 years ago
|
ref.shiftRight(pos + 1);
|
||
8 years ago
|
m_modeD = ref.getWord(0, ", ");
|
||
11 years ago
|
}
|
||
|
}
|
||
|
}
|
||
9 years ago
|
}
|
||
|
pos = line.find("CHANTYPES="_jrs);
|
||
|
if (pos != Jupiter::INVALID_INDEX)
|
||
|
{
|
||
|
Jupiter::ReferenceString ref = Jupiter::ReferenceString::substring(line, pos + 10);
|
||
8 years ago
|
m_chan_types = ref.getWord(0, " ");
|
||
9 years ago
|
}
|
||
|
}
|
||
|
break;
|
||
8 years ago
|
case Reply::LUSERCLIENT: // 251
|
||
9 years ago
|
{
|
||
|
Jupiter::StringL key = "RawData.";
|
||
|
size_t offset;
|
||
11 years ago
|
|
||
9 years ago
|
unsigned int i = 1;
|
||
|
Jupiter::ReferenceString value;
|
||
|
auto config_loop_condition = [&]
|
||
|
{
|
||
|
offset = key.aformat("%u", i);
|
||
|
value = Jupiter::IRC::Client::readConfigValue(key);
|
||
|
return !value.isEmpty();
|
||
|
};
|
||
|
while (config_loop_condition())
|
||
|
{
|
||
|
key.truncate(offset);
|
||
|
Jupiter::IRC::Client::send(value);
|
||
|
i++;
|
||
|
}
|
||
8 years ago
|
|
||
|
auto auto_join_channels_callback = [this](Jupiter::Config::SectionHashTable::Bucket::Entry &in_entry)
|
||
9 years ago
|
{
|
||
8 years ago
|
if (in_entry.value.get<bool>("AutoJoin"_jrs, false))
|
||
|
this->joinChannel(in_entry.value.getName());
|
||
|
};
|
||
|
|
||
|
Jupiter::Config *config = m_primary_section->getSection("Channels"_jrs);
|
||
|
|
||
|
if (config != nullptr)
|
||
|
config->getSections().callback(auto_join_channels_callback);
|
||
|
|
||
|
config = m_secondary_section->getSection("Channels"_jrs);
|
||
|
|
||
|
if (config != nullptr)
|
||
|
config->getSections().callback(auto_join_channels_callback);
|
||
11 years ago
|
|
||
8 years ago
|
m_connection_status = 5;
|
||
|
m_reconnect_attempts = 0;
|
||
9 years ago
|
this->OnConnect();
|
||
|
for (i = 0; i < Jupiter::plugins->size(); i++) Jupiter::plugins->get(i)->OnConnect(this);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
11 years ago
|
|
||
9 years ago
|
default: // Post-registration.
|
||
|
if (w2.equalsi("PRIVMSG"))
|
||
|
{
|
||
|
Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(line, 2, WHITESPACE);
|
||
|
if (chan.isNotEmpty())
|
||
|
{
|
||
|
Jupiter::ReferenceString nick = getSender(line);
|
||
|
if (nick.isNotEmpty())
|
||
11 years ago
|
{
|
||
9 years ago
|
Jupiter::ReferenceString premessage = Jupiter::ReferenceString::substring(line, line.find(':', 1) + 1);
|
||
|
if (premessage[0] == '\001') //CTCP (ACTIONs are included)
|
||
11 years ago
|
{
|
||
9 years ago
|
Jupiter::ReferenceString rawmessage(premessage.ptr() + 1, premessage.size() - 1);
|
||
|
Jupiter::ReferenceString command = rawmessage.getWord(0, WHITESPACE);
|
||
|
if (command[command.size() - 1] == IRC::CTCP) command.truncate(1);
|
||
|
Jupiter::ReferenceString message = rawmessage.substring(rawmessage.find(' ') + 1, rawmessage.find(IRC::CTCP));
|
||
|
if (message[message.size() - 1] == IRC::CTCP) message.truncate(1);
|
||
11 years ago
|
|
||
9 years ago
|
if (command.equals("ACTION"))
|
||
11 years ago
|
{
|
||
9 years ago
|
this->OnAction(chan, nick, message);
|
||
11 years ago
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
9 years ago
|
Jupiter::plugins->get(i)->OnAction(this, chan, nick, message);
|
||
11 years ago
|
}
|
||
|
else
|
||
|
{
|
||
9 years ago
|
Jupiter::StringL response = "NOTICE ";
|
||
|
response += nick;
|
||
|
response += " :" IRCCTCP;
|
||
|
response += command;
|
||
|
response += ' ';
|
||
|
if (command.equals("PING")) response += message;
|
||
|
else if (command.equals("VERSION")) response += Jupiter::version;
|
||
|
else if (command.equals("FINGER")) response += "Oh, yeah, a little to the left.";
|
||
|
else if (command.equals("SOURCE")) response += "https://github.com/JAJames/Jupiter";
|
||
|
else if (command.equals("USERINFO")) response += "Hey, I'm Jupiter! If you have questions, ask Agent! (irc.cncirc.net)";
|
||
|
else if (command.equals("CLIENTINFO")) response += "I'll tell you what I don't know: This command!";
|
||
|
else if (command.equals("TIME")) response += getTime();
|
||
|
else if (command.equals("ERRMSG")) response += message;
|
||
|
else
|
||
11 years ago
|
{
|
||
9 years ago
|
response = "NOTICE ";
|
||
|
response += nick;
|
||
|
response += " :" IRCCTCP "ERRMSG ";
|
||
|
response += command;
|
||
|
response += " :Query is unknown";
|
||
11 years ago
|
}
|
||
9 years ago
|
response += IRCCTCP ENDL;
|
||
8 years ago
|
m_socket->send(response);
|
||
9 years ago
|
this->OnCTCP(chan, nick, command, message);
|
||
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
|
Jupiter::plugins->get(i)->OnCTCP(this, chan, nick, message);
|
||
11 years ago
|
}
|
||
|
}
|
||
9 years ago
|
else
|
||
11 years ago
|
{
|
||
9 years ago
|
Jupiter::ReferenceString message = premessage;
|
||
|
this->OnChat(chan, nick, message);
|
||
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
|
Jupiter::plugins->get(i)->OnChat(this, chan, nick, message);
|
||
11 years ago
|
}
|
||
9 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (w2.equalsi("NOTICE"))
|
||
|
{
|
||
|
Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(line, 2, WHITESPACE);
|
||
|
if (chan.isNotEmpty())
|
||
|
{
|
||
|
size_t pos = line.find('!', 0);
|
||
|
auto message = Jupiter::ReferenceString::substring(line, line.find(':', 1) + 1, line.size());
|
||
|
if (pos < line.find(' '))
|
||
|
{
|
||
|
auto nick = Jupiter::ReferenceString::substring(line, 1, pos);
|
||
|
this->OnNotice(chan, nick, message);
|
||
11 years ago
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
9 years ago
|
Jupiter::plugins->get(i)->OnNotice(this, chan, nick, message);
|
||
11 years ago
|
}
|
||
9 years ago
|
else
|
||
11 years ago
|
{
|
||
9 years ago
|
auto sender = getSender(line);
|
||
|
if (sender.isNotEmpty())
|
||
11 years ago
|
{
|
||
9 years ago
|
this->OnServerNotice(chan, sender, message);
|
||
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
|
Jupiter::plugins->get(i)->OnServerNotice(this, chan, sender, message);
|
||
11 years ago
|
}
|
||
|
}
|
||
9 years ago
|
}
|
||
|
}
|
||
|
else if (w2.equalsi("NICK"))
|
||
|
{
|
||
|
auto nick = getSender(line);
|
||
|
Jupiter::ReferenceString newnick = Jupiter::ReferenceString::substring(line, line.find(' ', 1) + 1);
|
||
|
if (newnick.isNotEmpty() && newnick[0] == ':') newnick.shiftRight(1);
|
||
8 years ago
|
if (nick.equalsi(m_nickname))
|
||
9 years ago
|
{
|
||
8 years ago
|
m_nickname = newnick;
|
||
9 years ago
|
}
|
||
8 years ago
|
Jupiter::IRC::Client::User *user = Client::findUser(nick);
|
||
9 years ago
|
if (user != nullptr)
|
||
|
{
|
||
8 years ago
|
user->m_nickname = newnick;
|
||
9 years ago
|
this->OnNick(nick, newnick);
|
||
|
}
|
||
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
|
Jupiter::plugins->get(i)->OnNick(this, nick, newnick);
|
||
|
}
|
||
|
else if (w2.equalsi("JOIN"))
|
||
|
{
|
||
|
auto nick = getSender(line);
|
||
|
Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(line, 2, WHITESPACE);
|
||
8 years ago
|
|
||
|
if (chan[0] == ':')
|
||
|
chan.shiftRight(1);
|
||
|
|
||
|
Channel *channel = m_channels.get(chan);
|
||
|
|
||
|
if (m_nickname.equalsi(nick))
|
||
9 years ago
|
{
|
||
8 years ago
|
// TODO: Optimize by simply wiping channel data, rather than removing and re-adding
|
||
|
if (channel != nullptr)
|
||
|
Client::delChannel(channel->getName());
|
||
|
|
||
|
Client::addChannel(chan);
|
||
|
channel = m_channels.get(chan);
|
||
|
channel->m_adding_names = true;
|
||
|
|
||
9 years ago
|
if (channel->getType() < 0)
|
||
11 years ago
|
{
|
||
8 years ago
|
if (m_auto_part_message.isNotEmpty())
|
||
|
Jupiter::IRC::Client::partChannel(chan, m_auto_part_message);
|
||
9 years ago
|
else
|
||
|
Jupiter::IRC::Client::partChannel(chan);
|
||
|
}
|
||
|
}
|
||
8 years ago
|
else if (channel != nullptr)
|
||
|
channel->addUser(Client::findUserOrAdd(nick));
|
||
|
|
||
9 years ago
|
this->OnJoin(chan, nick);
|
||
8 years ago
|
|
||
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
|
Jupiter::plugins->get(i)->OnJoin(this, chan, nick);
|
||
9 years ago
|
}
|
||
|
else if (w2.equalsi("PART"))
|
||
|
{
|
||
|
auto nick = getSender(line);
|
||
|
if (nick.isNotEmpty())
|
||
|
{
|
||
|
Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(line, 2, WHITESPACE);
|
||
|
if (chan.isNotEmpty())
|
||
|
{
|
||
8 years ago
|
Channel *channel = m_channels.get(chan);
|
||
|
if (channel != nullptr)
|
||
11 years ago
|
{
|
||
8 years ago
|
Jupiter::IRC::Client::User *user = m_users.get(nick);
|
||
|
if (user != nullptr)
|
||
11 years ago
|
{
|
||
8 years ago
|
channel->delUser(nick);
|
||
9 years ago
|
Jupiter::ReferenceString reason;
|
||
|
size_t pos = line.find(':', 1);
|
||
8 years ago
|
|
||
9 years ago
|
if (pos != Jupiter::INVALID_INDEX)
|
||
|
reason = Jupiter::ReferenceString::substring(line, pos + 1);
|
||
8 years ago
|
|
||
9 years ago
|
this->OnPart(chan, nick, reason);
|
||
8 years ago
|
|
||
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
|
Jupiter::plugins->get(i)->OnPart(this, chan, nick, reason);
|
||
|
|
||
|
if (nick.equalsi(m_nickname))
|
||
|
Client::delChannel(chan);
|
||
|
|
||
|
if (user->getChannelCount() == 0)
|
||
|
m_users.remove(nick);
|
||
11 years ago
|
}
|
||
|
}
|
||
|
}
|
||
9 years ago
|
}
|
||
|
}
|
||
|
else if (w2.equalsi("KICK"))
|
||
|
{
|
||
|
Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(line, 2, WHITESPACE);
|
||
|
if (chan.isNotEmpty())
|
||
|
{
|
||
|
Jupiter::ReferenceString kicker = getSender(line);
|
||
|
if (kicker.isNotEmpty())
|
||
11 years ago
|
{
|
||
9 years ago
|
Jupiter::ReferenceString kicked = Jupiter::ReferenceString::getWord(line, 3, WHITESPACE);
|
||
|
if (kicked.isNotEmpty())
|
||
11 years ago
|
{
|
||
8 years ago
|
Channel *channel = m_channels.get(chan);
|
||
|
if (channel != nullptr)
|
||
11 years ago
|
{
|
||
8 years ago
|
Jupiter::IRC::Client::User *user = m_users.get(kicked);
|
||
|
if (user != nullptr)
|
||
11 years ago
|
{
|
||
8 years ago
|
channel->delUser(kicked);
|
||
9 years ago
|
size_t pos = line.find(':', 1);
|
||
|
Jupiter::ReferenceString reason;
|
||
8 years ago
|
|
||
9 years ago
|
if (pos != Jupiter::INVALID_INDEX)
|
||
|
reason = Jupiter::ReferenceString::substring(line, pos + 1);
|
||
8 years ago
|
|
||
9 years ago
|
this->OnKick(chan, kicker, kicked, reason);
|
||
8 years ago
|
|
||
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
|
Jupiter::plugins->get(i)->OnKick(this, chan, kicker, kicked, reason);
|
||
|
|
||
|
if (kicked.equalsi(m_nickname))
|
||
11 years ago
|
{
|
||
8 years ago
|
Client::delChannel(chan);
|
||
|
if (m_join_on_kick)
|
||
|
Jupiter::IRC::Client::joinChannel(chan);
|
||
11 years ago
|
}
|
||
8 years ago
|
|
||
|
if (user->getChannelCount() == 0)
|
||
|
m_users.remove(kicked);
|
||
11 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
9 years ago
|
}
|
||
|
}
|
||
|
else if (w2.equalsi("QUIT"))
|
||
|
{
|
||
|
Jupiter::ReferenceString nick = getSender(line);
|
||
|
Jupiter::ReferenceString message = Jupiter::ReferenceString::substring(line, line.find(':', 1) + 1);
|
||
8 years ago
|
Jupiter::IRC::Client::User *user = m_users.get(nick);
|
||
|
if (user != nullptr)
|
||
9 years ago
|
{
|
||
8 years ago
|
auto remove_user_callback = [&nick](ChannelTableType::Bucket::Entry &in_entry)
|
||
|
{
|
||
|
in_entry.value.delUser(nick);
|
||
|
};
|
||
|
|
||
|
m_channels.callback(remove_user_callback);
|
||
|
|
||
9 years ago
|
this->OnQuit(nick, message);
|
||
8 years ago
|
|
||
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
|
Jupiter::plugins->get(i)->OnQuit(this, nick, message);
|
||
|
|
||
|
m_users.remove(nick);
|
||
9 years ago
|
}
|
||
|
}
|
||
|
else if (w2.equalsi("INVITE"))
|
||
|
{
|
||
|
Jupiter::ReferenceString inviter = getSender(line);
|
||
|
Jupiter::ReferenceString invited = Jupiter::ReferenceString::getWord(line, 2, WHITESPACE);
|
||
|
Jupiter::ReferenceString chan = Jupiter::ReferenceString::substring(line, line.find(':', 1) + 1);
|
||
|
this->OnInvite(chan, inviter, invited);
|
||
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
|
Jupiter::plugins->get(i)->OnInvite(this, chan, inviter, invited);
|
||
|
}
|
||
|
else if (w2.equalsi("MODE"))
|
||
|
{
|
||
|
Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(line, 2, WHITESPACE);
|
||
|
if (chan.isNotEmpty())
|
||
|
{
|
||
8 years ago
|
if (m_chan_types.contains(chan[0]))
|
||
11 years ago
|
{
|
||
9 years ago
|
auto nick = getSender(line);
|
||
|
if (nick.isNotEmpty())
|
||
11 years ago
|
{
|
||
9 years ago
|
Jupiter::ReferenceString modestring = Jupiter::ReferenceString::substring(line, line.find(' ', 2) + 1);
|
||
|
if (modestring.wordCount(" ") > 1)
|
||
11 years ago
|
{
|
||
9 years ago
|
Jupiter::ReferenceString modes = modestring.getWord(0, " ");
|
||
|
if (modes.isNotEmpty())
|
||
11 years ago
|
{
|
||
9 years ago
|
modestring.shiftRight(modestring.find(' ') + 1);
|
||
|
Jupiter::ReferenceString tword;
|
||
|
unsigned char g = 0;
|
||
|
char symb = 0;
|
||
|
for (uint8_t z = 0; z != modes.size(); z++)
|
||
11 years ago
|
{
|
||
9 years ago
|
if (modes[z] == '+' || modes[z] == '-')
|
||
|
symb = modes[z];
|
||
8 years ago
|
else if (m_prefix_modes.contains(modes[z])) // user prefix mode
|
||
11 years ago
|
{
|
||
9 years ago
|
|
||
|
tword = modestring.getWord(g, " ");
|
||
|
if (tword.isNotEmpty())
|
||
11 years ago
|
{
|
||
8 years ago
|
Jupiter::IRC::Client::Channel *channel = m_channels.get(chan);
|
||
|
if (channel != nullptr)
|
||
11 years ago
|
{
|
||
8 years ago
|
if (symb == '+')
|
||
|
channel->addUserPrefix(Jupiter::ReferenceString(tword), m_prefixes[m_prefix_modes.find(modes[z])]);
|
||
|
else
|
||
|
channel->delUserPrefix(Jupiter::ReferenceString(tword), m_prefixes[m_prefix_modes.find(modes[z])]);
|
||
11 years ago
|
}
|
||
|
}
|
||
9 years ago
|
g++;
|
||
11 years ago
|
}
|
||
8 years ago
|
else if (m_modeA.contains(modes[z])) // mode type A
|
||
9 years ago
|
g++;
|
||
8 years ago
|
else if (m_modeB.contains(modes[z])) // mode type B
|
||
9 years ago
|
g++;
|
||
8 years ago
|
else if (m_modeC.contains(modes[z]) && symb == '+') // mode type C (with parameter)
|
||
9 years ago
|
g++;
|
||
|
// else; // mode type D
|
||
11 years ago
|
}
|
||
|
}
|
||
|
}
|
||
9 years ago
|
this->OnMode(chan, nick, modestring);
|
||
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
|
Jupiter::plugins->get(i)->OnMode(this, chan, nick, modestring);
|
||
11 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
9 years ago
|
// else if ACCOUNT
|
||
|
// else if CHGHOST
|
||
8 years ago
|
else if (numeric == Reply::NAMREPLY) // Some names.
|
||
11 years ago
|
{
|
||
9 years ago
|
Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(line, 4, " ");
|
||
|
Jupiter::ReferenceString names = Jupiter::ReferenceString::substring(line, line.find(':', 1) + 1);
|
||
8 years ago
|
|
||
|
Channel *channel = m_channels.get(chan);
|
||
|
if (channel != nullptr)
|
||
11 years ago
|
{
|
||
8 years ago
|
if (channel->m_adding_names == false)
|
||
9 years ago
|
{
|
||
8 years ago
|
Client::delChannel(chan);
|
||
|
Client::addChannel(chan);
|
||
|
channel = Jupiter::IRC::Client::getChannel(chan);
|
||
|
channel->m_adding_names = true;
|
||
9 years ago
|
}
|
||
8 years ago
|
|
||
|
// addNamesToChannel can be cut/pasted here
|
||
|
Client::addNamesToChannel(*channel, names);
|
||
11 years ago
|
}
|
||
|
}
|
||
8 years ago
|
else if (numeric == Reply::ENDOFNAMES) // We're done here.
|
||
9 years ago
|
{
|
||
|
Jupiter::ReferenceString chan = Jupiter::ReferenceString::getWord(line, 3, " ");
|
||
8 years ago
|
Channel *channel = m_channels.get(chan);
|
||
|
|
||
|
if (channel != nullptr)
|
||
|
channel->m_adding_names = false;
|
||
9 years ago
|
}
|
||
|
break;
|
||
11 years ago
|
}
|
||
9 years ago
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (w1.equals("PING"))
|
||
|
{
|
||
8 years ago
|
m_socket->send(Jupiter::StringS::Format("PONG %.*s" ENDL, w2.size(), w2.ptr()));
|
||
9 years ago
|
}
|
||
|
else if (w1.equals("NICK"))
|
||
|
{
|
||
|
if (w2.isNotEmpty())
|
||
8 years ago
|
m_nickname = w2;
|
||
9 years ago
|
}
|
||
|
else if (w1.equals("ERROR"))
|
||
|
{
|
||
|
Jupiter::ReferenceString reason = Jupiter::ReferenceString::substring(line, line.find(':') + 1);
|
||
|
this->OnError(reason);
|
||
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
|
Jupiter::plugins->get(i)->OnError(this, reason);
|
||
|
Jupiter::IRC::Client::disconnect();
|
||
|
}
|
||
|
else if (w1.equals("AUTHENTICATE"))
|
||
|
{
|
||
8 years ago
|
if (m_sasl_password.isNotEmpty())
|
||
11 years ago
|
{
|
||
8 years ago
|
Jupiter::StringS auth_str = m_nickname + '\0' + m_sasl_account + '\0' + m_sasl_password;
|
||
9 years ago
|
|
||
8 years ago
|
char *enc = Jupiter::base64encode(auth_str.ptr(), auth_str.size());
|
||
8 years ago
|
m_socket->send("AUTHENTICATE "_jrs + enc + ENDL);
|
||
9 years ago
|
delete[] enc;
|
||
11 years ago
|
}
|
||
8 years ago
|
m_socket->send("CAP END" ENDL);
|
||
|
Client::registerClient();
|
||
11 years ago
|
}
|
||
9 years ago
|
}
|
||
|
if (numeric != 0)
|
||
|
{
|
||
|
this->OnNumeric(numeric, line);
|
||
11 years ago
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
9 years ago
|
Jupiter::plugins->get(i)->OnNumeric(this, numeric, line);
|
||
11 years ago
|
}
|
||
|
}
|
||
9 years ago
|
this->OnRaw(line);
|
||
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
|
Jupiter::plugins->get(i)->OnRaw(this, line);
|
||
11 years ago
|
}
|
||
9 years ago
|
|
||
|
return 0;
|
||
11 years ago
|
}
|
||
|
|
||
|
bool Jupiter::IRC::Client::connect()
|
||
|
{
|
||
10 years ago
|
const Jupiter::ReadableString &clientAddress = Jupiter::IRC::Client::readConfigValue("ClientAddress"_jrs);
|
||
8 years ago
|
if (m_socket->connect(m_server_hostname.c_str(), m_server_port, clientAddress.isEmpty() ? nullptr : Jupiter::CStringS(clientAddress).c_str(), (unsigned short)Jupiter::IRC::Client::readConfigLong("ClientPort"_jrs)) == false)
|
||
11 years ago
|
return false;
|
||
|
|
||
8 years ago
|
m_socket->setBlocking(false);
|
||
|
if (m_ssl == false && Jupiter::IRC::Client::readConfigBool("STARTTLS"_jrs, true))
|
||
11 years ago
|
{
|
||
8 years ago
|
m_socket->send("STARTTLS" ENDL);
|
||
|
m_connection_status = 1;
|
||
11 years ago
|
}
|
||
8 years ago
|
else
|
||
|
Client::startCAP();
|
||
|
|
||
11 years ago
|
return true;
|
||
11 years ago
|
}
|
||
|
|
||
|
void Jupiter::IRC::Client::disconnect(bool stayDead)
|
||
|
{
|
||
8 years ago
|
m_connection_status = 0;
|
||
|
m_socket->close();
|
||
|
m_reconnect_time = time(0) + m_reconnect_delay;
|
||
|
m_dead = stayDead;
|
||
11 years ago
|
this->OnDisconnect();
|
||
10 years ago
|
bool ssl = Jupiter::IRC::Client::readConfigBool("SSL"_jrs);
|
||
8 years ago
|
if (ssl != m_ssl)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_ssl = ssl;
|
||
|
if (m_ssl)
|
||
11 years ago
|
{
|
||
8 years ago
|
Jupiter::SecureTCPSocket *t = new Jupiter::SecureTCPSocket(std::move(*m_socket));
|
||
|
if (m_ssl_certificate.isNotEmpty())
|
||
|
t->setCertificate(m_ssl_certificate, m_ssl_key);
|
||
11 years ago
|
|
||
8 years ago
|
delete m_socket;
|
||
|
m_socket = t;
|
||
11 years ago
|
}
|
||
|
else
|
||
|
{
|
||
8 years ago
|
Jupiter::TCPSocket *t = new Jupiter::TCPSocket(std::move(*m_socket));
|
||
|
delete m_socket;
|
||
|
m_socket = t;
|
||
11 years ago
|
}
|
||
|
}
|
||
11 years ago
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
11 years ago
|
Jupiter::plugins->get(i)->OnDisconnect(this);
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::disconnect(const Jupiter::ReadableString &message, bool stayDead)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_socket->send(Jupiter::StringS::Format("QUIT :%.*s" ENDL, message.size(), message.ptr()));
|
||
11 years ago
|
Jupiter::IRC::Client::disconnect(stayDead);
|
||
|
}
|
||
|
|
||
|
void Jupiter::IRC::Client::reconnect()
|
||
|
{
|
||
8 years ago
|
if (m_connection_status != 0) Jupiter::IRC::Client::disconnect();
|
||
|
m_reconnect_attempts++;
|
||
11 years ago
|
bool successConnect = Jupiter::IRC::Client::connect();
|
||
|
this->OnReconnectAttempt(successConnect);
|
||
11 years ago
|
for (size_t i = 0; i < Jupiter::plugins->size(); i++)
|
||
11 years ago
|
Jupiter::plugins->get(i)->OnReconnectAttempt(this, successConnect);
|
||
11 years ago
|
}
|
||
|
|
||
|
int Jupiter::IRC::Client::think()
|
||
|
{
|
||
9 years ago
|
auto handle_error = [this](int error_code)
|
||
|
{
|
||
8 years ago
|
if (this->m_dead == true)
|
||
9 years ago
|
return error_code;
|
||
|
|
||
8 years ago
|
if (this->m_max_reconnect_attempts < 0 || this->m_reconnect_attempts < this->m_max_reconnect_attempts)
|
||
9 years ago
|
{
|
||
8 years ago
|
if (!this->m_reconnect_delay || this->m_reconnect_time < time(0))
|
||
9 years ago
|
this->reconnect();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
return error_code;
|
||
|
};
|
||
|
|
||
8 years ago
|
if (m_connection_status == 0)
|
||
9 years ago
|
return handle_error(-1);
|
||
|
|
||
8 years ago
|
int tmp = m_socket->recv();
|
||
9 years ago
|
if (tmp > 0)
|
||
11 years ago
|
{
|
||
9 years ago
|
// Process incoming data
|
||
8 years ago
|
Jupiter::ReadableString::TokenizeResult<Jupiter::Reference_String> result = Jupiter::ReferenceString::tokenize(m_socket->getBuffer(), "\r\n"_jrs);
|
||
9 years ago
|
if (result.token_count != 0)
|
||
11 years ago
|
{
|
||
8 years ago
|
if (result.tokens[0].size() > 0)
|
||
|
{
|
||
|
// Ensure there's not a token getting split over separate buffers
|
||
8 years ago
|
if (m_last_line.size() > 0)
|
||
8 years ago
|
{
|
||
8 years ago
|
if (result.tokens[0][0] == '\n' && m_last_line[m_last_line.size() - 1] == '\r')
|
||
8 years ago
|
{
|
||
8 years ago
|
m_last_line.truncate(1); // Remove \r
|
||
8 years ago
|
|
||
8 years ago
|
Jupiter::IRC::Client::process_line(m_last_line);
|
||
|
m_last_line.erase();
|
||
8 years ago
|
|
||
|
result.tokens[0].shiftRight(1); // Remove \n
|
||
8 years ago
|
}
|
||
|
}
|
||
|
|
||
8 years ago
|
m_last_line += result.tokens[0];
|
||
8 years ago
|
}
|
||
|
|
||
9 years ago
|
if (result.token_count != 1)
|
||
|
{
|
||
8 years ago
|
Jupiter::IRC::Client::process_line(m_last_line);
|
||
|
m_last_line = result.tokens[result.token_count - 1];
|
||
9 years ago
|
|
||
|
for (size_t index = 1; index != result.token_count - 1; ++index)
|
||
|
if (Jupiter::IRC::Client::process_line(result.tokens[index]) != 0)
|
||
|
return handle_error(1);
|
||
|
}
|
||
11 years ago
|
}
|
||
9 years ago
|
|
||
|
return 0;
|
||
11 years ago
|
}
|
||
9 years ago
|
|
||
|
// No incoming data; check for errors
|
||
8 years ago
|
tmp = m_socket->getLastError();
|
||
9 years ago
|
|
||
|
if (tmp == 10035) // Operation would block
|
||
|
return 0;
|
||
|
|
||
|
// Serious error; disconnect if necessary
|
||
8 years ago
|
if (m_connection_status != 0)
|
||
9 years ago
|
Jupiter::IRC::Client::disconnect();
|
||
|
|
||
|
return handle_error(tmp);
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::readConfigValue(const Jupiter::ReadableString &key, const Jupiter::ReadableString &defaultValue) const
|
||
11 years ago
|
{
|
||
8 years ago
|
if (m_primary_section != nullptr)
|
||
9 years ago
|
{
|
||
8 years ago
|
const Jupiter::ReadableString &val = m_primary_section->get(key);
|
||
9 years ago
|
|
||
|
if (val.isNotEmpty())
|
||
|
return val;
|
||
|
}
|
||
|
|
||
8 years ago
|
if (m_secondary_section != nullptr)
|
||
|
return m_secondary_section->get(key, defaultValue);
|
||
9 years ago
|
|
||
|
return defaultValue;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
bool Jupiter::IRC::Client::readConfigBool(const Jupiter::ReadableString &key, bool defaultValue) const
|
||
11 years ago
|
{
|
||
8 years ago
|
if (m_primary_section != nullptr)
|
||
9 years ago
|
{
|
||
8 years ago
|
const Jupiter::ReadableString &val = m_primary_section->get(key);
|
||
9 years ago
|
|
||
|
if (val.isNotEmpty())
|
||
|
return val.asBool();
|
||
|
}
|
||
|
|
||
8 years ago
|
if (m_secondary_section != nullptr)
|
||
|
return m_secondary_section->get<bool>(key, defaultValue);
|
||
9 years ago
|
|
||
|
return defaultValue;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
int Jupiter::IRC::Client::readConfigInt(const Jupiter::ReadableString &key, int defaultValue) const
|
||
11 years ago
|
{
|
||
8 years ago
|
if (m_primary_section != nullptr)
|
||
9 years ago
|
{
|
||
8 years ago
|
const Jupiter::ReadableString &val = m_primary_section->get(key);
|
||
9 years ago
|
|
||
|
if (val.isNotEmpty())
|
||
|
return val.asInt();
|
||
|
}
|
||
|
|
||
8 years ago
|
if (m_secondary_section != nullptr)
|
||
|
return m_secondary_section->get<int>(key, defaultValue);
|
||
9 years ago
|
|
||
|
return defaultValue;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
long Jupiter::IRC::Client::readConfigLong(const Jupiter::ReadableString &key, long defaultValue) const
|
||
11 years ago
|
{
|
||
8 years ago
|
if (m_primary_section != nullptr)
|
||
9 years ago
|
{
|
||
8 years ago
|
const Jupiter::ReadableString &val = m_primary_section->get(key);
|
||
9 years ago
|
|
||
|
if (val.isNotEmpty())
|
||
|
return val.asInt();
|
||
|
}
|
||
|
|
||
8 years ago
|
if (m_secondary_section != nullptr)
|
||
|
return m_secondary_section->get<long>(key, defaultValue);
|
||
9 years ago
|
|
||
|
return defaultValue;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
double Jupiter::IRC::Client::readConfigDouble(const Jupiter::ReadableString &key, double defaultValue) const
|
||
11 years ago
|
{
|
||
8 years ago
|
if (m_primary_section != nullptr)
|
||
9 years ago
|
{
|
||
8 years ago
|
const Jupiter::ReadableString &val = m_primary_section->get(key);
|
||
9 years ago
|
|
||
|
if (val.isNotEmpty())
|
||
|
return val.asDouble();
|
||
|
}
|
||
|
|
||
8 years ago
|
if (m_secondary_section != nullptr)
|
||
|
return m_secondary_section->get<double>(key, defaultValue);
|
||
9 years ago
|
|
||
|
return defaultValue;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
void Jupiter::IRC::Client::writeToLogs(const Jupiter::ReadableString &message)
|
||
11 years ago
|
{
|
||
8 years ago
|
if (m_log_file != nullptr)
|
||
11 years ago
|
{
|
||
8 years ago
|
message.println(m_log_file);
|
||
|
fflush(m_log_file);
|
||
11 years ago
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
8 years ago
|
* @brief IRC Client Private Function Implementations
|
||
11 years ago
|
*/
|
||
|
|
||
8 years ago
|
void Jupiter::IRC::Client::delChannel(const Jupiter::ReadableString &in_channel)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_channels.remove(in_channel);
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
Jupiter::IRC::Client::User *Jupiter::IRC::Client::findUser(const Jupiter::ReadableString &in_nickname) const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_users.get(in_nickname);
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
Jupiter::IRC::Client::User *Jupiter::IRC::Client::findUserOrAdd(const Jupiter::ReadableString &name)
|
||
11 years ago
|
{
|
||
11 years ago
|
Jupiter::ReferenceString nick = Jupiter::ReferenceString::getWord(name, 0, "!");
|
||
8 years ago
|
Jupiter::IRC::Client::User *result = Jupiter::IRC::Client::findUser(nick);
|
||
|
|
||
|
if (result != nullptr)
|
||
|
return result;
|
||
|
|
||
|
User user;
|
||
|
user.m_nickname = nick;
|
||
|
user.m_username = Jupiter::ReferenceString::getWord(name, 1, "!@");
|
||
|
user.m_hostname = Jupiter::ReferenceString::getWord(name, 2, "!@");
|
||
|
m_users.set(nick, user);
|
||
|
|
||
|
return m_users.get(nick);
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
void Jupiter::IRC::Client::addNamesToChannel(Channel &in_channel, Jupiter::ReadableString &in_names)
|
||
11 years ago
|
{
|
||
8 years ago
|
Jupiter::ReferenceString tmp;
|
||
11 years ago
|
size_t offset;
|
||
8 years ago
|
unsigned int nameLen = in_names.wordCount(" ");
|
||
|
|
||
|
for (size_t i = 0; i != nameLen; i++)
|
||
11 years ago
|
{
|
||
8 years ago
|
tmp = Jupiter::ReferenceString::getWord(in_names, i, " ");
|
||
|
|
||
|
if (tmp.isNotEmpty())
|
||
11 years ago
|
{
|
||
8 years ago
|
offset = tmp.span(m_prefixes);
|
||
|
tmp.shiftRight(offset);
|
||
|
|
||
|
Client::User *user = Client::findUserOrAdd(tmp);
|
||
|
tmp.shiftLeft(offset);
|
||
|
|
||
|
in_channel.addUser(user);
|
||
|
|
||
11 years ago
|
while (offset > 0)
|
||
11 years ago
|
{
|
||
8 years ago
|
--offset;
|
||
|
|
||
|
in_channel.addUserPrefix(user->getNickname(), tmp[offset]);
|
||
11 years ago
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
8 years ago
|
void Jupiter::IRC::Client::addChannel(const Jupiter::ReadableString &in_channel)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_channels.set(in_channel, Channel(in_channel, this));
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
bool Jupiter::IRC::Client::startCAP()
|
||
11 years ago
|
{
|
||
8 years ago
|
m_connection_status = 2;
|
||
|
return m_socket->send("CAP LS"_jrs ENDL) > 0;
|
||
11 years ago
|
}
|
||
9 years ago
|
|
||
8 years ago
|
bool Jupiter::IRC::Client::registerClient()
|
||
11 years ago
|
{
|
||
8 years ago
|
bool result = true;
|
||
11 years ago
|
const char *localHostname = Jupiter::Socket::getLocalHostname();
|
||
11 years ago
|
Jupiter::StringS messageToSend;
|
||
8 years ago
|
|
||
|
messageToSend.format("USER %.*s %s %.*s :%.*s" ENDL, m_nickname.size(), m_nickname.ptr(), localHostname, m_server_hostname.size(), m_server_hostname.ptr(), m_realname.size(), m_realname.ptr());
|
||
|
|
||
|
if (m_socket->send(messageToSend) <= 0)
|
||
|
result = false;
|
||
|
|
||
|
messageToSend.format("NICK %.*s" ENDL, m_nickname.size(), m_nickname.ptr());
|
||
|
|
||
|
if (m_socket->send(messageToSend) <= 0)
|
||
|
result = false;
|
||
|
|
||
|
m_connection_status = 3;
|
||
|
return result;
|
||
11 years ago
|
}
|
||
|
|
||
|
/**
|
||
|
* User Implementation
|
||
|
*/
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::User::getNickname() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_nickname;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::User::getUsername() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_username;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::User::getHostname() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_hostname;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
size_t Jupiter::IRC::Client::User::getChannelCount() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_channel_count;
|
||
11 years ago
|
}
|
||
|
|
||
|
/**
|
||
|
* Channel Implementation
|
||
|
*/
|
||
|
|
||
8 years ago
|
Jupiter::IRC::Client::Channel::Channel(const Jupiter::ReadableString &in_name, Jupiter::IRC::Client *in_parent)
|
||
11 years ago
|
{
|
||
8 years ago
|
auto to_lower = [&in_name]()
|
||
|
{
|
||
|
Jupiter::String result(in_name.size());
|
||
|
const char *itr = in_name.ptr();
|
||
|
const char *end = itr + in_name.size();
|
||
|
|
||
|
while (itr != end)
|
||
|
{
|
||
8 years ago
|
result += static_cast<char>(tolower(*itr));
|
||
8 years ago
|
++itr;
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
};
|
||
|
|
||
8 years ago
|
m_name = in_name;
|
||
|
m_parent = in_parent;
|
||
|
m_type = m_parent->getDefaultChanType();
|
||
11 years ago
|
|
||
8 years ago
|
Jupiter::String name = to_lower();
|
||
|
|
||
|
auto read_type = [&name](Jupiter::Config &in_config, int default_type)
|
||
8 years ago
|
{
|
||
8 years ago
|
return in_config["Channels"_jrs][name].get<int>("Type"_jrs, default_type);
|
||
8 years ago
|
};
|
||
11 years ago
|
|
||
8 years ago
|
if (m_parent->getSecondaryConfigSection() != nullptr)
|
||
|
m_type = read_type(*m_parent->getSecondaryConfigSection(), m_type);
|
||
|
|
||
|
if (m_parent->getPrimaryConfigSection() != nullptr)
|
||
8 years ago
|
m_type = read_type(*m_parent->getPrimaryConfigSection(), m_type);
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
Jupiter::IRC::Client::Channel::User *Jupiter::IRC::Client::Channel::addUser(Jupiter::IRC::Client::User *user)
|
||
11 years ago
|
{
|
||
8 years ago
|
Channel::User channel_user;
|
||
|
channel_user.m_user = user;
|
||
11 years ago
|
|
||
8 years ago
|
++user->m_channel_count;
|
||
11 years ago
|
|
||
8 years ago
|
m_users.set(channel_user.getNickname(), channel_user);
|
||
|
return m_users.get(channel_user.getNickname());
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
Jupiter::IRC::Client::Channel::User *Jupiter::IRC::Client::Channel::addUser(Jupiter::IRC::Client::User *user, const char prefix)
|
||
11 years ago
|
{
|
||
8 years ago
|
Channel::User channel_user;
|
||
|
channel_user.m_user = user;
|
||
|
channel_user.m_prefixes = prefix;
|
||
11 years ago
|
|
||
8 years ago
|
++user->m_channel_count;
|
||
11 years ago
|
|
||
8 years ago
|
m_users.set(channel_user.getNickname(), channel_user);
|
||
|
return m_users.get(channel_user.getNickname());
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
void Jupiter::IRC::Client::Channel::delUser(const Jupiter::ReadableString &in_nickname)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_users.remove(in_nickname);
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
void Jupiter::IRC::Client::Channel::addUserPrefix(const Jupiter::ReadableString &in_nickname, char prefix)
|
||
11 years ago
|
{
|
||
8 years ago
|
Channel::User *user = m_users.get(in_nickname);
|
||
11 years ago
|
|
||
8 years ago
|
if (user != nullptr && user->m_prefixes.contains(prefix) == false)
|
||
|
user->m_prefixes += prefix;
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
void Jupiter::IRC::Client::Channel::delUserPrefix(const Jupiter::ReadableString &in_nickname, char prefix)
|
||
11 years ago
|
{
|
||
8 years ago
|
Channel::User *user = m_users.get(in_nickname);
|
||
11 years ago
|
|
||
8 years ago
|
if (user != nullptr)
|
||
|
user->m_prefixes.remove(prefix);
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::Channel::getName() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_name;
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
Jupiter::IRC::Client::Channel::User *Jupiter::IRC::Client::Channel::getUser(const Jupiter::ReadableString &in_nickname) const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_users.get(in_nickname);
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
char Jupiter::IRC::Client::Channel::getUserPrefix(const Channel::User &in_user) const
|
||
|
{
|
||
|
const Jupiter::ReadableString &prefixes = m_parent->getPrefixes();
|
||
|
|
||
|
for (size_t index = 0; index != prefixes.size(); ++index)
|
||
|
if (in_user.m_prefixes.contains(prefixes[index]))
|
||
|
return prefixes[index];
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
8 years ago
|
char Jupiter::IRC::Client::Channel::getUserPrefix(const Jupiter::ReadableString &in_nickname) const
|
||
11 years ago
|
{
|
||
8 years ago
|
Channel::User *user = m_users.get(in_nickname);
|
||
11 years ago
|
|
||
8 years ago
|
if (user != nullptr)
|
||
8 years ago
|
return this->getUserPrefix(*user);
|
||
11 years ago
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
8 years ago
|
const Jupiter::IRC::Client::Channel::UserTableType &Jupiter::IRC::Client::Channel::getUsers() const
|
||
|
{
|
||
|
return m_users;
|
||
|
}
|
||
|
|
||
8 years ago
|
size_t Jupiter::IRC::Client::Channel::getUserCount() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_users.size();
|
||
11 years ago
|
}
|
||
|
|
||
|
int Jupiter::IRC::Client::Channel::getType() const
|
||
|
{
|
||
8 years ago
|
return m_type;
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
void Jupiter::IRC::Client::Channel::setType(int in_type)
|
||
11 years ago
|
{
|
||
8 years ago
|
m_type = in_type;
|
||
11 years ago
|
}
|
||
|
|
||
|
/**
|
||
|
* Channel User Implementation
|
||
|
*/
|
||
|
|
||
|
Jupiter::IRC::Client::Channel::User::~User()
|
||
|
{
|
||
8 years ago
|
if (m_user != nullptr)
|
||
|
--m_user->m_channel_count;
|
||
11 years ago
|
}
|
||
|
|
||
|
Jupiter::IRC::Client::User *Jupiter::IRC::Client::Channel::User::getUser() const
|
||
|
{
|
||
8 years ago
|
return m_user;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::Channel::User::getPrefixes() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_prefixes;
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::Channel::User::getNickname() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_user->getNickname();
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::Channel::User::getUsername() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_user->getUsername();
|
||
11 years ago
|
}
|
||
|
|
||
11 years ago
|
const Jupiter::ReadableString &Jupiter::IRC::Client::Channel::User::getHostname() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_user->getHostname();
|
||
11 years ago
|
}
|
||
|
|
||
8 years ago
|
size_t Jupiter::IRC::Client::Channel::User::getChannelCount() const
|
||
11 years ago
|
{
|
||
8 years ago
|
return m_user->getChannelCount();
|
||
11 years ago
|
}
|