Skip to content

Commit

Permalink
mod_chanserv: Allow ChanServ to invite users.
Browse files Browse the repository at this point in the history
Adds INVITE command support to ChanServ, so that
channel operators can use ChanServ to invite themselves
to channels with +i. (GUARD needs to be enabled for
this to work if the channel is otherwise empty).

Other IRC-related fixes:

net_irc: Remove extra data from 433 response.
mod_irc_client: Add specific handling for DCC.
mod_discord: Fix formatting width in "discord users".
mod_chanserv: Add missing syntax for MLOCK.
mod_chanserv: Don't print garbage for NULL columns.
  • Loading branch information
InterLinked1 committed Dec 23, 2023
1 parent 2de063e commit 065c5ab
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 7 deletions.
47 changes: 46 additions & 1 deletion modules/mod_chanserv.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,14 @@ static int sql_fetch_strings(const char *username, const char *channel, void cb(
}

while (MYSQL_NEXT_ROW(stmt)) {
/* If a row is empty, set the string to empty.
* We need to do this per record, not just once at the beginning,
* since a column could be non-NULL for one record and then NULL for another. */
for (i = 0; i < num_fields; i++) {
if (bind_null[i]) {
strfields[i][0] = '\0';
}
}
cb(username, bind_strings, rownum++, data); /* Only call on success */
res = 0;
}
Expand Down Expand Up @@ -215,6 +223,14 @@ static int sql_fetch_strings2(const char *username, const char *channel, const c
}

while (MYSQL_NEXT_ROW(stmt)) {
/* If a row is empty, set the string to empty.
* We need to do this per record, not just once at the beginning,
* since a column could be non-NULL for one record and then NULL for another. */
for (i = 0; i < num_fields; i++) {
if (bind_null[i]) {
strfields[i][0] = '\0';
}
}
cb(username, bind_strings, rownum++, data); /* Only call on success */
res = 0;
}
Expand Down Expand Up @@ -620,11 +636,35 @@ static void chanserv_info(const char *username, char *msg)
}
}

static void chanserv_invite(const char *username, char *channel)
{
int res;

if (strlen_zero(channel)) {
chanserv_notice(username, " Insufficient parameters for INVITE");
chanserv_notice(username, "Syntax: INFO <#channel>");
return;
}

/* Only channel operators can invite themselves to a channel */
res = channel_unauthorized(channel, username, CHANNEL_USER_MODE_OP);
if (res > 0) {
/* Channel is already registered with ChanServ */
chanserv_notice(username, "You are not authorized to perform this operation.");
return;
} else if (res < 0) {
chanserv_notice(username, "%s is not registered.", channel);
return;
}

chanserv_send("INVITE %s %s", username, channel);
}

static struct chanserv_subcmd chanserv_set_cmds[] =
{
{ "ENTRYMSG", "Sets the channel entry message.", "SET ENTRYMSG allows you to change or set a message sent to all users joining the channel.\r\n" "Syntax: SET <#channel> ENTRYMSG [message]" },
{ "GUARD", "Sets whether or not services will inhabit the channel.", "SET GUARD allows you to have ChanServ join your channel.\r\nSyntax: SET <#channel> GUARD ON|OFF" },
{ "MLOCK", "Sets channel mode lock.", "MLOCK (or \"mode lock\") allows you to enforce a set of modes on a channel." },
{ "MLOCK", "Sets channel mode lock.", "MLOCK (or \"mode lock\") allows you to enforce a set of modes on a channel.\r\nSyntax: SET <#channel> MLOCK [modes]" },
{ "KEEPTOPIC", "Enables topic retention.", "SET KEEPTOPIC enables restoration of the old topic after the channel has become empty.\r\nIn some cases, it may revert topic changes after services outages, so it is\r\nnot recommended to turn this on if your channel tends to never empty." }
};

Expand Down Expand Up @@ -709,6 +749,8 @@ static void chanserv_set(const char *username, char *msg)
if (!strlen_zero(params)) {
chanserv_send("MODE %s %s", channel, params);
} /* else, leave any existing modes intact if MLOCK if removed. */
} else {
chanserv_notice(username, "SET MLOCK operation failed.");
}
} else {
chanserv_notice(username, "Invalid ChanServ SET subcommand.");
Expand Down Expand Up @@ -863,6 +905,9 @@ static struct chanserv_cmd chanserv_cmds[] =
"Syntax: HELP <command> [parameters]" },
{ "INFO", chanserv_info, NULL, 0, "Displays information on registrations.", "INFO displays channel information such as registration time, flags, and other details.\r\n"
"Syntax: INFO <#channel>" },
{ "INVITE", chanserv_invite, NULL, 0, "Invites you to a channel.", "INVITE requests services to invite you to the specified channel\r\n"
"This is useful if you use the +i channel mode.\r\n"
"Syntax: INVITE <#channel>" },
{ "OP", chanserv_op, NULL, 0, "Gives channel ops to a user.", "These commands perform status mode changes on a channel.\r\n"
"If the last parameter is omitted the action is performed on the person requesting the command.\r\n"
"Syntax: OP <#channel> [nickname]" },
Expand Down
4 changes: 2 additions & 2 deletions modules/mod_discord.c
Original file line number Diff line number Diff line change
Expand Up @@ -1287,12 +1287,12 @@ static int cli_discord_users(struct bbs_cli_args *a)
int i = 0;
struct user *u;

