summaryrefslogtreecommitdiff
path: root/src/core/hook/wee-hook-url.c
diff options
context:
space:
mode:
authorSébastien Helleu <flashcode@flashtux.org>2023-09-08 11:34:56 +0200
committerSébastien Helleu <flashcode@flashtux.org>2023-09-16 10:19:51 +0200
commit63922ca03840caaa6deaf010d7627ad9542e19c5 (patch)
tree2c5f7c353e38907b66c88ca37adc01c88642b628 /src/core/hook/wee-hook-url.c
parenta5f4c3770be0496bc7c8981ecd4adbe323831b4e (diff)
downloadweechat-63922ca03840caaa6deaf010d7627ad9542e19c5.zip
api: add function hook_url
Diffstat (limited to 'src/core/hook/wee-hook-url.c')
-rw-r--r--src/core/hook/wee-hook-url.c419
1 files changed, 419 insertions, 0 deletions
diff --git a/src/core/hook/wee-hook-url.c b/src/core/hook/wee-hook-url.c
new file mode 100644
index 000000000..6f00da4f2
--- /dev/null
+++ b/src/core/hook/wee-hook-url.c
@@ -0,0 +1,419 @@
+/*
+ * wee-hook-url.c - WeeChat URL hook
+ *
+ * Copyright (C) 2023 Sébastien Helleu <flashcode@flashtux.org>
+ *
+ * This file is part of WeeChat, the extensible chat client.
+ *
+ * WeeChat is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * WeeChat 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with WeeChat. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+
+#include "../weechat.h"
+#include "../wee-hashtable.h"
+#include "../wee-hook.h"
+#include "../wee-infolist.h"
+#include "../wee-log.h"
+#include "../wee-string.h"
+#include "../wee-url.h"
+#include "../../gui/gui-chat.h"
+#include "../../plugins/plugin.h"
+
+
+/*
+ * Returns description of hook.
+ *
+ * Note: result must be freed after use.
+ */
+
+char *
+hook_url_get_description (struct t_hook *hook)
+{
+ char str_desc[1024];
+
+ snprintf (str_desc, sizeof (str_desc),
+ "URL: \"%s\", thread id: %d",
+ HOOK_URL(hook, url),
+ 0);
+
+ return strdup (str_desc);
+}
+
+/*
+ * Displays keys and values of a hashtable.
+ */
+
+void
+hook_url_hashtable_map_cb (void *data, struct t_hashtable *hashtable,
+ const void *key, const void *value)
+{
+ /* make C compiler happy */
+ (void) data;
+ (void) hashtable;
+
+ gui_chat_printf (NULL, " %s: \"%s\"",
+ (const char *)key,
+ (const char *)value);
+}
+
+/*
+ * Runs callback of url hook.
+ */
+
+void
+hook_url_run_callback (struct t_hook *hook)
+{
+ if (url_debug)
+ {
+ gui_chat_printf (NULL, "Running hook_url callback for URL \"%s\":",
+ HOOK_URL(hook, url));
+ gui_chat_printf (NULL, " options:");
+ hashtable_map (HOOK_URL(hook, options), &hook_url_hashtable_map_cb, NULL);
+ gui_chat_printf (NULL, " output:");
+ hashtable_map (HOOK_URL(hook, output), &hook_url_hashtable_map_cb, NULL);
+ }
+
+ (void) (HOOK_URL(hook, callback))
+ (hook->callback_pointer,
+ hook->callback_data,
+ HOOK_URL(hook, url),
+ HOOK_URL(hook, options),
+ HOOK_URL(hook, output));
+}
+
+/*
+ * Thread cleanup function: mark thread as not running any more.
+ */
+
+void
+hook_url_thread_cleanup (void *hook_pointer)
+{
+ struct t_hook *hook;
+
+ hook = (struct t_hook *)hook_pointer;
+
+ HOOK_URL(hook, thread_running) = 0;
+}
+
+/*
+ * URL transfer (in a separate thread).
+ */
+
+void *
+hook_url_transfer_thread (void *hook_pointer)
+{
+ struct t_hook *hook;
+
+ hook = (struct t_hook *)hook_pointer;
+
+ pthread_cleanup_push (&hook_url_thread_cleanup, hook);
+
+ (void) weeurl_download (HOOK_URL(hook, url),
+ HOOK_URL(hook, options),
+ HOOK_URL(hook, output));
+
+ pthread_cleanup_pop (1);
+
+ return NULL;
+}
+
+/*
+ * Checks if thread is still alive.
+ */
+
+int
+hook_url_timer_cb (const void *pointer, void *data, int remaining_calls)
+{
+ struct t_hook *hook;
+ const char *ptr_error;
+
+ /* make C compiler happy */
+ (void) data;
+ (void) remaining_calls;
+
+ hook = (struct t_hook *)pointer;
+
+ if (hook->deleted)
+ return WEECHAT_RC_OK;
+
+ if (!HOOK_URL(hook, thread_running))
+ {
+ hook_url_run_callback (hook);
+ ptr_error = hashtable_get (HOOK_URL(hook, output), "error");
+ if (ptr_error && ptr_error[0])
+ {
+ gui_chat_printf (
+ NULL,
+ _("%sURL transfer error: %s (URL: \"%s\")"),
+ gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
+ ptr_error,
+ HOOK_URL(hook, url));
+ }
+ unhook (hook);
+ return WEECHAT_RC_OK;
+ }
+
+ if (remaining_calls == 0)
+ {
+ hook_url_run_callback (hook);
+ if (weechat_debug_core >= 1)
+ {
+ gui_chat_printf (
+ NULL,
+ _("End of URL transfer '%s', timeout reached (%.1fs)"),
+ HOOK_URL(hook, url),
+ ((float)HOOK_URL(hook, timeout)) / 1000);
+ }
+ pthread_cancel (HOOK_URL(hook, thread_id));
+ usleep (1000);
+ unhook (hook);
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * Starts transfer for an URL hook.
+ */
+
+void
+hook_url_transfer (struct t_hook *hook)
+{
+ int rc, timeout, max_calls;
+ long interval;
+
+ HOOK_URL(hook, thread_running) = 1;
+
+ /* create thread */
+ rc = pthread_create (&(HOOK_URL(hook, thread_id)), NULL,
+ &hook_url_transfer_thread, hook);
+ if (rc != 0)
+ {
+ gui_chat_printf (NULL,
+ _("%sError running thread in hook_url: %s (URL: \"%s\")"),
+ gui_chat_prefix[GUI_CHAT_PREFIX_ERROR],
+ strerror (rc),
+ HOOK_URL(hook, url));
+ unhook (hook);
+ return;
+ }
+
+ /* main thread */
+ timeout = HOOK_URL(hook, timeout);
+ interval = 100;
+ max_calls = 0;
+ if (timeout > 0)
+ {
+ if (timeout <= 100)
+ {
+ interval = timeout;
+ max_calls = 1;
+ }
+ else
+ {
+ interval = 100;
+ max_calls = timeout / 100;
+ if (timeout % 100 == 0)
+ max_calls++;
+ }
+ }
+ HOOK_URL(hook, hook_timer) = hook_timer (hook->plugin,
+ interval, 0, max_calls,
+ &hook_url_timer_cb,
+ hook,
+ NULL);
+}
+
+/*
+ * Hooks a URL.
+ *
+ * Returns pointer to new hook, NULL if error.
+ */
+
+struct t_hook *
+hook_url (struct t_weechat_plugin *plugin,
+ const char *url,
+ struct t_hashtable *options,
+ int timeout,
+ t_hook_callback_url *callback,
+ const void *callback_pointer,
+ void *callback_data)
+{
+ struct t_hook *new_hook;
+ struct t_hook_url *new_hook_url;
+
+ new_hook = NULL;
+ new_hook_url = NULL;
+
+ if (!url || !url[0] || !callback)
+ goto error;
+
+ new_hook = malloc (sizeof (*new_hook));
+ if (!new_hook)
+ goto error;
+
+ new_hook_url = malloc (sizeof (*new_hook_url));
+ if (!new_hook_url)
+ goto error;
+
+ hook_init_data (new_hook, plugin, HOOK_TYPE_URL, HOOK_PRIORITY_DEFAULT,
+ callback_pointer, callback_data);
+
+ new_hook->hook_data = new_hook_url;
+ new_hook_url->callback = callback;
+ new_hook_url->url = strdup (url);
+ new_hook_url->options = (options) ? hashtable_dup (options) : NULL;
+ new_hook_url->timeout = timeout;
+ new_hook_url->thread_id = 0;
+ new_hook_url->thread_running = 0;
+ new_hook_url->hook_timer = NULL;
+ new_hook_url->output = hashtable_new (32,
+ WEECHAT_HASHTABLE_STRING,
+ WEECHAT_HASHTABLE_STRING,
+ NULL, NULL);
+ hook_add_to_list (new_hook);
+
+ if (weechat_debug_core >= 1)
+ {
+ gui_chat_printf (NULL,
+ "debug: hook_url: url=\"%s\", "
+ "options=\"%s\", timeout=%d",
+ new_hook_url->url,
+ hashtable_get_string (new_hook_url->options,
+ "keys_values"),
+ new_hook_url->timeout);
+ }
+
+ hook_url_transfer (new_hook);
+
+ return new_hook;
+
+error:
+ if (new_hook)
+ free (new_hook);
+ if (new_hook_url)
+ free (new_hook_url);
+ return NULL;
+}
+
+/*
+ * Frees data in a url hook.
+ */
+
+void
+hook_url_free_data (struct t_hook *hook)
+{
+ if (!hook || !hook->hook_data)
+ return;
+
+ if (HOOK_URL(hook, url))
+ {
+ free (HOOK_URL(hook, url));
+ HOOK_URL(hook, url) = NULL;
+ }
+ if (HOOK_URL(hook, options))
+ {
+ hashtable_free (HOOK_URL(hook, options));
+ HOOK_URL(hook, options) = NULL;
+ }
+ if (HOOK_URL(hook, hook_timer))
+ {
+ unhook (HOOK_URL(hook, hook_timer));
+ HOOK_URL(hook, hook_timer) = NULL;
+ }
+ if (HOOK_URL(hook, thread_running))
+ {
+ pthread_cancel (HOOK_URL(hook, thread_id));
+ HOOK_URL(hook, thread_running) = 0;
+ }
+ if (HOOK_URL(hook, output))
+ {
+ hashtable_free (HOOK_URL(hook, output));
+ HOOK_URL(hook, output) = NULL;
+ }
+
+ free (hook->hook_data);
+ hook->hook_data = NULL;
+}
+
+/*
+ * Adds url hook data in the infolist item.
+ *
+ * Returns:
+ * 1: OK
+ * 0: error
+ */
+
+int
+hook_url_add_to_infolist (struct t_infolist_item *item,
+ struct t_hook *hook)
+{
+ if (!item || !hook || !hook->hook_data)
+ return 0;
+
+ if (!infolist_new_var_pointer (item, "callback", HOOK_URL(hook, callback)))
+ return 0;
+ if (!infolist_new_var_string (item, "url", HOOK_URL(hook, url)))
+ return 0;
+ if (!infolist_new_var_string (item, "options", hashtable_get_string (HOOK_URL(hook, options), "keys_values")))
+ return 0;
+ if (!infolist_new_var_integer (item, "timeout", (int)(HOOK_URL(hook, timeout))))
+ return 0;
+ if (!infolist_new_var_integer (item, "thread_running", (int)(HOOK_URL(hook, thread_running))))
+ return 0;
+ if (!infolist_new_var_pointer (item, "hook_timer", HOOK_URL(hook, hook_timer)))
+ return 0;
+ if (!infolist_new_var_string (item, "output", hashtable_get_string (HOOK_URL(hook, output), "keys_values")))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * Prints url hook data in WeeChat log file (usually for crash dump).
+ */
+
+void
+hook_url_print_log (struct t_hook *hook)
+{
+ if (!hook || !hook->hook_data)
+ return;
+
+ log_printf (" url data:");
+ log_printf (" callback. . . . . . . : 0x%lx", HOOK_URL(hook, callback));
+ log_printf (" url . . . . . . . . . : '%s'", HOOK_URL(hook, url));
+ log_printf (" options . . . . . . . : 0x%lx (hashtable: '%s')",
+ HOOK_URL(hook, options),
+ hashtable_get_string (HOOK_URL(hook, options),
+ "keys_values"));
+ log_printf (" timeout . . . . . . . : %ld", HOOK_URL(hook, timeout));
+ log_printf (" thread_running. . . . : %d", (int)HOOK_URL(hook, thread_running));
+ log_printf (" hook_timer. . . . . . : 0x%lx", HOOK_URL(hook, hook_timer));
+ log_printf (" output. . . . . . . . : 0x%lx (hashtable: '%s')",
+ HOOK_URL(hook, output),
+ hashtable_get_string (HOOK_URL(hook, output),
+ "keys_values"));
+}