Move purple plugins into their own subdirectories
Not sure if the trip though reviewboard will preserve the moves, so you might have to that yourself manually.
Testing Done:
Compile only.
Reviewed at https://reviews.imfreedom.org/r/1738/
--- a/libpurple/plugins/autoaccept.c Sun Sep 11 02:09:40 2022 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,340 +0,0 @@
- * Autoaccept - Auto-accept file transfers from selected users
- * This program 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 2 of the
- * License, or (at your option) any later version.
- * 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
- * General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-#include <glib/gi18n-lib.h>
-#define PLUGIN_ID "core-plugin_pack-autoaccept"
-#define PLUGIN_NAME N_("Autoaccept")
-#define PLUGIN_CATEGORY N_("Utility")
-#define PLUGIN_STATIC_NAME Autoaccept
-#define PLUGIN_SUMMARY N_("Auto-accept file transfer requests from selected users.")
-#define PLUGIN_DESCRIPTION N_("Auto-accept file transfer requests from selected users.")
-#define PLUGIN_AUTHORS {"Sadrul H Chowdhury <sadrul@users.sourceforge.net>", NULL}
-#include <glib/gstdio.h>
-#include <gplugin-native.h>
-#define PREF_PREFIX "/plugins/core/" PLUGIN_ID
-#define PREF_PATH PREF_PREFIX "/path"
-#define PREF_STRANGER PREF_PREFIX "/stranger"
-#define PREF_NOTIFY PREF_PREFIX "/notify"
-#define PREF_NEWDIR PREF_PREFIX "/newdir"
-#define PREF_ESCAPE PREF_PREFIX "/escape"
-#define PREF_STRANGER_OLD PREF_PREFIX "/reject_stranger"
-ensure_path_exists(const char *dir)
- if (!g_file_test(dir, G_FILE_TEST_IS_DIR))
- if (g_mkdir_with_parents(dir, S_IRUSR | S_IWUSR | S_IXUSR)) {
-auto_accept_complete_cb(PurpleXfer *xfer, G_GNUC_UNUSED GParamSpec *pspec,
- G_GNUC_UNUSED gpointer data)
- PurpleConversationManager *manager = NULL;
- if (purple_xfer_get_status(xfer) != PURPLE_XFER_STATUS_DONE) {
- manager = purple_conversation_manager_get_default();
- if(purple_prefs_get_bool(PREF_NOTIFY) &&
- !purple_conversation_manager_find_im(manager,
- purple_xfer_get_account(xfer),
- purple_xfer_get_remote_user(xfer)))
- char *message = g_strdup_printf(_("Autoaccepted file transfer of \"%s\" from \"%s\" completed."),
- purple_xfer_get_filename(xfer), purple_xfer_get_remote_user(xfer));
- purple_notify_info(NULL, _("Autoaccept complete"), message,
- NULL, purple_request_cpar_from_account(
- purple_xfer_get_account(xfer)));
-file_recv_request_cb(PurpleXfer *xfer, gpointer handle)
- PurpleAccount *account;
- account = purple_xfer_get_account(xfer);
- node = PURPLE_BLIST_NODE(purple_blist_find_buddy(account, purple_xfer_get_remote_user(xfer)));
- /* If person is on buddy list, use the buddy setting; otherwise, use the
- node = purple_blist_node_get_parent(node);
- g_return_if_fail(PURPLE_IS_CONTACT(node));
- accept_setting = purple_blist_node_get_int(node, "autoaccept");
- accept_setting = purple_prefs_get_int(PREF_STRANGER);
- switch (accept_setting)
- pref = purple_prefs_get_string(PREF_PATH);
- if (ensure_path_exists(pref))
- if (purple_prefs_get_bool(PREF_NEWDIR))
- dirname = g_build_filename(pref, purple_normalize(account, purple_xfer_get_remote_user(xfer)), NULL);
- dirname = g_build_filename(pref, NULL);
- if (!ensure_path_exists(dirname))
- /* Escape filename (if escaping is turned on) */
- if (purple_prefs_get_bool(PREF_ESCAPE)) {
- escape = purple_escape_filename(purple_xfer_get_filename(xfer));
- escape = purple_xfer_get_filename(xfer);
- filename = g_build_filename(dirname, escape, NULL);
- /* Split at the first dot, to avoid uniquifying "foo.tar.gz" to "foo.tar-2.gz" */
- name_and_ext = g_strsplit(escape, ".", 2);
- name = name_and_ext[0];
- g_strfreev(name_and_ext);
- if (name_and_ext[1] != NULL) {
- /* g_strsplit does not include the separator in each chunk. */
- ext = g_strdup_printf(".%s", name_and_ext[1]);
- /* Make sure the file doesn't exist. Do we want some better checking than this? */
- /* FIXME: There is a race here: if the newly uniquified file name gets created between
- * this g_file_test and the transfer starting, the file created in the meantime
- * will be clobbered. But it's not at all straightforward to fix.
- while (g_file_test(filename, G_FILE_TEST_EXISTS)) {
- char *file = g_strdup_printf("%s-%d%s", name, count++, ext);
- filename = g_build_filename(dirname, file, NULL);
- purple_xfer_request_accepted(xfer, filename);
- g_strfreev(name_and_ext);
- g_signal_connect(xfer, "notify::status",
- G_CALLBACK(auto_accept_complete_cb), NULL);
- purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_LOCAL);
-save_cb(PurpleBlistNode *node, int choice)
- if (PURPLE_IS_BUDDY(node))
- node = purple_blist_node_get_parent(node);
- g_return_if_fail(PURPLE_IS_CONTACT(node));
- purple_blist_node_set_int(node, "autoaccept", choice);
-set_auto_accept_settings(PurpleBlistNode *node, gpointer plugin)
- if (PURPLE_IS_BUDDY(node))
- node = purple_blist_node_get_parent(node);
- g_return_if_fail(PURPLE_IS_CONTACT(node));
- message = g_strdup_printf(_("When a file-transfer request arrives from %s"),
- purple_contact_get_alias(PURPLE_CONTACT(node)));
- purple_request_choice(plugin, _("Set Autoaccept Setting"), message,
- NULL, GINT_TO_POINTER(purple_blist_node_get_int(node, "autoaccept")),
- _("_Save"), G_CALLBACK(save_cb),
- _("Ask"), GINT_TO_POINTER(FT_ASK),
- _("Auto Accept"), GINT_TO_POINTER(FT_ACCEPT),
- _("Auto Reject"), GINT_TO_POINTER(FT_REJECT),
-context_menu(PurpleBlistNode *node, GList **menu, gpointer plugin)
- PurpleActionMenu *action;
- if (!PURPLE_IS_BUDDY(node) && !PURPLE_IS_CONTACT(node) &&
- !purple_blist_node_is_transient(node))
- action = purple_action_menu_new(_("Autoaccept File Transfers..."),
- G_CALLBACK(set_auto_accept_settings), plugin, NULL);
- (*menu) = g_list_prepend(*menu, action);
-static PurplePluginPrefFrame *
-get_plugin_pref_frame(PurplePlugin *plugin)
- PurplePluginPrefFrame *frame;
- PurplePluginPref *pref;
- frame = purple_plugin_pref_frame_new();
- /* XXX: Is there a better way than this? There really should be. */
- pref = purple_plugin_pref_new_with_name_and_label(PREF_PATH, _("Path to save the files in\n"
- "(Please provide the full path)"));
- purple_plugin_pref_frame_add(frame, pref);
- pref = purple_plugin_pref_new_with_name_and_label(PREF_STRANGER,
- _("When a file-transfer request arrives from a user who is\n"
- "*not* on your buddy list:"));
- purple_plugin_pref_set_pref_type(pref, PURPLE_PLUGIN_PREF_CHOICE);
- purple_plugin_pref_add_choice(pref, _("Ask"), GINT_TO_POINTER(FT_ASK));
- purple_plugin_pref_add_choice(pref, _("Auto Accept"), GINT_TO_POINTER(FT_ACCEPT));
- purple_plugin_pref_add_choice(pref, _("Auto Reject"), GINT_TO_POINTER(FT_REJECT));
- purple_plugin_pref_frame_add(frame, pref);
- pref = purple_plugin_pref_new_with_name_and_label(PREF_NOTIFY,
- _("Notify with a popup when an autoaccepted file transfer is complete\n"
- "(only when there's no conversation with the sender)"));
- purple_plugin_pref_frame_add(frame, pref);
- pref = purple_plugin_pref_new_with_name_and_label(PREF_NEWDIR,
- _("Create a new directory for each user"));
- purple_plugin_pref_frame_add(frame, pref);
- pref = purple_plugin_pref_new_with_name_and_label(PREF_ESCAPE,
- _("Escape the filenames"));
- purple_plugin_pref_frame_add(frame, pref);
-static GPluginPluginInfo *
-auto_accept_query(GError **error)
- const gchar * const authors[] = PLUGIN_AUTHORS;
- return purple_plugin_info_new(
- "version", DISPLAY_VERSION,
- "category", PLUGIN_CATEGORY,
- "summary", PLUGIN_SUMMARY,
- "description", PLUGIN_DESCRIPTION,
- "website", PURPLE_WEBSITE,
- "abi-version", PURPLE_ABI_VERSION,
- "pref-frame-cb", get_plugin_pref_frame,
-auto_accept_load(GPluginPlugin *plugin, GError **error)
- dirname = g_build_filename(g_get_user_special_dir(G_USER_DIRECTORY_DOWNLOAD), "autoaccept", NULL);
- purple_prefs_add_none(PREF_PREFIX);
- purple_prefs_add_string(PREF_PATH, dirname);
- purple_prefs_add_bool(PREF_NOTIFY, TRUE);
- purple_prefs_add_bool(PREF_NEWDIR, TRUE);
- purple_prefs_add_bool(PREF_ESCAPE, TRUE);
- /* migrate the old pref (we should only care if the plugin is actually *used*) */
- * TODO: We should eventually call purple_prefs_remove(PREFS_STRANGER_OLD)
- * to clean up after ourselves, but we don't want to do it yet
- * so that we don't break users who share a .purple directory
- * between old libpurple clients and new libpurple clients.
- * --Mark Doliner, 2011-01-03
- if (!purple_prefs_exists(PREF_STRANGER)) {
- if (purple_prefs_exists(PREF_STRANGER_OLD) && purple_prefs_get_bool(PREF_STRANGER_OLD))
- purple_prefs_add_int(PREF_STRANGER, FT_REJECT);
- purple_prefs_set_int(PREF_STRANGER, FT_ASK);
- purple_signal_connect(purple_xfers_get_handle(), "file-recv-request", plugin,
- G_CALLBACK(file_recv_request_cb), plugin);
- purple_signal_connect(purple_blist_get_handle(), "blist-node-extended-menu", plugin,
- G_CALLBACK(context_menu), plugin);
-auto_accept_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error)
-GPLUGIN_NATIVE_PLUGIN_DECLARE(auto_accept)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/autoaccept/autoaccept.c Mon Sep 12 04:49:23 2022 -0500
@@ -0,0 +1,340 @@
+ * Autoaccept - Auto-accept file transfers from selected users + * This program 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 2 of the + * License, or (at your option) any later version. + * 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 + * General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +#include <glib/gi18n-lib.h> +#define PLUGIN_ID "core-plugin_pack-autoaccept" +#define PLUGIN_NAME N_("Autoaccept") +#define PLUGIN_CATEGORY N_("Utility") +#define PLUGIN_STATIC_NAME Autoaccept +#define PLUGIN_SUMMARY N_("Auto-accept file transfer requests from selected users.") +#define PLUGIN_DESCRIPTION N_("Auto-accept file transfer requests from selected users.") +#define PLUGIN_AUTHORS {"Sadrul H Chowdhury <sadrul@users.sourceforge.net>", NULL} +#include <glib/gstdio.h> +#include <gplugin-native.h> +#define PREF_PREFIX "/plugins/core/" PLUGIN_ID +#define PREF_PATH PREF_PREFIX "/path" +#define PREF_STRANGER PREF_PREFIX "/stranger" +#define PREF_NOTIFY PREF_PREFIX "/notify" +#define PREF_NEWDIR PREF_PREFIX "/newdir" +#define PREF_ESCAPE PREF_PREFIX "/escape" +#define PREF_STRANGER_OLD PREF_PREFIX "/reject_stranger" +ensure_path_exists(const char *dir) + if (!g_file_test(dir, G_FILE_TEST_IS_DIR)) + if (g_mkdir_with_parents(dir, S_IRUSR | S_IWUSR | S_IXUSR)) { +auto_accept_complete_cb(PurpleXfer *xfer, G_GNUC_UNUSED GParamSpec *pspec, + G_GNUC_UNUSED gpointer data) + PurpleConversationManager *manager = NULL; + if (purple_xfer_get_status(xfer) != PURPLE_XFER_STATUS_DONE) { + manager = purple_conversation_manager_get_default(); + if(purple_prefs_get_bool(PREF_NOTIFY) && + !purple_conversation_manager_find_im(manager, + purple_xfer_get_account(xfer), + purple_xfer_get_remote_user(xfer))) + char *message = g_strdup_printf(_("Autoaccepted file transfer of \"%s\" from \"%s\" completed."), + purple_xfer_get_filename(xfer), purple_xfer_get_remote_user(xfer)); + purple_notify_info(NULL, _("Autoaccept complete"), message, + NULL, purple_request_cpar_from_account( + purple_xfer_get_account(xfer))); +file_recv_request_cb(PurpleXfer *xfer, gpointer handle) + PurpleAccount *account; + account = purple_xfer_get_account(xfer); + node = PURPLE_BLIST_NODE(purple_blist_find_buddy(account, purple_xfer_get_remote_user(xfer))); + /* If person is on buddy list, use the buddy setting; otherwise, use the + node = purple_blist_node_get_parent(node); + g_return_if_fail(PURPLE_IS_CONTACT(node)); + accept_setting = purple_blist_node_get_int(node, "autoaccept"); + accept_setting = purple_prefs_get_int(PREF_STRANGER); + switch (accept_setting) + pref = purple_prefs_get_string(PREF_PATH); + if (ensure_path_exists(pref)) + if (purple_prefs_get_bool(PREF_NEWDIR)) + dirname = g_build_filename(pref, purple_normalize(account, purple_xfer_get_remote_user(xfer)), NULL); + dirname = g_build_filename(pref, NULL); + if (!ensure_path_exists(dirname)) + /* Escape filename (if escaping is turned on) */ + if (purple_prefs_get_bool(PREF_ESCAPE)) { + escape = purple_escape_filename(purple_xfer_get_filename(xfer)); + escape = purple_xfer_get_filename(xfer); + filename = g_build_filename(dirname, escape, NULL); + /* Split at the first dot, to avoid uniquifying "foo.tar.gz" to "foo.tar-2.gz" */ + name_and_ext = g_strsplit(escape, ".", 2); + name = name_and_ext[0]; + g_strfreev(name_and_ext); + if (name_and_ext[1] != NULL) { + /* g_strsplit does not include the separator in each chunk. */ + ext = g_strdup_printf(".%s", name_and_ext[1]); + /* Make sure the file doesn't exist. Do we want some better checking than this? */ + /* FIXME: There is a race here: if the newly uniquified file name gets created between + * this g_file_test and the transfer starting, the file created in the meantime + * will be clobbered. But it's not at all straightforward to fix. + while (g_file_test(filename, G_FILE_TEST_EXISTS)) { + char *file = g_strdup_printf("%s-%d%s", name, count++, ext); + filename = g_build_filename(dirname, file, NULL); + purple_xfer_request_accepted(xfer, filename); + g_strfreev(name_and_ext); + g_signal_connect(xfer, "notify::status", + G_CALLBACK(auto_accept_complete_cb), NULL); + purple_xfer_set_status(xfer, PURPLE_XFER_STATUS_CANCEL_LOCAL); +save_cb(PurpleBlistNode *node, int choice) + if (PURPLE_IS_BUDDY(node)) + node = purple_blist_node_get_parent(node); + g_return_if_fail(PURPLE_IS_CONTACT(node)); + purple_blist_node_set_int(node, "autoaccept", choice); +set_auto_accept_settings(PurpleBlistNode *node, gpointer plugin) + if (PURPLE_IS_BUDDY(node)) + node = purple_blist_node_get_parent(node); + g_return_if_fail(PURPLE_IS_CONTACT(node)); + message = g_strdup_printf(_("When a file-transfer request arrives from %s"), + purple_contact_get_alias(PURPLE_CONTACT(node))); + purple_request_choice(plugin, _("Set Autoaccept Setting"), message, + NULL, GINT_TO_POINTER(purple_blist_node_get_int(node, "autoaccept")), + _("_Save"), G_CALLBACK(save_cb), + _("Ask"), GINT_TO_POINTER(FT_ASK), + _("Auto Accept"), GINT_TO_POINTER(FT_ACCEPT), + _("Auto Reject"), GINT_TO_POINTER(FT_REJECT), +context_menu(PurpleBlistNode *node, GList **menu, gpointer plugin) + PurpleActionMenu *action; + if (!PURPLE_IS_BUDDY(node) && !PURPLE_IS_CONTACT(node) && + !purple_blist_node_is_transient(node)) + action = purple_action_menu_new(_("Autoaccept File Transfers..."), + G_CALLBACK(set_auto_accept_settings), plugin, NULL); + (*menu) = g_list_prepend(*menu, action); +static PurplePluginPrefFrame * +get_plugin_pref_frame(PurplePlugin *plugin) + PurplePluginPrefFrame *frame; + PurplePluginPref *pref; + frame = purple_plugin_pref_frame_new(); + /* XXX: Is there a better way than this? There really should be. */ + pref = purple_plugin_pref_new_with_name_and_label(PREF_PATH, _("Path to save the files in\n" + "(Please provide the full path)")); + purple_plugin_pref_frame_add(frame, pref); + pref = purple_plugin_pref_new_with_name_and_label(PREF_STRANGER, + _("When a file-transfer request arrives from a user who is\n" + "*not* on your buddy list:")); + purple_plugin_pref_set_pref_type(pref, PURPLE_PLUGIN_PREF_CHOICE); + purple_plugin_pref_add_choice(pref, _("Ask"), GINT_TO_POINTER(FT_ASK)); + purple_plugin_pref_add_choice(pref, _("Auto Accept"), GINT_TO_POINTER(FT_ACCEPT)); + purple_plugin_pref_add_choice(pref, _("Auto Reject"), GINT_TO_POINTER(FT_REJECT)); + purple_plugin_pref_frame_add(frame, pref); + pref = purple_plugin_pref_new_with_name_and_label(PREF_NOTIFY, + _("Notify with a popup when an autoaccepted file transfer is complete\n" + "(only when there's no conversation with the sender)")); + purple_plugin_pref_frame_add(frame, pref); + pref = purple_plugin_pref_new_with_name_and_label(PREF_NEWDIR, + _("Create a new directory for each user")); + purple_plugin_pref_frame_add(frame, pref); + pref = purple_plugin_pref_new_with_name_and_label(PREF_ESCAPE, + _("Escape the filenames")); + purple_plugin_pref_frame_add(frame, pref); +static GPluginPluginInfo * +auto_accept_query(GError **error) + const gchar * const authors[] = PLUGIN_AUTHORS; + return purple_plugin_info_new( + "version", DISPLAY_VERSION, + "category", PLUGIN_CATEGORY, + "summary", PLUGIN_SUMMARY, + "description", PLUGIN_DESCRIPTION, + "website", PURPLE_WEBSITE, + "abi-version", PURPLE_ABI_VERSION, + "pref-frame-cb", get_plugin_pref_frame, +auto_accept_load(GPluginPlugin *plugin, GError **error) + dirname = g_build_filename(g_get_user_special_dir(G_USER_DIRECTORY_DOWNLOAD), "autoaccept", NULL); + purple_prefs_add_none(PREF_PREFIX); + purple_prefs_add_string(PREF_PATH, dirname); + purple_prefs_add_bool(PREF_NOTIFY, TRUE); + purple_prefs_add_bool(PREF_NEWDIR, TRUE); + purple_prefs_add_bool(PREF_ESCAPE, TRUE); + /* migrate the old pref (we should only care if the plugin is actually *used*) */ + * TODO: We should eventually call purple_prefs_remove(PREFS_STRANGER_OLD) + * to clean up after ourselves, but we don't want to do it yet + * so that we don't break users who share a .purple directory + * between old libpurple clients and new libpurple clients. + * --Mark Doliner, 2011-01-03 + if (!purple_prefs_exists(PREF_STRANGER)) { + if (purple_prefs_exists(PREF_STRANGER_OLD) && purple_prefs_get_bool(PREF_STRANGER_OLD)) + purple_prefs_add_int(PREF_STRANGER, FT_REJECT); + purple_prefs_set_int(PREF_STRANGER, FT_ASK); + purple_signal_connect(purple_xfers_get_handle(), "file-recv-request", plugin, + G_CALLBACK(file_recv_request_cb), plugin); + purple_signal_connect(purple_blist_get_handle(), "blist-node-extended-menu", plugin, + G_CALLBACK(context_menu), plugin); +auto_accept_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error) +GPLUGIN_NATIVE_PLUGIN_DECLARE(auto_accept) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/autoaccept/meson.build Mon Sep 12 04:49:23 2022 -0500
@@ -0,0 +1,7 @@
+autoaccept = library('autoaccept', 'autoaccept.c', + c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="PurplePlugin-AutoAccept"'], + dependencies : [libpurple_dep, glib], + install : true, install_dir : PURPLE_PLUGINDIR) +devenv.append('PURPLE_PLUGIN_PATH', meson.current_build_dir()) --- a/libpurple/plugins/buddynote.c Sun Sep 11 02:09:40 2022 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
- * BuddyNote - Store notes on particular buddies
- * Copyright (C) 2004 Stu Tomlinson <stu@nosnilmot.com>
- * This program 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 2
- * of the License, or (at your option) any later version.
- * 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 General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA.
-#include <glib/gi18n-lib.h>
-#include <gplugin-native.h>
-dont_do_it_cb(PurpleBlistNode *node, const char *note)
-do_it_cb(PurpleBlistNode *node, const char *note)
- purple_blist_node_set_string(node, "notes", note);
-buddynote_edit_cb(PurpleBlistNode *node, gpointer data)
- note = purple_blist_node_get_string(node, "notes");
- purple_request_input(node, _("Notes"),
- _("Enter your notes below..."),
- note, TRUE, FALSE, "html",
- _("Save"), G_CALLBACK(do_it_cb),
- _("Cancel"), G_CALLBACK(dont_do_it_cb),
-buddynote_extended_menu_cb(PurpleBlistNode *node, GList **m)
- PurpleActionMenu *bna = NULL;
- if (purple_blist_node_is_transient(node))
- *m = g_list_append(*m, bna);
- bna = purple_action_menu_new(_("Edit Notes..."), G_CALLBACK(buddynote_edit_cb), NULL, NULL);
- *m = g_list_append(*m, bna);
-static GPluginPluginInfo *
-buddy_note_query(GError **error)
- const gchar * const authors[] = {
- "Stu Tomlinson <stu@nosnilmot.com>",
- return purple_plugin_info_new(
- "id", "core-plugin_pack-buddynote",
- "name", N_("Buddy Notes"),
- "version", DISPLAY_VERSION,
- "category", N_("Utility"),
- "summary", N_("Store notes on particular buddies."),
- "description", N_("Adds the option to store notes for buddies on your "
- "website", PURPLE_WEBSITE,
- "abi-version", PURPLE_ABI_VERSION,
-buddy_note_load(GPluginPlugin *plugin, GError **error)
- purple_signal_connect(purple_blist_get_handle(), "blist-node-extended-menu",
- plugin, G_CALLBACK(buddynote_extended_menu_cb), NULL);
-buddy_note_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error)
-GPLUGIN_NATIVE_PLUGIN_DECLARE(buddy_note)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/buddynote/buddynote.c Mon Sep 12 04:49:23 2022 -0500
@@ -0,0 +1,105 @@
+ * BuddyNote - Store notes on particular buddies + * Copyright (C) 2004 Stu Tomlinson <stu@nosnilmot.com> + * This program 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 2 + * of the License, or (at your option) any later version. + * 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 General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301, USA. +#include <glib/gi18n-lib.h> +#include <gplugin-native.h> +dont_do_it_cb(PurpleBlistNode *node, const char *note) +do_it_cb(PurpleBlistNode *node, const char *note) + purple_blist_node_set_string(node, "notes", note); +buddynote_edit_cb(PurpleBlistNode *node, gpointer data) + note = purple_blist_node_get_string(node, "notes"); + purple_request_input(node, _("Notes"), + _("Enter your notes below..."), + note, TRUE, FALSE, "html", + _("Save"), G_CALLBACK(do_it_cb), + _("Cancel"), G_CALLBACK(dont_do_it_cb), +buddynote_extended_menu_cb(PurpleBlistNode *node, GList **m) + PurpleActionMenu *bna = NULL; + if (purple_blist_node_is_transient(node)) + *m = g_list_append(*m, bna); + bna = purple_action_menu_new(_("Edit Notes..."), G_CALLBACK(buddynote_edit_cb), NULL, NULL); + *m = g_list_append(*m, bna); +static GPluginPluginInfo * +buddy_note_query(GError **error) + const gchar * const authors[] = { + "Stu Tomlinson <stu@nosnilmot.com>", + return purple_plugin_info_new( + "id", "core-plugin_pack-buddynote", + "name", N_("Buddy Notes"), + "version", DISPLAY_VERSION, + "category", N_("Utility"), + "summary", N_("Store notes on particular buddies."), + "description", N_("Adds the option to store notes for buddies on your " + "website", PURPLE_WEBSITE, + "abi-version", PURPLE_ABI_VERSION, +buddy_note_load(GPluginPlugin *plugin, GError **error) + purple_signal_connect(purple_blist_get_handle(), "blist-node-extended-menu", + plugin, G_CALLBACK(buddynote_extended_menu_cb), NULL); +buddy_note_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error) +GPLUGIN_NATIVE_PLUGIN_DECLARE(buddy_note) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/buddynote/meson.build Mon Sep 12 04:49:23 2022 -0500
@@ -0,0 +1,7 @@
+buddynote = library('buddynote', 'buddynote.c', + c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="PurplePlugin-BuddyNote"'], + dependencies : [libpurple_dep], + install : true, install_dir : PURPLE_PLUGINDIR) +devenv.append('PURPLE_PLUGIN_PATH', meson.current_build_dir()) --- a/libpurple/plugins/idle.c Sun Sep 11 02:09:40 2022 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,332 +0,0 @@
- * idle.c - I'dle Mak'er plugin for Purple
- * This file is part of Purple.
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * This program 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 2 of the License, or
- * (at your option) any later version.
- * 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 General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
-#include <glib/gi18n-lib.h>
-#include <gplugin-native.h>
-/* This plugin no longer depends on gtk */
-#define IDLE_PLUGIN_ID "core-idle"
-static GList *idled_accts = NULL;
-unidle_filter(PurpleAccount *acct)
- if (g_list_find(idled_accts, acct))
-idleable_filter(PurpleAccount *account)
- PurpleProtocol *protocol;
- protocol = purple_account_get_protocol(account);
- g_return_val_if_fail(protocol != NULL, FALSE);
- return PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, set_idle);
-set_idle_time(PurpleAccount *acct, int mins_idle)
- PurpleConnection *gc = purple_account_get_connection(acct);
- PurplePresence *presence = purple_account_get_presence(acct);
- purple_debug_info("idle",
- "setting idle time for %s to %d\n",
- purple_account_get_username(acct), mins_idle);
- t = time(NULL) - (60 * mins_idle); /* subtract seconds idle from current time */
- t = 0; /* time idle is irrelevant */
- purple_presence_set_idle(presence, mins_idle ? TRUE : FALSE, t);
-idle_action_ok(void *ignored, PurpleRequestFields *fields)
- int tm = purple_request_fields_get_integer(fields, "mins");
- PurpleAccount *acct = purple_request_fields_get_account(fields, "acct");
- /* only add the account to the GList if it's not already been idled */
- if (!unidle_filter(acct))
- purple_debug_misc("idle",
- "%s hasn't been idled yet; adding to list.\n",
- purple_account_get_username(acct));
- idled_accts = g_list_append(idled_accts, acct);
- set_idle_time(acct, tm);
-idle_all_action_ok(void *ignored, PurpleRequestFields *fields)
- PurpleAccountManager *manager = NULL;
- PurpleAccount *acct = NULL;
- int tm = purple_request_fields_get_integer(fields, "mins");
- manager = purple_account_manager_get_default();
- list = purple_account_manager_get_enabled(manager);
- for(iter = list; iter; iter = iter->next) {
- acct = (PurpleAccount *)(iter->data);
- if(acct && idleable_filter(acct)) {
- purple_debug_misc("idle", "Idling %s.\n",
- purple_account_get_username(acct));
- set_idle_time(acct, tm);
- if(!g_list_find(idled_accts, acct))
- idled_accts = g_list_append(idled_accts, acct);
-unidle_action_ok(void *ignored, PurpleRequestFields *fields)
- PurpleAccount *acct = purple_request_fields_get_account(fields, "acct");
- set_idle_time(acct, 0); /* unidle the account */
- /* once the account has been unidled it shouldn't be in the list */
- idled_accts = g_list_remove(idled_accts, acct);
-signing_off_cb(PurpleConnection *gc, void *data)
- PurpleAccount *account;
- account = purple_connection_get_account(gc);
- idled_accts = g_list_remove(idled_accts, account);
-/******************************************************************************
- *****************************************************************************/
-purple_idle_set_account_idle_time(G_GNUC_UNUSED GSimpleAction *action,
- G_GNUC_UNUSED GVariant *parameter,
- /* Use the super fancy request API */
- PurpleRequestFields *request;
- PurpleRequestFieldGroup *group;
- PurpleRequestField *field;
- group = purple_request_field_group_new(NULL);
- field = purple_request_field_account_new("acct", _("Account"), NULL);
- purple_request_field_account_set_filter(field, idleable_filter);
- purple_request_field_account_set_show_all(field, FALSE);
- purple_request_field_group_add_field(group, field);
- field = purple_request_field_int_new("mins", _("Minutes"), 10, 0, 9999);
- purple_request_field_group_add_field(group, field);
- request = purple_request_fields_new();
- purple_request_fields_add_group(request, group);
- purple_request_fields(data,
- _("Set Account Idle Time"),
- _("_Set"), G_CALLBACK(idle_action_ok),
-purple_idle_unset_account_idle_time(G_GNUC_UNUSED GSimpleAction *action,
- G_GNUC_UNUSED GVariant *parameter,
- PurpleRequestFields *request;
- PurpleRequestFieldGroup *group;
- PurpleRequestField *field;
- if (idled_accts == NULL)
- purple_notify_info(NULL, NULL, _("None of your accounts are idle."), NULL, NULL);
- group = purple_request_field_group_new(NULL);
- field = purple_request_field_account_new("acct", _("Account"), NULL);
- purple_request_field_account_set_filter(field, unidle_filter);
- purple_request_field_account_set_show_all(field, FALSE);
- purple_request_field_group_add_field(group, field);
- request = purple_request_fields_new();
- purple_request_fields_add_group(request, group);
- purple_request_fields(data,
- _("Unset Account Idle Time"),
- _("_Unset"), G_CALLBACK(unidle_action_ok),
-purple_idle_set_all_accounts_idle_time(G_GNUC_UNUSED GSimpleAction *action,
- G_GNUC_UNUSED GVariant *parameter,
- PurpleRequestFields *request;
- PurpleRequestFieldGroup *group;
- PurpleRequestField *field;
- group = purple_request_field_group_new(NULL);
- field = purple_request_field_int_new("mins", _("Minutes"), 10, 0, 9999);
- purple_request_field_group_add_field(group, field);
- request = purple_request_fields_new();
- purple_request_fields_add_group(request, group);
- purple_request_fields(data,
- _("Set Idle Time for All Accounts"),
- _("_Set"), G_CALLBACK(idle_all_action_ok),
-purple_idle_unset_all_accounts_idle_time(G_GNUC_UNUSED GSimpleAction *action,
- G_GNUC_UNUSED GVariant *parameter,
- G_GNUC_UNUSED gpointer data)
- /* freeing the list here will cause segfaults if the user idles an account
- * after the list is freed */
- g_list_foreach(idled_accts, (GFunc)set_idle_time, GINT_TO_POINTER(0));
- g_list_free(idled_accts);
-/******************************************************************************
- *****************************************************************************/
-static GPluginPluginInfo *
-idle_query(GError **error)
- GSimpleActionGroup *group = NULL;
- GActionEntry entries[] = {
- .name = "set-account-idle-time",
- .activate = purple_idle_set_account_idle_time,
- .name = "unset-account-idle-time",
- .activate = purple_idle_unset_account_idle_time,
- .name = "set-all-accounts-idle-time",
- .activate = purple_idle_set_all_accounts_idle_time,
- .name = "unset-all-accounts-idle-time",
- .activate = purple_idle_unset_all_accounts_idle_time,
- const gchar * const authors[] = {
- "Eric Warmenhoven <eric@warmenhoven.org>",
- group = g_simple_action_group_new();
- g_action_map_add_action_entries(G_ACTION_MAP(group), entries,
- G_N_ELEMENTS(entries), NULL);
- g_menu_append(menu, _("Set Account Idle Time"), "set-account-idle-time");
- g_menu_append(menu, _("Unset Account Idle Time"),
- "unset-account-idle-time");
- g_menu_append(menu, _("Set Idle Time for All Accounts"),
- "set-all-accounts-idle-time");
- g_menu_append(menu, _("Unset Idle Time for All Idled Accounts"),
- "unset-all-accounts-idle-time");
- return purple_plugin_info_new(
- /* This is a cultural reference. Dy'er Mak'er is a song by Led Zeppelin.
- If that doesn't translate well into your language, drop the 's before translating. */
- "name", N_("I'dle Mak'er"),
- "version", DISPLAY_VERSION,
- "category", N_("Utility"),
- "summary", N_("Allows you to hand-configure how long you've been idle"),
- "description", N_("Allows you to hand-configure how long you've been idle"),
- "website", PURPLE_WEBSITE,
- "abi-version", PURPLE_ABI_VERSION,
-idle_load(GPluginPlugin *plugin, GError **error)
- purple_signal_connect(purple_connections_get_handle(), "signing-off",
- G_CALLBACK(signing_off_cb), NULL);
-idle_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error)
- purple_idle_unset_all_accounts_idle_time(NULL, NULL, NULL);
-GPLUGIN_NATIVE_PLUGIN_DECLARE(idle);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/idle/idle.c Mon Sep 12 04:49:23 2022 -0500
@@ -0,0 +1,332 @@
+ * idle.c - I'dle Mak'er plugin for Purple + * This file is part of Purple. + * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * This program 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 2 of the License, or + * (at your option) any later version. + * 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 General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA +#include <glib/gi18n-lib.h> +#include <gplugin-native.h> +/* This plugin no longer depends on gtk */ +#define IDLE_PLUGIN_ID "core-idle" +static GList *idled_accts = NULL; +unidle_filter(PurpleAccount *acct) + if (g_list_find(idled_accts, acct)) +idleable_filter(PurpleAccount *account) + PurpleProtocol *protocol; + protocol = purple_account_get_protocol(account); + g_return_val_if_fail(protocol != NULL, FALSE); + return PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, set_idle); +set_idle_time(PurpleAccount *acct, int mins_idle) + PurpleConnection *gc = purple_account_get_connection(acct); + PurplePresence *presence = purple_account_get_presence(acct); + purple_debug_info("idle", + "setting idle time for %s to %d\n", + purple_account_get_username(acct), mins_idle); + t = time(NULL) - (60 * mins_idle); /* subtract seconds idle from current time */ + t = 0; /* time idle is irrelevant */ + purple_presence_set_idle(presence, mins_idle ? TRUE : FALSE, t); +idle_action_ok(void *ignored, PurpleRequestFields *fields) + int tm = purple_request_fields_get_integer(fields, "mins"); + PurpleAccount *acct = purple_request_fields_get_account(fields, "acct"); + /* only add the account to the GList if it's not already been idled */ + if (!unidle_filter(acct)) + purple_debug_misc("idle", + "%s hasn't been idled yet; adding to list.\n", + purple_account_get_username(acct)); + idled_accts = g_list_append(idled_accts, acct); + set_idle_time(acct, tm); +idle_all_action_ok(void *ignored, PurpleRequestFields *fields) + PurpleAccountManager *manager = NULL; + PurpleAccount *acct = NULL; + int tm = purple_request_fields_get_integer(fields, "mins"); + manager = purple_account_manager_get_default(); + list = purple_account_manager_get_enabled(manager); + for(iter = list; iter; iter = iter->next) { + acct = (PurpleAccount *)(iter->data); + if(acct && idleable_filter(acct)) { + purple_debug_misc("idle", "Idling %s.\n", + purple_account_get_username(acct)); + set_idle_time(acct, tm); + if(!g_list_find(idled_accts, acct)) + idled_accts = g_list_append(idled_accts, acct); +unidle_action_ok(void *ignored, PurpleRequestFields *fields) + PurpleAccount *acct = purple_request_fields_get_account(fields, "acct"); + set_idle_time(acct, 0); /* unidle the account */ + /* once the account has been unidled it shouldn't be in the list */ + idled_accts = g_list_remove(idled_accts, acct); +signing_off_cb(PurpleConnection *gc, void *data) + PurpleAccount *account; + account = purple_connection_get_account(gc); + idled_accts = g_list_remove(idled_accts, account); +/****************************************************************************** + *****************************************************************************/ +purple_idle_set_account_idle_time(G_GNUC_UNUSED GSimpleAction *action, + G_GNUC_UNUSED GVariant *parameter, + /* Use the super fancy request API */ + PurpleRequestFields *request; + PurpleRequestFieldGroup *group; + PurpleRequestField *field; + group = purple_request_field_group_new(NULL); + field = purple_request_field_account_new("acct", _("Account"), NULL); + purple_request_field_account_set_filter(field, idleable_filter); + purple_request_field_account_set_show_all(field, FALSE); + purple_request_field_group_add_field(group, field); + field = purple_request_field_int_new("mins", _("Minutes"), 10, 0, 9999); + purple_request_field_group_add_field(group, field); + request = purple_request_fields_new(); + purple_request_fields_add_group(request, group); + purple_request_fields(data, + _("Set Account Idle Time"), + _("_Set"), G_CALLBACK(idle_action_ok), +purple_idle_unset_account_idle_time(G_GNUC_UNUSED GSimpleAction *action, + G_GNUC_UNUSED GVariant *parameter, + PurpleRequestFields *request; + PurpleRequestFieldGroup *group; + PurpleRequestField *field; + if (idled_accts == NULL) + purple_notify_info(NULL, NULL, _("None of your accounts are idle."), NULL, NULL); + group = purple_request_field_group_new(NULL); + field = purple_request_field_account_new("acct", _("Account"), NULL); + purple_request_field_account_set_filter(field, unidle_filter); + purple_request_field_account_set_show_all(field, FALSE); + purple_request_field_group_add_field(group, field); + request = purple_request_fields_new(); + purple_request_fields_add_group(request, group); + purple_request_fields(data, + _("Unset Account Idle Time"), + _("_Unset"), G_CALLBACK(unidle_action_ok), +purple_idle_set_all_accounts_idle_time(G_GNUC_UNUSED GSimpleAction *action, + G_GNUC_UNUSED GVariant *parameter, + PurpleRequestFields *request; + PurpleRequestFieldGroup *group; + PurpleRequestField *field; + group = purple_request_field_group_new(NULL); + field = purple_request_field_int_new("mins", _("Minutes"), 10, 0, 9999); + purple_request_field_group_add_field(group, field); + request = purple_request_fields_new(); + purple_request_fields_add_group(request, group); + purple_request_fields(data, + _("Set Idle Time for All Accounts"), + _("_Set"), G_CALLBACK(idle_all_action_ok), +purple_idle_unset_all_accounts_idle_time(G_GNUC_UNUSED GSimpleAction *action, + G_GNUC_UNUSED GVariant *parameter, + G_GNUC_UNUSED gpointer data) + /* freeing the list here will cause segfaults if the user idles an account + * after the list is freed */ + g_list_foreach(idled_accts, (GFunc)set_idle_time, GINT_TO_POINTER(0)); + g_list_free(idled_accts); +/****************************************************************************** + *****************************************************************************/ +static GPluginPluginInfo * +idle_query(GError **error) + GSimpleActionGroup *group = NULL; + GActionEntry entries[] = { + .name = "set-account-idle-time", + .activate = purple_idle_set_account_idle_time, + .name = "unset-account-idle-time", + .activate = purple_idle_unset_account_idle_time, + .name = "set-all-accounts-idle-time", + .activate = purple_idle_set_all_accounts_idle_time, + .name = "unset-all-accounts-idle-time", + .activate = purple_idle_unset_all_accounts_idle_time, + const gchar * const authors[] = { + "Eric Warmenhoven <eric@warmenhoven.org>", + group = g_simple_action_group_new(); + g_action_map_add_action_entries(G_ACTION_MAP(group), entries, + G_N_ELEMENTS(entries), NULL); + g_menu_append(menu, _("Set Account Idle Time"), "set-account-idle-time"); + g_menu_append(menu, _("Unset Account Idle Time"), + "unset-account-idle-time"); + g_menu_append(menu, _("Set Idle Time for All Accounts"), + "set-all-accounts-idle-time"); + g_menu_append(menu, _("Unset Idle Time for All Idled Accounts"), + "unset-all-accounts-idle-time"); + return purple_plugin_info_new( + /* This is a cultural reference. Dy'er Mak'er is a song by Led Zeppelin. + If that doesn't translate well into your language, drop the 's before translating. */ + "name", N_("I'dle Mak'er"), + "version", DISPLAY_VERSION, + "category", N_("Utility"), + "summary", N_("Allows you to hand-configure how long you've been idle"), + "description", N_("Allows you to hand-configure how long you've been idle"), + "website", PURPLE_WEBSITE, + "abi-version", PURPLE_ABI_VERSION, +idle_load(GPluginPlugin *plugin, GError **error) + purple_signal_connect(purple_connections_get_handle(), "signing-off", + G_CALLBACK(signing_off_cb), NULL); +idle_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error) + purple_idle_unset_all_accounts_idle_time(NULL, NULL, NULL); +GPLUGIN_NATIVE_PLUGIN_DECLARE(idle); --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/idle/meson.build Mon Sep 12 04:49:23 2022 -0500
@@ -0,0 +1,7 @@
+idle = library('idle', 'idle.c', + c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="PurplePlugin-Idle"'], + dependencies : [libpurple_dep], + install : true, install_dir : PURPLE_PLUGINDIR) +devenv.append('PURPLE_PLUGIN_PATH', meson.current_build_dir()) --- a/libpurple/plugins/joinpart.c Sun Sep 11 02:09:40 2022 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,281 +0,0 @@
- * Purple is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * This program 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 2 of the License, or
- * (at your option) any later version.
- * 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 General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
-#include <glib/gi18n-lib.h>
-#include <gplugin-native.h>
-#define JOINPART_PLUGIN_ID "core-rlaager-joinpart"
-/* The number of minutes before a person is considered
- * to have stopped being part of active conversation. */
-#define DELAY_PREF "/plugins/core/joinpart/delay"
-#define DELAY_DEFAULT 10
-/* The number of people that must be in a room for this
- * plugin to have any effect */
-#define THRESHOLD_PREF "/plugins/core/joinpart/threshold"
-#define THRESHOLD_DEFAULT 20
-#define HIDE_BUDDIES_PREF "/plugins/core/joinpart/hide_buddies"
-#define HIDE_BUDDIES_DEFAULT FALSE
- PurpleConversation *conv;
-static guint joinpart_key_hash(const struct joinpart_key *key)
- g_return_val_if_fail(key != NULL, 0);
- return g_direct_hash(key->conv) + g_str_hash(key->user);
-static gboolean joinpart_key_equal(const struct joinpart_key *a, const struct joinpart_key *b)
- return (a->conv == b->conv) && purple_strequal(a->user, b->user);
-static void joinpart_key_destroy(struct joinpart_key *key)
- g_return_if_fail(key != NULL);
-static gboolean should_hide_notice(PurpleConversation *conv, const char *name,
- PurpleChatConversation *chat;
- struct joinpart_key key;
- g_return_val_if_fail(conv != NULL, FALSE);
- g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(conv), FALSE);
- /* If the room is small, don't bother. */
- chat = PURPLE_CHAT_CONVERSATION(conv);
- threshold = purple_prefs_get_int(THRESHOLD_PREF);
- if (purple_chat_conversation_get_users_count(chat) < threshold)
- if (!purple_prefs_get_bool(HIDE_BUDDIES_PREF) &&
- purple_blist_find_buddy(purple_conversation_get_account(conv), name))
- /* Only show the notice if the user has spoken recently. */
- key.user = (gchar *)name;
- last_said = g_hash_table_lookup(users, &key);
- int delay = purple_prefs_get_int(DELAY_PREF);
- if (delay > 0 && (*last_said + (delay * 60)) >= time(NULL))
-static gboolean chat_user_leaving_cb(PurpleConversation *conv, const char *name,
- const char *reason, GHashTable *users)
- return should_hide_notice(conv, name, users);
-static gboolean chat_user_joining_cb(PurpleConversation *conv, const char *name,
- PurpleChatUserFlags flags,
- return should_hide_notice(conv, name, users);
-static void received_chat_msg_cb(PurpleAccount *account, char *sender,
- char *message, PurpleConversation *conv,
- PurpleMessageFlags flags, GHashTable *users)
- struct joinpart_key key;
- /* Most of the time, we'll already have tracked the user,
- * so we avoid memory allocation here. */
- last_said = g_hash_table_lookup(users, &key);
- /* They just said something, so update the time. */
- struct joinpart_key *key2;
- key2 = g_new(struct joinpart_key, 1);
- key2->user = g_strdup(sender);
- last_said = g_new(time_t, 1);
- g_hash_table_insert(users, key2, last_said);
-static gboolean check_expire_time(struct joinpart_key *key,
- time_t *last_said, time_t *limit)
- purple_debug_info("joinpart", "Removing key for %s\n", key->user);
- return (*last_said < *limit);
-static gboolean clean_users_hash(GHashTable *users)
- int delay = purple_prefs_get_int(DELAY_PREF);
- time_t limit = time(NULL) - (60 * delay);
- g_hash_table_foreach_remove(users, (GHRFunc)check_expire_time, &limit);
-static PurplePluginPrefFrame *
-get_plugin_pref_frame(PurplePlugin *plugin)
- PurplePluginPrefFrame *frame;
- PurplePluginPref *ppref;
- g_return_val_if_fail(plugin != NULL, FALSE);
- frame = purple_plugin_pref_frame_new();
- ppref = purple_plugin_pref_new_with_label(_("Hide Joins/Parts"));
- purple_plugin_pref_frame_add(frame, ppref);
- ppref = purple_plugin_pref_new_with_name_and_label(THRESHOLD_PREF,
- /* Translators: Followed by an input request a number of people */
- _("For rooms with more than this many people"));
- purple_plugin_pref_set_bounds(ppref, 0, 1000);
- purple_plugin_pref_frame_add(frame, ppref);
- ppref = purple_plugin_pref_new_with_name_and_label(DELAY_PREF,
- _("If user has not spoken in this many minutes"));
- purple_plugin_pref_set_bounds(ppref, 0, 8 * 60); /* 8 Hours */
- purple_plugin_pref_frame_add(frame, ppref);
- ppref = purple_plugin_pref_new_with_name_and_label(HIDE_BUDDIES_PREF,
- _("Apply hiding rules to buddies"));
- purple_plugin_pref_frame_add(frame, ppref);
-static GPluginPluginInfo *
-join_part_query(GError **error)
- const gchar * const authors[] = {
- "Richard Laager <rlaager@pidgin.im>",
- return purple_plugin_info_new(
- "id", JOINPART_PLUGIN_ID,
- "name", N_("Join/Part Hiding"),
- "version", DISPLAY_VERSION,
- "category", N_("User interface"),
- "summary", N_("Hides extraneous join/part messages."),
- "description", N_("This plugin hides join/part messages in "
- "large rooms, except for those users actively "
- "taking part in a conversation."),
- "website", PURPLE_WEBSITE,
- "abi-version", PURPLE_ABI_VERSION,
- "pref-frame-cb", get_plugin_pref_frame,
-join_part_load(GPluginPlugin *plugin, GError **error)
- purple_prefs_add_none("/plugins/core/joinpart");
- purple_prefs_add_int(DELAY_PREF, DELAY_DEFAULT);
- purple_prefs_add_int(THRESHOLD_PREF, THRESHOLD_DEFAULT);
- purple_prefs_add_bool(HIDE_BUDDIES_PREF, HIDE_BUDDIES_DEFAULT);
- users = g_hash_table_new_full((GHashFunc)joinpart_key_hash,
- (GEqualFunc)joinpart_key_equal,
- (GDestroyNotify)joinpart_key_destroy,
- conv_handle = purple_conversations_get_handle();
- purple_signal_connect(conv_handle, "chat-user-joining", plugin,
- G_CALLBACK(chat_user_joining_cb), users);
- purple_signal_connect(conv_handle, "chat-user-leaving", plugin,
- G_CALLBACK(chat_user_leaving_cb), users);
- purple_signal_connect(conv_handle, "received-chat-msg", plugin,
- G_CALLBACK(received_chat_msg_cb), users);
- /* Cleanup every 5 minutes */
- id = g_timeout_add_seconds(60 * 5, (GSourceFunc)clean_users_hash, users);
- g_object_set_data(G_OBJECT(plugin), "users", users);
- g_object_set_data(G_OBJECT(plugin), "id", GUINT_TO_POINTER(id));
-join_part_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error)
- /* Destroy the hash table. The core plugin code will
- * disconnect the signals, and since Purple is single-threaded,
- * we don't have to worry one will be called after this. */
- g_hash_table_destroy((GHashTable *)g_object_get_data(G_OBJECT(plugin), "users"));
- g_source_remove(GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(plugin), "id")));
-GPLUGIN_NATIVE_PLUGIN_DECLARE(join_part)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/joinpart/joinpart.c Mon Sep 12 04:49:23 2022 -0500
@@ -0,0 +1,281 @@
+ * Purple is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * This program 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 2 of the License, or + * (at your option) any later version. + * 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 General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA +#include <glib/gi18n-lib.h> +#include <gplugin-native.h> +#define JOINPART_PLUGIN_ID "core-rlaager-joinpart" +/* The number of minutes before a person is considered + * to have stopped being part of active conversation. */ +#define DELAY_PREF "/plugins/core/joinpart/delay" +#define DELAY_DEFAULT 10 +/* The number of people that must be in a room for this + * plugin to have any effect */ +#define THRESHOLD_PREF "/plugins/core/joinpart/threshold" +#define THRESHOLD_DEFAULT 20 +#define HIDE_BUDDIES_PREF "/plugins/core/joinpart/hide_buddies" +#define HIDE_BUDDIES_DEFAULT FALSE + PurpleConversation *conv; +static guint joinpart_key_hash(const struct joinpart_key *key) + g_return_val_if_fail(key != NULL, 0); + return g_direct_hash(key->conv) + g_str_hash(key->user); +static gboolean joinpart_key_equal(const struct joinpart_key *a, const struct joinpart_key *b) + return (a->conv == b->conv) && purple_strequal(a->user, b->user); +static void joinpart_key_destroy(struct joinpart_key *key) + g_return_if_fail(key != NULL); +static gboolean should_hide_notice(PurpleConversation *conv, const char *name, + PurpleChatConversation *chat; + struct joinpart_key key; + g_return_val_if_fail(conv != NULL, FALSE); + g_return_val_if_fail(PURPLE_IS_CHAT_CONVERSATION(conv), FALSE); + /* If the room is small, don't bother. */ + chat = PURPLE_CHAT_CONVERSATION(conv); + threshold = purple_prefs_get_int(THRESHOLD_PREF); + if (purple_chat_conversation_get_users_count(chat) < threshold) + if (!purple_prefs_get_bool(HIDE_BUDDIES_PREF) && + purple_blist_find_buddy(purple_conversation_get_account(conv), name)) + /* Only show the notice if the user has spoken recently. */ + key.user = (gchar *)name; + last_said = g_hash_table_lookup(users, &key); + int delay = purple_prefs_get_int(DELAY_PREF); + if (delay > 0 && (*last_said + (delay * 60)) >= time(NULL)) +static gboolean chat_user_leaving_cb(PurpleConversation *conv, const char *name, + const char *reason, GHashTable *users) + return should_hide_notice(conv, name, users); +static gboolean chat_user_joining_cb(PurpleConversation *conv, const char *name, + PurpleChatUserFlags flags, + return should_hide_notice(conv, name, users); +static void received_chat_msg_cb(PurpleAccount *account, char *sender, + char *message, PurpleConversation *conv, + PurpleMessageFlags flags, GHashTable *users) + struct joinpart_key key; + /* Most of the time, we'll already have tracked the user, + * so we avoid memory allocation here. */ + last_said = g_hash_table_lookup(users, &key); + /* They just said something, so update the time. */ + struct joinpart_key *key2; + key2 = g_new(struct joinpart_key, 1); + key2->user = g_strdup(sender); + last_said = g_new(time_t, 1); + g_hash_table_insert(users, key2, last_said); +static gboolean check_expire_time(struct joinpart_key *key, + time_t *last_said, time_t *limit) + purple_debug_info("joinpart", "Removing key for %s\n", key->user); + return (*last_said < *limit); +static gboolean clean_users_hash(GHashTable *users) + int delay = purple_prefs_get_int(DELAY_PREF); + time_t limit = time(NULL) - (60 * delay); + g_hash_table_foreach_remove(users, (GHRFunc)check_expire_time, &limit); +static PurplePluginPrefFrame * +get_plugin_pref_frame(PurplePlugin *plugin) + PurplePluginPrefFrame *frame; + PurplePluginPref *ppref; + g_return_val_if_fail(plugin != NULL, FALSE); + frame = purple_plugin_pref_frame_new(); + ppref = purple_plugin_pref_new_with_label(_("Hide Joins/Parts")); + purple_plugin_pref_frame_add(frame, ppref); + ppref = purple_plugin_pref_new_with_name_and_label(THRESHOLD_PREF, + /* Translators: Followed by an input request a number of people */ + _("For rooms with more than this many people")); + purple_plugin_pref_set_bounds(ppref, 0, 1000); + purple_plugin_pref_frame_add(frame, ppref); + ppref = purple_plugin_pref_new_with_name_and_label(DELAY_PREF, + _("If user has not spoken in this many minutes")); + purple_plugin_pref_set_bounds(ppref, 0, 8 * 60); /* 8 Hours */ + purple_plugin_pref_frame_add(frame, ppref); + ppref = purple_plugin_pref_new_with_name_and_label(HIDE_BUDDIES_PREF, + _("Apply hiding rules to buddies")); + purple_plugin_pref_frame_add(frame, ppref); +static GPluginPluginInfo * +join_part_query(GError **error) + const gchar * const authors[] = { + "Richard Laager <rlaager@pidgin.im>", + return purple_plugin_info_new( + "id", JOINPART_PLUGIN_ID, + "name", N_("Join/Part Hiding"), + "version", DISPLAY_VERSION, + "category", N_("User interface"), + "summary", N_("Hides extraneous join/part messages."), + "description", N_("This plugin hides join/part messages in " + "large rooms, except for those users actively " + "taking part in a conversation."), + "website", PURPLE_WEBSITE, + "abi-version", PURPLE_ABI_VERSION, + "pref-frame-cb", get_plugin_pref_frame, +join_part_load(GPluginPlugin *plugin, GError **error) + purple_prefs_add_none("/plugins/core/joinpart"); + purple_prefs_add_int(DELAY_PREF, DELAY_DEFAULT); + purple_prefs_add_int(THRESHOLD_PREF, THRESHOLD_DEFAULT); + purple_prefs_add_bool(HIDE_BUDDIES_PREF, HIDE_BUDDIES_DEFAULT); + users = g_hash_table_new_full((GHashFunc)joinpart_key_hash, + (GEqualFunc)joinpart_key_equal, + (GDestroyNotify)joinpart_key_destroy, + conv_handle = purple_conversations_get_handle(); + purple_signal_connect(conv_handle, "chat-user-joining", plugin, + G_CALLBACK(chat_user_joining_cb), users); + purple_signal_connect(conv_handle, "chat-user-leaving", plugin, + G_CALLBACK(chat_user_leaving_cb), users); + purple_signal_connect(conv_handle, "received-chat-msg", plugin, + G_CALLBACK(received_chat_msg_cb), users); + /* Cleanup every 5 minutes */ + id = g_timeout_add_seconds(60 * 5, (GSourceFunc)clean_users_hash, users); + g_object_set_data(G_OBJECT(plugin), "users", users); + g_object_set_data(G_OBJECT(plugin), "id", GUINT_TO_POINTER(id)); +join_part_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error) + /* Destroy the hash table. The core plugin code will + * disconnect the signals, and since Purple is single-threaded, + * we don't have to worry one will be called after this. */ + g_hash_table_destroy((GHashTable *)g_object_get_data(G_OBJECT(plugin), "users")); + g_source_remove(GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(plugin), "id"))); +GPLUGIN_NATIVE_PLUGIN_DECLARE(join_part) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/joinpart/meson.build Mon Sep 12 04:49:23 2022 -0500
@@ -0,0 +1,7 @@
+joinpart = library('joinpart', 'joinpart.c', + c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="PurplePlugin-JoinPart"'], + dependencies : [libpurple_dep], + install : true, install_dir : PURPLE_PLUGINDIR) +devenv.append('PURPLE_PLUGIN_PATH', meson.current_build_dir()) --- a/libpurple/plugins/meson.build Sun Sep 11 02:09:40 2022 -0500
+++ b/libpurple/plugins/meson.build Mon Sep 12 04:49:23 2022 -0500
@@ -1,49 +1,12 @@
subdir('keychain-access')
subdir('notification-sound')
-autoaccept = library('autoaccept', 'autoaccept.c',
- c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="PurplePlugin-AutoAccept"'],
- dependencies : [libpurple_dep, glib],
- install : true, install_dir : PURPLE_PLUGINDIR)
-buddynote = library('buddynote', 'buddynote.c',
- c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="PurplePlugin-BuddyNote"'],
- dependencies : [libpurple_dep],
- install : true, install_dir : PURPLE_PLUGINDIR)
-idle = library('idle', 'idle.c',
- c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="PurplePlugin-Idle"'],
- dependencies : [libpurple_dep],
- install : true, install_dir : PURPLE_PLUGINDIR)
-joinpart = library('joinpart', 'joinpart.c',
- c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="PurplePlugin-JoinPart"'],
- dependencies : [libpurple_dep],
- install : true, install_dir : PURPLE_PLUGINDIR)
-psychic = library('psychic', 'psychic.c',
- c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="PurplePlugin-Psychic"'],
- dependencies : [libpurple_dep],
- install : true, install_dir : PURPLE_PLUGINDIR)
-statenotify = library('statenotify', 'statenotify.c',
- c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="PurplePlugin-StateNotify"'],
- dependencies : [libpurple_dep],
- install : true, install_dir : PURPLE_PLUGINDIR)
-purple_toast = library('purple-toast', 'purple-toast.c',
- c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="PurplePlugin-Toast"'],
- dependencies : [libpurple_dep],
- install : true, install_dir : PURPLE_PLUGINDIR)
-devenv.append('PURPLE_PLUGIN_PATH', meson.current_build_dir())
--- a/libpurple/plugins/psychic.c Sun Sep 11 02:09:40 2022 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
- * This program 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 2 of the
- * License, or (at your option) any later version.
- * 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
- * General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-#include <glib/gi18n-lib.h>
-#include <gplugin-native.h>
-#define PLUGIN_ID "core-psychic"
-#define PLUGIN_NAME N_("Psychic Mode")
-#define PLUGIN_CATEGORY N_("Utility")
-#define PLUGIN_SUMMARY N_("Psychic mode for incoming conversation")
-#define PLUGIN_DESC N_("Causes conversation windows to appear as other" \
- " users begin to message you. This works for" \
- " AIM, ICQ, XMPP, and Sametime")
-#define PLUGIN_AUTHORS { "Christopher O'Brien <siege@preoccupied.net>", NULL }
-#define PREFS_BASE "/plugins/core/psychic"
-#define PREF_BUDDIES PREFS_BASE "/buddies_only"
-#define PREF_NOTICE PREFS_BASE "/show_notice"
-#define PREF_STATUS PREFS_BASE "/activate_online"
-#define PREF_RAISE PREFS_BASE "/raise_conv"
-buddy_typing_cb(PurpleAccount *acct, const char *name, void *data) {
- PurpleConversation *im;
- PurpleConversationManager *manager;
- if(purple_prefs_get_bool(PREF_STATUS) &&
- ! purple_status_is_available(purple_account_get_active_status(acct))) {
- purple_debug_info("psychic", "not available, doing nothing\n");
- if(purple_prefs_get_bool(PREF_BUDDIES) &&
- ! purple_blist_find_buddy(acct, name)) {
- purple_debug_info("psychic", "not in blist, doing nothing\n");
- if(FALSE == purple_account_privacy_check(acct, name)) {
- purple_debug_info("psychic", "user %s is blocked\n", name);
- manager = purple_conversation_manager_get_default();
- im = purple_conversation_manager_find_im(manager, acct, name);
- purple_debug_info("psychic", "no previous conversation exists\n");
- im = purple_im_conversation_new(acct, name);
- if(purple_prefs_get_bool(PREF_RAISE)) {
- purple_conversation_present(im);
- if(purple_prefs_get_bool(PREF_NOTICE)) {
- /* This is a quote from Star Wars. You should probably not
- translate it literally. If you can't find a fitting cultural
- reference in your language, consider translating something
- like this instead: "You feel a new message coming." */
- purple_conversation_write_system_message(im,
- _("You feel a disturbance in the force..."),
- PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_ACTIVE_ONLY);
- /* Necessary because we may be creating a new conversation window. */
- purple_im_conversation_set_typing_state(PURPLE_IM_CONVERSATION(im),
-static PurplePluginPrefFrame *
-get_plugin_pref_frame(PurplePlugin *plugin) {
- PurplePluginPrefFrame *frame;
- PurplePluginPref *pref;
- frame = purple_plugin_pref_frame_new();
- pref = purple_plugin_pref_new_with_name(PREF_BUDDIES);
- purple_plugin_pref_set_label(pref, _("Only enable for users on"
- purple_plugin_pref_frame_add(frame, pref);
- pref = purple_plugin_pref_new_with_name(PREF_STATUS);
- purple_plugin_pref_set_label(pref, _("Disable when away"));
- purple_plugin_pref_frame_add(frame, pref);
- pref = purple_plugin_pref_new_with_name(PREF_NOTICE);
- purple_plugin_pref_set_label(pref, _("Display notification message in"
- purple_plugin_pref_frame_add(frame, pref);
- pref = purple_plugin_pref_new_with_name(PREF_RAISE);
- purple_plugin_pref_set_label(pref, _("Raise psychic conversations"));
- purple_plugin_pref_frame_add(frame, pref);
-static GPluginPluginInfo *
-psychic_query(GError **error) {
- const gchar * const authors[] = PLUGIN_AUTHORS;
- return purple_plugin_info_new(
- "version", DISPLAY_VERSION,
- "category", PLUGIN_CATEGORY,
- "summary", PLUGIN_SUMMARY,
- "description", PLUGIN_DESC,
- "website", PURPLE_WEBSITE,
- "abi-version", PURPLE_ABI_VERSION,
- "pref-frame-cb", get_plugin_pref_frame,
-psychic_load(GPluginPlugin *plugin, GError **error) {
- purple_prefs_add_none(PREFS_BASE);
- purple_prefs_add_bool(PREF_BUDDIES, FALSE);
- purple_prefs_add_bool(PREF_NOTICE, TRUE);
- purple_prefs_add_bool(PREF_STATUS, TRUE);
- convs_handle = purple_conversations_get_handle();
- purple_signal_connect(convs_handle, "buddy-typing", plugin,
- G_CALLBACK(buddy_typing_cb), NULL);
-psychic_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error) {
-GPLUGIN_NATIVE_PLUGIN_DECLARE(psychic)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/psychic/meson.build Mon Sep 12 04:49:23 2022 -0500
@@ -0,0 +1,7 @@
+psychic = library('psychic', 'psychic.c', + c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="PurplePlugin-Psychic"'], + dependencies : [libpurple_dep], + install : true, install_dir : PURPLE_PLUGINDIR) +devenv.append('PURPLE_PLUGIN_PATH', meson.current_build_dir()) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/psychic/psychic.c Mon Sep 12 04:49:23 2022 -0500
@@ -0,0 +1,167 @@
+ * This program 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 2 of the + * License, or (at your option) any later version. + * 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 + * General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +#include <glib/gi18n-lib.h> +#include <gplugin-native.h> +#define PLUGIN_ID "core-psychic" +#define PLUGIN_NAME N_("Psychic Mode") +#define PLUGIN_CATEGORY N_("Utility") +#define PLUGIN_SUMMARY N_("Psychic mode for incoming conversation") +#define PLUGIN_DESC N_("Causes conversation windows to appear as other" \ + " users begin to message you. This works for" \ + " AIM, ICQ, XMPP, and Sametime") +#define PLUGIN_AUTHORS { "Christopher O'Brien <siege@preoccupied.net>", NULL } +#define PREFS_BASE "/plugins/core/psychic" +#define PREF_BUDDIES PREFS_BASE "/buddies_only" +#define PREF_NOTICE PREFS_BASE "/show_notice" +#define PREF_STATUS PREFS_BASE "/activate_online" +#define PREF_RAISE PREFS_BASE "/raise_conv" +buddy_typing_cb(PurpleAccount *acct, const char *name, void *data) { + PurpleConversation *im; + PurpleConversationManager *manager; + if(purple_prefs_get_bool(PREF_STATUS) && + ! purple_status_is_available(purple_account_get_active_status(acct))) { + purple_debug_info("psychic", "not available, doing nothing\n"); + if(purple_prefs_get_bool(PREF_BUDDIES) && + ! purple_blist_find_buddy(acct, name)) { + purple_debug_info("psychic", "not in blist, doing nothing\n"); + if(FALSE == purple_account_privacy_check(acct, name)) { + purple_debug_info("psychic", "user %s is blocked\n", name); + manager = purple_conversation_manager_get_default(); + im = purple_conversation_manager_find_im(manager, acct, name); + purple_debug_info("psychic", "no previous conversation exists\n"); + im = purple_im_conversation_new(acct, name); + if(purple_prefs_get_bool(PREF_RAISE)) { + purple_conversation_present(im); + if(purple_prefs_get_bool(PREF_NOTICE)) { + /* This is a quote from Star Wars. You should probably not + translate it literally. If you can't find a fitting cultural + reference in your language, consider translating something + like this instead: "You feel a new message coming." */ + purple_conversation_write_system_message(im, + _("You feel a disturbance in the force..."), + PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_ACTIVE_ONLY); + /* Necessary because we may be creating a new conversation window. */ + purple_im_conversation_set_typing_state(PURPLE_IM_CONVERSATION(im), +static PurplePluginPrefFrame * +get_plugin_pref_frame(PurplePlugin *plugin) { + PurplePluginPrefFrame *frame; + PurplePluginPref *pref; + frame = purple_plugin_pref_frame_new(); + pref = purple_plugin_pref_new_with_name(PREF_BUDDIES); + purple_plugin_pref_set_label(pref, _("Only enable for users on" + purple_plugin_pref_frame_add(frame, pref); + pref = purple_plugin_pref_new_with_name(PREF_STATUS); + purple_plugin_pref_set_label(pref, _("Disable when away")); + purple_plugin_pref_frame_add(frame, pref); + pref = purple_plugin_pref_new_with_name(PREF_NOTICE); + purple_plugin_pref_set_label(pref, _("Display notification message in" + purple_plugin_pref_frame_add(frame, pref); + pref = purple_plugin_pref_new_with_name(PREF_RAISE); + purple_plugin_pref_set_label(pref, _("Raise psychic conversations")); + purple_plugin_pref_frame_add(frame, pref); +static GPluginPluginInfo * +psychic_query(GError **error) { + const gchar * const authors[] = PLUGIN_AUTHORS; + return purple_plugin_info_new( + "version", DISPLAY_VERSION, + "category", PLUGIN_CATEGORY, + "summary", PLUGIN_SUMMARY, + "description", PLUGIN_DESC, + "website", PURPLE_WEBSITE, + "abi-version", PURPLE_ABI_VERSION, + "pref-frame-cb", get_plugin_pref_frame, +psychic_load(GPluginPlugin *plugin, GError **error) { + purple_prefs_add_none(PREFS_BASE); + purple_prefs_add_bool(PREF_BUDDIES, FALSE); + purple_prefs_add_bool(PREF_NOTICE, TRUE); + purple_prefs_add_bool(PREF_STATUS, TRUE); + convs_handle = purple_conversations_get_handle(); + purple_signal_connect(convs_handle, "buddy-typing", plugin, + G_CALLBACK(buddy_typing_cb), NULL); +psychic_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error) { +GPLUGIN_NATIVE_PLUGIN_DECLARE(psychic) --- a/libpurple/plugins/purple-toast.c Sun Sep 11 02:09:40 2022 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,239 +0,0 @@
- * Pidgin is the legal property of its developers, whose names are too numerous
- * to list here. Please refer to the COPYRIGHT file distributed with this
- * This program 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 2 of the License, or
- * (at your option) any later version.
- * 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 General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
-#include <gplugin-native.h>
-/******************************************************************************
- *****************************************************************************/
-purple_toast_get_application(void) {
- static GApplication *application = NULL;
- if(G_UNLIKELY(application == NULL)) {
- application = g_application_get_default();
- if(application == NULL) {
- application = g_application_new(NULL, G_APPLICATION_FLAGS_NONE);
- g_application_register(application, NULL, NULL);
-purple_toast_show_notification(const gchar *title,
- GNotification *notification = g_notification_new(title);
- gchar *stripped = purple_markup_strip_html(body);
- g_notification_set_body(notification, stripped);
- g_notification_set_icon(notification, icon);
- g_application_send_notification(purple_toast_get_application(),
- g_object_unref(G_OBJECT(notification));
-purple_toast_find_icon(PurpleAccount *account,
- if(PURPLE_IS_BUDDY(buddy)) {
- PurpleBuddyIcon *buddy_icon = purple_buddy_get_icon(buddy);
- const gchar *filename = NULL;
- filename = purple_buddy_icon_get_full_path(buddy_icon);
- GFile *file = g_file_new_for_path(filename);
- icon = g_file_icon_new(file);
- PurpleImage *image = NULL;
- const gchar *path = NULL;
- image = purple_buddy_icons_find_account_icon(account);
- if(PURPLE_IS_IMAGE(image)) {
- path = purple_image_get_path(image);
- GFile *file = g_file_new_for_path(path);
- icon = g_file_icon_new(file);
- g_object_unref(G_OBJECT(file));
- g_object_unref(G_OBJECT(image));
- /* We should probably have a fallback, but we need a libpurple or
- * pidgin icon or something to make that happen.
-/******************************************************************************
- *****************************************************************************/
-purple_toast_im_message_received(PurpleAccount *account,
- PurpleConversation *conv,
- PurpleMessageFlags flags,
- PurpleBuddy *buddy = NULL;
- const gchar *title = NULL;
- buddy = purple_blist_find_buddy(account, sender);
- title = PURPLE_IS_BUDDY(buddy) ? purple_buddy_get_alias(buddy) : sender;
- icon = purple_toast_find_icon(account, buddy, sender);
- purple_toast_show_notification(title, message, icon);
- g_object_unref(G_OBJECT(icon));
-purple_toast_chat_message_received(PurpleAccount *account,
- PurpleConversation *conv,
- PurpleMessageFlags flags,
- PurpleBuddy *buddy = NULL;
- const gchar *chat_name = NULL, *from = NULL;
- /* figure out the title */
- chat_name = purple_conversation_get_name(PURPLE_CONVERSATION(conv));
- PurpleChat *chat = purple_blist_find_chat(account, chat_name);
- chat_name = purple_chat_get_name(chat);
- buddy = purple_blist_find_buddy(account, sender);
- if(PURPLE_IS_BUDDY(buddy)) {
- from = purple_buddy_get_alias(buddy);
- title = g_strdup_printf("%s : %s", chat_name, from);
- /* figure out the icon */
- icon = purple_toast_find_icon(account, buddy, sender);
- /* show the notification */
- purple_toast_show_notification(title, message, icon);
- /* clean up our memory */
- g_object_unref(G_OBJECT(icon));
-/******************************************************************************
- *****************************************************************************/
-static GPluginPluginInfo *
-purple_toast_query(G_GNUC_UNUSED GError **error) {
- const gchar * const authors[] = {
- "Gary Kramlich <grim@reaperworld.com>",
- return purple_plugin_info_new(
- "abi-version", PURPLE_ABI_VERSION,
- "name", "Purple Toast",
- "summary", "Toast notifications",
-purple_toast_load(GPluginPlugin *plugin, G_GNUC_UNUSED GError **error) {
- gpointer conv_handle = purple_conversations_get_handle();
- purple_signal_connect(conv_handle,
- G_CALLBACK(purple_toast_im_message_received),
- purple_signal_connect(conv_handle,
- G_CALLBACK(purple_toast_chat_message_received),
-purple_toast_unload(G_GNUC_UNUSED GPluginPlugin *plugin,
- G_GNUC_UNUSED gboolean shutdown,
- G_GNUC_UNUSED GError **error)
-GPLUGIN_NATIVE_PLUGIN_DECLARE(purple_toast)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/purple-toast/meson.build Mon Sep 12 04:49:23 2022 -0500
@@ -0,0 +1,7 @@
+purple_toast = library('purple-toast', 'purple-toast.c', + c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="PurplePlugin-Toast"'], + dependencies : [libpurple_dep], + install : true, install_dir : PURPLE_PLUGINDIR) +devenv.append('PURPLE_PLUGIN_PATH', meson.current_build_dir()) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/purple-toast/purple-toast.c Mon Sep 12 04:49:23 2022 -0500
@@ -0,0 +1,239 @@
+ * Pidgin is the legal property of its developers, whose names are too numerous + * to list here. Please refer to the COPYRIGHT file distributed with this + * This program 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 2 of the License, or + * (at your option) any later version. + * 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 General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA +#include <gplugin-native.h> +/****************************************************************************** + *****************************************************************************/ +purple_toast_get_application(void) { + static GApplication *application = NULL; + if(G_UNLIKELY(application == NULL)) { + application = g_application_get_default(); + if(application == NULL) { + application = g_application_new(NULL, G_APPLICATION_FLAGS_NONE); + g_application_register(application, NULL, NULL); +purple_toast_show_notification(const gchar *title, + GNotification *notification = g_notification_new(title); + gchar *stripped = purple_markup_strip_html(body); + g_notification_set_body(notification, stripped); + g_notification_set_icon(notification, icon); + g_application_send_notification(purple_toast_get_application(), + g_object_unref(G_OBJECT(notification)); +purple_toast_find_icon(PurpleAccount *account, + if(PURPLE_IS_BUDDY(buddy)) { + PurpleBuddyIcon *buddy_icon = purple_buddy_get_icon(buddy); + const gchar *filename = NULL; + filename = purple_buddy_icon_get_full_path(buddy_icon); + GFile *file = g_file_new_for_path(filename); + icon = g_file_icon_new(file); + PurpleImage *image = NULL; + const gchar *path = NULL; + image = purple_buddy_icons_find_account_icon(account); + if(PURPLE_IS_IMAGE(image)) { + path = purple_image_get_path(image); + GFile *file = g_file_new_for_path(path); + icon = g_file_icon_new(file); + g_object_unref(G_OBJECT(file)); + g_object_unref(G_OBJECT(image)); + /* We should probably have a fallback, but we need a libpurple or + * pidgin icon or something to make that happen. +/****************************************************************************** + *****************************************************************************/ +purple_toast_im_message_received(PurpleAccount *account, + PurpleConversation *conv, + PurpleMessageFlags flags, + PurpleBuddy *buddy = NULL; + const gchar *title = NULL; + buddy = purple_blist_find_buddy(account, sender); + title = PURPLE_IS_BUDDY(buddy) ? purple_buddy_get_alias(buddy) : sender; + icon = purple_toast_find_icon(account, buddy, sender); + purple_toast_show_notification(title, message, icon); + g_object_unref(G_OBJECT(icon)); +purple_toast_chat_message_received(PurpleAccount *account, + PurpleConversation *conv, + PurpleMessageFlags flags, + PurpleBuddy *buddy = NULL; + const gchar *chat_name = NULL, *from = NULL; + /* figure out the title */ + chat_name = purple_conversation_get_name(PURPLE_CONVERSATION(conv)); + PurpleChat *chat = purple_blist_find_chat(account, chat_name); + chat_name = purple_chat_get_name(chat); + buddy = purple_blist_find_buddy(account, sender); + if(PURPLE_IS_BUDDY(buddy)) { + from = purple_buddy_get_alias(buddy); + title = g_strdup_printf("%s : %s", chat_name, from); + /* figure out the icon */ + icon = purple_toast_find_icon(account, buddy, sender); + /* show the notification */ + purple_toast_show_notification(title, message, icon); + /* clean up our memory */ + g_object_unref(G_OBJECT(icon)); +/****************************************************************************** + *****************************************************************************/ +static GPluginPluginInfo * +purple_toast_query(G_GNUC_UNUSED GError **error) { + const gchar * const authors[] = { + "Gary Kramlich <grim@reaperworld.com>", + return purple_plugin_info_new( + "abi-version", PURPLE_ABI_VERSION, + "name", "Purple Toast", + "summary", "Toast notifications", +purple_toast_load(GPluginPlugin *plugin, G_GNUC_UNUSED GError **error) { + gpointer conv_handle = purple_conversations_get_handle(); + purple_signal_connect(conv_handle, + G_CALLBACK(purple_toast_im_message_received), + purple_signal_connect(conv_handle, + G_CALLBACK(purple_toast_chat_message_received), +purple_toast_unload(G_GNUC_UNUSED GPluginPlugin *plugin, + G_GNUC_UNUSED gboolean shutdown, + G_GNUC_UNUSED GError **error) +GPLUGIN_NATIVE_PLUGIN_DECLARE(purple_toast) --- a/libpurple/plugins/statenotify.c Sun Sep 11 02:09:40 2022 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,185 +0,0 @@
- * This program 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 2 of the
- * License, or (at your option) any later version.
- * 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
- * General Public License for more details.
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-#include <glib/gi18n-lib.h>
-#include <gplugin-native.h>
-#define STATENOTIFY_PLUGIN_ID "core-statenotify"
-write_status(PurpleBuddy *buddy, const char *message)
- PurpleAccount *account = NULL;
- PurpleConversation *im;
- PurpleConversationManager *manager;
- const gchar *buddy_name = NULL;
- account = purple_buddy_get_account(buddy);
- buddy_name = purple_buddy_get_name(buddy);
- manager = purple_conversation_manager_get_default();
- im = purple_conversation_manager_find_im(manager, account, buddy_name);
- /* Prevent duplicate notifications for buddies in multiple groups */
- if (buddy != purple_blist_find_buddy(account, buddy_name))
- who = purple_buddy_get_alias(buddy);
- escaped = g_markup_escape_text(who, -1);
- g_snprintf(buf, sizeof(buf), message, escaped);
- purple_conversation_write_system_message(im, buf,
- PURPLE_MESSAGE_ACTIVE_ONLY | PURPLE_MESSAGE_NO_LINKIFY);
-buddy_status_changed_cb(PurpleBuddy *buddy, PurpleStatus *old_status,
- PurpleStatus *status, void *data)
- gboolean available, old_available;
- if (!purple_status_is_exclusive(status) ||
- !purple_status_is_exclusive(old_status))
- available = purple_status_is_available(status);
- old_available = purple_status_is_available(old_status);
- if (purple_prefs_get_bool("/plugins/core/statenotify/notify_away")) {
- if (available && !old_available)
- write_status(buddy, _("%s is no longer away."));
- else if (!available && old_available)
- write_status(buddy, _("%s has gone away."));
-buddy_idle_changed_cb(PurpleBuddy *buddy, gboolean old_idle, gboolean idle,
- if (purple_prefs_get_bool("/plugins/core/statenotify/notify_idle")) {
- if (idle && !old_idle) {
- write_status(buddy, _("%s has become idle."));
- } else if (!idle && old_idle) {
- write_status(buddy, _("%s is no longer idle."));
-buddy_signon_cb(PurpleBuddy *buddy, void *data)
- if (purple_prefs_get_bool("/plugins/core/statenotify/notify_signon"))
- write_status(buddy, _("%s has signed on."));
-buddy_signoff_cb(PurpleBuddy *buddy, void *data)
- if (purple_prefs_get_bool("/plugins/core/statenotify/notify_signon"))
- write_status(buddy, _("%s has signed off."));
-static PurplePluginPrefFrame *
-get_plugin_pref_frame(PurplePlugin *plugin)
- PurplePluginPrefFrame *frame;
- PurplePluginPref *ppref;
- frame = purple_plugin_pref_frame_new();
- ppref = purple_plugin_pref_new_with_label(_("Notify When"));
- purple_plugin_pref_frame_add(frame, ppref);
- ppref = purple_plugin_pref_new_with_name_and_label("/plugins/core/statenotify/notify_away", _("Buddy Goes _Away"));
- purple_plugin_pref_frame_add(frame, ppref);
- ppref = purple_plugin_pref_new_with_name_and_label("/plugins/core/statenotify/notify_idle", _("Buddy Goes _Idle"));
- purple_plugin_pref_frame_add(frame, ppref);
- ppref = purple_plugin_pref_new_with_name_and_label("/plugins/core/statenotify/notify_signon", _("Buddy _Signs On/Off"));
- purple_plugin_pref_frame_add(frame, ppref);
-static GPluginPluginInfo *
-state_notify_query(GError **error)
- const gchar * const authors[] = {
- "Christian Hammond <chipx86@gnupdate.org>",
- return purple_plugin_info_new(
- "id", STATENOTIFY_PLUGIN_ID,
- "name", N_("Buddy State Notification"),
- "version", DISPLAY_VERSION,
- "category", N_("Notification"),
- "summary", N_("Notifies in a conversation window when a "
- "buddy goes or returns from away or idle."),
- "description", N_("Notifies in a conversation window when a "
- "buddy goes or returns from away or idle."),
- "website", PURPLE_WEBSITE,
- "abi-version", PURPLE_ABI_VERSION,
- "pref-frame-cb", get_plugin_pref_frame,
-state_notify_load(GPluginPlugin *plugin, GError **error)
- void *blist_handle = purple_blist_get_handle();
- purple_prefs_add_none("/plugins/core/statenotify");
- purple_prefs_add_bool("/plugins/core/statenotify/notify_away", TRUE);
- purple_prefs_add_bool("/plugins/core/statenotify/notify_idle", TRUE);
- purple_prefs_add_bool("/plugins/core/statenotify/notify_signon", TRUE);
- purple_signal_connect(blist_handle, "buddy-status-changed", plugin,
- G_CALLBACK(buddy_status_changed_cb), NULL);
- purple_signal_connect(blist_handle, "buddy-idle-changed", plugin,
- G_CALLBACK(buddy_idle_changed_cb), NULL);
- purple_signal_connect(blist_handle, "buddy-signed-on", plugin,
- G_CALLBACK(buddy_signon_cb), NULL);
- purple_signal_connect(blist_handle, "buddy-signed-off", plugin,
- G_CALLBACK(buddy_signoff_cb), NULL);
-state_notify_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error)
-GPLUGIN_NATIVE_PLUGIN_DECLARE(state_notify)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/statenotify/meson.build Mon Sep 12 04:49:23 2022 -0500
@@ -0,0 +1,7 @@
+statenotify = library('statenotify', 'statenotify.c', + c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="PurplePlugin-StateNotify"'], + dependencies : [libpurple_dep], + install : true, install_dir : PURPLE_PLUGINDIR) +devenv.append('PURPLE_PLUGIN_PATH', meson.current_build_dir()) --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/statenotify/statenotify.c Mon Sep 12 04:49:23 2022 -0500
@@ -0,0 +1,185 @@
+ * This program 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 2 of the + * License, or (at your option) any later version. + * 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 + * General Public License for more details. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +#include <glib/gi18n-lib.h> +#include <gplugin-native.h> +#define STATENOTIFY_PLUGIN_ID "core-statenotify" +write_status(PurpleBuddy *buddy, const char *message) + PurpleAccount *account = NULL; + PurpleConversation *im; + PurpleConversationManager *manager; + const gchar *buddy_name = NULL; + account = purple_buddy_get_account(buddy); + buddy_name = purple_buddy_get_name(buddy); + manager = purple_conversation_manager_get_default(); + im = purple_conversation_manager_find_im(manager, account, buddy_name); + /* Prevent duplicate notifications for buddies in multiple groups */ + if (buddy != purple_blist_find_buddy(account, buddy_name)) + who = purple_buddy_get_alias(buddy); + escaped = g_markup_escape_text(who, -1); + g_snprintf(buf, sizeof(buf), message, escaped); + purple_conversation_write_system_message(im, buf, + PURPLE_MESSAGE_ACTIVE_ONLY | PURPLE_MESSAGE_NO_LINKIFY); +buddy_status_changed_cb(PurpleBuddy *buddy, PurpleStatus *old_status, + PurpleStatus *status, void *data) + gboolean available, old_available; + if (!purple_status_is_exclusive(status) || + !purple_status_is_exclusive(old_status)) + available = purple_status_is_available(status); + old_available = purple_status_is_available(old_status); + if (purple_prefs_get_bool("/plugins/core/statenotify/notify_away")) { + if (available && !old_available) + write_status(buddy, _("%s is no longer away.")); + else if (!available && old_available) + write_status(buddy, _("%s has gone away.")); +buddy_idle_changed_cb(PurpleBuddy *buddy, gboolean old_idle, gboolean idle, + if (purple_prefs_get_bool("/plugins/core/statenotify/notify_idle")) { + if (idle && !old_idle) { + write_status(buddy, _("%s has become idle.")); + } else if (!idle && old_idle) { + write_status(buddy, _("%s is no longer idle.")); +buddy_signon_cb(PurpleBuddy *buddy, void *data) + if (purple_prefs_get_bool("/plugins/core/statenotify/notify_signon")) + write_status(buddy, _("%s has signed on.")); +buddy_signoff_cb(PurpleBuddy *buddy, void *data) + if (purple_prefs_get_bool("/plugins/core/statenotify/notify_signon")) + write_status(buddy, _("%s has signed off.")); +static PurplePluginPrefFrame * +get_plugin_pref_frame(PurplePlugin *plugin) + PurplePluginPrefFrame *frame; + PurplePluginPref *ppref; + frame = purple_plugin_pref_frame_new(); + ppref = purple_plugin_pref_new_with_label(_("Notify When")); + purple_plugin_pref_frame_add(frame, ppref); + ppref = purple_plugin_pref_new_with_name_and_label("/plugins/core/statenotify/notify_away", _("Buddy Goes _Away")); + purple_plugin_pref_frame_add(frame, ppref); + ppref = purple_plugin_pref_new_with_name_and_label("/plugins/core/statenotify/notify_idle", _("Buddy Goes _Idle")); + purple_plugin_pref_frame_add(frame, ppref); + ppref = purple_plugin_pref_new_with_name_and_label("/plugins/core/statenotify/notify_signon", _("Buddy _Signs On/Off")); + purple_plugin_pref_frame_add(frame, ppref); +static GPluginPluginInfo * +state_notify_query(GError **error) + const gchar * const authors[] = { + "Christian Hammond <chipx86@gnupdate.org>", + return purple_plugin_info_new( + "id", STATENOTIFY_PLUGIN_ID, + "name", N_("Buddy State Notification"), + "version", DISPLAY_VERSION, + "category", N_("Notification"), + "summary", N_("Notifies in a conversation window when a " + "buddy goes or returns from away or idle."), + "description", N_("Notifies in a conversation window when a " + "buddy goes or returns from away or idle."), + "website", PURPLE_WEBSITE, + "abi-version", PURPLE_ABI_VERSION, + "pref-frame-cb", get_plugin_pref_frame, +state_notify_load(GPluginPlugin *plugin, GError **error) + void *blist_handle = purple_blist_get_handle(); + purple_prefs_add_none("/plugins/core/statenotify"); + purple_prefs_add_bool("/plugins/core/statenotify/notify_away", TRUE); + purple_prefs_add_bool("/plugins/core/statenotify/notify_idle", TRUE); + purple_prefs_add_bool("/plugins/core/statenotify/notify_signon", TRUE); + purple_signal_connect(blist_handle, "buddy-status-changed", plugin, + G_CALLBACK(buddy_status_changed_cb), NULL); + purple_signal_connect(blist_handle, "buddy-idle-changed", plugin, + G_CALLBACK(buddy_idle_changed_cb), NULL); + purple_signal_connect(blist_handle, "buddy-signed-on", plugin, + G_CALLBACK(buddy_signon_cb), NULL); + purple_signal_connect(blist_handle, "buddy-signed-off", plugin, + G_CALLBACK(buddy_signoff_cb), NULL); +state_notify_unload(GPluginPlugin *plugin, gboolean shutdown, GError **error) +GPLUGIN_NATIVE_PLUGIN_DECLARE(state_notify)