1
0
forked from bip/bip

Compare commits

...

8 Commits

Author SHA1 Message Date
Loïc Gomez
5f054bdded
Fix bipmkpw compilation issues per external variables
- Add missing extern stanza to global variables

Signed-off-by: Loïc Gomez <bip@animanova.fr>
2024-03-20 22:10:37 +09:00
Loïc Gomez
76c9ee11de
Handle CAP requests from clients, reply with no capabilities
Some clients require the server to handle CAP requests (IRCv3).
This adds basic support for CAP requests during the authentication
phase, sending no capabilities on CAP LS or CAP LIST, and CAP NAK
with all requested capabilities listed on CAP REQ.

This will be a base for adding capabilities later.

Signed-off-by: Loïc Gomez <bip@animanova.fr>
2024-03-20 22:07:43 +09:00
Loïc Gomez
b810ba0f77
Add method to stringify a line struct, skipping first N elements
- adds an internal method _irc_line_to_string with current irc_line_to_string
  code, adding capability to skip the first N elements
- call this internal method from irc_line_to_string with N=0
- call this internal method from new irc_line_to_string_skip method

Signed-off-by: Loïc Gomez <bip@animanova.fr>
2024-03-20 21:53:45 +09:00
Loïc Gomez
d19099eb3c
Log unhandled IRC errors as LOG_INFO in bip.log
This will allow for user feedback in main bip.log when an IRC error
occurs, like:
- 401 ERR_NOSUCHNICK
- 404 ERR_CANNOTSENDTOCHAN
- 432 ERR_ERRONEUSNICKNAME

These should not be logged as LOG_ERROR as they are not bip errors but
usually on the end user instead.

Signed-off-by: Loïc Gomez <bip@animanova.fr>
2024-02-18 23:45:12 +01:00
Loïc Gomez
99a1244e46
Allow a user to /BIP JUMP [-f] [other_conn] (within their list).
This can be useful when a connection is very slow to reconnect and the
user wants to force an immediate reconnection.

Also:
- fix message when JUMPing on some already reconnecting link
- add find_link() method
- add reconnect timer info if any (else display 0s)
- add -f flag to reset reconnect timer

Signed-off-by: Loïc Gomez <bip@animanova.fr>
2024-02-18 23:39:27 +09:00
Loïc Gomez
edd460a8fa
Set default recon_timer (and step) to 30s
Waiting 2 minutes on the first disconnect is depressing.
With this the maximum of 10min wait time is reached after 20 attempts
instead of the current 5 attempts.

