summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Gediminas Jakutis <gediminas@varciai.lt> 2019-05-17 13:56:05 +0300
committerGravatar Gediminas Jakutis <gediminas@varciai.lt> 2019-05-17 13:56:05 +0300
commite355b074ac00e8b05af89f854b0e46d80a5de00a (patch)
treec67cb5abee3c843b2ca2be112e68ce6cf1e706c7 /src
parentd51604d94e66d400376091aa2a735a238bb74f20 (diff)
downloadusurpation-e355b074ac00e8b05af89f854b0e46d80a5de00a.tar.gz
usurpation-e355b074ac00e8b05af89f854b0e46d80a5de00a.tar.bz2
usurpation-e355b074ac00e8b05af89f854b0e46d80a5de00a.zip
daemon: add a skeleton libpurple interface.
This loads and initialized libpurple, but does not actually do anything. This should be enough to warrant closing Ticket #18. Signed-off-by: Gediminas Jakutis <gediminas@varciai.lt>
Diffstat (limited to 'src')
-rw-r--r--src/daemon/main.c4
-rw-r--r--src/daemon/meson.build2
-rw-r--r--src/daemon/purple.c211
-rw-r--r--src/daemon/purple_private.h56
-rw-r--r--src/daemon/settings.c28
-rw-r--r--src/daemon/settings_private.h4
6 files changed, 305 insertions, 0 deletions
diff --git a/src/daemon/main.c b/src/daemon/main.c
index 302a9ce..41e798b 100644
--- a/src/daemon/main.c
+++ b/src/daemon/main.c
@@ -24,6 +24,7 @@
#include <stdio.h>
#include "settings.h"
#include "net.h"
+#include "purple.h"
/* the logic is a placeholder right now */
int main(int argc, char **argv)
@@ -35,6 +36,9 @@ int main(int argc, char **argv)
settings_init();
net_init(setting_port()); /* TODO: get port from settings. */
+ if (purple_init() && setting_verbose()) {
+ fprintf(stderr, "libpurple initialization failed\n");
+ }
/* by default and if running by as a system service, the init system
* needs to keep control of the process and thus only detach if
diff --git a/src/daemon/meson.build b/src/daemon/meson.build
index 44fa299..aa0aa75 100644
--- a/src/daemon/meson.build
+++ b/src/daemon/meson.build
@@ -2,7 +2,9 @@ d_filenames = [
'main.c',
'settings.c',
'net.c',
+ 'purple.c',
'settings_private.h',
+ 'purple_private.h',
]
d_conf_filenames = [
diff --git a/src/daemon/purple.c b/src/daemon/purple.c
new file mode 100644
index 0000000..6b73774
--- /dev/null
+++ b/src/daemon/purple.c
@@ -0,0 +1,211 @@
+/*
+ * Usurpation – server daemon main logic
+ *
+ * Copyright (C) 2019 Gediminas Jakutis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; version 2.1
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <libpurple/purple.h>
+#include <glib.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include "purple_private.h"
+#include "settings.h"
+
+static PurpleConversationUiOps conv_uiops =
+{
+ NULL, /* create_conversation */
+ NULL, /* destroy_conversation */
+ NULL, /* write_chat */
+ NULL, /* write_im */
+ NULL, /* write_conv */
+ NULL, /* chat_add_users */
+ NULL, /* chat_rename_user */
+ NULL, /* chat_remove_users */
+ NULL, /* chat_update_user */
+ NULL, /* present */
+ NULL, /* has_focus */
+ NULL, /* send_confirm */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static PurpleEventLoopUiOps eventloops =
+{
+ g_timeout_add,
+ g_source_remove,
+ glib_input_add,
+ g_source_remove,
+ NULL,
+ g_timeout_add_seconds,
+
+ /* padding */
+ NULL,
+ NULL,
+ NULL
+};
+
+static gboolean purple_glib_io(GIOChannel *source, GIOCondition cond, gpointer data)
+{
+ struct glib_io *bloc = data;
+ PurpleInputCondition pio_cond = 0;
+
+ if (cond & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
+ pio_cond |= PURPLE_INPUT_READ;
+ }
+
+ if (cond & (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+ pio_cond |= PURPLE_INPUT_WRITE;
+ }
+
+ bloc->func(bloc->data, g_io_channel_unix_get_fd(source), pio_cond);
+
+ return 1;
+}
+
+static guint glib_input_add(gint fd, PurpleInputCondition pio_cond, PurpleInputFunction func, gpointer data)
+{
+ struct glib_io *bloc;
+ GIOChannel *channel;
+ GIOCondition cond = 0;
+
+ bloc = g_new0(struct glib_io, 1);
+ bloc->func = func;
+ bloc->data = data;
+
+ if (pio_cond & PURPLE_INPUT_READ) {
+ cond |= G_IO_IN | G_IO_HUP | G_IO_ERR;
+ }
+
+ if (pio_cond & PURPLE_INPUT_WRITE) {
+ cond |= G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+ }
+
+ channel = g_io_channel_unix_new(fd);
+ bloc->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, purple_glib_io, bloc, g_free);
+ g_io_channel_unref(channel);
+
+ return bloc->result;
+}
+
+/* TODO: semi-stub */
+static void iface_init(void)
+{
+ purple_conversations_set_ui_ops(&conv_uiops);
+}
+
+static void pthread_mutex_unlock_thunk(void *arg)
+{
+ pthread_mutex_t *mutex = arg;
+
+ (void) pthread_mutex_unlock(mutex);
+}
+
+static void *purple_spawn(void *disregard)
+{
+ GMainLoop *loop;
+ char *progname = NULL;
+ char *user = NULL;
+ char *password = NULL;
+ char *proto = NULL;
+
+ (void) disregard;
+
+ pthread_cleanup_push(pthread_mutex_unlock_thunk, &state.mutex);
+ pthread_cleanup_push(free, progname);
+ pthread_cleanup_push(free, user);
+ pthread_cleanup_push(free, password);
+ pthread_cleanup_push(free, proto);
+
+ progname = setting_progname();
+ user = setting_im_user();
+ password = setting_im_password();
+ proto = setting_im_proto();
+ loop = g_main_loop_new(NULL, FALSE);
+
+ /* avoid an unholy army of libpurple's DNS resolver process zombies */
+ signal(SIGCHLD, SIG_IGN);
+
+ /* do not actually save anything about the account through libpurple */
+ purple_util_set_user_dir("/dev/full");
+
+ /*
+ * TODO:
+ * we do allow verbosity here yet
+ * use this once we do:
+ * purple_debug_set_enabled(setting_verbose());
+ */
+ purple_debug_set_enabled(0);
+
+ purple_core_set_ui_ops(&core_uiops);
+ purple_eventloop_set_ui_ops(&eventloops);
+ purple_core_init(setting_progname());
+ purple_prefs_load();
+
+ state.account = purple_account_new(setting_im_user(), setting_im_proto());
+ purple_account_set_password(state.account, setting_im_password());
+ purple_account_set_enabled(state.account, setting_progname(), TRUE);
+
+ g_main_loop_run(loop);
+
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+ pthread_cleanup_pop(1);
+
+ return NULL;
+}
+
+/*
+ * The following functions are exported and thus, can be wildly called by other
+ * modules and thus, are guarded by a mutex to make kind of a singleton, as it
+ * is NOT safe to access libpurple from more than one context / thread while
+ * using the same configuration (read: confdir).
+ */
+
+int purple_init(void)
+{
+ int ret = 0;
+
+ /* aquire the """singleton""" mutex */
+ if (pthread_mutex_trylock(&state.mutex)) {
+ /* TODO: use proper error numbers */
+ ret = 1;
+ } else {
+ if ((ret = pthread_create(&state.purple, NULL, purple_spawn, NULL))) {
+ /* thread creation failed, release the mutex */
+ pthread_mutex_unlock(&state.mutex);
+ }
+ }
+
+ return ret;
+}
+
+void purple_close(void)
+{
+
+ if (pthread_mutex_trylock(&state.mutex) == EBUSY) {
+ pthread_cancel(state.purple);
+ pthread_join(state.purple, NULL);
+ }
+}
diff --git a/src/daemon/purple_private.h b/src/daemon/purple_private.h
new file mode 100644
index 0000000..ff50139
--- /dev/null
+++ b/src/daemon/purple_private.h
@@ -0,0 +1,56 @@
+/*
+ * Usurpation – server daemon IM module, private header
+ *
+ * Copyright (C) 2019 Gediminas Jakutis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; version 2.1
+ * of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef USURPATION_PURPLE_PRIVATE_H
+#define USURPATION_PURPLE_PRIVATE_H
+
+#include <pthread.h>
+
+static void iface_init(void);
+
+static struct state {
+ pthread_mutex_t mutex;
+ pthread_t purple;
+ PurpleAccount *account;
+} state = {PTHREAD_MUTEX_INITIALIZER, 0, 0};
+
+struct glib_io {
+ PurpleInputFunction func;
+ guint result;
+ void *data;
+};
+
+static PurpleCoreUiOps core_uiops = {
+ NULL,
+ NULL,
+ iface_init,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static gboolean purple_glib_io(GIOChannel *source, GIOCondition cond, gpointer data);
+static guint glib_input_add(gint fd, PurpleInputCondition pio_cond, PurpleInputFunction function, gpointer data);
+static void *purple_spawn(void *disregard);
+static void pthread_mutex_unlock_thunk(void *arg);
+
+#endif /* USURPATION_PURPLE_PRIVATE_H */
diff --git a/src/daemon/settings.c b/src/daemon/settings.c
index 8decf08..b5c9c0c 100644
--- a/src/daemon/settings.c
+++ b/src/daemon/settings.c
@@ -19,6 +19,10 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+#define _GNU_SOURCE
+
+#include <string.h>
+#include <errno.h>
#include "settings.h"
#include "settings_private.h"
@@ -31,6 +35,10 @@ void settings_init(void)
unset_flag(flag_daemonize);
settings.port = 6996;
set_flag(flag_verbose);
+ settings.progname = program_invocation_short_name;
+ settings.im_user = "user";
+ settings.im_password = "password";
+ settings.im_proto = "prpl-irc";
}
int setting_detach(void)
@@ -48,6 +56,26 @@ unsigned short int setting_port(void)
return settings.port;
}
+char *setting_progname(void)
+{
+ return strdup(settings.progname);
+}
+
+char *setting_im_user(void)
+{
+ return strdup(settings.im_user);
+}
+
+char *setting_im_password(void)
+{
+ return strdup(settings.im_password);
+}
+
+char *setting_im_proto(void)
+{
+ return strdup(settings.im_proto);
+}
+
/* could be a one-liner, but let's make the logic more obvious */
int test_flag(unsigned int flag)
{
diff --git a/src/daemon/settings_private.h b/src/daemon/settings_private.h
index 336c151..388509a 100644
--- a/src/daemon/settings_private.h
+++ b/src/daemon/settings_private.h
@@ -28,6 +28,10 @@ static const unsigned int flag_verbose = 1 << 1;
static struct settings {
unsigned int flags;
unsigned short int port;
+ char *progname;
+ char *im_user;
+ char *im_password;
+ char *im_proto;
} settings;
int test_flag(unsigned int flag);