The complete source code of IdealIRC
http://www.idealirc.org/
692 lines
17 KiB
692 lines
17 KiB
/*
|
|
* IdealIRC - Internet Relay Chat client
|
|
* Copyright (C) 2021 Tom-Andre Barstad.
|
|
* This software is licensed under the Software Attribution License.
|
|
* See LICENSE for more information.
|
|
*/
|
|
|
|
#include "ICommand.h"
|
|
#include "Commands.h"
|
|
|
|
#include "IRCClient/IRCMember.h"
|
|
#include "IRCClient/IRCChannel.h"
|
|
|
|
#include "MdiManager.h"
|
|
#include "Script/Manager.h"
|
|
#include "fmt/format.h"
|
|
#include "ICommandPriv.h"
|
|
#include <algorithm>
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
|
#define QT_SPLIT_SKIP_EMPTY_PARTS QString::SkipEmptyParts
|
|
#else
|
|
#define QT_SPLIT_SKIP_EMPTY_PARTS Qt::SkipEmptyParts
|
|
#endif
|
|
|
|
ICommand::ICommand(IRC& connection_)
|
|
: mp(new ICommandPriv(*this, connection_, connection_.getStatus()))
|
|
{}
|
|
|
|
ICommand::~ICommand() = default;
|
|
|
|
void ICommand::parse(QString text)
|
|
{
|
|
auto& connection = mp->connection;
|
|
|
|
if (text.isEmpty())
|
|
return;
|
|
|
|
if (text[0] == '/')
|
|
text = text.mid(1);
|
|
|
|
if (tryParseIRC(text) || tryParseInternal(text))
|
|
return;
|
|
else if (ScriptManager::instance()->runCommand(text))
|
|
return;
|
|
else if (!connection.isOnline()) {
|
|
const auto command = text.split(' ')[0];
|
|
print_notConnectedToServer(command);
|
|
}
|
|
else {
|
|
const int nextSpace = text.indexOf(' ');
|
|
if (nextSpace == -1)
|
|
connection.raw(text.toUpper().toStdString());
|
|
else {
|
|
QString command = text.mid(0, nextSpace).toUpper();
|
|
QString out = QString("%1 %2")
|
|
.arg(command)
|
|
.arg(text.mid(nextSpace + 1));
|
|
connection.raw(out.toStdString());
|
|
}
|
|
}
|
|
}
|
|
|
|
IRC& ICommand::getConnection()
|
|
{
|
|
return mp->connection;
|
|
}
|
|
|
|
bool ICommand::tryParseIRC(QString cmdLine)
|
|
{
|
|
auto& connection = mp->connection;
|
|
|
|
int spaceidx = cmdLine.indexOf(' ');
|
|
spaceidx = spaceidx > -1 ? spaceidx : cmdLine.length();
|
|
const QString command = cmdLine.mid(0, spaceidx).toUpper();
|
|
cmdLine.remove(0, spaceidx);
|
|
|
|
using namespace Command::IRC; // For the string constants below.
|
|
if (command == PASS) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_Message });
|
|
if (!argv[0])
|
|
print_notEnoughParameters(command);
|
|
else
|
|
connection.command(PASS, *argv[0]);
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == NICK) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_Message });
|
|
if (!argv[0])
|
|
print_notEnoughParameters(command);
|
|
else {
|
|
if (!connection.isOnline())
|
|
connection.setNickname(*argv[0]);
|
|
connection.command(NICK, *argv[0]);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == OPER) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord, &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (argv.size() < 2)
|
|
print_notEnoughParameters(command);
|
|
else
|
|
connection.command(OPER, { *argv[0], *argv[1] });
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == MODE) {
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord, &ICommand::prd_Message });
|
|
connection.raw(fmt::format("{} {}", MODE, argv.joinString(' ')));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == QUIT) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_Message });
|
|
connection.expectDisconnect();
|
|
connection.command(QUIT, *argv[0]);
|
|
return true;
|
|
}
|
|
|
|
else if (command == SQUIT) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord, &ICommand::prd_Message });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[0])
|
|
print_notEnoughParameters(command);
|
|
else
|
|
connection.command(SQUIT, { *argv[0] }, *argv[1]);
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == JOIN) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord, &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[0])
|
|
print_notEnoughParameters(command);
|
|
else
|
|
connection.command(JOIN, { *argv[0], argv[1].value_or("") });
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == PART) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord, &ICommand::prd_Message });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[0])
|
|
print_notEnoughParameters(command);
|
|
else
|
|
connection.command(PART, { *argv[0] }, argv[1].value_or(""));
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == TOPIC) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_Switch, &ICommand::prd_AnyWord, &ICommand::prd_Message });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[1])
|
|
print_notEnoughParameters(command);
|
|
else {
|
|
if (argv[0].value_or("") == "-c") {
|
|
connection.command(TOPIC, { *argv[1] }, "");
|
|
return true;
|
|
}
|
|
|
|
if (argv[2])
|
|
connection.command(TOPIC, { *argv[1] }, *argv[2]);
|
|
else
|
|
connection.command(TOPIC, { *argv[1] });
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == NAMES) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[0])
|
|
print_notEnoughParameters(command);
|
|
else
|
|
connection.command(NAMES, { *argv[0] });
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == LIST) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else
|
|
connection.command(LIST, { argv[0].value_or("") });
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == INVITE) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord, &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[0] || !argv[1])
|
|
print_notEnoughParameters(command);
|
|
else
|
|
connection.command(INVITE, { *argv[0], *argv[1] });
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == KICK) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_OptionalChannel, &ICommand::prd_AnyWord, &ICommand::prd_Message });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[1])
|
|
print_notEnoughParameters(command);
|
|
else
|
|
mp->cmd_kick(*argv[0], *argv[1], argv[2].value_or(""));
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == PRIVMSG || command == Command::Internal::MSG) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord, &ICommand::prd_Message });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[0])
|
|
print_notEnoughParameters(command);
|
|
else
|
|
mp->cmd_privmsg(*argv[0], argv[1].value_or(""));
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == NOTICE) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord, &ICommand::prd_Message });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[0])
|
|
print_notEnoughParameters(command);
|
|
else
|
|
mp->cmd_notice(*argv[0], argv[1].value_or(""));
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == MOTD) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else
|
|
connection.command(MOTD, { argv[0].value_or("") });
|
|
return true;
|
|
}
|
|
|
|
else if (command == LUSERS) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else
|
|
connection.command(LUSERS, { argv[0].value_or("") });
|
|
return true;
|
|
}
|
|
|
|
else if (command == VERSION) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else
|
|
connection.command(VERSION, { argv[0].value_or("") });
|
|
return true;
|
|
}
|
|
|
|
else if (command == STATS) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else
|
|
connection.command(STATS, { argv[0].value_or("") });
|
|
return true;
|
|
}
|
|
|
|
else if (command == LINKS) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else
|
|
connection.command(LINKS, { argv[0].value_or("") });
|
|
return true;
|
|
}
|
|
|
|
else if (command == TIME) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else
|
|
connection.command(TIME, { argv[0].value_or("") });
|
|
return true;
|
|
}
|
|
|
|
else if (command == CONNECT) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else
|
|
connection.command(CONNECT, { argv[0].value_or("") });
|
|
return true;
|
|
}
|
|
|
|
else if (command == TRACE) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_Message });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else
|
|
connection.command(TRACE, { argv[0].value_or("") });
|
|
return true;
|
|
}
|
|
|
|
else if (command == ADMIN) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else
|
|
connection.command(ADMIN, { argv[0].value_or("") });
|
|
return true;
|
|
}
|
|
|
|
else if (command == INFO) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else
|
|
connection.command(INFO, { argv[0].value_or("") });
|
|
return true;
|
|
}
|
|
|
|
else if (command == SERVLIST) {
|
|
|
|
}
|
|
|
|
else if (command == SQUERY) {
|
|
|
|
}
|
|
|
|
else if (command == WHO) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_Message });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else
|
|
connection.command(WHO, { argv[0].value_or("") });
|
|
return true;
|
|
}
|
|
|
|
else if (command == WHOIS) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[0])
|
|
print_notEnoughParameters(command);
|
|
else
|
|
connection.command(WHOIS, { *argv[0] });
|
|
return true;
|
|
}
|
|
|
|
else if (command == WHOWAS) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[0])
|
|
print_notEnoughParameters(command);
|
|
else
|
|
connection.command(WHOWAS, { *argv[0] });
|
|
return true;
|
|
}
|
|
|
|
else if (command == KILL) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord, &ICommand::prd_Message });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[0]) {
|
|
print_notEnoughParameters(command);
|
|
return true;
|
|
}
|
|
connection.command(KILL, { *argv[0] }, argv[1].value_or(""));
|
|
return true;
|
|
}
|
|
|
|
else if (command == PING) {
|
|
|
|
}
|
|
|
|
else if (command == PONG) {
|
|
|
|
}
|
|
|
|
else if (command == AWAY) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_Message });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (argv[0])
|
|
connection.command(AWAY, *argv[0]);
|
|
else
|
|
connection.raw(AWAY);
|
|
return true;
|
|
}
|
|
|
|
else if (command == REHASH) {
|
|
|
|
}
|
|
|
|
else if (command == DIE) {
|
|
|
|
}
|
|
|
|
else if (command == RESTART) {
|
|
|
|
}
|
|
|
|
else if (command == SUMMON) {
|
|
|
|
}
|
|
|
|
else if (command == USERS) {
|
|
|
|
}
|
|
|
|
else if (command == WALLOPS) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_Message });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[0])
|
|
print_notEnoughParameters(command);
|
|
else
|
|
connection.command(WALLOPS, *argv[0]);
|
|
return true;
|
|
}
|
|
|
|
else if (command == USERHOST) {
|
|
|
|
}
|
|
|
|
else if (command == ISON) {
|
|
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool ICommand::tryParseInternal(QString cmdLine)
|
|
{
|
|
auto& connection = mp->connection;
|
|
auto& status = mp->status;
|
|
|
|
int spaceidx = cmdLine.indexOf(' ');
|
|
spaceidx = spaceidx > -1 ? spaceidx : cmdLine.length();
|
|
const QString command = cmdLine.mid(0, spaceidx).toUpper();
|
|
cmdLine.remove(0, spaceidx);
|
|
|
|
using namespace Command::Internal;
|
|
using namespace Command::IRC;
|
|
|
|
if (command == CTCP || command == CTCPREPLY) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord, &ICommand::prd_AnyWordToUpper, &ICommand::prd_Message });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[0] || !argv[1])
|
|
print_notEnoughParameters(command);
|
|
else {
|
|
if (command == CTCP)
|
|
mp->cmd_ctcp(*argv[0], *argv[1], argv[2].value_or(""));
|
|
else
|
|
mp->cmd_ctcpreply(*argv[0], *argv[1], argv[2].value_or(""));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
else if (command == ME) {
|
|
IWin* cw = status.getActiveWindow();
|
|
|
|
if (cw->getType() != IWin::Type::Channel && cw->getType() != IWin::Type::Private) {
|
|
print_invalidWindowTypeForCommand(command);
|
|
return true;
|
|
}
|
|
|
|
CommandData argv(cmdLine, { &ICommand::prd_Message });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[0])
|
|
print_notEnoughParameters(command);
|
|
else {
|
|
const auto target = cw->getButtonText().toStdString();
|
|
mp->cmd_me(target, argv[0].value_or(""));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
else if (command == ECHO) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_Switch, &ICommand::prd_Switch, &ICommand::prd_Message });
|
|
if (!argv[2]) {
|
|
print_notEnoughParameters(command);
|
|
return true;
|
|
}
|
|
|
|
std::string arg1, arg2;
|
|
if (argv[0])
|
|
arg1 = *argv[0];
|
|
if (argv[1])
|
|
arg2 = *argv[1];
|
|
|
|
mp->cmd_echo(arg1, arg2, *argv[2]);
|
|
return true;
|
|
}
|
|
|
|
else if (command == QUERY) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_AnyWord });
|
|
if (!connection.isOnline())
|
|
print_notConnectedToServer(command);
|
|
else if (!argv[0])
|
|
print_notEnoughParameters(command);
|
|
else
|
|
status.createPrivateWindow(argv[0]->c_str());
|
|
return true;
|
|
}
|
|
|
|
else if (command == MUTERESP) {
|
|
QStringList list = cmdLine.split(' ', QT_SPLIT_SKIP_EMPTY_PARTS);
|
|
if (list.isEmpty()) {
|
|
print_notEnoughParameters(command);
|
|
return true;
|
|
}
|
|
connection.setIgnoreVerbosity(list);
|
|
return true;
|
|
}
|
|
|
|
else if (command == UNMUTERESP) {
|
|
QStringList list = cmdLine.split(' ', QT_SPLIT_SKIP_EMPTY_PARTS);
|
|
if (list.isEmpty()) {
|
|
print_notEnoughParameters(command);
|
|
return true;
|
|
}
|
|
connection.unsetIgnoreVerbosity(list);
|
|
return true;
|
|
}
|
|
|
|
else if (command == CLEAR) {
|
|
auto& mdi = MdiManager::instance();
|
|
mdi.currentWindow()->clear();
|
|
return true;
|
|
}
|
|
|
|
else if (command == QUOTE || command == RAW) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_Message });
|
|
if (!argv[0]) {
|
|
print_notEnoughParameters(command);
|
|
return true;
|
|
}
|
|
|
|
// don't do "isOnline" since BNCs asks to do "/quote pass blah" and such before connection registration.
|
|
// ... as well as other services that would require something similar.
|
|
if (!connection.isConnected()) {
|
|
print_notConnectedToServer(command);
|
|
return true;
|
|
}
|
|
|
|
connection.raw(*argv[0]);
|
|
|
|
return true;
|
|
}
|
|
|
|
else if (command == SERVER) {
|
|
CommandData argv(cmdLine, { &ICommand::prd_Switch, &ICommand::prd_AnyWord });
|
|
if (!argv[1]) {
|
|
print_notEnoughParameters(command);
|
|
return true;
|
|
}
|
|
|
|
bool ssl{ false };
|
|
bool newstatus{ false };
|
|
bool activate{ false };
|
|
if (argv[0]) {
|
|
ssl = argv[0]->find('s') != std::string::npos;
|
|
newstatus = argv[0]->find('n') != std::string::npos;
|
|
activate = argv[0]->find('a') != std::string::npos;
|
|
}
|
|
|
|
QStringList serverport = QString::fromStdString(*argv[1]).split(':');
|
|
auto host = serverport[0].toStdString();
|
|
auto port = serverport.size() > 1 ? serverport[1].toStdString() : "6667";
|
|
|
|
mp->cmd_server(ssl, newstatus, activate, host, port);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void ICommand::print_notEnoughParameters(const QString& command)
|
|
{
|
|
const auto& mdi = MdiManager::instance();
|
|
mdi.currentStatus()->printToActive(PrintType::ProgramInfo, tr("/%1: Not enough parameters.").arg(command.toLower()));
|
|
}
|
|
|
|
void ICommand::print_invalidCommandSwitch(const QString& command)
|
|
{
|
|
const auto& mdi = MdiManager::instance();
|
|
mdi.currentStatus()->printToActive(PrintType::ProgramInfo, tr("/%1: Invalid command switch.").arg(command.toLower()));
|
|
}
|
|
|
|
void ICommand::print_invalidWindowTypeForCommand(const QString& command)
|
|
{
|
|
const auto& mdi = MdiManager::instance();
|
|
mdi.currentStatus()->printToActive(PrintType::ProgramInfo, tr("/%1: Invalid window type for that command.").arg(command.toLower()));
|
|
}
|
|
|
|
void ICommand::print_notConnectedToServer(const QString& command)
|
|
{
|
|
const auto& mdi = MdiManager::instance();
|
|
mdi.currentStatus()->printToActive(PrintType::ProgramInfo, tr("/%1: Not connected to a server.").arg(command.toLower()));
|
|
}
|
|
|
|
std::optional<std::string> ICommand::prd_AnyWord(int& idx, const QString& line)
|
|
{
|
|
std::string ret;
|
|
std::string stdline = line.toStdString();
|
|
for (; idx < stdline.size(); ++idx) {
|
|
const char c = stdline[idx];
|
|
if (c == ' ')
|
|
break;
|
|
ret += c;
|
|
}
|
|
|
|
if (ret.empty())
|
|
return {};
|
|
|
|
return ret;
|
|
}
|
|
|
|
std::optional<std::string> ICommand::prd_AnyWordToUpper(int& idx, const QString& line)
|
|
{
|
|
auto ret = prd_AnyWord(idx, line);
|
|
if (ret) {
|
|
std::transform(ret->begin(), ret->end(), ret->begin(),
|
|
[](unsigned char c) -> unsigned char { return std::toupper(c); });
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
std::optional<std::string> ICommand::prd_OptionalChannel(int& idx, const QString& line)
|
|
{
|
|
const auto& mdi = MdiManager::instance();
|
|
const auto& isupport = mdi.currentStatus()->getConnection().isupport();
|
|
const auto& chantypes = isupport.at("CHANTYPES");
|
|
|
|
if (chantypes.find_first_of(line.toStdString()[idx]) == std::string::npos)
|
|
return std::nullopt;
|
|
return prd_AnyWord(idx, line);
|
|
}
|
|
|
|
std::optional<std::string> ICommand::prd_NotSwitch(int& idx, const QString& line)
|
|
{
|
|
if (line[idx] == '-' || line[idx] == '+')
|
|
return std::nullopt;
|
|
return prd_AnyWord(idx, line);
|
|
}
|
|
|
|
std::optional<std::string> ICommand::prd_Switch(int& idx, const QString& line)
|
|
{
|
|
if (line[idx] != '-' && line[idx] != '+')
|
|
return std::nullopt;
|
|
return prd_AnyWord(idx, line);
|
|
}
|
|
|
|
std::optional<std::string> ICommand::prd_Message(int& idx, const QString& line)
|
|
{
|
|
QString ret = line.mid(idx);
|
|
if (ret.isEmpty())
|
|
return std::nullopt;
|
|
return ret.toStdString();
|
|
}
|
|
|