63 Commits

Author SHA1 Message Date
4179a9bd49 Update NEWS, bump version 2018-10-21 05:44:39 +02:00
aa4e86c2a0 degesch: add a comment about ENOTCONN 2018-10-21 05:40:24 +02:00
5bbe9ceef8 Update NEWS 2018-10-21 05:40:24 +02:00
f80226620c kike: fix wildcard handling in WHOIS 2018-10-21 05:40:24 +02:00
2fccfb10f7 kike: allow STATS with no parameters
We were in plain conflict with RFC 2812 for no apparent reason.
2018-10-21 05:40:16 +02:00
b9eddabedd kike: explicit conversion from pointer to boolean
In practice the values in the map may only be 1 or 0, so it doesn't
matter, but in C it is better to be safe than sorry.
2018-08-01 09:22:59 +02:00
50ed74a740 kike: break out properly on errors in MODE processing
We used to only abort the inner loop, which was insufficient.
2018-08-01 09:21:37 +02:00
3ca08badc2 kike: reset user modes while processing USER
Since the processing always succeeds and registration cannot be undone,
this doesn't seem to fix any real issue.
2018-08-01 09:17:45 +02:00
b0f5b8c10d kike: do nothing on equivalent renicks 2018-08-01 09:17:12 +02:00
d87d533078 kike: code cleanups 2018-08-01 09:16:45 +02:00
3c47e5b354 kike: fix grammar in hostname validation
This has an entry in RFC 2812 errata, although it's held for document
update.  We can afford the strictness.
2018-08-01 09:16:45 +02:00
54d3406175 kike: fix grammar in config item description 2018-08-01 09:16:44 +02:00
f79dd027e9 kike: add a comment about identifier encoding 2018-08-01 09:16:44 +02:00
fa78831cbd Update NEWS, bump version 2018-06-22 00:59:41 +02:00
94b0ec80cf fancy-prompt.lua: workaround a Readline UTF-8 bug 2018-06-22 00:55:17 +02:00
300f9a9708 Bump liberty 2018-06-22 00:03:21 +02:00
b1a89f313a degesch: add static analysis for the logger
Caught two more occurences than I was able to find by just scanning
the source, so the effort wasn't in vain.
2018-06-21 23:46:03 +02:00
fab5115cd0 Remove .travis.yml
We don't depend on any proprietary services no longer.  I'll have to
make my own replacements with blackjack and hookers.  Until then,
the file stays in the commit log as an example.
2018-06-21 23:46:03 +02:00
d0cb3c1ac6 Update README 2018-06-21 23:46:03 +02:00
a0e9ede3e3 Relicense to 0BSD, update mail address
I've come to the conclusion that copyright mostly just stands in the way
of software development.  In my jurisdiction I cannot give up my own
copyright and 0BSD seems to be the closest thing to public domain.

The updated mail address, also used in my author/committer lines,
is shorter and looks nicer.  People rarely interact anyway.
2018-06-21 23:46:03 +02:00
787569e653 Update submodule URL for liberty 2018-06-21 23:45:55 +02:00
5d353b0721 Prepare NEWS for the next release 2018-06-21 23:26:16 +02:00
006d34eeae degesch: fix some log messages
We could use some static analysis for these.
2018-06-21 23:25:45 +02:00
19400ee8b7 kike: disable TLS session reuse 2018-01-09 06:25:16 +01:00
674ffb2f6d kike: handle accept() errors better
Might prevent some denial of service attacks.
2018-01-09 05:48:36 +01:00
6c30452b28 kike: thorough review, no functional changes 2018-01-09 05:47:37 +01:00
670e1c5770 kike: introduce cstr_set() 2018-01-08 23:16:14 +01:00
4586b0e1e4 degesch: introduce cstr_set() 2018-01-08 22:19:28 +01:00
b4507b56af degesch: thorough review, no functional changes 2018-01-08 22:19:23 +01:00
bf6d507bb2 degesch: fix IPv6:port in irc_split_host_port() 2018-01-08 22:19:02 +01:00
099a49e6d5 degesch: fix a minor bug in buffer_merge()
The pointer to the last item in the linked list wasn't always fixed,
although nothing really touched it afterwards.
2018-01-08 22:17:02 +01:00
4627ee82dd degesch: simplify a popular assertion 2018-01-08 22:16:57 +01:00
682f90e989 degesch: simplify the configuration dumper 2018-01-08 22:16:52 +01:00
277af83100 degesch: show an error message on log write failure
Running out of space and I/O errors seem like the most likely causes.
2018-01-08 22:16:36 +01:00
a5a0078def degesch: make buffer index computation easier to follow 2018-01-08 22:16:10 +01:00
868e34d15c degesch: fix a Lua error message 2018-01-08 22:16:06 +01:00
dc47b16034 Bump liberty, avoid fall-through warnings 2018-01-07 17:37:19 +01:00
d0f19f8be3 Update README
"Edgy" is actually a fitting word.  And we've lost OBS!
2017-12-06 23:49:18 +01:00
ddb45a1cc4 Update README 2017-12-02 13:06:39 +01:00
3974919741 Update README
So be it, SJWHub, at least I have a reason to move.
2017-12-02 11:06:48 +01:00
36be830bfc degesch: better shift state encoding handling
I don't know, probably didn't matter.
2017-07-07 20:55:25 +02:00
f7dce5e861 slack.lua: add a feature to undo emoji 2017-07-03 06:45:46 +02:00
757047bd20 CMakeLists.txt: fix variable name 2017-07-03 06:44:15 +02:00
a2611cdc3c Rework constructors/destructors 2017-06-22 22:56:24 +02:00
68bc297809 Bump liberty 2017-06-22 22:39:39 +02:00
933760c2a2 kike: fix two memory leaks 2017-06-22 20:36:21 +02:00
156ea32a90 slack.lua: support @here and @channel 2017-05-18 10:44:36 +02:00
f744681b17 slack.lua: improve input hook matching 2017-05-17 15:05:51 +02:00
bdc6334aec slack.lua: more unfucking
And now it's already fairly usable.
2017-05-17 00:32:54 +02:00
96864517c6 Fix licensing notice in README 2017-05-14 22:13:00 +02:00
0bdcd4aa8b fancy-prompt.lua: remove unnecessary local variable 2017-05-13 20:04:21 +02:00
b18a8048c1 degesch: add a slack plugin
Slack's IRC gateway is crap but it doesn't need to be *such* crap.
2017-05-13 20:04:21 +02:00
c3d62b8799 Avoid the "poller_fd::closed" feature
Reliability enhancement for Linux.