bbs_dprintf(a->fdout, "%-20s %7s %5s\n", "User", "Status", "Roles");
bbs_dprintf(a->fdout, "%-40s %7s %5s\n", "User", "Status", "Roles");
RWLIST_RDLOCK(&users);
RWLIST_TRAVERSE(&users, u, entry) {
char buf[48];
snprintf(buf, sizeof(buf), "%s#%s\n", u->username, u->discriminator);
bbs_dprintf(a->fdout, "%-20s %7s %5d" "%s\n", buf, status_str(u->status), u->numroles, u->admin ? " [Guild Admin]" : "");
bbs_dprintf(a->fdout, "%-40s %7s %5d" "%s\n", buf, status_str(u->status), u->numroles, u->admin ? " [Guild Admin]" : "");
i++;
}
RWLIST_UNLOCK(&users);
Expand Down
33 changes: 30 additions & 3 deletions modules/mod_irc_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@

#include "include/mod_irc_client.h"

#define MIN_VERSION_REQUIRED SEMVER_VERSION(0,2,0)
#define MIN_VERSION_REQUIRED SEMVER_VERSION(0,2,1)
#if SEMVER_VERSION(LIRC_VERSION_MAJOR, LIRC_VERSION_MINOR, LIRC_VERSION_PATCH) < MIN_VERSION_REQUIRED
#error "lirc version too old"
#endif
Expand Down Expand Up @@ -536,6 +536,28 @@ static void handle_ctcp(struct bbs_irc_client *client, struct irc_client *ircl,
irc_client_ctcp_reply(ircl, irc_msg_prefix(msg), ctcp, timebuf);
}
break;
case CTCP_DCC:
/* Unimplemented:
* Because DCC can't be used to send files by users behind a firewall,
* it is not very useful these days:
* https://www.kvirc.net/doc/doc_dcc_connection.html
*
* DCC SEND is more interesting than DCC CHAT,
* since it can be used to send files peer-to-peer.
* However, the receiver has to connect to the server (like with FTP active mode),
* making this virtually unusable in the modern Internet.
*
* A neat idea I had was to allow IRC uses to DCC SEND to a bot,
* with integrated relay support, e.g. IRC users could use DCC SEND
* to upload files as attachments to Discord, for example.
* But since users are expected to be behind NAT and a firewall,
* use of DCC is altogether unlikely to work for anyone.
*
* Ambassador does support size, e.g.:
* SEND filename 1216726377 52309 193273
*/
bbs_warning("Direct Client Connection CHAT/SEND not supported\n");
break;
default:
bbs_warning("Unhandled CTCP extended data type: %s\n", irc_ctcp_name(irc_msg_ctcp_type(msg)));
}
Expand Down Expand Up @@ -722,9 +744,14 @@ int __attribute__ ((format (gnu_printf, 4, 5))) bbs_irc_client_msg(const char *c
* which is what would happen now.
* Omitting this for now is more correct, but means messages from the local IRC server
* will get relayed to other actual IRC channels but not to door_irc, for example.
* Might work if we skip the sending module? Or maybe not??? */
* Might work if we skip the sending module? Or maybe not???
*
* This is delicate though: with just RELAY_TO_IRC, messages work between
* relay modules and door_irc but not with the native net_irc IRC network.
*/

res = msg_relay(client, RELAY_TO_IRC, IRC_CMD_PRIVMSG, channel, prefix, 0, buf, (size_t) len); /* No prefix */
bbs_debug(7, "Relaying message: client '%s' channel '%s' prefix '%s'\n", clientname, channel, S_IF(prefix));
res = msg_relay(client, RELAY_TO_IRC | RELAY_FROM_IRC, IRC_CMD_PRIVMSG, channel, prefix, 0, buf, (size_t) len); /* No prefix */

RWLIST_UNLOCK(&irc_clients);
return res;
Expand Down
4 changes: 3 additions & 1 deletion nets/net_irc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2314,7 +2314,7 @@ static void handle_nick(struct irc_user *user, char *s)
}

if (bbs_user_exists(s)) {
send_numeric(user, 433, "%s :Nickname is already in use.\r\n", s);
send_numeric(user, 433, "%s\r\n", s);
send_reply(user, "NOTICE AUTH :*** This nickname is registered. Please choose a different nickname, or identify using NickServ\r\n");
/* Client will need to send NS IDENTIFY <password> or PRIVMSG NickServ :IDENTIFY <password> */
} else { /* Nickname is not claimed. It's fine. */
Expand Down Expand Up @@ -3445,6 +3445,8 @@ int __chanserv_exec(void *mod, char *s)
handle_modes(user, s);
} else if (!strcasecmp(command, "TOPIC")) {
handle_topic(user, s);
} else if (!strcasecmp(command, "INVITE")) {
handle_invite(user, s);
} else {
bbs_error("Command '%s' is unsupported for ChanServ\n", command);
return -1;
Expand Down

0 comments on commit 065c5ab

Please sign in to comment.