/* * Copyright (C) 2002-2004 Morten Brix Pedersen * * 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 #include #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 , join a channel")); } else { conn->sendJoin(params); } } void Part(ServerConnection *conn, const ustring& params) { if (params.length() == 0) { throw CommandException(_("/PART [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 [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 [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(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 , 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 , whois nick.")); } else { conn->sendWhois(params); } } void Mode(ServerConnection *conn, const ustring& params) { if (params.empty()) { throw CommandException(_("/MODE , 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 , 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 servers = App->getServers(); std::vector::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 , 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 , 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 [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 , 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 , 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 , 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 [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 , send raw text to server.")); } else { conn->sendRaw(params); } } void Names(ServerConnection *conn, const ustring& params) { if (params.empty()) { throw CommandException(_("/NAMES , see who's on a channel.")); } else { conn->sendNames(params); } } void Oper(ServerConnection* conn, const ustring& params) { if (params.empty()) { throw CommandException(_("/OPER , oper up.")); } else { ustring login, password; istringstream ss(params); ss >> login; ss >> password; if (login.empty() || password.empty()) throw CommandException(_("/OPER , 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 [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 , send wallop message.")); } else { conn->sendWallops(params); } } void DCC(ServerConnection* conn, const ustring& params) { if (params.empty()) { throw CommandException(_("/DCC , 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(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 , 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 , 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 , 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 , 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 servers = App->getServers(); std::vector::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] , execute a command, if -o is used, output to channel."); } } */ void getCommands(std::set& 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; } }