This feature was created for ponymap, however we don't care about an
extra syscall in most places.  Doing it right even saves lines.
2017-05-06 21:35:44 +02:00
ec842db0fb Update copyright years 2017-04-22 19:41:27 +02:00
0981df485a degesch: simplify quitting
- send a QUIT on C-c, too
 - shut down the connection on /disconnect, too

Connection management is one of the few fucked up parts
that remain in that state for historical reasons.
2017-04-20 20:55:49 +02:00
9f0c18cc41 degesch: fix confusing message
It seemed like we were connecting albeit we were connected already.
2017-04-20 20:26:04 +02:00
1313a712df degesch: make a second /disconnect always succeed 2017-04-20 20:25:21 +02:00
f45f9ab873 Travis CI: brevify notifications 2017-02-03 23:17:15 +01:00
9e5725662f Bump liberty 2017-01-23 23:50:27 +01:00
0785a6f417 degesch: Lua is no longer experimental
But rather essential to me.
2017-01-23 23:41:14 +01:00
cb9957cd64 Travis CI: try adding the PPA back 2016-12-30 14:47:50 +01:00
40bb2497f7 Travis CI: try removing a dead PPA 2016-12-30 14:42:06 +01:00
d7960b463f Fix LibreSSL compatibility 2016-12-30 08:51:49 +01:00
23 changed files with 1007 additions and 1036 deletions

2
.gitmodules vendored
View File

@@ -1,3 +1,3 @@
[submodule "liberty"] [submodule "liberty"]
path = liberty path = liberty
url = git://github.com/pjanouch/liberty.git url = https://git.janouch.name/p/liberty.git

View File

@@ -1,44 +0,0 @@
sudo: required
dist: trusty
language: c
notifications:
irc:
channels: "irc.janouch.name#dev"
use_notice: true
skip_join: true
env:
global:
- secure: "ck6keK5tTbVCN7VGyKglS890hjovUNt2zyOydiyFtQDciaB/rvEwkKy4anMCEdZHFpGAPE9iBmNYaGUsD1Y+KifhhImVMbuThe2D8MLv5crSLRheYPbbmhO8MWPAxmQnuQhpwsUKZlHvUfX8nh+d0juNdqXklvhVml78Gi99QFw="
matrix:
- readline=ON libedit=OFF
- readline=OFF libedit=ON
addons:
coverity_scan:
project:
name: "pjanouch/uirc3"
description: "Experimental IRC client, daemon and bot"
notification_email: p.janouch@gmail.com
build_command_prepend: "cmake .. -DCMAKE_BUILD_TYPE=Release"
build_command: "make"
branch_pattern: coverity_scan
compiler:
- clang
- gcc
before_install:
# We need this PPA for a recent version of libedit
- sudo add-apt-repository ppa:ondrej/php5-5.6 -y
# We need this PPA for Lua 5.3
- sudo add-apt-repository ppa:vbernat/haproxy-1.6 -y
- sudo apt-get update -qq
install:
- sudo apt-get install -y libncursesw5-dev libreadline-dev libedit-dev
liblua5.3-dev libffi-dev help2man expect
before_script:
- mkdir build
- cd build
script:
- cmake .. -DCMAKE_INSTALL_PREFIX=/usr
-DWANT_READLINE=$readline -DWANT_LIBEDIT=$libedit
- make all test
- cpack -G DEB
- ../test

View File

