Created
March 13, 2025 19:08
-
-
Save matheusfillipe/b02a8e26bae360930315f05654a8994c to your computer and use it in GitHub Desktop.
Unrealircd 6.x relaymsg module
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* draft/relaymsg module for UnrealIRCd | |
* | |
* This module implements a minimal IRCv3 draft/relaymsg handler that relays | |
* PRIVMSG/NOTICE messages with an overridden source to channels. | |
* | |
* The RELAYMSG command format is: | |
* RELAYMSG <target> <relayprefix> <command> <parameters...> | |
* | |
* Only channel targets (beginning with '#' or '&') are supported. | |
* | |
* The module creates a minimal fake Client whose nick is derived from | |
* <relayprefix> (expected in "nick!user@host" format) and uses sendto_channel() | |
* to deliver the message. | |
* | |
* NOTE: This is a minimal example for demonstration purposes. | |
*/ | |
#include "unrealircd.h" | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdio.h> | |
/* Module header */ | |
ModuleHeader MOD_HEADER = { | |
"third/relaymsg", /* Module name */ | |
"0.0.1", | |
"Provides minimal IRCv3 draft/relaymsg support for relaying PRIVMSG/NOTICE with an overridden source to channels", | |
"Matheus Fillipe", /* author */ | |
"unrealircd-6", /* do not change this, it indicates module API version */ | |
}; | |
/* | |
* Declaration for find_channel(), assumed to be exported. | |
*/ | |
extern Channel *find_channel(const char *chan); | |
/* | |
* Minimal fake client creation. | |
* | |
* Allocates a Client and copies the nick portion (up to the first '!') | |
* from the relay prefix into client->name. | |
* | |
* Adjust this code if your Client structure differs. | |
*/ | |
static Client *create_fake_client(const char *prefix) { | |
Client *client = calloc(1, sizeof(Client)); | |
if (!client) | |
return NULL; | |
{ | |
const char *bang = strchr(prefix, '!'); | |
if (bang) { | |
size_t nicklen = bang - prefix; | |
strlcpy(client->name, prefix, nicklen + 1); | |
} else { | |
strlcpy(client->name, prefix, sizeof(client->name)); | |
} | |
} | |
/* Mark as local by setting client->local to a non-NULL dummy pointer */ | |
client->local = (LocalClient *)1; | |
return client; | |
} | |
/* | |
* Free the fake client. | |
* | |
* Since the string fields are stored in fixed arrays inside Client, | |
* simply free the client. | |
*/ | |
static void destroy_fake_client(Client *client) { | |
if (client) | |
free(client); | |
} | |
/* | |
* relaymsg_cmd - handle the RELAYMSG command. | |
* | |
* Expected parameters: | |
* [0] - "RELAYMSG" | |
* [1] - <target> : the channel (must begin with '#' or '&'). | |
* [2] - <relayprefix> : full prefix to use as source ("nick!user@host"). | |
* [3] - <command> : the command to relay (typically PRIVMSG or NOTICE). | |
* [4...] - <parameters...> : message text. | |
*/ | |
CMD_FUNC(relaymsg_cmd) { | |
char message[1024]; | |
int i; | |
if (parc < 4) { | |
sendto_server(client, 0UL, 0UL, NULL, "ERROR :Not enough parameters for RELAYMSG"); | |
return; | |
} | |
const char *target = parv[1]; | |
const char *relayprefix = parv[2]; | |
const char *relaycmd = parv[3]; | |
/* Concatenate remaining parameters into the message */ | |
message[0] = '\0'; | |
for (i = 4; i < parc; i++) { | |
if (i > 4) | |
strlcat(message, " ", sizeof(message)); | |
strlcat(message, parv[i], sizeof(message)); | |
} | |
/* Only support channel targets */ | |
if (target[0] != '#' && target[0] != '&') { | |
sendto_server(client, 0UL, 0UL, NULL, "ERROR :Target must be a channel"); | |
return; | |
} | |
Channel *chan = find_channel(target); | |
if (!chan) { | |
sendto_server(client, 0UL, 0UL, NULL, "ERROR :No such channel"); | |
return; | |
} | |
Client *fake = create_fake_client(relayprefix); | |
if (!fake) { | |
sendto_server(client, 0UL, 0UL, NULL, "ERROR :Unable to create fake client for RELAYMSG"); | |
return; | |
} | |
/* Relay the message to the channel. | |
* | |
* sendto_channel() signature (example): | |
* void sendto_channel(Channel *channel, Client *from, Client *skip, | |
* char *member_modes, long clicap, int sendflags, | |
* const char *cmd, const char *format, ...); | |
* | |
* Here: | |
* - from is our fake client, | |
* - skip is NULL, | |
* - member_modes is NULL, | |
* - clicap is 0, | |
* - sendflags is 0. | |
*/ | |
sendto_channel(chan, fake, NULL, NULL, 0, SEND_ALL, relaycmd, ":%s", message); | |
destroy_fake_client(fake); | |
} | |
/* | |
* Module initialization. | |
* | |
* Register the "RELAYMSG" command using CommandAdd(). | |
*/ | |
MOD_INIT() { | |
if (!CommandAdd(modinfo->handle, "RELAYMSG", relaymsg_cmd, 4, CMD_OPER)) | |
return MOD_FAILED; | |
return MOD_SUCCESS; | |
} | |
/* | |
* Module unload function. | |
*/ | |
MOD_DESTROY() { | |
return MOD_SUCCESS; | |
} | |
MOD_LOAD() | |
{ | |
/* Do necessary initialization for when module is loaded */ | |
/* For example: CommandOverrideAdd() */ | |
return MOD_SUCCESS; /* returning anything else is not really supported here */ | |
} | |
MOD_UNLOAD() | |
{ | |
// Perform any cleanup for unload | |
return MOD_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment