summaryrefslogtreecommitdiff
path: root/src/irc/core/irc-servers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/irc/core/irc-servers.c')
-rw-r--r--src/irc/core/irc-servers.c136
1 files changed, 88 insertions, 48 deletions
diff --git a/src/irc/core/irc-servers.c b/src/irc/core/irc-servers.c
index 13784f88..3117e345 100644
--- a/src/irc/core/irc-servers.c
+++ b/src/irc/core/irc-servers.c
@@ -32,6 +32,10 @@
#include "irc-queries.h"
#include "irc-servers-setup.h"
#include "irc-servers.h"
+#include "irc-cap.h"
+#include "sasl.h"
+
+#include "channels-setup.h"
#include "channel-rejoin.h"
#include "servers-idle.h"
#include "servers-reconnect.h"
@@ -71,13 +75,28 @@ static int isnickflag_func(SERVER_REC *server, char flag)
static int ischannel_func(SERVER_REC *server, const char *data)
{
- if (*data == '@') {
- /* @#channel, @+#channel */
- data++;
- if (*data == '+' && ischannel(data[1]))
- return 1;
- }
- return ischannel(*data);
+ IRC_SERVER_REC *irc_server = (IRC_SERVER_REC *) server;
+ char *chantypes, *statusmsg;
+
+ g_return_val_if_fail(data != NULL, FALSE);
+
+ /* empty string is no channel */
+ if (*data == '\0')
+ return FALSE;
+
+ chantypes = g_hash_table_lookup(irc_server->isupport, "chantypes");
+ if (chantypes == NULL)
+ chantypes = "#&!+"; /* normal, local, secure, modeless */
+
+ statusmsg = g_hash_table_lookup(irc_server->isupport, "statusmsg");
+ if (statusmsg == NULL)
+ statusmsg = "@";
+
+ data += strspn(data, statusmsg);
+
+ /* strchr(3) considers the trailing NUL as part of the string, make sure
+ * we didn't advance too much. */
+ return *data != '\0' && strchr(chantypes, *data) != NULL;
}
static char **split_line(const SERVER_REC *server, const char *line,
@@ -85,6 +104,7 @@ static char **split_line(const SERVER_REC *server, const char *line,
{
const char *start = settings_get_str("split_line_start");
const char *end = settings_get_str("split_line_end");
+ gboolean onspace = settings_get_bool("split_line_on_space");
char *recoded_start = recode_out(server, start, target);
char *recoded_end = recode_out(server, end, target);
char **lines;
@@ -103,7 +123,7 @@ static char **split_line(const SERVER_REC *server, const char *line,
return NULL;
}
- lines = recode_split(server, line, target, len);
+ lines = recode_split(server, line, target, len, onspace);
for (i = 0; lines[i] != NULL; i++) {
if (i != 0 && *start != '\0') {
/* Not the first line. */
@@ -178,23 +198,15 @@ static char **split_message(SERVER_REC *server, const char *target,
const char *msg)
{
IRC_SERVER_REC *ircserver = IRC_SERVER(server);
- int userhostlen = MAX_USERHOST_LEN;
g_return_val_if_fail(ircserver != NULL, NULL);
g_return_val_if_fail(target != NULL, NULL);
g_return_val_if_fail(msg != NULL, NULL);
- /*
- * If we have joined a channel, userhost will be set, so we can
- * calculate the exact maximum length.
- */
- if (ircserver->userhost != NULL)
- userhostlen = strlen(ircserver->userhost);
-
- /* length calculation shamelessly stolen from splitlong.pl */
+ /* length calculation shamelessly stolen from splitlong_safe.pl */
return split_line(SERVER(server), msg, target,
510 - strlen(":! PRIVMSG :") -
- strlen(ircserver->nick) - userhostlen -
+ strlen(ircserver->nick) - MAX_USERHOST_LEN -
strlen(target));
}
@@ -202,7 +214,6 @@ static void server_init(IRC_SERVER_REC *server)
{
IRC_SERVER_CONNECT_REC *conn;
char *address, *ptr, *username, *cmd;
- GTimeVal now;
g_return_if_fail(server != NULL);
@@ -221,6 +232,13 @@ static void server_init(IRC_SERVER_REC *server)
g_free(cmd);
}
+ if (conn->sasl_mechanism != SASL_MECHANISM_NONE)
+ cap_toggle(server, "sasl", TRUE);
+
+ cap_toggle(server, "multi-prefix", TRUE);
+
+ irc_send_cmd_now(server, "CAP LS");
+
if (conn->password != NULL && *conn->password != '\0') {
/* send password */
cmd = g_strdup_printf("PASS %s", conn->password);
@@ -270,9 +288,8 @@ static void server_init(IRC_SERVER_REC *server)
/* prevent the queue from sending too early, we have a max cut off of 120 secs */
/* this will reset to 1 sec after we get the 001 event */
- g_get_current_time(&now);
- memcpy(&((IRC_SERVER_REC *)server)->wait_cmd, &now, sizeof(GTimeVal));
- ((IRC_SERVER_REC *)server)->wait_cmd.tv_sec += 120;
+ g_get_current_time(&server->wait_cmd);
+ g_time_val_add(&server->wait_cmd, 120 * G_USEC_PER_SEC);
}
SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn)
@@ -293,7 +310,7 @@ SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn)
if (server->connrec->port <= 0) {
server->connrec->port =
- server->connrec->use_ssl ? 6697 : 6667;
+ server->connrec->use_tls ? 6697 : 6667;
}
server->cmd_queue_speed = ircconn->cmd_queue_speed > 0 ?
@@ -311,7 +328,7 @@ SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn)
ircconn->max_whois : DEFAULT_MAX_WHOIS;
server->max_msgs_in_cmd = ircconn->max_msgs > 0 ?
ircconn->max_msgs : DEFAULT_MAX_MSGS;
- server->connrec->use_ssl = conn->use_ssl;
+ server->connrec->use_tls = conn->use_tls;
modes_server_init(server);
@@ -321,6 +338,8 @@ SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn)
void irc_server_connect(SERVER_REC *server)
{
+ g_return_if_fail(server != NULL);
+
if (!server_start_connect(server)) {
server_connect_unref(server->connrec);
g_free(server);
@@ -416,7 +435,18 @@ static void sig_disconnected(IRC_SERVER_REC *server)
server_redirect_destroy(tmp->next->data);
}
g_slist_free(server->cmdqueue);
- server->cmdqueue = NULL;
+ server->cmdqueue = NULL;
+
+ gslist_free_full(server->cap_active, (GDestroyNotify) g_free);
+ server->cap_active = NULL;
+
+ gslist_free_full(server->cap_supported, (GDestroyNotify) g_free);
+ server->cap_supported = NULL;
+
+ gslist_free_full(server->cap_queue, (GDestroyNotify) g_free);
+ server->cap_queue = NULL;
+
+ g_free_and_null(server->sasl_buffer);
/* these are dynamically allocated only if isupport was sent */
g_hash_table_foreach(server->isupport,
@@ -458,18 +488,14 @@ void irc_server_send_action(IRC_SERVER_REC *server, const char *target, const ch
char **irc_server_split_action(IRC_SERVER_REC *server, const char *target,
const char *data)
{
- int userhostlen = MAX_USERHOST_LEN;
-
g_return_val_if_fail(server != NULL, NULL);
g_return_val_if_fail(target != NULL, NULL);
g_return_val_if_fail(data != NULL, NULL);
- if (server->userhost != NULL)
- userhostlen = strlen(server->userhost);
-
return split_line(SERVER(server), data, target,
510 - strlen(":! PRIVMSG :\001ACTION \001") -
- strlen(server->nick) - userhostlen - strlen(target));
+ strlen(server->nick) - MAX_USERHOST_LEN -
+ strlen(target));
}
void irc_server_send_away(IRC_SERVER_REC *server, const char *reason)
@@ -484,9 +510,11 @@ void irc_server_send_away(IRC_SERVER_REC *server, const char *reason)
if (*reason != '\0') {
server->away_reason = g_strdup(reason);
reason = recoded = recode_out(SERVER(server), reason, NULL);
+ irc_send_cmdv(server, "AWAY :%s", reason);
+ } else {
+ irc_send_cmdv(server, "AWAY");
}
- irc_send_cmdv(server, "AWAY :%s", reason);
}
g_free(recoded);
}
@@ -509,7 +537,7 @@ void irc_server_send_data(IRC_SERVER_REC *server, const char *data, int len)
server->wait_cmd.tv_sec = 0;
else {
memcpy(&server->wait_cmd, &server->last_cmd, sizeof(GTimeVal));
- server->wait_cmd.tv_sec += 2 + len/100;
+ g_time_val_add(&server->wait_cmd, (2 + len/100) * G_USEC_PER_SEC);
}
}
@@ -597,9 +625,16 @@ char *irc_server_get_channels(IRC_SERVER_REC *server)
GString *chans, *keys;
char *ret;
int use_keys;
+ int rejoin_channels_mode;
g_return_val_if_fail(server != NULL, FALSE);
+ rejoin_channels_mode = settings_get_choice("rejoin_channels_on_reconnect");
+
+ /* do we want to rejoin channels in the first place? */
+ if(rejoin_channels_mode == 0)
+ return g_strdup("");
+
chans = g_string_new(NULL);
keys = g_string_new(NULL);
use_keys = FALSE;
@@ -607,22 +642,27 @@ char *irc_server_get_channels(IRC_SERVER_REC *server)
/* get currently joined channels */
for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
CHANNEL_REC *channel = tmp->data;
-
- g_string_append_printf(chans, "%s,", channel->name);
- g_string_append_printf(keys, "%s,", channel->key == NULL ? "x" :
- channel->key);
- if (channel->key != NULL)
- use_keys = TRUE;
+ CHANNEL_SETUP_REC *setup = channel_setup_find(channel->name, channel->server->connrec->chatnet);
+ if ((setup != NULL && setup->autojoin && rejoin_channels_mode == 2) || rejoin_channels_mode == 1) {
+ g_string_append_printf(chans, "%s,", channel->name);
+ g_string_append_printf(keys, "%s,", channel->key == NULL ? "x" : channel->key);
+ if (channel->key != NULL)
+ use_keys = TRUE;
+ }
}
/* get also the channels that are in rejoin list */
for (tmp = server->rejoin_channels; tmp != NULL; tmp = tmp->next) {
REJOIN_REC *rec = tmp->data;
+ CHANNEL_SETUP_REC *setup = channel_setup_find(rec->channel, server->tag);
+
+ if ((setup != NULL && setup->autojoin && rejoin_channels_mode == 2) || rejoin_channels_mode == 1) {
+ g_string_append_printf(chans, "%s,", rec->channel);
+ g_string_append_printf(keys, "%s,", rec->key == NULL ? "x" :
+ rec->key);
- g_string_append_printf(chans, "%s,", rec->channel);
- g_string_append_printf(keys, "%s,", rec->key == NULL ? "x" :
- rec->key);
- if (rec->key != NULL) use_keys = TRUE;
+ if (rec->key != NULL) use_keys = TRUE;
+ }
}
if (chans->len > 0) {
@@ -641,13 +681,12 @@ char *irc_server_get_channels(IRC_SERVER_REC *server)
static void event_connected(IRC_SERVER_REC *server, const char *data, const char *from)
{
char *params, *nick;
- GTimeVal now;
g_return_if_fail(server != NULL);
params = event_get_params(data, 1, &nick);
- if (strcmp(server->nick, nick) != 0) {
+ if (g_strcmp0(server->nick, nick) != 0) {
/* nick changed unexpectedly .. connected via proxy, etc. */
g_free(server->nick);
server->nick = g_strdup(nick);
@@ -664,8 +703,7 @@ static void event_connected(IRC_SERVER_REC *server, const char *data, const char
server->real_connect_time = time(NULL);
/* let the queue send now that we are identified */
- g_get_current_time(&now);
- memcpy(&server->wait_cmd, &now, sizeof(GTimeVal));
+ g_get_current_time(&server->wait_cmd);
if (server->connrec->usermode != NULL) {
/* Send the user mode, before the autosendcmd.
@@ -753,7 +791,7 @@ static void event_isupport(IRC_SERVER_REC *server, const char *data)
char **item, *sptr, *eptr;
char **isupport;
gpointer key, value;
-
+
g_return_if_fail(server != NULL);
server->isupport_sent = TRUE;
@@ -979,9 +1017,11 @@ void irc_server_init_isupport(IRC_SERVER_REC *server)
void irc_servers_init(void)
{
+ settings_add_choice("servers", "rejoin_channels_on_reconnect", 1, "off;on;auto");
settings_add_str("misc", "usermode", DEFAULT_USER_MODE);
settings_add_str("misc", "split_line_start", "");
settings_add_str("misc", "split_line_end", "");
+ settings_add_bool("misc", "split_line_on_space", TRUE);
settings_add_time("flood", "cmd_queue_speed", DEFAULT_CMD_QUEUE_SPEED);
settings_add_int("flood", "cmds_max_at_once", DEFAULT_CMDS_MAX_AT_ONCE);