commit
b68b0dc71d
5
NEWS
5
NEWS
@ -1,3 +1,8 @@
|
|||||||
|
29-10-2007: Certificate validation change. In "basic" mode, expired
|
||||||
|
certificates are now accepted as long as they are in store (therefore trusted).
|
||||||
|
This makes the basic mode be more SSH like. Some extreme security zealots might
|
||||||
|
want to be warned.
|
||||||
|
|
||||||
02-09-2007: as of now log parameters go in the user {} statment. This brakes
|
02-09-2007: as of now log parameters go in the user {} statment. This brakes
|
||||||
every config and there is no backwrads compatibility as of now.
|
every config and there is no backwrads compatibility as of now.
|
||||||
Lots of internal changes, expect crashes.
|
Lots of internal changes, expect crashes.
|
||||||
|
1
TODO
1
TODO
@ -1,3 +1,4 @@
|
|||||||
|
- check conn_list usage: esp wrt list_remove and closes
|
||||||
- uid, gid
|
- uid, gid
|
||||||
- keep invites when detached ?
|
- keep invites when detached ?
|
||||||
- allow global (or per net ?) IP filtering
|
- allow global (or per net ?) IP filtering
|
||||||
|
@ -226,7 +226,12 @@ The password. It \fBMUST\fP be generated with \fBbimkpw\fP or it'll not work.
|
|||||||
Tells whether BIP should check the server SSL certificate and against what.
|
Tells whether BIP should check the server SSL certificate and against what.
|
||||||
Can be \fBnone\fP for no check at all, \fBca\fP to check if the cert is signed
|
Can be \fBnone\fP for no check at all, \fBca\fP to check if the cert is signed
|
||||||
by a Certificate Authority in repository, or \fBbasic\fP to check if cert
|
by a Certificate Authority in repository, or \fBbasic\fP to check if cert
|
||||||
exists in repository. The repository is defined by \fBssl_check_store\fP.
|
exists in repository. The repository is defined by \fBssl_check_store\fP. This
|
||||||
|
allows a "ssh-like" private key generation scheme. Note that in basic mode:
|
||||||
|
.br
|
||||||
|
- expired certificates that are in the store are considered valid.
|
||||||
|
.br
|
||||||
|
- CA-signed certificates are considered valid even if not in store.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fBssl_check_store\fP (default: \fBnot set\fP)
|
\fBssl_check_store\fP (default: \fBnot set\fP)
|
||||||
|
@ -37,7 +37,7 @@ log_level = 3;
|
|||||||
# %m -> 2 digit month
|
# %m -> 2 digit month
|
||||||
# %d -> 2 digit day
|
# %d -> 2 digit day
|
||||||
# %c -> destination (#chan, privates, ...)
|
# %c -> destination (#chan, privates, ...)
|
||||||
#log_format = "%n/%Y-%m/%c.%d.log";
|
#log_format = "%u/%n/%Y-%m/%c.%d.log";
|
||||||
|
|
||||||
# Sets the frequency (in seconds) of log syncing (real write to kernel)
|
# Sets the frequency (in seconds) of log syncing (real write to kernel)
|
||||||
#log_sync_interval = 5;
|
#log_sync_interval = 5;
|
||||||
|
13
scripts/bip-take-snapshot
Executable file
13
scripts/bip-take-snapshot
Executable file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
prefix=bip-$(date +%y%m%d)
|
||||||
|
|
||||||
|
if [ ! -d src ] ; then
|
||||||
|
echo "Please run me in bip sources root." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
git-archive --format=tar --prefix=$prefix/ HEAD | gzip -c > ../$prefix.tar.gz
|
||||||
|
|
399
src/bip.c
399
src/bip.c
@ -17,6 +17,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#include "irc.h"
|
#include "irc.h"
|
||||||
@ -48,7 +49,7 @@ int conf_log = DEFAULT_LOG;
|
|||||||
int conf_log_system = DEFAULT_LOG_SYSTEM;
|
int conf_log_system = DEFAULT_LOG_SYSTEM;
|
||||||
int conf_log_sync_interval = DEFAULT_LOG_SYNC_INTERVAL;
|
int conf_log_sync_interval = DEFAULT_LOG_SYNC_INTERVAL;
|
||||||
|
|
||||||
list_t *parse_conf(FILE *file);
|
list_t *parse_conf(FILE *file, int *err);
|
||||||
static void conf_die(char *fmt, ...);
|
static void conf_die(char *fmt, ...);
|
||||||
#ifdef HAVE_LIBSSL
|
#ifdef HAVE_LIBSSL
|
||||||
int adm_trust(struct link_client *ic, struct line *line);
|
int adm_trust(struct link_client *ic, struct line *line);
|
||||||
@ -56,6 +57,7 @@ int adm_trust(struct link_client *ic, struct line *line);
|
|||||||
static char *get_tuple_value(list_t *tuple_l, int lex);
|
static char *get_tuple_value(list_t *tuple_l, int lex);
|
||||||
void bip_notify(struct link_client *ic, char *fmt, ...);
|
void bip_notify(struct link_client *ic, char *fmt, ...);
|
||||||
void adm_list_connections(struct link_client *ic, struct user *bu);
|
void adm_list_connections(struct link_client *ic, struct user *bu);
|
||||||
|
void free_conf(list_t *l);
|
||||||
|
|
||||||
static void hash_binary(char *hex, unsigned char **password, unsigned int *seed)
|
static void hash_binary(char *hex, unsigned char **password, unsigned int *seed)
|
||||||
{
|
{
|
||||||
@ -94,7 +96,7 @@ static int add_server(struct server *s, list_t *data)
|
|||||||
while ((t = list_remove_first(data))) {
|
while ((t = list_remove_first(data))) {
|
||||||
switch (t->type) {
|
switch (t->type) {
|
||||||
case LEX_HOST:
|
case LEX_HOST:
|
||||||
s->host = t->pdata;
|
MOVE_STRING(s->host, t->pdata);
|
||||||
break;
|
break;
|
||||||
case LEX_PORT:
|
case LEX_PORT:
|
||||||
s->port = t->ndata;
|
s->port = t->ndata;
|
||||||
@ -102,6 +104,9 @@ static int add_server(struct server *s, list_t *data)
|
|||||||
default:
|
default:
|
||||||
fatal("Config error in server block (%d)", t->type);
|
fatal("Config error in server block (%d)", t->type);
|
||||||
}
|
}
|
||||||
|
if (t->tuple_type == TUPLE_STR && t->pdata)
|
||||||
|
free(t->pdata);
|
||||||
|
free(t);
|
||||||
}
|
}
|
||||||
if (!s->host) {
|
if (!s->host) {
|
||||||
free(s);
|
free(s);
|
||||||
@ -115,23 +120,12 @@ static int add_server(struct server *s, list_t *data)
|
|||||||
|
|
||||||
extern list_t *root_list;
|
extern list_t *root_list;
|
||||||
int yyparse();
|
int yyparse();
|
||||||
int conf_error;
|
|
||||||
char conf_errstr[ERRBUFSZ];
|
|
||||||
|
|
||||||
static void conf_start(void)
|
|
||||||
{
|
|
||||||
conf_error = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void conf_die(char *fmt, ...)
|
static void conf_die(char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
|
_mylog(LOG_ERROR, fmt, ap);
|
||||||
vsnprintf(conf_errstr, ERRBUFSZ, fmt, ap);
|
|
||||||
conf_errstr[ERRBUFSZ - 1] = 0;
|
|
||||||
conf_error = 1;
|
|
||||||
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,8 +301,9 @@ static int add_network(bip_t *bip, list_t *data)
|
|||||||
struct tuple *t;
|
struct tuple *t;
|
||||||
struct network *n;
|
struct network *n;
|
||||||
int i;
|
int i;
|
||||||
|
int r;
|
||||||
|
|
||||||
char *name = get_tuple_value(data, LEX_NAME);
|
char *name = get_tuple_pvalue(data, LEX_NAME);
|
||||||
|
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
conf_die("Network with no name");
|
conf_die("Network with no name");
|
||||||
@ -340,29 +335,103 @@ static int add_network(bip_t *bip, list_t *data)
|
|||||||
n->serverv = realloc(n->serverv, (n->serverc + 1)
|
n->serverv = realloc(n->serverv, (n->serverc + 1)
|
||||||
* sizeof(struct server));
|
* sizeof(struct server));
|
||||||
n->serverc++;
|
n->serverc++;
|
||||||
add_server(&n->serverv[n->serverc - 1], t->pdata);
|
memset(&n->serverv[n->serverc - 1], 0,
|
||||||
|
sizeof(struct server));
|
||||||
|
r = add_server(&n->serverv[n->serverc - 1], t->pdata);
|
||||||
|
if (!r) {
|
||||||
|
n->serverc--;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
free(t->pdata);
|
free(t->pdata);
|
||||||
t->pdata = NULL;
|
t->pdata = NULL;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
conf_die("unknown keyword in network statement");
|
conf_die("unknown keyword in network statement");
|
||||||
if (t->type == TUPLE_STR)
|
return 0;
|
||||||
free(t->pdata);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (t->type == TUPLE_STR && t->pdata)
|
if (t->tuple_type == TUPLE_STR && t->pdata)
|
||||||
free(t->pdata);
|
free(t->pdata);
|
||||||
free(t);
|
free(t);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void adm_bip_delconn(bip_t *bip, struct link_client *ic, char *conn_name)
|
||||||
|
{
|
||||||
|
struct user *user = LINK(ic)->user;
|
||||||
|
struct link *l;
|
||||||
|
|
||||||
|
if (!hash_get(&user->connections, conn_name)) {
|
||||||
|
adm_reply(ic, "cannot find this connection");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
l = hash_get(&user->connections, conn_name);
|
||||||
|
link_kill(bip, l);
|
||||||
|
adm_reply(ic, "deleted");
|
||||||
|
}
|
||||||
|
|
||||||
|
void adm_bip_addconn(bip_t *bip, struct link_client *ic, char *conn_name,
|
||||||
|
char *network_name)
|
||||||
|
{
|
||||||
|
struct user *user = LINK(ic)->user;
|
||||||
|
struct network *network;
|
||||||
|
|
||||||
|
/* check name uniqueness */
|
||||||
|
if (hash_get(&user->connections, conn_name)) {
|
||||||
|
adm_reply(ic, "connection name already exists for this user.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check we know about this network */
|
||||||
|
network = hash_get(&bip->networks, network_name);
|
||||||
|
if (!network) {
|
||||||
|
adm_reply(ic, "no such network name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct link *l;
|
||||||
|
l = irc_link_new();
|
||||||
|
l->name = strdup(conn_name);
|
||||||
|
hash_insert(&user->connections, conn_name, l);
|
||||||
|
list_add_last(&bip->link_list, l);
|
||||||
|
l->user = user;
|
||||||
|
l->network = network;
|
||||||
|
l->log = log_new(user, conn_name);
|
||||||
|
#ifdef HAVE_LIBSSL
|
||||||
|
l->ssl_check_mode = user->ssl_check_mode;
|
||||||
|
l->untrusted_certs = sk_X509_new_null();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#define SCOPY(member) l->member = (LINK(ic)->member ? strdup(LINK(ic)->member) : NULL)
|
||||||
|
#define ICOPY(member) l->member = LINK(ic)->member
|
||||||
|
|
||||||
|
SCOPY(connect_nick);
|
||||||
|
SCOPY(username);
|
||||||
|
SCOPY(realname);
|
||||||
|
/* we don't copy server password */
|
||||||
|
SCOPY(vhost);
|
||||||
|
ICOPY(follow_nick);
|
||||||
|
ICOPY(ignore_first_nick);
|
||||||
|
SCOPY(away_nick);
|
||||||
|
SCOPY(no_client_away_msg);
|
||||||
|
/* we don't copy on_connect_send */
|
||||||
|
#ifdef HAVE_LIBSSL
|
||||||
|
ICOPY(ssl_check_mode);
|
||||||
|
#endif
|
||||||
|
#undef SCOPY
|
||||||
|
#undef ICOPY
|
||||||
|
adm_reply(ic, "connection added, you should soon be able to connect");
|
||||||
|
}
|
||||||
|
|
||||||
static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
||||||
{
|
{
|
||||||
struct tuple *t, *t2;
|
struct tuple *t, *t2;
|
||||||
struct link *l;
|
struct link *l;
|
||||||
struct chan_info *ci;
|
struct chan_info *ci;
|
||||||
char *name = get_tuple_value(data, LEX_NAME);
|
char *name = get_tuple_pvalue(data, LEX_NAME);
|
||||||
|
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
conf_die("Connection with no name");
|
conf_die("Connection with no name");
|
||||||
@ -380,7 +449,6 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
|||||||
l->untrusted_certs = sk_X509_new_null();
|
l->untrusted_certs = sk_X509_new_null();
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
#warning "CODEME (user switch..)"
|
|
||||||
l->network = NULL;
|
l->network = NULL;
|
||||||
log_reinit_all(l->log);
|
log_reinit_all(l->log);
|
||||||
}
|
}
|
||||||
@ -416,8 +484,20 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
|||||||
MOVE_STRING(l->vhost, t->pdata);
|
MOVE_STRING(l->vhost, t->pdata);
|
||||||
break;
|
break;
|
||||||
case LEX_CHANNEL:
|
case LEX_CHANNEL:
|
||||||
ci = calloc(sizeof(struct chan_info), 1);
|
name = get_tuple_pvalue(t->pdata, LEX_NAME);
|
||||||
ci->backlog = 1;
|
if (name == NULL) {
|
||||||
|
conf_die("Channel with no name");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ci = hash_get(&l->chan_infos, name);
|
||||||
|
if (!ci) {
|
||||||
|
ci = chan_info_new();
|
||||||
|
hash_insert(&l->chan_infos, name, ci);
|
||||||
|
/* FIXME: this order is not reloaded */
|
||||||
|
list_add_last(&l->chan_infos_order, ci);
|
||||||
|
ci->backlog = 1;
|
||||||
|
}
|
||||||
|
|
||||||
while ((t2 = list_remove_first(t->pdata))) {
|
while ((t2 = list_remove_first(t->pdata))) {
|
||||||
switch (t2->type) {
|
switch (t2->type) {
|
||||||
@ -431,11 +511,11 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
|||||||
ci->backlog = t2->ndata;
|
ci->backlog = t2->ndata;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (t2->tuple_type == TUPLE_STR && t2->pdata)
|
||||||
|
free(t2->pdata);
|
||||||
|
free(t2);
|
||||||
}
|
}
|
||||||
list_free(t->pdata);
|
list_free(t->pdata);
|
||||||
|
|
||||||
hash_insert(&l->chan_infos, ci->name, ci);
|
|
||||||
list_add_last(&l->chan_infos_order, ci);
|
|
||||||
break;
|
break;
|
||||||
case LEX_FOLLOW_NICK:
|
case LEX_FOLLOW_NICK:
|
||||||
l->follow_nick = t->ndata;
|
l->follow_nick = t->ndata;
|
||||||
@ -451,6 +531,7 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
|||||||
break;
|
break;
|
||||||
case LEX_ON_CONNECT_SEND:
|
case LEX_ON_CONNECT_SEND:
|
||||||
list_add_last(&l->on_connect_send, t->pdata);
|
list_add_last(&l->on_connect_send, t->pdata);
|
||||||
|
t->pdata = NULL;
|
||||||
break;
|
break;
|
||||||
#ifdef HAVE_LIBSSL
|
#ifdef HAVE_LIBSSL
|
||||||
case LEX_SSL_CHECK_MODE:
|
case LEX_SSL_CHECK_MODE:
|
||||||
@ -458,15 +539,13 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
|||||||
l->ssl_check_mode = SSL_CHECK_BASIC;
|
l->ssl_check_mode = SSL_CHECK_BASIC;
|
||||||
if (strcmp(t->pdata, "ca") == 0)
|
if (strcmp(t->pdata, "ca") == 0)
|
||||||
l->ssl_check_mode = SSL_CHECK_CA;
|
l->ssl_check_mode = SSL_CHECK_CA;
|
||||||
free(t->pdata);
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
conf_die("unknown keyword in connection statement");
|
conf_die("unknown keyword in connection statement");
|
||||||
if (t->type == TUPLE_STR)
|
return 0;
|
||||||
free(t->pdata);
|
|
||||||
}
|
}
|
||||||
if (t->type == TUPLE_STR && t->pdata)
|
if (t->tuple_type == TUPLE_STR && t->pdata)
|
||||||
free(t->pdata);
|
free(t->pdata);
|
||||||
free(t);
|
free(t);
|
||||||
}
|
}
|
||||||
@ -488,10 +567,12 @@ static int add_connection(bip_t *bip, struct user *user, list_t *data)
|
|||||||
conf_die("No realname set and no default realname.");
|
conf_die("No realname set and no default realname.");
|
||||||
l->realname = strdup(user->default_realname);
|
l->realname = strdup(user->default_realname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
l->in_use = 1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *get_tuple_value(list_t *tuple_l, int lex)
|
static char *get_tuple_pvalue(list_t *tuple_l, int lex)
|
||||||
{
|
{
|
||||||
struct tuple *t;
|
struct tuple *t;
|
||||||
list_iterator_t it;
|
list_iterator_t it;
|
||||||
@ -504,13 +585,35 @@ static char *get_tuple_value(list_t *tuple_l, int lex)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_user(bip_t *bip, list_t *data)
|
static int get_tuple_nvalue(list_t *tuple_l, int lex)
|
||||||
|
{
|
||||||
|
struct tuple *t;
|
||||||
|
list_iterator_t it;
|
||||||
|
|
||||||
|
for (list_it_init(tuple_l, &it); (t = list_it_item(&it));
|
||||||
|
list_it_next(&it)) {
|
||||||
|
if (t->type == lex)
|
||||||
|
return t->ndata;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct historical_directives {
|
||||||
|
int always_backlog;
|
||||||
|
int backlog;
|
||||||
|
int bl_msg_only;
|
||||||
|
int backlog_lines;
|
||||||
|
int backlog_no_timestamp;
|
||||||
|
int blreset_on_talk;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int add_user(bip_t *bip, list_t *data, struct historical_directives *hds)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
struct tuple *t;
|
struct tuple *t;
|
||||||
struct user *u;
|
struct user *u;
|
||||||
|
|
||||||
char *name = get_tuple_value(data, LEX_NAME);
|
char *name = get_tuple_pvalue(data, LEX_NAME);
|
||||||
|
|
||||||
if (name == NULL) {
|
if (name == NULL) {
|
||||||
conf_die("User with no name");
|
conf_die("User with no name");
|
||||||
@ -540,17 +643,25 @@ static int add_user(bip_t *bip, list_t *data)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u->backlog = hds->backlog;
|
||||||
|
u->always_backlog = hds->always_backlog;
|
||||||
|
u->bl_msg_only = hds->bl_msg_only;
|
||||||
|
u->backlog_lines = hds->backlog_lines;
|
||||||
|
u->backlog_no_timestamp = hds->backlog_no_timestamp;
|
||||||
|
u->blreset_on_talk = hds->blreset_on_talk;
|
||||||
|
|
||||||
while ((t = list_remove_first(data))) {
|
while ((t = list_remove_first(data))) {
|
||||||
switch (t->type) {
|
switch (t->type) {
|
||||||
case LEX_NAME:
|
case LEX_NAME:
|
||||||
MOVE_STRING(u->name, t->pdata);
|
MOVE_STRING(u->name, t->pdata);
|
||||||
break;
|
break;
|
||||||
case LEX_ADMIN:
|
case LEX_ADMIN:
|
||||||
u->admin = t->ndata;
|
u->admin = t->ndata;
|
||||||
break;
|
break;
|
||||||
case LEX_PASSWORD:
|
case LEX_PASSWORD:
|
||||||
hash_binary(t->pdata, &u->password, &u->seed);
|
hash_binary(t->pdata, &u->password, &u->seed);
|
||||||
free(t->pdata);
|
free(t->pdata);
|
||||||
|
t->pdata = NULL;
|
||||||
break;
|
break;
|
||||||
case LEX_DEFAULT_NICK:
|
case LEX_DEFAULT_NICK:
|
||||||
MOVE_STRING(u->default_nick, t->pdata);
|
MOVE_STRING(u->default_nick, t->pdata);
|
||||||
@ -585,6 +696,7 @@ static int add_user(bip_t *bip, list_t *data)
|
|||||||
case LEX_CONNECTION:
|
case LEX_CONNECTION:
|
||||||
r = add_connection(bip, u, t->pdata);
|
r = add_connection(bip, u, t->pdata);
|
||||||
free(t->pdata);
|
free(t->pdata);
|
||||||
|
t->pdata = NULL;
|
||||||
if (!r)
|
if (!r)
|
||||||
return 0;
|
return 0;
|
||||||
break;
|
break;
|
||||||
@ -595,16 +707,17 @@ static int add_user(bip_t *bip, list_t *data)
|
|||||||
if (!strncmp(t->pdata, "ca", 2))
|
if (!strncmp(t->pdata, "ca", 2))
|
||||||
u->ssl_check_mode = SSL_CHECK_CA;
|
u->ssl_check_mode = SSL_CHECK_CA;
|
||||||
free(t->pdata);
|
free(t->pdata);
|
||||||
|
t->pdata = NULL;
|
||||||
break;
|
break;
|
||||||
case LEX_SSL_CHECK_STORE:
|
case LEX_SSL_CHECK_STORE:
|
||||||
u->ssl_check_store = t->pdata;
|
MOVE_STRING(u->ssl_check_store, t->pdata);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
conf_die("Uknown keyword in user statement");
|
conf_die("Uknown keyword in user statement");
|
||||||
break;
|
return 0;
|
||||||
}
|
}
|
||||||
if (t->type == TUPLE_STR && t->pdata)
|
if (t->tuple_type == TUPLE_STR && t->pdata)
|
||||||
free(t->pdata);
|
free(t->pdata);
|
||||||
free(t);
|
free(t);
|
||||||
}
|
}
|
||||||
@ -613,6 +726,7 @@ static int add_user(bip_t *bip, list_t *data)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u->in_use = 1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -649,7 +763,6 @@ static int validate_config(bip_t *bip)
|
|||||||
link->name);
|
link->name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//conf_die("user: ... net: ... can i has nick/user/rael");
|
|
||||||
r = 0;
|
r = 0;
|
||||||
|
|
||||||
for (hash_it_init(&link->chan_infos, &cit);
|
for (hash_it_init(&link->chan_infos, &cit);
|
||||||
@ -672,21 +785,99 @@ static int validate_config(bip_t *bip)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strstr(conf_log_format, "\%u") == NULL)
|
||||||
|
mylog(LOG_WARN, "log_format doesn't contain \%u, all users'"
|
||||||
|
" logs will be mixed !");
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear_marks(bip_t *bip)
|
||||||
|
{
|
||||||
|
list_iterator_t lit;
|
||||||
|
hash_iterator_t hit;
|
||||||
|
|
||||||
|
for (list_it_init(&bip->link_list, &lit); list_it_item(&lit);
|
||||||
|
list_it_next(&lit))
|
||||||
|
((struct link *)list_it_item(&lit))->in_use = 0;
|
||||||
|
for (hash_it_init(&bip->users, &hit); hash_it_item(&hit);
|
||||||
|
hash_it_next(&hit))
|
||||||
|
((struct user *)hash_it_item(&hit))->in_use = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void user_kill(bip_t *bip, struct user *user)
|
||||||
|
{
|
||||||
|
(void)bip;
|
||||||
|
if (!hash_is_empty(&user->connections))
|
||||||
|
fatal("user_kill, user still has connections");
|
||||||
|
free(user->name);
|
||||||
|
free(user->password);
|
||||||
|
MAYFREE(user->default_nick);
|
||||||
|
MAYFREE(user->default_username);
|
||||||
|
MAYFREE(user->default_realname);
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSL
|
||||||
|
MAYFREE(user->ssl_check_store);
|
||||||
|
#endif
|
||||||
|
free(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sweep(bip_t *bip)
|
||||||
|
{
|
||||||
|
list_iterator_t lit;
|
||||||
|
hash_iterator_t hit;
|
||||||
|
|
||||||
|
for (list_it_init(&bip->link_list, &lit); list_it_item(&lit);
|
||||||
|
list_it_next(&lit)) {
|
||||||
|
struct link *l = ((struct link *)list_it_item(&lit));
|
||||||
|
if (!l->in_use) {
|
||||||
|
mylog(LOG_INFO, "Administratively killing %s/%s",
|
||||||
|
l->user->name, l->name);
|
||||||
|
link_kill(bip, l);
|
||||||
|
list_remove_if_exists(&bip->conn_list, l);
|
||||||
|
list_it_remove(&lit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (hash_it_init(&bip->users, &hit); hash_it_item(&hit);
|
||||||
|
hash_it_next(&hit)) {
|
||||||
|
struct user *u = (struct user *)hash_it_item(&hit);
|
||||||
|
if (!u->in_use) {
|
||||||
|
hash_it_remove(&hit);
|
||||||
|
user_kill(bip, u);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int fireup(bip_t *bip, FILE *conf)
|
int fireup(bip_t *bip, FILE *conf)
|
||||||
{
|
{
|
||||||
|
int r;
|
||||||
struct tuple *t;
|
struct tuple *t;
|
||||||
list_t *l;
|
int err = 0;
|
||||||
|
struct historical_directives hds;
|
||||||
|
|
||||||
conf_start();
|
clear_marks(bip);
|
||||||
|
parse_conf(conf, &err);
|
||||||
l = parse_conf(conf);
|
if (err) {
|
||||||
if (conf_error)
|
free_conf(root_list);
|
||||||
|
root_list = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
while ((t = list_remove_first(l))) {
|
#define SET_HV(d, n) do {\
|
||||||
|
int __gtv = get_tuple_nvalue(root_list, LEX_##n);\
|
||||||
|
if (__gtv != -1) \
|
||||||
|
d = __gtv;\
|
||||||
|
else\
|
||||||
|
d = DEFAULT_##n;\
|
||||||
|
} while(0);
|
||||||
|
SET_HV(hds.always_backlog, ALWAYS_BACKLOG);
|
||||||
|
SET_HV(hds.backlog, BACKLOG);
|
||||||
|
SET_HV(hds.bl_msg_only, BL_MSG_ONLY);
|
||||||
|
SET_HV(hds.backlog_lines, BACKLOG_LINES);
|
||||||
|
SET_HV(hds.backlog_no_timestamp, BACKLOG_NO_TIMESTAMP);
|
||||||
|
SET_HV(hds.blreset_on_talk, BLRESET_ON_TALK);
|
||||||
|
#undef SET_HV
|
||||||
|
|
||||||
|
while ((t = list_remove_first(root_list))) {
|
||||||
switch (t->type) {
|
switch (t->type) {
|
||||||
case LEX_LOG_SYNC_INTERVAL:
|
case LEX_LOG_SYNC_INTERVAL:
|
||||||
conf_log_sync_interval = t->ndata;
|
conf_log_sync_interval = t->ndata;
|
||||||
@ -718,44 +909,41 @@ int fireup(bip_t *bip, FILE *conf)
|
|||||||
case LEX_PID_FILE:
|
case LEX_PID_FILE:
|
||||||
MOVE_STRING(conf_pid_file, t->pdata);
|
MOVE_STRING(conf_pid_file, t->pdata);
|
||||||
break;
|
break;
|
||||||
|
case LEX_ALWAYS_BACKLOG:
|
||||||
|
hds.always_backlog = t->ndata;
|
||||||
|
break;
|
||||||
|
case LEX_BACKLOG:
|
||||||
|
hds.backlog = t->ndata;
|
||||||
|
break;
|
||||||
|
case LEX_BL_MSG_ONLY:
|
||||||
|
hds.bl_msg_only = t->ndata;
|
||||||
|
break;
|
||||||
|
case LEX_BACKLOG_LINES:
|
||||||
|
hds.backlog_lines = t->ndata;
|
||||||
|
break;
|
||||||
|
case LEX_BACKLOG_NO_TIMESTAMP:
|
||||||
|
hds.backlog_no_timestamp = t->ndata;
|
||||||
|
break;
|
||||||
|
case LEX_BLRESET_ON_TALK:
|
||||||
|
hds.blreset_on_talk = t->ndata;
|
||||||
|
break;
|
||||||
case LEX_NETWORK:
|
case LEX_NETWORK:
|
||||||
add_network(bip, t->pdata);
|
r = add_network(bip, t->pdata);
|
||||||
list_free(t->pdata);
|
list_free(t->pdata);
|
||||||
|
if (!r)
|
||||||
|
goto out_conf_error;
|
||||||
break;
|
break;
|
||||||
case LEX_USER:
|
case LEX_USER:
|
||||||
add_user(bip, t->pdata);
|
r = add_user(bip, t->pdata, &hds);
|
||||||
list_free(t->pdata);
|
list_free(t->pdata);
|
||||||
|
if (!r)
|
||||||
|
goto out_conf_error;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
#warning deprecated but we still need to support these
|
|
||||||
#if 0
|
|
||||||
case LEX_ALWAYS_BACKLOG:
|
|
||||||
conf_always_backlog = t->ndata;
|
|
||||||
break;
|
|
||||||
case LEX_BACKLOG:
|
|
||||||
conf_backlog = t->ndata;
|
|
||||||
break;
|
|
||||||
case LEX_BL_MSG_ONLY:
|
|
||||||
conf_bl_msg_only = t->ndata;
|
|
||||||
break;
|
|
||||||
case LEX_BACKLOG_LINES:
|
|
||||||
conf_backlog_lines = t->ndata;
|
|
||||||
break;
|
|
||||||
case LEX_BACKLOG_NO_TIMESTAMP:
|
|
||||||
conf_backlog_no_timestamp = t->ndata;
|
|
||||||
break;
|
|
||||||
case LEX_BLRESET_ON_TALK:
|
|
||||||
conf_blreset_on_talk = t->ndata;
|
|
||||||
break;
|
|
||||||
/* end of deprectated */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
conf_die("Config error in base config (%d)", t->type);
|
conf_die("Config error in base config (%d)", t->type);
|
||||||
|
goto out_conf_error;
|
||||||
}
|
}
|
||||||
if (t->type == TUPLE_STR && t->pdata)
|
if (t->tuple_type == TUPLE_STR && t->pdata)
|
||||||
free(t->pdata);
|
free(t->pdata);
|
||||||
free(t);
|
free(t);
|
||||||
}
|
}
|
||||||
@ -763,14 +951,20 @@ int fireup(bip_t *bip, FILE *conf)
|
|||||||
root_list = NULL;
|
root_list = NULL;
|
||||||
|
|
||||||
validate_config(bip);
|
validate_config(bip);
|
||||||
|
sweep(bip);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
out_conf_error:
|
||||||
|
free_conf(root_list);
|
||||||
|
root_list = NULL;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void log_file_setup(void)
|
static void log_file_setup(void)
|
||||||
{
|
{
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
|
|
||||||
if (conf_log_system) {
|
if (conf_log_system && conf_daemonize) {
|
||||||
if (conf_global_log_file && conf_global_log_file != stderr)
|
if (conf_global_log_file && conf_global_log_file != stderr)
|
||||||
fclose(conf_global_log_file);
|
fclose(conf_global_log_file);
|
||||||
snprintf(buf, 4095, "%s/bip.log", conf_log_root);
|
snprintf(buf, 4095, "%s/bip.log", conf_log_root);
|
||||||
@ -881,7 +1075,7 @@ int main(int argc, char **argv)
|
|||||||
signal(SIGXCPU, rlimit_cpu_reached);
|
signal(SIGXCPU, rlimit_cpu_reached);
|
||||||
|
|
||||||
conf_log_root = NULL;
|
conf_log_root = NULL;
|
||||||
conf_log_format = DEFAULT_LOG_FORMAT;
|
conf_log_format = strdup(DEFAULT_LOG_FORMAT);
|
||||||
conf_log_level = DEFAULT_LOG_LEVEL;
|
conf_log_level = DEFAULT_LOG_LEVEL;
|
||||||
conf_daemonize = 1;
|
conf_daemonize = 1;
|
||||||
conf_global_log_file = stderr;
|
conf_global_log_file = stderr;
|
||||||
@ -932,13 +1126,10 @@ int main(int argc, char **argv)
|
|||||||
fatal("%s config file not found", confpath);
|
fatal("%s config file not found", confpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
r = fireup(&bip, conf);
|
r = fireup(&bip, conf);
|
||||||
fclose(conf);
|
fclose(conf);
|
||||||
if (!r) {
|
if (!r)
|
||||||
fatal("%s", conf_errstr);
|
fatal("Not starting: error in config file.");
|
||||||
exit(28);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!conf_biphome) {
|
if (!conf_biphome) {
|
||||||
char *home = getenv("HOME");
|
char *home = getenv("HOME");
|
||||||
@ -1000,9 +1191,6 @@ int main(int argc, char **argv)
|
|||||||
fatal("Could not create listening socket");
|
fatal("Could not create listening socket");
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (conf_error)
|
|
||||||
mylog(LOG_ERROR, "conf error: %s", conf_errstr);
|
|
||||||
|
|
||||||
irc_main(&bip);
|
irc_main(&bip);
|
||||||
|
|
||||||
sighup = 0;
|
sighup = 0;
|
||||||
@ -1641,11 +1829,13 @@ void adm_bip_help(struct link_client *ic, int admin)
|
|||||||
"configuration");
|
"configuration");
|
||||||
bip_notify(ic, "/BIP LIST networks|users|connections|all_links"
|
bip_notify(ic, "/BIP LIST networks|users|connections|all_links"
|
||||||
"|all_connections");
|
"|all_connections");
|
||||||
|
bip_notify(ic, "/BIP ADD_CONN <connection name> <network>");
|
||||||
|
bip_notify(ic, "/BIP DEL_CONN <connection name>");
|
||||||
} else {
|
} else {
|
||||||
bip_notify(ic, "/BIP LIST networks|connections");
|
bip_notify(ic, "/BIP LIST networks|connections");
|
||||||
}
|
}
|
||||||
bip_notify(ic, "/BIP JUMP # jump to next server (in same network)");
|
bip_notify(ic, "/BIP JUMP # jump to next server (in same network)");
|
||||||
bip_notify(ic, "/BIP BLRESET # reset backlog (this connection only)");
|
bip_notify(ic, "/BIP BLRESET # reset backlog (this connection only). Add -q flag and the operation is quiet.");
|
||||||
#ifdef HAVE_LIBSSL
|
#ifdef HAVE_LIBSSL
|
||||||
bip_notify(ic, "/BIP TRUST # trust this server certificate");
|
bip_notify(ic, "/BIP TRUST # trust this server certificate");
|
||||||
#endif
|
#endif
|
||||||
@ -1659,14 +1849,15 @@ void adm_bip_help(struct link_client *ic, int admin)
|
|||||||
bip_notify(ic, "/BIP AWAY_NICK # clear away nick");
|
bip_notify(ic, "/BIP AWAY_NICK # clear away nick");
|
||||||
}
|
}
|
||||||
|
|
||||||
int adm_bip(struct link_client *ic, struct line *line, unsigned int privmsg)
|
int adm_bip(bip_t *bip, struct link_client *ic, struct line *line,
|
||||||
|
unsigned int privmsg)
|
||||||
{
|
{
|
||||||
int admin = LINK(ic)->user->admin;
|
int admin = LINK(ic)->user->admin;
|
||||||
|
|
||||||
if (line->elemc < privmsg + 2)
|
if (line->elemc < privmsg + 2)
|
||||||
return OK_FORGET;
|
return OK_FORGET;
|
||||||
|
|
||||||
mylog(LOG_STD, "/BIP %s from %s", line->elemv[privmsg + 1],
|
mylog(LOG_INFO, "/BIP %s from %s", line->elemv[privmsg + 1],
|
||||||
LINK(ic)->user->name);
|
LINK(ic)->user->name);
|
||||||
if (strcasecmp(line->elemv[privmsg + 1], "RELOAD") == 0) {
|
if (strcasecmp(line->elemv[privmsg + 1], "RELOAD") == 0) {
|
||||||
if (!admin) {
|
if (!admin) {
|
||||||
@ -1736,7 +1927,12 @@ int adm_bip(struct link_client *ic, struct line *line, unsigned int privmsg)
|
|||||||
}
|
}
|
||||||
bip_notify(ic, "-- Jumping to next server");
|
bip_notify(ic, "-- Jumping to next server");
|
||||||
} else if (strcasecmp(line->elemv[privmsg + 1], "BLRESET") == 0) {
|
} else if (strcasecmp(line->elemv[privmsg + 1], "BLRESET") == 0) {
|
||||||
adm_blreset(ic);
|
if (line->elemc == privmsg + 3 &&
|
||||||
|
strcmp(line->elemv[privmsg + 2], "-q") == 0) {
|
||||||
|
log_reinit_all(LINK(ic)->log);
|
||||||
|
} else {
|
||||||
|
adm_blreset(ic);
|
||||||
|
}
|
||||||
} else if (strcasecmp(line->elemv[privmsg + 1], "HELP") == 0) {
|
} else if (strcasecmp(line->elemv[privmsg + 1], "HELP") == 0) {
|
||||||
adm_bip_help(ic, admin);
|
adm_bip_help(ic, admin);
|
||||||
} else if (strcasecmp(line->elemv[privmsg + 1], "FOLLOW_NICK") == 0) {
|
} else if (strcasecmp(line->elemv[privmsg + 1], "FOLLOW_NICK") == 0) {
|
||||||
@ -1771,6 +1967,22 @@ int adm_bip(struct link_client *ic, struct line *line, unsigned int privmsg)
|
|||||||
bip_notify(ic, "-- AWAY_NICK command needs zero or one"
|
bip_notify(ic, "-- AWAY_NICK command needs zero or one"
|
||||||
" argument");
|
" argument");
|
||||||
}
|
}
|
||||||
|
} else if (admin &&
|
||||||
|
strcasecmp(line->elemv[privmsg + 1], "ADD_CONN") == 0) {
|
||||||
|
if (line->elemc != privmsg + 4) {
|
||||||
|
adm_reply(ic, "/BIP ADD_CONN <connection name> "
|
||||||
|
"<network name>");
|
||||||
|
} else {
|
||||||
|
adm_bip_addconn(bip, ic, line->elemv[privmsg + 2],
|
||||||
|
line->elemv[privmsg + 3]);
|
||||||
|
}
|
||||||
|
} else if (admin &&
|
||||||
|
strcasecmp(line->elemv[privmsg + 1], "DEL_CONN") == 0) {
|
||||||
|
if (line->elemc != privmsg + 3) {
|
||||||
|
adm_reply(ic, "/BIP DEL_CONN <connection name>");
|
||||||
|
} else {
|
||||||
|
adm_bip_delconn(bip, ic, line->elemv[privmsg + 2]);
|
||||||
|
}
|
||||||
#ifdef HAVE_LIBSSL
|
#ifdef HAVE_LIBSSL
|
||||||
} else if (strcasecmp(line->elemv[privmsg + 1], "TRUST") == 0) {
|
} else if (strcasecmp(line->elemv[privmsg + 1], "TRUST") == 0) {
|
||||||
return adm_trust(ic, line);
|
return adm_trust(ic, line);
|
||||||
@ -1785,12 +1997,14 @@ void free_conf(list_t *l)
|
|||||||
{
|
{
|
||||||
struct tuple *t;
|
struct tuple *t;
|
||||||
list_iterator_t li;
|
list_iterator_t li;
|
||||||
|
|
||||||
for (list_it_init(l, &li); (t = list_it_item(&li)); list_it_next(&li)) {
|
for (list_it_init(l, &li); (t = list_it_item(&li)); list_it_next(&li)) {
|
||||||
switch (t->tuple_type) {
|
switch (t->tuple_type) {
|
||||||
case TUPLE_STR:
|
case TUPLE_STR:
|
||||||
free(t->pdata); /* no break, for the style */
|
printf("freeconf: %s\n", (char *)t->pdata);
|
||||||
|
free(t->pdata);
|
||||||
|
break;
|
||||||
case TUPLE_INT:
|
case TUPLE_INT:
|
||||||
free(t);
|
|
||||||
break;
|
break;
|
||||||
case TUPLE_LIST:
|
case TUPLE_LIST:
|
||||||
free_conf(t->pdata);
|
free_conf(t->pdata);
|
||||||
@ -1799,5 +2013,8 @@ void free_conf(list_t *l)
|
|||||||
fatal("internal error free_conf");
|
fatal("internal error free_conf");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
free(t);
|
||||||
}
|
}
|
||||||
|
free(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,8 @@
|
|||||||
#ifdef HAVE_LIBSSL
|
#ifdef HAVE_LIBSSL
|
||||||
int adm_trust(struct link_client *ic, struct line *line);
|
int adm_trust(struct link_client *ic, struct line *line);
|
||||||
#endif
|
#endif
|
||||||
int adm_bip(struct link_client *ic, struct line *line, unsigned int privmsg);
|
int adm_bip(bip_t *bip, struct link_client *ic, struct line *line,
|
||||||
|
unsigned int privmsg);
|
||||||
int ssl_check_trust(struct link_client *ic);
|
int ssl_check_trust(struct link_client *ic);
|
||||||
void adm_blreset(struct link_client *ic);
|
void adm_blreset(struct link_client *ic);
|
||||||
void bip_notify(struct link_client *ic, char *fmt, ...);
|
void bip_notify(struct link_client *ic, char *fmt, ...);
|
||||||
|
25
src/conf.y
25
src/conf.y
@ -19,9 +19,7 @@
|
|||||||
extern int yylex (void);
|
extern int yylex (void);
|
||||||
extern char *yytext;
|
extern char *yytext;
|
||||||
extern int linec;
|
extern int linec;
|
||||||
extern int conf_error;
|
int conf_error;
|
||||||
#define ERRBUFSZ 80
|
|
||||||
extern char conf_errstr[ERRBUFSZ];
|
|
||||||
|
|
||||||
int yywrap()
|
int yywrap()
|
||||||
{
|
{
|
||||||
@ -30,9 +28,7 @@ int yywrap()
|
|||||||
|
|
||||||
int yyerror()
|
int yyerror()
|
||||||
{
|
{
|
||||||
snprintf(conf_errstr, ERRBUFSZ, "Parse error near %s, line %d\n",
|
mylog(LOG_ERROR, "Parse error near %s, line %d\n", yytext, linec + 1);
|
||||||
yytext, linec + 1);
|
|
||||||
conf_errstr[ERRBUFSZ - 1] = 0;
|
|
||||||
conf_error = 1;
|
conf_error = 1;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -114,6 +110,23 @@ command:
|
|||||||
| LEX_LOG_SYNC_INTERVAL LEX_EQ LEX_INT { $$ = tuple_i_new(
|
| LEX_LOG_SYNC_INTERVAL LEX_EQ LEX_INT { $$ = tuple_i_new(
|
||||||
LEX_LOG_SYNC_INTERVAL, $3); }
|
LEX_LOG_SYNC_INTERVAL, $3); }
|
||||||
| LEX_PID_FILE LEX_EQ LEX_STRING { $$ = tuple_s_new(LEX_PID_FILE, $3); }
|
| LEX_PID_FILE LEX_EQ LEX_STRING { $$ = tuple_s_new(LEX_PID_FILE, $3); }
|
||||||
|
/* deprecated */
|
||||||
|
| LEX_BACKLOG_LINES LEX_EQ LEX_INT {
|
||||||
|
$$ = tuple_i_new(LEX_BACKLOG_LINES, $3);
|
||||||
|
}
|
||||||
|
| LEX_BACKLOG_NO_TIMESTAMP LEX_EQ LEX_BOOL {
|
||||||
|
$$ = tuple_i_new(LEX_BACKLOG_NO_TIMESTAMP, $3);
|
||||||
|
}
|
||||||
|
| LEX_BACKLOG LEX_EQ LEX_BOOL { $$ = tuple_i_new(LEX_BACKLOG, $3); }
|
||||||
|
| LEX_BLRESET_ON_TALK LEX_EQ LEX_BOOL {
|
||||||
|
$$ = tuple_i_new(LEX_BLRESET_ON_TALK, $3);
|
||||||
|
}
|
||||||
|
| LEX_BL_MSG_ONLY LEX_EQ LEX_BOOL {
|
||||||
|
$$ = tuple_i_new(LEX_BL_MSG_ONLY, $3);
|
||||||
|
}
|
||||||
|
| LEX_ALWAYS_BACKLOG LEX_EQ LEX_BOOL { $$ = tuple_i_new(
|
||||||
|
LEX_ALWAYS_BACKLOG, $3); }
|
||||||
|
/* /deprecated */
|
||||||
| LEX_NETWORK LEX_LBRA network LEX_RBRA { $$ = tuple_l_new(LEX_NETWORK,
|
| LEX_NETWORK LEX_LBRA network LEX_RBRA { $$ = tuple_l_new(LEX_NETWORK,
|
||||||
$3); }
|
$3); }
|
||||||
| LEX_USER LEX_LBRA user LEX_RBRA { $$ = tuple_l_new(LEX_USER, $3); }
|
| LEX_USER LEX_LBRA user LEX_RBRA { $$ = tuple_l_new(LEX_USER, $3); }
|
||||||
|
@ -52,7 +52,7 @@ void connection_close(connection_t *cn)
|
|||||||
{
|
{
|
||||||
mylog(LOG_DEBUG, "Connection close asked. FD:%d ",
|
mylog(LOG_DEBUG, "Connection close asked. FD:%d ",
|
||||||
(long)cn->handle);
|
(long)cn->handle);
|
||||||
if (cn->connected != CONN_DISCONN) {
|
if (cn->connected != CONN_DISCONN && cn->connected != CONN_ERROR) {
|
||||||
cn->connected = CONN_DISCONN;
|
cn->connected = CONN_DISCONN;
|
||||||
if (close(cn->handle) == -1)
|
if (close(cn->handle) == -1)
|
||||||
mylog(LOG_WARN, "Error on socket close: %s",
|
mylog(LOG_WARN, "Error on socket close: %s",
|
||||||
@ -873,7 +873,8 @@ static void create_socket(char *dsthostname, char *dstport, char *srchostname,
|
|||||||
|
|
||||||
err = getaddrinfo(dsthostname, dstport, &hint, &cdata->dst);
|
err = getaddrinfo(dsthostname, dstport, &hint, &cdata->dst);
|
||||||
if (err) {
|
if (err) {
|
||||||
mylog(LOG_ERROR, "getaddrinfo(dst): %s", gai_strerror(err));
|
mylog(LOG_ERROR, "getaddrinfo(%s): %s", dsthostname,
|
||||||
|
gai_strerror(err));
|
||||||
connecting_data_free(cdata);
|
connecting_data_free(cdata);
|
||||||
cdata = NULL;
|
cdata = NULL;
|
||||||
return;
|
return;
|
||||||
@ -1010,8 +1011,10 @@ connection_t *accept_new(connection_t *cn)
|
|||||||
|
|
||||||
mylog(LOG_DEBUG, "Trying to accept new client on %d", cn->handle);
|
mylog(LOG_DEBUG, "Trying to accept new client on %d", cn->handle);
|
||||||
err = accept(cn->handle, &sa, &sa_len);
|
err = accept(cn->handle, &sa, &sa_len);
|
||||||
if (err < 0)
|
if (err < 0) {
|
||||||
|
mylog(LOG_ERROR, "accept failed: %s", strerror(errno));
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
socket_set_nonblock(err);
|
socket_set_nonblock(err);
|
||||||
|
|
||||||
conn = connection_init(cn->anti_flood, cn->ssl, cn->timeout, 0);
|
conn = connection_init(cn->anti_flood, cn->ssl, cn->timeout, 0);
|
||||||
@ -1175,14 +1178,20 @@ static int bip_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
|
|||||||
(err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY ||
|
(err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY ||
|
||||||
err == X509_V_ERR_CERT_UNTRUSTED ||
|
err == X509_V_ERR_CERT_UNTRUSTED ||
|
||||||
err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
|
err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE ||
|
||||||
err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT)) {
|
err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
|
||||||
|
err == X509_V_ERR_CERT_HAS_EXPIRED)) {
|
||||||
|
|
||||||
if (X509_STORE_get_by_subject(ctx, X509_LU_X509,
|
if (X509_STORE_get_by_subject(ctx, X509_LU_X509,
|
||||||
X509_get_subject_name(err_cert), &xobj) > 0 &&
|
X509_get_subject_name(err_cert), &xobj) > 0 &&
|
||||||
!X509_cmp(xobj.data.x509, err_cert)) {
|
!X509_cmp(xobj.data.x509, err_cert)) {
|
||||||
|
|
||||||
mylog(LOG_INFO, "Basic mode; peer certificate found "
|
if (err == X509_V_ERR_CERT_HAS_EXPIRED)
|
||||||
"in store, accepting it!");
|
mylog(LOG_INFO, "Basic mode; Accepting "
|
||||||
|
"*expired* peer certificate "
|
||||||
|
"found in store.");
|
||||||
|
else
|
||||||
|
mylog(LOG_INFO, "Basic mode; Accepting peer "
|
||||||
|
"certificate found in store.");
|
||||||
|
|
||||||
result = 1;
|
result = 1;
|
||||||
err = X509_V_OK;
|
err = X509_V_OK;
|
||||||
|
130
src/irc.c
130
src/irc.c
@ -49,14 +49,14 @@ void oidentd_dump(list_t *connl);
|
|||||||
|
|
||||||
void irc_client_free(struct link_client *cli);
|
void irc_client_free(struct link_client *cli);
|
||||||
extern int conf_log_sync_interval;
|
extern int conf_log_sync_interval;
|
||||||
extern int conf_error;
|
|
||||||
extern char conf_errstr[];
|
|
||||||
|
|
||||||
void write_user_list(connection_t *c, char *dest);
|
void write_user_list(connection_t *c, char *dest);
|
||||||
|
|
||||||
static void irc_copy_cli(struct link_client *src, struct link_client *dest,
|
static void irc_copy_cli(struct link_client *src, struct link_client *dest,
|
||||||
struct line *line);
|
struct line *line);
|
||||||
static void irc_cli_make_join(struct link_client *ic);
|
static void irc_cli_make_join(struct link_client *ic);
|
||||||
|
static void server_setup_reconnect_timer(struct link *link);
|
||||||
|
int irc_cli_bip(bip_t *bip, struct link_client *ic, struct line *line);
|
||||||
|
|
||||||
#define LAGOUT_TIME 480
|
#define LAGOUT_TIME 480
|
||||||
#define LAGCHECK_TIME (90)
|
#define LAGCHECK_TIME (90)
|
||||||
@ -377,11 +377,16 @@ int irc_dispatch_server(bip_t *bip, struct link_server *server,
|
|||||||
size_t nicklen = strlen(server->nick);
|
size_t nicklen = strlen(server->nick);
|
||||||
char *newnick = malloc(nicklen + 2);
|
char *newnick = malloc(nicklen + 2);
|
||||||
strcpy(newnick, server->nick);
|
strcpy(newnick, server->nick);
|
||||||
if (strlen(server->nick) < 9)
|
if (strlen(server->nick) < 9) {
|
||||||
strcat(newnick, "`");
|
strcat(newnick, "`");
|
||||||
else if (newnick[8] != '`') {
|
} else if (newnick[7] != '`') {
|
||||||
newnick[8] = '`';
|
if (newnick[8] != '`') {
|
||||||
newnick[9] = 0;
|
newnick[8] = '`';
|
||||||
|
newnick[9] = 0;
|
||||||
|
} else {
|
||||||
|
newnick[7] = '`';
|
||||||
|
newnick[9] = 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
newnick[8] = rand() * ('z' - 'a') / RAND_MAX +
|
newnick[8] = rand() * ('z' - 'a') / RAND_MAX +
|
||||||
'a';
|
'a';
|
||||||
@ -601,9 +606,9 @@ void unbind_from_link(struct link_client *ic)
|
|||||||
fatal("realloc");
|
fatal("realloc");
|
||||||
}
|
}
|
||||||
|
|
||||||
int irc_cli_bip(struct link_client *ic, struct line *line)
|
int irc_cli_bip(bip_t *bip, struct link_client *ic, struct line *line)
|
||||||
{
|
{
|
||||||
return adm_bip(ic, line, 0);
|
return adm_bip(bip, ic, line, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PASS_SEP ':'
|
#define PASS_SEP ':'
|
||||||
@ -853,13 +858,14 @@ static int irc_cli_quit(struct link_client *ic, struct line *line)
|
|||||||
return OK_CLOSE;
|
return OK_CLOSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int irc_cli_privmsg(struct link_client *ic, struct line *line)
|
static int irc_cli_privmsg(bip_t *bip, struct link_client *ic,
|
||||||
|
struct line *line)
|
||||||
{
|
{
|
||||||
if (line->elemc >= 3)
|
if (line->elemc >= 3)
|
||||||
log_cli_privmsg(LINK(ic)->log, LINK(ic)->l_server->nick,
|
log_cli_privmsg(LINK(ic)->log, LINK(ic)->l_server->nick,
|
||||||
line->elemv[1], line->elemv[2]);
|
line->elemv[1], line->elemv[2]);
|
||||||
if (strcmp(line->elemv[1], "-bip") == 0)
|
if (strcmp(line->elemv[1], "-bip") == 0)
|
||||||
return adm_bip(ic, line, 1);
|
return adm_bip(bip, ic, line, 1);
|
||||||
|
|
||||||
if (LINK(ic)->user->blreset_on_talk)
|
if (LINK(ic)->user->blreset_on_talk)
|
||||||
log_reinit_all(LINK(ic)->log);
|
log_reinit_all(LINK(ic)->log);
|
||||||
@ -1047,7 +1053,6 @@ static int irc_dispatch_trust_client(struct link_client *ic, struct line *line)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int irc_cli_bip(struct link_client *ic, struct line *line);
|
|
||||||
static int irc_dispatch_client(bip_t *bip, struct link_client *ic,
|
static int irc_dispatch_client(bip_t *bip, struct link_client *ic,
|
||||||
struct line *line)
|
struct line *line)
|
||||||
{
|
{
|
||||||
@ -1066,7 +1071,7 @@ static int irc_dispatch_client(bip_t *bip, struct link_client *ic,
|
|||||||
"before sending commands\r\n");
|
"before sending commands\r\n");
|
||||||
r = OK_FORGET;
|
r = OK_FORGET;
|
||||||
} else if (strcasecmp(line->elemv[0], "BIP") == 0) {
|
} else if (strcasecmp(line->elemv[0], "BIP") == 0) {
|
||||||
r = irc_cli_bip(ic, line);
|
r = irc_cli_bip(bip, ic, line);
|
||||||
} else if (strcmp(line->elemv[0], "JOIN") == 0) {
|
} else if (strcmp(line->elemv[0], "JOIN") == 0) {
|
||||||
r = irc_cli_join(ic, line);
|
r = irc_cli_join(ic, line);
|
||||||
} else if (strcmp(line->elemv[0], "PART") == 0) {
|
} else if (strcmp(line->elemv[0], "PART") == 0) {
|
||||||
@ -1076,7 +1081,7 @@ static int irc_dispatch_client(bip_t *bip, struct link_client *ic,
|
|||||||
} else if (strcmp(line->elemv[0], "QUIT") == 0) {
|
} else if (strcmp(line->elemv[0], "QUIT") == 0) {
|
||||||
r = irc_cli_quit(ic, line);
|
r = irc_cli_quit(ic, line);
|
||||||
} else if (strcmp(line->elemv[0], "PRIVMSG") == 0) {
|
} else if (strcmp(line->elemv[0], "PRIVMSG") == 0) {
|
||||||
r = irc_cli_privmsg(ic, line);
|
r = irc_cli_privmsg(bip, ic, line);
|
||||||
} else if (strcmp(line->elemv[0], "NOTICE") == 0) {
|
} else if (strcmp(line->elemv[0], "NOTICE") == 0) {
|
||||||
r = irc_cli_notice(ic, line);
|
r = irc_cli_notice(ic, line);
|
||||||
} else if (strcmp(line->elemv[0], "WHO") == 0) {
|
} else if (strcmp(line->elemv[0], "WHO") == 0) {
|
||||||
@ -1425,11 +1430,6 @@ static void channel_free(struct channel *c)
|
|||||||
if (c->create_ts)
|
if (c->create_ts)
|
||||||
free(c->create_ts);
|
free(c->create_ts);
|
||||||
|
|
||||||
/*
|
|
||||||
char *l;
|
|
||||||
while ((l = (char *)list_remove_first(&c->bans)))
|
|
||||||
free(l);
|
|
||||||
*/
|
|
||||||
hash_iterator_t hi;
|
hash_iterator_t hi;
|
||||||
for (hash_it_init(&c->nicks, &hi); hash_it_item(&hi); hash_it_next(&hi))
|
for (hash_it_init(&c->nicks, &hi); hash_it_item(&hi); hash_it_next(&hi))
|
||||||
nick_free(hash_it_item(&hi));
|
nick_free(hash_it_item(&hi));
|
||||||
@ -1475,7 +1475,7 @@ static int irc_part(struct link_server *server, struct line *line)
|
|||||||
free(s_nick);
|
free(s_nick);
|
||||||
|
|
||||||
log_part(LINK(server)->log, line->origin, s_chan,
|
log_part(LINK(server)->log, line->origin, s_chan,
|
||||||
line->elemc == 3 ? line->elemv[2]:NULL);
|
line->elemc == 3 ? line->elemv[2] : NULL);
|
||||||
|
|
||||||
nick_free(nick);
|
nick_free(nick);
|
||||||
return OK_COPY;
|
return OK_COPY;
|
||||||
@ -1894,7 +1894,6 @@ void server_cleanup(struct link_server *server)
|
|||||||
CONN(server) = NULL;
|
CONN(server) = NULL;
|
||||||
}
|
}
|
||||||
irc_lag_init(server);
|
irc_lag_init(server);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void irc_client_close(struct link_client *ic)
|
void irc_client_close(struct link_client *ic)
|
||||||
@ -1918,6 +1917,22 @@ void irc_client_close(struct link_client *ic)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void server_setup_reconnect_timer(struct link *link)
|
||||||
|
{
|
||||||
|
int timer = 0;
|
||||||
|
|
||||||
|
if (link->last_connection_attempt &&
|
||||||
|
time(NULL) - link->last_connection_attempt
|
||||||
|
< CONN_INTERVAL) {
|
||||||
|
timer = RECONN_TIMER * (link->s_conn_attempt);
|
||||||
|
if (timer > RECONN_TIMER_MAX)
|
||||||
|
timer = RECONN_TIMER_MAX;
|
||||||
|
}
|
||||||
|
mylog(LOG_ERROR, "%s dead, reconnecting in %d seconds", link->name,
|
||||||
|
timer);
|
||||||
|
link->recon_timer = timer;
|
||||||
|
}
|
||||||
|
|
||||||
static void irc_close(struct link_any *l)
|
static void irc_close(struct link_any *l)
|
||||||
{
|
{
|
||||||
if (CONN(l)) {
|
if (CONN(l)) {
|
||||||
@ -1926,28 +1941,16 @@ static void irc_close(struct link_any *l)
|
|||||||
}
|
}
|
||||||
if (TYPE(l) == IRC_TYPE_SERVER) {
|
if (TYPE(l) == IRC_TYPE_SERVER) {
|
||||||
/* TODO: free link_server as a whole */
|
/* TODO: free link_server as a whole */
|
||||||
int timer = 0;
|
|
||||||
struct link_server *is = (struct link_server *)l;
|
struct link_server *is = (struct link_server *)l;
|
||||||
|
|
||||||
if (LINK(is)->s_state == IRCS_CONNECTED)
|
if (LINK(is)->s_state == IRCS_CONNECTED)
|
||||||
irc_notify_disconnection(is);
|
irc_notify_disconnection(is);
|
||||||
else
|
|
||||||
LINK(is)->s_conn_attempt++;
|
|
||||||
irc_server_shutdown(is);
|
irc_server_shutdown(is);
|
||||||
log_disconnected(LINK(is)->log);
|
log_disconnected(LINK(is)->log);
|
||||||
|
|
||||||
server_next(LINK(is));
|
server_next(LINK(is));
|
||||||
server_cleanup(is);
|
server_cleanup(is);
|
||||||
if (LINK(is)->last_connection_attempt &&
|
server_setup_reconnect_timer(LINK(is));
|
||||||
time(NULL) - LINK(is)->last_connection_attempt
|
|
||||||
< CONN_INTERVAL) {
|
|
||||||
timer = RECONN_TIMER * (LINK(is)->s_conn_attempt);
|
|
||||||
if (timer > RECONN_TIMER_MAX)
|
|
||||||
timer = RECONN_TIMER_MAX;
|
|
||||||
}
|
|
||||||
mylog(LOG_ERROR, "%s dead, reconnecting in %d seconds",
|
|
||||||
LINK(l)->name, timer);
|
|
||||||
LINK(is)->recon_timer = timer;
|
|
||||||
|
|
||||||
LINK(is)->l_server = NULL;
|
LINK(is)->l_server = NULL;
|
||||||
irc_server_free((struct link_server *)is);
|
irc_server_free((struct link_server *)is);
|
||||||
@ -1987,10 +1990,21 @@ struct link_server *irc_server_new(struct link *link, connection_t *conn)
|
|||||||
|
|
||||||
void irc_server_free(struct link_server *s)
|
void irc_server_free(struct link_server *s)
|
||||||
{
|
{
|
||||||
|
if (CONN(s))
|
||||||
|
connection_free(CONN(s));
|
||||||
if (s->nick)
|
if (s->nick)
|
||||||
free(s->nick);
|
free(s->nick);
|
||||||
if (s->user_mode)
|
if (s->user_mode)
|
||||||
free(s->user_mode);
|
free(s->user_mode);
|
||||||
|
|
||||||
|
hash_iterator_t hi;
|
||||||
|
for (hash_it_init(&s->channels, &hi); hash_it_item(&hi);
|
||||||
|
hash_it_next(&hi)) {
|
||||||
|
struct channel *chan = hash_it_item(&hi);
|
||||||
|
channel_free(chan);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1999,6 +2013,8 @@ connection_t *irc_server_connect(struct link *link)
|
|||||||
struct link_server *ls;
|
struct link_server *ls;
|
||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
|
|
||||||
|
link->s_conn_attempt++;
|
||||||
|
|
||||||
mylog(LOG_INFO, "Connecting user '%s' to network '%s' using server "
|
mylog(LOG_INFO, "Connecting user '%s' to network '%s' using server "
|
||||||
"%s:%d", link->user->name, link->name,
|
"%s:%d", link->user->name, link->name,
|
||||||
link->network->serverv[link->cur_server].host,
|
link->network->serverv[link->cur_server].host,
|
||||||
@ -2015,6 +2031,11 @@ connection_t *irc_server_connect(struct link *link)
|
|||||||
CONNECT_TIMEOUT);
|
CONNECT_TIMEOUT);
|
||||||
if (!conn)
|
if (!conn)
|
||||||
fatal("connection_new");
|
fatal("connection_new");
|
||||||
|
if (conn->handle == -1) {
|
||||||
|
mylog(LOG_INFO, "Cannot connect.");
|
||||||
|
connection_free(conn);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
ls = irc_server_new(link, conn);
|
ls = irc_server_new(link, conn);
|
||||||
conn->user_data = ls;
|
conn->user_data = ls;
|
||||||
@ -2105,10 +2126,7 @@ void oidentd_dump(list_t *connl)
|
|||||||
content = (char *)malloc(stats.st_size + 1);
|
content = (char *)malloc(stats.st_size + 1);
|
||||||
|
|
||||||
if (content == NULL){
|
if (content == NULL){
|
||||||
mylog(LOG_WARN, "oidentd_dump : malloc failed, "
|
fatal("out of memory");
|
||||||
"returning");
|
|
||||||
fclose(f);
|
|
||||||
free(filename);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2154,6 +2172,7 @@ void oidentd_dump(list_t *connl)
|
|||||||
content[stats.st_size - 1] != '\n')
|
content[stats.st_size - 1] != '\n')
|
||||||
fprintf(f, "\n");
|
fprintf(f, "\n");
|
||||||
}
|
}
|
||||||
|
free(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (list_it_init(connl, &it); list_it_item(&it); list_it_next(&it)) {
|
for (list_it_init(connl, &it); list_it_item(&it); list_it_next(&it)) {
|
||||||
@ -2261,8 +2280,10 @@ void bip_tick(bip_t *bip)
|
|||||||
} else {
|
} else {
|
||||||
if (link->recon_timer == 0) {
|
if (link->recon_timer == 0) {
|
||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
conn = irc_server_connect(link);
|
|
||||||
link->last_connection_attempt = time(NULL);
|
link->last_connection_attempt = time(NULL);
|
||||||
|
conn = irc_server_connect(link);
|
||||||
|
if (!conn)
|
||||||
|
server_setup_reconnect_timer(link);
|
||||||
} else {
|
} else {
|
||||||
link->recon_timer--;
|
link->recon_timer--;
|
||||||
}
|
}
|
||||||
@ -2374,9 +2395,12 @@ void irc_main(bip_t *bip)
|
|||||||
{
|
{
|
||||||
int timeleft = 1000;
|
int timeleft = 1000;
|
||||||
|
|
||||||
/* XXX: This one MUST be first */
|
/*
|
||||||
/* TODO: maybe not anymore, check */
|
* If the list is empty, we are starting. Otherwise we are reloading,
|
||||||
list_add_first(&bip->conn_list, bip->listener);
|
* and conn_list is kept accross reloads.
|
||||||
|
*/
|
||||||
|
if (list_is_empty(&bip->conn_list))
|
||||||
|
list_add_first(&bip->conn_list, bip->listener);
|
||||||
|
|
||||||
while (!sighup) {
|
while (!sighup) {
|
||||||
connection_t *conn;
|
connection_t *conn;
|
||||||
@ -2401,10 +2425,6 @@ void irc_main(bip_t *bip)
|
|||||||
bip_on_event(bip, conn);
|
bip_on_event(bip, conn);
|
||||||
list_free(ready);
|
list_free(ready);
|
||||||
}
|
}
|
||||||
while (list_remove_first(&bip->conn_list))
|
|
||||||
;
|
|
||||||
while (list_remove_first(&bip->link_list))
|
|
||||||
;
|
|
||||||
while (list_remove_first(&bip->connecting_client_list))
|
while (list_remove_first(&bip->connecting_client_list))
|
||||||
;
|
;
|
||||||
return;
|
return;
|
||||||
@ -2421,12 +2441,6 @@ void irc_client_free(struct link_client *cli)
|
|||||||
free(cli);
|
free(cli);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
void irc_server_free(struct link_server *is)
|
|
||||||
{
|
|
||||||
free(is);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
struct link *irc_link_new()
|
struct link *irc_link_new()
|
||||||
{
|
{
|
||||||
struct link *link;
|
struct link *link;
|
||||||
@ -2443,11 +2457,18 @@ struct link *irc_link_new()
|
|||||||
|
|
||||||
void link_kill(bip_t *bip, struct link *link)
|
void link_kill(bip_t *bip, struct link *link)
|
||||||
{
|
{
|
||||||
|
list_remove(&bip->conn_list, CONN(link->l_server));
|
||||||
|
server_cleanup(link->l_server);
|
||||||
|
irc_server_free(link->l_server);
|
||||||
|
while (link->l_clientc) {
|
||||||
|
struct link_client *lc = link->l_clientv[0];
|
||||||
|
list_remove(&bip->conn_list, CONN(lc));
|
||||||
|
unbind_from_link(lc);
|
||||||
|
irc_client_free(lc);
|
||||||
|
}
|
||||||
|
|
||||||
hash_remove(&link->user->connections, link->name);
|
hash_remove(&link->user->connections, link->name);
|
||||||
free(link->name);
|
free(link->name);
|
||||||
irc_close((struct link_any *)link->l_server);
|
|
||||||
while (link->l_clientc)
|
|
||||||
irc_close((struct link_any *)link->l_clientv[0]);
|
|
||||||
log_free(link->log);
|
log_free(link->log);
|
||||||
MAYFREE(link->prev_nick);
|
MAYFREE(link->prev_nick);
|
||||||
MAYFREE(link->cli_nick);
|
MAYFREE(link->cli_nick);
|
||||||
@ -2473,5 +2494,6 @@ void link_kill(bip_t *bip, struct link *link)
|
|||||||
#ifdef HAVE_LIBSSL
|
#ifdef HAVE_LIBSSL
|
||||||
sk_X509_free(link->untrusted_certs);
|
sk_X509_free(link->untrusted_certs);
|
||||||
#endif
|
#endif
|
||||||
|
free(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ struct user {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
hash_t connections;
|
hash_t connections;
|
||||||
|
int in_use; /* for mark and sweep on reload */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct network
|
struct network
|
||||||
@ -158,6 +159,7 @@ struct link {
|
|||||||
int ssl_check_mode;
|
int ssl_check_mode;
|
||||||
STACK_OF(X509) *untrusted_certs;
|
STACK_OF(X509) *untrusted_certs;
|
||||||
#endif
|
#endif
|
||||||
|
int in_use; /* for mark and sweep on reload */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct link_connection {
|
struct link_connection {
|
||||||
|
13
src/lex.l
13
src/lex.l
@ -16,10 +16,10 @@
|
|||||||
int linec = 0;
|
int linec = 0;
|
||||||
#define YY_NO_UNPUT
|
#define YY_NO_UNPUT
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
extern int conf_error;
|
|
||||||
extern list_t *root_list;
|
extern list_t *root_list;
|
||||||
void yyparse(void);
|
void yyparse(void);
|
||||||
void free_conf(list_t*);
|
void free_conf(list_t*);
|
||||||
|
extern int conf_error;
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* SPANK ME WITH A SHOVEL */
|
/* SPANK ME WITH A SHOVEL */
|
||||||
@ -30,15 +30,14 @@ void dummy_lex_FFS(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
list_t *parse_conf(FILE *file)
|
list_t *parse_conf(FILE *file, int *err)
|
||||||
{
|
{
|
||||||
YY_BUFFER_STATE in = yy_create_buffer(file, YY_BUF_SIZE);
|
YY_BUFFER_STATE in = yy_create_buffer(file, YY_BUF_SIZE);
|
||||||
yy_switch_to_buffer(in);
|
yy_switch_to_buffer(in);
|
||||||
|
conf_error = 0;
|
||||||
yyparse();
|
yyparse();
|
||||||
if (conf_error) {
|
yy_delete_buffer(in);
|
||||||
free_conf(root_list);
|
*err = conf_error;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return root_list;
|
return root_list;
|
||||||
}
|
}
|
||||||
%}
|
%}
|
||||||
@ -113,6 +112,6 @@ list_t *parse_conf(FILE *file)
|
|||||||
"{" { return LEX_LBRA; }
|
"{" { return LEX_LBRA; }
|
||||||
"}" { return LEX_RBRA; }
|
"}" { return LEX_RBRA; }
|
||||||
";" { return LEX_SEMICOLON; }
|
";" { return LEX_SEMICOLON; }
|
||||||
. { printf("Parse error line %d, unknown character '%s'\n", linec + 1, yytext);
|
. { mylog(LOG_ERROR, "Parse error in config file line %d, unknown character '%s'\n", linec + 1, yytext);
|
||||||
return LEX_BUNCH; }
|
return LEX_BUNCH; }
|
||||||
%%
|
%%
|
||||||
|
61
src/log.c
61
src/log.c
@ -288,6 +288,7 @@ logfilegroup_t *log_find_file(log_t *logdata, char *destination)
|
|||||||
char *filename = NULL;
|
char *filename = NULL;
|
||||||
time_t t;
|
time_t t;
|
||||||
struct tm *ltime;
|
struct tm *ltime;
|
||||||
|
struct link *l;
|
||||||
|
|
||||||
if (!ischannel(*destination))
|
if (!ischannel(*destination))
|
||||||
destination = "privates";
|
destination = "privates";
|
||||||
@ -312,6 +313,24 @@ logfilegroup_t *log_find_file(log_t *logdata, char *destination)
|
|||||||
lfg = hash_get(&logdata->logfgs, destination);
|
lfg = hash_get(&logdata->logfgs, destination);
|
||||||
if (!lfg)
|
if (!lfg)
|
||||||
fatal("internal log_find_file");
|
fatal("internal log_find_file");
|
||||||
|
/* ok we are allocating a new lfg now, let's set it up for
|
||||||
|
* backlogging if applicable */
|
||||||
|
if (!logdata->user)
|
||||||
|
fatal("log_find_file: no user associated to logdata");
|
||||||
|
if (!logdata->network)
|
||||||
|
fatal("log_find_file: no network id associated to "
|
||||||
|
"logdata");
|
||||||
|
l = hash_get(&logdata->user->connections, logdata->network);
|
||||||
|
if (!l)
|
||||||
|
fatal("log_beautify: no connection associated to "
|
||||||
|
"logdata");
|
||||||
|
struct chan_info *ci = hash_get(&l->chan_infos, destination);
|
||||||
|
if (ci && !ci->backlog) {
|
||||||
|
lfg->track_backlog = 0;
|
||||||
|
} else {
|
||||||
|
lfg->track_backlog = 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (filename)
|
if (filename)
|
||||||
free(filename);
|
free(filename);
|
||||||
return lfg;
|
return lfg;
|
||||||
@ -362,6 +381,8 @@ logfilegroup_t *log_find_file(log_t *logdata, char *destination)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Da log routines
|
* Da log routines
|
||||||
|
* There are a lot of snprintf's here without enforcing the last \0 in the
|
||||||
|
* buffer, but _log_write takes care of this for us.
|
||||||
*/
|
*/
|
||||||
void log_join(log_t *logdata, char *ircmask, char *channel)
|
void log_join(log_t *logdata, char *ircmask, char *channel)
|
||||||
{
|
{
|
||||||
@ -374,9 +395,14 @@ void log_join(log_t *logdata, char *ircmask, char *channel)
|
|||||||
void log_part(log_t *logdata, char *ircmask, char *channel,
|
void log_part(log_t *logdata, char *ircmask, char *channel,
|
||||||
char *message)
|
char *message)
|
||||||
{
|
{
|
||||||
snprintf(logdata->buffer, LOGLINE_MAXLEN,
|
if (message)
|
||||||
|
snprintf(logdata->buffer, LOGLINE_MAXLEN,
|
||||||
"%s -!- %s has left %s [%s]", timestamp(), ircmask,
|
"%s -!- %s has left %s [%s]", timestamp(), ircmask,
|
||||||
channel, message);
|
channel, message);
|
||||||
|
else
|
||||||
|
snprintf(logdata->buffer, LOGLINE_MAXLEN,
|
||||||
|
"%s -!- %s has left %s", timestamp(), ircmask,
|
||||||
|
channel);
|
||||||
log_write(logdata, channel, logdata->buffer);
|
log_write(logdata, channel, logdata->buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,7 +660,10 @@ void log_client_connected(log_t *logdata)
|
|||||||
void log_advance_backlogs(log_t* ld, logfilegroup_t *lfg)
|
void log_advance_backlogs(log_t* ld, logfilegroup_t *lfg)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
(void)ld;
|
|
||||||
|
if (!lfg->track_backlog)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!ld->user->backlog || ld->user->backlog_lines == 0)
|
if (!ld->user->backlog || ld->user->backlog_lines == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -683,6 +712,9 @@ int log_has_backlog(log_t *logdata, char *destination)
|
|||||||
if (lfg->memlog)
|
if (lfg->memlog)
|
||||||
return !list_is_empty(lfg->memlog);
|
return !list_is_empty(lfg->memlog);
|
||||||
|
|
||||||
|
if (!lfg->track_backlog)
|
||||||
|
return 0;
|
||||||
|
|
||||||
logfile_t *lf;
|
logfile_t *lf;
|
||||||
lf = list_get_first(&lfg->file_group);
|
lf = list_get_first(&lfg->file_group);
|
||||||
if (lf != list_get_last(&lfg->file_group))
|
if (lf != list_get_last(&lfg->file_group))
|
||||||
@ -735,20 +767,6 @@ char *log_beautify(log_t *logdata, char *buf, char *dest)
|
|||||||
lots = p - sots;
|
lots = p - sots;
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
if (!logdata->user)
|
|
||||||
fatal("log_beautify: no user associated to logdata");
|
|
||||||
if (!logdata->network)
|
|
||||||
fatal("log_beautify: no network id associated to logdata");
|
|
||||||
l = hash_get(&logdata->user->connections, logdata->network);
|
|
||||||
if (!l)
|
|
||||||
fatal("log_beautify: no connection associated to logdata");
|
|
||||||
ci = hash_get(&l->chan_infos, dest);
|
|
||||||
if (ci && !ci->backlog) {
|
|
||||||
mylog(LOG_DEBUG, "Skipping unwanted channel %s for backlog",
|
|
||||||
dest);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strncmp(p, "-!-", 3) == 0) {
|
if (strncmp(p, "-!-", 3) == 0) {
|
||||||
if (logdata->user->bl_msg_only)
|
if (logdata->user->bl_msg_only)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -900,6 +918,9 @@ char *log_backread(log_t *logdata, char *destination, int *skip)
|
|||||||
if (!lfg)
|
if (!lfg)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
if (!lfg->track_backlog)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (!logdata->backlogging) {
|
if (!logdata->backlogging) {
|
||||||
logdata->backlogging = 1;
|
logdata->backlogging = 1;
|
||||||
mylog(LOG_DEBUG, "backlogging!");
|
mylog(LOG_DEBUG, "backlogging!");
|
||||||
@ -1171,7 +1192,7 @@ log_t *log_new(struct user *user, char *network)
|
|||||||
fatal("out of memory");
|
fatal("out of memory");
|
||||||
logdata->connected = 0;
|
logdata->connected = 0;
|
||||||
if (!log_all_logs)
|
if (!log_all_logs)
|
||||||
log_all_logs = list_new(NULL);
|
log_all_logs = list_new(list_ptr_cmp);
|
||||||
list_add_last(log_all_logs, logdata);
|
list_add_last(log_all_logs, logdata);
|
||||||
return logdata;
|
return logdata;
|
||||||
}
|
}
|
||||||
@ -1182,12 +1203,16 @@ void log_free(log_t *log)
|
|||||||
logfilegroup_t *lfg;
|
logfilegroup_t *lfg;
|
||||||
logfile_t *lf;
|
logfile_t *lf;
|
||||||
|
|
||||||
|
list_remove(log_all_logs, log);
|
||||||
|
|
||||||
|
free(log->network);
|
||||||
|
free(log->buffer);
|
||||||
|
|
||||||
for (hash_it_init(&log->logfgs, &it); (lfg = hash_it_item(&it));
|
for (hash_it_init(&log->logfgs, &it); (lfg = hash_it_item(&it));
|
||||||
hash_it_next(&it)) {
|
hash_it_next(&it)) {
|
||||||
log_reset(lfg);
|
log_reset(lfg);
|
||||||
if ((lf = list_remove_first(&lfg->file_group)))
|
if ((lf = list_remove_first(&lfg->file_group)))
|
||||||
logfile_free(lf);
|
logfile_free(lf);
|
||||||
free(lf);
|
|
||||||
}
|
}
|
||||||
hash_clean(&log->logfgs);
|
hash_clean(&log->logfgs);
|
||||||
free(log);
|
free(log);
|
||||||
|
@ -46,6 +46,7 @@ typedef struct logfilegroup
|
|||||||
list_t *memlog;
|
list_t *memlog;
|
||||||
int memc;
|
int memc;
|
||||||
list_iterator_t backlog_it;
|
list_iterator_t backlog_it;
|
||||||
|
int track_backlog;
|
||||||
} logfilegroup_t;
|
} logfilegroup_t;
|
||||||
|
|
||||||
typedef struct log {
|
typedef struct log {
|
||||||
|
104
src/util.c
104
src/util.c
@ -42,7 +42,7 @@ int is_valid_nick(char *str)
|
|||||||
while (*tmp != '\0' && (isalnum(*tmp) || *tmp == '-' || *tmp == '[' ||
|
while (*tmp != '\0' && (isalnum(*tmp) || *tmp == '-' || *tmp == '[' ||
|
||||||
*tmp == ']' || *tmp == '\\' || *tmp == '`' ||
|
*tmp == ']' || *tmp == '\\' || *tmp == '`' ||
|
||||||
*tmp == '^' || *tmp == '{' || *tmp == '}' ||
|
*tmp == '^' || *tmp == '{' || *tmp == '}' ||
|
||||||
*tmp == '|'))
|
*tmp == '|' || *tmp == '_' ))
|
||||||
tmp++;
|
tmp++;
|
||||||
return (*tmp == '\0');
|
return (*tmp == '\0');
|
||||||
}
|
}
|
||||||
@ -118,6 +118,9 @@ void _mylog(int level, char *fmt, va_list ap)
|
|||||||
{
|
{
|
||||||
char *prefix;
|
char *prefix;
|
||||||
|
|
||||||
|
if (!conf_log_system)
|
||||||
|
return;
|
||||||
|
|
||||||
if (level > conf_log_level)
|
if (level > conf_log_level)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -126,7 +129,7 @@ void _mylog(int level, char *fmt, va_list ap)
|
|||||||
prefix = "FATAL: ";
|
prefix = "FATAL: ";
|
||||||
break;
|
break;
|
||||||
case LOG_DEBUGVERB:
|
case LOG_DEBUGVERB:
|
||||||
prefix = "DEBUG: ";
|
prefix = "DEBUGVERB: ";
|
||||||
break;
|
break;
|
||||||
case LOG_DEBUG:
|
case LOG_DEBUG:
|
||||||
prefix = "DEBUG: ";
|
prefix = "DEBUG: ";
|
||||||
@ -157,9 +160,6 @@ void mylog(int level, char *fmt, ...)
|
|||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
if (!conf_log_system)
|
|
||||||
return;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
_mylog(level, fmt, ap);
|
_mylog(level, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@ -308,28 +308,6 @@ void *list_remove_last(list_t *list)
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
static void *list_remove_item(list_t *l, struct list_item *li)
|
|
||||||
{
|
|
||||||
void *ret = li->ptr;
|
|
||||||
if (!li->prev) {
|
|
||||||
if (l->first != li)
|
|
||||||
fatal("list_remove_item");
|
|
||||||
l->first = li->next;
|
|
||||||
} else
|
|
||||||
li->prev->next = li->next;
|
|
||||||
|
|
||||||
if (!li->next) {
|
|
||||||
if (l->last != li)
|
|
||||||
fatal("list_remove_item");
|
|
||||||
l->last = li->prev;
|
|
||||||
} else
|
|
||||||
li->next->prev = li->prev;
|
|
||||||
free(li);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
void *list_remove_if_exists(list_t *list, void *ptr)
|
void *list_remove_if_exists(list_t *list, void *ptr)
|
||||||
{
|
{
|
||||||
list_iterator_t li;
|
list_iterator_t li;
|
||||||
@ -383,12 +361,19 @@ void list_it_init(list_t *list, list_iterator_t *ti)
|
|||||||
{
|
{
|
||||||
ti->list = list;
|
ti->list = list;
|
||||||
ti->cur = list->first;
|
ti->cur = list->first;
|
||||||
|
ti->next = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void list_it_next(list_iterator_t *ti)
|
void list_it_next(list_iterator_t *ti)
|
||||||
{
|
{
|
||||||
if (ti->cur)
|
if (ti->cur) {
|
||||||
|
if (ti->next)
|
||||||
|
fatal("list_it_next: inconsistent interator state");
|
||||||
ti->cur = ti->cur->next;
|
ti->cur = ti->cur->next;
|
||||||
|
} else if (ti->next) {
|
||||||
|
ti->cur = ti->next;
|
||||||
|
ti->next = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *list_it_item(list_iterator_t *ti)
|
void *list_it_item(list_iterator_t *ti)
|
||||||
@ -415,7 +400,8 @@ void *list_it_remove(list_iterator_t *li)
|
|||||||
|
|
||||||
void *ptr = li->cur->ptr;
|
void *ptr = li->cur->ptr;
|
||||||
struct list_item *item = li->cur;
|
struct list_item *item = li->cur;
|
||||||
li->cur = li->cur->next;
|
li->next = li->cur->next;
|
||||||
|
li->cur = NULL;
|
||||||
free(item);
|
free(item);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
@ -555,50 +541,73 @@ void *hash_remove(hash_t *hash, char *key)
|
|||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int hash_is_empty(hash_t *h)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
if (!list_is_empty(&h->lists[i]))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void hash_it_init(hash_t *h, hash_iterator_t *hi)
|
void hash_it_init(hash_t *h, hash_iterator_t *hi)
|
||||||
{
|
{
|
||||||
memset(hi, 0, sizeof(hash_iterator_t));
|
memset(hi, 0, sizeof(hash_iterator_t));
|
||||||
hi->hash = h;
|
hi->hash = h;
|
||||||
|
|
||||||
while (list_is_empty(&h->lists[hi->list]) && hi->list < 256)
|
while (hi->list < 256 && list_is_empty(&h->lists[hi->list]))
|
||||||
hi->list++;
|
hi->list++;
|
||||||
if (hi->list < 256)
|
if (hi->list < 256)
|
||||||
hi->cur = h->lists[hi->list].first;
|
list_it_init(&h->lists[hi->list], &hi->lit);
|
||||||
else
|
|
||||||
hi->cur = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void hash_it_next(hash_iterator_t *hi)
|
void hash_it_next(hash_iterator_t *hi)
|
||||||
{
|
{
|
||||||
hash_t *hash = hi->hash;
|
list_it_next(&hi->lit);
|
||||||
|
if (!list_it_item(&hi->lit)) {
|
||||||
hi->cur = hi->cur->next;
|
do {
|
||||||
while (!hi->cur) {
|
hi->list++;
|
||||||
hi->list++;
|
if (hi->list == 256)
|
||||||
if (hi->list == 256) {
|
return;
|
||||||
hi->cur = NULL;
|
} while (list_is_empty(&hi->hash->lists[hi->list]));
|
||||||
return;
|
list_it_init(&hi->hash->lists[hi->list], &hi->lit);
|
||||||
}
|
|
||||||
hi->cur = hash->lists[hi->list].first;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *hash_it_item(hash_iterator_t *h)
|
void *hash_it_item(hash_iterator_t *h)
|
||||||
{
|
{
|
||||||
if (!h->cur)
|
struct hash_item *hi;
|
||||||
|
|
||||||
|
hi = list_it_item(&h->lit);
|
||||||
|
if (!hi)
|
||||||
return NULL;
|
return NULL;
|
||||||
struct hash_item *hi = h->cur->ptr;
|
|
||||||
return hi->item;
|
return hi->item;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *hash_it_key(hash_iterator_t *h)
|
char *hash_it_key(hash_iterator_t *h)
|
||||||
{
|
{
|
||||||
if (!h->cur)
|
struct hash_item *hi;
|
||||||
|
hi = list_it_item(&h->lit);
|
||||||
|
if (!hi)
|
||||||
return NULL;
|
return NULL;
|
||||||
struct hash_item *hi = h->cur->ptr;
|
|
||||||
return hi->key;
|
return hi->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *hash_it_remove(hash_iterator_t *hi)
|
||||||
|
{
|
||||||
|
struct hash_item *hitem;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
hitem = list_it_remove(&hi->lit);
|
||||||
|
|
||||||
|
ptr = hitem->item;
|
||||||
|
free(hitem->key);
|
||||||
|
free(hitem);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
void hash_dump(hash_t *h)
|
void hash_dump(hash_t *h)
|
||||||
{
|
{
|
||||||
hash_iterator_t it;
|
hash_iterator_t it;
|
||||||
@ -625,4 +634,3 @@ int ischannel(char p)
|
|||||||
{
|
{
|
||||||
return (p == '#' || p == '&' || p == '+' || p == '!');
|
return (p == '#' || p == '&' || p == '+' || p == '!');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
src/util.h
10
src/util.h
@ -15,6 +15,7 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
/* Warning: must be in order, 0 = less output */
|
/* Warning: must be in order, 0 = less output */
|
||||||
#define LOG_STD -1
|
#define LOG_STD -1
|
||||||
@ -30,9 +31,11 @@
|
|||||||
#define HASH_DEFAULT 0
|
#define HASH_DEFAULT 0
|
||||||
|
|
||||||
void mylog(int level, char *fmt, ...);
|
void mylog(int level, char *fmt, ...);
|
||||||
|
void _mylog(int level, char *fmt, va_list ap);
|
||||||
void fatal(char *fmt, ...);
|
void fatal(char *fmt, ...);
|
||||||
char *timestamp(void);
|
char *timestamp(void);
|
||||||
struct list_item;
|
struct list_item;
|
||||||
|
struct hash_item;
|
||||||
|
|
||||||
typedef struct list {
|
typedef struct list {
|
||||||
struct list_item *first;
|
struct list_item *first;
|
||||||
@ -43,16 +46,17 @@ typedef struct list {
|
|||||||
typedef struct list_iterator {
|
typedef struct list_iterator {
|
||||||
list_t *list;
|
list_t *list;
|
||||||
struct list_item *cur;
|
struct list_item *cur;
|
||||||
|
struct list_item *next;
|
||||||
} list_iterator_t;
|
} list_iterator_t;
|
||||||
|
|
||||||
/* our hash is also a list */
|
|
||||||
typedef struct hash {
|
typedef struct hash {
|
||||||
list_t lists[256];
|
list_t lists[256];
|
||||||
} hash_t;
|
} hash_t;
|
||||||
|
|
||||||
typedef struct hash_iterator {
|
typedef struct hash_iterator {
|
||||||
int list;
|
int list;
|
||||||
struct list_item *cur;
|
list_iterator_t lit;
|
||||||
|
struct hash_item *cur;
|
||||||
hash_t *hash;
|
hash_t *hash;
|
||||||
} hash_iterator_t;
|
} hash_iterator_t;
|
||||||
|
|
||||||
@ -102,10 +106,12 @@ void hash_insert(hash_t *hash, char *key, void *ptr);
|
|||||||
void *hash_get(hash_t *, char *key);
|
void *hash_get(hash_t *, char *key);
|
||||||
void *hash_remove(hash_t *hash, char *key);
|
void *hash_remove(hash_t *hash, char *key);
|
||||||
void *hash_remove_if_exists(hash_t *hash, char *key);
|
void *hash_remove_if_exists(hash_t *hash, char *key);
|
||||||
|
int hash_is_empty(hash_t *h);
|
||||||
void hash_it_init(hash_t *hash, hash_iterator_t *i);
|
void hash_it_init(hash_t *hash, hash_iterator_t *i);
|
||||||
void hash_it_next(hash_iterator_t *hi);
|
void hash_it_next(hash_iterator_t *hi);
|
||||||
void *hash_it_item(hash_iterator_t *h);
|
void *hash_it_item(hash_iterator_t *h);
|
||||||
char *hash_it_key(hash_iterator_t *h);
|
char *hash_it_key(hash_iterator_t *h);
|
||||||
|
void *hash_it_remove(hash_iterator_t *li);
|
||||||
|
|
||||||
int is_valid_nick(char *str);
|
int is_valid_nick(char *str);
|
||||||
int is_valid_username(char *str);
|
int is_valid_username(char *str);
|
||||||
|
Loading…
Reference in New Issue
Block a user