Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
3c048f0d56
|
|||
|
8e668ff31a
|
|||
|
eb70bf3fbc
|
|||
|
d86a68f510
|
|||
|
d6be22291d
|
|||
|
a813babb89
|
|||
|
b666ce6926
|
|||
|
e2bb051bd3
|
|||
|
52d1ded7df
|
|||
|
cb9f187f80
|
|||
|
0247c4667a
|
|||
|
572f4e2ea3
|
|||
|
50599e09bd
|
|||
|
b24bb0aded
|
|||
|
7c6cf42075
|
|||
|
414a525c4d
|
|||
|
6cee7159f2
|
|||
|
568f9b7123
|
|||
|
0d499dd125
|
|||
|
37e49b54cf
|
|||
|
742d590b8d
|
|||
|
b6528c73e3
|
|||
|
1e79aaec26
|
|||
|
0995da3900
|
|||
|
c8a826f016
|
|||
|
95c7ababc3
|
|||
|
a0d733fdb9
|
|||
|
557a39c6c8
|
|||
|
745e758394
|
|||
|
b60bdf119a
|
|||
|
278e2b236b
|
|||
|
2f758bbdb9
|
|||
|
911276b263
|
|||
|
cb5ad675a6
|
|||
|
9408dfc67c
|
|||
|
fed8b06aff
|
|||
|
7e64fd9886
|
|||
|
6928184a3d
|
|||
|
f7155f3919
|
|||
|
f032466307
|
|||
|
c0f4b554ef
|
|||
|
639da7a9a7
|
|||
|
230b04014f
|
|||
|
4848354bb9
|
|||
|
8028c7fa47
|
|||
|
43de836b91
|
|||
|
16d10f574b
|
|||
|
4cefa5ab1b
|
|||
|
92a4d4b5a7
|
|||
|
26f94d2459
|
|||
|
0be43691d0
|
|||
|
483ab39e3c
|
|||
|
beaf1a1f82
|
|||
|
5613c326c9
|
@@ -13,7 +13,7 @@ if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUC)
|
|||||||
endif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUC)
|
endif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUC)
|
||||||
|
|
||||||
# Version
|
# Version
|
||||||
set (project_version "0.9.4")
|
set (project_version "0.9.5")
|
||||||
|
|
||||||
# Try to append commit ID if it follows a version tag. It might be nicer if
|
# Try to append commit ID if it follows a version tag. It might be nicer if
|
||||||
# we could also detect dirty worktrees but that's very hard to get right.
|
# we could also detect dirty worktrees but that's very hard to get right.
|
||||||
|
|||||||
31
NEWS
31
NEWS
@@ -1,3 +1,34 @@
|
|||||||
|
0.9.5 (2016-12-30) "It's Time"
|
||||||
|
|
||||||
|
* Better support for the KILL command
|
||||||
|
|
||||||
|
* degesch: export many more fields to the Lua API, add a prompt hook
|
||||||
|
|
||||||
|
* degesch: show channel user count in the prompt
|
||||||
|
|
||||||
|
* degesch: allow hiding join/part messages and other noise (Meta-Shift-H)
|
||||||
|
|
||||||
|
* degesch: allow autojoining channels with keys
|
||||||
|
|
||||||
|
* degesch: rejoin channels with keys on reconnect
|
||||||
|
|
||||||
|
* degesch: make /query without arguments just open the buffer
|
||||||
|
|
||||||
|
* degesch: add a censor plugin
|
||||||
|
|
||||||
|
* degesch: die on configuration parse errors
|
||||||
|
|
||||||
|
* degesch: request channel modes also on rejoin
|
||||||
|
|
||||||
|
* degesch: don't show remembered channel modes on parted channels
|
||||||
|
|
||||||
|
* degesch: fix highlight detection in colored text
|
||||||
|
|
||||||
|
* degesch: fix CTCP handling for the real world and don't decode X-QUOTEs
|
||||||
|
|
||||||
|
* degesch: add support for OpenSSL 1.1.0
|
||||||
|
|
||||||
|
|
||||||
0.9.4 (2016-04-28) "Oops"
|
0.9.4 (2016-04-28) "Oops"
|
||||||
|
|
||||||
* degesch: fix crash on characters invalid in Windows-1252
|
* degesch: fix crash on characters invalid in Windows-1252
|
||||||
|
|||||||
33
README.adoc
33
README.adoc
@@ -20,11 +20,13 @@ The IRC client. It is largely defined by being built on top of GNU Readline
|
|||||||
that has been hacked to death. Its interface should feel somewhat familiar for
|
that has been hacked to death. Its interface should feel somewhat familiar for
|
||||||
weechat or irssi users.
|
weechat or irssi users.
|
||||||
|
|
||||||
|
image::degesch.png[align="center"]
|
||||||
|
|
||||||
This is the largest application within the project. It has most of the stuff
|
This is the largest application within the project. It has most of the stuff
|
||||||
you'd expect of an IRC client, such as being able to set up multiple servers,
|
you'd expect of an IRC client, such as being able to set up multiple servers,
|
||||||
a powerful configuration system, integrated help, text formatting, CTCP queries,
|
a powerful configuration system, integrated help, text formatting, CTCP queries,
|
||||||
automatic splitting of overlong messages, autocomplete, logging to file,
|
automatic splitting of overlong messages, autocomplete, logging to file,
|
||||||
auto-away, command aliases and rudimentary support for Lua scripting.
|
auto-away, command aliases and basic support for Lua scripting.
|
||||||
|
|
||||||
kike
|
kike
|
||||||
----
|
----
|
||||||
@@ -142,6 +144,35 @@ Consult the source code and the GNU Readline manual for a list of available
|
|||||||
functions. Also refer to the latter for the exact syntax of this file.
|
functions. Also refer to the latter for the exact syntax of this file.
|
||||||
Beware that you can easily break the program if you're not careful.
|
Beware that you can easily break the program if you're not careful.
|
||||||
|
|
||||||
|
How do I make degesch look like the screenshot?
|
||||||
|
-----------------------------------------------
|
||||||
|
First of all, you must build it with Lua support. With the defaults, degesch
|
||||||
|
doesn't look very fancy because some things are rather hackish, and I also don't
|
||||||
|
want to depend on UTF-8 or 256color terminals in the code. In addition to that,
|
||||||
|
I appear to be one of the few people who use black on white terminals.
|
||||||
|
|
||||||
|
/set behaviour.date_change_line = "%a %e %b %Y"
|
||||||
|
/set behaviour.plugin_autoload += "fancy-prompt.lua,thin-cursor.lua"
|
||||||
|
/set behaviour.backlog_helper = "LESSSECURE=1 less -R +Gb -Ps'Backlog ?ltlines %lt-%lb?L/%L. .?e(END):?pB%pB\\%..'"
|
||||||
|
/set behaviour.backlog_helper_strip_formatting = off
|
||||||
|
/set attributes.reset = "\x1b[0m"
|
||||||
|
/set attributes.userhost = "\x1b[38;5;109m"
|
||||||
|
/set attributes.join = "\x1b[38;5;108m"
|
||||||
|
/set attributes.part = "\x1b[38;5;138m"
|
||||||
|
/set attributes.external = "\x1b[38;5;248m"
|
||||||
|
/set attributes.timestamp = "\x1b[48;5;255m\x1b[38;5;250m"
|
||||||
|
|
||||||
|
Configuration profiles
|
||||||
|
----------------------
|
||||||
|
Even though the applications don't directly support configuration profiles,
|
||||||
|
they conform to the XDG standard, and thus you can change the location they
|
||||||
|
load configuration from via XDG_CONFIG_HOME (normally '~/.config') and the
|
||||||
|
location where store their data via XDG_DATA_HOME (normally '~/.local/share').
|
||||||
|
|
||||||
|
It would be relatively easy to make the applications assume whatever name you
|
||||||
|
run them under (for example by using symbolic links), and load different
|
||||||
|
configurations accordingly, but I consider it rather messy and unnecessary.
|
||||||
|
|
||||||
Contributing and Support
|
Contributing and Support
|
||||||
------------------------
|
------------------------
|
||||||
Use this project's GitHub to report any bugs, request features, or submit pull
|
Use this project's GitHub to report any bugs, request features, or submit pull
|
||||||
|
|||||||
104
common.c
104
common.c
@@ -34,12 +34,20 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
|
|
||||||
/// Shorthand to set an error and return failure from the function
|
static void
|
||||||
#define FAIL(...) \
|
init_openssl (void)
|
||||||
BLOCK_START \
|
{
|
||||||
error_set (e, __VA_ARGS__); \
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||||
return 0; \
|
SSL_library_init ();
|
||||||
BLOCK_END
|
// XXX: this list is probably not complete
|
||||||
|
atexit (EVP_cleanup);
|
||||||
|
SSL_load_error_strings ();
|
||||||
|
atexit (ERR_free_strings);
|
||||||
|
#else
|
||||||
|
// Cleanup is done automatically via atexit()
|
||||||
|
OPENSSL_init_ssl (0, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// --- To be moved to liberty --------------------------------------------------
|
// --- To be moved to liberty --------------------------------------------------
|
||||||
|
|
||||||
@@ -108,79 +116,11 @@ xwrite (int fd, const char *data, size_t len, struct error **e)
|
|||||||
if (res >= 0)
|
if (res >= 0)
|
||||||
written += res;
|
written += res;
|
||||||
else if (errno != EINTR)
|
else if (errno != EINTR)
|
||||||
FAIL ("%s", strerror (errno));
|
return error_set (e, "%s", strerror (errno));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Simple network I/O ------------------------------------------------------
|
|
||||||
|
|
||||||
// TODO: move to liberty and remove from dwmstatus.c as well
|
|
||||||
|
|
||||||
#define SOCKET_IO_OVERFLOW (8 << 20) ///< How large a read buffer can be
|
|
||||||
|
|
||||||
enum socket_io_result
|
|
||||||
{
|
|
||||||
SOCKET_IO_OK, ///< Completed successfully
|
|
||||||
SOCKET_IO_EOF, ///< Connection shut down by peer
|
|
||||||
SOCKET_IO_ERROR ///< Connection error
|
|
||||||
};
|
|
||||||
|
|
||||||
static enum socket_io_result
|
|
||||||
socket_io_try_read (int socket_fd, struct str *rb, struct error **e)
|
|
||||||
{
|
|
||||||
// We allow buffering of a fair amount of data, however within reason,
|
|
||||||
// so that it's not so easy to flood us and cause an allocation failure
|
|
||||||
ssize_t n_read;
|
|
||||||
while (rb->len < SOCKET_IO_OVERFLOW)
|
|
||||||
{
|
|
||||||
str_ensure_space (rb, 4096);
|
|
||||||
n_read = recv (socket_fd, rb->str + rb->len,
|
|
||||||
rb->alloc - rb->len - 1 /* null byte */, 0);
|
|
||||||
|
|
||||||
if (n_read > 0)
|
|
||||||
{
|
|
||||||
rb->str[rb->len += n_read] = '\0';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (n_read == 0)
|
|
||||||
return SOCKET_IO_EOF;
|
|
||||||
|
|
||||||
if (errno == EAGAIN)
|
|
||||||
return SOCKET_IO_OK;
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
error_set (e, "%s", strerror (errno));
|
|
||||||
return SOCKET_IO_ERROR;
|
|
||||||
}
|
|
||||||
return SOCKET_IO_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum socket_io_result
|
|
||||||
socket_io_try_write (int socket_fd, struct str *wb, struct error **e)
|
|
||||||
{
|
|
||||||
ssize_t n_written;
|
|
||||||
while (wb->len)
|
|
||||||
{
|
|
||||||
n_written = send (socket_fd, wb->str, wb->len, 0);
|
|
||||||
if (n_written >= 0)
|
|
||||||
{
|
|
||||||
str_remove_slice (wb, 0, n_written);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errno == EAGAIN)
|
|
||||||
return SOCKET_IO_OK;
|
|
||||||
if (errno == EINTR)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
error_set (e, "%s", strerror (errno));
|
|
||||||
return SOCKET_IO_ERROR;
|
|
||||||
}
|
|
||||||
return SOCKET_IO_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Logging -----------------------------------------------------------------
|
// --- Logging -----------------------------------------------------------------
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1023,6 +963,13 @@ ctcp_intra_decode (const char *chunk, size_t len, struct str *output)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// According to the original CTCP specification we should use
|
||||||
|
// ctcp_intra_decode() on all parts, however no one seems to use that
|
||||||
|
// and it breaks normal text with backslashes
|
||||||
|
#ifndef SUPPORT_CTCP_X_QUOTES
|
||||||
|
#define ctcp_intra_decode(s, len, output) str_append_data (output, s, len)
|
||||||
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ctcp_parse_tagged (const char *chunk, size_t len, struct ctcp_chunk *output)
|
ctcp_parse_tagged (const char *chunk, size_t len, struct ctcp_chunk *output)
|
||||||
{
|
{
|
||||||
@@ -1051,9 +998,6 @@ ctcp_parse (const char *message)
|
|||||||
|
|
||||||
struct ctcp_chunk *result = NULL, *result_tail = NULL;
|
struct ctcp_chunk *result = NULL, *result_tail = NULL;
|
||||||
|
|
||||||
// According to the original CTCP specification we should use
|
|
||||||
// ctcp_intra_decode() on all parts, however no one seems to
|
|
||||||
// use that and it breaks normal text with backslashes
|
|
||||||
size_t start = 0;
|
size_t start = 0;
|
||||||
bool in_ctcp = false;
|
bool in_ctcp = false;
|
||||||
for (size_t i = 0; i < m.len; i++)
|
for (size_t i = 0; i < m.len; i++)
|
||||||
@@ -1077,7 +1021,7 @@ ctcp_parse (const char *message)
|
|||||||
if (my_is_ctcp)
|
if (my_is_ctcp)
|
||||||
ctcp_parse_tagged (m.str + my_start, i - my_start, chunk);
|
ctcp_parse_tagged (m.str + my_start, i - my_start, chunk);
|
||||||
else
|
else
|
||||||
str_append_data (&chunk->text, m.str + my_start, i - my_start);
|
ctcp_intra_decode (m.str + my_start, i - my_start, &chunk->text);
|
||||||
LIST_APPEND_WITH_TAIL (result, result_tail, chunk);
|
LIST_APPEND_WITH_TAIL (result, result_tail, chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1091,7 +1035,7 @@ ctcp_parse (const char *message)
|
|||||||
chunk->is_partial = true;
|
chunk->is_partial = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
str_append_data (&chunk->text, m.str + start, m.len - start);
|
ctcp_intra_decode (m.str + start, m.len - start, &chunk->text);
|
||||||
LIST_APPEND_WITH_TAIL (result, result_tail, chunk);
|
LIST_APPEND_WITH_TAIL (result, result_tail, chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
degesch.png
Normal file
BIN
degesch.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.9 KiB |
35
kike.c
35
kike.c
@@ -1403,7 +1403,7 @@ irc_handle_cap (const struct irc_message *msg, struct client *c)
|
|||||||
if (msg->params.len > 1)
|
if (msg->params.len > 1)
|
||||||
{
|
{
|
||||||
args.full_params = msg->params.vector[1];
|
args.full_params = msg->params.vector[1];
|
||||||
cstr_split_ignore_empty (args.full_params, ' ', &args.params);
|
cstr_split (args.full_params, " ", true, &args.params);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct irc_cap_command *cmd =
|
struct irc_cap_command *cmd =
|
||||||
@@ -2186,7 +2186,7 @@ irc_handle_list (const struct irc_message *msg, struct client *c)
|
|||||||
{
|
{
|
||||||
struct str_vector channels;
|
struct str_vector channels;
|
||||||
str_vector_init (&channels);
|
str_vector_init (&channels);
|
||||||
cstr_split_ignore_empty (msg->params.vector[0], ',', &channels);
|
cstr_split (msg->params.vector[0], ",", true, &channels);
|
||||||
for (size_t i = 0; i < channels.len; i++)
|
for (size_t i = 0; i < channels.len; i++)
|
||||||
if ((chan = str_map_find (&c->ctx->channels, channels.vector[i]))
|
if ((chan = str_map_find (&c->ctx->channels, channels.vector[i]))
|
||||||
&& (!(chan->modes & IRC_CHAN_MODE_SECRET)
|
&& (!(chan->modes & IRC_CHAN_MODE_SECRET)
|
||||||
@@ -2317,7 +2317,7 @@ irc_handle_names (const struct irc_message *msg, struct client *c)
|
|||||||
{
|
{
|
||||||
struct str_vector channels;
|
struct str_vector channels;
|
||||||
str_vector_init (&channels);
|
str_vector_init (&channels);
|
||||||
cstr_split_ignore_empty (msg->params.vector[0], ',', &channels);
|
cstr_split (msg->params.vector[0], ",", true, &channels);
|
||||||
for (size_t i = 0; i < channels.len; i++)
|
for (size_t i = 0; i < channels.len; i++)
|
||||||
if ((chan = str_map_find (&c->ctx->channels, channels.vector[i]))
|
if ((chan = str_map_find (&c->ctx->channels, channels.vector[i]))
|
||||||
&& (!(chan->modes & IRC_CHAN_MODE_SECRET)
|
&& (!(chan->modes & IRC_CHAN_MODE_SECRET)
|
||||||
@@ -2480,7 +2480,7 @@ irc_handle_whois (const struct irc_message *msg, struct client *c)
|
|||||||
struct str_vector masks;
|
struct str_vector masks;
|
||||||
str_vector_init (&masks);
|
str_vector_init (&masks);
|
||||||
const char *masks_str = msg->params.vector[msg->params.len > 1];
|
const char *masks_str = msg->params.vector[msg->params.len > 1];
|
||||||
cstr_split_ignore_empty (masks_str, ',', &masks);
|
cstr_split (masks_str, ",", true, &masks);
|
||||||
for (size_t i = 0; i < masks.len; i++)
|
for (size_t i = 0; i < masks.len; i++)
|
||||||
{
|
{
|
||||||
const char *mask = masks.vector[i];
|
const char *mask = masks.vector[i];
|
||||||
@@ -2521,7 +2521,7 @@ irc_handle_whowas (const struct irc_message *msg, struct client *c)
|
|||||||
|
|
||||||
struct str_vector nicks;
|
struct str_vector nicks;
|
||||||
str_vector_init (&nicks);
|
str_vector_init (&nicks);
|
||||||
cstr_split_ignore_empty (msg->params.vector[0], ',', &nicks);
|
cstr_split (msg->params.vector[0], ",", true, &nicks);
|
||||||
|
|
||||||
for (size_t i = 0; i < nicks.len; i++)
|
for (size_t i = 0; i < nicks.len; i++)
|
||||||
{
|
{
|
||||||
@@ -2641,7 +2641,7 @@ irc_handle_part (const struct irc_message *msg, struct client *c)
|
|||||||
const char *reason = msg->params.len > 1 ? msg->params.vector[1] : NULL;
|
const char *reason = msg->params.len > 1 ? msg->params.vector[1] : NULL;
|
||||||
struct str_vector channels;
|
struct str_vector channels;
|
||||||
str_vector_init (&channels);
|
str_vector_init (&channels);
|
||||||
cstr_split_ignore_empty (msg->params.vector[0], ',', &channels);
|
cstr_split (msg->params.vector[0], ",", true, &channels);
|
||||||
for (size_t i = 0; i < channels.len; i++)
|
for (size_t i = 0; i < channels.len; i++)
|
||||||
irc_try_part (c, channels.vector[i], reason);
|
irc_try_part (c, channels.vector[i], reason);
|
||||||
str_vector_free (&channels);
|
str_vector_free (&channels);
|
||||||
@@ -2692,8 +2692,8 @@ irc_handle_kick (const struct irc_message *msg, struct client *c)
|
|||||||
struct str_vector users;
|
struct str_vector users;
|
||||||
str_vector_init (&channels);
|
str_vector_init (&channels);
|
||||||
str_vector_init (&users);
|
str_vector_init (&users);
|
||||||
cstr_split_ignore_empty (msg->params.vector[0], ',', &channels);
|
cstr_split (msg->params.vector[0], ",", true, &channels);
|
||||||
cstr_split_ignore_empty (msg->params.vector[1], ',', &users);
|
cstr_split (msg->params.vector[1], ",", true, &users);
|
||||||
|
|
||||||
if (channels.len == 1)
|
if (channels.len == 1)
|
||||||
for (size_t i = 0; i < users.len; i++)
|
for (size_t i = 0; i < users.len; i++)
|
||||||
@@ -2821,9 +2821,9 @@ irc_handle_join (const struct irc_message *msg, struct client *c)
|
|||||||
struct str_vector keys;
|
struct str_vector keys;
|
||||||
str_vector_init (&channels);
|
str_vector_init (&channels);
|
||||||
str_vector_init (&keys);
|
str_vector_init (&keys);
|
||||||
cstr_split_ignore_empty (msg->params.vector[0], ',', &channels);
|
cstr_split (msg->params.vector[0], ",", true, &channels);
|
||||||
if (msg->params.len > 1)
|
if (msg->params.len > 1)
|
||||||
cstr_split_ignore_empty (msg->params.vector[1], ',', &keys);
|
cstr_split (msg->params.vector[1], ",", true, &keys);
|
||||||
|
|
||||||
for (size_t i = 0; i < channels.len; i++)
|
for (size_t i = 0; i < channels.len; i++)
|
||||||
irc_try_join (c, channels.vector[i],
|
irc_try_join (c, channels.vector[i],
|
||||||
@@ -2991,6 +2991,11 @@ irc_handle_kill (const struct irc_message *msg, struct client *c)
|
|||||||
struct client *target;
|
struct client *target;
|
||||||
if (!(target = str_map_find (&c->ctx->users, msg->params.vector[0])))
|
if (!(target = str_map_find (&c->ctx->users, msg->params.vector[0])))
|
||||||
RETURN_WITH_REPLY (c, IRC_ERR_NOSUCHNICK, msg->params.vector[0]);
|
RETURN_WITH_REPLY (c, IRC_ERR_NOSUCHNICK, msg->params.vector[0]);
|
||||||
|
|
||||||
|
client_send (target, ":%s!%s@%s KILL %s :%s",
|
||||||
|
c->nickname, c->username, c->hostname,
|
||||||
|
target->nickname, msg->params.vector[1]);
|
||||||
|
|
||||||
char *reason = xstrdup_printf ("Killed by %s: %s",
|
char *reason = xstrdup_printf ("Killed by %s: %s",
|
||||||
c->nickname, msg->params.vector[1]);
|
c->nickname, msg->params.vector[1]);
|
||||||
client_close_link (target, reason);
|
client_close_link (target, reason);
|
||||||
@@ -3739,7 +3744,7 @@ irc_parse_config (struct server_context *ctx, struct error **e)
|
|||||||
str_vector_init (&fingerprints);
|
str_vector_init (&fingerprints);
|
||||||
const char *operators = str_map_find (&ctx->config, "operators");
|
const char *operators = str_map_find (&ctx->config, "operators");
|
||||||
if (operators)
|
if (operators)
|
||||||
cstr_split_ignore_empty (operators, ',', &fingerprints);
|
cstr_split (operators, ",", true, &fingerprints);
|
||||||
for (size_t i = 0; i < fingerprints.len; i++)
|
for (size_t i = 0; i < fingerprints.len; i++)
|
||||||
{
|
{
|
||||||
const char *key = fingerprints.vector[i];
|
const char *key = fingerprints.vector[i];
|
||||||
@@ -3900,7 +3905,7 @@ irc_setup_listen_fds (struct server_context *ctx, struct error **e)
|
|||||||
|
|
||||||
struct str_vector ports;
|
struct str_vector ports;
|
||||||
str_vector_init (&ports);
|
str_vector_init (&ports);
|
||||||
cstr_split_ignore_empty (bind_port, ',', &ports);
|
cstr_split (bind_port, ",", true, &ports);
|
||||||
ctx->listen_fds = xcalloc (ports.len, sizeof *ctx->listen_fds);
|
ctx->listen_fds = xcalloc (ports.len, sizeof *ctx->listen_fds);
|
||||||
ctx->listen_events = xcalloc (ports.len, sizeof *ctx->listen_events);
|
ctx->listen_events = xcalloc (ports.len, sizeof *ctx->listen_events);
|
||||||
for (size_t i = 0; i < ports.len; i++)
|
for (size_t i = 0; i < ports.len; i++)
|
||||||
@@ -4038,11 +4043,7 @@ main (int argc, char *argv[])
|
|||||||
|
|
||||||
print_status (PROGRAM_NAME " " PROGRAM_VERSION " starting");
|
print_status (PROGRAM_NAME " " PROGRAM_VERSION " starting");
|
||||||
setup_signal_handlers ();
|
setup_signal_handlers ();
|
||||||
|
init_openssl ();
|
||||||
SSL_library_init ();
|
|
||||||
atexit (EVP_cleanup);
|
|
||||||
SSL_load_error_strings ();
|
|
||||||
atexit (ERR_free_strings);
|
|
||||||
|
|
||||||
struct server_context ctx;
|
struct server_context ctx;
|
||||||
server_context_init (&ctx);
|
server_context_init (&ctx);
|
||||||
|
|||||||
2
liberty
2
liberty
Submodule liberty updated: 365aed456e...f53b717f3b
@@ -32,6 +32,7 @@ degesch.setup_config {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async, await = degesch.async, coroutine.yield
|
||||||
degesch.hook_irc (function (hook, server, line)
|
degesch.hook_irc (function (hook, server, line)
|
||||||
local msg = degesch.parse (line)
|
local msg = degesch.parse (line)
|
||||||
if msg.command ~= "KICK" then return line end
|
if msg.command ~= "KICK" then return line end
|
||||||
@@ -39,9 +40,10 @@ degesch.hook_irc (function (hook, server, line)
|
|||||||
local who = msg.prefix:match ("^[^!]*")
|
local who = msg.prefix:match ("^[^!]*")
|
||||||
local channel, whom = table.unpack (msg.params)
|
local channel, whom = table.unpack (msg.params)
|
||||||
if who ~= whom and whom == server.user.nickname then
|
if who ~= whom and whom == server.user.nickname then
|
||||||
degesch.hook_timer (function (hook)
|
async.go (function ()
|
||||||
|
await (async.timer_ms (timeout * 1000))
|
||||||
server:send ("JOIN " .. channel)
|
server:send ("JOIN " .. channel)
|
||||||
end, timeout * 1000)
|
end)
|
||||||
end
|
end
|
||||||
return line
|
return line
|
||||||
end)
|
end)
|
||||||
|
|||||||
74
plugins/degesch/censor.lua
Normal file
74
plugins/degesch/censor.lua
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
--
|
||||||
|
-- censor.lua: black out certain users' messages
|
||||||
|
--
|
||||||
|
-- Copyright (c) 2016, Přemysl Janouch <p.janouch@gmail.com>
|
||||||
|
--
|
||||||
|
-- Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
-- purpose with or without fee is hereby granted, provided that the above
|
||||||
|
-- copyright notice and this permission notice appear in all copies.
|
||||||
|
--
|
||||||
|
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
-- SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
-- OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
-- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
--
|
||||||
|
|
||||||
|
local to_pattern = function (mask)
|
||||||
|
if not mask:match ("!") then mask = mask .. "!*" end
|
||||||
|
if not mask:match ("@") then mask = mask .. "@*" end
|
||||||
|
|
||||||
|
-- That is, * acts like a wildcard, otherwise everything is escaped
|
||||||
|
return "^" .. mask:gsub ("[%^%$%(%)%%%.%[%]%+%-%?]", "%%%0")
|
||||||
|
:gsub ("%*", ".*") .. "$"
|
||||||
|
end
|
||||||
|
|
||||||
|
local patterns = {}
|
||||||
|
local read_masks = function (v)
|
||||||
|
patterns = {}
|
||||||
|
local add = function (who, where)
|
||||||
|
local channels = patterns[who] or {}
|
||||||
|
table.insert (channels, where)
|
||||||
|
patterns[who] = channels
|
||||||
|
end
|
||||||
|
for item in v:lower ():gmatch ("[^,]+") do
|
||||||
|
local who, where = item:match ("^([^/]+)/*(.*)")
|
||||||
|
if who then add (to_pattern (who), where == "" or where) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
degesch.setup_config {
|
||||||
|
masks = {
|
||||||
|
type = "string_array",
|
||||||
|
default = "\"\"",
|
||||||
|
comment = "user masks (optionally \"/#channel\") to censor",
|
||||||
|
on_change = read_masks
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
local censor = function (line)
|
||||||
|
-- Taking a shortcut to avoid lengthy message reassembly
|
||||||
|
local start, text = line:match ("^(.- PRIVMSG .-:)(.*)$")
|
||||||
|
local ctcp, rest = text:match ("^(\x01%g+ )(.*)")
|
||||||
|
text = ctcp and ctcp .. "\x0301,01" .. rest or "\x0301,01" .. text
|
||||||
|
return start .. text
|
||||||
|
end
|
||||||
|
|
||||||
|
degesch.hook_irc (function (hook, server, line)
|
||||||
|
local msg = degesch.parse (line)
|
||||||
|
if msg.command ~= "PRIVMSG" then return line end
|
||||||
|
|
||||||
|
local channel = msg.params[1]:lower ()
|
||||||
|
for who, where in pairs (patterns) do
|
||||||
|
if msg.prefix:lower ():match (who) then
|
||||||
|
for _, x in pairs (where) do
|
||||||
|
if x == true or x == channel then
|
||||||
|
return censor (line)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return line
|
||||||
|
end)
|
||||||
101
plugins/degesch/fancy-prompt.lua
Normal file
101
plugins/degesch/fancy-prompt.lua
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
--
|
||||||
|
-- fancy-prompt.lua: the fancy multiline prompt you probably want
|
||||||
|
--
|
||||||
|
-- Copyright (c) 2016, Přemysl Janouch <p.janouch@gmail.com>
|
||||||
|
--
|
||||||
|
-- Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
-- purpose with or without fee is hereby granted, provided that the above
|
||||||
|
-- copyright notice and this permission notice appear in all copies.
|
||||||
|
--
|
||||||
|
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
-- SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
-- OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
-- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
--
|
||||||
|
-- Beware that it is a hack and only goes about 90% of the way, which is why
|
||||||
|
-- this functionality is only available as a plugin in the first place
|
||||||
|
-- (well, and also for customizability).
|
||||||
|
--
|
||||||
|
-- The biggest problem is that the way we work with Readline is incompatible
|
||||||
|
-- with multiline prompts, and normal newlines just don't work. This is being
|
||||||
|
-- circumvented by using an overflowing single-line prompt with a specially
|
||||||
|
-- crafted character in the rightmost column that prevents the bar's background
|
||||||
|
-- from spilling all over the last line.
|
||||||
|
--
|
||||||
|
-- There is also a problem with C-r search rendering not clearing out the
|
||||||
|
-- background but to really fix that mode, we'd have to fully reimplement it
|
||||||
|
-- since its alternative prompt very often gets overriden by accident anyway.
|
||||||
|
|
||||||
|
local prompt = degesch.hook_prompt (function (hook)
|
||||||
|
local current = degesch.current_buffer
|
||||||
|
local chan = current.channel
|
||||||
|
local s = current.server
|
||||||
|
|
||||||
|
local bg_color = "255"
|
||||||
|
local current_n = 0
|
||||||
|
local active = ""
|
||||||
|
for i, buffer in ipairs (degesch.buffers) do
|
||||||
|
if buffer == current then
|
||||||
|
current_n = i
|
||||||
|
elseif buffer.new_messages_count ~= buffer.new_unimportant_count then
|
||||||
|
if active ~= "" then active = active .. "," end
|
||||||
|
if buffer.highlighted then
|
||||||
|
active = active .. "!"
|
||||||
|
bg_color = "224"
|
||||||
|
end
|
||||||
|
active = active .. i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if active ~= "" then active = "(" .. active .. ")" end
|
||||||
|
local x = current_n .. ":" .. current.name
|
||||||
|
if chan and chan.users_len ~= 0 then
|
||||||
|
local params = ""
|
||||||
|
for mode, param in pairs (chan.param_modes) do
|
||||||
|
params = params .. " +" .. mode .. " " .. param
|
||||||
|
end
|
||||||
|
local modes = chan.no_param_modes .. params:sub (3)
|
||||||
|
if modes ~= "" then x = x .. "(+" .. modes .. ")" end
|
||||||
|
x = x .. "{" .. chan.users_len .. "}"
|
||||||
|
end
|
||||||
|
if current.hide_unimportant then x = x .. "<H>" end
|
||||||
|
|
||||||
|
local lines, cols = degesch.get_screen_size ()
|
||||||
|
x = x .. " " .. active .. string.rep (" ", cols)
|
||||||
|
|
||||||
|
-- Cut off extra characters and apply formatting, including the hack.
|
||||||
|
-- Note that this doesn't count with full-width or zero-width characters.
|
||||||
|
local overflow = utf8.offset (x, cols - 1)
|
||||||
|
if overflow then x = x:sub (1, overflow) end
|
||||||
|
x = "\x01\x1b[0;4;1;38;5;16m\x1b[48;5;" .. bg_color .. "m\x02" ..
|
||||||
|
x .. "\x01\x1b[0;4;1;7;38;5;" .. bg_color .. "m\x02 \x01\x1b[0;1m\x02"
|
||||||
|
|
||||||
|
local user_prefix = function (chan, user)
|
||||||
|
for i, chan_user in ipairs (chan.users) do
|
||||||
|
if chan_user.user == user then return chan_user.prefixes end
|
||||||
|
end
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
if s then
|
||||||
|
x = x .. "["
|
||||||
|
local state = s.state
|
||||||
|
if state == "disconnected" or state == "connecting" then
|
||||||
|
x = x .. "(" .. state .. ")"
|
||||||
|
elseif state ~= "registered" then
|
||||||
|
x = x .. "(unregistered)"
|
||||||
|
else
|
||||||
|
local user, modes = s.user, s.user_mode
|
||||||
|
if chan then x = x .. user_prefix (chan, user) end
|
||||||
|
x = x .. user.nickname
|
||||||
|
if modes ~= "" then x = x .. "(" .. modes .. ")" end
|
||||||
|
end
|
||||||
|
x = x .. "] "
|
||||||
|
else
|
||||||
|
-- There needs to be at least one character so that the cursor
|
||||||
|
-- doesn't get damaged by our hack in that last column
|
||||||
|
x = x .. "> "
|
||||||
|
end
|
||||||
|
return x
|
||||||
|
end)
|
||||||
@@ -118,24 +118,23 @@ end
|
|||||||
local running
|
local running
|
||||||
|
|
||||||
-- Initiate a connection to last.fm servers
|
-- Initiate a connection to last.fm servers
|
||||||
|
async, await = degesch.async, coroutine.yield
|
||||||
local make_request = function (buffer, action)
|
local make_request = function (buffer, action)
|
||||||
if not user or not api_key then
|
if not user or not api_key then
|
||||||
report_error (buffer, "configuration is incomplete")
|
report_error (buffer, "configuration is incomplete")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if running then running.abort () end
|
if running then running:cancel () end
|
||||||
|
running = async.go (function ()
|
||||||
running = degesch.connect ("ws.audioscrobbler.com", 80, {
|
local c, host, e = await (async.dial ("ws.audioscrobbler.com", 80))
|
||||||
on_success = function (c, host)
|
if e then
|
||||||
on_connected (buffer, c, host, action)
|
|
||||||
running = nil
|
|
||||||
end,
|
|
||||||
on_error = function (e)
|
|
||||||
report_error (buffer, e)
|
report_error (buffer, e)
|
||||||
running = nil
|
else
|
||||||
|
on_connected (buffer, c, host, action)
|
||||||
end
|
end
|
||||||
})
|
running = nil
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|||||||
28
plugins/degesch/thin-cursor.lua
Normal file
28
plugins/degesch/thin-cursor.lua
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
--
|
||||||
|
-- thin-cursor.lua: set a thin cursor
|
||||||
|
--
|
||||||
|
-- Copyright (c) 2016, Přemysl Janouch <p.janouch@gmail.com>
|
||||||
|
--
|
||||||
|
-- Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
-- purpose with or without fee is hereby granted, provided that the above
|
||||||
|
-- copyright notice and this permission notice appear in all copies.
|
||||||
|
--
|
||||||
|
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
-- MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
||||||
|
-- SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
-- WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
||||||
|
-- OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||||
|
-- CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
--
|
||||||
|
-- If tmux doesn't work, add the following to its configuration:
|
||||||
|
-- set -as terminal-overrides ',*:Ss=\E[%p1%d q:Se=\E[2 q'
|
||||||
|
-- Change the "2" as per http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||||
|
|
||||||
|
local out = io.output ()
|
||||||
|
out:write ("\x1b[6 q"):flush ()
|
||||||
|
|
||||||
|
-- By registering a global variable, we get notified about plugin unload
|
||||||
|
x = setmetatable ({}, { __gc = function ()
|
||||||
|
out:write ("\x1b[2 q"):flush ()
|
||||||
|
end })
|
||||||
48
zyklonb.c
48
zyklonb.c
@@ -310,7 +310,7 @@ irc_get_boolean_from_config
|
|||||||
if (set_boolean_if_valid (value, str))
|
if (set_boolean_if_valid (value, str))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
FAIL ("invalid configuration value for `%s'", name);
|
return error_set (e, "invalid configuration value for `%s'", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@@ -324,12 +324,14 @@ irc_initialize_ca_set (SSL_CTX *ssl_ctx, const char *file, const char *path,
|
|||||||
if (SSL_CTX_load_verify_locations (ssl_ctx, file, path))
|
if (SSL_CTX_load_verify_locations (ssl_ctx, file, path))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
FAIL ("%s: %s", "failed to set locations for the CA certificate bundle",
|
return error_set (e, "%s: %s",
|
||||||
|
"failed to set locations for the CA certificate bundle",
|
||||||
ERR_reason_error_string (ERR_get_error ()));
|
ERR_reason_error_string (ERR_get_error ()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SSL_CTX_set_default_verify_paths (ssl_ctx))
|
if (!SSL_CTX_set_default_verify_paths (ssl_ctx))
|
||||||
FAIL ("%s: %s", "couldn't load the default CA certificate bundle",
|
return error_set (e, "%s: %s",
|
||||||
|
"couldn't load the default CA certificate bundle",
|
||||||
ERR_reason_error_string (ERR_get_error ()));
|
ERR_reason_error_string (ERR_get_error ()));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -442,7 +444,7 @@ error_ssl_1:
|
|||||||
// multiple errors on the OpenSSL stack.
|
// multiple errors on the OpenSSL stack.
|
||||||
if (!error_info)
|
if (!error_info)
|
||||||
error_info = ERR_error_string (ERR_get_error (), NULL);
|
error_info = ERR_error_string (ERR_get_error (), NULL);
|
||||||
FAIL ("%s: %s", "could not initialize TLS", error_info);
|
return error_set (e, "%s: %s", "could not initialize TLS", error_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@@ -455,7 +457,7 @@ irc_establish_connection (struct bot_context *ctx,
|
|||||||
|
|
||||||
int err = getaddrinfo (host, port, &gai_hints, &gai_result);
|
int err = getaddrinfo (host, port, &gai_hints, &gai_result);
|
||||||
if (err)
|
if (err)
|
||||||
FAIL ("%s: %s: %s", "connection failed",
|
return error_set (e, "%s: %s: %s", "connection failed",
|
||||||
"getaddrinfo", gai_strerror (err));
|
"getaddrinfo", gai_strerror (err));
|
||||||
|
|
||||||
int sockfd;
|
int sockfd;
|
||||||
@@ -497,7 +499,7 @@ irc_establish_connection (struct bot_context *ctx,
|
|||||||
freeaddrinfo (gai_result);
|
freeaddrinfo (gai_result);
|
||||||
|
|
||||||
if (!gai_iter)
|
if (!gai_iter)
|
||||||
FAIL ("connection failed");
|
return error_set (e, "connection failed");
|
||||||
|
|
||||||
ctx->irc_fd = sockfd;
|
ctx->irc_fd = sockfd;
|
||||||
return true;
|
return true;
|
||||||
@@ -1026,11 +1028,17 @@ plugin_launch (struct bot_context *ctx, const char *name, struct error **e)
|
|||||||
{
|
{
|
||||||
const char *plugin_dir = str_map_find (&ctx->config, "plugin_dir");
|
const char *plugin_dir = str_map_find (&ctx->config, "plugin_dir");
|
||||||
if (!plugin_dir)
|
if (!plugin_dir)
|
||||||
FAIL ("plugin directory not set");
|
{
|
||||||
|
error_set (e, "plugin directory not set");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int stdin_pipe[2];
|
int stdin_pipe[2];
|
||||||
if (pipe (stdin_pipe) == -1)
|
if (pipe (stdin_pipe) == -1)
|
||||||
FAIL ("%s: %s", "pipe", strerror (errno));
|
{
|
||||||
|
error_set (e, "%s: %s", "pipe", strerror (errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int stdout_pipe[2];
|
int stdout_pipe[2];
|
||||||
if (pipe (stdout_pipe) == -1)
|
if (pipe (stdout_pipe) == -1)
|
||||||
@@ -1117,9 +1125,9 @@ static bool
|
|||||||
plugin_load (struct bot_context *ctx, const char *name, struct error **e)
|
plugin_load (struct bot_context *ctx, const char *name, struct error **e)
|
||||||
{
|
{
|
||||||
if (!is_valid_plugin_name (name))
|
if (!is_valid_plugin_name (name))
|
||||||
FAIL ("invalid plugin name");
|
return error_set (e, "invalid plugin name");
|
||||||
if (str_map_find (&ctx->plugins_by_name, name))
|
if (str_map_find (&ctx->plugins_by_name, name))
|
||||||
FAIL ("the plugin has already been loaded");
|
return error_set (e, "the plugin has already been loaded");
|
||||||
|
|
||||||
struct plugin *plugin;
|
struct plugin *plugin;
|
||||||
if (!(plugin = plugin_launch (ctx, name, e)))
|
if (!(plugin = plugin_launch (ctx, name, e)))
|
||||||
@@ -1149,7 +1157,7 @@ plugin_unload (struct bot_context *ctx, const char *name, struct error **e)
|
|||||||
struct plugin *plugin = str_map_find (&ctx->plugins_by_name, name);
|
struct plugin *plugin = str_map_find (&ctx->plugins_by_name, name);
|
||||||
|
|
||||||
if (!plugin)
|
if (!plugin)
|
||||||
FAIL ("no such plugin is loaded");
|
return error_set (e, "no such plugin is loaded");
|
||||||
|
|
||||||
plugin_zombify (plugin);
|
plugin_zombify (plugin);
|
||||||
|
|
||||||
@@ -1168,7 +1176,7 @@ plugin_load_all_from_config (struct bot_context *ctx)
|
|||||||
struct str_vector plugins;
|
struct str_vector plugins;
|
||||||
str_vector_init (&plugins);
|
str_vector_init (&plugins);
|
||||||
|
|
||||||
cstr_split_ignore_empty (plugin_list, ',', &plugins);
|
cstr_split (plugin_list, ",", true, &plugins);
|
||||||
for (size_t i = 0; i < plugins.len; i++)
|
for (size_t i = 0; i < plugins.len; i++)
|
||||||
{
|
{
|
||||||
char *name = cstr_strip_in_place (plugins.vector[i], " ");
|
char *name = cstr_strip_in_place (plugins.vector[i], " ");
|
||||||
@@ -1208,7 +1216,7 @@ parse_bot_command (const char *s, const char *command, const char **following)
|
|||||||
static void
|
static void
|
||||||
split_bot_command_argument_list (const char *arguments, struct str_vector *out)
|
split_bot_command_argument_list (const char *arguments, struct str_vector *out)
|
||||||
{
|
{
|
||||||
cstr_split_ignore_empty (arguments, ',', out);
|
cstr_split (arguments, ",", true, out);
|
||||||
for (size_t i = 0; i < out->len; )
|
for (size_t i = 0; i < out->len; )
|
||||||
{
|
{
|
||||||
if (!*cstr_strip_in_place (out->vector[i], " \t"))
|
if (!*cstr_strip_in_place (out->vector[i], " \t"))
|
||||||
@@ -1778,7 +1786,7 @@ irc_connect (struct bot_context *ctx, struct error **e)
|
|||||||
// TODO: again, get rid of `struct error' in here. The question is: how
|
// TODO: again, get rid of `struct error' in here. The question is: how
|
||||||
// do we tell our caller that he should not try to reconnect?
|
// do we tell our caller that he should not try to reconnect?
|
||||||
if (!irc_host)
|
if (!irc_host)
|
||||||
FAIL ("no hostname specified in configuration");
|
return error_set (e, "no hostname specified in configuration");
|
||||||
|
|
||||||
bool use_tls;
|
bool use_tls;
|
||||||
if (!irc_get_boolean_from_config (ctx, "tls", &use_tls, e))
|
if (!irc_get_boolean_from_config (ctx, "tls", &use_tls, e))
|
||||||
@@ -1823,7 +1831,10 @@ parse_config (struct bot_context *ctx, struct error **e)
|
|||||||
const char *delay_str = str_map_find (&ctx->config, "reconnect_delay");
|
const char *delay_str = str_map_find (&ctx->config, "reconnect_delay");
|
||||||
hard_assert (delay_str != NULL); // We have a default value for this
|
hard_assert (delay_str != NULL); // We have a default value for this
|
||||||
if (!xstrtoul (&ctx->reconnect_delay, delay_str, 10))
|
if (!xstrtoul (&ctx->reconnect_delay, delay_str, 10))
|
||||||
FAIL ("invalid configuration value for `%s'", "reconnect_delay");
|
{
|
||||||
|
return error_set (e,
|
||||||
|
"invalid configuration value for `%s'", "reconnect_delay");
|
||||||
|
}
|
||||||
|
|
||||||
hard_assert (!ctx->admin_re);
|
hard_assert (!ctx->admin_re);
|
||||||
const char *admin = str_map_find (&ctx->config, "admin");
|
const char *admin = str_map_find (&ctx->config, "admin");
|
||||||
@@ -1999,12 +2010,7 @@ main (int argc, char *argv[])
|
|||||||
|
|
||||||
print_status (PROGRAM_NAME " " PROGRAM_VERSION " starting");
|
print_status (PROGRAM_NAME " " PROGRAM_VERSION " starting");
|
||||||
setup_signal_handlers ();
|
setup_signal_handlers ();
|
||||||
|
init_openssl ();
|
||||||
SSL_library_init ();
|
|
||||||
atexit (EVP_cleanup);
|
|
||||||
SSL_load_error_strings ();
|
|
||||||
// XXX: ERR_load_BIO_strings()? Anything else?
|
|
||||||
atexit (ERR_free_strings);
|
|
||||||
|
|
||||||
struct bot_context ctx;
|
struct bot_context ctx;
|
||||||
bot_context_init (&ctx);
|
bot_context_init (&ctx);
|
||||||
|
|||||||
Reference in New Issue
Block a user