/*
* Copyright (C) 2002-2004 Morten Brix Pedersen <morten@wtf.dk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#include <cstdio>
#include <sstream>
#include "Commands.h"
#include "ServerConnection.h"
#include "Utils.h"
#include "LostIRCApp.h"
using Glib::ustring;
using std::stringstream;
using std::istringstream;
const struct UserCommands cmds[] = {
{ "SERVER", Commands::Server, false },
{ "DISCONNECT", Commands::Disconnect, false },
{ "RECONNECT", Commands::Reconnect, false },
{ "JOIN", Commands::Join, true },
{ "WHOIS", Commands::Whois, true },
{ "PART", Commands::Part, true },
{ "QUIT", Commands::Quit, true },
{ "NICK", Commands::Nick, false },
{ "KICK", Commands::Kick, true },
{ "NAMES", Commands::Names, true },
{ "MODE", Commands::Mode, true },
{ "CTCP", Commands::Ctcp, true },
{ "AWAY", Commands::Away, true },
{ "AWAYALL", Commands::Awayall, true },
{ "INVITE", Commands::Invite, true },
{ "TOPIC", Commands::Topic, true },
{ "NOTICE", Commands::Notice, true },
{ "BANLIST", Commands::Banlist, true },
{ "MSG", Commands::Msg, true },
{ "ME", Commands::Me, true },
{ "WHO", Commands::Who, true },
{ "LIST", Commands::List, true },
{ "SET", Commands::Set, false },
{ "QUOTE", Commands::Quote, true },
//{ "EXEC", Commands::Exec, false },
{ "OPER", Commands::Oper, true },
{ "KILL", Commands::Kill, true },
{ "WALLOPS", Commands::Wallops, true },
{ "DCC", Commands::DCC, true },
{ "ADMIN", Commands::Admin, true },
{ "WHOWAS", Commands::Whowas, true },
{ "OP", Commands::Op, true },
{ "DEOP", Commands::Deop, true },
{ "VOICE", Commands::Voice, true },
{ "DEVOICE", Commands::Devoice, true },
{ "EXIT", Commands::Exit, false },
{ 0, 0, false }
};
namespace Commands {
void send(ServerConnection *conn, ustring cmd, const ustring& params) {
for (int i = 0; cmds[i].cmd != 0; ++i) {
if (cmds[i].cmd == cmd) {
if (!conn->Session.isConnected && cmds[i].reqConnected) {
throw CommandException(_("Must be connected."));
}
cmds[i].function(conn, params);
return;
}
}
// If no matching functions were found, just try to send the command raw
// to the server.
if (conn->Session.isConnected)
Quote(conn, cmd + " " + params);
}
void Join(ServerConnection *conn, const ustring& params)
{
if (params.length() == 0) {
throw CommandException(_("/JOIN <channel>, join a channel"));
} else {
conn->sendJoin(params);
}
}
void Part(ServerConnection *conn, const ustring& params)
{
if (params.length() == 0) {
throw CommandException(_("/PART <channel> [msg], part a channel - optional with a part message"));
} else {
ustring::size_type pos1 = params.find_first_of(" ");
ustring chan = params.substr(0, pos1);
ustring msg;
if (pos1 != ustring::npos)
msg = params.substr(pos1 + 1);
conn->sendPart(chan, msg);
}
}
void Quit(ServerConnection *conn, const ustring& params)
{
conn->sendQuit(params);
conn->disconnect();
}
void Kick(ServerConnection *conn, const ustring& params)
{
ustring chan, nick, msg;
ustring::size_type pos1 = params.find_first_of(" ");
chan = params.substr(0, pos1);
if (pos1 != ustring::npos) {
ustring::size_type pos2 = params.find_first_of(" ", pos1 + 1);
nick = params.substr(pos1 + 1, (pos2 - 1) - pos1);
if (pos2 != ustring::npos) {
msg = params.substr(pos2 + 1);
}
}
if (params.empty() || chan.empty() || nick.empty()) {
throw CommandException(_("/KICK <channel> <nick> [msg], kick a user from a channel."));
} else {
conn->sendKick(chan, nick, msg);
}
}
void Server(ServerConnection *conn, const ustring& params)
{
if (params.empty()) {
throw CommandException(_("/SERVER <host/ip> [port] [password], connect to an IRC server"));
} else {
ustring host, port, password;
istringstream ss(params);
ss >> host;
ss >> port;
ss >> password;
if (conn->Session.isConnected) {
conn->sendQuit();
conn->Session.isConnected = false;
}
if (!port.empty()) {
int p = Util::convert<int>(port);
if (!password.empty()) {
conn->connect(host, p, password);
} else {
conn->connect(host, p);
}
} else {
conn->connect(host);
}
}
}
void Disconnect(ServerConnection *conn, const ustring& params)
{
conn->removeReconnectTimer();
conn->disconnect();
}
void Reconnect(ServerConnection *conn, const ustring& params)
{
conn->reconnect();
}
void Nick(ServerConnection *conn, const ustring& params)
{
if (params.empty()) {
throw CommandException(_("/NICK <nick>, change nick."));
} else {
if (conn->Session.isConnected) {
conn->sendNick(params);
} else {
conn->Session.nick = params;
}
}
}
void Whois(ServerConnection *conn, const ustring& params)
{
if (params.empty()) {
throw CommandException(_("/WHOIS <nick>, whois nick."));
} else {
conn->sendWhois(params);
}
}
void Mode(ServerConnection *conn, const ustring& params)
{
if (params.empty()) {
throw CommandException(_("/MODE <channel> <modes>, set modes for a channel."));
} else {
conn->sendMode(params);
}
}
void Set(ServerConnection *conn, const ustring& params)
{
ustring::size_type pos1 = params.find_first_of(" ");
ustring key = params.substr(0, pos1);
ustring value;
if (pos1 != ustring::npos)
value = params.substr(pos1 + 1);
App->options.set(key, value);
}
void Ctcp(ServerConnection *conn, const ustring& params)
{
ustring::size_type pos1 = params.find_first_of(" ");
ustring to = params.substr(0, pos1);
ustring action;
if (pos1 != ustring::npos)
action = params.substr(pos1 + 1);
if (action.empty()) {
throw CommandException(_("/CTCP <nick> <message>, sends a CTCP message to a user"));
} else {
action = Util::upper(action);
conn->sendCtcp(to, action);
}
}
void Away(ServerConnection *conn, const ustring& params)
{
conn->sendAway(params);
}
void Awayall(ServerConnection *conn, const ustring& params)
{
std::vector<ServerConnection*> servers = App->getServers();
std::vector<ServerConnection*>::iterator i;
for (i = servers.begin(); i != servers.end(); ++i)
{
(*i)->sendAway(params);
}
}
void Banlist(ServerConnection *conn, const ustring& chan)
{
if (chan.empty()) {
throw CommandException(_("/BANLIST <channel>, see banlist for channel."));
} else {
conn->sendBanlist(chan);
}
}
void Invite(ServerConnection *conn, const ustring& params)
{
ustring to, chan;
stringstream ss(params);
ss >> to;
ss >> chan;
if (chan.empty()) {
throw CommandException(_("/INVITE <nick> <channel>, invites someone to a channel."));
} else {
conn->sendInvite(to, chan);
}
}
void Topic(ServerConnection *conn, const ustring& params)
{
ustring::size_type pos1 = params.find_first_of(" ");
ustring chan = params.substr(0, pos1);
ustring topic;
if (pos1 != ustring::npos)
topic = params.substr(pos1 + 1);
if (chan.empty()) {
throw CommandException(_("/TOPIC <channel> [topic], view or change topic for a channel."));
} else {
conn->sendTopic(chan, topic);
}
}
void Msg(ServerConnection *conn, const ustring& params)
{
ustring::size_type pos1 = params.find_first_of(" ");
ustring to = params.substr(0, pos1);
ustring msg;
if (pos1 != ustring::npos)
msg = params.substr(pos1 + 1);
if (msg.empty()) {
throw CommandException(_("/MSG <nick/channel> <message>, sends a normal message."));
} else {
conn->sendMsg(to, msg, false);
ustring sendgui = "Message to " + to + ":";
FE::emit(FE::get(CLIENTMSG) << sendgui << msg, FE::CURRENT, conn);
}
}
void Notice(ServerConnection *conn, const ustring& params)
{
ustring::size_type pos1 = params.find_first_of(" ");
ustring to = params.substr(0, pos1);
ustring msg;
if (pos1 != ustring::npos)
msg = params.substr(pos1 + 1);
if (msg.empty()) {
throw CommandException(_("/NOTICE <nick/channel> <message>, sends a notice."));
} else {
conn->sendNotice(to, msg);
ustring sendgui = _("Notice to ") + to + ":";
FE::emit(FE::get(CLIENTMSG) << sendgui << msg, FE::CURRENT, conn);
}
}
void Me(ServerConnection *conn, const ustring& params)
{
ustring::size_type pos1 = params.find_first_of(" ");
ustring to = params.substr(0, pos1);
ustring msg = params.substr(pos1 + 1);
if (msg.empty()) {
throw CommandException(_("/ME <message>, sends the action to the current channel."));
} else {
conn->sendMe(to, msg);
}
}
void Who(ServerConnection *conn, const ustring& params)
{
if (params.empty()) {
throw CommandException(_("/WHO <mask> [o], search for mask on network, if o is supplied, only search for opers."));
} else {
conn->sendWho(params);
}
}
void List(ServerConnection *conn, const ustring& params)
{
//throw CommandException(_("/LIST [channels] [server], list channels on a network, if a channel is supplied, only list that channel. If a server is supplied, forward the request to that IRC server."));
conn->sendList(params);
}
void Quote(ServerConnection *conn, const ustring& params)
{
if (params.empty()) {
throw CommandException(_("/QUOTE <text>, send raw text to server."));
} else {
conn->sendRaw(params);
}
}
void Names(ServerConnection *conn, const ustring& params)
{
if (params.empty()) {
throw CommandException(_("/NAMES <channel>, see who's on a channel."));
} else {
conn->sendNames(params);
}
}
void Oper(ServerConnection* conn, const ustring& params)
{
if (params.empty()) {
throw CommandException(_("/OPER <login> <password>, oper up."));
} else {
ustring login, password;
istringstream ss(params);
ss >> login;
ss >> password;
if (login.empty() || password.empty())
throw CommandException(_("/OPER <login> <password>, oper up."));
conn->sendOper(login, password);
}
}
void Kill(ServerConnection* conn, const ustring& params)
{
ustring::size_type pos1 = params.find_first_of(" ");
ustring nick = params.substr(0, pos1);
ustring reason;
if (pos1 != ustring::npos)
reason = params.substr(pos1 + 1);
if (nick.empty()) {
throw CommandException(_("/KILL <user> [reason], kill a user from the network."));
} else {
conn->sendKill(nick, reason);
}
}
void Wallops(ServerConnection* conn, const ustring& params)
{
if (params.empty()) {
throw CommandException(_("/WALLOPS <message>, send wallop message."));
} else {
conn->sendWallops(params);
}
}
void DCC(ServerConnection* conn, const ustring& params)
{
if (params.empty()) {
throw CommandException(_("/DCC <actions>, perform a DCC action."));
} else {
ustring action, secondparam;
istringstream ss(params);
ss >> action;
ss >> secondparam;
action = Util::upper(action);
if (action == "RECEIVE") {
if (!App->getDcc().start_dcc(Util::convert<int>(secondparam)))
throw CommandException(_("No DCC with that number"));
} else if (action == "SEND") {
std::string filename;
getline(ss, filename);
if (filename.empty())
throw CommandException(_("Missing filename"));
// Strip leading and ending whitespace.
filename = filename.substr(filename.find_first_not_of(' '));
filename = filename.substr(0, filename.find_last_not_of(' ')+1);
App->getDcc().addDccSendOut(filename, secondparam, conn);
}
}
}
void Admin(ServerConnection* conn, const ustring& params)
{
conn->sendAdmin(params);
}
void Whowas(ServerConnection* conn, const ustring& params)
{
conn->sendWhowas(params);
}
void Op(ServerConnection* conn, const ustring& params)
{
if (params.empty()) {
throw CommandException(_("/OP <channel> <nicks>, give operator status to one or more nicks."));
} else {
ustring chan;
istringstream ss(params);
ss >> chan;
Glib::ustring modeline = assignModes('+', 'o', ss);
conn->sendMode(chan + " " + modeline);
}
}
void Deop(ServerConnection* conn, const ustring& params)
{
if (params.empty()) {
throw CommandException(_("/DEOP <channel> <nicks>, remove operator status from one or more nicks."));
} else {
ustring chan;
istringstream ss(params);
ss >> chan;
Glib::ustring modeline = assignModes('-', 'o', ss);
conn->sendMode(chan + " " + modeline);
}
}
void Voice(ServerConnection* conn, const ustring& params)
{
if (params.empty()) {
throw CommandException(_("/VOICE <channel> <nicks>, gives voice to one or more nicks."));
} else {
ustring chan;
istringstream ss(params);
ss >> chan;
Glib::ustring modeline = assignModes('+', 'v', ss);
conn->sendMode(chan + " " + modeline);
}
}
void Devoice(ServerConnection* conn, const ustring& params)
{
if (params.empty()) {
throw CommandException(_("/DEVOICE <channel> <nicks>, removes voice from one or more nicks."));
} else {
ustring chan;
istringstream ss(params);
ss >> chan;
Glib::ustring modeline = assignModes('-', 'v', ss);
conn->sendMode(chan + " " + modeline);
}
}
void Exit(ServerConnection* conn, const ustring& params)
{
const std::vector<ServerConnection*> servers = App->getServers();
std::vector<ServerConnection*>::const_iterator i;
for (i = servers.begin(); i != servers.end(); ++i)
{
Quit(*i, params);
}
}
/*
void Exec(ServerConnection *conn, const ustring& params)
{
ustring::size_type pos1 = params.find_first_of(" ");
ustring param = params.substr(0, pos1);
ustring rest = params.substr(pos1 + 1);
if (param == "-o") {
FILE* f = popen(rest.c_str(), "r");
char buf[4028];
fread(buf, 1, 4028, f);
std::cout << "output: \n" << buf << std::endl;
FE::emit(FE::get(CLIENTMSG) << buf, FE::CURRENT, conn);
} else if (!params.empty()) {
FILE* f = popen(rest.c_str(), "r");
char buf[4028];
fread(buf, 1, 4028, f);
std::cout << "output: \n" << buf << std::endl;
FE::emit(FE::get(CLIENTMSG) << buf, FE::CURRENT, conn);
ustring str(buf);
} else {
throw CommandException("/EXEC [-o] <command>, execute a command, if -o is used, output to channel.");
}
}
*/
void getCommands(std::set<Glib::ustring>& commands)
{
for (int i = 0; cmds[i].cmd != 0; ++i)
commands.insert(cmds[i].cmd);
}
Glib::ustring assignModes(char sign, char mode, istringstream& ss)
{
ustring modes;
modes += sign;
ustring nicks;
ustring nick;
while (ss >> nick)
{
modes += mode;
nicks += nick + " ";
}
return modes + " " + nicks;
}
}
syntax highlighted by Code2HTML, v. 0.9.1