|
|
|
|
@@ -1733,6 +1733,9 @@ struct server
|
|
|
|
|
char *irc_idchan_prefixes; ///< Prefixes for "safe channels"
|
|
|
|
|
char *irc_statusmsg; ///< Prefixes for channel targets
|
|
|
|
|
|
|
|
|
|
char irc_extban_prefix; ///< EXTBAN prefix or \0
|
|
|
|
|
char *irc_extban_types; ///< EXTBAN types
|
|
|
|
|
|
|
|
|
|
char *irc_chanmodes_list; ///< Channel modes for lists
|
|
|
|
|
char *irc_chanmodes_param_always; ///< Channel modes with mandatory param
|
|
|
|
|
char *irc_chanmodes_param_when_set; ///< Channel modes with param when set
|
|
|
|
|
@@ -1781,6 +1784,9 @@ server_init_specifics (struct server *self)
|
|
|
|
|
self->irc_idchan_prefixes = xstrdup ("");
|
|
|
|
|
self->irc_statusmsg = xstrdup ("");
|
|
|
|
|
|
|
|
|
|
self->irc_extban_prefix = 0;
|
|
|
|
|
self->irc_extban_types = xstrdup ("");
|
|
|
|
|
|
|
|
|
|
self->irc_chanmodes_list = xstrdup ("b");
|
|
|
|
|
self->irc_chanmodes_param_always = xstrdup ("k");
|
|
|
|
|
self->irc_chanmodes_param_when_set = xstrdup ("l");
|
|
|
|
|
@@ -1799,6 +1805,8 @@ server_free_specifics (struct server *self)
|
|
|
|
|
free (self->irc_idchan_prefixes);
|
|
|
|
|
free (self->irc_statusmsg);
|
|
|
|
|
|
|
|
|
|
free (self->irc_extban_types);
|
|
|
|
|
|
|
|
|
|
free (self->irc_chanmodes_list);
|
|
|
|
|
free (self->irc_chanmodes_param_always);
|
|
|
|
|
free (self->irc_chanmodes_param_when_set);
|
|
|
|
|
@@ -3039,6 +3047,20 @@ irc_skip_statusmsg (struct server *s, const char *target)
|
|
|
|
|
return target + (*target && strchr (s->irc_statusmsg, *target));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
irc_is_extban (struct server *s, const char *target)
|
|
|
|
|
{
|
|
|
|
|
// Some servers have a prefix, and some support negation
|
|
|
|
|
if (s->irc_extban_prefix && *target++ != s->irc_extban_prefix)
|
|
|
|
|
return false;
|
|
|
|
|
if (*target == '~')
|
|
|
|
|
target++;
|
|
|
|
|
|
|
|
|
|
// XXX: we don't know if it's supposed to have an argument, or not
|
|
|
|
|
return *target && strchr (s->irc_extban_types, *target++)
|
|
|
|
|
&& strchr (":\0", *target);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
|
|
|
|
|
|
|
|
// As of 2020, everything should be in UTF-8. And if it's not, we'll decode it
|
|
|
|
|
@@ -4101,6 +4123,13 @@ buffer_open_log_file (struct app_context *ctx, struct buffer *buffer)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// TODO: should we try to reopen files wrt. case mapping?
|
|
|
|
|
// - Need to read the whole directory and look for matches:
|
|
|
|
|
// irc_server_strcmp(buffer->s, d_name, make_log_filename())
|
|
|
|
|
// remember to strip the ".log" suffix from d_name, case-sensitively.
|
|
|
|
|
// - The tolower_ascii() in make_log_filename() is a perfect overlap,
|
|
|
|
|
// it may stay as-is.
|
|
|
|
|
// - buffer_get_log_path() will need to return a FILE *,
|
|
|
|
|
// or an error that includes the below message.
|
|
|
|
|
char *path = buffer_get_log_path (buffer);
|
|
|
|
|
if (!(buffer->log_file = fopen (path, "ab")))
|
|
|
|
|
log_global_error (ctx, "Couldn't open log file `#s': #l",
|
|
|
|
|
@@ -7919,6 +7948,16 @@ irc_handle_isupport_statusmsg (struct server *s, char *value)
|
|
|
|
|
cstr_set (&s->irc_statusmsg, xstrdup (value));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
irc_handle_isupport_extban (struct server *s, char *value)
|
|
|
|
|
{
|
|
|
|
|
s->irc_extban_prefix = 0;
|
|
|
|
|
if (*value && *value != ',')
|
|
|
|
|
s->irc_extban_prefix = *value++;
|
|
|
|
|
|
|
|
|
|
cstr_set (&s->irc_extban_types, xstrdup (*value == ',' ? ++value : ""));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
irc_handle_isupport_chanmodes (struct server *s, char *value)
|
|
|
|
|
{
|
|
|
|
|
@@ -7975,6 +8014,7 @@ dispatch_isupport (struct server *s, const char *name, char *value)
|
|
|
|
|
MATCH ("CHANTYPES", irc_handle_isupport_chantypes);
|
|
|
|
|
MATCH ("IDCHAN", irc_handle_isupport_idchan);
|
|
|
|
|
MATCH ("STATUSMSG", irc_handle_isupport_statusmsg);
|
|
|
|
|
MATCH ("EXTBAN", irc_handle_isupport_extban);
|
|
|
|
|
MATCH ("CHANMODES", irc_handle_isupport_chanmodes);
|
|
|
|
|
MATCH ("MODES", irc_handle_isupport_modes);
|
|
|
|
|
|
|
|
|
|
@@ -8132,8 +8172,8 @@ irc_process_message (const struct irc_message *msg, struct server *s)
|
|
|
|
|
irc_sanitize_cut_off_utf8 (&msg->params.vector[msg->params.len - 1]);
|
|
|
|
|
|
|
|
|
|
// TODO: make use of IRCv3.2 server-time (with fallback to unixtime_msec())
|
|
|
|
|
// -> change all calls to log_{server,nick,outcoming,ctcp}*() to take
|
|
|
|
|
// an extra argument specifying time
|
|
|
|
|
// -> change all calls to log_{server,nick,chghost,outcoming,ctcp}*()
|
|
|
|
|
// to take an extra numeric argument specifying time
|
|
|
|
|
struct irc_handler key = { .name = msg->command };
|
|
|
|
|
struct irc_handler *handler = bsearch (&key, g_irc_handlers,
|
|
|
|
|
N_ELEMENTS (g_irc_handlers), sizeof key, irc_handler_cmp_by_name);
|
|
|
|
|
@@ -11559,7 +11599,8 @@ handle_command_topic (struct handler_args *a)
|
|
|
|
|
if (*a->arguments)
|
|
|
|
|
// FIXME: there's no way to start the topic with whitespace
|
|
|
|
|
// FIXME: there's no way to unset the topic;
|
|
|
|
|
// we could adopt the Tcl style of "-switches" with "--" sentinels
|
|
|
|
|
// we could adopt the Tcl style of "-switches" with "--" sentinels,
|
|
|
|
|
// or we could accept "strings" in the config format
|
|
|
|
|
irc_send (a->s, "TOPIC %s :%s", a->channel_name, a->arguments);
|
|
|
|
|
else
|
|
|
|
|
irc_send (a->s, "TOPIC %s", a->channel_name);
|
|
|
|
|
@@ -11638,8 +11679,7 @@ mass_channel_mode_mask_list
|
|
|
|
|
for (size_t i = 0; i < v.len; i++)
|
|
|
|
|
{
|
|
|
|
|
char *target = v.vector[i];
|
|
|
|
|
// TODO: support EXTBAN and leave those alone, too
|
|
|
|
|
if (strpbrk (target, "!@*?"))
|
|
|
|
|
if (strpbrk (target, "!@*?") || irc_is_extban (a->s, target))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
v.vector[i] = xstrdup_printf ("%s!*@*", target);
|
|
|
|
|
@@ -12188,8 +12228,9 @@ handle_command_help (struct handler_args *a)
|
|
|
|
|
if (!*a->arguments)
|
|
|
|
|
return show_command_list (ctx);
|
|
|
|
|
|
|
|
|
|
// TODO: we should probably also accept commands names with a leading slash
|
|
|
|
|
char *command = cut_word (&a->arguments);
|
|
|
|
|
const char *word = cut_word (&a->arguments);
|
|
|
|
|
|
|
|
|
|
const char *command = word + (*word == '/');
|
|
|
|
|
for (size_t i = 0; i < N_ELEMENTS (g_command_handlers); i++)
|
|
|
|
|
{
|
|
|
|
|
struct command_handler *handler = &g_command_handlers[i];
|
|
|
|
|
@@ -12197,13 +12238,13 @@ handle_command_help (struct handler_args *a)
|
|
|
|
|
return show_command_help (ctx, handler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (try_handle_command_help_option (ctx, command))
|
|
|
|
|
if (try_handle_command_help_option (ctx, word))
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
if (str_map_find (get_aliases_config (ctx), command))
|
|
|
|
|
log_global_status (ctx, "/#s is an alias", command);
|
|
|
|
|
else
|
|
|
|
|
log_global_error (ctx, "#s: #s", "No such command or option", command);
|
|
|
|
|
log_global_error (ctx, "#s: #s", "No such command or option", word);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -12278,6 +12319,12 @@ expand_alias_escape (const char *p, const char *arguments, struct str *output)
|
|
|
|
|
cstr_split (arguments, " ", true, &words);
|
|
|
|
|
|
|
|
|
|
// TODO: eventually also add support for argument ranges
|
|
|
|
|
// - Can use ${0}, ${0:}, ${:0}, ${1:-1} with strtol, dispose of $1 syntax
|
|
|
|
|
// (default aliases don't use numeric arguments).
|
|
|
|
|
// - Start numbering from zero, since we'd have to figure out what to do
|
|
|
|
|
// in case we encounter a zero if we keep the current approach.
|
|
|
|
|
// - Ignore the sequence altogether if no closing '}' can be found,
|
|
|
|
|
// or if the internal format doesn't fit the above syntax.
|
|
|
|
|
if (*p >= '1' && *p <= '9')
|
|
|
|
|
{
|
|
|
|
|
size_t offset = *p - '1';
|
|
|
|
|
|