Compare commits
18 Commits
master
...
fix_list_c
Author | SHA1 | Date | |
---|---|---|---|
|
12f228be25 | ||
|
e382d31b67 | ||
|
7ab58b5b72 | ||
|
8776eaf076 | ||
|
3cc93758ba | ||
|
8f71bc8c50 | ||
|
b0725acd05 | ||
|
771f664f02 | ||
|
d8e65ef890 | ||
|
bb0fec792a | ||
|
27cd17ea3b | ||
|
91dea58db0 | ||
89976d2eb9 | |||
|
f31e484bc1 | ||
|
e74198f0ef | ||
|
3a8d4283a5 | ||
|
d95b7a073a | ||
|
cd30ff7ea6 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -58,6 +58,8 @@ src/lex.c
|
||||
|
||||
# Binaries
|
||||
src/*.o
|
||||
src/utils/*.o
|
||||
src/utils/*/*.o
|
||||
src/*.a
|
||||
src/bip
|
||||
src/bipmkpw
|
||||
|
4
AUTHORS
4
AUTHORS
@ -10,4 +10,6 @@ Thanks to our marketting and management team:
|
||||
ack|, ato, blackmore, lafouine, Gaston & gromit
|
||||
|
||||
Crypto shamelessly stolen from Christophe 'sexy' Devine.
|
||||
Credits to Jouni Malinen for base64 library (http://web.mit.edu/freebsd/head/contrib/wpa/src/utils/)
|
||||
|
||||
Credits to Jouni Malinen for base64 library:
|
||||
Source: http://w1.fi/cgit/hostap/commit/src/utils/base64.c
|
||||
|
2
COPYING
2
COPYING
@ -1,4 +1,4 @@
|
||||
bip copyright 2004 2005 Arnaud Cornet and Loïc Gomez, is released under the
|
||||
BIP copyright 2004-2022 Arnaud Cornet and Loïc Gomez, is released under the
|
||||
terms of the GNU GPL, License that you can find below.
|
||||
|
||||
Specific permission is granted for the GPLed code in this distribution to
|
||||
|
2
README
2
README
@ -220,5 +220,5 @@ IV. USING BIP
|
||||
|
||||
Happy ircing!
|
||||
|
||||
-- Arnaud Cornet <nohar@t1r.net> and Loïc Gomez <opensource@kyoshiro.org>
|
||||
-- Arnaud Cornet <nohar@t1r.net> and Loïc Gomez <bip@kyoshiro.org>
|
||||
|
||||
|
@ -146,7 +146,7 @@ Defines the delay between each logfiles sync to the disk. Must be a non null
|
||||
positive integer.
|
||||
|
||||
.TP
|
||||
\fBreconn_timer\fP (default: \fB120\fP)
|
||||
\fBreconn_timer\fP (default: \fB30\fP)
|
||||
Defines the initial delay (in seconds) before a reconnection attempt.
|
||||
The delay increases with the 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.
|
||||
|
||||
.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,
|
||||
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
|
||||
|
@ -86,7 +86,7 @@
|
||||
# Sets the initial delay (in seconds) before a reconnection attempt.
|
||||
# The delay increases with the number of attempts:
|
||||
# delay = reconn_timer * number of attempts
|
||||
#reconn_timer = 120;
|
||||
#reconn_timer = 30;
|
||||
|
||||
# Network definition, a name and server info
|
||||
#network {
|
||||
|
@ -19,7 +19,7 @@ libbip_a_SOURCES = \
|
||||
path_util.c path_util.h \
|
||||
tuple.h \
|
||||
util.c util.h \
|
||||
utils/base64.c utils/base64.h
|
||||
utils/b64/base64.c utils/b64/base64.h
|
||||
|
||||
libbip_a_CFLAGS = ${OPENSSL_CFLAGS} $(AM_CFLAGS)
|
||||
|
||||
|
104
src/bip.c
104
src/bip.c
@ -39,6 +39,7 @@ int sighup = 0;
|
||||
|
||||
char *conf_log_root;
|
||||
char *conf_log_format;
|
||||
char *conf_timestamp_format;
|
||||
int conf_log_level;
|
||||
char *conf_ip;
|
||||
unsigned short conf_port;
|
||||
@ -67,6 +68,7 @@ void conf_die(bip_t *bip, char *fmt, ...);
|
||||
static char *get_tuple_pvalue(list_t *tuple_l, int lex);
|
||||
void bip_notify(struct link_client *ic, char *fmt, ...);
|
||||
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);
|
||||
|
||||
|
||||
@ -160,7 +162,8 @@ void conf_die(bip_t *bip, char *fmt, ...)
|
||||
error = bip_realloc(error, size);
|
||||
}
|
||||
va_start(ap, fmt);
|
||||
_mylog(LOG_ERROR, fmt, ap);
|
||||
/* log timestamp format is a conf option, we cannot log with time */
|
||||
mylog_nots(LOG_ERROR, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
@ -373,6 +376,45 @@ static int add_network(bip_t *bip, list_t *data)
|
||||
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)
|
||||
{
|
||||
struct bipuser *user = LINK(ic)->user;
|
||||
@ -664,6 +706,26 @@ static int add_connection(bip_t *bip, struct bipuser *user, list_t *data)
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct link *find_link(const char *link_name, struct bipuser *bu)
|
||||
{
|
||||
list_iterator_t it;
|
||||
|
||||
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 && 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)
|
||||
{
|
||||
struct tuple *t;
|
||||
@ -857,6 +919,7 @@ static int validate_config(bip_t *bip)
|
||||
struct bipuser *user;
|
||||
struct link *link;
|
||||
struct chan_info *ci;
|
||||
size_t len;
|
||||
int r = 1;
|
||||
|
||||
for (hash_it_init(&bip->users, &it); (user = hash_it_item(&it));
|
||||
@ -921,6 +984,10 @@ static int validate_config(bip_t *bip)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
len = strlen(conf_timestamp_format);
|
||||
if (len > TIMESTAMP_FORMAT_MAXLEN)
|
||||
fatal("Timestamp format length exceeds maximum allowed length(%d)", TIMESTAMP_FORMAT_MAXLEN);
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -1035,6 +1102,9 @@ int fireup(bip_t *bip, FILE *conf)
|
||||
case LEX_LOG_LEVEL:
|
||||
conf_log_level = t->ndata;
|
||||
break;
|
||||
case LEX_TIMESTAMP_FORMAT:
|
||||
MOVE_STRING(conf_timestamp_format, t->pdata);
|
||||
break;
|
||||
case LEX_IP:
|
||||
MOVE_STRING(conf_ip, t->pdata);
|
||||
break;
|
||||
@ -1331,9 +1401,10 @@ void adm_print_connection(struct link_client *ic, struct link *lnk,
|
||||
bufpos = buf;
|
||||
|
||||
list_iterator_t itocs;
|
||||
int i = 0;
|
||||
for (list_it_init(&lnk->on_connect_send, &itocs);
|
||||
list_it_item(&itocs);) {
|
||||
bufpos = bip_strcatf_fit(&remaining, bufpos, "%s",
|
||||
list_it_item(&itocs) && i < 10; i++) {
|
||||
bufpos = bip_strcatf_fit(&remaining, bufpos, " on_connect_send: %s",
|
||||
(char *)list_it_item(&itocs));
|
||||
if (!bufpos) {
|
||||
// if oversized, print and reset
|
||||
@ -1341,6 +1412,7 @@ void adm_print_connection(struct link_client *ic, struct link *lnk,
|
||||
bip_notify(ic, "%s", buf);
|
||||
remaining = LINE_SIZE_LIM;
|
||||
bufpos = buf;
|
||||
list_it_next(&itocs);
|
||||
continue;
|
||||
} else {
|
||||
// if ok, go to next item
|
||||
@ -1992,8 +2064,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 JUMP # jump to next server (in same "
|
||||
"network)");
|
||||
"/BIP JUMP [-f] [conn_name] # jump to next "
|
||||
"server (defaults to current network)");
|
||||
bip_notify(ic,
|
||||
"/BIP BLRESET [channel|query]# reset backlog "
|
||||
"(this connection only). Add -q flag and the "
|
||||
@ -2046,8 +2118,14 @@ void adm_bip_help(struct link_client *ic, int admin, const char *subhelp)
|
||||
" Removing a connection will cause "
|
||||
"its disconnection.");
|
||||
} 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,
|
||||
" 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) {
|
||||
bip_notify(ic, "/BIP BLRESET :");
|
||||
bip_notify(ic, " Reset backlog on this network.");
|
||||
@ -2227,12 +2305,16 @@ int adm_bip(bip_t *bip, struct link_client *ic, struct line *line, int privmsg)
|
||||
bip_notify(ic, "-- Invalid INFO request");
|
||||
}
|
||||
} else if (irc_line_elem_case_equals(line, privmsg + 1, "JUMP")) {
|
||||
if (LINK(ic)->l_server) {
|
||||
WRITE_LINE1(CONN(LINK(ic)->l_server), NULL, "QUIT",
|
||||
"jumpin' jumpin'");
|
||||
connection_close(CONN(LINK(ic)->l_server));
|
||||
if (irc_line_count(line) == privmsg + 2) {
|
||||
adm_bip_jump(ic, NULL, 0);
|
||||
} else if (irc_line_count(line) == privmsg + 3) {
|
||||
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")) {
|
||||
if (irc_line_includes(line, privmsg + 2)) {
|
||||
if (irc_line_elem_equals(line, privmsg + 2, "-q")) {
|
||||
|
@ -39,6 +39,7 @@
|
||||
extern int sighup;
|
||||
extern char *conf_log_root;
|
||||
extern char *conf_log_format;
|
||||
extern char *conf_timestamp_format;
|
||||
extern int conf_log_level;
|
||||
extern char *conf_ip;
|
||||
extern unsigned short conf_port;
|
||||
@ -170,6 +171,7 @@ int main(int argc, char **argv)
|
||||
conf_log_root = NULL;
|
||||
conf_log_format = bip_strdup(DEFAULT_LOG_FORMAT);
|
||||
conf_log_level = DEFAULT_LOG_LEVEL;
|
||||
conf_timestamp_format = bip_strdup(DEFAULT_TIMESTAMP_FORMAT);
|
||||
conf_reconn_timer = DEFAULT_RECONN_TIMER;
|
||||
conf_daemonize = 1;
|
||||
conf_global_log_file = stderr;
|
||||
|
@ -69,7 +69,7 @@ struct tuple *tuple_l_new(int type, void *p)
|
||||
|
||||
%}
|
||||
|
||||
%token LEX_IP LEX_EQ LEX_PORT LEX_CSS LEX_SEMICOLON LEX_CONNECTION LEX_NETWORK LEX_LBRA LEX_RBRA LEX_USER LEX_NAME LEX_NICK LEX_SERVER LEX_PASSWORD LEX_SRCIP LEX_HOST LEX_VHOST LEX_SOURCE_PORT LEX_NONE LEX_COMMENT LEX_BUNCH LEX_REALNAME LEX_SSL LEX_SSL_CHECK_MODE LEX_SSL_CHECK_STORE LEX_SSL_CLIENT_CERTFILE LEX_CIPHERS LEX_CSS_CIPHERS LEX_DEFAULT_CIPHERS LEX_DH_PARAM LEX_CHANNEL LEX_KEY LEX_LOG_ROOT LEX_LOG_FORMAT LEX_LOG_LEVEL LEX_BACKLOG_LINES LEX_BACKLOG_TIMESTAMP LEX_BACKLOG_NO_TIMESTAMP LEX_BACKLOG LEX_LOG LEX_LOG_SYSTEM LEX_LOG_SYNC_INTERVAL LEX_FOLLOW_NICK LEX_ON_CONNECT_SEND LEX_AWAY_NICK LEX_PID_FILE LEX_WRITE_OIDENTD LEX_OIDENTD_FILE LEX_IGN_FIRST_NICK LEX_ALWAYS_BACKLOG LEX_BLRESET_ON_TALK LEX_BLRESET_CONNECTION LEX_DEFAULT_USER LEX_DEFAULT_NICK LEX_DEFAULT_REALNAME LEX_NO_CLIENT_AWAY_MSG LEX_BL_MSG_ONLY LEX_ADMIN LEX_BIP_USE_NOTICE LEX_CSS_PEM LEX_AUTOJOIN_ON_KICK LEX_IGNORE_CAPAB LEX_RECONN_TIMER LEX_SASL_USERNAME LEX_SASL_PASSWORD LEX_SASL_MECHANISM
|
||||
%token LEX_IP LEX_EQ LEX_PORT LEX_CSS LEX_SEMICOLON LEX_CONNECTION LEX_NETWORK LEX_LBRA LEX_RBRA LEX_USER LEX_NAME LEX_NICK LEX_SERVER LEX_PASSWORD LEX_SRCIP LEX_HOST LEX_VHOST LEX_SOURCE_PORT LEX_NONE LEX_COMMENT LEX_BUNCH LEX_REALNAME LEX_SSL LEX_SSL_CHECK_MODE LEX_SSL_CHECK_STORE LEX_SSL_CLIENT_CERTFILE LEX_CIPHERS LEX_CSS_CIPHERS LEX_DEFAULT_CIPHERS LEX_DH_PARAM LEX_CHANNEL LEX_KEY LEX_LOG_ROOT LEX_LOG_FORMAT LEX_LOG_LEVEL LEX_BACKLOG_LINES LEX_BACKLOG_TIMESTAMP LEX_BACKLOG_NO_TIMESTAMP LEX_BACKLOG LEX_LOG LEX_LOG_SYSTEM LEX_LOG_SYNC_INTERVAL LEX_FOLLOW_NICK LEX_ON_CONNECT_SEND LEX_AWAY_NICK LEX_PID_FILE LEX_WRITE_OIDENTD LEX_OIDENTD_FILE LEX_IGN_FIRST_NICK LEX_ALWAYS_BACKLOG LEX_BLRESET_ON_TALK LEX_BLRESET_CONNECTION LEX_DEFAULT_USER LEX_DEFAULT_NICK LEX_DEFAULT_REALNAME LEX_NO_CLIENT_AWAY_MSG LEX_BL_MSG_ONLY LEX_ADMIN LEX_BIP_USE_NOTICE LEX_CSS_PEM LEX_AUTOJOIN_ON_KICK LEX_IGNORE_CAPAB LEX_RECONN_TIMER LEX_SASL_USERNAME LEX_SASL_PASSWORD LEX_SASL_MECHANISM LEX_TIMESTAMP_FORMAT
|
||||
|
||||
%union {
|
||||
int number;
|
||||
@ -108,6 +108,7 @@ command:
|
||||
| LEX_LOG_SYNC_INTERVAL LEX_EQ LEX_INT { $$ = tuple_i_new(
|
||||
LEX_LOG_SYNC_INTERVAL, $3); }
|
||||
| LEX_PID_FILE LEX_EQ LEX_STRING { $$ = tuple_s_new(LEX_PID_FILE, $3); }
|
||||
| LEX_TIMESTAMP_FORMAT LEX_EQ LEX_STRING { $$ = tuple_s_new(LEX_TIMESTAMP_FORMAT, $3); }
|
||||
| LEX_WRITE_OIDENTD LEX_EQ LEX_BOOL { $$ = tuple_i_new(LEX_WRITE_OIDENTD, $3); }
|
||||
| LEX_OIDENTD_FILE LEX_EQ LEX_STRING { $$ = tuple_s_new(LEX_OIDENTD_FILE, $3); }
|
||||
/* deprecated */
|
||||
|
@ -62,7 +62,7 @@ void connection_close(connection_t *cn)
|
||||
{
|
||||
mylog(LOG_DEBUG, "Connection close asked. FD:%d (status: %d)",
|
||||
(long)cn->handle, cn->connected);
|
||||
if (cn->connected != CONN_DISCONN && cn->connected != CONN_ERROR) {
|
||||
if (cn->connected != CONN_DISCONN) {
|
||||
cn->connected = CONN_DISCONN;
|
||||
if (close(cn->handle) == -1)
|
||||
mylog(LOG_WARN, "Error on socket close: %s",
|
||||
@ -1171,6 +1171,7 @@ static connection_t *connection_init(int anti_flood, int ssl, time_t timeout,
|
||||
static int ctx_set_dh(SSL_CTX *ctx)
|
||||
{
|
||||
/* Return ephemeral DH parameters. */
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L /* 3.0.0 */
|
||||
DH *dh = NULL;
|
||||
FILE *f;
|
||||
long ret;
|
||||
@ -1203,7 +1204,31 @@ static int ctx_set_dh(SSL_CTX *ctx)
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
BIO *pbio = BIO_new_file(conf_client_dh_file, "r");
|
||||
if (!pbio) {
|
||||
mylog(LOG_ERROR, "Unable to open DH parameters, BIO_new_file(%s): %s",
|
||||
conf_client_dh_file, ERR_error_string(ERR_get_error(), NULL));
|
||||
return 0;
|
||||
}
|
||||
|
||||
EVP_PKEY *param = PEM_read_bio_Parameters(pbio, NULL);
|
||||
BIO_free(pbio);
|
||||
if (!param) {
|
||||
mylog(LOG_ERROR, "TLS DH Error: PEM_read_bio_Parameters(%s): %s",
|
||||
conf_client_dh_file, ERR_error_string(ERR_get_error(), NULL));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (SSL_CTX_set0_tmp_dh_pkey(ctx, param) != 1) {
|
||||
EVP_PKEY_free(param);
|
||||
mylog(LOG_ERROR, "TLS DH Error: SSL_CTX_set0_tmp_dh_pkey(%s): %s",
|
||||
conf_client_dh_file, ERR_error_string(ERR_get_error(), NULL));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
mylog(LOG_DEBUG, "TLS: succesfully set up DH params %s",
|
||||
conf_client_dh_file);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
@ -19,7 +19,7 @@
|
||||
#define DEFAULT_BACKLOG 1
|
||||
#define DEFAULT_ALWAYS_BACKLOG 0
|
||||
#define DEFAULT_BL_MSG_ONLY 0
|
||||
#define DEFAULT_BACKLOG_LINES 10
|
||||
#define DEFAULT_BACKLOG_LINES 0
|
||||
#define DEFAULT_BACKLOG_TIMESTAMP BLTSTime
|
||||
#define DEFAULT_BLRESET_ON_TALK 0
|
||||
#define DEFAULT_BLRESET_CONNECTION 0
|
||||
@ -28,7 +28,9 @@
|
||||
#define DEFAULT_LOG_SYNC_INTERVAL 5
|
||||
#define DEFAULT_LOG_LEVEL LOG_INFO
|
||||
#define DEFAULT_LOG_FORMAT "%u/%n/%Y-%m/%c.%d.log"
|
||||
/* keep dd-mm-yyyy as default since we used that before adding the option */
|
||||
#define DEFAULT_TIMESTAMP_FORMAT "%d-%m-%Y %H:%M:%S"
|
||||
#define DEFAULT_BIP_USE_NOTICE 0
|
||||
#define DEFAULT_RECONN_TIMER 120
|
||||
#define DEFAULT_RECONN_TIMER 30
|
||||
|
||||
#endif /* DEFAULTS_H */
|
||||
|
52
src/irc.c
52
src/irc.c
@ -22,7 +22,7 @@
|
||||
#include "log.h"
|
||||
#include "connection.h"
|
||||
#include "md5.h"
|
||||
#include "utils/base64.h"
|
||||
#include "utils/b64/base64.h"
|
||||
|
||||
// TODO resolve assuming signed overflow does not occur when changing X +- C1
|
||||
// cmp C2 to X cmp C2 -+ C1
|
||||
@ -33,6 +33,7 @@
|
||||
extern int sighup;
|
||||
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_part(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);
|
||||
} else if (irc_line_elem_equals(line, 0, "NICK")) {
|
||||
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) {
|
||||
@ -1025,6 +1030,31 @@ static int irc_cli_pass(bip_t *bip, struct link_client *ic, struct line *line)
|
||||
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)
|
||||
{
|
||||
(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);
|
||||
} else if (irc_line_elem_equals(line, 0, "PASS")) {
|
||||
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;
|
||||
}
|
||||
@ -1448,6 +1480,17 @@ static int origin_is_me(struct line *l, struct link_server *server)
|
||||
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)
|
||||
{
|
||||
char *s_nick;
|
||||
@ -2166,15 +2209,16 @@ static int irc_server_sasl_authenticate(struct link_server *ircs)
|
||||
size_t p_len = strlen(sasl_password);
|
||||
size_t raw_len = u_len * 2 + p_len + 2;
|
||||
size_t enc_len;
|
||||
unsigned char *raw_str = bip_malloc(raw_len + 1);
|
||||
unsigned char *enc_str;
|
||||
char *raw_str = bip_malloc(raw_len + 1);
|
||||
char *enc_str;
|
||||
|
||||
memcpy(raw_str, sasl_username, u_len);
|
||||
raw_str[u_len] = '\0';
|
||||
memcpy(raw_str + u_len + 1, sasl_username, u_len);
|
||||
raw_str[u_len * 2 + 1] = '\0';
|
||||
memcpy(raw_str + u_len * 2 + 2, sasl_password, p_len);
|
||||
enc_str = base64_encode(raw_str, raw_len, &enc_len);
|
||||
enc_str = base64_encode_no_lf(raw_str, raw_len, &enc_len);
|
||||
free(raw_str);
|
||||
mylog(LOG_DEBUG, "[%s] Base64 encoded SASL auth token (len %d): %s",
|
||||
LINK(ircs)->name, enc_len, enc_str);
|
||||
|
||||
|
@ -90,6 +90,7 @@ list_t *parse_conf(FILE *file, int *err)
|
||||
"log_level" { return LEX_LOG_LEVEL; }
|
||||
"log_root" { return LEX_LOG_ROOT; }
|
||||
"log_format" { return LEX_LOG_FORMAT; }
|
||||
"timestamp_format" { return LEX_TIMESTAMP_FORMAT; }
|
||||
"backlog_lines" { return LEX_BACKLOG_LINES; }
|
||||
"backlog_timestamp" { return LEX_BACKLOG_TIMESTAMP; }
|
||||
"backlog_no_timestamp" { return LEX_BACKLOG_NO_TIMESTAMP; }
|
||||
|
26
src/line.c
26
src/line.c
@ -16,6 +16,8 @@
|
||||
#include "line.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
|
||||
// cmp C2 to X cmp C2 -+ C1
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
int i;
|
||||
@ -83,7 +98,7 @@ char *irc_line_to_string(struct line *l)
|
||||
|
||||
if (l->origin)
|
||||
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 += 1; /* remove one trailing space and add \r\n */
|
||||
len++; /* last args ":" */
|
||||
@ -95,7 +110,7 @@ char *irc_line_to_string(struct line *l)
|
||||
strcat(ret, l->origin);
|
||||
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, " ");
|
||||
}
|
||||
@ -143,6 +158,13 @@ void irc_line_drop(struct line *line, int elem)
|
||||
bip_cfree(array_drop(&line->words, elem));
|
||||
}
|
||||
|
||||
unsigned int irc_line_is_error(struct line *line)
|
||||
{
|
||||
const char *irc_code = irc_line_elem(line, 0);
|
||||
const char *error_code = "4";
|
||||
return (irc_code[0] == error_code[0]);
|
||||
}
|
||||
|
||||
int irc_line_elem_equals(struct line *line, int elem, const char *cmp)
|
||||
{
|
||||
return !strcmp(irc_line_elem(line, elem), cmp);
|
||||
|
@ -90,6 +90,7 @@ void irc_line_write(struct line *l, connection_t *c);
|
||||
void irc_line_append(struct line *l, const char *s);
|
||||
struct line *irc_line_new_from_string(char *str);
|
||||
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);
|
||||
void irc_line_free(struct line *l);
|
||||
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);
|
||||
int irc_line_count(struct line *line);
|
||||
char *irc_line_pop(struct line *l);
|
||||
unsigned 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_case_equals(struct line *line, int elem, const char *cmp);
|
||||
void irc_line_drop(struct line *line, int elem);
|
||||
|
@ -27,6 +27,7 @@ extern int errno;
|
||||
extern int log_level;
|
||||
extern char *conf_log_root;
|
||||
extern char *conf_log_format;
|
||||
extern char *conf_timestamp_format;
|
||||
extern int conf_log;
|
||||
|
||||
extern FILE *conf_global_log_file;
|
||||
@ -1030,7 +1031,7 @@ static time_t compute_time(const char *buf)
|
||||
time(&tv);
|
||||
tm = *localtime(&tv);
|
||||
|
||||
if (strptime(buf, "%d-%m-%Y %H:%M:%S", &tm) == NULL)
|
||||
if (strptime(buf, conf_timestamp_format, &tm) == NULL)
|
||||
return (time_t)-1;
|
||||
return mktime(&tm);
|
||||
}
|
||||
|
67
src/util.c
67
src/util.c
@ -29,11 +29,13 @@
|
||||
|
||||
extern int conf_log_level;
|
||||
extern int conf_log_system;
|
||||
extern char *conf_timestamp_format;
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
|
||||
extern int errno;
|
||||
#pragma GCC diagnostic pop
|
||||
extern FILE *conf_global_log_file;
|
||||
void _mylog(int level, int with_timestamp, char *fmt, va_list ap);
|
||||
|
||||
void memory_fatal(void)
|
||||
{
|
||||
@ -222,27 +224,46 @@ int is_valid_username(char *str)
|
||||
|
||||
char *timestamp(void)
|
||||
{
|
||||
static char ts[20];
|
||||
time_t tv;
|
||||
struct tm *tm;
|
||||
|
||||
time(&tv);
|
||||
tm = localtime(&tv);
|
||||
|
||||
strftime(ts, (size_t)20, "%d-%m-%Y %H:%M:%S", tm);
|
||||
return ts;
|
||||
return bip_strftime(tm);
|
||||
}
|
||||
|
||||
char *hrtime(time_t s)
|
||||
{
|
||||
static char ts[20];
|
||||
struct tm *tm;
|
||||
|
||||
if (s == 0)
|
||||
return "never";
|
||||
tm = localtime(&s);
|
||||
|
||||
strftime(ts, (size_t)20, "%d-%m-%Y %H:%M:%S", tm);
|
||||
return bip_strftime(tm);
|
||||
}
|
||||
|
||||
char *bip_strftime(struct tm *tm)
|
||||
{
|
||||
static char ts[TIMESTAMP_FORMAT_MAXLEN];
|
||||
size_t len, written;
|
||||
|
||||
ts[0] = '\0';
|
||||
len = strlen(conf_timestamp_format);
|
||||
if (len > TIMESTAMP_FORMAT_MAXLEN)
|
||||
fatal_nots("Timestamp format itself exceeds "
|
||||
"maximum allowed length(%d)", TIMESTAMP_FORMAT_MAXLEN);
|
||||
|
||||
/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39438 */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||
written = strftime(ts, (size_t)TIMESTAMP_FORMAT_MAXLEN, conf_timestamp_format, tm);
|
||||
#pragma GCC diagnostic pop
|
||||
/* if format len is 0, format is empty and written will also return 0 */
|
||||
if (!written && !errno && len != 0)
|
||||
mylog_nots(LOG_WARN, "Truncated timestamp, result exceeds "
|
||||
"maximum size of %d characters.", TIMESTAMP_FORMAT_MAXLEN);
|
||||
return ts;
|
||||
}
|
||||
|
||||
@ -260,7 +281,7 @@ char *checkmode2text(int v)
|
||||
}
|
||||
#endif
|
||||
|
||||
void _mylog(int level, char *fmt, va_list ap)
|
||||
void _mylog(int level, int with_timestamp, char *fmt, va_list ap)
|
||||
{
|
||||
char *prefix;
|
||||
|
||||
@ -294,7 +315,11 @@ void _mylog(int level, char *fmt, va_list ap)
|
||||
break;
|
||||
}
|
||||
|
||||
fprintf(conf_global_log_file, "%s %s", timestamp(), prefix);
|
||||
if (with_timestamp)
|
||||
fprintf(conf_global_log_file, "%s %s", timestamp(), prefix);
|
||||
else
|
||||
fprintf(conf_global_log_file, "%s", prefix);
|
||||
|
||||
vfprintf(conf_global_log_file, fmt, ap);
|
||||
fprintf(conf_global_log_file, "\n");
|
||||
#ifdef DEBUG
|
||||
@ -307,7 +332,16 @@ void mylog(int level, char *fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_mylog(level, fmt, ap);
|
||||
_mylog(level, 1, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void mylog_nots(int level, char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_mylog(level, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
@ -330,7 +364,22 @@ void fatal(char *fmt, ...)
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_mylog(LOG_FATAL, fmt, ap);
|
||||
_mylog(LOG_FATAL, 1, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
dump_trace();
|
||||
#endif
|
||||
|
||||
exit(200);
|
||||
}
|
||||
|
||||
void fatal_nots(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
_mylog(LOG_FATAL, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
|
@ -31,10 +31,14 @@
|
||||
#define HASH_NOCASE 1
|
||||
#define HASH_DEFAULT 0
|
||||
|
||||
#define TIMESTAMP_FORMAT_MAXLEN 50
|
||||
|
||||
void mylog(int level, char *fmt, ...);
|
||||
void _mylog(int level, char *fmt, va_list ap);
|
||||
void mylog_nots(int level, char *fmt, ...);
|
||||
void fatal(char *fmt, ...);
|
||||
void fatal_nots(char *fmt, ...);
|
||||
char *timestamp(void);
|
||||
char *bip_strftime(struct tm *tm);
|
||||
struct hash_item;
|
||||
|
||||
struct list_item {
|
||||
|
104
src/utils/b64/base64.c
Normal file
104
src/utils/b64/base64.c
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Base64 encoding/decoding (RFC1341)
|
||||
* Copyright (c) 2005-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "utils/common.h"
|
||||
#include "os.h"
|
||||
#include "base64.h"
|
||||
|
||||
static const char base64_table[65] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
|
||||
#define BASE64_PAD BIT(0)
|
||||
#define BASE64_LF BIT(1)
|
||||
|
||||
|
||||
static char * base64_gen_encode(const unsigned char *src, size_t len,
|
||||
size_t *out_len, const char *table, int add_pad)
|
||||
{
|
||||
char *out, *pos;
|
||||
const unsigned char *end, *in;
|
||||
size_t olen;
|
||||
int line_len;
|
||||
|
||||
if (len >= SIZE_MAX / 4)
|
||||
return NULL;
|
||||
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
|
||||
if (add_pad & BASE64_LF)
|
||||
olen += olen / 72; /* line feeds */
|
||||
olen++; /* nul termination */
|
||||
if (olen < len)
|
||||
return NULL; /* integer overflow */
|
||||
out = os_malloc(olen);
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
|
||||
end = src + len;
|
||||
in = src;
|
||||
pos = out;
|
||||
line_len = 0;
|
||||
while (end - in >= 3) {
|
||||
*pos++ = table[(in[0] >> 2) & 0x3f];
|
||||
*pos++ = table[(((in[0] & 0x03) << 4) | (in[1] >> 4)) & 0x3f];
|
||||
*pos++ = table[(((in[1] & 0x0f) << 2) | (in[2] >> 6)) & 0x3f];
|
||||
*pos++ = table[in[2] & 0x3f];
|
||||
in += 3;
|
||||
line_len += 4;
|
||||
if ((add_pad & BASE64_LF) && line_len >= 72) {
|
||||
*pos++ = '\n';
|
||||
line_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (end - in) {
|
||||
*pos++ = table[(in[0] >> 2) & 0x3f];
|
||||
if (end - in == 1) {
|
||||
*pos++ = table[((in[0] & 0x03) << 4) & 0x3f];
|
||||
if (add_pad & BASE64_PAD)
|
||||
*pos++ = '=';
|
||||
} else {
|
||||
*pos++ = table[(((in[0] & 0x03) << 4) |
|
||||
(in[1] >> 4)) & 0x3f];
|
||||
*pos++ = table[((in[1] & 0x0f) << 2) & 0x3f];
|
||||
}
|
||||
if (add_pad & BASE64_PAD)
|
||||
*pos++ = '=';
|
||||
line_len += 4;
|
||||
}
|
||||
|
||||
if ((add_pad & BASE64_LF) && line_len)
|
||||
*pos++ = '\n';
|
||||
|
||||
*pos = '\0';
|
||||
if (out_len)
|
||||
*out_len = (size_t)(pos - out);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* base64_encode - Base64 encode
|
||||
* @src: Data to be encoded
|
||||
* @len: Length of the data to be encoded
|
||||
* @out_len: Pointer to output length variable, or %NULL if not used
|
||||
* Returns: Allocated buffer of out_len bytes of encoded data,
|
||||
* or %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer. Returned buffer is
|
||||
* nul terminated to make it easier to use as a C string. The nul terminator is
|
||||
* not included in out_len.
|
||||
*/
|
||||
char * base64_encode_no_lf(const void *src, size_t len, size_t *out_len)
|
||||
{
|
||||
return base64_gen_encode(src, len, out_len, base64_table, BASE64_PAD);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
/*
|
||||
* Base64 encoding/decoding (RFC1341)
|
||||
* Copyright (c) 2005, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2022 Loïc Gomez
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
@ -10,7 +9,7 @@
|
||||
#ifndef BASE64_H
|
||||
#define BASE64_H
|
||||
|
||||
unsigned char *base64_encode(const unsigned char *src, size_t len,
|
||||
size_t *out_len);
|
||||
char * base64_encode_no_lf(const void *src, size_t len, size_t *out_len);
|
||||
|
||||
#endif /* BASE64_H */
|
||||
|
4
src/utils/b64/includes.h
Normal file
4
src/utils/b64/includes.h
Normal file
@ -0,0 +1,4 @@
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
3
src/utils/b64/os.h
Normal file
3
src/utils/b64/os.h
Normal file
@ -0,0 +1,3 @@
|
||||
#ifndef os_malloc
|
||||
#define os_malloc(s) malloc((s))
|
||||
#endif
|
3
src/utils/b64/utils/common.h
Normal file
3
src/utils/b64/utils/common.h
Normal file
@ -0,0 +1,3 @@
|
||||
#ifndef BIT
|
||||
#define BIT(x) (int)(1U << (x))
|
||||
#endif
|
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Base64 encoding/decoding (RFC1341)
|
||||
* Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2022 Loïc Gomez
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "base64.h"
|
||||
|
||||
static const unsigned char base64_table[65] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
/**
|
||||
* base64_encode - Base64 encode
|
||||
* @src: Data to be encoded
|
||||
* @len: Length of the data to be encoded
|
||||
* @out_len: Pointer to output length variable, or %NULL if not used
|
||||
* Returns: Allocated buffer of out_len bytes of encoded data,
|
||||
* or %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer. Returned buffer is
|
||||
* nul terminated to make it easier to use as a C string. The nul terminator is
|
||||
* not included in out_len.
|
||||
*
|
||||
* BIP change: remove line returns.
|
||||
*/
|
||||
unsigned char *base64_encode(const unsigned char *src, size_t len,
|
||||
size_t *out_len)
|
||||
{
|
||||
unsigned char *out, *pos;
|
||||
const unsigned char *end, *in;
|
||||
size_t olen;
|
||||
int line_len;
|
||||
|
||||
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
|
||||
olen += olen / 72; /* line feeds */
|
||||
olen++; /* nul termination */
|
||||
if (olen < len)
|
||||
return NULL; /* integer overflow */
|
||||
out = malloc(olen);
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
|
||||
end = src + len;
|
||||
in = src;
|
||||
pos = out;
|
||||
line_len = 0;
|
||||
while (end - in >= 3) {
|
||||
*pos++ = base64_table[in[0] >> 2];
|
||||
*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
|
||||
*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
|
||||
*pos++ = base64_table[in[2] & 0x3f];
|
||||
in += 3;
|
||||
line_len += 4;
|
||||
/*
|
||||
* BIP change: remove line returns.
|
||||
if (line_len >= 72) {
|
||||
*pos++ = '\n';
|
||||
line_len = 0;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if (end - in) {
|
||||
*pos++ = base64_table[in[0] >> 2];
|
||||
if (end - in == 1) {
|
||||
*pos++ = base64_table[(in[0] & 0x03) << 4];
|
||||
*pos++ = '=';
|
||||
} else {
|
||||
*pos++ = base64_table[((in[0] & 0x03) << 4)
|
||||
| (in[1] >> 4)];
|
||||
*pos++ = base64_table[(in[1] & 0x0f) << 2];
|
||||
}
|
||||
*pos++ = '=';
|
||||
line_len += 4;
|
||||
}
|
||||
|
||||
/*
|
||||
* BIP change: remove line returns.
|
||||
if (line_len)
|
||||
*pos++ = '\n';
|
||||
*/
|
||||
|
||||
*pos = '\0';
|
||||
if (out_len)
|
||||
*out_len = (size_t)(pos - out);
|
||||
return out;
|
||||
}
|
Loading…
Reference in New Issue
Block a user