2005-04-28 10:26:44 +02:00
|
|
|
|
/*
|
|
|
|
|
* $Id: irc.c,v 1.156 2005/04/21 06:58:50 nohar Exp $
|
|
|
|
|
*
|
|
|
|
|
* This file is part of the bip project
|
2005-10-09 13:47:20 +02:00
|
|
|
|
* Copyright (C) 2004 2005 Arnaud Cornet and Lo<EFBFBD>c Gomez
|
2005-04-28 10:26:44 +02:00
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
* See the file "COPYING" for the exact licensing terms.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include "util.h"
|
|
|
|
|
#include "irc.h"
|
2005-08-25 10:17:10 +02:00
|
|
|
|
#include "bip.h"
|
2005-04-28 10:26:44 +02:00
|
|
|
|
#include "log.h"
|
|
|
|
|
#include "connection.h"
|
|
|
|
|
#include "md5.h"
|
|
|
|
|
|
2005-05-24 01:05:11 +02:00
|
|
|
|
#define S_CONN_DELAY (10)
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
extern int sighup;
|
|
|
|
|
|
|
|
|
|
static int irc_join(struct link_server *server, struct line *line);
|
|
|
|
|
static int irc_part(struct link_server *server, struct line *line);
|
|
|
|
|
static int irc_mode(struct link_server *server, struct line *line);
|
|
|
|
|
static int irc_kick(struct link_server *server, struct line *line);
|
|
|
|
|
static int irc_privmsg(struct link_server *server, struct line *line);
|
|
|
|
|
static int irc_notice(struct link_server *server, struct line *line);
|
|
|
|
|
static int irc_quit(struct link_server *server, struct line *line);
|
|
|
|
|
static int irc_nick(struct link_server *server, struct line *line);
|
|
|
|
|
static int irc_generic_quit(struct link_server *server, struct line *line);
|
|
|
|
|
static int irc_topic(struct link_server *server, struct line *line);
|
|
|
|
|
static int irc_332(struct link_server *server, struct line *line);
|
|
|
|
|
static int irc_333(struct link_server *server, struct line *line);
|
|
|
|
|
static int irc_353(struct link_server *server, struct line *line);
|
|
|
|
|
static int irc_366(struct link_server *server, struct line *line);
|
2006-11-12 19:08:49 +01:00
|
|
|
|
static int irc_367(struct link_server *server, struct line *l);
|
|
|
|
|
static int irc_368(struct link_server *server, struct line *l);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
void irc_server_shutdown(struct link_server *s);
|
2007-01-26 19:52:21 +01:00
|
|
|
|
static int origin_is_me(struct line *l, struct link_server *server);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
void irc_client_free(struct link_client *cli);
|
2005-05-19 22:55:11 +02:00
|
|
|
|
extern int conf_backlog;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
extern int conf_log_sync_interval;
|
|
|
|
|
extern int conf_error;
|
|
|
|
|
extern char conf_errstr[];
|
2005-05-30 20:01:00 +02:00
|
|
|
|
extern int conf_blreset_on_talk;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
void write_user_list(connection_t *c, char *dest);
|
|
|
|
|
|
2005-05-29 15:42:50 +02:00
|
|
|
|
static void irc_copy_cli(struct link_client *src, struct link_client *dest,
|
|
|
|
|
struct line *line);
|
2005-08-18 09:57:46 +02:00
|
|
|
|
static void irc_cli_make_join(struct link_client *ic);
|
2005-05-29 15:42:50 +02:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
#define LAGOUT_TIME (360)
|
|
|
|
|
#define LAGCHECK_TIME (90)
|
2007-01-26 19:52:21 +01:00
|
|
|
|
/* XXX 10 => 120 */
|
|
|
|
|
#define RECONN_TIMER (10)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
#define LOGGING_TIMEOUT (360)
|
|
|
|
|
#define CONN_INTERVAL 60
|
|
|
|
|
#define CONNECT_TIMEOUT 60
|
|
|
|
|
|
|
|
|
|
struct channel *channel_new(const char *name)
|
|
|
|
|
{
|
|
|
|
|
struct channel *chan;
|
|
|
|
|
chan = calloc(sizeof(struct channel), 1);
|
|
|
|
|
if (!chan)
|
|
|
|
|
fatal("calloc");
|
|
|
|
|
chan->name = strdup(name);
|
|
|
|
|
hash_init(&chan->nicks, HASH_NOCASE);
|
|
|
|
|
return chan;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *nick_from_ircmask(char *mask)
|
|
|
|
|
{
|
|
|
|
|
char *nick = mask;
|
|
|
|
|
char *ret;
|
|
|
|
|
size_t len;
|
2006-06-08 20:55:26 +02:00
|
|
|
|
|
2006-06-20 13:31:22 +02:00
|
|
|
|
if (!mask)
|
|
|
|
|
fatal("nick_from_ircmask");
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
while (*nick && *nick != '!')
|
|
|
|
|
nick++;
|
|
|
|
|
if (!*nick)
|
|
|
|
|
return strdup(mask);
|
|
|
|
|
len = nick - mask;
|
|
|
|
|
ret = malloc(len + 1);
|
|
|
|
|
if (!ret)
|
|
|
|
|
fatal("malloc");
|
|
|
|
|
memcpy(ret, mask, len);
|
|
|
|
|
ret[len] = 0;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define NAMESIZE 256
|
|
|
|
|
|
|
|
|
|
list_t *channel_name_list(struct channel *c)
|
|
|
|
|
{
|
|
|
|
|
list_t *ret;
|
|
|
|
|
hash_iterator_t hi;
|
|
|
|
|
size_t s = NAMESIZE;
|
|
|
|
|
ret = list_new(NULL);
|
|
|
|
|
|
|
|
|
|
size_t len = 0;
|
|
|
|
|
char *str = malloc(NAMESIZE);
|
|
|
|
|
*str = 0;
|
|
|
|
|
for (hash_it_init(&c->nicks, &hi); hash_it_item(&hi);
|
|
|
|
|
hash_it_next(&hi)){
|
|
|
|
|
struct nick *n = hash_it_item(&hi);
|
|
|
|
|
|
|
|
|
|
if (strlen(n->name) + 2 >= NAMESIZE)
|
|
|
|
|
fatal("nick too big for me"); /* FIXME */
|
|
|
|
|
|
|
|
|
|
if (len + strlen(n->name) + 2 + (n->ovmask ? 1 : 0)
|
|
|
|
|
>= NAMESIZE) {
|
|
|
|
|
list_add_last(ret, str);
|
|
|
|
|
str = malloc(s);
|
|
|
|
|
*str = 0;
|
|
|
|
|
len = 0;
|
|
|
|
|
}
|
|
|
|
|
if (len != 0) {
|
|
|
|
|
strncat(str, " ", NAMESIZE);
|
|
|
|
|
len++;
|
|
|
|
|
}
|
2005-11-16 19:34:25 +01:00
|
|
|
|
if (n->ovmask & NICKOP) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
strncat(str, "@", NAMESIZE);
|
|
|
|
|
len++;
|
2005-11-16 19:34:25 +01:00
|
|
|
|
} else if (n->ovmask & NICKVOICED) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
strncat(str, "+", NAMESIZE);
|
|
|
|
|
len++;
|
|
|
|
|
}
|
|
|
|
|
strncat(str, n->name, NAMESIZE);
|
|
|
|
|
len += strlen(n->name);
|
|
|
|
|
if (len >= NAMESIZE)
|
|
|
|
|
fatal("internal error 5");
|
|
|
|
|
}
|
|
|
|
|
list_add_last(ret, str);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_001(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
2007-01-26 19:52:21 +01:00
|
|
|
|
(void)line;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
if (LINK(server)->s_state == IRCS_WAS_CONNECTED)
|
|
|
|
|
LINK(server)->s_state = IRCS_RECONNECTING;
|
2006-06-08 20:55:26 +02:00
|
|
|
|
else
|
2005-04-28 10:26:44 +02:00
|
|
|
|
LINK(server)->s_state = IRCS_CONNECTING;
|
|
|
|
|
|
2007-01-26 19:52:21 +01:00
|
|
|
|
/* change nick on client */
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < LINK(server)->l_clientc; i++) {
|
|
|
|
|
struct link_client *c = LINK(server)->l_clientv[i];
|
|
|
|
|
WRITE_LINE1(CONN(c), LINK(server)->cli_nick, "NICK",
|
|
|
|
|
server->nick);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
2007-01-26 19:52:21 +01:00
|
|
|
|
return OK_COPY;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void irc_start_lagtest(struct link_server *l)
|
|
|
|
|
{
|
|
|
|
|
l->laginit_ts = time(NULL);
|
|
|
|
|
write_line_fast(CONN(l), "PING :" S_PING "\r\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* returns 0 if we ping timeout
|
|
|
|
|
*/
|
|
|
|
|
void irc_compute_lag(struct link_server *is)
|
|
|
|
|
{
|
|
|
|
|
if (is->laginit_ts == -1)
|
|
|
|
|
fatal("irc_compute_lag");
|
|
|
|
|
|
|
|
|
|
is->lag = time(NULL) - is->laginit_ts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int irc_lags_out(struct link_server *is)
|
|
|
|
|
{
|
|
|
|
|
if (is->lag > LAGOUT_TIME) {
|
|
|
|
|
mylog(LOG_ERROR, "%s Lags out! closing", LINK(is)->name);
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
mylog(LOG_DEBUG, "%s lag : %d\n", LINK(is)->name, is->lag);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void irc_lag_init(struct link_server *is)
|
|
|
|
|
{
|
|
|
|
|
is->lagtest_timeout = LAGCHECK_TIME;
|
|
|
|
|
is->laginit_ts = -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void irc_server_join(struct link_server *s)
|
|
|
|
|
{
|
2005-05-30 20:35:49 +02:00
|
|
|
|
list_iterator_t it;
|
|
|
|
|
for (list_it_init(&LINK(s)->chan_infos_order, &it); list_it_item(&it);
|
|
|
|
|
list_it_next(&it)) {
|
|
|
|
|
struct chan_info *ci = list_it_item(&it);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (!ci->key)
|
|
|
|
|
WRITE_LINE1(CONN(s), NULL, "JOIN", ci->name);
|
|
|
|
|
else
|
|
|
|
|
WRITE_LINE2(CONN(s), NULL, "JOIN", ci->name, ci->key);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void irc_server_connected(struct link_server *server)
|
|
|
|
|
{
|
2006-06-08 20:55:26 +02:00
|
|
|
|
int i;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
LINK(server)->s_state = IRCS_CONNECTED;
|
|
|
|
|
irc_server_join(server);
|
|
|
|
|
log_connected(LINK(server)->log);
|
|
|
|
|
|
2007-01-26 19:52:21 +01:00
|
|
|
|
if (LINK(server)->cli_nick) {
|
|
|
|
|
/* we change nick on client */
|
|
|
|
|
for (i = 0; i < LINK(server)->l_clientc; i++) {
|
|
|
|
|
struct link_client *ic = LINK(server)->l_clientv[i];
|
|
|
|
|
WRITE_LINE1(CONN(ic), LINK(server)->cli_nick, "NICK",
|
|
|
|
|
server->nick);
|
|
|
|
|
}
|
|
|
|
|
free(LINK(server)->cli_nick);
|
|
|
|
|
LINK(server)->cli_nick = NULL;
|
2006-06-08 20:55:26 +02:00
|
|
|
|
}
|
|
|
|
|
/* basic helper for nickserv and co */
|
2006-09-18 20:05:17 +02:00
|
|
|
|
list_iterator_t itocs;
|
|
|
|
|
for (list_it_init(&LINK(server)->on_connect_send, &itocs);
|
|
|
|
|
list_it_item(&itocs); list_it_next(&itocs)) {
|
|
|
|
|
ssize_t len = strlen(list_it_item(&itocs)) + 2;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
char *str = malloc(len + 1);
|
2006-09-25 14:08:31 +02:00
|
|
|
|
sprintf(str, "%s\r\n", (char *)list_it_item(&itocs));
|
2005-04-28 10:26:44 +02:00
|
|
|
|
write_line(CONN(server), str);
|
|
|
|
|
free(str);
|
|
|
|
|
}
|
2006-09-25 14:08:31 +02:00
|
|
|
|
|
|
|
|
|
if (LINK(server)->l_clientc == 0) {
|
|
|
|
|
if (LINK(server)->away_nick)
|
|
|
|
|
WRITE_LINE1(CONN(server), NULL, "NICK",
|
|
|
|
|
LINK(server)->away_nick);
|
|
|
|
|
if (LINK(server)->no_client_away_msg)
|
|
|
|
|
WRITE_LINE1(CONN(server), NULL, "AWAY",
|
|
|
|
|
LINK(server)->no_client_away_msg);
|
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2005-11-16 19:34:25 +01:00
|
|
|
|
static int who_arg_to_ovmask(char *str)
|
|
|
|
|
{
|
|
|
|
|
int ovmask = 0;
|
|
|
|
|
if (strchr(str, '@'))
|
|
|
|
|
ovmask |= NICKOP;
|
|
|
|
|
if (strchr(str, '+'))
|
|
|
|
|
ovmask |= NICKVOICED;
|
|
|
|
|
return ovmask;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/*
|
2007-01-26 19:52:21 +01:00
|
|
|
|
* Given the way irc nets disrespect the rfc, we completely forget
|
2005-04-28 10:26:44 +02:00
|
|
|
|
* about this damn ircmask...
|
|
|
|
|
:irc.iiens.net 352 pwet * ~a je.suis.t1r.net irc.iiens.net pwet H :0 d
|
|
|
|
|
*/
|
2006-11-12 19:08:49 +01:00
|
|
|
|
static int irc_352(struct link_server *server, struct line *line)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
2007-01-26 19:52:21 +01:00
|
|
|
|
(void)server;
|
2005-11-16 19:34:25 +01:00
|
|
|
|
if (line->elemc < 8)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return ERR_PROTOCOL;
|
2005-11-16 19:34:25 +01:00
|
|
|
|
|
2007-01-26 19:52:21 +01:00
|
|
|
|
if (!origin_is_me(line, server)) {
|
2005-11-16 19:34:25 +01:00
|
|
|
|
struct channel *channel;
|
|
|
|
|
struct nick *nick;
|
|
|
|
|
|
|
|
|
|
channel = hash_get(&server->channels, line->elemv[2]);
|
|
|
|
|
if (!channel)
|
2007-01-26 19:52:21 +01:00
|
|
|
|
return OK_COPY_WHO;
|
2005-11-16 19:34:25 +01:00
|
|
|
|
|
|
|
|
|
nick = hash_get(&channel->nicks, line->elemv[6]);
|
|
|
|
|
if (!nick)
|
2007-01-26 19:52:21 +01:00
|
|
|
|
return OK_COPY_WHO;
|
2005-11-16 19:34:25 +01:00
|
|
|
|
|
|
|
|
|
nick->ovmask = who_arg_to_ovmask(line->elemv[7]);
|
|
|
|
|
}
|
2007-01-26 19:52:21 +01:00
|
|
|
|
|
2006-02-05 12:10:33 +01:00
|
|
|
|
return OK_COPY_WHO;
|
|
|
|
|
}
|
|
|
|
|
|
2006-02-21 08:48:12 +01:00
|
|
|
|
static int irc_315(struct link_server *server, struct line *l)
|
2006-02-05 12:10:33 +01:00
|
|
|
|
{
|
2006-02-21 08:48:12 +01:00
|
|
|
|
struct link *link = LINK(server);
|
|
|
|
|
if (link->who_client) {
|
2007-01-05 22:19:32 +01:00
|
|
|
|
if (link->who_client->who_count == 0) {
|
|
|
|
|
mylog(LOG_DEBUG, "Spurious irc_315");
|
|
|
|
|
return OK_COPY_WHO;
|
|
|
|
|
}
|
|
|
|
|
link->who_client->whoc_tstamp = time(NULL);
|
|
|
|
|
if (link->who_client->who_count > 0) {
|
|
|
|
|
--link->who_client->who_count;
|
|
|
|
|
mylog(LOG_INFO,
|
|
|
|
|
"RPL_ENDOFWHO: "
|
|
|
|
|
"Decrementing who count for %p: %d",
|
|
|
|
|
link->who_client, link->who_client->who_count);
|
|
|
|
|
}
|
2006-02-05 12:10:33 +01:00
|
|
|
|
}
|
2006-02-21 08:48:12 +01:00
|
|
|
|
l = NULL; /* keep gcc happy */
|
2006-02-05 12:10:33 +01:00
|
|
|
|
|
|
|
|
|
return OK_COPY_WHO;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2007-01-05 22:19:32 +01:00
|
|
|
|
void rotate_who_client(struct link *link)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
mylog(LOG_INFO, "rotate_who_client %p", link->who_client);
|
|
|
|
|
/* find a client with non-null who_count */
|
|
|
|
|
link->who_client = NULL;
|
|
|
|
|
for (i = 0; i < link->l_clientc; i++) {
|
|
|
|
|
struct link_client *ic = link->l_clientv[i];
|
|
|
|
|
if (!list_is_empty(&ic->who_queue)) {
|
|
|
|
|
char *l;
|
|
|
|
|
while ((l = list_remove_first(&ic->who_queue))) {
|
|
|
|
|
write_line(CONN(link->l_server), l);
|
|
|
|
|
free(l);
|
|
|
|
|
}
|
|
|
|
|
link->who_client = ic;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/*
|
|
|
|
|
* parses:join part mode kick kill privmsg quit nick names
|
|
|
|
|
* returns: -1 invalid protocol
|
|
|
|
|
*/
|
|
|
|
|
int irc_dispatch_server(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
int ret = OK_COPY;
|
|
|
|
|
|
|
|
|
|
if (line->elemc == 0)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
2007-01-26 19:52:21 +01:00
|
|
|
|
printf("coucou23: %s\n", line->elemv[0]);
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (strcmp(line->elemv[0], "PING") == 0) {
|
|
|
|
|
if (line->elemc < 2)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
struct line *resp = irc_line_new();
|
|
|
|
|
char *resps;
|
|
|
|
|
irc_line_append(resp, "PONG");
|
|
|
|
|
irc_line_append(resp, line->elemv[1]);
|
2005-05-26 17:36:15 +02:00
|
|
|
|
resp->colon = 1; /* it seems some ircds want it */
|
2005-04-28 10:26:44 +02:00
|
|
|
|
resps = irc_line_to_string(resp);
|
|
|
|
|
write_line_fast(CONN(server), resps);
|
|
|
|
|
irc_line_free(resp);
|
|
|
|
|
free(resps);
|
|
|
|
|
ret = OK_FORGET;
|
|
|
|
|
} else if (strcmp(line->elemv[0], "PONG") == 0) {
|
|
|
|
|
if (line->elemc == 3 && strcmp(line->elemv[2], S_PING) == 0) {
|
|
|
|
|
if (server->laginit_ts != -1) {
|
|
|
|
|
irc_compute_lag(server);
|
|
|
|
|
irc_lag_init(server);
|
|
|
|
|
}
|
|
|
|
|
ret = OK_FORGET;
|
|
|
|
|
}
|
|
|
|
|
} else if (strcmp(line->elemv[0], "433") == 0) {
|
|
|
|
|
if (LINK(server)->s_state != IRCS_CONNECTED) {
|
|
|
|
|
size_t nicklen = strlen(server->nick);
|
|
|
|
|
char *newnick = malloc(nicklen + 2);
|
|
|
|
|
strcpy(newnick, server->nick);
|
|
|
|
|
if (strlen(server->nick) < 9)
|
|
|
|
|
strcat(newnick, "`");
|
|
|
|
|
else if (newnick[8] != '`') {
|
|
|
|
|
newnick[8] = '`';
|
|
|
|
|
newnick[9] = 0;
|
|
|
|
|
} else {
|
|
|
|
|
newnick[8] = rand() * ('z' - 'a') / RAND_MAX +
|
|
|
|
|
'a';
|
|
|
|
|
newnick[9] = 0;
|
|
|
|
|
}
|
|
|
|
|
free(server->nick);
|
|
|
|
|
server->nick = newnick;
|
|
|
|
|
|
|
|
|
|
WRITE_LINE1(CONN(server), NULL, "NICK", server->nick);
|
|
|
|
|
ret = OK_FORGET;
|
|
|
|
|
}
|
|
|
|
|
} else if (LINK(server)->s_state == IRCS_RECONNECTING) {
|
|
|
|
|
ret = OK_FORGET;
|
|
|
|
|
if (strcmp(line->elemv[0], "376") == 0) /* end of motd */
|
|
|
|
|
irc_server_connected(server);
|
2005-12-12 20:03:02 +01:00
|
|
|
|
else if (strcmp(line->elemv[0], "422") == 0) /* no motd */
|
|
|
|
|
irc_server_connected(server);
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
} else if (LINK(server)->s_state == IRCS_CONNECTING) {
|
|
|
|
|
ret = OK_FORGET;
|
|
|
|
|
if (strcmp(line->elemv[0], "NOTICE") == 0) {
|
2006-02-05 12:10:33 +01:00
|
|
|
|
} else if (strcmp(line->elemv[0], "376") == 0) {
|
|
|
|
|
/* end of motd */
|
2005-12-12 20:03:02 +01:00
|
|
|
|
irc_server_connected(server);
|
|
|
|
|
list_add_last(&LINK(server)->init_strings,
|
|
|
|
|
irc_line_dup(line));
|
|
|
|
|
} else if (strcmp(line->elemv[0], "422") == 0) { /* no motd */
|
2005-04-28 10:26:44 +02:00
|
|
|
|
irc_server_connected(server);
|
|
|
|
|
list_add_last(&LINK(server)->init_strings,
|
|
|
|
|
irc_line_dup(line));
|
|
|
|
|
} else {
|
|
|
|
|
list_add_last(&LINK(server)->init_strings,
|
|
|
|
|
irc_line_dup(line));
|
|
|
|
|
}
|
|
|
|
|
} else if (strcmp(line->elemv[0], "001") == 0) {
|
|
|
|
|
ret = irc_001(server, line);
|
|
|
|
|
if (LINK(server)->s_state == IRCS_CONNECTING) {
|
|
|
|
|
if (!list_is_empty(&LINK(server)->init_strings))
|
|
|
|
|
return ERR_PROTOCOL;
|
2007-01-26 19:52:21 +01:00
|
|
|
|
/* update the irc mask */
|
2005-04-28 10:26:44 +02:00
|
|
|
|
list_add_last(&LINK(server)->init_strings,
|
|
|
|
|
irc_line_dup(line));
|
|
|
|
|
}
|
|
|
|
|
} else if (strcmp(line->elemv[0], "JOIN") == 0) {
|
|
|
|
|
ret = irc_join(server, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "332") == 0) {
|
|
|
|
|
ret = irc_332(server, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "333") == 0) {
|
|
|
|
|
ret = irc_333(server, line);
|
2005-11-16 19:34:25 +01:00
|
|
|
|
} else if (strcmp(line->elemv[0], "352") == 0) {
|
2006-11-12 19:08:49 +01:00
|
|
|
|
ret = irc_352(server, line);
|
2006-02-05 12:10:33 +01:00
|
|
|
|
} else if (strcmp(line->elemv[0], "315") == 0) {
|
|
|
|
|
ret = irc_315(server, line);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
} else if (strcmp(line->elemv[0], "353") == 0) {
|
|
|
|
|
ret = irc_353(server, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "366") == 0) {
|
|
|
|
|
ret = irc_366(server, line);
|
2006-11-12 19:08:49 +01:00
|
|
|
|
} else if (strcmp(line->elemv[0], "367") == 0) {
|
|
|
|
|
ret = irc_367(server, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "368") == 0) {
|
|
|
|
|
ret = irc_368(server, line);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
} else if (strcmp(line->elemv[0], "PART") == 0) {
|
|
|
|
|
ret = irc_part(server, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "MODE") == 0) {
|
|
|
|
|
ret = irc_mode(server, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "TOPIC") == 0) {
|
|
|
|
|
ret = irc_topic(server, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "KICK") == 0) {
|
|
|
|
|
ret = irc_kick(server, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "PRIVMSG") == 0) {
|
|
|
|
|
ret = irc_privmsg(server, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "NOTICE") == 0) {
|
|
|
|
|
ret = irc_notice(server, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "QUIT") == 0) {
|
|
|
|
|
ret = irc_quit(server, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "NICK") == 0) {
|
|
|
|
|
ret = irc_nick(server, line);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ret == OK_COPY) {
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < LINK(server)->l_clientc; i++) {
|
|
|
|
|
char *s = irc_line_to_string(line);
|
|
|
|
|
write_line(CONN(LINK(server)->l_clientv[i]), s);
|
|
|
|
|
free(s);
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-02-21 08:48:12 +01:00
|
|
|
|
if (ret == OK_COPY_WHO && LINK(server)->who_client) {
|
2006-02-05 12:10:33 +01:00
|
|
|
|
char *s;
|
|
|
|
|
|
|
|
|
|
s = irc_line_to_string(line);
|
2006-02-21 08:48:12 +01:00
|
|
|
|
write_line(CONN(LINK(server)->who_client), s);
|
2006-02-05 12:10:33 +01:00
|
|
|
|
free(s);
|
2007-01-05 22:19:32 +01:00
|
|
|
|
}
|
|
|
|
|
if (LINK(server)->who_client &&
|
|
|
|
|
LINK(server)->who_client->who_count == 0) {
|
|
|
|
|
mylog(LOG_INFO, "OK_COPY_WHO: who_count for %p is nul",
|
|
|
|
|
LINK(server)->who_client);
|
|
|
|
|
rotate_who_client(LINK(server));
|
2006-02-05 12:10:33 +01:00
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* send join and related stuff to client */
|
|
|
|
|
static void irc_send_join(struct link_client *ic, struct channel *chan)
|
|
|
|
|
{
|
2007-01-26 19:52:21 +01:00
|
|
|
|
WRITE_LINE1(CONN(ic), LINK(ic)->l_server->nick, "JOIN", chan->name);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (chan->topic)
|
|
|
|
|
WRITE_LINE3(CONN(ic), P_SERV, "332", LINK(ic)->l_server->nick,
|
|
|
|
|
chan->name, chan->topic);
|
|
|
|
|
if (chan->creator && chan->create_ts)
|
|
|
|
|
WRITE_LINE4(CONN(ic), P_SERV, "333", LINK(ic)->l_server->nick,
|
|
|
|
|
chan->name, chan->creator, chan->create_ts);
|
|
|
|
|
|
|
|
|
|
/* XXX: could be more efficient */
|
2005-05-19 22:55:11 +02:00
|
|
|
|
if (conf_backlog && log_has_backlog(LINK(ic)->log, chan->name)) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
char *line;
|
2006-11-12 14:22:32 +01:00
|
|
|
|
int skip = 0;
|
|
|
|
|
while ((line =
|
|
|
|
|
log_backread(LINK(ic)->log, chan->name, &skip))) {
|
|
|
|
|
if (!skip)
|
|
|
|
|
write_line(CONN(ic), line);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
free(line);
|
|
|
|
|
}
|
|
|
|
|
WRITE_LINE2(CONN(ic), P_IRCMASK, "PRIVMSG", chan->name,
|
|
|
|
|
"End of backlog.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
list_t *name_list = channel_name_list(chan);
|
|
|
|
|
char *s;
|
|
|
|
|
while ((s = list_remove_first(name_list))) {
|
|
|
|
|
char tmptype[2];
|
|
|
|
|
tmptype[0] = chan->type;
|
|
|
|
|
tmptype[1] = 0;
|
|
|
|
|
WRITE_LINE4(CONN(ic), P_SERV, "353", LINK(ic)->l_server->nick,
|
|
|
|
|
tmptype, chan->name, s);
|
|
|
|
|
free(s);
|
|
|
|
|
}
|
|
|
|
|
list_free(name_list);
|
|
|
|
|
|
|
|
|
|
WRITE_LINE3(CONN(ic), P_SERV, "366", LINK(ic)->l_server->nick,
|
|
|
|
|
chan->name, "End of /NAMES list.");
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void write_init_string(connection_t *c, struct line *line, char *nick)
|
|
|
|
|
{
|
|
|
|
|
char *tmp;
|
|
|
|
|
char *l;
|
|
|
|
|
|
|
|
|
|
tmp = line->elemv[1];
|
|
|
|
|
line->elemv[1] = nick;
|
|
|
|
|
l = irc_line_to_string(line);
|
|
|
|
|
write_line(c, l);
|
|
|
|
|
free(l);
|
|
|
|
|
line->elemv[1] = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void bind_to_link(struct link *l, struct link_client *ic)
|
|
|
|
|
{
|
|
|
|
|
int i = l->l_clientc;
|
|
|
|
|
|
|
|
|
|
LINK(ic) = l;
|
|
|
|
|
l->l_clientc++;
|
|
|
|
|
l->l_clientv = realloc(l->l_clientv, l->l_clientc *
|
|
|
|
|
sizeof(struct link_client *));
|
|
|
|
|
if (!l->l_clientv)
|
|
|
|
|
fatal("realloc");
|
|
|
|
|
l->l_clientv[i] = ic;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-25 10:17:10 +02:00
|
|
|
|
void unbind_from_link(struct link_client *ic)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
{
|
|
|
|
|
struct link *l = LINK(ic);
|
|
|
|
|
int i;
|
2006-02-21 08:48:12 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
for (i = 0; i < l->l_clientc; i++)
|
|
|
|
|
if (l->l_clientv[i] == ic)
|
|
|
|
|
break;
|
|
|
|
|
if (i == l->l_clientc)
|
|
|
|
|
fatal("unbind_from_link");
|
2006-02-21 08:48:12 +01:00
|
|
|
|
|
2007-01-05 22:19:32 +01:00
|
|
|
|
if (l->who_client == ic) {
|
|
|
|
|
mylog(LOG_INFO, "unbind_from_link: %p: %d",
|
|
|
|
|
l->who_client, ic->who_count);
|
2006-02-21 08:48:12 +01:00
|
|
|
|
l->who_client = NULL;
|
2007-01-05 22:19:32 +01:00
|
|
|
|
} else {
|
|
|
|
|
mylog(LOG_INFO,
|
|
|
|
|
"unbind_from_link: nothing to do %p != %p: %d",
|
|
|
|
|
ic, l->who_client,
|
|
|
|
|
ic->who_count);
|
|
|
|
|
}
|
2006-02-21 08:48:12 +01:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
for (i = i + 1; i < l->l_clientc; i++)
|
|
|
|
|
l->l_clientv[i - 1] = l->l_clientv[i];
|
|
|
|
|
|
|
|
|
|
l->l_clientc--;
|
|
|
|
|
l->l_clientv = realloc(l->l_clientv, l->l_clientc *
|
|
|
|
|
sizeof(struct link_client *));
|
|
|
|
|
if (l->l_clientc == 0) { /* realloc was equiv to free() */
|
|
|
|
|
l->l_clientv = NULL;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!l->l_clientv)
|
|
|
|
|
fatal("realloc");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int irc_cli_bip(struct link_client *ic, struct line *line)
|
|
|
|
|
{
|
2007-01-12 19:34:45 +01:00
|
|
|
|
return adm_bip(ic, line, 0);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2005-07-09 14:55:01 +02:00
|
|
|
|
#define PASS_SEP ':'
|
|
|
|
|
|
|
|
|
|
static char *get_str_elem(char *str, int num)
|
|
|
|
|
{
|
|
|
|
|
char *ret;
|
|
|
|
|
char *c;
|
|
|
|
|
char *cur = str;
|
|
|
|
|
int index = 0;
|
|
|
|
|
|
2005-08-01 13:16:39 +02:00
|
|
|
|
while ((c = strchr(cur, PASS_SEP))) {
|
2005-07-09 14:55:01 +02:00
|
|
|
|
if (index < num) {
|
|
|
|
|
index++;
|
|
|
|
|
cur = c + 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (c - cur < 1)
|
|
|
|
|
return NULL;
|
|
|
|
|
ret = malloc(c - cur + 1);
|
|
|
|
|
strncpy(ret, cur, c - cur);
|
|
|
|
|
ret[c - cur] = 0;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
if (index == num) {
|
|
|
|
|
c = str + strlen(str);
|
|
|
|
|
if (c - cur < 1)
|
|
|
|
|
return NULL;
|
|
|
|
|
ret = malloc(c - cur + 1);
|
|
|
|
|
strncpy(ret, cur, c - cur);
|
|
|
|
|
ret[c - cur] = 0;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-18 09:57:46 +02:00
|
|
|
|
static void irc_cli_make_join(struct link_client *ic)
|
|
|
|
|
{
|
|
|
|
|
if (LINK(ic)->l_server) {
|
|
|
|
|
/* join channels, step one, those in conf, in order */
|
|
|
|
|
list_iterator_t li;
|
|
|
|
|
for (list_it_init(&LINK(ic)->chan_infos_order, &li);
|
|
|
|
|
list_it_item(&li); list_it_next(&li)) {
|
|
|
|
|
struct chan_info *ci = (struct chan_info *)
|
|
|
|
|
list_it_item(&li);
|
|
|
|
|
struct channel *chan;
|
|
|
|
|
if ((chan = hash_get(&LINK(ic)->l_server->channels,
|
|
|
|
|
ci->name)))
|
|
|
|
|
irc_send_join(ic, chan);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* step two, those not in conf */
|
|
|
|
|
hash_iterator_t hi;
|
|
|
|
|
for (hash_it_init(&LINK(ic)->l_server->channels, &hi);
|
|
|
|
|
hash_it_item(&hi); hash_it_next(&hi)) {
|
|
|
|
|
struct channel *chan = (struct channel *)
|
|
|
|
|
hash_it_item(&hi);
|
|
|
|
|
if (!hash_get(&LINK(ic)->chan_infos, chan->name))
|
|
|
|
|
irc_send_join(ic, chan);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* backlog privates */
|
|
|
|
|
char *str;
|
2006-11-12 14:22:32 +01:00
|
|
|
|
int skip = 0;
|
|
|
|
|
while ((str = log_backread(LINK(ic)->log, S_PRIVATES, &skip))) {
|
|
|
|
|
if (!skip)
|
|
|
|
|
write_line(CONN(ic), str);
|
2005-08-18 09:57:46 +02:00
|
|
|
|
free(str);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
static int irc_cli_startup(struct link_client *ic, struct line *line,
|
|
|
|
|
list_t *linkl)
|
|
|
|
|
{
|
2005-07-09 14:55:01 +02:00
|
|
|
|
char *init_nick;
|
|
|
|
|
char *user, *pass, *connname;
|
2005-08-01 13:24:10 +02:00
|
|
|
|
(void)line;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
2005-07-09 14:55:01 +02:00
|
|
|
|
if (!ic->init_pass)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
fatal("internal irc_cli_startup");
|
|
|
|
|
|
2005-07-09 14:55:01 +02:00
|
|
|
|
user = get_str_elem(ic->init_pass, 0);
|
|
|
|
|
if (!user)
|
|
|
|
|
return ERR_AUTH;
|
|
|
|
|
pass = get_str_elem(ic->init_pass, 1);
|
|
|
|
|
if (!pass) {
|
|
|
|
|
free(user);
|
|
|
|
|
return ERR_AUTH;
|
|
|
|
|
}
|
|
|
|
|
connname = get_str_elem(ic->init_pass, 2);
|
|
|
|
|
if (!connname) {
|
|
|
|
|
free(pass);
|
|
|
|
|
free(user);
|
|
|
|
|
return ERR_AUTH;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
list_iterator_t it;
|
|
|
|
|
for (list_it_init(linkl, &it); list_it_item(&it); list_it_next(&it)) {
|
|
|
|
|
struct link *l = list_it_item(&it);
|
2005-07-09 14:55:01 +02:00
|
|
|
|
if (strcmp(user, l->username) == 0
|
|
|
|
|
&& strcmp(connname, l->name) == 0) {
|
|
|
|
|
if (chash_cmp(pass, l->password, l->seed) == 0) {
|
|
|
|
|
bind_to_link(l, ic);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-16 00:46:28 +02:00
|
|
|
|
if (!LINK(ic))
|
2005-07-09 14:55:01 +02:00
|
|
|
|
mylog(LOG_ERROR, "Invalid credentials (user:%s connection:%s)",
|
|
|
|
|
user, connname);
|
|
|
|
|
free(user);
|
|
|
|
|
free(connname);
|
|
|
|
|
free(pass);
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
free(ic->init_pass);
|
|
|
|
|
ic->init_pass = NULL;
|
|
|
|
|
init_nick = ic->init_nick;
|
|
|
|
|
ic->init_nick = NULL;
|
|
|
|
|
|
2005-05-21 15:44:09 +02:00
|
|
|
|
if (!LINK(ic)) {
|
|
|
|
|
free(init_nick);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return ERR_AUTH;
|
2005-05-21 15:44:09 +02:00
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
2005-08-25 10:17:10 +02:00
|
|
|
|
#ifdef HAVE_LIBSSL
|
2005-08-27 10:24:55 +02:00
|
|
|
|
if (LINK(ic)->s_state != IRCS_CONNECTED) {
|
2005-08-25 10:17:10 +02:00
|
|
|
|
/* Check if we have an untrusted certificate from the server */
|
|
|
|
|
if (ssl_check_trust(ic)) {
|
2005-12-12 20:03:02 +01:00
|
|
|
|
TYPE(ic) = IRC_TYPE_TRUST_CLIENT;
|
2005-08-25 10:17:10 +02:00
|
|
|
|
ic->allow_trust = 1;
|
|
|
|
|
free(init_nick);
|
|
|
|
|
return OK_FORGET;
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-12-12 20:03:02 +01:00
|
|
|
|
#endif
|
2005-08-25 10:17:10 +02:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (LINK(ic)->s_state == IRCS_NONE) {
|
|
|
|
|
/* drop it if corresponding server hasn't connected at all. */
|
2005-08-02 12:11:47 +02:00
|
|
|
|
write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
|
2005-04-28 10:26:44 +02:00
|
|
|
|
":ERROR Proxy not yet connected, try again "
|
|
|
|
|
"later\r\n");
|
|
|
|
|
unbind_from_link(ic);
|
2005-05-21 15:44:09 +02:00
|
|
|
|
free(init_nick);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return OK_CLOSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TYPE(ic) = IRC_TYPE_CLIENT;
|
|
|
|
|
|
|
|
|
|
for (list_it_init(&LINK(ic)->init_strings, &it);
|
|
|
|
|
list_it_item(&it); list_it_next(&it))
|
|
|
|
|
write_init_string(CONN(ic), list_it_item(&it), init_nick);
|
|
|
|
|
|
2006-09-18 18:06:23 +02:00
|
|
|
|
/* we change nick on server */
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (LINK(ic)->l_server) {
|
|
|
|
|
struct link_server *server = LINK(ic)->l_server;
|
2007-01-26 19:52:21 +01:00
|
|
|
|
WRITE_LINE1(CONN(ic), init_nick, "NICK", server->nick);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
if (!LINK(ic)->ignore_first_nick)
|
|
|
|
|
WRITE_LINE1(CONN(server), NULL, "NICK", init_nick);
|
|
|
|
|
else if (LINK(ic)->away_nick &&
|
|
|
|
|
strcmp(LINK(ic)->away_nick, server->nick) == 0)
|
|
|
|
|
WRITE_LINE1(CONN(server), NULL, "NICK",
|
|
|
|
|
LINK(server)->connect_nick);
|
2006-09-18 18:06:23 +02:00
|
|
|
|
|
|
|
|
|
/* change away status */
|
2006-09-25 14:08:31 +02:00
|
|
|
|
if (server && LINK(ic)->no_client_away_msg)
|
|
|
|
|
WRITE_LINE0(CONN(server), NULL, "AWAY");
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!LINK(ic)->l_server) {
|
|
|
|
|
free(init_nick);
|
|
|
|
|
return OK_FORGET;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-18 09:57:46 +02:00
|
|
|
|
irc_cli_make_join(ic);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
log_client_connected(LINK(ic)->log);
|
|
|
|
|
free(init_nick);
|
|
|
|
|
|
|
|
|
|
return OK_FORGET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_cli_nick(struct link_client *ic, struct line *line, list_t *cl)
|
|
|
|
|
{
|
|
|
|
|
if (line->elemc != 2)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
if ((ic->state & IRCC_READY) == IRCC_READY)
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
|
|
|
|
|
ic->state |= IRCC_NICK;
|
|
|
|
|
if (ic->init_nick)
|
|
|
|
|
free(ic->init_nick);
|
|
|
|
|
ic->init_nick = strdup(line->elemv[1]);
|
|
|
|
|
|
|
|
|
|
if ((ic->state & IRCC_READY) == IRCC_READY)
|
|
|
|
|
return irc_cli_startup(ic, line, cl);
|
|
|
|
|
|
|
|
|
|
if ((ic->state & IRCC_PASS) != IRCC_PASS)
|
|
|
|
|
WRITE_LINE2(CONN(ic), P_SERV, "NOTICE", ic->init_nick,
|
2006-04-20 14:51:46 +02:00
|
|
|
|
"You should type /QUOTE PASS your_username:your_password:your_connection_name");
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
return OK_FORGET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_cli_user(struct link_client *ic, struct line *line, list_t *cl)
|
|
|
|
|
{
|
|
|
|
|
if (line->elemc != 5)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
if ((ic->state & IRCC_READY) == IRCC_READY)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
ic->state |= IRCC_USER;
|
|
|
|
|
if ((ic->state & IRCC_READY) == IRCC_READY)
|
|
|
|
|
return irc_cli_startup(ic, line, cl);
|
|
|
|
|
return OK_FORGET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_cli_pass(struct link_client *ic, struct line *line, list_t *cl)
|
|
|
|
|
{
|
|
|
|
|
if (line->elemc != 2)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
if ((ic->state & IRCC_READY) == IRCC_READY)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
ic->state |= IRCC_PASS;
|
|
|
|
|
if (ic->init_pass)
|
|
|
|
|
free(ic->init_pass);
|
|
|
|
|
ic->init_pass = strdup(line->elemv[1]);
|
|
|
|
|
if ((ic->state & IRCC_READY) == IRCC_READY)
|
|
|
|
|
return irc_cli_startup(ic, line, cl);
|
|
|
|
|
return OK_FORGET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_cli_quit(struct link_client *ic, struct line *line)
|
|
|
|
|
{
|
2005-08-01 13:24:10 +02:00
|
|
|
|
(void)ic;
|
|
|
|
|
(void)line;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return OK_CLOSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_cli_privmsg(struct link_client *ic, struct line *line)
|
|
|
|
|
{
|
2007-01-12 19:34:45 +01:00
|
|
|
|
if (line->elemc >= 3)
|
|
|
|
|
log_cli_privmsg(LINK(ic)->log, LINK(ic)->l_server->nick,
|
2005-04-28 10:26:44 +02:00
|
|
|
|
line->elemv[1], line->elemv[2]);
|
2007-01-12 19:34:45 +01:00
|
|
|
|
if (strcmp(line->elemv[1], "-bip") == 0)
|
|
|
|
|
return adm_bip(ic, line, 1);
|
|
|
|
|
|
2005-05-30 20:01:00 +02:00
|
|
|
|
if (conf_blreset_on_talk)
|
|
|
|
|
adm_blreset(ic);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return OK_COPY_CLI;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_cli_notice(struct link_client *ic, struct line *line)
|
|
|
|
|
{
|
2005-05-19 22:55:11 +02:00
|
|
|
|
log_cli_notice(LINK(ic)->log, LINK(ic)->l_server->nick,
|
2005-04-28 10:26:44 +02:00
|
|
|
|
line->elemv[1], line->elemv[2]);
|
|
|
|
|
return OK_COPY_CLI;
|
|
|
|
|
}
|
|
|
|
|
|
2006-02-05 12:10:33 +01:00
|
|
|
|
static int irc_cli_who(struct link_client *ic, struct line *line)
|
|
|
|
|
{
|
2006-02-21 08:48:12 +01:00
|
|
|
|
struct link *l = LINK(ic);
|
2006-02-05 12:10:33 +01:00
|
|
|
|
|
2007-01-05 22:19:32 +01:00
|
|
|
|
++ic->who_count;
|
|
|
|
|
if (ic->who_count == 1)
|
|
|
|
|
ic->whoc_tstamp = time(NULL);
|
|
|
|
|
mylog(LOG_INFO, "cli_who: Incrementing who count for %p: %d",
|
|
|
|
|
ic, ic->who_count);
|
|
|
|
|
|
2006-02-21 08:48:12 +01:00
|
|
|
|
if (l->who_client && l->who_client != ic) {
|
2006-02-05 12:10:33 +01:00
|
|
|
|
list_add_first(&ic->who_queue, irc_line_to_string(line));
|
|
|
|
|
return OK_FORGET;
|
|
|
|
|
}
|
|
|
|
|
|
2006-02-21 08:48:12 +01:00
|
|
|
|
if (!l->who_client)
|
|
|
|
|
l->who_client = ic;
|
2006-02-05 12:10:33 +01:00
|
|
|
|
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
2006-11-12 19:08:49 +01:00
|
|
|
|
static int irc_cli_mode(struct link_client *ic, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
struct link *l = LINK(ic);
|
|
|
|
|
|
|
|
|
|
if (line->elemc != 3)
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
|
|
|
|
|
/* This is a wild guess and that sucks. */
|
|
|
|
|
if (strcmp(line->elemv[0], "MODE") != 0 ||
|
|
|
|
|
strchr(line->elemv[2], 'b') == NULL)
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
|
2007-01-05 22:19:32 +01:00
|
|
|
|
++ic->who_count;
|
|
|
|
|
if (ic->who_count == 1)
|
|
|
|
|
ic->whoc_tstamp = time(NULL);
|
|
|
|
|
mylog(LOG_INFO, "cli_mode: Incrementing who count for %p: %d",
|
|
|
|
|
l->who_client, ic->who_count);
|
|
|
|
|
|
2006-11-12 19:08:49 +01:00
|
|
|
|
if (l->who_client && l->who_client != ic) {
|
|
|
|
|
list_add_first(&ic->who_queue, irc_line_to_string(line));
|
|
|
|
|
return OK_FORGET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!l->who_client)
|
|
|
|
|
l->who_client = ic;
|
|
|
|
|
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
|
|
|
|
|
static void irc_notify_disconnection(struct link_server *is)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
2007-01-26 19:52:21 +01:00
|
|
|
|
LINK(is)->cli_nick = strdup(is->nick);
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
for (i = 0; i < LINK(is)->l_clientc; i++) {
|
|
|
|
|
struct link_client *ic = LINK(is)->l_clientv[i];
|
|
|
|
|
hash_iterator_t hi;
|
|
|
|
|
for (hash_it_init(&is->channels, &hi); hash_it_item(&hi);
|
|
|
|
|
hash_it_next(&hi)) {
|
|
|
|
|
struct channel *c = (struct channel *)hash_it_item(&hi);
|
2005-07-25 10:27:03 +02:00
|
|
|
|
WRITE_LINE3(CONN(ic), P_IRCMASK, "KICK",
|
|
|
|
|
c->name, is->nick,
|
|
|
|
|
"Server disconnected, reconnecting");
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
2007-01-26 19:52:21 +01:00
|
|
|
|
WRITE_LINE2(CONN(ic), P_IRCMASK, "PRIVMSG", is->nick,
|
2005-04-28 10:26:44 +02:00
|
|
|
|
"Server disconnected, reconnecting");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void irc_add_channel_info(struct link_server *ircs, char *chan, char *key)
|
|
|
|
|
{
|
|
|
|
|
struct chan_info *ci;
|
|
|
|
|
if (!ischannel(*chan))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
ci = hash_get(&LINK(ircs)->chan_infos, chan);
|
|
|
|
|
if (!ci) {
|
|
|
|
|
struct chan_info *ci;
|
|
|
|
|
ci = malloc(sizeof(struct chan_info));
|
|
|
|
|
ci->name = strdup(chan);
|
|
|
|
|
ci->key = key ? strdup(key) : NULL;
|
|
|
|
|
hash_insert(&LINK(ircs)->chan_infos, chan, ci);
|
2005-05-30 20:35:49 +02:00
|
|
|
|
list_add_last(&LINK(ircs)->chan_infos_order, ci);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
} else {
|
|
|
|
|
if (ci->key) {
|
|
|
|
|
free(ci->key);
|
|
|
|
|
ci->key = NULL;
|
|
|
|
|
}
|
|
|
|
|
ci->key = key ? strdup(key) : NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_cli_join(struct link_client *irc, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
if (line->elemc != 2 && line->elemc != 3)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
2005-08-01 13:24:10 +02:00
|
|
|
|
char *s, *e, *ks, *ke = 0;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
s = line->elemv[1];
|
|
|
|
|
if (line->elemc == 3)
|
|
|
|
|
ks = line->elemv[2];
|
|
|
|
|
else
|
|
|
|
|
ks = NULL;
|
|
|
|
|
|
|
|
|
|
while ((e = strchr(s, ','))) {
|
|
|
|
|
size_t len = e - s;
|
|
|
|
|
char *p = malloc(len + 1);
|
|
|
|
|
size_t klen;
|
|
|
|
|
char *kp = NULL;
|
|
|
|
|
|
|
|
|
|
memcpy(p, s, len);
|
|
|
|
|
p[len] = 0;
|
|
|
|
|
if (ks) {
|
|
|
|
|
if (strlen(ks)) {
|
|
|
|
|
ke = strchr(ks, ',');
|
|
|
|
|
if (!ke)
|
|
|
|
|
ke = ks + strlen(ks);
|
|
|
|
|
klen = ke - ks;
|
|
|
|
|
kp = malloc(klen + 1);
|
|
|
|
|
memcpy(kp, ks, klen);
|
|
|
|
|
kp[klen] = 0;
|
|
|
|
|
if (*ke == 0)
|
|
|
|
|
ks = NULL;
|
|
|
|
|
} else
|
|
|
|
|
kp = ks = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
irc_add_channel_info(LINK(irc)->l_server, p, kp);
|
|
|
|
|
free(p);
|
|
|
|
|
if (kp) {
|
|
|
|
|
free(kp);
|
|
|
|
|
if (ks)
|
|
|
|
|
ks = ke + 1;
|
|
|
|
|
}
|
|
|
|
|
s = e + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
irc_add_channel_info(LINK(irc)->l_server, s, ks);
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_cli_part(struct link_client *irc, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
if (line->elemc != 2 && line->elemc != 3)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
struct chan_info *ci;
|
|
|
|
|
if ((ci = hash_remove_if_exists(&LINK(irc)->chan_infos,
|
|
|
|
|
line->elemv[1])) != NULL) {
|
2005-05-30 20:35:49 +02:00
|
|
|
|
list_remove(&LINK(irc)->chan_infos_order, ci);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
free(ci->name);
|
|
|
|
|
if (ci->key)
|
|
|
|
|
free(ci->key);
|
|
|
|
|
free(ci);
|
|
|
|
|
}
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
2005-12-12 20:03:02 +01:00
|
|
|
|
#ifdef HAVE_LIBSSL
|
|
|
|
|
static int irc_dispatch_trust_client(struct link_client *ic, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
int r = OK_COPY;
|
|
|
|
|
if (line->elemc < 2)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
if (strcmp(line->elemv[0], "BIP") == 0 &&
|
|
|
|
|
strcmp(line->elemv[1], "TRUST") == 0)
|
|
|
|
|
r = adm_trust(ic, line);
|
2006-06-08 20:55:26 +02:00
|
|
|
|
|
2005-12-12 20:03:02 +01:00
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
int irc_cli_bip(struct link_client *ic, struct line *line);
|
|
|
|
|
static int irc_dispatch_client(struct link_client *ic, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
int r = OK_COPY;
|
|
|
|
|
if (line->elemc == 0)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
if (strcmp(line->elemv[0], "PING") == 0) {
|
|
|
|
|
if (line->elemc < 2)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
WRITE_LINE1(CONN(ic), LINK(ic)->name, "PONG", line->elemv[1]);
|
|
|
|
|
r = OK_FORGET;
|
2005-08-04 14:40:09 +02:00
|
|
|
|
} else if (LINK(ic)->s_state != IRCS_CONNECTED) {
|
|
|
|
|
write_line_fast(CONN(ic), ":irc.bip.net NOTICE pouet "
|
|
|
|
|
":ERROR Proxy not connected, please wait "
|
|
|
|
|
"before sending commands\r\n");
|
|
|
|
|
r = OK_FORGET;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
} else if (strcasecmp(line->elemv[0], "BIP") == 0) {
|
|
|
|
|
r = irc_cli_bip(ic, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "JOIN") == 0) {
|
|
|
|
|
r = irc_cli_join(ic, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "PART") == 0) {
|
|
|
|
|
r = irc_cli_part(ic, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "NICK") == 0) {
|
|
|
|
|
r = irc_cli_nick(ic, line, NULL);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "QUIT") == 0) {
|
|
|
|
|
r = irc_cli_quit(ic, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "PRIVMSG") == 0) {
|
|
|
|
|
r = irc_cli_privmsg(ic, line);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "NOTICE") == 0) {
|
|
|
|
|
r = irc_cli_notice(ic, line);
|
2006-02-05 12:10:33 +01:00
|
|
|
|
} else if (strcmp(line->elemv[0], "WHO") == 0) {
|
|
|
|
|
r = irc_cli_who(ic, line);
|
2006-11-12 19:08:49 +01:00
|
|
|
|
} else if (strcmp(line->elemv[0], "MODE") == 0) {
|
|
|
|
|
r = irc_cli_mode(ic, line);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r == OK_COPY || r == OK_COPY_CLI) {
|
|
|
|
|
char *str = irc_line_to_string(line);
|
|
|
|
|
if (LINK(ic)->s_state == IRCS_CONNECTED &&
|
2007-01-26 19:52:21 +01:00
|
|
|
|
LINK(ic)->l_server->nick)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
write_line(CONN(LINK(ic)->l_server), str);
|
2007-01-26 19:52:21 +01:00
|
|
|
|
else if (LINK(ic)->l_server->nick)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
WRITE_LINE2(CONN(ic), P_IRCMASK, "PRIVMSG",
|
2007-01-26 19:52:21 +01:00
|
|
|
|
LINK(ic)->l_server->nick,
|
2005-04-28 10:26:44 +02:00
|
|
|
|
":Not connected please try again "
|
|
|
|
|
"later...\r\n");
|
|
|
|
|
|
|
|
|
|
free(str);
|
2005-05-29 15:42:50 +02:00
|
|
|
|
if (r == OK_COPY_CLI) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
int i;
|
|
|
|
|
struct link_server *s = LINK(ic)->l_server;
|
2005-05-29 15:42:50 +02:00
|
|
|
|
|
|
|
|
|
for (i = 0; i < LINK(s)->l_clientc; i++)
|
|
|
|
|
irc_copy_cli(ic, LINK(s)->l_clientv[i], line);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2005-05-29 15:42:50 +02:00
|
|
|
|
static void irc_copy_cli(struct link_client *src, struct link_client *dest,
|
|
|
|
|
struct line *line)
|
|
|
|
|
{
|
|
|
|
|
char *str;
|
|
|
|
|
if (src == dest)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (line->elemc <= 2 || strcmp(line->elemv[0], "PRIVMSG") != 0) {
|
|
|
|
|
str = irc_line_to_string(line);
|
|
|
|
|
write_line(CONN(dest), str);
|
|
|
|
|
free(str);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ischannel(*line->elemv[1]) || LINK(src) != LINK(dest)) {
|
2007-01-26 19:52:21 +01:00
|
|
|
|
line->origin = LINK(src)->l_server->nick;
|
2005-05-29 15:42:50 +02:00
|
|
|
|
str = irc_line_to_string(line);
|
|
|
|
|
line->origin = NULL;
|
|
|
|
|
write_line(CONN(dest), str);
|
|
|
|
|
free(str);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* LINK(src) == LINK(dest) */
|
|
|
|
|
size_t len = strlen(line->elemv[2]) + 5;
|
|
|
|
|
char *tmp;
|
|
|
|
|
|
|
|
|
|
if (len == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
tmp = malloc(len);
|
|
|
|
|
|
|
|
|
|
snprintf(tmp, len, " -> %s", line->elemv[2]);
|
|
|
|
|
tmp[len - 1] = 0;
|
|
|
|
|
|
|
|
|
|
line->origin = line->elemv[1];
|
|
|
|
|
/* tricky: */
|
2007-01-26 19:52:21 +01:00
|
|
|
|
line->elemv[1] = LINK(src)->l_server->nick;
|
2005-05-29 15:42:50 +02:00
|
|
|
|
|
|
|
|
|
free(line->elemv[2]);
|
|
|
|
|
line->elemv[2] = tmp;
|
|
|
|
|
str = irc_line_to_string(line);
|
|
|
|
|
/* end of trick: */
|
|
|
|
|
line->elemv[1] = line->origin;
|
|
|
|
|
line->origin = NULL;
|
|
|
|
|
write_line(CONN(dest), str);
|
|
|
|
|
free(str);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
static int irc_dispatch_loging_client(struct link_client *ic, struct line *line,
|
|
|
|
|
list_t *linkl)
|
|
|
|
|
{
|
|
|
|
|
if (line->elemc == 0)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
if (strcmp(line->elemv[0], "NICK") == 0) {
|
|
|
|
|
return irc_cli_nick(ic, line, linkl);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "USER") == 0) {
|
|
|
|
|
return irc_cli_user(ic, line, linkl);
|
|
|
|
|
} else if (strcmp(line->elemv[0], "PASS") == 0) {
|
|
|
|
|
return irc_cli_pass(ic, line, linkl);
|
|
|
|
|
}
|
|
|
|
|
return OK_FORGET;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int irc_dispatch(struct link_any *l, struct line *line, list_t *linkl)
|
|
|
|
|
{
|
|
|
|
|
switch (TYPE(l)) {
|
|
|
|
|
case IRC_TYPE_SERVER:
|
|
|
|
|
return irc_dispatch_server((struct link_server*)l, line);
|
|
|
|
|
break;
|
|
|
|
|
case IRC_TYPE_CLIENT:
|
|
|
|
|
return irc_dispatch_client((struct link_client*)l, line);
|
|
|
|
|
break;
|
|
|
|
|
case IRC_TYPE_LOGING_CLIENT:
|
|
|
|
|
return irc_dispatch_loging_client((struct link_client*)l,
|
|
|
|
|
line, linkl);
|
|
|
|
|
break;
|
2005-12-12 20:03:02 +01:00
|
|
|
|
#ifdef HAVE_LIBSSL
|
|
|
|
|
case IRC_TYPE_TRUST_CLIENT:
|
|
|
|
|
return irc_dispatch_trust_client((struct link_client*)l, line);
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
2005-04-28 10:26:44 +02:00
|
|
|
|
default:
|
|
|
|
|
fatal("gn<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>");
|
|
|
|
|
}
|
|
|
|
|
return ERR_PROTOCOL; /* never reached */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int origin_is_me(struct line *l, struct link_server *server)
|
|
|
|
|
{
|
2006-06-08 20:55:26 +02:00
|
|
|
|
char *nick;
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (!l->origin)
|
|
|
|
|
return 0;
|
2006-06-08 20:55:26 +02:00
|
|
|
|
nick = nick_from_ircmask(l->origin);
|
2007-01-26 19:52:21 +01:00
|
|
|
|
if (strcasecmp(nick, server->nick) == 0) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
free(nick);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
free(nick);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_join(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
char *s_nick;
|
|
|
|
|
char *s_chan;
|
|
|
|
|
struct channel *channel;
|
|
|
|
|
struct nick *nick;
|
|
|
|
|
|
|
|
|
|
if (line->elemc != 2 && line->elemc != 3)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
s_chan = line->elemv[1];
|
|
|
|
|
log_join(LINK(server)->log, line->origin, s_chan);
|
|
|
|
|
|
|
|
|
|
channel = hash_get(&server->channels, s_chan);
|
|
|
|
|
if (origin_is_me(line, server)) {
|
|
|
|
|
if (!channel) {
|
|
|
|
|
channel = channel_new(s_chan);
|
|
|
|
|
hash_insert(&server->channels, s_chan, channel);
|
|
|
|
|
}
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
/* if we're not on channel and !origin_is_me, we should not get any
|
|
|
|
|
* JOIN */
|
|
|
|
|
if (!channel)
|
|
|
|
|
return ERR_PROTOCOL;
|
2006-06-08 20:55:26 +02:00
|
|
|
|
if (!line->origin)
|
|
|
|
|
return ERR_PROTOCOL;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
s_nick = nick_from_ircmask(line->origin);
|
|
|
|
|
|
|
|
|
|
nick = calloc(sizeof(struct nick), 1);
|
|
|
|
|
if (!nick)
|
|
|
|
|
fatal("calloc");
|
|
|
|
|
nick->name = s_nick; /* not freeing s_nick */
|
|
|
|
|
hash_insert(&channel->nicks, s_nick, nick);
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_332(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
struct channel *channel;
|
|
|
|
|
if (line->elemc != 4)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
channel = hash_get(&server->channels, line->elemv[2]);
|
|
|
|
|
/* we can get topic reply for chans we're not on */
|
|
|
|
|
if (!channel)
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
|
|
|
|
|
if (channel->topic)
|
|
|
|
|
free(channel->topic);
|
|
|
|
|
channel->topic = strdup(line->elemv[3]);
|
|
|
|
|
|
|
|
|
|
log_init_topic(LINK(server)->log, channel->name, channel->topic);
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_333(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
struct channel *channel;
|
|
|
|
|
if (line->elemc != 5)
|
|
|
|
|
return ERR_PROTOCOL;
|
2006-06-08 20:55:26 +02:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
channel = hash_get(&server->channels, line->elemv[2]);
|
|
|
|
|
/* we can get topic info reply for chans we're not on */
|
|
|
|
|
if (!channel)
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
if (channel->creator)
|
|
|
|
|
free(channel->creator);
|
|
|
|
|
channel->creator = strdup(line->elemv[3]);
|
|
|
|
|
if (channel->create_ts)
|
|
|
|
|
free(channel->create_ts);
|
|
|
|
|
channel->create_ts = strdup(line->elemv[4]);
|
|
|
|
|
log_init_topic_time(LINK(server)->log, channel->name, channel->creator,
|
|
|
|
|
channel->create_ts);
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void nick_free(struct nick *nick)
|
|
|
|
|
{
|
|
|
|
|
if (nick->name)
|
|
|
|
|
free(nick->name);
|
|
|
|
|
free(nick);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_353(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
struct channel *channel;
|
|
|
|
|
struct nick *nick;
|
|
|
|
|
char *names, *eon;
|
|
|
|
|
size_t len;
|
|
|
|
|
char *tmp;
|
|
|
|
|
|
|
|
|
|
if (line->elemc != 5)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
channel = hash_get(&server->channels, line->elemv[3]);
|
|
|
|
|
/* we can get names reply for chans we're not on */
|
|
|
|
|
if (!channel)
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
|
|
|
|
|
if (!channel->running_names) {
|
|
|
|
|
channel->running_names = 1;
|
|
|
|
|
hash_iterator_t hi;
|
|
|
|
|
for (hash_it_init(&channel->nicks, &hi); hash_it_item(&hi);
|
|
|
|
|
hash_it_next(&hi)) {
|
|
|
|
|
nick_free(hash_it_item(&hi));
|
|
|
|
|
}
|
|
|
|
|
hash_clean(&channel->nicks);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* TODO check that type is one of "=" / "*" / "@" */
|
|
|
|
|
channel->type = line->elemv[2][0];
|
|
|
|
|
|
|
|
|
|
names = line->elemv[4];
|
|
|
|
|
|
|
|
|
|
while (*names) {
|
|
|
|
|
eon = names;
|
|
|
|
|
int ovmask = 0;
|
|
|
|
|
/* these should be exclusive */
|
|
|
|
|
if (*names == '@') {
|
|
|
|
|
names++;
|
|
|
|
|
ovmask |= NICKOP;
|
|
|
|
|
} else if (*names == '+') {
|
|
|
|
|
names++;
|
|
|
|
|
ovmask |= NICKVOICED;
|
|
|
|
|
}
|
|
|
|
|
eon = names;
|
|
|
|
|
while (*eon && *eon != ' ')
|
|
|
|
|
eon++;
|
|
|
|
|
|
|
|
|
|
len = eon - names;
|
|
|
|
|
tmp = malloc(len + 1);
|
|
|
|
|
if (!tmp)
|
|
|
|
|
fatal("malloc");
|
|
|
|
|
memcpy(tmp, names, len);
|
|
|
|
|
tmp[len] = 0;
|
|
|
|
|
|
|
|
|
|
nick = malloc(sizeof(struct nick));
|
|
|
|
|
if (!nick)
|
|
|
|
|
fatal("malloc");
|
|
|
|
|
nick->name = tmp;
|
|
|
|
|
nick->ovmask = ovmask;
|
|
|
|
|
|
|
|
|
|
hash_insert(&channel->nicks, nick->name, nick);
|
|
|
|
|
while (*eon && *eon == ' ')
|
|
|
|
|
eon++;
|
|
|
|
|
names = eon;
|
|
|
|
|
}
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_366(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
struct channel *channel;
|
|
|
|
|
|
|
|
|
|
if (line->elemc != 4)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
channel = hash_get(&server->channels, line->elemv[2]);
|
|
|
|
|
if (channel && channel->running_names)
|
|
|
|
|
channel->running_names = 0;
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
2006-11-12 19:08:49 +01:00
|
|
|
|
static int irc_367(struct link_server *server, struct line *l)
|
|
|
|
|
{
|
2006-11-16 15:34:28 +01:00
|
|
|
|
(void)server;
|
|
|
|
|
(void)l;
|
2006-11-12 19:08:49 +01:00
|
|
|
|
return OK_COPY_WHO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* same as irc_315 */
|
|
|
|
|
static int irc_368(struct link_server *server, struct line *l)
|
|
|
|
|
{
|
|
|
|
|
struct link *link = LINK(server);
|
|
|
|
|
if (link->who_client) {
|
2007-01-05 22:19:32 +01:00
|
|
|
|
if (link->who_client->who_count == 0) {
|
|
|
|
|
mylog(LOG_DEBUG, "Spurious irc_368");
|
|
|
|
|
return OK_COPY_WHO;
|
|
|
|
|
}
|
|
|
|
|
link->who_client->whoc_tstamp = time(NULL);
|
|
|
|
|
|
|
|
|
|
if (link->who_client->who_count > 0) {
|
|
|
|
|
--link->who_client->who_count;
|
|
|
|
|
mylog(LOG_INFO,
|
|
|
|
|
"RPL_ENDOFBANLIST: "
|
|
|
|
|
"Decrementing who count for %p: %d",
|
|
|
|
|
link->who_client, link->who_client->who_count);
|
|
|
|
|
}
|
2006-11-12 19:08:49 +01:00
|
|
|
|
}
|
|
|
|
|
l = NULL; /* keep gcc happy */
|
|
|
|
|
|
|
|
|
|
return OK_COPY_WHO;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
static void channel_free(struct channel *c)
|
|
|
|
|
{
|
|
|
|
|
if (c->name)
|
|
|
|
|
free(c->name);
|
|
|
|
|
if (c->mode)
|
|
|
|
|
free(c->mode);
|
|
|
|
|
if (c->key)
|
|
|
|
|
free(c->key);
|
|
|
|
|
if (c->topic)
|
|
|
|
|
free(c->topic);
|
|
|
|
|
if (c->creator)
|
|
|
|
|
free(c->creator);
|
|
|
|
|
if (c->create_ts)
|
|
|
|
|
free(c->create_ts);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
char *l;
|
|
|
|
|
while ((l = (char *)list_remove_first(&c->bans)))
|
|
|
|
|
free(l);
|
|
|
|
|
*/
|
|
|
|
|
hash_iterator_t hi;
|
|
|
|
|
for (hash_it_init(&c->nicks, &hi); hash_it_item(&hi); hash_it_next(&hi))
|
|
|
|
|
nick_free(hash_it_item(&hi));
|
|
|
|
|
hash_clean(&c->nicks);
|
|
|
|
|
free(c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_part(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
char *s_nick;
|
|
|
|
|
char *s_chan;
|
|
|
|
|
struct channel *channel;
|
|
|
|
|
struct nick *nick;
|
|
|
|
|
|
|
|
|
|
if (line->elemc != 2 && line->elemc != 3)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
s_chan = line->elemv[1];
|
|
|
|
|
|
|
|
|
|
channel = hash_get(&server->channels, s_chan);
|
|
|
|
|
/* we can't get part message for chans we're not on */
|
|
|
|
|
if (!channel)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
if (origin_is_me(line, server)) {
|
|
|
|
|
log_part(LINK(server)->log, line->origin, s_chan,
|
|
|
|
|
line->elemc == 3 ? line->elemv[2] : NULL);
|
|
|
|
|
|
|
|
|
|
hash_remove(&server->channels, s_chan);
|
|
|
|
|
channel_free(channel);
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
2006-06-08 20:55:26 +02:00
|
|
|
|
if (!line->origin)
|
|
|
|
|
return ERR_PROTOCOL;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
s_nick = nick_from_ircmask(line->origin);
|
|
|
|
|
nick = hash_get(&channel->nicks, s_nick);
|
|
|
|
|
if (!nick) {
|
|
|
|
|
free(s_nick);
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
}
|
|
|
|
|
nick = hash_remove(&channel->nicks, s_nick);
|
|
|
|
|
free(s_nick);
|
|
|
|
|
|
|
|
|
|
log_part(LINK(server)->log, line->origin, s_chan,
|
|
|
|
|
line->elemc == 3 ? line->elemv[2]:NULL);
|
|
|
|
|
|
|
|
|
|
nick_free(nick);
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mode_add_letter_uniq(struct link_server *s, char c)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < s->user_mode_len; i++) {
|
|
|
|
|
if (s->user_mode[i] == c)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
s->user_mode = realloc(s->user_mode, s->user_mode_len + 1);
|
|
|
|
|
s->user_mode[s->user_mode_len++] = c;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void mode_remove_letter(struct link_server *s, char c)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
for (i = 0; i < s->user_mode_len; i++) {
|
|
|
|
|
if (s->user_mode[i] == c) {
|
|
|
|
|
for (; i < s->user_mode_len - 1; i++)
|
|
|
|
|
s->user_mode[i] = s->user_mode[i + 1];
|
|
|
|
|
s->user_mode_len--;
|
|
|
|
|
s->user_mode = realloc(s->user_mode, s->user_mode_len);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void irc_user_mode(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
char *mode;
|
|
|
|
|
int add = 1;
|
|
|
|
|
for (mode = line->elemv[2]; *mode; mode++) {
|
|
|
|
|
if (*mode == '-')
|
|
|
|
|
add = 0;
|
|
|
|
|
else if (*mode == '+')
|
|
|
|
|
add = 1;
|
|
|
|
|
else {
|
|
|
|
|
if (add) {
|
|
|
|
|
mode_add_letter_uniq(server, *mode);
|
|
|
|
|
} else {
|
|
|
|
|
mode_remove_letter(server, *mode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_mode(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
struct channel *channel;
|
|
|
|
|
char *mode;
|
|
|
|
|
int add = 1;
|
|
|
|
|
unsigned cur_arg = 0;
|
|
|
|
|
struct nick *nick;
|
|
|
|
|
|
|
|
|
|
if (line->elemc < 3)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
2005-08-01 13:16:39 +02:00
|
|
|
|
/* nick mode change */
|
|
|
|
|
if (strcmp(line->elemv[1], server->nick) == 0) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
log_mode(LINK(server)->log, line->origin, line->elemv[1],
|
|
|
|
|
line->elemv[2], line->elemv + 3,
|
|
|
|
|
line->elemc - 3);
|
|
|
|
|
irc_user_mode(server, line);
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
2005-08-01 13:16:39 +02:00
|
|
|
|
if (!ischannel(line->elemv[1][0]))
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
/* channel mode change */
|
|
|
|
|
channel = hash_get(&server->channels, line->elemv[1]);
|
|
|
|
|
/* we can't get mode message for chans we're not on */
|
|
|
|
|
if (!channel)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
log_mode(LINK(server)->log, line->origin, line->elemv[1],
|
|
|
|
|
line->elemv[2], line->elemv + 3, line->elemc - 3);
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/*
|
|
|
|
|
* MODE -a+b.. #channel args
|
|
|
|
|
* ^ ^
|
|
|
|
|
* mode cur_arg
|
|
|
|
|
*/
|
|
|
|
|
for (mode = line->elemv[2]; *mode; mode++) {
|
|
|
|
|
switch (*mode) {
|
|
|
|
|
case '-':
|
|
|
|
|
add = 0;
|
|
|
|
|
break;
|
|
|
|
|
case '+':
|
|
|
|
|
add = 1;
|
|
|
|
|
break;
|
|
|
|
|
case 'b':
|
|
|
|
|
if (cur_arg + 3 >= line->elemc)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
cur_arg++;
|
|
|
|
|
break;
|
|
|
|
|
case 'o':
|
|
|
|
|
|
|
|
|
|
if (cur_arg + 3 >= line->elemc)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
nick = hash_get(&channel->nicks,
|
|
|
|
|
line->elemv[cur_arg + 3]);
|
|
|
|
|
if (!nick)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
if (add)
|
|
|
|
|
nick->ovmask |= NICKOP;
|
|
|
|
|
else
|
|
|
|
|
nick->ovmask &= ~NICKOP;
|
|
|
|
|
cur_arg++;
|
|
|
|
|
break;
|
|
|
|
|
case 'v':
|
|
|
|
|
if (cur_arg + 3 >= line->elemc)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
nick = hash_get(&channel->nicks,
|
|
|
|
|
line->elemv[cur_arg + 3]);
|
|
|
|
|
if (!nick)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
if (add)
|
|
|
|
|
nick->ovmask |= NICKVOICED;
|
|
|
|
|
else
|
|
|
|
|
nick->ovmask &= ~NICKVOICED;
|
|
|
|
|
cur_arg++;
|
|
|
|
|
break;
|
|
|
|
|
case 'k':
|
|
|
|
|
if (add) {
|
|
|
|
|
if (cur_arg + 3 >= line->elemc)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
channel->key = strdup(line->elemv[cur_arg + 3]);
|
|
|
|
|
cur_arg++;
|
|
|
|
|
} else {
|
|
|
|
|
if (channel->key) {
|
|
|
|
|
free(channel->key);
|
|
|
|
|
channel->key = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'l':
|
2006-03-07 22:33:10 +01:00
|
|
|
|
if (add)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
cur_arg++;
|
|
|
|
|
break;
|
|
|
|
|
case 'h':
|
|
|
|
|
case 'H':
|
2006-03-07 22:33:10 +01:00
|
|
|
|
case 'e':
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (cur_arg + 3 >= line->elemc)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
cur_arg++;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *irc_timestamp(void)
|
|
|
|
|
{
|
|
|
|
|
char *ts = malloc(21);
|
|
|
|
|
snprintf(ts, 20, "%ld", (long int)time(NULL));
|
|
|
|
|
return ts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_topic(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
struct channel *channel;
|
|
|
|
|
char *topic;
|
|
|
|
|
|
|
|
|
|
if (line->elemc != 3)
|
|
|
|
|
return ERR_PROTOCOL;
|
2006-06-08 20:55:26 +02:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
channel = hash_get(&server->channels, line->elemv[1]);
|
|
|
|
|
/* we can't get topic message for chans we're not on */
|
|
|
|
|
if (!channel)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
if (channel->topic)
|
|
|
|
|
free(channel->topic);
|
|
|
|
|
topic = line->elemv[2];
|
|
|
|
|
if (*topic == ':')
|
|
|
|
|
topic++;
|
|
|
|
|
channel->topic = strdup(topic);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* :arion.oftc.net 333 bip`luser #bipqSDFQE3
|
|
|
|
|
* nohar!~nohar@borne28.noc.nerim.net 1107338095
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (channel->creator)
|
|
|
|
|
free(channel->creator);
|
|
|
|
|
channel->creator = strmaydup(line->origin);
|
|
|
|
|
if (channel->create_ts)
|
|
|
|
|
free(channel->create_ts);
|
|
|
|
|
channel->create_ts = irc_timestamp();
|
|
|
|
|
|
|
|
|
|
log_topic(LINK(server)->log, line->origin, line->elemv[1], topic);
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_kick(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
struct channel *channel;
|
|
|
|
|
struct nick *nick;
|
|
|
|
|
|
|
|
|
|
if (line->elemc != 3 && line->elemc != 4)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
channel = hash_get(&server->channels, line->elemv[1]);
|
|
|
|
|
/* we can't get kick message for chans we're not on */
|
|
|
|
|
if (!channel)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
nick = hash_get(&channel->nicks, line->elemv[2]);
|
|
|
|
|
if (!nick)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
|
|
|
|
if (strcmp(nick->name, server->nick) == 0) {
|
|
|
|
|
log_kick(LINK(server)->log, line->origin, channel->name,
|
|
|
|
|
nick->name,
|
|
|
|
|
line->elemc == 4 ? line->elemv[3] : NULL);
|
|
|
|
|
|
|
|
|
|
hash_remove(&server->channels, channel->name);
|
|
|
|
|
channel_free(channel);
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
2006-06-08 20:55:26 +02:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
hash_remove(&channel->nicks, nick->name);
|
|
|
|
|
nick_free(nick);
|
|
|
|
|
log_kick(LINK(server)->log, line->origin, line->elemv[1],
|
|
|
|
|
line->elemv[2],
|
|
|
|
|
line->elemc == 4 ? line->elemv[3] : NULL);
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_privmsg(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
2005-05-17 14:52:12 +02:00
|
|
|
|
if (LINK(server)->s_state == IRCS_CONNECTED)
|
|
|
|
|
log_privmsg(LINK(server)->log, line->origin, line->elemv[1],
|
|
|
|
|
line->elemv[2]);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_notice(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
2005-05-17 14:52:12 +02:00
|
|
|
|
if (LINK(server)->s_state == IRCS_CONNECTED)
|
|
|
|
|
log_notice(LINK(server)->log, line->origin, line->elemv[1],
|
|
|
|
|
line->elemv[2]);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_quit(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
return irc_generic_quit(server, line);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_nick(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
struct channel *channel;
|
|
|
|
|
struct nick *nick;
|
|
|
|
|
hash_iterator_t hi;
|
|
|
|
|
|
|
|
|
|
if (line->elemc != 2)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
2006-06-08 20:55:26 +02:00
|
|
|
|
if (!line->origin)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
2007-01-26 19:52:21 +01:00
|
|
|
|
if (origin_is_me(line, server)) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
free(server->nick);
|
|
|
|
|
server->nick = strdup(line->elemv[1]);
|
|
|
|
|
if (LINK(server)->follow_nick &&
|
|
|
|
|
(LINK(server)->away_nick == NULL ||
|
|
|
|
|
strcmp(server->nick, LINK(server)->away_nick))
|
|
|
|
|
!= 0) {
|
|
|
|
|
free(LINK(server)->connect_nick);
|
|
|
|
|
LINK(server)->connect_nick = strdup(server->nick);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (hash_it_init(&server->channels, &hi); hash_it_item(&hi);
|
|
|
|
|
hash_it_next(&hi)) {
|
|
|
|
|
channel = hash_it_item(&hi);
|
2007-01-26 19:52:21 +01:00
|
|
|
|
nick = hash_get(&channel->nicks, server->nick);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (!nick)
|
|
|
|
|
continue;
|
2007-01-26 19:52:21 +01:00
|
|
|
|
hash_remove(&channel->nicks, server->nick);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
free(nick->name);
|
|
|
|
|
nick->name = strdup(line->elemv[1]);
|
|
|
|
|
hash_insert(&channel->nicks, nick->name, nick);
|
2007-01-26 19:52:21 +01:00
|
|
|
|
log_nick(LINK(server)->log, server->nick, channel->name,
|
2005-04-28 10:26:44 +02:00
|
|
|
|
line->elemv[1]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int irc_generic_quit(struct link_server *server, struct line *line)
|
|
|
|
|
{
|
|
|
|
|
struct channel *channel;
|
|
|
|
|
struct nick *nick;
|
|
|
|
|
hash_iterator_t hi;
|
|
|
|
|
char *s_nick;
|
|
|
|
|
|
|
|
|
|
if (line->elemc != 2 && line->elemc != 1)
|
|
|
|
|
return ERR_PROTOCOL;
|
|
|
|
|
|
2006-06-08 20:55:26 +02:00
|
|
|
|
if (!line->origin)
|
|
|
|
|
return ERR_PROTOCOL;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
s_nick = nick_from_ircmask(line->origin);
|
2006-06-08 20:55:26 +02:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
for (hash_it_init(&server->channels, &hi); hash_it_item(&hi);
|
|
|
|
|
hash_it_next(&hi)) {
|
|
|
|
|
channel = hash_it_item(&hi);
|
|
|
|
|
nick = hash_get(&channel->nicks, s_nick);
|
|
|
|
|
if (!nick)
|
|
|
|
|
continue;
|
|
|
|
|
hash_remove(&channel->nicks, s_nick);
|
|
|
|
|
nick_free(nick);
|
2006-06-08 20:55:26 +02:00
|
|
|
|
|
2005-05-30 15:20:17 +02:00
|
|
|
|
log_quit(LINK(server)->log, line->origin, channel->name,
|
2005-04-28 10:26:44 +02:00
|
|
|
|
line->elemc == 2 ? line->elemv[1] : NULL);
|
|
|
|
|
}
|
|
|
|
|
free(s_nick);
|
|
|
|
|
return OK_COPY;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void irc_server_startup(struct link_server *ircs)
|
|
|
|
|
{
|
|
|
|
|
char *nick;
|
|
|
|
|
|
|
|
|
|
if (LINK(ircs)->s_password)
|
|
|
|
|
WRITE_LINE1(CONN(ircs), NULL, "PASS", LINK(ircs)->s_password);
|
|
|
|
|
|
|
|
|
|
WRITE_LINE4(CONN(ircs), NULL, "USER", LINK(ircs)->user, "0", "*",
|
|
|
|
|
LINK(ircs)->real_name);
|
|
|
|
|
|
|
|
|
|
nick = ircs->nick;
|
|
|
|
|
if (LINK(ircs)->away_nick && LINK(ircs)->l_clientc == 0) {
|
|
|
|
|
if (nick)
|
|
|
|
|
free(nick);
|
|
|
|
|
nick = strdup(LINK(ircs)->away_nick);
|
|
|
|
|
}
|
2005-08-23 10:53:13 +02:00
|
|
|
|
if ((!LINK(ircs)->follow_nick && !LINK(ircs)->away_nick)
|
|
|
|
|
|| nick == NULL) {
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (nick)
|
|
|
|
|
free(nick);
|
|
|
|
|
nick = strdup(LINK(ircs)->connect_nick);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ircs->nick = nick;
|
|
|
|
|
WRITE_LINE1(CONN(ircs), NULL, "NICK", ircs->nick);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void server_next(struct link *l)
|
|
|
|
|
{
|
|
|
|
|
l->cur_server++;
|
|
|
|
|
if (l->cur_server >= l->serverc)
|
|
|
|
|
l->cur_server -= l->serverc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct link_client *irc_accept_new(connection_t *conn)
|
|
|
|
|
{
|
|
|
|
|
struct link_client *ircc;
|
|
|
|
|
connection_t *newconn;
|
|
|
|
|
|
|
|
|
|
newconn = accept_new(conn);
|
|
|
|
|
if (!newconn)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
ircc = calloc(sizeof(struct link_client), 1);
|
|
|
|
|
CONN(ircc) = newconn;
|
|
|
|
|
TYPE(ircc) = IRC_TYPE_LOGING_CLIENT;
|
|
|
|
|
CONN(ircc)->user_data = ircc;
|
|
|
|
|
return ircc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void server_cleanup(struct link_server *server)
|
|
|
|
|
{
|
|
|
|
|
if (server->nick) {
|
|
|
|
|
free(server->nick);
|
|
|
|
|
server->nick = NULL;
|
|
|
|
|
}
|
|
|
|
|
if (LINK(server)->s_state == IRCS_CONNECTED) {
|
|
|
|
|
LINK(server)->s_state = IRCS_WAS_CONNECTED;
|
|
|
|
|
} else {
|
|
|
|
|
struct line *s;
|
|
|
|
|
LINK(server)->s_state = IRCS_NONE;
|
|
|
|
|
while ((s = list_remove_first(&LINK(server)->init_strings)))
|
|
|
|
|
irc_line_free(s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hash_iterator_t hi;
|
|
|
|
|
for (hash_it_init(&server->channels, &hi); hash_it_item(&hi);
|
|
|
|
|
hash_it_next(&hi))
|
|
|
|
|
channel_free(hash_it_item(&hi));
|
|
|
|
|
hash_init(&server->channels, HASH_NOCASE);
|
|
|
|
|
|
|
|
|
|
if (CONN(server)) {
|
|
|
|
|
connection_free(CONN(server));
|
|
|
|
|
CONN(server) = NULL;
|
|
|
|
|
}
|
|
|
|
|
irc_lag_init(server);
|
2005-08-04 14:40:09 +02:00
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void irc_client_close(struct link_client *ic)
|
|
|
|
|
{
|
|
|
|
|
if (TYPE(ic) == IRC_TYPE_CLIENT) {
|
|
|
|
|
struct link_server *is = LINK(ic)->l_server;
|
|
|
|
|
log_client_disconnected(LINK(ic)->log);
|
|
|
|
|
unbind_from_link(ic);
|
|
|
|
|
if (LINK(ic)->l_clientc == 0) {
|
2006-04-23 18:38:57 +02:00
|
|
|
|
if (is && LINK(ic)->away_nick)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
WRITE_LINE1(CONN(is), NULL, "NICK",
|
|
|
|
|
LINK(ic)->away_nick);
|
2006-09-18 18:06:23 +02:00
|
|
|
|
if (is && LINK(ic)->no_client_away_msg)
|
|
|
|
|
WRITE_LINE1(CONN(is), NULL, "AWAY",
|
|
|
|
|
LINK(ic)->no_client_away_msg);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
log_client_none_connected(LINK(ic)->log);
|
|
|
|
|
}
|
|
|
|
|
irc_client_free(ic);
|
|
|
|
|
} else if (TYPE(ic) == IRC_TYPE_LOGING_CLIENT) {
|
|
|
|
|
irc_client_free(ic);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void irc_close(struct link_any *l)
|
|
|
|
|
{
|
|
|
|
|
if (CONN(l)) {
|
|
|
|
|
connection_free(CONN(l));
|
|
|
|
|
CONN(l) = NULL;
|
|
|
|
|
}
|
|
|
|
|
if (TYPE(l) == IRC_TYPE_SERVER) {
|
|
|
|
|
/* TODO: free link_server as a whole */
|
|
|
|
|
int timer = 0;
|
|
|
|
|
struct link_server *is = (struct link_server *)l;
|
|
|
|
|
|
|
|
|
|
if (LINK(is)->s_state == IRCS_CONNECTED)
|
|
|
|
|
irc_notify_disconnection(is);
|
|
|
|
|
irc_server_shutdown(is);
|
|
|
|
|
log_disconnected(LINK(is)->log);
|
|
|
|
|
|
|
|
|
|
server_next(LINK(is));
|
|
|
|
|
server_cleanup(is);
|
2005-05-27 12:25:31 +02:00
|
|
|
|
if (LINK(is)->last_connection &&
|
|
|
|
|
time(NULL) - LINK(is)->last_connection
|
2005-04-28 10:26:44 +02:00
|
|
|
|
< CONN_INTERVAL)
|
|
|
|
|
timer = RECONN_TIMER;
|
|
|
|
|
mylog(LOG_ERROR, "%s dead, reconnecting in %d seconds",
|
|
|
|
|
LINK(l)->name, timer);
|
|
|
|
|
LINK(is)->recon_timer = timer;
|
|
|
|
|
|
|
|
|
|
irc_server_free((struct link_server *)is);
|
2005-08-04 14:40:09 +02:00
|
|
|
|
LINK(is)->l_server = NULL;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
} else {
|
|
|
|
|
irc_client_close((struct link_client *)l);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-02-05 12:10:33 +01:00
|
|
|
|
struct link_client *irc_client_new(void)
|
|
|
|
|
{
|
|
|
|
|
struct link_client *c;
|
|
|
|
|
|
|
|
|
|
c = calloc(sizeof(struct link_client), 1);
|
|
|
|
|
list_init(&c->who_queue, list_ptr_cmp);
|
|
|
|
|
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
struct link_server *irc_server_new(struct link *link, connection_t *conn)
|
|
|
|
|
{
|
|
|
|
|
struct link_server *s;
|
|
|
|
|
|
|
|
|
|
s = calloc(sizeof(struct link_server), 1);
|
|
|
|
|
if (!s)
|
|
|
|
|
fatal("calloc");
|
|
|
|
|
|
|
|
|
|
TYPE(s) = IRC_TYPE_SERVER;
|
|
|
|
|
hash_init(&s->channels, HASH_NOCASE);
|
|
|
|
|
|
|
|
|
|
link->l_server = s;
|
|
|
|
|
LINK(s) = link;
|
|
|
|
|
CONN(s) = conn;
|
|
|
|
|
|
|
|
|
|
irc_lag_init(s);
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void irc_server_free(struct link_server *s)
|
|
|
|
|
{
|
|
|
|
|
if (s->nick)
|
|
|
|
|
free(s->nick);
|
|
|
|
|
if (s->user_mode)
|
|
|
|
|
free(s->user_mode);
|
|
|
|
|
free(s);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
connection_t *irc_server_connect(struct link *link)
|
|
|
|
|
{
|
|
|
|
|
struct link_server *ls;
|
|
|
|
|
connection_t *conn;
|
|
|
|
|
|
2005-11-17 18:55:12 +01:00
|
|
|
|
mylog(LOG_INFO, "Connecting user '%s' to network '%s' using server "
|
|
|
|
|
"%s:%d", link->username, link->name,
|
|
|
|
|
link->serverv[link->cur_server]->host,
|
|
|
|
|
link->serverv[link->cur_server]->port);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
conn = connection_new(link->serverv[link->cur_server]->host,
|
|
|
|
|
link->serverv[link->cur_server]->port,
|
|
|
|
|
link->vhost, link->bind_port,
|
2005-08-25 10:17:10 +02:00
|
|
|
|
#ifdef HAVE_LIBSSL
|
2005-06-04 13:05:54 +02:00
|
|
|
|
link->s_ssl, link->ssl_check_mode,
|
2005-08-25 10:17:10 +02:00
|
|
|
|
link->ssl_check_store,
|
|
|
|
|
#else
|
|
|
|
|
0, 0, NULL,
|
|
|
|
|
#endif
|
|
|
|
|
CONNECT_TIMEOUT);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
if (!conn)
|
|
|
|
|
fatal("connection_new");
|
|
|
|
|
|
|
|
|
|
ls = irc_server_new(link, conn);
|
|
|
|
|
|
|
|
|
|
conn->user_data = ls;
|
|
|
|
|
irc_server_startup(ls);
|
|
|
|
|
return conn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int irc_server_lag_compute(struct link *l)
|
|
|
|
|
{
|
|
|
|
|
struct link_server *server = l->l_server;
|
|
|
|
|
|
|
|
|
|
if (LINK(server)->s_state == IRCS_CONNECTED) {
|
|
|
|
|
if (server->laginit_ts != -1) {
|
|
|
|
|
irc_compute_lag(server);
|
|
|
|
|
if (!irc_lags_out(server))
|
|
|
|
|
return 0;
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
server->lagtest_timeout--;
|
|
|
|
|
if (server->lagtest_timeout == 0)
|
|
|
|
|
irc_start_lagtest(server);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void irc_server_shutdown(struct link_server *s)
|
|
|
|
|
{
|
|
|
|
|
if (!s->nick)
|
|
|
|
|
return;
|
|
|
|
|
if (LINK(s)->prev_nick)
|
|
|
|
|
free(LINK(s)->prev_nick);
|
|
|
|
|
LINK(s)->prev_nick = strdup(s->nick);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2005-05-12 10:29:27 +02:00
|
|
|
|
#ifdef HAVE_OIDENTD
|
|
|
|
|
/* ugly */
|
|
|
|
|
void oidentd_dump(list_t *connl)
|
|
|
|
|
{
|
|
|
|
|
list_iterator_t it;
|
|
|
|
|
FILE *f;
|
|
|
|
|
char *home;
|
|
|
|
|
char tmpbuf[256];
|
2005-05-13 15:58:24 +02:00
|
|
|
|
int err;
|
2005-05-12 10:29:27 +02:00
|
|
|
|
|
|
|
|
|
home = getenv("HOME");
|
|
|
|
|
if (!home)
|
|
|
|
|
return;
|
|
|
|
|
strcpy(tmpbuf, home);
|
|
|
|
|
strcat(tmpbuf, "/.oidentd.conf");
|
|
|
|
|
f = fopen(tmpbuf, "w");
|
|
|
|
|
if (!f)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (list_it_init(connl, &it); list_it_item(&it); list_it_next(&it)) {
|
|
|
|
|
connection_t *c = list_it_item(&it);
|
|
|
|
|
struct link_any *la = c->user_data;
|
|
|
|
|
if (c->connected == CONN_OK && la &&
|
|
|
|
|
TYPE(la) == IRC_TYPE_SERVER) {
|
|
|
|
|
struct link_server *ls = (struct link_server*)la;
|
|
|
|
|
struct link *l = LINK(ls);
|
|
|
|
|
|
|
|
|
|
char *localip, *remoteip;
|
|
|
|
|
int localport, remoteport;
|
|
|
|
|
|
|
|
|
|
localip = connection_localip(CONN(ls));
|
|
|
|
|
localport = connection_localport(CONN(ls));
|
|
|
|
|
remoteip = connection_remoteip(CONN(ls));
|
|
|
|
|
remoteport = connection_remoteport(CONN(ls));
|
|
|
|
|
|
2005-05-13 15:58:24 +02:00
|
|
|
|
fprintf(f, "to %s fport %d from %s lport %d {\n",
|
2005-05-12 10:29:27 +02:00
|
|
|
|
remoteip, remoteport, localip,
|
|
|
|
|
localport);
|
2005-05-13 15:58:24 +02:00
|
|
|
|
fprintf(f, "\treply \"%s\"\n", l->user);
|
2005-05-12 10:29:27 +02:00
|
|
|
|
fprintf(f, "}\n");
|
|
|
|
|
free(localip);
|
|
|
|
|
free(remoteip);
|
|
|
|
|
}
|
|
|
|
|
}
|
2005-05-19 01:31:14 +02:00
|
|
|
|
fflush(f);
|
2005-05-12 10:29:27 +02:00
|
|
|
|
fclose(f);
|
2005-05-13 15:58:24 +02:00
|
|
|
|
err = chmod(tmpbuf, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
|
|
|
|
if (err) {
|
|
|
|
|
mylog(LOG_WARN, "Unable to set modes for '%s': %s", tmpbuf,
|
|
|
|
|
strerror(errno));
|
|
|
|
|
}
|
2005-05-12 10:29:27 +02:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2005-05-27 18:50:26 +02:00
|
|
|
|
/* do not use */
|
|
|
|
|
list_t *_connections = NULL;
|
2005-05-12 10:29:27 +02:00
|
|
|
|
|
2007-01-05 22:19:32 +01:00
|
|
|
|
void timeout_clean_who_counts(list_t *conns)
|
|
|
|
|
{
|
|
|
|
|
list_iterator_t it;
|
|
|
|
|
for (list_it_init(conns, &it); list_it_item(&it); list_it_next(&it)) {
|
|
|
|
|
struct link *l = list_it_item(&it);
|
|
|
|
|
struct link_client *client = l->who_client;
|
|
|
|
|
|
|
|
|
|
if (client && client->whoc_tstamp) {
|
|
|
|
|
time_t now;
|
|
|
|
|
now = time(NULL);
|
|
|
|
|
if (now - client->whoc_tstamp > 10) {
|
|
|
|
|
mylog(LOG_DEBUG, "Yawn, "
|
|
|
|
|
"forgetting one who reply");
|
|
|
|
|
if (client->who_count > 0)
|
|
|
|
|
--client->who_count;
|
|
|
|
|
client->whoc_tstamp = time(NULL);
|
|
|
|
|
if (client->who_count == 0)
|
|
|
|
|
rotate_who_client(l);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
struct link_client *reloading_client;
|
|
|
|
|
/*
|
|
|
|
|
* The main loop
|
|
|
|
|
* inc is the incoming connection, clientl list a list of client struct that
|
|
|
|
|
* represent the accepcted credentials
|
|
|
|
|
*/
|
|
|
|
|
void irc_main(connection_t *inc, list_t *ll)
|
|
|
|
|
{
|
|
|
|
|
list_t reconnectl;
|
|
|
|
|
list_t timerwaitl;
|
|
|
|
|
list_t connl;
|
|
|
|
|
list_t connecting_c;
|
|
|
|
|
list_t connected_c;
|
|
|
|
|
int timeleft = 1000;
|
|
|
|
|
int logflush_timer = conf_log_sync_interval;
|
|
|
|
|
|
|
|
|
|
list_init(&reconnectl, NULL);
|
|
|
|
|
list_init(&timerwaitl, NULL);
|
|
|
|
|
list_init(&connl, list_ptr_cmp);
|
|
|
|
|
list_init(&connecting_c, list_ptr_cmp);
|
|
|
|
|
list_init(&connected_c, list_ptr_cmp);
|
|
|
|
|
|
2005-05-27 18:50:26 +02:00
|
|
|
|
_connections = &connl;
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/* XXX: This one MUST be first */
|
|
|
|
|
list_add_first(&connl, inc);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Merge with already connected data, happens on SIGHUP
|
|
|
|
|
*/
|
|
|
|
|
list_iterator_t it;
|
|
|
|
|
for (list_it_init(ll, &it); list_it_item(&it); list_it_next(&it)) {
|
|
|
|
|
struct link *link = list_it_item(&it);
|
|
|
|
|
if (link->l_server)
|
|
|
|
|
list_add_last(&connl, CONN(link->l_server));
|
|
|
|
|
else
|
|
|
|
|
list_add_last(&reconnectl, link);
|
|
|
|
|
if (link->l_clientc) {
|
|
|
|
|
int i;
|
2005-05-24 00:51:33 +02:00
|
|
|
|
for (i = 0; i < link->l_clientc; i++) {
|
|
|
|
|
struct link_client *c;
|
|
|
|
|
c = link->l_clientv[i];
|
|
|
|
|
list_add_last(&connl, CONN(c));
|
|
|
|
|
if (TYPE(c) == IRC_TYPE_LOGING_CLIENT)
|
|
|
|
|
list_add_last(&connecting_c, c);
|
|
|
|
|
if (TYPE(c) == IRC_TYPE_CLIENT)
|
|
|
|
|
list_add_last(&connected_c, c);
|
|
|
|
|
}
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (conf_error && reloading_client) {
|
|
|
|
|
char *nick;
|
|
|
|
|
if (LINK(reloading_client)->l_server)
|
|
|
|
|
nick = LINK(reloading_client)->l_server->nick;
|
|
|
|
|
else
|
|
|
|
|
nick = LINK(reloading_client)->prev_nick;
|
|
|
|
|
WRITE_LINE2(CONN(reloading_client), P_IRCMASK, "PRIVMSG", nick,
|
|
|
|
|
conf_errstr);
|
|
|
|
|
reloading_client = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (!sighup) {
|
|
|
|
|
struct link *link;
|
|
|
|
|
connection_t *conn;
|
|
|
|
|
|
|
|
|
|
if (timeleft == 0) {
|
2007-01-05 22:19:32 +01:00
|
|
|
|
/*
|
|
|
|
|
* Compute timeouts for next reconnections and lagouts
|
|
|
|
|
*/
|
2005-05-24 01:05:11 +02:00
|
|
|
|
static int throttle_prot = S_CONN_DELAY - 1;
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
timeleft = 1000;
|
|
|
|
|
|
2005-05-24 01:05:11 +02:00
|
|
|
|
if (++throttle_prot == S_CONN_DELAY) {
|
|
|
|
|
throttle_prot = 0;
|
|
|
|
|
|
|
|
|
|
/* Lauch one reconnection at a time */
|
|
|
|
|
if ((link = list_remove_first(&reconnectl))) {
|
|
|
|
|
conn = irc_server_connect(link);
|
|
|
|
|
list_add_last(&connl, conn);
|
2005-05-27 12:25:31 +02:00
|
|
|
|
link->last_connection = time(NULL);
|
2005-05-24 01:05:11 +02:00
|
|
|
|
}
|
2005-05-24 00:55:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/* log flushs */
|
|
|
|
|
if (logflush_timer-- <= 0) {
|
|
|
|
|
logflush_timer = conf_log_sync_interval;
|
|
|
|
|
log_flush_all();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* reconnects */
|
|
|
|
|
list_iterator_t li;
|
|
|
|
|
for (list_it_init(&timerwaitl, &li); list_it_item(&li);
|
|
|
|
|
list_it_next(&li)) {
|
|
|
|
|
struct link *l = list_it_item(&li);
|
|
|
|
|
if (l->recon_timer <= 0) {
|
|
|
|
|
list_it_remove(&li);
|
|
|
|
|
list_add_last(&reconnectl, l);
|
|
|
|
|
} else {
|
|
|
|
|
l->recon_timer--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* server lags */
|
|
|
|
|
for (list_it_init(ll, &li); list_it_item(&li);
|
|
|
|
|
list_it_next(&li)) {
|
|
|
|
|
struct link *l = list_it_item(&li);
|
|
|
|
|
if(l->l_server && irc_server_lag_compute(l)) {
|
|
|
|
|
log_ping_timeout(l->log);
|
|
|
|
|
list_remove(&connl, CONN(l->l_server));
|
|
|
|
|
irc_close((struct link_any *)
|
|
|
|
|
l->l_server);
|
|
|
|
|
list_add_last(&timerwaitl, l);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* drop lagging connecting client */
|
|
|
|
|
for (list_it_init(&connecting_c, &li);
|
|
|
|
|
list_it_item(&li); list_it_next(&li)) {
|
|
|
|
|
struct link_client *ic = list_it_item(&li);
|
|
|
|
|
ic->logging_timer++;
|
|
|
|
|
if (ic->logging_timer > LOGGING_TIMEOUT) {
|
|
|
|
|
list_remove(&connl, CONN(ic));
|
|
|
|
|
irc_close((struct link_any *)ic);
|
|
|
|
|
list_it_remove(&li);
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-01-05 22:19:32 +01:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Cleanup lagging or dangling who_count buffers
|
|
|
|
|
*/
|
|
|
|
|
timeout_clean_who_counts(ll);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
}
|
|
|
|
|
|
2005-05-12 10:29:27 +02:00
|
|
|
|
int nc;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
/* Da main loop */
|
2005-05-12 10:29:27 +02:00
|
|
|
|
list_t *ready = wait_event(&connl, &timeleft, &nc);
|
|
|
|
|
#ifdef HAVE_OIDENTD
|
|
|
|
|
if (nc)
|
|
|
|
|
oidentd_dump(&connl);
|
|
|
|
|
#endif
|
2005-04-28 10:26:44 +02:00
|
|
|
|
while ((conn = list_remove_first(ready))) {
|
|
|
|
|
struct link_any *lc =
|
|
|
|
|
(struct link_any *)conn->user_data;
|
|
|
|
|
|
|
|
|
|
if (conn == inc) {
|
|
|
|
|
struct link_client *n = irc_accept_new(conn);
|
|
|
|
|
if (!n)
|
|
|
|
|
fatal("Problem while binding local"
|
|
|
|
|
" socket");
|
|
|
|
|
list_add_last(&connl, CONN(n));
|
|
|
|
|
list_add_last(&connecting_c, n);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* reached only if socket is not listening */
|
|
|
|
|
int err;
|
|
|
|
|
list_t *linel = read_lines(conn, &err);
|
|
|
|
|
if (err) {
|
|
|
|
|
if (TYPE(lc) == IRC_TYPE_SERVER) {
|
|
|
|
|
mylog(LOG_ERROR, "read_lines error, "
|
|
|
|
|
"closing %s ...",
|
|
|
|
|
LINK(lc)->name);
|
|
|
|
|
irc_server_shutdown(LINK(lc)->l_server);
|
|
|
|
|
} else {
|
|
|
|
|
mylog(LOG_ERROR, "read_lines error, "
|
|
|
|
|
"closing...");
|
|
|
|
|
}
|
|
|
|
|
goto prot_err;
|
|
|
|
|
}
|
|
|
|
|
if (!linel)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
char *line_s;
|
|
|
|
|
while ((line_s = list_remove_first(linel))) {
|
|
|
|
|
struct line *line;
|
|
|
|
|
mylog(LOG_DEBUG, "\"%s\"", line_s);
|
|
|
|
|
if (*line_s == 0) { /* irssi does that.*/
|
|
|
|
|
free(line_s);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
line = irc_line(line_s);
|
|
|
|
|
if (!line) {
|
|
|
|
|
mylog(LOG_ERROR, "Error in protocol, "
|
|
|
|
|
"closing...");
|
|
|
|
|
free(line_s);
|
|
|
|
|
goto prot_err_lines;
|
|
|
|
|
}
|
|
|
|
|
int r;
|
|
|
|
|
int oldtype = TYPE(lc);
|
|
|
|
|
r = irc_dispatch((struct link_any*)
|
|
|
|
|
conn->user_data, line, ll);
|
|
|
|
|
irc_line_free(line);
|
|
|
|
|
free(line_s);
|
|
|
|
|
if (r == ERR_PROTOCOL) {
|
|
|
|
|
mylog(LOG_ERROR, "Error in protocol, "
|
|
|
|
|
"closing...");
|
|
|
|
|
goto prot_err_lines;
|
|
|
|
|
}
|
2005-05-16 00:46:28 +02:00
|
|
|
|
if (r == ERR_AUTH)
|
2005-04-28 10:26:44 +02:00
|
|
|
|
goto prot_err_lines;
|
|
|
|
|
/* XXX: not real error */
|
|
|
|
|
if (r == OK_CLOSE)
|
|
|
|
|
goto prot_err_lines;
|
|
|
|
|
|
|
|
|
|
if (oldtype == IRC_TYPE_LOGING_CLIENT &&
|
|
|
|
|
TYPE(lc) == IRC_TYPE_CLIENT) {
|
|
|
|
|
list_remove(&connecting_c, lc);
|
|
|
|
|
list_add_last(&connected_c, lc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
list_free(linel);
|
|
|
|
|
continue;
|
|
|
|
|
prot_err_lines:
|
|
|
|
|
while ((line_s = list_remove_first(linel)))
|
|
|
|
|
free(line_s);
|
|
|
|
|
prot_err:
|
|
|
|
|
list_remove(&connl, conn);
|
|
|
|
|
if (linel)
|
|
|
|
|
list_free(linel);
|
|
|
|
|
if (lc) {
|
|
|
|
|
if (TYPE(lc) == IRC_TYPE_CLIENT)
|
|
|
|
|
list_remove(&connected_c, lc);
|
|
|
|
|
if (TYPE(lc) == IRC_TYPE_LOGING_CLIENT)
|
|
|
|
|
list_remove(&connecting_c, lc);
|
|
|
|
|
if (TYPE(lc) == IRC_TYPE_SERVER)
|
|
|
|
|
list_add_last(&timerwaitl, LINK(lc));
|
|
|
|
|
irc_close(lc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
list_free(ready);
|
|
|
|
|
}
|
2005-05-26 17:36:15 +02:00
|
|
|
|
while (list_remove_first(&connecting_c))
|
|
|
|
|
;
|
|
|
|
|
while (list_remove_first(&connected_c))
|
|
|
|
|
;
|
|
|
|
|
while (list_remove_first(&connl))
|
|
|
|
|
;
|
|
|
|
|
while (list_remove_first(&timerwaitl))
|
|
|
|
|
;
|
|
|
|
|
while (list_remove_first(&reconnectl))
|
|
|
|
|
;
|
2005-05-27 18:50:26 +02:00
|
|
|
|
_connections = NULL;
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void irc_client_free(struct link_client *cli)
|
|
|
|
|
{
|
|
|
|
|
if (CONN(cli))
|
|
|
|
|
connection_free(CONN(cli));
|
|
|
|
|
if (cli->init_pass)
|
|
|
|
|
free(cli->init_pass);
|
|
|
|
|
if (cli->init_nick)
|
|
|
|
|
free(cli->init_nick);
|
|
|
|
|
free(cli);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
void irc_server_free(struct link_server *is)
|
|
|
|
|
{
|
|
|
|
|
free(is);
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
struct link *irc_link_new()
|
|
|
|
|
{
|
|
|
|
|
struct link *link;
|
|
|
|
|
link = calloc(sizeof(struct link), 1);
|
|
|
|
|
if (!link)
|
|
|
|
|
fatal("calloc");
|
|
|
|
|
|
|
|
|
|
hash_init(&link->chan_infos, HASH_NOCASE);
|
2005-05-30 20:35:49 +02:00
|
|
|
|
list_init(&link->chan_infos_order, list_ptr_cmp);
|
2006-09-18 18:06:23 +02:00
|
|
|
|
list_init(&link->on_connect_send, list_ptr_cmp);
|
2005-04-28 10:26:44 +02:00
|
|
|
|
return link;
|
|
|
|
|
}
|
|
|
|
|
|