Allow the execution of multiple commands after the IRC connection
fix #3275
This commit is contained in:
+5
-4
@@ -645,10 +645,11 @@ On a server JID (e.g on the JID chat.freenode.org@biboumi.example.com)
|
|||||||
In encoding into UTF-8. If the conversion fails at some point, some
|
In encoding into UTF-8. If the conversion fails at some point, some
|
||||||
characters will be replaced by the placeholders.
|
characters will be replaced by the placeholders.
|
||||||
* Out encoding: Currently ignored.
|
* Out encoding: Currently ignored.
|
||||||
* After-connection IRC command: A raw IRC command that will be sent to
|
* After-connection IRC commands: Raw IRC commands that will be sent
|
||||||
the server immediately after the connection has been successful. It
|
one by one to the server immediately after the connection has been
|
||||||
can for example be used to identify yourself using NickServ, with a
|
successful. It can for example be used to identify yourself using
|
||||||
command like this: `PRIVMSG NickServ :identify PASSWORD`.
|
NickServ, with a command like this: `PRIVMSG NickServ :identify
|
||||||
|
PASSWORD`.
|
||||||
* Ports: The list of TCP ports to use when connecting to this IRC server.
|
* Ports: The list of TCP ports to use when connecting to this IRC server.
|
||||||
This list will be tried in sequence, until the connection succeeds for
|
This list will be tried in sequence, until the connection succeeds for
|
||||||
one of them. The connection made on these ports will not use TLS, the
|
one of them. The connection made on these ports will not use TLS, the
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ struct Column
|
|||||||
T value{};
|
T value{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ForeignKey: Column<std::size_t> {
|
||||||
|
static constexpr auto name = "fk_";
|
||||||
|
};
|
||||||
|
|
||||||
struct Id: Column<std::size_t> {
|
struct Id: Column<std::size_t> {
|
||||||
static constexpr std::size_t unset_value = static_cast<std::size_t>(-1);
|
static constexpr std::size_t unset_value = static_cast<std::size_t>(-1);
|
||||||
static constexpr auto name = "id_";
|
static constexpr auto name = "id_";
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ Database::GlobalOptionsTable Database::global_options("globaloptions_");
|
|||||||
Database::IrcServerOptionsTable Database::irc_server_options("ircserveroptions_");
|
Database::IrcServerOptionsTable Database::irc_server_options("ircserveroptions_");
|
||||||
Database::IrcChannelOptionsTable Database::irc_channel_options("ircchanneloptions_");
|
Database::IrcChannelOptionsTable Database::irc_channel_options("ircchanneloptions_");
|
||||||
Database::RosterTable Database::roster("roster");
|
Database::RosterTable Database::roster("roster");
|
||||||
|
Database::AfterConnectionCommandsTable Database::after_connection_commands("after_connection_commands_");
|
||||||
std::map<Database::CacheKey, Database::EncodingIn::real_type> Database::encoding_in_cache{};
|
std::map<Database::CacheKey, Database::EncodingIn::real_type> Database::encoding_in_cache{};
|
||||||
|
|
||||||
Database::GlobalPersistent::GlobalPersistent():
|
Database::GlobalPersistent::GlobalPersistent():
|
||||||
@@ -53,6 +54,8 @@ void Database::open(const std::string& filename)
|
|||||||
Database::irc_channel_options.upgrade(*Database::db);
|
Database::irc_channel_options.upgrade(*Database::db);
|
||||||
Database::roster.create(*Database::db);
|
Database::roster.create(*Database::db);
|
||||||
Database::roster.upgrade(*Database::db);
|
Database::roster.upgrade(*Database::db);
|
||||||
|
Database::after_connection_commands.create(*Database::db);
|
||||||
|
Database::after_connection_commands.upgrade(*Database::db);
|
||||||
create_index<Database::Owner, Database::IrcChanName, Database::IrcServerName>(*Database::db, "archive_index", Database::muc_log_lines.get_name());
|
create_index<Database::Owner, Database::IrcChanName, Database::IrcServerName>(*Database::db, "archive_index", Database::muc_log_lines.get_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,6 +91,32 @@ Database::IrcServerOptions Database::get_irc_server_options(const std::string& o
|
|||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Database::AfterConnectionCommands Database::get_after_connection_commands(const IrcServerOptions& server_options)
|
||||||
|
{
|
||||||
|
const auto id = server_options.col<Id>();
|
||||||
|
if (id == Id::unset_value)
|
||||||
|
return {};
|
||||||
|
auto request = Database::after_connection_commands.select();
|
||||||
|
request.where() << ForeignKey{} << "=" << id;
|
||||||
|
return request.execute(*Database::db);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Database::set_after_connection_commands(const Database::IrcServerOptions& server_options, Database::AfterConnectionCommands& commands)
|
||||||
|
{
|
||||||
|
const auto id = server_options.col<Id>();
|
||||||
|
if (id == Id::unset_value)
|
||||||
|
return ;
|
||||||
|
auto query = Database::after_connection_commands.del();
|
||||||
|
query.where() << ForeignKey{} << "=" << id;
|
||||||
|
query.execute(*Database::db);
|
||||||
|
|
||||||
|
for (auto& command: commands)
|
||||||
|
{
|
||||||
|
command.col<ForeignKey>() = server_options.col<Id>();
|
||||||
|
command.save(Database::db);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Database::IrcChannelOptions Database::get_irc_channel_options(const std::string& owner, const std::string& server, const std::string& channel)
|
Database::IrcChannelOptions Database::get_irc_channel_options(const std::string& owner, const std::string& server, const std::string& channel)
|
||||||
{
|
{
|
||||||
auto request = Database::irc_channel_options.select();
|
auto request = Database::irc_channel_options.select();
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ class Database
|
|||||||
using GlobalOptionsTable = Table<Id, Owner, MaxHistoryLength, RecordHistory, GlobalPersistent>;
|
using GlobalOptionsTable = Table<Id, Owner, MaxHistoryLength, RecordHistory, GlobalPersistent>;
|
||||||
using GlobalOptions = GlobalOptionsTable::RowType;
|
using GlobalOptions = GlobalOptionsTable::RowType;
|
||||||
|
|
||||||
using IrcServerOptionsTable = Table<Id, Owner, Server, Pass, AfterConnectionCommand, TlsPorts, Ports, Username, Realname, VerifyCert, TrustedFingerprint, EncodingOut, EncodingIn, MaxHistoryLength, Address>;
|
using IrcServerOptionsTable = Table<Id, Owner, Server, Pass, TlsPorts, Ports, Username, Realname, VerifyCert, TrustedFingerprint, EncodingOut, EncodingIn, MaxHistoryLength, Address>;
|
||||||
using IrcServerOptions = IrcServerOptionsTable::RowType;
|
using IrcServerOptions = IrcServerOptionsTable::RowType;
|
||||||
|
|
||||||
using IrcChannelOptionsTable = Table<Id, Owner, Server, Channel, EncodingOut, EncodingIn, MaxHistoryLength, Persistent, RecordHistoryOptional>;
|
using IrcChannelOptionsTable = Table<Id, Owner, Server, Channel, EncodingOut, EncodingIn, MaxHistoryLength, Persistent, RecordHistoryOptional>;
|
||||||
@@ -101,6 +101,9 @@ class Database
|
|||||||
using RosterTable = Table<LocalJid, RemoteJid>;
|
using RosterTable = Table<LocalJid, RemoteJid>;
|
||||||
using RosterItem = RosterTable::RowType;
|
using RosterItem = RosterTable::RowType;
|
||||||
|
|
||||||
|
using AfterConnectionCommandsTable = Table<Id, ForeignKey, AfterConnectionCommand>;
|
||||||
|
using AfterConnectionCommands = std::vector<AfterConnectionCommandsTable::RowType>;
|
||||||
|
|
||||||
Database() = default;
|
Database() = default;
|
||||||
~Database() = default;
|
~Database() = default;
|
||||||
|
|
||||||
@@ -121,6 +124,9 @@ class Database
|
|||||||
static IrcChannelOptions get_irc_channel_options_with_server_and_global_default(const std::string& owner,
|
static IrcChannelOptions get_irc_channel_options_with_server_and_global_default(const std::string& owner,
|
||||||
const std::string& server,
|
const std::string& server,
|
||||||
const std::string& channel);
|
const std::string& channel);
|
||||||
|
static AfterConnectionCommands get_after_connection_commands(const IrcServerOptions& server_options);
|
||||||
|
static void set_after_connection_commands(const IrcServerOptions& server_options, AfterConnectionCommands& commands);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all the lines between (optional) start and end dates, with a (optional) limit.
|
* Get all the lines between (optional) start and end dates, with a (optional) limit.
|
||||||
* If after_id is set, only the records after it will be returned.
|
* If after_id is set, only the records after it will be returned.
|
||||||
@@ -158,6 +164,8 @@ class Database
|
|||||||
static IrcServerOptionsTable irc_server_options;
|
static IrcServerOptionsTable irc_server_options;
|
||||||
static IrcChannelOptionsTable irc_channel_options;
|
static IrcChannelOptionsTable irc_channel_options;
|
||||||
static RosterTable roster;
|
static RosterTable roster;
|
||||||
|
static AfterConnectionCommandsTable after_connection_commands;
|
||||||
|
|
||||||
static std::unique_ptr<DatabaseEngine> db;
|
static std::unique_ptr<DatabaseEngine> db;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <database/query.hpp>
|
||||||
|
#include <database/engine.hpp>
|
||||||
|
|
||||||
|
class DeleteQuery: public Query
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DeleteQuery(const std::string& name):
|
||||||
|
Query("DELETE")
|
||||||
|
{
|
||||||
|
this->body += " from " + name;
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteQuery& where()
|
||||||
|
{
|
||||||
|
this->body += " WHERE ";
|
||||||
|
return *this;
|
||||||
|
};
|
||||||
|
|
||||||
|
void execute(DatabaseEngine& db)
|
||||||
|
{
|
||||||
|
auto statement = db.prepare(this->body);
|
||||||
|
if (!statement)
|
||||||
|
return;
|
||||||
|
#ifdef DEBUG_SQL_QUERIES
|
||||||
|
const auto timer = this->log_and_time();
|
||||||
|
#endif
|
||||||
|
statement->bind(std::move(this->params));
|
||||||
|
if (statement->step() != StepResult::Done)
|
||||||
|
log_error("Failed to execute DELETE command");
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <database/engine.hpp>
|
#include <database/engine.hpp>
|
||||||
|
|
||||||
#include <database/select_query.hpp>
|
#include <database/select_query.hpp>
|
||||||
|
#include <database/delete_query.hpp>
|
||||||
#include <database/row.hpp>
|
#include <database/row.hpp>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -85,6 +86,12 @@ class Table
|
|||||||
return select;
|
return select;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto del()
|
||||||
|
{
|
||||||
|
DeleteQuery query(this->name);
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& get_name() const
|
const std::string& get_name() const
|
||||||
{
|
{
|
||||||
return this->name;
|
return this->name;
|
||||||
|
|||||||
@@ -889,8 +889,9 @@ void IrcClient::on_welcome_message(const IrcMessage& message)
|
|||||||
#ifdef USE_DATABASE
|
#ifdef USE_DATABASE
|
||||||
auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(),
|
auto options = Database::get_irc_server_options(this->bridge.get_bare_jid(),
|
||||||
this->get_hostname());
|
this->get_hostname());
|
||||||
if (!options.col<Database::AfterConnectionCommand>().empty())
|
const auto commands = Database::get_after_connection_commands(options);
|
||||||
this->send_raw(options.col<Database::AfterConnectionCommand>());
|
for (const auto& command: commands)
|
||||||
|
this->send_raw(command.col<Database::AfterConnectionCommand>());
|
||||||
#endif
|
#endif
|
||||||
// Install a repeated events to regularly send a PING
|
// Install a repeated events to regularly send a PING
|
||||||
TimedEventsManager::instance().add_event(TimedEvent(240s, std::bind(&IrcClient::send_ping_command, this),
|
TimedEventsManager::instance().add_event(TimedEvent(240s, std::bind(&IrcClient::send_ping_command, this),
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com
|
|||||||
server_domain = target.local;
|
server_domain = target.local;
|
||||||
auto options = Database::get_irc_server_options(owner.local + "@" + owner.domain,
|
auto options = Database::get_irc_server_options(owner.local + "@" + owner.domain,
|
||||||
server_domain);
|
server_domain);
|
||||||
|
auto commands = Database::get_after_connection_commands(options);
|
||||||
|
|
||||||
XmlSubNode x(command_node, "jabber:x:data:x");
|
XmlSubNode x(command_node, "jabber:x:data:x");
|
||||||
x["type"] = "form";
|
x["type"] = "form";
|
||||||
@@ -307,14 +308,14 @@ void ConfigureIrcServerStep1(XmppComponent&, AdhocSession& session, XmlNode& com
|
|||||||
|
|
||||||
{
|
{
|
||||||
XmlSubNode after_cnt_cmd(x, "field");
|
XmlSubNode after_cnt_cmd(x, "field");
|
||||||
after_cnt_cmd["var"] = "after_connect_command";
|
after_cnt_cmd["var"] = "after_connect_commands";
|
||||||
after_cnt_cmd["type"] = "text-single";
|
after_cnt_cmd["type"] = "text-multi";
|
||||||
after_cnt_cmd["desc"] = "Custom IRC command sent after the connection is established with the server.";
|
after_cnt_cmd["desc"] = "Custom IRC commands sent after the connection is established with the server.";
|
||||||
after_cnt_cmd["label"] = "After-connection IRC command";
|
after_cnt_cmd["label"] = "After-connection IRC commands";
|
||||||
if (!options.col<Database::AfterConnectionCommand>().empty())
|
for (const auto& command: commands)
|
||||||
{
|
{
|
||||||
XmlSubNode after_cnt_cmd_value(after_cnt_cmd, "value");
|
XmlSubNode after_cnt_cmd_value(after_cnt_cmd, "value");
|
||||||
after_cnt_cmd_value.set_inner(options.col<Database::AfterConnectionCommand>());
|
after_cnt_cmd_value.set_inner(command.col<Database::AfterConnectionCommand>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,6 +385,8 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com
|
|||||||
server_domain = target.local;
|
server_domain = target.local;
|
||||||
auto options = Database::get_irc_server_options(owner.local + "@" + owner.domain,
|
auto options = Database::get_irc_server_options(owner.local + "@" + owner.domain,
|
||||||
server_domain);
|
server_domain);
|
||||||
|
auto commands = Database::get_after_connection_commands(options);
|
||||||
|
|
||||||
for (const XmlNode* field: x->get_children("field", "jabber:x:data"))
|
for (const XmlNode* field: x->get_children("field", "jabber:x:data"))
|
||||||
{
|
{
|
||||||
const XmlNode* value = field->get_child("value", "jabber:x:data");
|
const XmlNode* value = field->get_child("value", "jabber:x:data");
|
||||||
@@ -427,8 +430,16 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com
|
|||||||
else if (field->get_tag("var") == "pass" && value)
|
else if (field->get_tag("var") == "pass" && value)
|
||||||
options.col<Database::Pass>() = value->get_inner();
|
options.col<Database::Pass>() = value->get_inner();
|
||||||
|
|
||||||
else if (field->get_tag("var") == "after_connect_command" && value)
|
else if (field->get_tag("var") == "after_connect_commands")
|
||||||
options.col<Database::AfterConnectionCommand>() = value->get_inner();
|
{
|
||||||
|
commands.clear();
|
||||||
|
for (const auto& val: values)
|
||||||
|
{
|
||||||
|
auto command = Database::after_connection_commands.row();
|
||||||
|
command.col<Database::AfterConnectionCommand>() = val->get_inner();
|
||||||
|
commands.push_back(std::move(command));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
else if (field->get_tag("var") == "username" && value)
|
else if (field->get_tag("var") == "username" && value)
|
||||||
{
|
{
|
||||||
@@ -450,6 +461,7 @@ void ConfigureIrcServerStep2(XmppComponent&, AdhocSession& session, XmlNode& com
|
|||||||
}
|
}
|
||||||
Database::invalidate_encoding_in_cache();
|
Database::invalidate_encoding_in_cache();
|
||||||
options.save(Database::db);
|
options.save(Database::db);
|
||||||
|
Database::set_after_connection_commands(options, commands);
|
||||||
|
|
||||||
command_node.delete_all_children();
|
command_node.delete_all_children();
|
||||||
XmlSubNode note(command_node, "note");
|
XmlSubNode note(command_node, "note");
|
||||||
|
|||||||
@@ -117,6 +117,49 @@ TEST_CASE("Database")
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("Server options")
|
||||||
|
{
|
||||||
|
const std::string owner{"toto@example.com"};
|
||||||
|
const std::string owner2{"toto2@example.com"};
|
||||||
|
const std::string server{"irc.example.com"};
|
||||||
|
|
||||||
|
auto soptions = Database::get_irc_server_options(owner, server);
|
||||||
|
auto soptions2 = Database::get_irc_server_options(owner2, server);
|
||||||
|
|
||||||
|
auto after_connection_commands = Database::get_after_connection_commands(soptions);
|
||||||
|
CHECK(after_connection_commands.empty());
|
||||||
|
|
||||||
|
soptions.save(Database::db);
|
||||||
|
soptions2.save(Database::db);
|
||||||
|
auto com = Database::after_connection_commands.row();
|
||||||
|
com.col<Database::AfterConnectionCommand>() = "first";
|
||||||
|
after_connection_commands.push_back(com);
|
||||||
|
com.col<Database::AfterConnectionCommand>() = "second";
|
||||||
|
after_connection_commands.push_back(com);
|
||||||
|
Database::set_after_connection_commands(soptions, after_connection_commands);
|
||||||
|
|
||||||
|
after_connection_commands.clear();
|
||||||
|
com.col<Database::AfterConnectionCommand>() = "first";
|
||||||
|
after_connection_commands.push_back(com);
|
||||||
|
com.col<Database::AfterConnectionCommand>() = "second";
|
||||||
|
after_connection_commands.push_back(com);
|
||||||
|
Database::set_after_connection_commands(soptions2, after_connection_commands);
|
||||||
|
|
||||||
|
after_connection_commands = Database::get_after_connection_commands(soptions);
|
||||||
|
CHECK(after_connection_commands.size() == 2);
|
||||||
|
after_connection_commands = Database::get_after_connection_commands(soptions2);
|
||||||
|
CHECK(after_connection_commands.size() == 2);
|
||||||
|
|
||||||
|
after_connection_commands.clear();
|
||||||
|
after_connection_commands.push_back(com);
|
||||||
|
Database::set_after_connection_commands(soptions, after_connection_commands);
|
||||||
|
|
||||||
|
after_connection_commands = Database::get_after_connection_commands(soptions);
|
||||||
|
CHECK(after_connection_commands.size() == 1);
|
||||||
|
after_connection_commands = Database::get_after_connection_commands(soptions2);
|
||||||
|
CHECK(after_connection_commands.size() == 2);
|
||||||
|
}
|
||||||
|
|
||||||
Database::close();
|
Database::close();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2701,7 +2701,7 @@ if __name__ == '__main__':
|
|||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='boolean'][@var='verify_cert']/dataform:value[text()='true']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='boolean'][@var='verify_cert']/dataform:value[text()='true']",
|
||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='fingerprint']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='fingerprint']",
|
||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-private'][@var='pass']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-private'][@var='pass']",
|
||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='after_connect_command']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-multi'][@var='after_connect_commands']",
|
||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='username']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='username']",
|
||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='realname']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='realname']",
|
||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='encoding_in']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='encoding_in']",
|
||||||
@@ -2718,7 +2718,7 @@ if __name__ == '__main__':
|
|||||||
"<field var='verify_cert'><value>1</value></field>"
|
"<field var='verify_cert'><value>1</value></field>"
|
||||||
"<field var='fingerprint'><value>12:12:12</value></field>"
|
"<field var='fingerprint'><value>12:12:12</value></field>"
|
||||||
"<field var='pass'><value>coucou</value></field>"
|
"<field var='pass'><value>coucou</value></field>"
|
||||||
"<field var='after_connect_command'><value>INVALID command</value></field>"
|
"<field var='after_connect_commands'><value>first command</value><value>second command</value></field>"
|
||||||
"<field var='username'><value>username</value></field>"
|
"<field var='username'><value>username</value></field>"
|
||||||
"<field var='realname'><value>realname</value></field>"
|
"<field var='realname'><value>realname</value></field>"
|
||||||
"<field var='encoding_out'><value>UTF-8</value></field>"
|
"<field var='encoding_out'><value>UTF-8</value></field>"
|
||||||
@@ -2736,7 +2736,8 @@ if __name__ == '__main__':
|
|||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='boolean'][@var='verify_cert']/dataform:value[text()='true']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='boolean'][@var='verify_cert']/dataform:value[text()='true']",
|
||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='fingerprint']/dataform:value[text()='12:12:12']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='fingerprint']/dataform:value[text()='12:12:12']",
|
||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-private'][@var='pass']/dataform:value[text()='coucou']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-private'][@var='pass']/dataform:value[text()='coucou']",
|
||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='after_connect_command']/dataform:value[text()='INVALID command']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-multi'][@var='after_connect_commands']/dataform:value[text()='first command']",
|
||||||
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-multi'][@var='after_connect_commands']/dataform:value[text()='second command']",
|
||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='username']/dataform:value[text()='username']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='username']/dataform:value[text()='username']",
|
||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='realname']/dataform:value[text()='realname']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='realname']/dataform:value[text()='realname']",
|
||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='encoding_in']/dataform:value[text()='latin-1']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-single'][@var='encoding_in']/dataform:value[text()='latin-1']",
|
||||||
@@ -2757,7 +2758,7 @@ if __name__ == '__main__':
|
|||||||
"<command xmlns='http://jabber.org/protocol/commands' node='configure' sessionid='{sessionid}' action='next'>"
|
"<command xmlns='http://jabber.org/protocol/commands' node='configure' sessionid='{sessionid}' action='next'>"
|
||||||
"<x xmlns='jabber:x:data' type='submit'>"
|
"<x xmlns='jabber:x:data' type='submit'>"
|
||||||
"<field var='pass'><value></value></field>"
|
"<field var='pass'><value></value></field>"
|
||||||
"<field var='after_connect_command'><value></value></field>"
|
"<field var='after_connect_commands'></field>"
|
||||||
"<field var='username'><value></value></field>"
|
"<field var='username'><value></value></field>"
|
||||||
"<field var='realname'><value></value></field>"
|
"<field var='realname'><value></value></field>"
|
||||||
"<field var='encoding_out'><value></value></field>"
|
"<field var='encoding_out'><value></value></field>"
|
||||||
@@ -2770,7 +2771,7 @@ if __name__ == '__main__':
|
|||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:title[text()='Configure the IRC server irc.localhost']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:title[text()='Configure the IRC server irc.localhost']",
|
||||||
"/iq/commands:command/dataform:x[@type='form']/dataform:instructions[text()='Edit the form, to configure the settings of the IRC server irc.localhost']",
|
"/iq/commands:command/dataform:x[@type='form']/dataform:instructions[text()='Edit the form, to configure the settings of the IRC server irc.localhost']",
|
||||||
"!/iq/commands:command/dataform:x[@type='form']/dataform:field[@var='pass']/dataform:value",
|
"!/iq/commands:command/dataform:x[@type='form']/dataform:field[@var='pass']/dataform:value",
|
||||||
"!/iq/commands:command/dataform:x[@type='form']/dataform:field[@var='after_connect_command']/dataform:value",
|
"!/iq/commands:command/dataform:x[@type='form']/dataform:field[@var='after_connect_commands']/dataform:value",
|
||||||
"!/iq/commands:command/dataform:x[@type='form']/dataform:field[@var='username']/dataform:value",
|
"!/iq/commands:command/dataform:x[@type='form']/dataform:field[@var='username']/dataform:value",
|
||||||
"!/iq/commands:command/dataform:x[@type='form']/dataform:field[@var='realname']/dataform:value",
|
"!/iq/commands:command/dataform:x[@type='form']/dataform:field[@var='realname']/dataform:value",
|
||||||
"!/iq/commands:command/dataform:x[@type='form']/dataform:field[@var='encoding_in']/dataform:value",
|
"!/iq/commands:command/dataform:x[@type='form']/dataform:field[@var='encoding_in']/dataform:value",
|
||||||
|
|||||||
Reference in New Issue
Block a user