summaryrefslogtreecommitdiff
path: root/src/map/channel.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/channel.c')
-rw-r--r--src/map/channel.c205
1 files changed, 111 insertions, 94 deletions
diff --git a/src/map/channel.c b/src/map/channel.c
index 3d1b3f975..43e903fc9 100644
--- a/src/map/channel.c
+++ b/src/map/channel.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2015 Hercules Dev Team
+ * Copyright (C) 2013-2020 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,6 +26,7 @@
#include "map/instance.h"
#include "map/irc-bot.h"
#include "map/map.h"
+#include "map/npc.h"
#include "map/pc.h"
#include "common/cbasetypes.h"
#include "common/conf.h"
@@ -43,7 +44,7 @@
#include <stdlib.h>
#include <string.h>
-struct channel_interface channel_s;
+static struct channel_interface channel_s;
struct channel_interface *channel;
static struct Channel_Config channel_config;
@@ -55,7 +56,7 @@ static struct Channel_Config channel_config;
* @param sd The issuer character, for character-specific channels (i.e. map, ally)
* @return a pointer to the channel, or NULL.
*/
-struct channel_data *channel_search(const char *name, struct map_session_data *sd)
+static struct channel_data *channel_search(const char *name, struct map_session_data *sd)
{
const char *realname = name;
if (!realname || !*realname)
@@ -94,7 +95,7 @@ struct channel_data *channel_search(const char *name, struct map_session_data *s
* @param color The channel chat color.
* @return A pointer to the created channel.
*/
-struct channel_data *channel_create(enum channel_types type, const char *name, unsigned char color)
+static struct channel_data *channel_create(enum channel_types type, const char *name, unsigned char color)
{
struct channel_data *chan;
@@ -122,7 +123,7 @@ struct channel_data *channel_create(enum channel_types type, const char *name, u
*
* @param chan The channel to delete
*/
-void channel_delete(struct channel_data *chan)
+static void channel_delete(struct channel_data *chan)
{
nullpo_retv(chan);
@@ -155,7 +156,7 @@ void channel_delete(struct channel_data *chan)
* @param chan The channel to edit.
* @param pass The password to set. Pass NULL to remove existing passwords.
*/
-void channel_set_password(struct channel_data *chan, const char *password)
+static void channel_set_password(struct channel_data *chan, const char *password)
{
nullpo_retv(chan);
if (password)
@@ -175,7 +176,7 @@ void channel_set_password(struct channel_data *chan, const char *password)
* @retval HCS_STATUS_NOPERM if the source character doesn't have enough permissions.
* @retval HCS_STATUS_FAIL in case of generic failure.
*/
-enum channel_operation_status channel_ban(struct channel_data *chan, const struct map_session_data *ssd, struct map_session_data *tsd)
+static enum channel_operation_status channel_ban(struct channel_data *chan, const struct map_session_data *ssd, struct map_session_data *tsd)
{
struct channel_ban_entry *entry = NULL;
@@ -214,7 +215,7 @@ enum channel_operation_status channel_ban(struct channel_data *chan, const struc
* @retval HCS_STATUS_NOPERM if the source character doesn't have enough permissions.
* @retval HCS_STATUS_FAIL in case of generic failure.
*/
-enum channel_operation_status channel_unban(struct channel_data *chan, const struct map_session_data *ssd, struct map_session_data *tsd)
+static enum channel_operation_status channel_unban(struct channel_data *chan, const struct map_session_data *ssd, struct map_session_data *tsd)
{
nullpo_retr(HCS_STATUS_FAIL, chan);
@@ -250,7 +251,7 @@ enum channel_operation_status channel_unban(struct channel_data *chan, const str
* @param chan The channel.
* @param options The new options set to apply.
*/
-void channel_set_options(struct channel_data *chan, unsigned int options)
+static void channel_set_options(struct channel_data *chan, unsigned int options)
{
nullpo_retv(chan);
@@ -266,7 +267,7 @@ void channel_set_options(struct channel_data *chan, unsigned int options)
*
* If no source character is specified, it'll send an anonymous message.
*/
-void channel_send(struct channel_data *chan, struct map_session_data *sd, const char *msg)
+static void channel_send(struct channel_data *chan, struct map_session_data *sd, const char *msg)
{
char message[150];
nullpo_retv(chan);
@@ -275,15 +276,26 @@ void channel_send(struct channel_data *chan, struct map_session_data *sd, const
if (sd && chan->msg_delay != 0
&& DIFF_TICK(sd->hchsysch_tick + chan->msg_delay*1000, timer->gettick()) > 0
&& !pc_has_permission(sd, PC_PERM_HCHSYS_ADMIN)) {
- clif->messagecolor_self(sd->fd, COLOR_RED, msg_sd(sd,1455));
+ char output[CHAT_SIZE_MAX];
+ sprintf(output, msg_sd(sd, 1455), DIFF_TICK(sd->hchsysch_tick + chan->msg_delay * 1000, timer->gettick()) / 1000); // "You cannot send a message to this channel for another %d seconds."
+ clif->messagecolor_self(sd->fd, COLOR_RED, output);
return;
} else if (sd) {
+ int i;
+
safesnprintf(message, 150, "[ #%s ] %s : %s", chan->name, sd->status.name, msg);
clif->channel_msg(chan,sd,message);
if (chan->type == HCS_TYPE_IRC)
ircbot->relay(sd->status.name,msg);
if (chan->msg_delay != 0)
sd->hchsysch_tick = timer->gettick();
+
+ for (i = 0; i < MAX_EVENTQUEUE; i++) {
+ if (chan->handlers[i][0] != '\0') {
+ pc->setregstr(sd, script->add_variable("@channelmes$"), msg);
+ npc->event(sd, chan->handlers[i], 0);
+ }
+ }
} else {
safesnprintf(message, 150, "[ #%s ] %s", chan->name, msg);
clif->channel_msg2(chan, message);
@@ -299,7 +311,7 @@ void channel_send(struct channel_data *chan, struct map_session_data *sd, const
* @param sd The character
* @param stealth If true, hide join announcements.
*/
-void channel_join_sub(struct channel_data *chan, struct map_session_data *sd, bool stealth)
+static void channel_join_sub(struct channel_data *chan, struct map_session_data *sd, bool stealth)
{
nullpo_retv(chan);
nullpo_retv(sd);
@@ -307,17 +319,17 @@ void channel_join_sub(struct channel_data *chan, struct map_session_data *sd, bo
if (idb_put(chan->users, sd->status.char_id, sd))
return;
- RECREATE(sd->channels, struct channel_data *, ++sd->channel_count);
- sd->channels[sd->channel_count - 1] = chan;
+ VECTOR_ENSURE(sd->channels, 1, 1);
+ VECTOR_PUSH(sd->channels, chan);
if (!stealth && (chan->options&HCS_OPT_ANNOUNCE_JOIN)) {
char message[60];
- sprintf(message, "#%s '%s' joined",chan->name,sd->status.name);
+ sprintf(message, msg_txt(897), chan->name, sd->status.name); // #%s '%s' joined
clif->channel_msg(chan,sd,message);
}
/* someone is cheating, we kindly disconnect the bastard */
- if (sd->channel_count > 200) {
+ if (VECTOR_LENGTH(sd->channels) > 200) {
sockt->eof(sd->fd);
}
@@ -339,7 +351,7 @@ void channel_join_sub(struct channel_data *chan, struct map_session_data *sd, bo
* @retval HCS_STATUS_BANNED if the character is in the channel's ban list
* @retval HCS_STATUS_FAIL in case of generic error
*/
-enum channel_operation_status channel_join(struct channel_data *chan, struct map_session_data *sd, const char *password, bool silent)
+static enum channel_operation_status channel_join(struct channel_data *chan, struct map_session_data *sd, const char *password, bool silent)
{
bool stealth = false;
@@ -397,41 +409,25 @@ enum channel_operation_status channel_join(struct channel_data *chan, struct map
* @param chan The channel to leave
* @param sd The character
*/
-void channel_leave_sub(struct channel_data *chan, struct map_session_data *sd)
+static void channel_leave_sub(struct channel_data *chan, struct map_session_data *sd)
{
- unsigned char i;
+ int i;
nullpo_retv(chan);
nullpo_retv(sd);
- for (i = 0; i < sd->channel_count; i++) {
- if (sd->channels[i] == chan) {
- sd->channels[i] = NULL;
- break;
- }
- }
- if (i < sd->channel_count) {
- unsigned char cursor = 0;
- for (i = 0; i < sd->channel_count; i++) {
- if (sd->channels[i] == NULL)
- continue;
- if (cursor != i) {
- sd->channels[cursor] = sd->channels[i];
- }
- cursor++;
- }
- if (!(sd->channel_count = cursor)) {
- aFree(sd->channels);
- sd->channels = NULL;
- }
+ ARR_FIND(0, VECTOR_LENGTH(sd->channels), i, VECTOR_INDEX(sd->channels, i) == chan);
+ if (i < VECTOR_LENGTH(sd->channels)) {
+ VECTOR_ERASE(sd->channels, i);
}
}
+
/**
* Leaves a channel.
*
* @param chan The channel to leave
* @param sd The character
*/
-void channel_leave(struct channel_data *chan, struct map_session_data *sd)
+static void channel_leave(struct channel_data *chan, struct map_session_data *sd)
{
nullpo_retv(chan);
nullpo_retv(sd);
@@ -446,7 +442,7 @@ void channel_leave(struct channel_data *chan, struct map_session_data *sd)
channel->delete(chan);
} else if (!channel->config->closing && (chan->options & HCS_OPT_ANNOUNCE_JOIN)) {
char message[60];
- sprintf(message, "#%s '%s' left",chan->name,sd->status.name);
+ sprintf(message, msg_txt(898), chan->name, sd->status.name); // #%s '%s' left
clif->channel_msg(chan,sd,message);
}
@@ -460,17 +456,12 @@ void channel_leave(struct channel_data *chan, struct map_session_data *sd)
*
* @param sd The target character
*/
-void channel_quit(struct map_session_data *sd)
+static void channel_quit(struct map_session_data *sd)
{
nullpo_retv(sd);
- while (sd->channel_count > 0) {
+ while (VECTOR_LENGTH(sd->channels) > 0) {
// Loop downward to avoid unnecessary array compactions by channel_leave
- struct channel_data *chan = sd->channels[sd->channel_count-1];
-
- if (chan == NULL) {
- sd->channel_count--;
- continue;
- }
+ struct channel_data *chan = VECTOR_LAST(sd->channels);
channel->leave(chan, sd);
}
@@ -481,7 +472,7 @@ void channel_quit(struct map_session_data *sd)
*
* @param sd The target character (sd must be non null)
*/
-void channel_map_join(struct map_session_data *sd)
+static void channel_map_join(struct map_session_data *sd)
{
nullpo_retv(sd);
if (sd->state.autotrade || sd->state.standalone)
@@ -497,7 +488,7 @@ void channel_map_join(struct map_session_data *sd)
channel->join(map->list[sd->bl.m].channel, sd, "", false);
}
-void channel_irc_join(struct map_session_data *sd)
+static void channel_irc_join(struct map_session_data *sd)
{
struct channel_data *chan = ircbot->channel;
@@ -519,7 +510,7 @@ void channel_irc_join(struct map_session_data *sd)
* @param g_source Source guild
* @param g_ally Allied guild
*/
-void channel_guild_join_alliance(const struct guild *g_source, const struct guild *g_ally)
+static void channel_guild_join_alliance(const struct guild *g_source, const struct guild *g_ally)
{
struct channel_data *chan;
@@ -547,7 +538,7 @@ void channel_guild_join_alliance(const struct guild *g_source, const struct guil
* @param g_source Source guild
* @param g_ally Former allied guild
*/
-void channel_guild_leave_alliance(const struct guild *g_source, const struct guild *g_ally)
+static void channel_guild_leave_alliance(const struct guild *g_source, const struct guild *g_ally)
{
struct channel_data *chan;
@@ -571,22 +562,21 @@ void channel_guild_leave_alliance(const struct guild *g_source, const struct gui
*
* @param sd The character (must be non null)
*/
-void channel_quit_guild(struct map_session_data *sd)
+static void channel_quit_guild(struct map_session_data *sd)
{
- unsigned char i;
-
nullpo_retv(sd);
- for (i = 0; i < sd->channel_count; i++) {
- struct channel_data *chan = sd->channels[i];
+ for (int i = VECTOR_LENGTH(sd->channels) - 1; i >= 0; i--) {
+ // Loop downward to avoid issues when channel->leave() compacts the array
+ struct channel_data *chan = VECTOR_INDEX(sd->channels, i);
- if (chan == NULL || chan->type != HCS_TYPE_ALLY)
+ if (chan->type != HCS_TYPE_ALLY)
continue;
channel->leave(chan, sd);
}
}
-void read_channels_config(void)
+static void read_channels_config(void)
{
struct config_t channels_conf;
struct config_setting_t *chsys = NULL;
@@ -609,7 +599,11 @@ void read_channels_config(void)
local_autojoin = 0, ally_autojoin = 0,
allow_user_channel_creation = 0,
irc_enabled = 0,
- irc_autojoin = 0;
+ irc_autojoin = 0,
+ irc_flood_protection_rate = 0,
+ irc_flood_protection_burst = 0,
+ irc_flood_protection_enabled = 0,
+ channel_opt_msg_delay = 10;
if( !libconfig->setting_lookup_string(settings, "map_local_channel_name", &local_name) )
local_name = "map";
@@ -640,58 +634,52 @@ void read_channels_config(void)
const char *irc_server, *irc_channel,
*irc_nick, *irc_nick_pw;
int irc_use_ghost = 0;
- if( libconfig->setting_lookup_string(settings, "irc_channel_network", &irc_server) ) {
- if( !strstr(irc_server,":") ) {
+ if (!libconfig->setting_lookup_string(settings, "irc_channel_network", &irc_server)) {
+ channel->config->irc = false;
+ ShowWarning("channels.conf : irc channel enabled but irc_channel_network wasn't found, disabling irc channel...\n");
+ } else {
+ char *server = aStrdup(irc_server);
+ char *port = strchr(server, ':');
+ if (port == NULL) {
+ channel->config->irc = false;
+ ShowWarning("channels.conf: network port wasn't found in 'irc_channel_network', disabling irc channel...\n");
+ } else if ((size_t)(port-server) > sizeof channel->config->irc_server - 1) {
channel->config->irc = false;
- ShowWarning("channels.conf : network port wasn't found in 'irc_channel_network', disabling irc channel...\n");
+ ShowWarning("channels.conf: server name is too long in 'irc_channel_network', disabling irc channel...\n");
} else {
- unsigned char d = 0, dlen = strlen(irc_server);
- char server[40];
- if (dlen > 39)
- dlen = 39;
- memset(server, '\0', sizeof(server));
-
- for(d = 0; d < dlen; d++) {
- if(irc_server[d] == ':') {
- memcpy(server, irc_server, d);
- safestrncpy(channel->config->irc_server, server, 40);
- memcpy(server, &irc_server[d+1], dlen - d - 1);
- channel->config->irc_server_port = atoi(server);
- break;
- }
- }
+ *port = '\0';
+ port++;
+ safestrncpy(channel->config->irc_server, server, sizeof channel->config->irc_server);
+ channel->config->irc_server_port = atoi(port);
}
- } else {
- channel->config->irc = false;
- ShowWarning("channels.conf : irc channel enabled but irc_channel_network wasn't found, disabling irc channel...\n");
+ aFree(server);
}
- if( libconfig->setting_lookup_string(settings, "irc_channel_channel", &irc_channel) )
+ if (libconfig->setting_lookup_string(settings, "irc_channel_channel", &irc_channel)) {
safestrncpy(channel->config->irc_channel, irc_channel, 50);
- else {
+ } else {
channel->config->irc = false;
ShowWarning("channels.conf : irc channel enabled but irc_channel_channel wasn't found, disabling irc channel...\n");
}
- if( libconfig->setting_lookup_string(settings, "irc_channel_nick", &irc_nick) ) {
- if( strcmpi(irc_nick,"Hercules_chSysBot") == 0 ) {
+ if (libconfig->setting_lookup_string(settings, "irc_channel_nick", &irc_nick)) {
+ if (strcmpi(irc_nick,"Hercules_chSysBot") == 0) {
sprintf(channel->config->irc_nick, "Hercules_chSysBot%d",rnd()%777);
- } else
+ } else {
safestrncpy(channel->config->irc_nick, irc_nick, 40);
+ }
} else {
channel->config->irc = false;
ShowWarning("channels.conf : irc channel enabled but irc_channel_nick wasn't found, disabling irc channel...\n");
}
- if( libconfig->setting_lookup_string(settings, "irc_channel_nick_pw", &irc_nick_pw) ) {
+ if (libconfig->setting_lookup_string(settings, "irc_channel_nick_pw", &irc_nick_pw)) {
safestrncpy(channel->config->irc_nick_pw, irc_nick_pw, 30);
config_setting_lookup_bool(settings, "irc_channel_use_ghost", &irc_use_ghost);
channel->config->irc_use_ghost = irc_use_ghost;
}
-
}
libconfig->setting_lookup_bool(settings, "map_local_channel_autojoin", &local_autojoin);
libconfig->setting_lookup_bool(settings, "ally_channel_autojoin", &ally_autojoin);
libconfig->setting_lookup_bool(settings, "irc_channel_autojoin", &irc_autojoin);
-
if (local_autojoin)
channel->config->local_autojoin = true;
if (ally_autojoin)
@@ -699,6 +687,26 @@ void read_channels_config(void)
if (irc_autojoin)
channel->config->irc_autojoin = true;
+ libconfig->setting_lookup_bool(settings, "irc_flood_protection_enabled", &irc_flood_protection_enabled);
+
+ if (irc_flood_protection_enabled) {
+ ircbot->flood_protection_enabled = true;
+
+ libconfig->setting_lookup_int(settings, "irc_flood_protection_rate", &irc_flood_protection_rate);
+ libconfig->setting_lookup_int(settings, "irc_flood_protection_burst", &irc_flood_protection_burst);
+
+ if (irc_flood_protection_rate > 0)
+ ircbot->flood_protection_rate = irc_flood_protection_rate;
+ else
+ ircbot->flood_protection_rate = 1000;
+ if (irc_flood_protection_burst > 0)
+ ircbot->flood_protection_burst = irc_flood_protection_burst;
+ else
+ ircbot->flood_protection_burst = 3;
+ } else {
+ ircbot->flood_protection_enabled = false;
+ }
+
libconfig->setting_lookup_bool(settings, "allow_user_channel_creation", &allow_user_channel_creation);
if( allow_user_channel_creation )
@@ -791,6 +799,16 @@ void read_channels_config(void)
}
}
+ libconfig->setting_lookup_int(settings, "channel_opt_msg_delay", &channel_opt_msg_delay);
+ if (channel_opt_msg_delay < 0) {
+ ShowWarning("channels.conf: channel_opt_msg_delay value '%d' must be from 0-255. Defaulting to 0...\n", channel_opt_msg_delay);
+ channel_opt_msg_delay = 0;
+ } else if (channel_opt_msg_delay > 255) {
+ ShowWarning("channels.conf: channel_opt_msg_delay value '%d' must be from 0-255. Defaulting to 255...\n", channel_opt_msg_delay);
+ channel_opt_msg_delay = 255;
+ }
+ channel->config->channel_opt_msg_delay = channel_opt_msg_delay;
+
ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' channels in '"CL_WHITE"%s"CL_RESET"'.\n", db_size(channel->db), config_filename);
}
libconfig->destroy(&channels_conf);
@@ -799,7 +817,7 @@ void read_channels_config(void)
/*==========================================
*
*------------------------------------------*/
-int do_init_channel(bool minimal)
+static int do_init_channel(bool minimal)
{
if (minimal)
return 0;
@@ -811,11 +829,10 @@ int do_init_channel(bool minimal)
return 0;
}
-void do_final_channel(void)
+static void do_final_channel(void)
{
struct DBIterator *iter = db_iterator(channel->db);
struct channel_data *chan;
- unsigned char i;
for( chan = dbi_first(iter); dbi_exists(iter); chan = dbi_next(iter) ) {
channel->delete(chan);
@@ -823,7 +840,7 @@ void do_final_channel(void)
dbi_destroy(iter);
- for(i = 0; i < channel->config->colors_count; i++) {
+ for (int i = 0; i < channel->config->colors_count; i++) {
aFree(channel->config->colors_name[i]);
}