]> PatchyGit - patchyircd.git/commitdiff
admin: make lua mandatory dependency
authorEgor <egor@patchysicp.xyz>
Wed, 21 Jan 2026 16:31:38 +0000 (18:31 +0200)
committerEgor <egor@patchysicp.xyz>
Wed, 21 Jan 2026 16:31:38 +0000 (18:31 +0200)
README.md
configure.ac
src/admin.cpp
src/admin.hpp
src/irc.cpp
src/main.cpp
src/net.cpp

index 7eb227e..6d2f645 100644 (file)
--- a/README.md
+++ b/README.md
@@ -3,6 +3,14 @@
 patchy IRC server?????
 
 ## How to compile and use
+Required dependencies:
+- libuv
+- lua5.4
+- sqlite3
+
+Optional dependencies:
+- libtls
+
 Basic compilation:
 ```
 autoreconf -iv # if you're compiling from source control
@@ -70,17 +78,28 @@ organization running the server. Third line is a contact email address.
 You can set these to whatever you want, though setting a contact email is
 recommended.
 
-When the server starts, it reads the `init.txt` file. A fake oper connection
-performs the actions specified in the file. This allows initializing permanent
-channels. If you specify source (i.e. `:nick!user@host` before the command),
-the oper's nick will change accordingly. You can also fake the current unix time
-by prefixing the line with `$123` (`$0` sets the time back to real time). Faking
-nick and time is useful for JOIN and TOPIC commands. `chanlog.txt` records all
-channels changes in this format.
-(NOTE: this feature is deprecated. We only use it for bootstrapping lua:
-`LUA eval :dofile(getluafile"init.lua")`. Then in `lua/local.lua` we set up the
-channels. Also, be sure to PART any `--autojoin` channels if you want to give
-those a specific creation timestamp.)
+When the server starts, it initialized the lua subsystem by running the
+`init.lua` file. You can put your own code into `local.lua`. In particular, this
+allows automatically initializing permanent channels.
+```lua
+channel_new("#anime", 1652016295) -- name, creation time
+local chan = channel_map["#anime"]
+channel_mode(chan, "+b", "*!~*@*") -- varargs, like MODE command
+-- note that default modes are +ntP
+channel_topic(chan, "Anime!", "root", 1751023162) -- topic, who set, when set
+```
+The scripts can be reloaded by opers with `/quote LUA reload`, so you probably
+want to wrap some of your code like so:
+```lua
+if not local_processed then
+       local_processed = true
+       -- code here
+end
+```
+
+Channel state changes are logged in `chanlog.txt`, in a format similar to IRC
+protocol. Lines are prefixed with `$123`, which indicates the unix timestamp for
+when the action has occured.
 
 ## Command-line options
 Add TCP listeners with `--listenPlain ip port` and `--listenTls ip port`. If
index 777f905..3cb910c 100644 (file)
@@ -56,7 +56,7 @@ AS_IF([test "x$enable_pch" = xyes],
 
 PKG_CHECK_MODULES(LIBUV, [libuv])
 PKG_HAVE_DEFINE_WITH_MODULES(LIBTLS, [libtls])
-PKG_HAVE_DEFINE_WITH_MODULES(LUA, [lua5.4])
+PKG_CHECK_MODULES(LUA, [lua5.4])
 PKG_CHECK_MODULES(SQLITE3, [sqlite3])
 
 AC_OUTPUT
index 13f4e0d..bb2be59 100644 (file)
@@ -1,7 +1,6 @@
 // Copyright (c) 2023-2026 Egor
 // SPDX-License-Identifier: GPL-2.0-or-later
 #include "common.hpp"
-#ifdef HAVE_LUA
 #include "admin.hpp"
 #include "irc.hpp"
 #include "ircfmt.hpp"
@@ -452,6 +451,13 @@ void admin_fini(void)
                GL = 0;
        }
 }
+void admin_dostring(const char *command)
+{
+       lua_State *L = GL;
+       if (luaL_dostring(L, command) != LUA_OK)
+               fprintf(stderr, "%s\n", lua_tostring(L, -1));
+       lua_settop(L, 0);
+}
 int admin_command(Client *client, char *source, char *command, int argc, char *args[])
 {
        if (!is_registered(client))
@@ -534,4 +540,3 @@ int admin_hook(const char *hook, Client *cl1, Client *cl2, Channel *chan, char *
        lua_pop(L, 1);
        return rv;
 }
-#endif
index f2b31c2..f8050c5 100644 (file)
@@ -1,12 +1,11 @@
-// Copyright (c) 2023-2025 Egor
+// Copyright (c) 2023-2026 Egor
 // SPDX-License-Identifier: GPL-2.0-or-later
 #ifndef ADMIN_H_
 #define ADMIN_H_
-#ifdef HAVE_LUA
 #include "ircdata.hpp"
 void admin_init(void);
 void admin_fini(void);
+void admin_dostring(const char *command);
 int admin_command(Client *client, char *source, char *command, int argc, char *args[]);
 int admin_hook(const char *hook, Client *cl1, Client *cl2, Channel *chan, char *txt);
 #endif
-#endif
index 1cde194..c51dff1 100644 (file)
@@ -733,9 +733,7 @@ privmsg_notice_common:
                        return err_needmoreparams(client, command), sendbuf(client), 0;
                client->lastactivity = get_time();
                if (!strcmp(args[0], "cia")) {
-#ifdef HAVE_LUA
                        admin_hook(command[0] == 'P' ? "privmsgtoservice" : "noticetoservice", client, 0, 0, args[1]);
-#endif
                        return 0;
                }
                (command[0] == 'P' ? msg_privmsg : msg_notice)(client, args[0], args[1]);
@@ -759,7 +757,6 @@ privmsg_notice_common:
                                return err_cannotsendtochan(client, chan->name), sendbuf(client), 0;
                        if (chan->dmode & DMODE_MODERATED && !chan->v.has(client) && !chan->o.has(client))
                                return err_cannotsendtochan(client, chan->name), sendbuf(client), 0;
-#ifdef HAVE_LUA
                        switch (admin_hook("sendtochannel", client, 0, chan, args[1])) {
                        case -1:
                                msg_quit(client, "Quit: eel bearing atlantean", "");
@@ -769,7 +766,6 @@ privmsg_notice_common:
                        case 1:
                                return err_cannotsendtochan(client, chan->name), sendbuf(client), 0;
                        }
-#endif
                        if (!is_modmsg) {
                                sendbuf_list_sans_self(client, chan->members, 0);
                        } else if (memchr(args[0], '+', is_modmsg)) {
@@ -781,7 +777,6 @@ privmsg_notice_common:
                        }
                } else {
                        Client *cl = findClient(args[0]);
-#ifdef HAVE_LUA
                        if (!cl)
                                return err_nosuchnick(client, args[0]), sendbuf(client), 0;
                        switch (admin_hook("sendtoclient", client, cl, 0, args[1])) {
@@ -793,7 +788,6 @@ privmsg_notice_common:
                        case 1:
                                return err_cantsendtouser(client, cl), sendbuf(client), 0;
                        }
-#endif
                        sendbuf(cl);
                        if (cl->away)
                                rpl_away(client, cl), sendbuf(client);
@@ -1108,9 +1102,7 @@ privmsg_notice_common:
                        rpl_whoismodes(client, cl), sendbuf(client);
                        if (cl->umode & UMODE_BOT)
                                rpl_whoisbot(client, cl), sendbuf(client);
-#ifdef HAVE_LUA
                        admin_hook("whois", client, cl, 0, 0);
-#endif
                        rpl_endofwhois(client, cl), sendbuf(client);
                } else {
                        err_nosuchnick(client, nick);
@@ -1210,12 +1202,10 @@ privmsg_notice_common:
                sendbuf_monitor(client->key, cookie, CAP_SETNAME|CAP_EXTENDEDMONITOR, 0);
                if (client->cookie != cookie)
                        sendbuf(client);
-#ifdef HAVE_LUA
        } MATCH_COMMAND("LUA") {
                if (argc < 1)
                        return err_needmoreparams(client, command), sendbuf(client), 0;
                return admin_command(client, source, args[0], argc-1, args+1);
-#endif
        } MATCH_ELSE {
 unknown:
                err_unknowncommand(client, command), sendbuf(client);
@@ -1274,9 +1264,7 @@ void newUser(Client *client) {
        sendLUSERS(client);
        rpl_umodeis(client),  sendbuf(client);
        sendMOTD(client);
-#ifdef HAVE_LUA
        admin_hook("newuser", client, 0, 0, 0);
-#endif
        for (auto key : autojoin)
                channel_join(client, key, NULL);
 }
@@ -1360,10 +1348,8 @@ void setNick(Client *client, char* nickname) {
        }
 
        // Update nickname
-       if(client->nick) {
-#ifdef HAVE_LUA
+       if (client->nick) {
                admin_hook("nickchange", client, 0, 0, key);
-#endif
                msg_nick(client, nickname);
                sendbuf(client);
                sendbuf_visible(client);
@@ -1377,9 +1363,7 @@ void setNick(Client *client, char* nickname) {
                delete[] client->nick;
                delete[] client->key;
        } else {
-#ifdef HAVE_LUA
                admin_hook("nickadd", client, 0, 0, key);
-#endif
        }
 
        client->nick = mystrdup(nickname);
index 80e1aeb..91532fa 100644 (file)
@@ -213,9 +213,7 @@ int main(int argc, char *argv[])
        auto dblk = db::init();
        netpoll::init();
        job_init();
-#ifdef HAVE_LUA
        admin_init();
-#endif
 
        struct tls *tls_ctx = NULL;
 #ifdef HAVE_LIBTLS
@@ -288,53 +286,8 @@ int main(int argc, char *argv[])
                netpoll::reg(listener.fd, UV_READABLE);
        }
 
-       FILE *f = fopen(getdatafile("init.txt"), "rbe");
-       if (f) {
-               Client *fake = new Client();
-               fake->fd = -1;
-               fake->umode |= UMODE_OPER | UMODE_SECURE;
-               fake->hostname = mystrdup("localhost");
-               if (!fake->hostname)
-                       abortf("strdup fail (hostname)\n");
-               strcpy_lit(fake->rbuf, "NICK :root\r\n");
-               irc_parse_line(fake, fake->rbuf, 0);
-               strcpy_lit(fake->rbuf, "USER root 0 * :Patchouli Knowledge\r\n");
-               irc_parse_line(fake, fake->rbuf, 0);
-               while (fgets(fake->rbuf, sizeof(fake->rbuf), f)) {
-                       char *p = fake->rbuf;
-                       size_t len = strlen(fake->rbuf);
-                       if (!len || fake->rbuf[len-1] != '\n')
-                               break;
-                       unsigned long faketime;
-                       if (sscanf(p, "$%lu", &faketime)) {
-                               set_time((time_t)faketime);
-                               p = strchr(fake->rbuf, ' ');
-                               if (!p)
-                                       continue;
-                               len -= ++p - fake->rbuf;
-                               memmove(fake->rbuf, p, len);
-                       }
-                       if (*p == ':') {
-                               char *sp = strchr(p, ' ');
-                               char *bang = strchr(p, '!');
-                               if (sp && bang && bang < sp) {
-                                       size_t nlen = bang - p - 1;
-                                       if (memcmp(&p[1], fake->nick, nlen) != 0) {
-                                               char *nnick = new char[nlen+1];
-                                               memcpy(nnick, &p[1], nlen);
-                                               nnick[nlen] = '\0';
-                                               delete[] fake->nick;
-                                               fake->nick = nnick;
-                                       }
-                               }
-                       }
-                       irc_parse_line(fake, p, 0);
-               }
-               strcpy_lit(fake->rbuf, "QUIT :bye\r\n");
-               irc_parse_line(fake, fake->rbuf, 0);
-               set_time(0);
-               fclose(f);
-       }
+       admin_dostring("dofile(getluafile'init.lua')");
+
        fchanlog = fopen(getdatafile("chanlog.txt"), "abe");
        if (fchanlog) {
                fprintf(fchanlog, "$0 AAA :server starting %lu\r\n", (unsigned long)get_time());
@@ -406,9 +359,7 @@ int main(int argc, char *argv[])
                }
        }
 
-#ifdef HAVE_LUA
        admin_fini();
-#endif
        job_fini();
        netpoll::fini();
 #ifdef HAVE_LIBTLS
index 7948bff..d718aaf 100644 (file)
@@ -1,5 +1,5 @@
 // Copyright (c) 2022 Sam Smith
-// Copyright (c) 2022-2025 Egor
+// Copyright (c) 2022-2026 Egor
 // SPDX-License-Identifier: GPL-2.0-or-later
 #include "common.hpp"
 #include "net.hpp"
@@ -77,9 +77,7 @@ void killConnection(Client *cl, int byChoice)
                channel_part(cl, chan, NULL, NULL);
        /* Remove from client_map and get rid of the pending invites */
        if (cl->key) {
-#ifdef HAVE_LUA
                admin_hook("nickdel", cl, 0, 0, cl->key);
-#endif
                client_map.remove(cl);
                rpl_monoffline(0, cl->key), sendbuf_monitor(cl->key, 0, 0, 0);
                for (auto chan : cl->invites)