Signed-off-by: Loïc Gomez <bip@animanova.fr>
2024-02-18 00:07:41 +01:00
Loïc Gomez
4cd5bdb381
Set default backlog_lines = 0 (fixes Debian bug #818374)
This would have defaults move to backlog_always=false / log=true /
backlog_lines=0, which should not cause much trouble as backlog will
be reset after being displayed.

Also, it is doubtfuk anyone would be keeping the default of 10 for
backlog as it is pretty much an undesirable configuration.

We need to annouce this change as important though, so users having
log = false are aware memory usage could increase if they don't set
it manually to another value.

Signed-off-by: Loïc Gomez <bip@animanova.fr>
2024-02-17 03:29:45 +01:00
c6a872ed61
Add bipgenconfig.1 to dist_man_MANS
Fix 1df884545f
2022-03-20 11:42:09 +01:00
10 changed files with 161 additions and 20 deletions

View File

@ -3,7 +3,7 @@ if COND_WANT_TESTS
endif endif
SUBDIRS = src . $(MAYBE_TESTS) SUBDIRS = src . $(MAYBE_TESTS)
dist_man_MANS = bip.1 bip.conf.5 bipmkpw.1 dist_man_MANS = bip.1 bip.conf.5 bipmkpw.1 bipgenconfig.1
examplesdir = $(prefix)/share/doc/bip/examples/ examplesdir = $(prefix)/share/doc/bip/examples/
dist_examples_DATA = samples/bip.conf samples/bip.vim dist_examples_DATA = samples/bip.conf samples/bip.vim

View File

@ -146,7 +146,7 @@ Defines the delay between each logfiles sync to the disk. Must be a non null
positive integer. positive integer.
.TP .TP
\fBreconn_timer\fP (default: \fB120\fP) \fBreconn_timer\fP (default: \fB30\fP)
Defines the initial delay (in seconds) before a reconnection attempt. Defines the initial delay (in seconds) before a reconnection attempt.
The delay increases with the number of attempts: The delay increases with the number of attempts:
delay = reconn_timer * number of attempts delay = reconn_timer * number of attempts
@ -227,7 +227,7 @@ This option should of course not be enabled if \fBbacklog_lines\fP is 0 !
If you still want to do so, don't forget to \fB/BIP BLRESET\fP sometimes. If you still want to do so, don't forget to \fB/BIP BLRESET\fP sometimes.
.TP .TP
\fBbacklog_lines\fP (default: \fB10\fP) \fBbacklog_lines\fP (default: \fB0\fP)
If set to 0, BIP will replay all the logs since last client disconnect. Else, If set to 0, BIP will replay all the logs since last client disconnect. Else,
it'll replay exactly \fBbacklog_lines\fP lines on each channel and privates. it'll replay exactly \fBbacklog_lines\fP lines on each channel and privates.
Be aware that BIP will replay \fBbacklog_lines\fP lines of all privates, even Be aware that BIP will replay \fBbacklog_lines\fP lines of all privates, even

View File

@ -86,7 +86,7 @@
# Sets the initial delay (in seconds) before a reconnection attempt. # Sets the initial delay (in seconds) before a reconnection attempt.
# The delay increases with the number of attempts: # The delay increases with the number of attempts:
# delay = reconn_timer * number of attempts # delay = reconn_timer * number of attempts
#reconn_timer = 120; #reconn_timer = 30;
# Network definition, a name and server info # Network definition, a name and server info
#network { #network {

View File

@ -119,7 +119,7 @@ my %optdesc = (
'optional' => 1, 'optional' => 1,
'depends' => 'log', 'depval' => 'true', 'depends' => 'log', 'depval' => 'true',
'desc' => 'Do you want to activate backlog {play back logs} system ?' }, 'desc' => 'Do you want to activate backlog {play back logs} system ?' },
'backlog_lines' => { 'type' => 'i', 'adv' => 0, 'default' => '10', 'backlog_lines' => { 'type' => 'i', 'adv' => 0, 'default' => '0',
'optional' => 1, 'optional' => 1,
'depends' => 'backlog', 'depval' => 'true', 'depends' => 'backlog', 'depval' => 'true',
'desc' => 'How much line do you want bip to play back upon client connect' . 'desc' => 'How much line do you want bip to play back upon client connect' .

View File

@ -67,6 +67,7 @@ void conf_die(bip_t *bip, char *fmt, ...);
static char *get_tuple_pvalue(list_t *tuple_l, int lex); static char *get_tuple_pvalue(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 bipuser *bu); void adm_list_connections(struct link_client *ic, struct bipuser *bu);
struct link *find_link(const char *link_name, struct bipuser *bu);
void free_conf(list_t *l); void free_conf(list_t *l);
@ -373,6 +374,45 @@ static int add_network(bip_t *bip, list_t *data)
return 1; return 1;
} }
void adm_bip_jump(struct link_client *ic, const char *conn_name,
int reset_timer)
{
struct link *lnk;
if (conn_name) {
lnk = find_link(conn_name, LINK(ic)->user);
if (!lnk) {
bip_notify(ic, "-- Cannot find connection named %s",
conn_name);
return;
}
goto do_the_jump;
} else {
lnk = LINK(ic);
}
do_the_jump:
if (!lnk->l_server) {
if (reset_timer) {
lnk->recon_timer = 0;
bip_notify(ic,
"-- %s is not connected, "
"timer has been reset, please wait",
conn_name);
return;
}
int timer = (lnk->recon_timer ? lnk->recon_timer : 0);
bip_notify(ic,
"-- %s is not connected, "
"please wait for reconnect (%ds)",
conn_name, timer);
return;
}
WRITE_LINE1(CONN(lnk->l_server), NULL, "QUIT", "jumpin' jumpin'");
connection_close(CONN(lnk->l_server));
bip_notify(ic, "-- Jumping to next server on %s", conn_name);
}
void adm_bip_delconn(bip_t *bip, struct link_client *ic, const char *conn_name) void adm_bip_delconn(bip_t *bip, struct link_client *ic, const char *conn_name)
{ {
struct bipuser *user = LINK(ic)->user; struct bipuser *user = LINK(ic)->user;
@ -664,6 +704,31 @@ static int add_connection(bip_t *bip, struct bipuser *user, list_t *data)
return 1; return 1;
} }
struct link *find_link(const char *link_name, struct bipuser *bu)
{
list_iterator_t it;
// Immediately return NULL when bip user (bu) is NULL
if (!bu) {
return NULL;
}
for (list_it_init(&_bip->link_list, &it); list_it_item(&it);
list_it_next(&it)) {
struct link *lnk = list_it_item(&it);
if (!lnk)
continue;
// Only lookup in optionally specified user links
if (bu != lnk->user)
continue;
if (strcmp(link_name, lnk->name) == 0)
return lnk;
}
return NULL;
}
static char *get_tuple_pvalue(list_t *tuple_l, int lex) static char *get_tuple_pvalue(list_t *tuple_l, int lex)
{ {
struct tuple *t; struct tuple *t;
@ -1992,8 +2057,8 @@ void adm_bip_help(struct link_client *ic, int admin, const char *subhelp)
bip_notify(ic, "/BIP LIST networks|connections"); bip_notify(ic, "/BIP LIST networks|connections");
} }
bip_notify(ic, bip_notify(ic,
"/BIP JUMP # jump to next server (in same " "/BIP JUMP [-f] [conn_name] # jump to next "
"network)"); "server (defaults to current network)");
bip_notify(ic, bip_notify(ic,
"/BIP BLRESET [channel|query]# reset backlog " "/BIP BLRESET [channel|query]# reset backlog "
"(this connection only). Add -q flag and the " "(this connection only). Add -q flag and the "
@ -2046,8 +2111,14 @@ void adm_bip_help(struct link_client *ic, int admin, const char *subhelp)
" Removing a connection will cause " " Removing a connection will cause "
"its disconnection."); "its disconnection.");
} else if (strcasecmp(subhelp, "JUMP") == 0) { } else if (strcasecmp(subhelp, "JUMP") == 0) {
bip_notify(ic, "/BIP JUMP :"); bip_notify(ic, "/BIP JUMP [-f] [conn_name]:");
bip_notify(ic, " Jump to next server in current network."); bip_notify(ic, " Jump to next server in current network.");
bip_notify(ic,
" If [conn_name] is set, jump to next server in "
"[conn_name] network instead.");
bip_notify(ic,
" If [-f] flag is used, also resets reconnect "
"timer.");
} else if (strcasecmp(subhelp, "BLRESET") == 0) { } else if (strcasecmp(subhelp, "BLRESET") == 0) {
bip_notify(ic, "/BIP BLRESET :"); bip_notify(ic, "/BIP BLRESET :");
bip_notify(ic, " Reset backlog on this network."); bip_notify(ic, " Reset backlog on this network.");
@ -2227,12 +2298,16 @@ int adm_bip(bip_t *bip, struct link_client *ic, struct line *line, int privmsg)
bip_notify(ic, "-- Invalid INFO request"); bip_notify(ic, "-- Invalid INFO request");
} }
} else if (irc_line_elem_case_equals(line, privmsg + 1, "JUMP")) { } else if (irc_line_elem_case_equals(line, privmsg + 1, "JUMP")) {
if (LINK(ic)->l_server) { if (irc_line_count(line) == privmsg + 2) {
WRITE_LINE1(CONN(LINK(ic)->l_server), NULL, "QUIT", adm_bip_jump(ic, NULL, 0);
"jumpin' jumpin'"); } else if (irc_line_count(line) == privmsg + 3) {
connection_close(CONN(LINK(ic)->l_server)); adm_bip_jump(ic, irc_line_elem(line, privmsg + 2), 0);
} else if (irc_line_count(line) == privmsg + 4
&& irc_line_elem_equals(line, privmsg + 2, "-f")) {
adm_bip_jump(ic, irc_line_elem(line, privmsg + 3), 1);
} else {
bip_notify(ic, "-- Invalid usage (/BIP HELP JUMP)");
} }
bip_notify(ic, "-- Jumping to next server");
} else if (irc_line_elem_case_equals(line, privmsg + 1, "BLRESET")) { } else if (irc_line_elem_case_equals(line, privmsg + 1, "BLRESET")) {
if (irc_line_includes(line, privmsg + 2)) { if (irc_line_includes(line, privmsg + 2)) {
if (irc_line_elem_equals(line, privmsg + 2, "-q")) { if (irc_line_elem_equals(line, privmsg + 2, "-q")) {

View File

@ -23,9 +23,9 @@
#include "util.h" #include "util.h"
#include "md5.h" #include "md5.h"
int conf_log_level; extern int conf_log_level;
FILE *conf_global_log_file; extern FILE *conf_global_log_file;
int conf_log_system; extern int conf_log_system;
void bipmkpw_fatal(char *msg, char *err) void bipmkpw_fatal(char *msg, char *err)
{ {

View File

@ -19,7 +19,7 @@
#define DEFAULT_BACKLOG 1 #define DEFAULT_BACKLOG 1
#define DEFAULT_ALWAYS_BACKLOG 0 #define DEFAULT_ALWAYS_BACKLOG 0
#define DEFAULT_BL_MSG_ONLY 0 #define DEFAULT_BL_MSG_ONLY 0
#define DEFAULT_BACKLOG_LINES 10 #define DEFAULT_BACKLOG_LINES 0
#define DEFAULT_BACKLOG_TIMESTAMP BLTSTime #define DEFAULT_BACKLOG_TIMESTAMP BLTSTime
#define DEFAULT_BLRESET_ON_TALK 0 #define DEFAULT_BLRESET_ON_TALK 0
#define DEFAULT_BLRESET_CONNECTION 0 #define DEFAULT_BLRESET_CONNECTION 0
@ -29,6 +29,6 @@
#define DEFAULT_LOG_LEVEL LOG_INFO #define DEFAULT_LOG_LEVEL LOG_INFO
#define DEFAULT_LOG_FORMAT "%u/%n/%Y-%m/%c.%d.log" #define DEFAULT_LOG_FORMAT "%u/%n/%Y-%m/%c.%d.log"
#define DEFAULT_BIP_USE_NOTICE 0 #define DEFAULT_BIP_USE_NOTICE 0
#define DEFAULT_RECONN_TIMER 120 #define DEFAULT_RECONN_TIMER 30
#endif /* DEFAULTS_H */ #endif /* DEFAULTS_H */

View File

@ -33,6 +33,7 @@
extern int sighup; extern int sighup;
extern bip_t *_bip; extern bip_t *_bip;
static int irc_generic_error(struct link_server *server, struct line *line);
static int irc_join(struct link_server *server, struct line *line); 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_part(struct link_server *server, struct line *line);
static int irc_mode(struct link_server *server, struct line *line); static int irc_mode(struct link_server *server, struct line *line);
@ -625,6 +626,10 @@ int irc_dispatch_server(bip_t *bip, struct link_server *server,
ret = irc_quit(server, line); ret = irc_quit(server, line);
} else if (irc_line_elem_equals(line, 0, "NICK")) { } else if (irc_line_elem_equals(line, 0, "NICK")) {
ret = irc_nick(server, line); ret = irc_nick(server, line);
} else if (irc_line_is_error(line)) {
// IRC errors catchall (for unhandled ones)
// logs error to bip.log
ret = irc_generic_error(server, line);
} }
if (ret == OK_COPY) { if (ret == OK_COPY) {
@ -1025,6 +1030,31 @@ static int irc_cli_pass(bip_t *bip, struct link_client *ic, struct line *line)
return OK_FORGET; return OK_FORGET;
} }
static int irc_cli_cap(bip_t *bip, struct link_client *ic, struct line *line)
{
if (irc_line_count(line) < 2)
return ERR_PROTOCOL;
/* When we decide to enable actual capabilities, we'll have to handle CAP
* version, add a flag cap_started or similar, and handle CAP END.
*/
if (irc_line_elem_equals(line, 1, "LS")) {
WRITE_LINE2(CONN(ic), NULL, "CAP", "*", "LS");
} else if (irc_line_elem_equals(line, 1, "LIST")) {
WRITE_LINE3(CONN(ic), NULL, "CAP", "*", "LIST", "");
} else if (irc_line_elem_equals(line, 1, "REQ")) {
char *caps = irc_line_to_string_skip(line, 2);
if (caps) {
caps++;
WRITE_LINE3(CONN(ic), NULL, "CAP", "*", "NAK", caps);
}
}
if ((ic->state & IRCC_READY) == IRCC_READY)
return irc_cli_startup(bip, ic, line);
return OK_FORGET;
}
static int irc_cli_quit(struct link_client *ic, struct line *line) static int irc_cli_quit(struct link_client *ic, struct line *line)
{ {
(void)ic; (void)ic;
@ -1403,6 +1433,8 @@ static int irc_dispatch_logging_client(bip_t *bip, struct link_client *ic,
return irc_cli_user(bip, ic, line); return irc_cli_user(bip, ic, line);
} else if (irc_line_elem_equals(line, 0, "PASS")) { } else if (irc_line_elem_equals(line, 0, "PASS")) {
return irc_cli_pass(bip, ic, line); return irc_cli_pass(bip, ic, line);
} else if (irc_line_elem_equals(line, 0, "CAP")) {
return irc_cli_cap(bip, ic, line);
} }
return OK_FORGET; return OK_FORGET;
} }
@ -1448,6 +1480,17 @@ static int origin_is_me(struct line *l, struct link_server *server)
return 0; return 0;
} }
static int irc_generic_error(struct link_server *server, struct line *line)
{
if (irc_line_count(line) == 4)
mylog(LOG_INFO, "[%s] IRC error: %s", LINK(server)->name,
irc_line_elem(line, 3));
else
mylog(LOG_INFO, "[%s] IRC error: %s", LINK(server)->name,
irc_line_to_string(line));
return OK_COPY;
}
static int irc_join(struct link_server *server, struct line *line) static int irc_join(struct link_server *server, struct line *line)
{ {
char *s_nick; char *s_nick;

View File

@ -16,6 +16,8 @@
#include "line.h" #include "line.h"
#include "util.h" #include "util.h"
char *_irc_line_to_string(struct line *l, int skip_first);
// TODO resolve assuming signed overflow does not occur when changing X +- C1 // TODO resolve assuming signed overflow does not occur when changing X +- C1
// cmp C2 to X cmp C2 -+ C1 // cmp C2 to X cmp C2 -+ C1
#pragma GCC diagnostic ignored "-Wstrict-overflow" #pragma GCC diagnostic ignored "-Wstrict-overflow"
@ -76,6 +78,19 @@ void irc_line_append(struct line *l, const char *s)
} }
char *irc_line_to_string(struct line *l) char *irc_line_to_string(struct line *l)
{
return _irc_line_to_string(l, 0);
}
char *irc_line_to_string_skip(struct line *l, int skip_first)
{
if (skip_first >= irc_line_count(l)) {
return NULL;
}
return _irc_line_to_string(l, skip_first);
}
char *_irc_line_to_string(struct line *l, int skip_first)
{ {
size_t len = 0; size_t len = 0;
int i; int i;
@ -83,7 +98,7 @@ char *irc_line_to_string(struct line *l)
if (l->origin) if (l->origin)
len = strlen(l->origin) + 2; len = strlen(l->origin) + 2;
for (i = 0; i < array_count(&l->words); i++) for (i = skip_first; i < array_count(&l->words); i++)
len += strlen(array_get(&l->words, i)) + 1; len += strlen(array_get(&l->words, i)) + 1;
len += 1; /* remove one trailing space and add \r\n */ len += 1; /* remove one trailing space and add \r\n */
len++; /* last args ":" */ len++; /* last args ":" */
@ -95,7 +110,7 @@ char *irc_line_to_string(struct line *l)
strcat(ret, l->origin); strcat(ret, l->origin);
strcat(ret, " "); strcat(ret, " ");
} }
for (i = 0; i < array_count(&l->words) - 1; i++) { for (i = skip_first; i < array_count(&l->words) - 1; i++) {
strcat(ret, array_get(&l->words, i)); strcat(ret, array_get(&l->words, i));
strcat(ret, " "); strcat(ret, " ");
} }
@ -143,6 +158,12 @@ void irc_line_drop(struct line *line, int elem)
bip_cfree(array_drop(&line->words, elem)); bip_cfree(array_drop(&line->words, elem));
} }
int irc_line_is_error(struct line *line)
{
const char *irc_code = irc_line_elem(line, 0);
return (irc_code[0] == '4');
}
int irc_line_elem_equals(struct line *line, int elem, const char *cmp) int irc_line_elem_equals(struct line *line, int elem, const char *cmp)
{ {
return !strcmp(irc_line_elem(line, elem), cmp); return !strcmp(irc_line_elem(line, elem), cmp);

View File

@ -90,6 +90,7 @@ void irc_line_write(struct line *l, connection_t *c);
void irc_line_append(struct line *l, const char *s); void irc_line_append(struct line *l, const char *s);
struct line *irc_line_new_from_string(char *str); struct line *irc_line_new_from_string(char *str);
char *irc_line_to_string(struct line *l); char *irc_line_to_string(struct line *l);
char *irc_line_to_string_skip(struct line *l, int skip_first);
char *irc_line_to_string_to(struct line *line, char *nick); char *irc_line_to_string_to(struct line *line, char *nick);
void irc_line_free(struct line *l); void irc_line_free(struct line *l);
struct line *irc_line_dup(struct line *line); struct line *irc_line_dup(struct line *line);
@ -98,6 +99,7 @@ int irc_line_includes(struct line *line, int elem);
const char *irc_line_elem(struct line *line, int elem); const char *irc_line_elem(struct line *line, int elem);
int irc_line_count(struct line *line); int irc_line_count(struct line *line);
char *irc_line_pop(struct line *l); char *irc_line_pop(struct line *l);
int irc_line_is_error(struct line *line);
int irc_line_elem_equals(struct line *line, int elem, const char *cmp); int irc_line_elem_equals(struct line *line, int elem, const char *cmp);
int irc_line_elem_case_equals(struct line *line, int elem, const char *cmp); int irc_line_elem_case_equals(struct line *line, int elem, const char *cmp);
void irc_line_drop(struct line *line, int elem); void irc_line_drop(struct line *line, int elem);