@@ -6,14 +6,14 @@ option (WANT_READLINE "Use GNU Readline for the UI (better)" ON)
option (WANT_LIBEDIT "Use BSD libedit for the UI" OFF) option (WANT_LIBEDIT "Use BSD libedit for the UI" OFF)
# Moar warnings # Moar warnings
if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUC) if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUCC)
# -Wunused-function is pretty annoying here, as everything is static # -Wunused-function is pretty annoying here, as everything is static
set (CMAKE_C_FLAGS set (wdisabled "-Wno-unused-function")
"${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Wno-unused-function") set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra ${wdisabled}")
endif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUC) endif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUCC)
# Version # Version
set (project_version "0.9.5") set (project_version "0.9.7")
# 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.
@@ -84,7 +84,7 @@ link_directories (${libffi_LIBRARY_DIRS})
# FIXME: other Lua versions may be acceptable, don't know yet # FIXME: other Lua versions may be acceptable, don't know yet
pkg_search_module (lua lua53 lua5.3 lua-5.3 lua>=5.3) pkg_search_module (lua lua53 lua5.3 lua-5.3 lua>=5.3)
option (WITH_LUA "Enable experimental support for Lua plugins" ${lua_FOUND}) option (WITH_LUA "Enable support for Lua plugins" ${lua_FOUND})
if (WITH_LUA) if (WITH_LUA)
if (NOT lua_FOUND) if (NOT lua_FOUND)
@@ -180,6 +180,8 @@ endfunction (make_tests_for)
include (CTest) include (CTest)
if (BUILD_TESTING) if (BUILD_TESTING)
make_tests_for (degesch) make_tests_for (degesch)
add_test (NAME custom-static-analysis
COMMAND ${PROJECT_SOURCE_DIR}/test-static)
endif (BUILD_TESTING) endif (BUILD_TESTING)
# Various clang-based diagnostics, loads of fake positives and spam # Various clang-based diagnostics, loads of fake positives and spam
@@ -232,7 +234,7 @@ endforeach (page)
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Experimental IRC client, daemon and bot") set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Experimental IRC client, daemon and bot")
set (CPACK_PACKAGE_VERSION "${project_version_safe}") set (CPACK_PACKAGE_VERSION "${project_version_safe}")
set (CPACK_PACKAGE_VENDOR "Premysl Janouch") set (CPACK_PACKAGE_VENDOR "Premysl Janouch")
set (CPACK_PACKAGE_CONTACT "Přemysl Janouch <p.janouch@gmail.com>") set (CPACK_PACKAGE_CONTACT "Přemysl Janouch <p@janouch.name>")
set (CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") set (CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
set (CPACK_GENERATOR "TGZ;ZIP") set (CPACK_GENERATOR "TGZ;ZIP")

View File

@@ -1,8 +1,7 @@
Copyright (c) 2014 - 2015, Přemysl Janouch <p.janouch@gmail.com> Copyright (c) 2014 - 2018, Přemysl Janouch <p@janouch.name>
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted.
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

41
NEWS
View File

@@ -1,3 +1,44 @@
0.9.7 (2018-10-21) "Business as Usual"
* kike: fix wildcard handling in WHOIS
* kike: properly handle STATS without parametetrs
* kike: abort earlier when an invalid mode character is detected while
processing channel MODE messages
* kike: do not send NICK notifications when the nickname doesn't really change
* kike: fix hostname string verification (only used for "server_name")
0.9.6 (2018-06-22) "I've Been Sitting Here All This Time"
* Code has been relicensed to 0BSD and moved to a private git hosting
* Fix LibreSSL compatibility
* degesch: a second /disconnect cuts the connection by force
* degesch: send a QUIT message to the IRC server on Ctrl-C
* degesch: add a Slack plugin (even though the gateway's now defunct)
* degesch: show an error message on log write failure
* degesch: fix parsing of literal IPv6 addresses with port numbers
* degesch: fix some error messages
* degesch: workaround a Readline bug in the fancy-prompt.lua plugin
* kike: fix two memory leaks
* kike: improve error handling for incoming connections
* kike: disable TLS session reuse
0.9.5 (2016-12-30) "It's Time" 0.9.5 (2016-12-30) "It's Time"
* Better support for the KILL command * Better support for the KILL command

View File

@@ -2,17 +2,17 @@ uirc3
===== =====
:compact-option: :compact-option:
The unethical IRC trinity. This project consists of an experimental IRC client, The [line-through]#unethical# edgy IRC trinity. This project consists of an
daemon, and bot. It's all you're ever going to need for chatting, as long as experimental IRC client, daemon, and bot. It's all you're ever going to need
you can make do with minimalist software. for chatting, as long as you can make do with minimalist software.
All of them have these potentially interesting properties: All of them have these potentially interesting properties:
- full IPv6 support - IPv6 support
- TLS support, including client certificates - TLS support, including client certificates
- lean on dependencies (with the exception of 'degesch') - lean on dependencies (with the exception of 'degesch')
- compact and arguably easy to hack on - compact and arguably easy to hack on
- permissive license - very permissive license
degesch degesch
------- -------
@@ -52,6 +52,9 @@ Not supported:
be used to implement this feature if needed be used to implement this feature if needed
- limits of almost any kind, just connections and mode `+l` - limits of almost any kind, just connections and mode `+l`
This program has been https://git.janouch.name/p/haven/src/branch/master/hid[
ported to Go], and development continues over there.
ZyklonB ZyklonB
------- -------
The IRC bot. It builds upon the concept of my other VitaminA IRC bot. The main The IRC bot. It builds upon the concept of my other VitaminA IRC bot. The main
@@ -68,11 +71,7 @@ support (even though socksify can add that easily to any program).
Packages Packages
-------- --------
Regular releases are sporadic. git master should be stable enough. You can get Regular releases are sporadic. git master should be stable enough. You can get
a package with the latest development version from Archlinux's AUR, or from a package with the latest development version from Archlinux's AUR.
openSUSE Build Service for the rest of mainstream distributions. Consult the
list of repositories and their respective links at:
https://build.opensuse.org/project/repositories/home:pjanouch:git
Building Building
-------- --------
@@ -81,7 +80,7 @@ Runtime dependencies: openssl +
Additionally for degesch: curses, libffi, lua >= 5.3 (optional), Additionally for degesch: curses, libffi, lua >= 5.3 (optional),
readline >= 6.0 or libedit >= 2013-07-12 readline >= 6.0 or libedit >= 2013-07-12
$ git clone --recursive https://github.com/pjanouch/uirc3.git $ git clone --recursive https://git.janouch.name/p/uirc3.git
$ mkdir uirc3/build $ mkdir uirc3/build
$ cd uirc3/build $ cd uirc3/build
$ cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug \ $ cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Debug \
@@ -175,24 +174,16 @@ 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 https://git.janouch.name/p/uirc3 to report any bugs, request features,
requests. If you want to discuss this project, or maybe just hang out with or submit pull requests. `git send-email` is tolerated. If you want to discuss
the developer, feel free to join me at irc://irc.janouch.name, channel #dev. the project, feel free to join me at ircs://irc.janouch.name, channel #dev.
Disclaimer Bitcoin donations are accepted at: 12r5uEWEgcHC46xd64tt3hHt9EUvYYDHe9
----------
I am not an antisemitist, I'm just being an offensive asshole with the naming.
And no, I'm not going to change the names.
License License
------- -------
'uirc3' is written by Přemysl Janouch <p.janouch@gmail.com>. This software is released under the terms of the 0BSD license, the text of which
is included within the package along with the list of authors.
You may use the software under the terms of the ISC license, the text of which Note that 'degesch' technically becomes GPL-licensed when you statically link it
is included within the package, or, at your option, you may relicense the work against GNU Readline, but that is not a concern of this source package.
under the MIT or the Modified BSD License, as listed at the following site:
http://www.gnu.org/licenses/license-list.html
Note that 'degesch' technically becomes GPL-licensed when you compile it against
GNU Readline, but that is not a concern of this source package.

View File

@@ -1,11 +1,10 @@
/* /*
* common.c: common functionality * common.c: common functionality
* *
* Copyright (c) 2014 - 2015, Přemysl Janouch <p.janouch@gmail.com> * Copyright (c) 2014 - 2015, Přemysl Janouch <p@janouch.name>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted.
* copyright notice and this permission notice appear in all copies.
* *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
@@ -37,7 +36,7 @@
static void static void
init_openssl (void) init_openssl (void)
{ {
#if OPENSSL_VERSION_NUMBER < 0x10100000L #if OPENSSL_VERSION_NUMBER < 0x10100000L || LIBRESSL_VERSION_NUMBER
SSL_library_init (); SSL_library_init ();
// XXX: this list is probably not complete // XXX: this list is probably not complete
atexit (EVP_cleanup); atexit (EVP_cleanup);
@@ -51,8 +50,15 @@ init_openssl (void)
// --- To be moved to liberty -------------------------------------------------- // --- To be moved to liberty --------------------------------------------------
static void
cstr_set (char **s, char *new)
{
free (*s);
*s = new;
}
static ssize_t static ssize_t
str_vector_find (const struct str_vector *v, const char *s) strv_find (const struct strv *v, const char *s)
{ {
for (size_t i = 0; i < v->len; i++) for (size_t i = 0; i < v->len; i++)
if (!strcmp (v->vector[i], s)) if (!strcmp (v->vector[i], s))
@@ -81,11 +87,10 @@ unixtime_msec (long *msec)
static char * static char *
resolve_relative_runtime_unique_filename (const char *filename) resolve_relative_runtime_unique_filename (const char *filename)
{ {
struct str path;
str_init (&path);
const char *runtime_dir = getenv ("XDG_RUNTIME_DIR"); const char *runtime_dir = getenv ("XDG_RUNTIME_DIR");
const char *tmpdir = getenv ("TMPDIR"); const char *tmpdir = getenv ("TMPDIR");
struct str path = str_make ();
if (runtime_dir && *runtime_dir == '/') if (runtime_dir && *runtime_dir == '/')
str_append (&path, runtime_dir); str_append (&path, runtime_dir);
else if (tmpdir && *tmpdir == '/') else if (tmpdir && *tmpdir == '/')
@@ -702,7 +707,7 @@ socks_try_fill_read_buffer (struct socks_connector *self, size_t n)
return true; return true;
ssize_t received; ssize_t received;
str_ensure_space (&self->read_buffer, remains); str_reserve (&self->read_buffer, remains);
do do
received = recv (self->socket_fd, received = recv (self->socket_fd,
self->read_buffer.str + self->read_buffer.len, remains, 0); self->read_buffer.str + self->read_buffer.len, remains, 0);
@@ -726,8 +731,8 @@ socks_call_on_data (struct socks_connector *self)
if (self->read_buffer.len < to_consume) if (self->read_buffer.len < to_consume)
return true; return true;
struct msg_unpacker unpacker; struct msg_unpacker unpacker =
msg_unpacker_init (&unpacker, self->read_buffer.str, self->read_buffer.len); msg_unpacker_make (self->read_buffer.str, self->read_buffer.len);
bool result = self->on_data (self, &unpacker); bool result = self->on_data (self, &unpacker);
str_remove_slice (&self->read_buffer, 0, to_consume); str_remove_slice (&self->read_buffer, 0, to_consume);
return result; return result;
@@ -792,16 +797,16 @@ socks_connector_init (struct socks_connector *self, struct poller *poller)
{ {
memset (self, 0, sizeof *self); memset (self, 0, sizeof *self);
poller_fd_init (&self->socket_event, poller, (self->socket_fd = -1)); self->socket_event = poller_fd_make (poller, (self->socket_fd = -1));
self->socket_event.dispatcher = (poller_fd_fn) socks_connector_on_ready; self->socket_event.dispatcher = (poller_fd_fn) socks_connector_on_ready;
self->socket_event.user_data = self; self->socket_event.user_data = self;
poller_timer_init (&self->timeout, poller); self->timeout = poller_timer_make (poller);
self->timeout.dispatcher = (poller_timer_fn) socks_connector_on_timeout; self->timeout.dispatcher = (poller_timer_fn) socks_connector_on_timeout;
self->timeout.user_data = self; self->timeout.user_data = self;
str_init (&self->read_buffer); self->read_buffer = str_make ();
str_init (&self->write_buffer); self->write_buffer = str_make ();
} }
static void static void
@@ -902,8 +907,8 @@ static struct ctcp_chunk *
ctcp_chunk_new (void) ctcp_chunk_new (void)
{ {
struct ctcp_chunk *self = xcalloc (1, sizeof *self); struct ctcp_chunk *self = xcalloc (1, sizeof *self);
str_init (&self->tag); self->tag = str_make ();
str_init (&self->text); self->text = str_make ();
return self; return self;
} }
@@ -992,8 +997,7 @@ ctcp_parse_tagged (const char *chunk, size_t len, struct ctcp_chunk *output)
static struct ctcp_chunk * static struct ctcp_chunk *
ctcp_parse (const char *message) ctcp_parse (const char *message)
{ {
struct str m; struct str m = str_make ();
str_init (&m);
ctcp_low_level_decode (message, &m); ctcp_low_level_decode (message, &m);
struct ctcp_chunk *result = NULL, *result_tail = NULL; struct ctcp_chunk *result = NULL, *result_tail = NULL;

1054
degesch.c

File diff suppressed because it is too large Load Diff

468
kike.c

File diff suppressed because it is too large Load Diff

Submodule liberty updated: f53b717f3b...bb30c7d86e

View File

@@ -1,11 +1,10 @@
-- --
-- auto-rejoin.lua: join back automatically when someone kicks you -- auto-rejoin.lua: join back automatically when someone kicks you
-- --
-- Copyright (c) 2016, Přemysl Janouch <p.janouch@gmail.com> -- Copyright (c) 2016, Přemysl Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted, provided that the above -- purpose with or without fee is hereby granted.
-- copyright notice and this permission notice appear in all copies.
-- --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

View File

@@ -1,11 +1,10 @@
-- --
-- censor.lua: black out certain users' messages -- censor.lua: black out certain users' messages
-- --
-- Copyright (c) 2016, Přemysl Janouch <p.janouch@gmail.com> -- Copyright (c) 2016, Přemysl Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted, provided that the above -- purpose with or without fee is hereby granted.
-- copyright notice and this permission notice appear in all copies.
-- --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

View File

@@ -1,11 +1,10 @@
-- --
-- fancy-prompt.lua: the fancy multiline prompt you probably want -- fancy-prompt.lua: the fancy multiline prompt you probably want
-- --
-- Copyright (c) 2016, Přemysl Janouch <p.janouch@gmail.com> -- Copyright (c) 2016, Přemysl Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted, provided that the above -- purpose with or without fee is hereby granted.
-- copyright notice and this permission notice appear in all copies.
-- --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
@@ -29,7 +28,7 @@
-- background but to really fix that mode, we'd have to fully reimplement it -- 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. -- since its alternative prompt very often gets overriden by accident anyway.
local prompt = degesch.hook_prompt (function (hook) degesch.hook_prompt (function (hook)
local current = degesch.current_buffer local current = degesch.current_buffer
local chan = current.channel local chan = current.channel
local s = current.server local s = current.server
@@ -65,6 +64,10 @@ local prompt = degesch.hook_prompt (function (hook)
local lines, cols = degesch.get_screen_size () local lines, cols = degesch.get_screen_size ()
x = x .. " " .. active .. string.rep (" ", cols) x = x .. " " .. active .. string.rep (" ", cols)
-- Readline seems to be broken and completely corrupts the prompt
-- (tested on 7.0.003 Archlinux, 7.0-5 Debian buster)
x = x:gsub("[\128-\255]", "?")
-- Cut off extra characters and apply formatting, including the hack. -- Cut off extra characters and apply formatting, including the hack.
-- Note that this doesn't count with full-width or zero-width characters. -- Note that this doesn't count with full-width or zero-width characters.
local overflow = utf8.offset (x, cols - 1) local overflow = utf8.offset (x, cols - 1)

View File

@@ -5,11 +5,10 @@
-- --
-- I call this style closure-oriented programming -- I call this style closure-oriented programming
-- --
-- Copyright (c) 2016, Přemysl Janouch <p.janouch@gmail.com> -- Copyright (c) 2016, Přemysl Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted, provided that the above -- purpose with or without fee is hereby granted.
-- copyright notice and this permission notice appear in all copies.
-- --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

View File

@@ -1,11 +1,10 @@
-- --
-- ping-timeout.lua: ping timeout readability enhancement plugin -- ping-timeout.lua: ping timeout readability enhancement plugin
-- --
-- Copyright (c) 2015 - 2016, Přemysl Janouch <p.janouch@gmail.com> -- Copyright (c) 2015 - 2016, Přemysl Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted, provided that the above -- purpose with or without fee is hereby granted.
-- copyright notice and this permission notice appear in all copies.
-- --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

147
plugins/degesch/slack.lua Normal file
View File

@@ -0,0 +1,147 @@
--
-- slack.lua: try to fix up UX when using the Slack IRC gateway
--
-- Copyright (c) 2017, Přemysl Janouch <p@janouch.name>
--
-- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted.
--
-- 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 servers = {}
local read_servers = function (v)
servers = {}
for name in v:lower ():gmatch "[^,]+" do
servers[name] = true
end
end
-- This is a reverse list of Slack's automatic emoji, noseless forms
local unemojify, emoji, emoji_default = false, {}, {
heart = "<3",
broken_heart = "</3",
sunglasses = "8)",
anguished = "D:",
cry = ":'(",
monkey_face = ":o)",
kiss = ":*",
smiley = "=)",
smile = ":D",
wink = ";)",
laughing = ":>",
neutral_face = ":|",
open_mouth = ":o",
angry = ">:(",
slightly_smiling_face = ":)",
disappointed = ":(",
confused = ":/",
stuck_out_tongue = ":p",
stuck_out_tongue_winking_eye = ";p",
}
local load_emoji = function (extra)
emoji = {}
for k, v in pairs (emoji_default) do emoji[k] = v end
for k, v in extra:gmatch "([^,]+) ([^,]+)" do emoji[k] = v end
end
degesch.setup_config {
servers = {
type = "string_array",
default = "\"\"",
comment = "list of server names that are Slack IRC gateways",
on_change = read_servers
},
unemojify = {
type = "boolean",
default = "true",
comment = "convert emoji to normal ASCII emoticons",
on_change = function (v) unemojify = v end
},
extra_emoji = {
type = "string_array",
default = "\"grinning :)),joy :'),innocent o:),persevere >_<\"",
comment = "overrides or extra emoji for unemojify",
on_change = function (v) load_emoji (v) end
}
}
-- We can handle external messages about what we've supposedly sent just fine,
-- so let's get rid of that "[username] some message sent from the web UI" crap
degesch.hook_irc (function (hook, server, line)
local msg, us = degesch.parse (line), server.user
if not servers[server.name] or msg.command ~= "PRIVMSG" or not us
or msg.params[1]:lower () ~= us.nickname:lower () then return line end
-- Taking a shortcut to avoid lengthy message reassembly
local quoted_nick = us.nickname:gsub ("[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0")
local text = line:match ("^.- PRIVMSG .- :%[" .. quoted_nick .. "%] (.*)$")
if not text then return line end
return ":" .. us.nickname .. "!" .. server.irc_user_host .. " PRIVMSG "
.. msg.prefix:match "^[^!@]*" .. " :" .. text
end)
-- Unfuck emoji and :nick!nick@irc.tinyspeck.com MODE #channel +v nick : active
degesch.hook_irc (function (hook, server, line)
if not servers[server.name] then return line end
if unemojify then
local start, text = line:match ("^(.- PRIVMSG .-:)(.*)$")
if start then return start .. text:gsub (":([a-z_]+):", function (name)
if emoji[name] then return emoji[name] end
return ":" .. name .. ":"
end) end
end
return line:gsub ("^(:%S+ MODE .+) : .*", "%1")
end)
-- The gateway simply ignores the NAMES command altogether
degesch.hook_input (function (hook, buffer, input)
if not buffer.channel or not servers[buffer.server.name]
or not input:match "^/names%s*$" then return input end
local users = buffer.channel.users
table.sort (users, function (a, b)
if a.prefixes > b.prefixes then return true end
if a.prefixes < b.prefixes then return false end
return a.user.nickname < b.user.nickname
end)
local names = "Users on " .. buffer.channel.name .. ":"
for i, chan_user in ipairs (users) do
names = names .. " " .. chan_user.prefixes .. chan_user.user.nickname
end
buffer:log (names)
end)
degesch.hook_completion (function (hook, data, word)
local chan = degesch.current_buffer.channel
local server = degesch.current_buffer.server
if not chan or not servers[server.name] then return end
-- In /commands there is typically no desire at all to add the at sign
if data.location == 1 and data.words[1]:match "^/" then return end
-- Handle both when the at sign is already there and when it is not
local needle = word:gsub ("^@", ""):lower ()
local t = {}
local try = function (name)
if data.location == 0 then name = name .. ":" end
if name:sub (1, #needle):lower () == needle then
table.insert (t, "@" .. name)
end
end
for _, chan_user in ipairs (chan.users) do
try (chan_user.user.nickname)
end
for _, special in ipairs { "channel", "here" } do
try (special)
end
return t
end)

View File

@@ -1,11 +1,10 @@
-- --
-- thin-cursor.lua: set a thin cursor -- thin-cursor.lua: set a thin cursor
-- --
-- Copyright (c) 2016, Přemysl Janouch <p.janouch@gmail.com> -- Copyright (c) 2016, Přemysl Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted, provided that the above -- purpose with or without fee is hereby granted.
-- copyright notice and this permission notice appear in all copies.
-- --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

View File

@@ -1,11 +1,10 @@
-- --
-- utm-filter.lua: filter out Google Analytics bullshit from URLs -- utm-filter.lua: filter out Google Analytics bullshit from URLs
-- --
-- Copyright (c) 2015, Přemysl Janouch <p.janouch@gmail.com> -- Copyright (c) 2015, Přemysl Janouch <p@janouch.name>
-- --
-- Permission to use, copy, modify, and/or distribute this software for any -- Permission to use, copy, modify, and/or distribute this software for any
-- purpose with or without fee is hereby granted, provided that the above -- purpose with or without fee is hereby granted.
-- copyright notice and this permission notice appear in all copies.
-- --
-- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -- WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

View File

@@ -2,7 +2,7 @@
# #
# ZyklonB factoids plugin # ZyklonB factoids plugin
# #
# Copyright 2016 Přemysl Janouch <p.janouch@gmail.com> # Copyright 2016 Přemysl Janouch <p@janouch.name>
# See the file LICENSE for licensing information. # See the file LICENSE for licensing information.
# #

View File

@@ -2,7 +2,7 @@
-- --
-- ZyklonB seen plugin -- ZyklonB seen plugin
-- --
-- Copyright 2016 Přemysl Janouch <p.janouch@gmail.com> -- Copyright 2016 Přemysl Janouch <p@janouch.name>
-- See the file LICENSE for licensing information. -- See the file LICENSE for licensing information.
-- --

View File

@@ -2,7 +2,7 @@
# #
# ZyklonB YouTube plugin, displaying info about YouTube links # ZyklonB YouTube plugin, displaying info about YouTube links
# #
# Copyright 2014 - 2015, Přemysl Janouch <p.janouch@gmail.com> # Copyright 2014 - 2015, Přemysl Janouch <p@janouch.name>
# See the file LICENSE for licensing information. # See the file LICENSE for licensing information.
# #

14
test-static Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/sh
# We don't use printf's percent notation with our custom logging mechanism,
# so the compiler cannot check it for us like it usually does
perl -n0777 - "$(dirname "$0")"/degesch.c <<-'END'
while (/\blog_[^ ]+\s*\([^"()]*"[^"]*%[^%][^"]*"/gm) {
my ($p, $m) = ($`, $&);
printf "$ARGV:%d: suspicious log format string: %s...\n",
(1 + $p =~ tr/\n//), ($m =~ s/\s+/ /rg);
$status = 1;
}
END {
exit $status;
}
END

116
zyklonb.c
View File

@@ -1,11 +1,10 @@
/* /*
* zyklonb.c: the experimental IRC bot * zyklonb.c: the experimental IRC bot
* *
* Copyright (c) 2014 - 2016, Přemysl Janouch <p.janouch@gmail.com> * Copyright (c) 2014 - 2016, Přemysl Janouch <p@janouch.name>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted.
* copyright notice and this permission notice appear in all copies.
* *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
@@ -83,22 +82,22 @@ struct plugin
struct str write_buffer; ///< Output yet to be sent out struct str write_buffer; ///< Output yet to be sent out
}; };
static void static struct plugin *
plugin_init (struct plugin *self) plugin_new (void)
{ {
memset (self, 0, sizeof *self); struct plugin *self = xcalloc (1, sizeof *self);
self->pid = -1; self->pid = -1;
str_init (&self->queued_output); self->queued_output = str_make ();
self->read_fd = -1; self->read_fd = -1;
str_init (&self->read_buffer); self->read_buffer = str_make ();
self->write_fd = -1; self->write_fd = -1;
str_init (&self->write_buffer); self->write_buffer = str_make ();
return self;
} }
static void static void
plugin_free (struct plugin *self) plugin_destroy (struct plugin *self)
{ {
soft_assert (self->pid == -1); soft_assert (self->pid == -1);
free (self->name); free (self->name);
@@ -113,6 +112,8 @@ plugin_free (struct plugin *self)
if (!self->initialized) if (!self->initialized)
str_free (&self->queued_output); str_free (&self->queued_output);
free (self);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -152,34 +153,33 @@ static void on_irc_reconnect_timeout (void *user_data);
static void static void
bot_context_init (struct bot_context *self) bot_context_init (struct bot_context *self)
{ {
str_map_init (&self->config); self->config = str_map_make (free);
self->config.free = free;
simple_config_load_defaults (&self->config, g_config_table); simple_config_load_defaults (&self->config, g_config_table);
self->admin_re = NULL; self->admin_re = NULL;
self->irc_fd = -1; self->irc_fd = -1;
str_init (&self->read_buffer); self->read_buffer = str_make ();
self->irc_registered = false; self->irc_registered = false;
self->ssl = NULL; self->ssl = NULL;
self->ssl_ctx = NULL; self->ssl_ctx = NULL;
self->plugins = NULL; self->plugins = NULL;
str_map_init (&self->plugins_by_name); self->plugins_by_name = str_map_make (NULL);
poller_init (&self->poller); poller_init (&self->poller);
self->quitting = false; self->quitting = false;
self->polling = false; self->polling = false;
poller_timer_init (&self->timeout_tmr, &self->poller); self->timeout_tmr = poller_timer_make (&self->poller);
self->timeout_tmr.dispatcher = on_irc_timeout; self->timeout_tmr.dispatcher = on_irc_timeout;
self->timeout_tmr.user_data = self; self->timeout_tmr.user_data = self;
poller_timer_init (&self->ping_tmr, &self->poller); self->ping_tmr = poller_timer_make (&self->poller);
self->ping_tmr.dispatcher = on_irc_ping_timeout; self->ping_tmr.dispatcher = on_irc_ping_timeout;
self->ping_tmr.user_data = self; self->ping_tmr.user_data = self;
poller_timer_init (&self->reconnect_tmr, &self->poller); self->reconnect_tmr = poller_timer_make (&self->poller);
self->reconnect_tmr.dispatcher = on_irc_reconnect_timeout; self->reconnect_tmr.dispatcher = on_irc_reconnect_timeout;
self->reconnect_tmr.user_data = self; self->reconnect_tmr.user_data = self;
} }
@@ -193,18 +193,13 @@ bot_context_free (struct bot_context *self)
str_free (&self->read_buffer); str_free (&self->read_buffer);
// TODO: terminate the plugins properly before this is called // TODO: terminate the plugins properly before this is called
struct plugin *link, *tmp; LIST_FOR_EACH (struct plugin, link, self->plugins)
for (link = self->plugins; link; link = tmp) plugin_destroy (link);
{
tmp = link->next;
plugin_free (link);
free (link);
}
if (self->irc_fd != -1) if (self->irc_fd != -1)
{ {
xclose (self->irc_fd);
poller_fd_reset (&self->irc_event); poller_fd_reset (&self->irc_event);
xclose (self->irc_fd);
} }
if (self->ssl) if (self->ssl)
SSL_free (self->ssl); SSL_free (self->ssl);
@@ -272,8 +267,7 @@ irc_send (struct bot_context *ctx, const char *format, ...)
return false; return false;
va_start (ap, format); va_start (ap, format);
struct str str; struct str str = str_make ();
str_init (&str);
str_append_vprintf (&str, format, ap); str_append_vprintf (&str, format, ap);
str_append (&str, "\r\n"); str_append (&str, "\r\n");
va_end (ap); va_end (ap);
@@ -509,7 +503,7 @@ irc_establish_connection (struct bot_context *ctx,
static int g_signal_pipe[2]; ///< A pipe used to signal... signals static int g_signal_pipe[2]; ///< A pipe used to signal... signals
static struct str_vector static struct strv
g_original_argv, ///< Original program arguments g_original_argv, ///< Original program arguments
g_recovery_env; ///< Environment for re-exec recovery g_recovery_env; ///< Environment for re-exec recovery
@@ -684,8 +678,8 @@ recovery_handler (int signum, siginfo_t *info, void *context)
static void static void
prepare_recovery_environment (void) prepare_recovery_environment (void)
{ {
str_vector_init (&g_recovery_env); g_recovery_env = strv_make ();
str_vector_add_vector (&g_recovery_env, environ); strv_append_vector (&g_recovery_env, environ);
// Prepare a location within the environment where we will put the startup // Prepare a location within the environment where we will put the startup
// (or maybe rather restart) reason in case of an irrecoverable error. // (or maybe rather restart) reason in case of an irrecoverable error.
@@ -702,7 +696,7 @@ prepare_recovery_environment (void)
else else
{ {
g_startup_reason_location = g_recovery_env.vector + g_recovery_env.len; g_startup_reason_location = g_recovery_env.vector + g_recovery_env.len;
str_vector_add (&g_recovery_env, ""); strv_append (&g_recovery_env, "");
} }
} }
@@ -964,7 +958,7 @@ on_plugin_readable (const struct pollfd *fd, struct plugin *plugin)
struct str *buf = &plugin->read_buffer; struct str *buf = &plugin->read_buffer;
while (true) while (true)
{ {
str_ensure_space (buf, 512 + 1); str_reserve (buf, 512 + 1);
ssize_t n_read = read (fd->fd, buf->str + buf->len, ssize_t n_read = read (fd->fd, buf->str + buf->len,
buf->alloc - buf->len - 1); buf->alloc - buf->len - 1);
@@ -1047,8 +1041,7 @@ plugin_launch (struct bot_context *ctx, const char *name, struct error **e)
goto fail_1; goto fail_1;
} }
struct str work_dir; struct str work_dir = str_make ();
str_init (&work_dir);
get_xdg_home_dir (&work_dir, "XDG_DATA_HOME", ".local/share"); get_xdg_home_dir (&work_dir, "XDG_DATA_HOME", ".local/share");
str_append_printf (&work_dir, "/%s", PROGRAM_NAME); str_append_printf (&work_dir, "/%s", PROGRAM_NAME);
@@ -1102,8 +1095,7 @@ plugin_launch (struct bot_context *ctx, const char *name, struct error **e)
xclose (stdin_pipe[0]); xclose (stdin_pipe[0]);
xclose (stdout_pipe[1]); xclose (stdout_pipe[1]);
struct plugin *plugin = xmalloc (sizeof *plugin); struct plugin *plugin = plugin_new ();
plugin_init (plugin);
plugin->ctx = ctx; plugin->ctx = ctx;
plugin->pid = pid; plugin->pid = pid;
plugin->name = xstrdup (name); plugin->name = xstrdup (name);
@@ -1136,11 +1128,11 @@ plugin_load (struct bot_context *ctx, const char *name, struct error **e)
set_blocking (plugin->read_fd, false); set_blocking (plugin->read_fd, false);
set_blocking (plugin->write_fd, false); set_blocking (plugin->write_fd, false);
poller_fd_init (&plugin->read_event, &ctx->poller, plugin->read_fd); plugin->read_event = poller_fd_make (&ctx->poller, plugin->read_fd);
plugin->read_event.dispatcher = (poller_fd_fn) on_plugin_readable; plugin->read_event.dispatcher = (poller_fd_fn) on_plugin_readable;
plugin->read_event.user_data = plugin; plugin->read_event.user_data = plugin;
poller_fd_init (&plugin->write_event, &ctx->poller, plugin->write_fd); plugin->write_event = poller_fd_make (&ctx->poller, plugin->write_fd);
plugin->write_event.dispatcher = (poller_fd_fn) on_plugin_writable; plugin->write_event.dispatcher = (poller_fd_fn) on_plugin_writable;
plugin->write_event.user_data = plugin; plugin->write_event.user_data = plugin;
@@ -1173,9 +1165,7 @@ plugin_load_all_from_config (struct bot_context *ctx)
if (!plugin_list) if (!plugin_list)
return; return;
struct str_vector plugins; struct strv plugins = strv_make ();
str_vector_init (&plugins);
cstr_split (plugin_list, ",", true, &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++)
{ {
@@ -1189,7 +1179,7 @@ plugin_load_all_from_config (struct bot_context *ctx)
} }
} }
str_vector_free (&plugins); strv_free (&plugins);
} }
// --- Main program ------------------------------------------------------------ // --- Main program ------------------------------------------------------------
@@ -1214,13 +1204,13 @@ 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 strv *out)
{ {
cstr_split (arguments, ",", true, 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"))
str_vector_remove (out, i); strv_remove (out, i);
else else
i++; i++;
} }
@@ -1256,10 +1246,8 @@ respond_to_user (struct bot_context *ctx, const struct irc_message *msg,
strncpy (nick, msg->prefix, sizeof nick - 1); strncpy (nick, msg->prefix, sizeof nick - 1);
nick[sizeof nick - 1] = '\0'; nick[sizeof nick - 1] = '\0';
struct str text;
va_list ap; va_list ap;
struct str text = str_make ();
str_init (&text);
va_start (ap, format); va_start (ap, format);
str_append_vprintf (&text, format, ap); str_append_vprintf (&text, format, ap);
va_end (ap); va_end (ap);
@@ -1320,9 +1308,7 @@ process_plugin_reload (struct bot_context *ctx,
static char * static char *
make_status_report (struct bot_context *ctx) make_status_report (struct bot_context *ctx)
{ {
struct str report; struct str report = str_make ();
str_init (&report);
const char *reason = getenv (g_startup_reason_str); const char *reason = getenv (g_startup_reason_str);
if (!reason) if (!reason)
reason = "launched normally"; reason = "launched normally";
@@ -1367,8 +1353,7 @@ process_privmsg (struct bot_context *ctx, const struct irc_message *msg)
return; return;
const char *following; const char *following;
struct str_vector list; struct strv list = strv_make ();
str_vector_init (&list);
if (parse_bot_command (text, "quote", &following)) if (parse_bot_command (text, "quote", &following))
// This seems to replace tons of random stupid commands // This seems to replace tons of random stupid commands
@@ -1408,7 +1393,7 @@ process_privmsg (struct bot_context *ctx, const struct irc_message *msg)
process_plugin_unload (ctx, msg, list.vector[i]); process_plugin_unload (ctx, msg, list.vector[i]);
} }
str_vector_free (&list); strv_free (&list);
} }
static void static void
@@ -1585,13 +1570,11 @@ on_irc_disconnected (struct bot_context *ctx)
ctx->ssl_ctx = NULL; ctx->ssl_ctx = NULL;
} }
poller_fd_reset (&ctx->irc_event);
xclose (ctx->irc_fd); xclose (ctx->irc_fd);
ctx->irc_fd = -1; ctx->irc_fd = -1;
ctx->irc_registered = false; ctx->irc_registered = false;
ctx->irc_event.closed = true;
poller_fd_reset (&ctx->irc_event);
// TODO: inform plugins about the disconnect event // TODO: inform plugins about the disconnect event
// All of our timers have lost their meaning now // All of our timers have lost their meaning now
@@ -1646,7 +1629,7 @@ on_irc_readable (const struct pollfd *fd, struct bot_context *ctx)
bool disconnected = false; bool disconnected = false;
while (true) while (true)
{ {
str_ensure_space (buf, 512); str_reserve (buf, 512);
switch (fill_buffer (ctx, buf)) switch (fill_buffer (ctx, buf))
{ {
case IRC_READ_AGAIN: case IRC_READ_AGAIN:
@@ -1807,7 +1790,7 @@ irc_connect (struct bot_context *ctx, struct error **e)
} }
print_status ("connection established"); print_status ("connection established");
poller_fd_init (&ctx->irc_event, &ctx->poller, ctx->irc_fd); ctx->irc_event = poller_fd_make (&ctx->poller, ctx->irc_fd);
ctx->irc_event.dispatcher = (poller_fd_fn) on_irc_readable; ctx->irc_event.dispatcher = (poller_fd_fn) on_irc_readable;
ctx->irc_event.user_data = ctx; ctx->irc_event.user_data = ctx;
@@ -1888,8 +1871,7 @@ on_plugin_death (struct plugin *plugin, int status)
plugin->read_fd = -1; plugin->read_fd = -1;
LIST_UNLINK (ctx->plugins, plugin); LIST_UNLINK (ctx->plugins, plugin);
plugin_free (plugin); plugin_destroy (plugin);
free (plugin);
// Living child processes block us from quitting // Living child processes block us from quitting
try_finish_quit (ctx); try_finish_quit (ctx);
@@ -1967,8 +1949,8 @@ on_signal_pipe_readable (const struct pollfd *fd, struct bot_context *ctx)
int int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
str_vector_init (&g_original_argv); g_original_argv = strv_make ();
str_vector_add_vector (&g_original_argv, argv); strv_append_vector (&g_original_argv, argv);
static const struct opt opts[] = static const struct opt opts[] =
{ {
@@ -1981,8 +1963,8 @@ main (int argc, char *argv[])
{ 0, NULL, NULL, 0, NULL } { 0, NULL, NULL, 0, NULL }
}; };
struct opt_handler oh; struct opt_handler oh =
opt_handler_init (&oh, argc, argv, opts, NULL, "Experimental IRC bot."); opt_handler_make (argc, argv, opts, NULL, "Experimental IRC bot.");
int c; int c;
while ((c = opt_handler_get (&oh)) != -1) while ((c = opt_handler_get (&oh)) != -1)
@@ -2024,7 +2006,7 @@ main (int argc, char *argv[])
exit (EXIT_FAILURE); exit (EXIT_FAILURE);
} }
poller_fd_init (&ctx.signal_event, &ctx.poller, g_signal_pipe[0]); ctx.signal_event = poller_fd_make (&ctx.poller, g_signal_pipe[0]);
ctx.signal_event.dispatcher = (poller_fd_fn) on_signal_pipe_readable; ctx.signal_event.dispatcher = (poller_fd_fn) on_signal_pipe_readable;
ctx.signal_event.user_data = &ctx; ctx.signal_event.user_data = &ctx;
poller_fd_set (&ctx.signal_event, POLLIN); poller_fd_set (&ctx.signal_event, POLLIN);
@@ -2056,7 +2038,7 @@ main (int argc, char *argv[])
poller_run (&ctx.poller); poller_run (&ctx.poller);
bot_context_free (&ctx); bot_context_free (&ctx);
str_vector_free (&g_original_argv); strv_free (&g_original_argv);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }