Remove Finch
We are intending on moving Finch to its own repository, but that's going to
take some time and we have other things to do at the moment. So instead we're
removing it so that we can move forward with everything else immediately.
Testing Done:
Hung out with the turtles
Reviewed at https://reviews.imfreedom.org/r/3076/
--- a/AUTHORS Wed Apr 10 02:23:01 2024 -0500
+++ b/AUTHORS Wed Apr 10 22:19:38 2024 -0500
@@ -1,4 +1,4 @@
-Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
+Pidgin The Universal Chat Client ==========================================================================
For a complete list of all contributors, see the COPYRIGHT file.
--- a/COPYRIGHT Wed Apr 10 02:23:01 2024 -0500
+++ b/COPYRIGHT Wed Apr 10 22:19:38 2024 -0500
@@ -1,4 +1,4 @@
-Pidgin, Finch, and libpurple
This file is intended to be a comprehensive list of contributors to
this project. If you have contributed to this project then you deserve
--- a/ChangeLog Wed Apr 10 02:23:01 2024 -0500
+++ b/ChangeLog Wed Apr 10 22:19:38 2024 -0500
@@ -1,4 +1,4 @@
-Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
+Pidgin: The Universal Chat Client version 3.0.0 (??/??/????):
--- a/ChangeLog.API Wed Apr 10 02:23:01 2024 -0500
+++ b/ChangeLog.API Wed Apr 10 22:19:38 2024 -0500
@@ -1,7 +1,7 @@
-Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
+Pidgin: The Universal Chat Client -This file intends to list all changes to libpurple, Pidgin, and Finch's public
-API. We sometimes forget to add changes to this file--sorry.
+This file intends to list all changes to libpurple and Pidgin's public API. We +sometimes forget to add changes to this file--sorry. If your plugin fails to build with a new major version (e.g. 3.0.0) we
suggest checking this list first, in case a function was simply renamed.
@@ -1281,47 +1281,6 @@
- * FinchPluginInfo, inherits PurplePluginInfo
- * gntft.h file renamed to gntxfer.h
- * gnt_append_menu_action renamed to finch_append_menu_action
- * gnt_ui_init renamed to finch_ui_init
- * gnt_ui_uninit renamed to finch_ui_uninit
- * finch_accounts_get_ui_ops
- * finch_idle_get_ui_ops
- * finch_pounce_editor_show
- * finch_pounces_get_handle
- * finch_pounces_manager_hide
- * finch_pounces_manager_show
- * finch_sound_get_active_profile
- * finch_sound_get_profiles
- * finch_sound_get_ui_ops
- * finch_sound_is_enabled
- * finch_sound_set_active_profile
- * finch_sounds_show_all
- * ENTRY_CHAR renamed to GNT_ENTRY_CHAR
- * g_hash_table_duplicate renamed to gnt_hash_table_duplicate
- * GDupFunc renamed to GntDuplicateFunc
- * _GntProgressBarOrientation
--- a/NEWS Wed Apr 10 02:23:01 2024 -0500
+++ b/NEWS Wed Apr 10 22:19:38 2024 -0500
@@ -1,4 +1,4 @@
-Pidgin and Finch: The Pimpin' Penguin IM Clients That're Good for the Soul
+Pidgin: The Universal Chat Client Our development blog is available at: https://planet.pidgin.im
--- a/README Wed Apr 10 02:23:01 2024 -0500
+++ b/README Wed Apr 10 22:19:38 2024 -0500
@@ -1,6 +1,6 @@
[![pidgin wordmark](img/wordmark.png)](https://pidgin.im/)
-# Purple, Pidgin and Finch
libpurple is a library intended to be used by programmers seeking to write an
IM client that connects to many IM networks. It comes with support for Bonjour,
@@ -9,9 +9,6 @@
Pidgin is a graphical IM client written in C, which uses the GTK toolkit.
-Finch is a text-based IM client written in C, which uses
-[libgnt](https://keep.imfreedom.org/libgnt/libgnt).
These programs are not endorsed by, nor affiliated with, any proprietary
instant messaging company in any way.
@@ -61,13 +58,6 @@
-If you're working against Finch 3 you can use:
Obviously you're still free to install into your system directly, but then
you'll most likely end up having orphaned files laying around that our build
system doesn't know how to remove once they're removed from our code base. This
@@ -80,9 +70,8 @@
-libpurple, Pidgin, and Finch ship with a number of plugins, but you can find
-additional third party plugins at
-[pidgin.im/plugins](https://pidgin.im/plugins).
+libpurple and Pidgin ship with a number of plugins, but you can find additional +third party plugins at [pidgin.im/plugins](https://pidgin.im/plugins). --- a/convey.yaml Wed Apr 10 02:23:01 2024 -0500
+++ b/convey.yaml Wed Apr 10 22:19:38 2024 -0500
@@ -42,10 +42,6 @@
- meson setup build-docs -Ddoc=true
- ninja -C build-docs doc
- # - pushd build-docs/doc/reference/finch
- # - zip -9r finch3-docs.zip finch3
- pushd build-docs/doc/reference/pidgin
- zip -9r pidgin3-docs.zip pidgin3
--- a/doc/finch3.1.in Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,617 +0,0 @@
-.\" Copyright (c) 2006, Sadrul Habib Chowdhury <sadrul@users.sf.net>
-.\" This is free documentation; 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.
-.\" The GNU General Public License's references to "object code"
-.\" and "executables" are to be interpreted as the output of any
-.\" document formatting or typesetting system, including
-.\" intermediate and printed output.
-.\" This manual 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 manual; if not, write to the Free
-.\" Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
-Finch \- A Pimpin' Penguin console frontend to libpurple. Instant
-\fBfinch3 \fI[options]\fR
-\fBfinch3\fR is a console-based modular messaging client based on libpurple
-which is capable of connecting to AIM, XMPP, ICQ, IRC, SILC,
-Novell GroupWise, Lotus Sametime, Zephyr, Gadu-Gadu, and QQ all at once. It has
-many common features found in other clients, as well as many unique features.
-Finch is not endorsed by or affiliated with America Online, ICQ, or Microsoft.
-The following options are provided by \fBfinch3\fR using the standard GNU
-.B \-c, \-\-config=\fIDIR\fB
-Use \fIDIR\fR as the directory for config files instead of \fI~/.purple\fR.
-Print debugging messages to stderr and start with the \fBDebug\fR window. The
-messages shown in the \fBDebug\fR window are the same as the ones printed in
-Print this help and exit.
-Don't automatically login when \fBfinch3\fR starts. Sets all accounts to
-Display the version information window.
-You can use the following shortcuts (see the "Widget Actions" section for a more complete list):
-Bring up a list of available actions. You can use this list to access the
-accounts window, plugins window, preference window etc.
-Go to the previous window.
-Show the list of windows. You can select and jump to any window from the list.
-Close the current window.
-Start moving a window. Press the cursor keys to move the window. When you are
-done, press \fBEnter\fR or \fBEscape\fR.
-Start resizing a window. Press the cursor keys to resize the window. When you
-are done, press \fBEnter\fR or \fBEscape\fR.
-Dump the contents of the screen in HTML format.
-Move the position of the current window in the window list one place to the
-Move the position of the current window in the window list one place to the
-Refresh the windows. This is useful after resizing the terminal window.
-Jump to the 1st, 2nd ... 10th window.
-Jump to the next URGENT (highlighted) window.
-Jump to the previous URGENT (highlighted) window.
-.B Ctrl \+ o \fR or \fB F10
-Bring up the menu (if there is one) for a window.
-.B F11 \fR or \fB Ctrl \+ x
-Popup the context menu (if there is one) for the selected widget.
-Show a list of available key-bindings for the current widget in focus.
-Switch to the next workspace
-Switch to the previous workspace
-Tag (or untag) the current window
-Attached all the tagged windows to the current workspace
-Create a new workspace and switch to it
-\fIgntrc\fR: configuration file for gnt applications. Its location depends on the platform and/or the $XDG_CONFIG_HOME environment variable. If this environment variable is set, Finch will look for the gntrc file at \fB$XDG_CONFIG_HOME/gnt/gntrc\fR. Otherwise it will look for the file at \fB$HOME/.config/gnt/gntrc\fR and \fB%LOCALAPPDATA%\(rsgnt\(rsgntrc\fR, respectively depending on the platform.
-A sample file looks like:
-color-available = green; black
-color-away = blue; black
-color-idle = gray; black
-color-offline = red; black
-color-message-sent = cyan; default
-color-message-received = red; default
-color-message-highlight = black; green
-color-message-action = yellow; default
-color-timestamp = blue; default
-#See below for details on color
-# There is experimental mouse support
-# To use some custom window-manager
-wm = /usr/local/lib/gnt/s.so
-# There's also a custom window manager called irssi.so
-# Remember window-positions based on the titles (on by default)
-# Use borderless one-line high buttons
-# Workspaces are created simply by adding Workspace-X groups as follows:
-# window-names specifies that windows with these semi-colon separated names are placed
-window-names = buddylist;debug-window
-window-names = conversation-window
-# window-titles specifies that windows with these semi-colon separated titles are placed
-into this workspace. These are matched as substrings. Window titles take precedence over
-window-titles = Preferences
-# The RGB values range in [0, 1000]
-white = 1000; 1000; 1000
-darkgray = 256; 256; 256
-highlightd = black; gray
-shadow = black; darkgray
-# Remap some keys for GntEntry
-# Remap the up-arrow to the left-arrow
-# Remap the down-arrow to the right-arrow
-# Completely ignore the key 'q'
-# But the following will NOT work
-# Hitting 'space' will activate a button
-You can specify key-bindings for specific widgets. The following entries in
-\fIgntrc\fR correspond to the default keybindings for the actions:
-page-down = suggest-next-page
-page-up = suggest-prev-page
-# Following is the default binding for the context-menu
-# The following will let you open the context-menu in the buddylist with c-b
-The \fBc-\fR corresponds to the \fBControl\fR key. You can also use \fBctrl-\fR
-or \fBctr-\fR or \fBctl-\fR to indicate a combination. For alt-keys, you can use
-one of \fBa-\fR, \fBalt-\fR, \fBm-\fR or \fBmeta-\fR. You can also use
-\fBhome\fR, \fBend\fR, \fBleft\fR, \fBright\fR etc. keys.
-To unbind a key which has a default binding, you simply bind it to the empty string. For example, to unbind \fBAlt + q\fR from the Quit function, you would use:
-You can also specify key-bindings to trigger specific menuitems in windows. For example, the following entry in \fIgntrc\fR will bind \fBCtrl + t\fR to the 'Send IM...' item in the buddylist:
-The following is the list of IDs of the current menuitems in the buddylist:
-There is experimental mouse support. You can focus windows, activate buttons,
-select rows in a list, scroll using the wheel-scroll etc. Selecting text in a
-text-view copies it to the gnt clipboard. Mouse support is disabled by default,
-so you need to enable it in \fIgntrc\fR (see the sample above).
-The default window management is very limited. But it is possible to write
-custom window managers to suit your needs. There is a sample window-manager
-included (named \fIs.so\fR) which adds a little 'close-button' for the windows,
-removes the borders from the buddylist and pops up new windows in the middle of
-the screen, instead of at the upper-left corder. It is provided as a sample
-simple manager, but it should be possible to write more complex managers, and
-it's very possible that the window-manager API will need to be enhanced. Look at
-the sample \fIgntrc\fR file above to see how to select a window-manager.
-It is also possible to rebind the window-manager actions in \fIgntrc\fR, eg:
-a-c-j = window-scroll-down
-a-c-k = window-scroll-up
-# The following action is still incomplete, and doesn't have a default binding
-# Other actions: window-next-urgent, window-prev-urgent
-# For the sample custom window manager
-# For the irssi window manager
-.SH Conversation Commands
-There are a few helpful commands in addition to the regular commands. You can
-use these from any conversation to access other windows.
-for the accounts window.
-for the preferences window.
-FAQ for \fBfinch3\fR is located at
-\fIhttps://developer.pidgin.im/wiki/Using%20Finch\fR
-Known bugs are listed at
-\fIhttps://developer.pidgin.im/query?status=new&status=assigned&status=reopened&component=finch+%28gnt%2Fncurses%29&order=priority\fR
-Before sending a bug report, please verify that you have the latest
-version of \fBfinch3\fR and libpurple. Many bugs (major and minor) are
-fixed at each release, and if yours is out of date, the problem may already have
-If you fix a bug in \fBfinch3\fR (or otherwise enhance it), please submit a
-patch (using \fBhg diff > my.diff\fR against the latest version from the
-Mercurial repository) at \fIhttps://developer.pidgin.im/newticket\fR
-You are also encouraged to drop by at \fB#pidgin\fR on \fIirc.freenode.net\fR
-\fIhttps://pidgin.im/\fR
-\fIhttps://developer.pidgin.im/\fR
-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
-\fBWITHOUT ANY WARRANTY\fR; 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
-Sadrul Habib Chowdhury <\fIsadrul@users.sourceforge.net\fR>
-This manpage was written by Sadrul Habib Chowdhury
-<\fIsadrul@users.sourceforge.net\fR> and Dennis Ristuccia
-<\fIdennis@dennisr.net\fR>.
--- a/doc/meson.build Wed Apr 10 02:23:01 2024 -0500
+++ b/doc/meson.build Wed Apr 10 22:19:38 2024 -0500
@@ -9,11 +9,3 @@
install_dir : get_option('mandir') / 'man1')
- configuration : man_conf,
- install_dir : get_option('mandir') / 'man1')
--- a/doc/pidgin3.1.in Wed Apr 10 02:23:01 2024 -0500
+++ b/doc/pidgin3.1.in Wed Apr 10 22:19:38 2024 -0500
@@ -548,8 +548,6 @@
\fIhttps://developer.pidgin.im/\fR
This program is free software; you can redistribute it and/or modify
--- a/doc/reference/finch/finch.toml.in Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-version = "@PURPLE_MAJOR_VERSION@.@PURPLE_MINOR_VERSION@.@PURPLE_MICRO_VERSION@"
-browse_url = "https://keep.imfreedom.org/pidgin/pidgin/"
-repository_url = "https://keep.imfreedom.org/pidgin/pidgin/"
-website_url = "https://keep.imfreedom.org/pidgin/pidgin/"
-authors = "Pidgin Developers"
-license = "GPL-2.0-or-later"
-description = "Finch Universal Chat Client"
-dependencies = [ "GLib-2.0", "GObject-2.0", "GModule-2.0", "Gnt-3.0", "Purple-3.0" ]
- [dependencies."GLib-2.0"]
- description = "General-purpose, portable utility library."
- docs_url = "https://docs.gtk.org/glib/"
- [dependencies."GObject-2.0"]
- description = "The base type system library"
- docs_url = "https://docs.gtk.org/gobject/"
- [dependencies."GModule-2.0"]
- description = "Portable API for dynamically loading modules"
- docs_url = "https://docs.gtk.org/gmodule/"
- [dependencies."Gnt-3.0"]
- description = "GLib NCurses Toolkit"
- docs_url = "https://docs.imfreedom.org/gnt3/"
- [dependencies."Purple-3.0"]
- description = "Purple Universal Chat Library"
- docs_url = "https://docs.imfreedom.org/purple3/"
-show_index_summary = true
-show_class_hierarchy = true
-base_url = "https://keep.imfreedom.org/pidgin/pidgin/file/default/"
-# The same order will be used when generating the index
-urlmap_file = "urlmap.js"
--- a/doc/reference/finch/meson.build Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,37 +0,0 @@
-finch_doc_content_files = []
- finch_toml = configure_file(
- input : 'finch.toml.in',
- configuration : version_conf,
- install_dir : docs_dir / 'finch',
- finch_doc = custom_target('finch-doc',
- input : [ finch_toml, libfinch_gir[0] ],
- '--output-dir=@OUTPUT@',
- '--content-dir=@0@'.format(meson.current_source_dir()),
- '--add-include-path=@0@'.format(meson.global_build_root() / 'subprojects/birb/birb'),
- '--add-include-path=@0@'.format(meson.global_build_root() / 'subprojects/gplugin/gplugin'),
- '--add-include-path=@0@'.format(meson.global_build_root() / 'subprojects/libgnt'),
- '--add-include-path=@0@'.format(meson.project_build_root() / 'libpurple'),
- depends: [ libpurple_gir[0] ],
- depend_files : [ finch_doc_content_files ],
- build_by_default : true,
- install_dir : docs_dir,
--- a/doc/reference/finch/urlmap.js Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-// SPDX-FileCopyrightText: 2021 GNOME Foundation
-// SPDX-License-Identifier: LGPL-2.1-or-later
-// A map between namespaces and base URLs for their online documentation
- [ 'GLib', 'https://docs.gtk.org/glib/' ],
- [ 'GObject', 'https://docs.gtk.org/gobject/' ],
- [ 'Gnt3', 'https://docs.imfreedom.org/gnt3/' ],
- [ 'Purple3', 'https://docs.imfreedom.org/purple3/' ],
--- a/doc/reference/meson.build Wed Apr 10 02:23:01 2024 -0500
+++ b/doc/reference/meson.build Wed Apr 10 22:19:38 2024 -0500
@@ -9,13 +9,7 @@
-alias_target('doc', libpurple_doc, protocols_doc, pidgin_doc, finch_doc)
+alias_target('doc', libpurple_doc, protocols_doc, pidgin_doc) --- a/finch/finch.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,47 +0,0 @@
- * Finch 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
-int main(int argc, char *argv[])
- signal(SIGPIPE, SIG_IGN);
- g_set_application_name(_("Finch"));
- if (finch_start(&argc, &argv)) {
--- a/finch/finch.h.in Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
- * Finch 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, see <https://www.gnu.org/licenses/>.
-#ifndef __GI_SCANNER__ /* hide this bit from g-ir-scanner */
-# ifdef FINCH_COMPILATION
-# error "finch source files should not be including finch.h"
-# endif /* FINCH_COMPILATION */
-#endif /* __GI_SCANNER__ */
-#ifndef FINCH_GLOBAL_HEADER_INSIDE
-# define FINCH_GLOBAL_HEADER_INSIDE
-#endif /* FINCH_GLOBAL_HEADER_INSIDE */
-#undef FINCH_GLOBAL_HEADER_INSIDE
--- a/finch/finch_winres.rc.in Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION @PURPLE_MAJOR_VERSION@,@PURPLE_MINOR_VERSION@,@PURPLE_MICRO_VERSION@,0
- PRODUCTVERSION @PURPLE_MAJOR_VERSION@,@PURPLE_MINOR_VERSION@,@PURPLE_MICRO_VERSION@,0
- FILESUBTYPE VFT2_UNKNOWN
- VALUE "CompanyName", "The Pidgin developer community"
- VALUE "FileDescription", "Finch instant messenger"
- VALUE "FileVersion", "@PURPLE_VERSION@"
- VALUE "InternalName", "finch"
- VALUE "LegalCopyright", "Copyright (C) 1998-2014 The Pidgin developer community (See the COPYRIGHT file in the source distribution)."
- VALUE "OriginalFilename", "finch.exe"
- VALUE "ProductName", "Finch"
- VALUE "ProductVersion", "@PURPLE_VERSION@"
- VALUE "Translation", 0x409, 1200
--- a/finch/finchnotifications.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,398 +0,0 @@
- * Finch - Universal Text Chat Client
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- * Finch 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, see <https://www.gnu.org/licenses/>.
-#include <purpleconfig.h>
-#include <glib/gi18n-lib.h>
-#include <glib/gstdio.h>
-#include "finchnotifications.h"
-/*******************************************************************************
- ******************************************************************************/
-finch_notifications_update(GntTree *list, GListModel *model) {
- gnt_tree_remove_all(GNT_TREE(list));
- for(index = 0; index < g_list_model_get_n_items(model); index++) {
- PurpleNotification *notification = g_list_model_get_item(model, index);
- GntTreeRow *row = NULL;
- row = gnt_tree_create_row(list,
- purple_notification_get_title(notification));
- gnt_tree_add_row_last(list, notification, row, NULL);
-finch_notification_delete_notification(PurpleNotification *notification) {
- if(PURPLE_IS_NOTIFICATION(notification)) {
- PurpleNotificationManager *manager = NULL;
- purple_notification_delete(notification);
- manager = purple_notification_manager_get_default();
- purple_notification_manager_remove(manager, notification);
-/*******************************************************************************
- * Finch Notification Callbacks
- ******************************************************************************/
-finch_notification_delete(G_GNUC_UNUSED GntWidget *widget, gpointer data) {
- PurpleNotification *notification = g_object_get_data(data, "notification");
- finch_notification_delete_notification(notification);
- gnt_widget_destroy(GNT_WIDGET(data));
-finch_notification_reconnect_account(G_GNUC_UNUSED GntWidget *widget,
- PurpleNotification *notification = g_object_get_data(data, "notification");
- PurpleAccount *account = purple_notification_get_account(notification);
- if(PURPLE_IS_ACCOUNT(account)) {
- purple_account_connect(account);
- gnt_widget_destroy(GNT_WIDGET(data));
-finch_notification_reenable_account(G_GNUC_UNUSED GntWidget *widget,
- PurpleNotification *notification = g_object_get_data(data, "notification");
- PurpleAccount *account = purple_notification_get_account(notification);
- if(PURPLE_IS_ACCOUNT(account)) {
- purple_account_set_enabled(account, TRUE);
- gnt_widget_destroy(GNT_WIDGET(data));
-finch_notification_modify_account(G_GNUC_UNUSED GntWidget *widget,
- PurpleNotification *notification = g_object_get_data(data, "notification");
- PurpleAccount *account = purple_notification_get_account(notification);
- if(PURPLE_IS_ACCOUNT(account)) {
- finch_account_dialog_show(account);
- gnt_widget_destroy(GNT_WIDGET(data));
-finch_notification_contact_authorize(G_GNUC_UNUSED GntWidget *widget,
- PurpleAccount *account = NULL;
- PurpleNotification *notification = NULL;
- PurpleNotificationManager *manager = NULL;
- PurpleAuthorizationRequest *auth_request = NULL;
- const gchar *alias = NULL, *username = NULL;
- /* Get the notification and authorization request from the data. */
- notification = g_object_get_data(data, "notification");
- auth_request = purple_notification_get_data(notification);
- /* Accept the authorization request. */
- purple_authorization_request_accept(auth_request);
- /* Remove the notification from the manager. */
- manager = purple_notification_manager_get_default();
- purple_notification_manager_remove(manager, notification);
- /* Request the user to add the person they just authorized. */
- account = purple_authorization_request_get_account(auth_request);
- alias = purple_authorization_request_get_alias(auth_request);
- username = purple_authorization_request_get_username(auth_request);
- purple_blist_request_add_buddy(account, username, NULL, alias);
- /* Destroy the dialog. */
- gnt_widget_destroy(GNT_WIDGET(data));
-finch_notification_contact_deny(G_GNUC_UNUSED GntWidget *widget, gpointer data)
- PurpleNotification *notification = NULL;
- PurpleNotificationManager *manager = NULL;
- PurpleAuthorizationRequest *auth_request = NULL;
- /* Get the notification and authorization request from the data. */
- notification = g_object_get_data(data, "notification");
- auth_request = purple_notification_get_data(notification);
- /* Deny the request. */
- purple_authorization_request_deny(auth_request, NULL);
- /* Remove the notification from the manager. */
- manager = purple_notification_manager_get_default();
- purple_notification_manager_remove(manager, notification);
- /* Destroy the dialog. */
- gnt_widget_destroy(GNT_WIDGET(data));
-/*******************************************************************************
- * Finch Notification API
- ******************************************************************************/
-finch_notification_show(PurpleNotification *notification) {
- GntWidget *dialog = NULL, *label = NULL, *hbox = NULL, *button = NULL;
- PurpleAccount *account = NULL;
- PurpleNotificationType type;
- account = purple_notification_get_account(notification);
- dialog = gnt_box_new(FALSE, TRUE);
- gnt_box_set_toplevel(GNT_BOX(dialog), TRUE);
- gnt_box_set_alignment(GNT_BOX(dialog), GNT_ALIGN_MID);
- g_object_set_data(G_OBJECT(dialog), "notification", notification);
- label = gnt_label_new(purple_notification_get_title(notification));
- gnt_box_add_widget(GNT_BOX(dialog), label);
- hbox = gnt_box_new(FALSE, FALSE);
- type = purple_notification_get_notification_type(notification);
- data = purple_notification_get_data(notification);
- if(type == PURPLE_NOTIFICATION_TYPE_GENERIC) {
- gnt_box_set_title(GNT_BOX(dialog),
- purple_notification_get_title(notification));
- label = gnt_label_new(purple_notification_get_data(notification));
- gnt_box_add_widget(GNT_BOX(dialog), label);
- } else if(type == PURPLE_NOTIFICATION_TYPE_CONNECTION_ERROR) {
- PurpleConnectionErrorInfo *info = data;
- gnt_box_set_title(GNT_BOX(dialog), _("Connection Error"));
- /* Add the connection error reason. */
- label = gnt_label_new(info->description);
- gnt_box_add_widget(GNT_BOX(dialog), label);
- if(purple_account_get_enabled(account)) {
- button = gnt_button_new(_("Reconnect"));
- g_signal_connect(button, "activate",
- G_CALLBACK(finch_notification_reconnect_account),
- button = gnt_button_new(_("Re-enable"));
- g_signal_connect(button, "activate",
- G_CALLBACK(finch_notification_reenable_account),
- gnt_box_add_widget(GNT_BOX(hbox), button);
- button = gnt_button_new(_("Modify Account"));
- g_signal_connect(button, "activate",
- G_CALLBACK(finch_notification_modify_account),
- gnt_box_add_widget(GNT_BOX(hbox), button);
- } else if(type == PURPLE_NOTIFICATION_TYPE_AUTHORIZATION_REQUEST) {
- PurpleAuthorizationRequest *auth_request = NULL;
- const gchar *message = NULL;
- gnt_box_set_title(GNT_BOX(dialog), _("Authorization Request"));
- auth_request = purple_notification_get_data(notification);
- message = purple_authorization_request_get_message(auth_request);
- /* Add the message if we have one. */
- if(message != NULL && *message != '\0') {
- label = gnt_label_new(message);
- gnt_box_add_widget(GNT_BOX(dialog), label);
- button = gnt_button_new(_("Authorize"));
- g_signal_connect(button, "activate",
- G_CALLBACK(finch_notification_contact_authorize),
- gnt_box_add_widget(GNT_BOX(hbox), button);
- button = gnt_button_new(_("Deny"));
- g_signal_connect(button, "activate",
- G_CALLBACK(finch_notification_contact_deny), dialog);
- gnt_box_add_widget(GNT_BOX(hbox), button);
- gnt_box_add_widget(GNT_BOX(dialog), hbox);
- button = gnt_button_new(_("Delete"));
- g_signal_connect(button, "activate",
- G_CALLBACK(finch_notification_delete), dialog);
- gnt_box_add_widget(GNT_BOX(hbox), button);
- gnt_widget_show(dialog);
-/*******************************************************************************
- ******************************************************************************/
-finch_notifications_changed_cb(GListModel *model,
- G_GNUC_UNUSED guint position,
- G_GNUC_UNUSED guint removed,
- finch_notifications_update(data, model);
- gnt_widget_set_urgent(notifications.window);
-finch_notifications_open_cb(G_GNUC_UNUSED GntWidget *w,
- G_GNUC_UNUSED gpointer data)
- PurpleNotification *notification = NULL;
- notification = gnt_tree_get_selection_data(GNT_TREE(notifications.list));
- if(!PURPLE_IS_NOTIFICATION(notification)) {
- finch_notification_show(notification);
-finch_notifications_delete_cb(G_GNUC_UNUSED GntWidget *widget,
- G_GNUC_UNUSED gpointer data)
- PurpleNotification *notification = NULL;
- notification = gnt_tree_get_selection_data(GNT_TREE(notifications.list));
- finch_notification_delete_notification(notification);
-finch_notifications_activate_cb(G_GNUC_UNUSED GntWidget *w,
- G_GNUC_UNUSED gpointer data)
- PurpleNotification *notification = NULL;
- notification = gnt_tree_get_selection_data(GNT_TREE(notifications.list));
- finch_notification_show(notification);
-/*******************************************************************************
- ******************************************************************************/
-finch_notifications_window_show(void) {
- GListModel *model = NULL;
- if(notifications.window) {
- gnt_window_present(notifications.window);
- notifications.window = gnt_vbox_new(FALSE);
- gnt_box_set_toplevel(GNT_BOX(notifications.window), TRUE);
- gnt_box_set_fill(GNT_BOX(notifications.window), TRUE);
- gnt_box_set_title(GNT_BOX(notifications.window), _("Notifications"));
- gnt_box_set_alignment(GNT_BOX(notifications.window), GNT_ALIGN_MID);
- gnt_box_set_pad(GNT_BOX(notifications.window), 0);
- gnt_widget_set_name(notifications.window, "notifications");
- /* Create the box that lists all of the notifications. */
- notifications.list = gnt_tree_new_with_columns(1);
- gnt_tree_set_compare_func(GNT_TREE(notifications.list),
- purple_notification_compare);
- gnt_widget_set_has_border(notifications.list, FALSE);
- gnt_box_add_widget(GNT_BOX(notifications.window), notifications.list);
- g_signal_connect(notifications.list, "activate",
- G_CALLBACK(finch_notifications_activate_cb), NULL);
- /* Get the notification manager to get the model and populate the list. */
- model = purple_notification_manager_get_default_as_model();
- finch_notifications_update(GNT_TREE(notifications.list), model);
- g_signal_connect_object(model, "items-changed",
- G_CALLBACK(finch_notifications_changed_cb),
- notifications.list, 0);
- gnt_box_add_widget(GNT_BOX(notifications.window), gnt_line_new(FALSE));
- box = gnt_hbox_new(FALSE);
- gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_MID);
- gnt_box_set_fill(GNT_BOX(box), FALSE);
- wid = gnt_button_new(_("Open"));
- g_signal_connect(wid, "activate", G_CALLBACK(finch_notifications_open_cb),
- gnt_box_add_widget(GNT_BOX(box), wid);
- wid = gnt_button_new(_("Delete"));
- g_signal_connect(wid, "activate", G_CALLBACK(finch_notifications_delete_cb),
- gnt_box_add_widget(GNT_BOX(box), wid);
- gnt_box_add_widget(GNT_BOX(notifications.window), box);
- gnt_widget_show(notifications.window);
-finch_notifications_init(void) {
-finch_notifications_uninit(void) {
- g_clear_pointer(¬ifications.window, gnt_widget_destroy);
--- a/finch/finchnotifications.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
- * Finch - Universal Text Chat Client
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- * Finch 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, see <https://www.gnu.org/licenses/>.
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-#ifndef FINCH_NOTIFICATIONS_H
-#define FINCH_NOTIFICATIONS_H
- * finch_notifications_init:
- * Perform necessary initializations.
-void finch_notifications_init(void);
- * finch_notifications_uninit:
- * Perform necessary uninitialization.
-void finch_notifications_uninit(void);
- * finch_notifications_window_show:
- * Show the notifications window.
-void finch_notifications_window_show(void);
-#endif /* FINCH_NOTIFICATIONS_H */
--- a/finch/finchui.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,220 +0,0 @@
- * Finch - Universal Text Chat Client
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- * Finch 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, see <https://www.gnu.org/licenses/>.
-#define G_SETTINGS_ENABLE_BACKEND
-#include <gio/gsettingsbackend.h>
-#include "finchnotifications.h"
-#include "gntroomlist.h"
-G_DEFINE_FINAL_TYPE(FinchUi, finch_ui, PURPLE_TYPE_UI)
-/******************************************************************************
- * PurpleUi Implementation
- *****************************************************************************/
-finch_ui_prefs_init(G_GNUC_UNUSED PurpleUi *ui) {
-finch_ui_start(G_GNUC_UNUSED PurpleUi *ui, G_GNUC_UNUSED GError **error) {
-#ifdef _WIN32 /* TODO: don't change it when using FHS under win32 */
- gnt_set_config_dir(purple_config_dir());
- purple_prefs_add_none("/purple/gnt");
- finch_connections_init();
- purple_connections_set_ui_ops(finch_connections_get_ui_ops());
- /* Initialize the buddy list */
- purple_blist_set_ui(FINCH_TYPE_BUDDY_LIST);
- /* Now the conversations */
- finch_conversation_init();
- purple_conversations_set_ui_ops(finch_conv_get_ui_ops());
- purple_notify_set_ui_ops(finch_notify_get_ui_ops());
- purple_request_set_ui_ops(finch_request_get_ui_ops());
- purple_xfers_set_ui_ops(finch_xfers_get_ui_ops());
- purple_roomlist_set_ui_ops(finch_roomlist_get_ui_ops());
- finch_media_manager_init();
- gnt_register_action(_("Accounts"), finch_accounts_show_all);
- gnt_register_action(_("Buddy List"), finch_blist_show);
- gnt_register_action(_("Notifications"), finch_notifications_window_show);
- gnt_register_action(_("Debug Window"), finch_debug_window_show);
- gnt_register_action(_("File Transfers"), finch_xfer_dialog_show);
- gnt_register_action(_("Plugins"), finch_plugins_show_all);
- gnt_register_action(_("Room List"), finch_roomlist_show_all);
- gnt_register_action(_("Preferences"), finch_prefs_show_all);
- gnt_register_action(_("Statuses"), finch_savedstatus_show_all);
-finch_ui_stop(G_GNUC_UNUSED PurpleUi *ui) {
- finch_accounts_uninit();
- purple_connections_set_ui_ops(NULL);
- finch_connections_uninit();
- purple_blist_set_ui(G_TYPE_INVALID);
- purple_conversations_set_ui_ops(NULL);
- finch_conversation_uninit();
- purple_notify_set_ui_ops(NULL);
- purple_request_set_ui_ops(NULL);
- finch_request_uninit();
- purple_xfers_set_ui_ops(NULL);
- finch_roomlist_uninit();
- purple_roomlist_set_ui_ops(NULL);
- finch_media_manager_uninit();
- gnt_set_config_dir(NULL);
-finch_ui_get_settings_backend(G_GNUC_UNUSED PurpleUi *ui) {
- GSettingsBackend *backend = NULL;
- config = g_build_filename(purple_config_dir(), "finch3.ini", NULL);
- backend = g_keyfile_settings_backend_new(config, "/", NULL);
-static PurpleHistoryAdapter *
-finch_ui_get_history_adapter(G_GNUC_UNUSED PurpleUi *ui) {
- PurpleHistoryAdapter *adapter = NULL;
- g_mkdir_with_parents(purple_config_dir(), 0700);
- filename = g_build_filename(purple_config_dir(), "history.db", NULL);
- adapter = purple_sqlite_history_adapter_new(filename);
-/******************************************************************************
- * GObject Implementation
- *****************************************************************************/
-finch_ui_init(G_GNUC_UNUSED FinchUi *ui) {
-finch_ui_class_init(FinchUiClass *klass) {
- PurpleUiClass *ui_class = PURPLE_UI_CLASS(klass);
- ui_class->prefs_init = finch_ui_prefs_init;
- ui_class->start = finch_ui_start;
- ui_class->stop = finch_ui_stop;
- ui_class->get_settings_backend = finch_ui_get_settings_backend;
- ui_class->get_history_adapter = finch_ui_get_history_adapter;
-/******************************************************************************
- *****************************************************************************/
- "website", "https://pidgin.im",
- "support-website", "https://pidgin.im/contact/",
- "client-type", "console",
--- a/finch/finchui.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
- * Finch - Universal Text Chat Client
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- * Finch 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, see <https://www.gnu.org/licenses/>.
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-#define FINCH_TYPE_UI (finch_ui_get_type())
-G_DECLARE_FINAL_TYPE(FinchUi, finch_ui, FINCH, UI, PurpleUi)
- * Creates the [class@Purple.Ui] for finch.
- * Note: This isn't really useful outside of Finch itself.
-PurpleUi *finch_ui_new(void);
--- a/finch/gntaccount.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,956 +0,0 @@
- * Finch 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>
-static FinchAccountList accounts;
- PurpleAccount *account; /* NULL for a new account */
- GntWidget *require_password;
- GList *protocol_entries;
-/* This is necessary to close an edit-dialog when an account is deleted */
-static GList *accountdialogs;
-account_add(PurpleAccount *account) {
- PurpleContactInfo *info = PURPLE_CONTACT_INFO(account);
- GntTreeRow *row = NULL;
- row = gnt_tree_create_row(GNT_TREE(accounts.tree),
- purple_contact_info_get_username(info),
- purple_account_get_protocol_name(account));
- gnt_tree_add_choice(GNT_TREE(accounts.tree), account, row, NULL, NULL);
- gnt_tree_set_choice(GNT_TREE(accounts.tree), account,
- purple_account_get_enabled(account));
-edit_dialog_destroy(AccountEditDialog *dialog)
- accountdialogs = g_list_remove(accountdialogs, dialog);
- g_list_free(dialog->protocol_entries);
- g_list_free(dialog->split_entries);
-save_account_cb(AccountEditDialog *dialog)
- PurpleAccount *account;
- PurpleContactInfo *info = NULL;
- PurpleProtocol *protocol;
- /* XXX: Do some error checking first. */
- protocol = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol));
- /* Username && user-splits */
- value = gnt_entry_get_text(GNT_ENTRY(dialog->username));
- if (value == NULL || *value == '\0')
- purple_notify_error(NULL, _("Error"),
- dialog->account ? _("Account was not modified") :
- _("Account was not added"),
- _("Username of an account must be non-empty."),
- purple_request_cpar_from_account(dialog->account));
- username = g_string_new(value);
- GList *iter, *entries, *splits;
- splits = purple_protocol_get_user_splits(protocol);
- for (iter = splits, entries = dialog->split_entries;
- iter && entries; iter = iter->next, entries = entries->next)
- PurpleAccountUserSplit *split = iter->data;
- GntWidget *entry = entries->data;
- value = entry ? gnt_entry_get_text(GNT_ENTRY(entry)) : NULL;
- if (value == NULL || *value == '\0')
- value = purple_account_user_split_get_default_value(split);
- g_string_append_printf(username, "%c%s",
- purple_account_user_split_get_separator(split),
- g_list_free_full(splits,
- (GDestroyNotify)purple_account_user_split_destroy);
- if(dialog->account == NULL) {
- PurpleAccountManager *manager = purple_account_manager_get_default();
- account = purple_account_new(username->str, purple_protocol_get_id(protocol));
- info = PURPLE_CONTACT_INFO(account);
- purple_account_manager_add(manager, account);
- /* We don't have a cleanup function for this dialog, so we can really
- * only unref this new instance here. The pointer will remain valid as
- * the account manager adds a reference.
- g_object_unref(account);
- account = dialog->account;
- info = PURPLE_CONTACT_INFO(account);
- if (purple_account_is_disconnected(account)) {
- purple_account_set_protocol_id(account,
- purple_protocol_get_id(protocol));
- purple_contact_info_set_username(info, username->str);
- const char *old = purple_account_get_protocol_id(account);
- if (!purple_strequal(old, purple_protocol_get_id(protocol))) {
- purple_notify_error(NULL, _("Error"),
- _("Account was not modified"),
- _("The account's protocol cannot be "
- "changed while it is connected to the "
- purple_request_cpar_from_account(
- g_string_free(username, TRUE);
- oldproto = g_strdup(purple_normalize(account, purple_contact_info_get_username(info)));
- if (g_utf8_collate(oldproto, purple_normalize(account, username->str))) {
- purple_notify_error(NULL, _("Error"),
- _("Account was not modified"),
- _("The account's username cannot be "
- "changed while it is connected to the "
- purple_request_cpar_from_account(
- g_string_free(username, TRUE);
- purple_contact_info_set_username(info, username->str);
- g_string_free(username, TRUE);
- value = gnt_entry_get_text(GNT_ENTRY(dialog->alias));
- purple_contact_info_set_alias(info, value);
- /* Remember password and require password */
- purple_account_set_remember_password(account,
- gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->remember)));
- purple_account_set_require_password(account,
- gnt_check_box_get_checked(GNT_CHECK_BOX(dialog->require_password)));
- GList *iter, *entries, *opts;
- opts = purple_protocol_get_account_options(protocol);
- for (iter = opts, entries = dialog->protocol_entries;
- iter && entries; iter = iter->next, entries = entries->next)
- PurpleAccountOption *option = iter->data;
- GntWidget *entry = entries->data;
- PurplePrefType type = purple_account_option_get_pref_type(option);
- const char *setting = purple_account_option_get_setting(option);
- if (type == PURPLE_PREF_STRING)
- const char *value = gnt_entry_get_text(GNT_ENTRY(entry));
- purple_account_set_string(account, setting, value);
- else if (type == PURPLE_PREF_INT)
- const char *str = gnt_entry_get_text(GNT_ENTRY(entry));
- purple_account_set_int(account, setting, value);
- else if (type == PURPLE_PREF_BOOLEAN)
- gboolean value = gnt_check_box_get_checked(GNT_CHECK_BOX(entry));
- purple_account_set_bool(account, setting, value);
- else if (type == PURPLE_PREF_STRING_LIST)
- gchar *value = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(entry));
- purple_account_set_string(account, setting, value);
- g_assert_not_reached();
- g_list_free_full(opts, (GDestroyNotify)purple_account_option_destroy);
- /* XXX: Proxy options */
- if (accounts.window && accounts.tree) {
- gnt_tree_set_selected(GNT_TREE(accounts.tree), account);
- gnt_box_give_focus_to_child(GNT_BOX(accounts.window), accounts.tree);
- if (dialog->account == NULL) {
- /* This is a new account. Set it to the current status. */
- /* Xerox from gtkaccount.c :D */
- const PurpleSavedStatus *saved_status;
- saved_status = purple_savedstatus_get_current();
- if (saved_status != NULL) {
- purple_savedstatus_activate_for_account(saved_status, account);
- purple_account_set_enabled(account, TRUE);
- /* In case of a new account, the 'Accounts' window is updated from the
- * 'added' callback. In case of changes in an existing account, we need to
- * explicitly do it here.
- if (dialog->account != NULL && accounts.window) {
- gnt_tree_change_text(GNT_TREE(accounts.tree), dialog->account,
- 0, purple_contact_info_get_username(info));
- gnt_tree_change_text(GNT_TREE(accounts.tree), dialog->account,
- 1, purple_account_get_protocol_name(dialog->account));
- gnt_widget_destroy(dialog->window);
-update_user_splits(AccountEditDialog *dialog)
- PurpleProtocol *protocol;
- GList *iter, *entries, *splits;
- gboolean have_account = PURPLE_IS_ACCOUNT(dialog->account);
- gnt_box_remove_all(GNT_BOX(dialog->splits));
- g_list_free(dialog->split_entries);
- dialog->splits = gnt_vbox_new(FALSE);
- gnt_box_set_pad(GNT_BOX(dialog->splits), 0);
- gnt_box_set_fill(GNT_BOX(dialog->splits), TRUE);
- dialog->split_entries = NULL;
- protocol = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol));
- PurpleContactInfo *info = PURPLE_CONTACT_INFO(dialog->account);
- username = g_strdup(purple_contact_info_get_username(info));
- splits = purple_protocol_get_user_splits(protocol);
- for (iter = splits; iter; iter = iter->next)
- PurpleAccountUserSplit *split = iter->data;
- GntWidget *entry = NULL;
- if (!purple_account_user_split_is_constant(split)) {
- hbox = gnt_hbox_new(TRUE);
- gnt_box_add_widget(GNT_BOX(dialog->splits), hbox);
- buf = g_strdup_printf("%s:", purple_account_user_split_get_text(split));
- gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(buf));
- entry = gnt_entry_new(NULL);
- gnt_box_add_widget(GNT_BOX(hbox), entry);
- dialog->split_entries = g_list_append(dialog->split_entries, entry);
- for (iter = g_list_last(splits), entries = g_list_last(dialog->split_entries);
- iter && entries; iter = iter->prev, entries = entries->prev)
- GntWidget *entry = entries->data;
- PurpleAccountUserSplit *split = iter->data;
- const char *value = NULL;
- if(purple_account_user_split_get_reverse(split))
- s = strrchr(username, purple_account_user_split_get_separator(split));
- s = strchr(username, purple_account_user_split_get_separator(split));
- value = purple_account_user_split_get_default_value(split);
- if (value != NULL && entry != NULL)
- gnt_entry_set_text(GNT_ENTRY(entry), value);
- g_list_free_full(splits, (GDestroyNotify)purple_account_user_split_destroy);
- gnt_entry_set_text(GNT_ENTRY(dialog->username), username);
-add_account_options(AccountEditDialog *dialog)
- PurpleProtocol *protocol;
- PurpleAccount *account;
- gnt_box_remove_all(GNT_BOX(dialog->protocols));
- dialog->protocols = vbox = gnt_vbox_new(FALSE);
- gnt_box_set_pad(GNT_BOX(vbox), 0);
- gnt_box_set_alignment(GNT_BOX(vbox), GNT_ALIGN_LEFT);
- gnt_box_set_fill(GNT_BOX(vbox), TRUE);
- g_clear_list(&dialog->protocol_entries, NULL);
- vbox = dialog->protocols;
- protocol = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol));
- account = dialog->account;
- opts = purple_protocol_get_account_options(protocol);
- for (iter = opts; iter; iter = iter->next)
- PurpleAccountOption *option = iter->data;
- PurplePrefType type = purple_account_option_get_pref_type(option);
- box = gnt_hbox_new(TRUE);
- gnt_box_set_pad(GNT_BOX(box), 0);
- gnt_box_add_widget(GNT_BOX(vbox), box);
- if (type == PURPLE_PREF_BOOLEAN)
- GntWidget *widget = gnt_check_box_new(purple_account_option_get_text(option));
- gnt_box_add_widget(GNT_BOX(box), widget);
- dialog->protocol_entries = g_list_append(dialog->protocol_entries, widget);
- gnt_check_box_set_checked(GNT_CHECK_BOX(widget),
- purple_account_get_bool(account,
- purple_account_option_get_setting(option),
- purple_account_option_get_default_bool(option)));
- gnt_check_box_set_checked(GNT_CHECK_BOX(widget),
- purple_account_option_get_default_bool(option));
- gnt_box_add_widget(GNT_BOX(box),
- gnt_label_new(purple_account_option_get_text(option)));
- if (type == PURPLE_PREF_STRING_LIST)
- GntWidget *combo = gnt_combo_box_new();
- GList *opt_iter = purple_account_option_get_list(option);
- const char *dv = purple_account_option_get_default_list_value(option);
- const char *active = dv;
- active = purple_account_get_string(account,
- purple_account_option_get_setting(option), dv);
- gnt_box_add_widget(GNT_BOX(box), combo);
- dialog->protocol_entries = g_list_append(dialog->protocol_entries, combo);
- for ( ; opt_iter; opt_iter = opt_iter->next)
- PurpleKeyValuePair *kvp = opt_iter->data;
- gnt_combo_box_add_data(GNT_COMBO_BOX(combo), kvp->value, kvp->key);
- if (purple_strequal(kvp->value, active))
- gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), kvp->value);
- GntWidget *entry = gnt_entry_new(NULL);
- gnt_box_add_widget(GNT_BOX(box), entry);
- dialog->protocol_entries = g_list_append(dialog->protocol_entries, entry);
- if (type == PURPLE_PREF_STRING)
- const char *dv = purple_account_option_get_default_string(option);
- gnt_entry_set_text(GNT_ENTRY(entry),
- purple_account_get_string(account,
- purple_account_option_get_setting(option), dv));
- gnt_entry_set_text(GNT_ENTRY(entry), dv);
- else if (type == PURPLE_PREF_INT)
- int value = purple_account_option_get_default_int(option);
- value = purple_account_get_int(account,
- purple_account_option_get_setting(option), value);
- g_snprintf(str, sizeof(str), "%d", value);
- gnt_entry_set_flag(GNT_ENTRY(entry), GNT_ENTRY_FLAG_INT);
- gnt_entry_set_text(GNT_ENTRY(entry), str);
- g_assert_not_reached();
- g_list_free_full(opts, (GDestroyNotify)purple_account_option_destroy);
-update_user_options(AccountEditDialog *dialog)
- PurpleProtocol *protocol = NULL;
- PurpleProtocolOptions options;
- protocol = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(dialog->protocol));
- options = purple_protocol_get_options(protocol);
- if(dialog->remember == NULL) {
- dialog->remember = gnt_check_box_new(_("Remember password"));
- if(dialog->require_password == NULL) {
- dialog->require_password = gnt_check_box_new(_("Require a password "
- gnt_widget_set_visible(dialog->require_password,
- options & OPT_PROTO_PASSWORD_OPTIONAL);
- gboolean remember_password = FALSE;
- gboolean require_password = FALSE;
- purple_account_get_remember_password(dialog->account);
- gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->remember),
- require_password = purple_account_get_require_password(dialog->account);
- gnt_check_box_set_checked(GNT_CHECK_BOX(dialog->require_password),
-protocol_changed_cb(G_GNUC_UNUSED GntWidget *combo,
- G_GNUC_UNUSED PurpleProtocol *old,
- G_GNUC_UNUSED PurpleProtocol *new,
- AccountEditDialog *dialog)
- update_user_splits(dialog);
- add_account_options(dialog);
- update_user_options(dialog); /* This may not be necessary here */
- gnt_box_readjust(GNT_BOX(dialog->window));
- gnt_widget_draw(dialog->window);
-edit_account(PurpleAccount *account)
- GntWidget *window, *hbox;
- GntWidget *combo, *button, *entry;
- AccountEditDialog *dialog;
- PurpleProtocol *protocol;
- PurpleProtocolManager *protocol_manager = NULL;
- for (iter = accountdialogs; iter; iter = iter->next)
- AccountEditDialog *dlg = iter->data;
- if (dlg->account == account)
- protocol_manager = purple_protocol_manager_get_default();
- list = purple_protocol_manager_get_all(protocol_manager);
- purple_notify_error(NULL, _("Error"),
- _("There are no protocols installed."),
- _("(You probably forgot to 'make install'.)"),
- purple_request_cpar_from_account(account));
- dialog = g_new0(AccountEditDialog, 1);
- accountdialogs = g_list_prepend(accountdialogs, dialog);
- dialog->window = window = gnt_vbox_new(FALSE);
- dialog->account = account;
- gnt_box_set_toplevel(GNT_BOX(window), TRUE);
- gnt_box_set_title(GNT_BOX(window), account ? _("Modify Account") : _("New Account"));
- gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
- gnt_box_set_pad(GNT_BOX(window), 0);
- gnt_widget_set_name(window, "edit-account");
- gnt_box_set_fill(GNT_BOX(window), TRUE);
- hbox = gnt_hbox_new(TRUE);
- gnt_box_set_pad(GNT_BOX(hbox), 0);
- gnt_box_add_widget(GNT_BOX(window), hbox);
- dialog->protocol = combo = gnt_combo_box_new();
- for (iter = list; iter; iter = iter->next)
- gnt_combo_box_add_data(GNT_COMBO_BOX(combo), iter->data,
- purple_protocol_get_name(PURPLE_PROTOCOL(iter->data)));
- protocol = purple_account_get_protocol(account);
- if (account && protocol)
- gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), protocol);
- gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), list->data);
- g_signal_connect(G_OBJECT(combo), "selection-changed", G_CALLBACK(protocol_changed_cb), dialog);
- gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Protocol:")));
- gnt_box_add_widget(GNT_BOX(hbox), combo);
- hbox = gnt_hbox_new(TRUE);
- gnt_box_set_pad(GNT_BOX(hbox), 0);
- gnt_box_add_widget(GNT_BOX(window), hbox);
- dialog->username = entry = gnt_entry_new(NULL);
- gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Username:")));
- gnt_box_add_widget(GNT_BOX(hbox), entry);
- update_user_splits(dialog);
- gnt_box_add_widget(GNT_BOX(window), dialog->splits);
- hbox = gnt_hbox_new(TRUE);
- gnt_box_set_pad(GNT_BOX(hbox), 0);
- gnt_box_add_widget(GNT_BOX(window), hbox);
- dialog->alias = entry = gnt_entry_new(NULL);
- gnt_box_add_widget(GNT_BOX(hbox), gnt_label_new(_("Alias:")));
- gnt_box_add_widget(GNT_BOX(hbox), entry);
- if(PURPLE_IS_ACCOUNT(account)) {
- PurpleContactInfo *info = PURPLE_CONTACT_INFO(account);
- const char *alias = purple_contact_info_get_alias(info);
- gnt_entry_set_text(GNT_ENTRY(entry), alias);
- update_user_options(dialog);
- gnt_box_add_widget(GNT_BOX(window), dialog->remember);
- gnt_box_add_widget(GNT_BOX(window), dialog->require_password);
- gnt_box_add_widget(GNT_BOX(window), gnt_line_new(FALSE));
- add_account_options(dialog);
- gnt_box_add_widget(GNT_BOX(window), dialog->protocols);
- /* TODO: Add proxy options */
- hbox = gnt_hbox_new(FALSE);
- gnt_box_add_widget(GNT_BOX(window), hbox);
- gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID);
- button = gnt_button_new(_("Cancel"));
- gnt_box_add_widget(GNT_BOX(hbox), button);
- g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), window);
- button = gnt_button_new(_("Save"));
- gnt_box_add_widget(GNT_BOX(hbox), button);
- g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(save_account_cb), dialog);
- g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(edit_dialog_destroy), dialog);
- gnt_widget_show(window);
- gnt_box_readjust(GNT_BOX(window));
- gnt_widget_draw(window);
-add_account_cb(G_GNUC_UNUSED GntWidget *widget, G_GNUC_UNUSED gpointer data)
-modify_account_cb(G_GNUC_UNUSED GntWidget *widget, GntTree *tree)
- PurpleAccount *account = gnt_tree_get_selection_data(tree);
-really_delete_account(PurpleAccount *account)
- PurpleNotificationManager *manager = NULL;
- for (iter = accountdialogs; iter; iter = iter->next)
- AccountEditDialog *dlg = iter->data;
- if (dlg->account == account)
- gnt_widget_destroy(dlg->window);
- manager = purple_notification_manager_get_default();
- purple_notification_manager_remove_with_account(manager, account, TRUE);
- purple_accounts_delete(account);
-delete_account_cb(G_GNUC_UNUSED GntWidget *widget, GntTree *tree)
- PurpleAccount *account = NULL;
- PurpleContactInfo *info = NULL;
- account = gnt_tree_get_selection_data(tree);
- if(!PURPLE_IS_ACCOUNT(account)) {
- info = PURPLE_CONTACT_INFO(account);
- prompt = g_strdup_printf(_("Are you sure you want to delete %s?"),
- purple_contact_info_get_username(info));
- purple_request_action(account, _("Delete Account"), prompt, NULL,
- PURPLE_DEFAULT_ACTION_NONE,
- purple_request_cpar_from_account(account), account, 2,
- _("Delete"), really_delete_account, _("Cancel"), NULL);
-account_toggled(GntWidget *widget, void *key, G_GNUC_UNUSED gpointer data)
- PurpleAccount *account = key;
- gboolean enabled = gnt_tree_get_choice(GNT_TREE(widget), key);
- purple_savedstatus_activate_for_account(purple_savedstatus_get_current(),
- purple_account_set_enabled(account, enabled);
-account_list_key_pressed_cb(GntWidget *widget, const char *text,
- G_GNUC_UNUSED gpointer data)
- GntTree *tree = GNT_TREE(widget);
- PurpleAccountManager *manager = NULL;
- GListModel *manager_model = NULL;
- PurpleAccount *account = gnt_tree_get_selection_data(tree);
- move = 2; /* XXX: This seems to be a bug in libpurple */
- manager = purple_account_manager_get_default();
- manager_model = G_LIST_MODEL(manager);
- count = g_list_model_get_n_items(manager_model);
- for(pos = 0; pos < count; pos++) {
- PurpleAccount *acct = g_list_model_get_item(manager_model, pos);
- pos = (move + pos + count + 1) % (count + 1);
- purple_account_manager_reorder(manager, account, pos);
- /* I don't like this, but recreating the entire list seems to be
- * the easiest way of doing it */
- gnt_tree_remove_all(tree);
- for(pos = 0; pos < count; pos++) {
- PurpleAccount *account = g_list_model_get_item(manager_model, pos);
- g_object_unref(account);
- gnt_tree_set_selected(tree, account);
-reset_accounts_win(G_GNUC_UNUSED GntWidget *widget,
- G_GNUC_UNUSED gpointer data)
- accounts.window = NULL;
-finch_accounts_show_all(void)
- GListModel *manager_model = NULL;
- GntWidget *box, *button;
- gnt_window_present(accounts.window);
- accounts.window = gnt_vbox_new(FALSE);
- gnt_box_set_toplevel(GNT_BOX(accounts.window), TRUE);
- gnt_box_set_title(GNT_BOX(accounts.window), _("Accounts"));
- gnt_box_set_pad(GNT_BOX(accounts.window), 0);
- gnt_box_set_alignment(GNT_BOX(accounts.window), GNT_ALIGN_MID);
- gnt_widget_set_name(accounts.window, "accounts");
- gnt_box_add_widget(GNT_BOX(accounts.window),
- gnt_label_new(_("You can enable/disable accounts from the following list.")));
- gnt_box_add_widget(GNT_BOX(accounts.window), gnt_line_new(FALSE));
- accounts.tree = gnt_tree_new_with_columns(2);
- gnt_widget_set_has_border(accounts.tree, FALSE);
- manager_model = purple_account_manager_get_default_as_model();
- n_items = g_list_model_get_n_items(manager_model);
- for(guint index = 0; index < n_items; index++) {
- PurpleAccount *account = g_list_model_get_item(manager_model, index);
- g_object_unref(account);
- g_signal_connect(G_OBJECT(accounts.tree), "toggled", G_CALLBACK(account_toggled), NULL);
- g_signal_connect(G_OBJECT(accounts.tree), "key_pressed", G_CALLBACK(account_list_key_pressed_cb), NULL);
- gnt_tree_set_col_width(GNT_TREE(accounts.tree), 0, 40);
- gnt_tree_set_col_width(GNT_TREE(accounts.tree), 1, 10);
- gnt_box_add_widget(GNT_BOX(accounts.window), accounts.tree);
- gnt_box_add_widget(GNT_BOX(accounts.window), gnt_line_new(FALSE));
- box = gnt_hbox_new(FALSE);
- button = gnt_button_new(_("Add"));
- gnt_box_add_widget(GNT_BOX(box), button);
- gnt_util_set_trigger_widget(GNT_WIDGET(accounts.tree), GNT_KEY_INS, button);
- g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(add_account_cb), NULL);
- button = gnt_button_new(_("Modify"));
- gnt_box_add_widget(GNT_BOX(box), button);
- g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(modify_account_cb), accounts.tree);
- button = gnt_button_new(_("Delete"));
- gnt_box_add_widget(GNT_BOX(box), button);
- gnt_util_set_trigger_widget(GNT_WIDGET(accounts.tree), GNT_KEY_DEL, button);
- g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(delete_account_cb), accounts.tree);
- gnt_box_add_widget(GNT_BOX(accounts.window), box);
- g_signal_connect(G_OBJECT(accounts.window), "destroy", G_CALLBACK(reset_accounts_win), NULL);
- gnt_widget_show(accounts.window);
-void finch_account_dialog_show(PurpleAccount *account)
-account_added_callback(G_GNUC_UNUSED PurpleAccountManager *manager,
- PurpleAccount *account, G_GNUC_UNUSED gpointer data)
- if (accounts.window == NULL)
- gnt_widget_draw(accounts.tree);
-account_removed_callback(G_GNUC_UNUSED PurpleAccountManager *manager,
- PurpleAccount *account, G_GNUC_UNUSED gpointer data)
- if (accounts.window == NULL)
- gnt_tree_remove(GNT_TREE(accounts.tree), account);
-account_abled_cb(G_GNUC_UNUSED PurpleAccountManager *manager,
- PurpleAccount *account,
- G_GNUC_UNUSED GParamSpec *pspec,
- G_GNUC_UNUSED gpointer data)
- if(accounts.window == NULL) {
- gnt_tree_set_choice(GNT_TREE(accounts.tree), account,
- purple_account_get_enabled(account));
-finch_accounts_init(void)
- PurpleAccountManager *manager = NULL;
- GListModel *manager_model = NULL;
- manager = purple_account_manager_get_default();
- manager_model = G_LIST_MODEL(manager);
- g_signal_connect(manager, "added", G_CALLBACK(account_added_callback),
- g_signal_connect(manager, "removed", G_CALLBACK(account_removed_callback),
- g_signal_connect(manager, "account-changed::enabled",
- G_CALLBACK(account_abled_cb), NULL);
- n_items = g_list_model_get_n_items(manager_model);
- gboolean has_enabled_account = FALSE;
- for(guint index = 0; index < n_items; index++) {
- PurpleAccount *account = NULL;
- account = g_list_model_get_item(manager_model, index);
- if(purple_account_get_enabled(account)) {
- has_enabled_account = TRUE;
- g_object_unref(account);
- g_object_unref(account);
- if(!has_enabled_account) {
- finch_accounts_show_all();
- finch_accounts_show_all();
-finch_accounts_uninit(void) {
- g_clear_pointer(&accounts.window, gnt_widget_destroy);
--- a/finch/gntaccount.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-/**********************************************************************
- **********************************************************************/
- * Perform necessary initializations.
-void finch_accounts_init(void);
- * finch_accounts_uninit:
- * Perform necessary uninitializations.
-void finch_accounts_uninit(void);
- * finch_accounts_show_all:
- * Show the account-manager dialog.
-void finch_accounts_show_all(void);
- * finch_account_dialog_show:
- * @account: The account to edit, or %NULL to create a new account.
- * Show the edit dialog for an account.
-void finch_account_dialog_show(PurpleAccount *account);
-#endif /* FINCH_ACCOUNT_H */
--- a/finch/gntblist.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,3027 +0,0 @@
- * Finch 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 "gntmenuutil.h"
-#define PREF_ROOT "/finch/blist"
-#define TYPING_TIMEOUT_S 4
-#define UI_DATA "ui-finch"
-#define SHOW_EMPTY_GROUP_TIMEOUT 60
-struct _FinchBuddyList {
- PurpleBuddyList parent;
- PurpleBlistNode *tnode; /* Who is the tooltip being displayed for? */
- GList *tagged; /* A list of tagged blistnodes */
- PurpleBlistNode *cnode;
- /* XXX: I am KISSing */
- GntWidget *status; /* Dropdown with the statuses */
- GntWidget *statustext; /* Status message */
- /* These are the menuitems that get regenerated */
- /* When a new group is manually added, it is empty, but we still want to show it
- * for a while (SHOW_EMPTY_GROUP_TIMEOUT seconds) even if 'show empty groups' is
- guint new_group_timeout;
- FinchBlistManager *manager;
- gpointer row; /* the row in the GntTree */
- guint signed_timer; /* used when 'recently' signed on/off */
- PurpleStatusPrimitive prim;
- PurpleSavedStatus *saved;
-static FinchBuddyList *ggblist;
-static void add_buddy(PurpleBuddy *buddy, FinchBuddyList *ggblist);
-static void add_contact(PurpleMetaContact *contact, FinchBuddyList *ggblist);
-static void add_group(PurpleGroup *group, FinchBuddyList *ggblist);
-static void add_chat(PurpleChat *chat, FinchBuddyList *ggblist);
-static void add_node(PurpleBlistNode *node, FinchBuddyList *ggblist);
-static void node_update(PurpleBuddyList *list, PurpleBlistNode *node);
-static void draw_tooltip(FinchBuddyList *ggblist);
-static void tooltip_for_buddy(PurpleBuddy *buddy, GString *str, gboolean full);
-static gboolean remove_typing_cb(gpointer data);
-static void remove_peripherals(FinchBuddyList *ggblist);
-static const char * get_display_name(PurpleBlistNode *node);
-static void savedstatus_changed(PurpleSavedStatus *now, PurpleSavedStatus *old);
-static void blist_show(PurpleBuddyList *list);
-static void update_node_display(PurpleBlistNode *buddy,
- FinchBuddyList *ggblist);
-static void update_buddy_display(PurpleBuddy *buddy, FinchBuddyList *ggblist);
-static gboolean account_autojoin_cb(PurpleConnection *pc, gpointer data);
-static void finch_request_add_buddy(PurpleBuddyList *list,
- PurpleAccount *account,
- const char *username, const char *grp,
-static void menu_group_set_cb(GntMenuItem *item, gpointer data);
-static int blist_node_compare_position(PurpleBlistNode *n1, PurpleBlistNode *n2);
-static int blist_node_compare_text(PurpleBlistNode *n1, PurpleBlistNode *n2);
-static int blist_node_compare_status(PurpleBlistNode *n1, PurpleBlistNode *n2);
-static int color_available;
-static int color_offline;
- * Buddy List Manager functions.
-static gboolean default_can_add_node(PurpleBlistNode *node)
- gboolean offline = purple_prefs_get_bool(PREF_ROOT "/showoffline");
- if (PURPLE_IS_BUDDY(node)) {
- PurpleBuddy *buddy = (PurpleBuddy*)node;
- FinchBlistNode *fnode = g_object_get_data(G_OBJECT(node), UI_DATA);
- if (!purple_buddy_get_contact(buddy))
- return FALSE; /* When a new buddy is added and show-offline is set */
- if (PURPLE_BUDDY_IS_ONLINE(buddy))
- return TRUE; /* The buddy is online */
- if (!purple_account_is_connected(purple_buddy_get_account(buddy)))
- return FALSE; /* The account is disconnected. Do not show */
- return TRUE; /* We want to see offline buddies too */
- if (fnode && fnode->signed_timer)
- return TRUE; /* Show if the buddy just signed off */
- if (purple_blist_node_get_bool(node, "show_offline"))
- } else if (PURPLE_IS_META_CONTACT(node)) {
- PurpleBlistNode *child;
- for (child = purple_blist_node_get_first_child(node);
- child; child = purple_blist_node_get_sibling_next(child)) {
- if (default_can_add_node(child)) {
- } else if (PURPLE_IS_CHAT(node)) {
- PurpleChat *chat = (PurpleChat*)node;
- if (purple_account_is_connected(purple_chat_get_account(chat)))
- return TRUE; /* Show whenever the account is online */
- } else if (PURPLE_IS_GROUP(node)) {
- PurpleBlistNode *child;
- gboolean empty = purple_prefs_get_bool(PREF_ROOT "/emptygroups");
- return TRUE; /* If we want to see empty groups, we can show any group */
- for (child = purple_blist_node_get_first_child(node);
- child; child = purple_blist_node_get_sibling_next(child)) {
- if (default_can_add_node(child)) {
- if (ggblist && ggblist->new_group && g_list_find(ggblist->new_group, node))
-static gpointer default_find_parent(PurpleBlistNode *node)
- if (PURPLE_IS_BUDDY(node) || PURPLE_IS_META_CONTACT(node) || PURPLE_IS_CHAT(node))
- ret = purple_blist_node_get_parent(node);
- add_node(ret, ggblist);
-static gboolean default_create_tooltip(gpointer selected_row, GString **body, char **tool_title)
- PurpleBlistNode *node = selected_row;
- str = g_string_new("");
- if (PURPLE_IS_META_CONTACT(node)) {
- PurpleBuddy *pr = purple_meta_contact_get_priority_buddy((PurpleMetaContact*)node);
- gboolean offline = !PURPLE_BUDDY_IS_ONLINE(pr);
- gboolean showoffline = purple_prefs_get_bool(PREF_ROOT "/showoffline");
- const char *name = purple_buddy_get_name(pr);
- title = g_strdup(name);
- tooltip_for_buddy(pr, str, TRUE);
- for (node = purple_blist_node_get_first_child(node); node; node = purple_blist_node_get_sibling_next(node)) {
- PurpleBuddy *buddy = (PurpleBuddy*)node;
- int value = purple_blist_node_get_int(node, "last_seen");
- if (node == (PurpleBlistNode*)pr)
- if (!purple_account_is_connected(purple_buddy_get_account(buddy)))
- if (!showoffline && !PURPLE_BUDDY_IS_ONLINE(buddy))
- str = g_string_append(str, "\n----------\n");
- tooltip_for_buddy(buddy, str, FALSE);
- } else if (PURPLE_IS_BUDDY(node)) {
- PurpleBuddy *buddy = (PurpleBuddy *)node;
- tooltip_for_buddy(buddy, str, TRUE);
- title = g_strdup(purple_buddy_get_name(buddy));
- if (!PURPLE_BUDDY_IS_ONLINE((PurpleBuddy*)node))
- lastseen = purple_blist_node_get_int(node, "last_seen");
- } else if (PURPLE_IS_GROUP(node)) {
- PurpleGroup *group = (PurpleGroup *)node;
- g_string_append_printf(str, _("Online: %d\nTotal: %d"),
- purple_counting_node_get_online_count(PURPLE_COUNTING_NODE(group)),
- purple_counting_node_get_current_size(PURPLE_COUNTING_NODE(group)));
- title = g_strdup(purple_group_get_name(group));
- } else if (PURPLE_IS_CHAT(node)) {
- PurpleAccount *account = NULL;
- PurpleContactInfo *info = NULL;
- PurpleChat *chat = NULL;
- chat = PURPLE_CHAT(node);
- account = purple_chat_get_account(chat);
- info = PURPLE_CONTACT_INFO(account);
- g_string_append_printf(str, _("Account: %s (%s)"),
- purple_contact_info_get_username(info),
- purple_account_get_protocol_name(account));
- title = g_strdup(purple_chat_get_name(chat));
- g_string_free(str, TRUE);
- char *tmp = purple_str_seconds_to_string(time(NULL) - lastseen);
- g_string_append_printf(str, _("\nLast Seen: %s ago"), tmp);
- g_string_free(str, TRUE);
-static FinchBlistManager default_manager =
- default_create_tooltip,
- {NULL, NULL, NULL, NULL}
-finch_blist_node_free(FinchBlistNode *node) {
- g_clear_handle_id(&node->signed_timer, g_source_remove);
-create_finch_blist_node(PurpleBlistNode *node, gpointer row)
- FinchBlistNode *fnode = g_object_get_data(G_OBJECT(node), UI_DATA);
- fnode = g_new0(FinchBlistNode, 1);
- fnode->signed_timer = 0;
- g_object_set_data_full(G_OBJECT(node), UI_DATA, fnode,
- (GDestroyNotify)finch_blist_node_free);
-get_display_color(PurpleBlistNode *node)
- if (PURPLE_IS_META_CONTACT(node))
- node = PURPLE_BLIST_NODE(purple_meta_contact_get_priority_buddy(PURPLE_META_CONTACT(node)));
- if (!PURPLE_IS_BUDDY(node))
- buddy = (PurpleBuddy*)node;
- if (purple_presence_is_idle(purple_buddy_get_presence(buddy))) {
- } else if (purple_presence_is_available(purple_buddy_get_presence(buddy))) {
- color = color_available;
- } else if (purple_presence_is_online(purple_buddy_get_presence(buddy)) &&
- !purple_presence_is_available(purple_buddy_get_presence(buddy))) {
- } else if (!purple_presence_is_online(purple_buddy_get_presence(buddy))) {
-static GntTextFormatFlags
-get_blist_node_flag(FinchBuddyList *ggblist, PurpleBlistNode *node)
- GntTextFormatFlags flag = 0;
- FinchBlistNode *fnode = g_object_get_data(G_OBJECT(node), UI_DATA);
- if (ggblist->tagged && g_list_find(ggblist->tagged, node))
- flag |= GNT_TEXT_FLAG_BOLD;
- if (fnode && fnode->signed_timer)
- flag |= GNT_TEXT_FLAG_BLINK;
- else if (PURPLE_IS_META_CONTACT(node)) {
- node = PURPLE_BLIST_NODE(purple_meta_contact_get_priority_buddy(PURPLE_META_CONTACT(node)));
- fnode = g_object_get_data(G_OBJECT(node), UI_DATA);
- if (fnode && fnode->signed_timer)
- flag |= GNT_TEXT_FLAG_BLINK;
-blist_update_row_flags(FinchBuddyList *ggblist, PurpleBlistNode *node)
- gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), node,
- get_blist_node_flag(ggblist, node));
- gnt_tree_set_row_color(GNT_TREE(ggblist->tree), node, get_display_color(node));
-new_node(G_GNUC_UNUSED PurpleBuddyList *list,
- G_GNUC_UNUSED PurpleBlistNode *node)
-add_node(PurpleBlistNode *node, FinchBuddyList *ggblist)
- if(g_object_get_data(G_OBJECT(node), UI_DATA)) {
- if(!ggblist->manager->can_add_node(node)) {
- if(PURPLE_IS_BUDDY(node)) {
- add_buddy((PurpleBuddy*)node, ggblist);
- } else if (PURPLE_IS_META_CONTACT(node)) {
- add_contact((PurpleMetaContact*)node, ggblist);
- } else if (PURPLE_IS_GROUP(node)) {
- add_group((PurpleGroup*)node, ggblist);
- } else if (PURPLE_IS_CHAT(node)) {
- add_chat((PurpleChat *)node, ggblist);
-void finch_blist_manager_add_node(PurpleBlistNode *node)
- add_node(node, ggblist);
-remove_tooltip(FinchBuddyList *ggblist)
- gnt_widget_destroy(ggblist->tooltip);
- ggblist->tooltip = NULL;
-node_remove(PurpleBuddyList *list, PurpleBlistNode *node)
- FinchBuddyList *ggblist = FINCH_BUDDY_LIST(list);
- PurpleBlistNode *parent;
- if (ggblist == NULL || g_object_get_data(G_OBJECT(node), UI_DATA) == NULL)
- if (PURPLE_IS_GROUP(node) && ggblist->new_group) {
- ggblist->new_group = g_list_remove(ggblist->new_group, node);
- gnt_tree_remove(GNT_TREE(ggblist->tree), node);
- ggblist->tagged = g_list_remove(ggblist->tagged, node);
- parent = purple_blist_node_get_parent(node);
- for (node = purple_blist_node_get_first_child(node); node;
- node = purple_blist_node_get_sibling_next(node))
- node_remove(list, node);
- if (!ggblist->manager->can_add_node(parent))
- node_remove(list, parent);
- node_update(list, parent);
-node_update(PurpleBuddyList *list, PurpleBlistNode *node)
- FinchBuddyList *ggblist;
- g_return_if_fail(FINCH_IS_BUDDY_LIST(list));
- /* It really looks like this should never happen ... but it does.
- This will at least emit a warning to the log when it
- happens, so maybe someone will figure it out. */
- g_return_if_fail(node != NULL);
- ggblist = FINCH_BUDDY_LIST(list);
- if (ggblist->window == NULL) {
- if(g_object_get_data(G_OBJECT(node), UI_DATA) != NULL) {
- gnt_tree_change_text(GNT_TREE(ggblist->tree), node, 0,
- get_display_name(node));
- gnt_tree_sort_row(GNT_TREE(ggblist->tree), node);
- blist_update_row_flags(ggblist, node);
- if (gnt_tree_get_parent_key(GNT_TREE(ggblist->tree), node) !=
- ggblist->manager->find_parent(node))
- node_remove(list, node);
- if (PURPLE_IS_BUDDY(node)) {
- PurpleBuddy *buddy = (PurpleBuddy*)node;
- add_node((PurpleBlistNode *)buddy, FINCH_BUDDY_LIST(list));
- node_update(list, purple_blist_node_get_parent(node));
- } else if (PURPLE_IS_CHAT(node)) {
- add_node(node, FINCH_BUDDY_LIST(list));
- } else if (PURPLE_IS_META_CONTACT(node)) {
- if (g_object_get_data(G_OBJECT(node), UI_DATA) == NULL) {
- /* The core seems to expect the UI to add the buddies. */
- for (node = purple_blist_node_get_first_child(node); node; node = purple_blist_node_get_sibling_next(node))
- add_node(node, FINCH_BUDDY_LIST(list));
- } else if (PURPLE_IS_GROUP(node)) {
- if (!ggblist->manager->can_add_node(node))
- node_remove(list, node);
- add_node(node, FINCH_BUDDY_LIST(list));
- if (ggblist->tnode == node) {
-remove_new_empty_group(G_GNUC_UNUSED gpointer data)
- FinchBuddyList *ggblist;
- list = purple_blist_get_default();
- g_return_val_if_fail(list, FALSE);
- ggblist = FINCH_BUDDY_LIST(list);
- ggblist->new_group_timeout = 0;
- while (ggblist->new_group) {
- PurpleBlistNode *group = ggblist->new_group->data;
- ggblist->new_group = g_list_delete_link(ggblist->new_group, ggblist->new_group);
- node_update(list, group);
-add_buddy_cb(G_GNUC_UNUSED gpointer data, PurpleRequestPage *page) {
- const char *username = purple_request_page_get_string(page, "screenname");
- const char *alias = purple_request_page_get_string(page, "alias");
- const char *group = purple_request_page_get_string(page, "group");
- const char *invite = purple_request_page_get_string(page, "invite");
- PurpleAccount *account = purple_request_page_get_account(page, "account");
- const char *error = NULL;
- error = _("You must provide a username for the buddy.");
- error = _("You must provide a group.");
- error = _("You must select an account.");
- else if (!purple_account_is_connected(account))
- error = _("The selected account is not online.");
- finch_request_add_buddy(purple_blist_get_default(), account,
- username, group, alias);
- purple_notify_error(NULL, _("Error"), _("Error adding buddy"),
- error, purple_request_cpar_from_account(account));
- grp = purple_blist_find_group(group);
- grp = purple_group_new(group);
- purple_blist_add_group(grp, NULL);
- /* XXX: Ask to merge if there's already a buddy with the same alias in the same group (#4553) */
- if ((buddy = purple_blist_find_buddy_in_group(account, username, grp)) == NULL)
- buddy = purple_buddy_new(account, username, alias);
- purple_blist_add_buddy(buddy, NULL, grp, NULL);
- purple_account_add_buddy(account, buddy, invite);
-finch_request_add_buddy(G_GNUC_UNUSED PurpleBuddyList *list,
- PurpleAccount *account, const char *username,
- const char *grp, const char *alias)
- PurpleRequestPage *page = purple_request_page_new();
- PurpleRequestGroup *group = purple_request_group_new(NULL);
- PurpleRequestField *field;
- purple_request_page_add_group(page, group);
- field = purple_request_field_string_new("screenname", _("Username"), username, FALSE);
- purple_request_group_add_field(group, field);
- field = purple_request_field_string_new("alias", _("Alias (optional)"), alias, FALSE);
- purple_request_group_add_field(group, field);
- field = purple_request_field_string_new("invite", _("Invite message (optional)"), NULL, FALSE);
- purple_request_group_add_field(group, field);
- field = purple_request_field_string_new("group", _("Add in group"), grp, FALSE);
- purple_request_group_add_field(group, field);
- purple_request_field_set_type_hint(field, "group");
- field = purple_request_field_account_new("account", _("Account"), NULL);
- purple_request_field_account_set_show_all(PURPLE_REQUEST_FIELD_ACCOUNT(field),
- purple_request_field_account_set_value(PURPLE_REQUEST_FIELD_ACCOUNT(field),
- purple_request_group_add_field(group, field);
- purple_request_fields(NULL, _("Add Buddy"), NULL, _("Please enter buddy information."),
- _("Add"), G_CALLBACK(add_buddy_cb),
- purple_request_cpar_from_account(account),
-join_chat(PurpleChat *chat)
- PurpleAccount *account = purple_chat_get_account(chat);
- PurpleConversationManager *manager;
- PurpleConversation *conv;
- name = purple_chat_get_name_only(chat);
- manager = purple_conversation_manager_get_default();
- conv = purple_conversation_manager_find_chat(manager, account, name);
- if (!conv || purple_chat_conversation_has_left(PURPLE_CHAT_CONVERSATION(conv))) {
- purple_serv_join_chat(purple_account_get_connection(account),
- purple_chat_get_components(chat));
- purple_conversation_present(conv);
-add_chat_cb(G_GNUC_UNUSED gpointer data, PurpleRequestPage *page) {
- PurpleAccount *account;
- const char *alias, *name, *group;
- GHashTable *hash = NULL;
- PurpleProtocol *protocol;
- account = purple_request_page_get_account(page, "account");
- name = purple_request_page_get_string(page, "name");
- alias = purple_request_page_get_string(page, "alias");
- group = purple_request_page_get_string(page, "group");
- autojoin = purple_request_page_get_bool(page, "autojoin");
- if (!purple_account_is_connected(account) || !name || !*name)
- gc = purple_account_get_connection(account);
- protocol = purple_connection_get_protocol(gc);
- hash = purple_protocol_chat_info_defaults(PURPLE_PROTOCOL_CHAT(protocol), gc, name);
- chat = purple_chat_new(account, name, hash);
- if ((grp = purple_blist_find_group(group)) == NULL) {
- grp = purple_group_new(group);
- purple_blist_add_group(grp, NULL);
- purple_blist_add_chat(chat, grp, NULL);
- purple_chat_set_alias(chat, alias);
- purple_blist_node_set_bool((PurpleBlistNode*)chat, "gnt-autojoin", autojoin);
-finch_request_add_chat(G_GNUC_UNUSED PurpleBuddyList *list,
- PurpleAccount *account, PurpleGroup *grp,
- const char *alias, const char *name)
- PurpleRequestPage *page = purple_request_page_new();
- PurpleRequestGroup *group = purple_request_group_new(NULL);
- PurpleRequestField *field;
- purple_request_page_add_group(page, group);
- field = purple_request_field_account_new("account", _("Account"), NULL);
- purple_request_field_account_set_show_all(PURPLE_REQUEST_FIELD_ACCOUNT(field),
- purple_request_field_account_set_value(PURPLE_REQUEST_FIELD_ACCOUNT(field),
- purple_request_group_add_field(group, field);
- field = purple_request_field_string_new("name", _("Name"), name, FALSE);
- purple_request_group_add_field(group, field);
- field = purple_request_field_string_new("alias", _("Alias"), alias, FALSE);
- purple_request_group_add_field(group, field);
- field = purple_request_field_string_new("group", _("Group"), grp ? purple_group_get_name(grp) : NULL, FALSE);
- purple_request_group_add_field(group, field);
- purple_request_field_set_type_hint(field, "group");
- field = purple_request_field_bool_new("autojoin", _("Auto-join"), FALSE);
- purple_request_group_add_field(group, field);
- purple_request_fields(NULL, _("Add Chat"), NULL,
- _("You can edit more information from the context menu later."),
- page, _("Add"), G_CALLBACK(add_chat_cb), _("Cancel"), NULL,
-add_group_cb(FinchBuddyList *ggblist, const char *group)
- if (!group || !*group) {
- purple_notify_error(NULL, _("Error"), _("Error adding group"),
- _("You must give a name for the group to add."), NULL);
- g_object_unref(ggblist);
- grp = purple_blist_find_group(group);
- grp = purple_group_new(group);
- purple_blist_add_group(grp, NULL);
- /* Treat the group as a new group even if it had existed before. This should
- * make things easier to add buddies to empty groups (new or old) without having
- * to turn on 'show empty groups' setting */
- ggblist->new_group = g_list_prepend(ggblist->new_group, grp);
- g_clear_handle_id(&ggblist->new_group_timeout, g_source_remove);
- ggblist->new_group_timeout = g_timeout_add_seconds(SHOW_EMPTY_GROUP_TIMEOUT,
- remove_new_empty_group, NULL);
- FinchBlistNode *fnode = g_object_get_data(G_OBJECT(grp), UI_DATA);
- add_node((PurpleBlistNode*)grp, ggblist);
- gnt_tree_set_selected(GNT_TREE(ggblist->tree), grp);
- g_object_unref(ggblist);
-finch_request_add_group(PurpleBuddyList *list)
- purple_request_input(NULL, _("Add Group"), NULL,
- _("Enter the name of the group"), NULL, FALSE,
- FALSE, NULL, _("Add"), G_CALLBACK(add_group_cb),
- _("Cancel"), G_CALLBACK(g_object_unref), NULL,
-finch_blist_get_handle(void)
-add_group(PurpleGroup *group, FinchBuddyList *ggblist)
- PurpleBlistNode *node = (PurpleBlistNode *)group;
- if(g_object_get_data(G_OBJECT(node), UI_DATA)) {
- parent = ggblist->manager->find_parent((PurpleBlistNode*)group);
- create_finch_blist_node(node, gnt_tree_add_row_after(GNT_TREE(ggblist->tree), group,
- gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)),
- gnt_tree_set_expanded(GNT_TREE(ggblist->tree), node,
- !purple_blist_node_get_bool(node, "collapsed"));
-get_display_name(PurpleBlistNode *node)
- static char text[2096];
- const char *name = NULL;
- if (PURPLE_IS_META_CONTACT(node))
- node = PURPLE_BLIST_NODE(purple_meta_contact_get_priority_buddy(PURPLE_META_CONTACT(node))); /* XXX: this can return NULL?! */
- if (PURPLE_IS_BUDDY(node))
- PurpleBuddy *buddy = (PurpleBuddy *)node;
- PurpleStatusPrimitive prim;
- PurplePresence *presence;
- gboolean ascii = gnt_ascii_only();
- presence = purple_buddy_get_presence(buddy);
- if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOBILE))
- strncpy(status, ascii ? ":" : "☎", sizeof(status) - 1);
- now = purple_presence_get_active_status(presence);
- prim = purple_status_type_get_primitive(purple_status_get_status_type(now));
- case PURPLE_STATUS_OFFLINE:
- strncpy(status, ascii ? "x" : "⊗", sizeof(status) - 1);
- case PURPLE_STATUS_AVAILABLE:
- strncpy(status, ascii ? "o" : "â—¯", sizeof(status) - 1);
- strncpy(status, ascii ? "." : "⊖", sizeof(status) - 1);
- name = purple_buddy_get_alias(buddy);
- else if (PURPLE_IS_CHAT(node))
- PurpleChat *chat = (PurpleChat*)node;
- name = purple_chat_get_name(chat);
- strncpy(status, "~", sizeof(status) - 1);
- else if (PURPLE_IS_GROUP(node))
- return purple_group_get_name((PurpleGroup*)node);
- g_snprintf(text, sizeof(text) - 1, "%s %s", status, name);
-add_chat(PurpleChat *chat, FinchBuddyList *ggblist)
- PurpleBlistNode *node = (PurpleBlistNode *)chat;
- if(g_object_get_data(G_OBJECT(node), UI_DATA)) {
- if(!purple_account_is_connected(purple_chat_get_account(chat))) {
- parent = ggblist->manager->find_parent((PurpleBlistNode*)chat);
- create_finch_blist_node(node, gnt_tree_add_row_after(GNT_TREE(ggblist->tree), chat,
- gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)),
-add_contact(PurpleMetaContact *contact, FinchBuddyList *ggblist)
- PurpleBlistNode *node = (PurpleBlistNode*)contact;
- if(g_object_get_data(G_OBJECT(node), UI_DATA)) {
- name = get_display_name(node);
- parent = ggblist->manager->find_parent((PurpleBlistNode*)contact);
- create_finch_blist_node(node, gnt_tree_add_row_after(GNT_TREE(ggblist->tree), contact,
- gnt_tree_create_row(GNT_TREE(ggblist->tree), name),
- gnt_tree_set_expanded(GNT_TREE(ggblist->tree), contact, FALSE);
-add_buddy(PurpleBuddy *buddy, FinchBuddyList *ggblist)
- PurpleBlistNode *node = (PurpleBlistNode *)buddy;
- PurpleMetaContact *contact;
- if(g_object_get_data(G_OBJECT(node), UI_DATA)) {
- contact = purple_buddy_get_contact(buddy);
- parent = ggblist->manager->find_parent((PurpleBlistNode*)buddy);
- create_finch_blist_node(node, gnt_tree_add_row_after(GNT_TREE(ggblist->tree), buddy,
- gnt_tree_create_row(GNT_TREE(ggblist->tree), get_display_name(node)),
- blist_update_row_flags(ggblist, (PurpleBlistNode *)buddy);
- if (buddy == purple_meta_contact_get_priority_buddy(contact)) {
- blist_update_row_flags(ggblist, (PurpleBlistNode *)contact);
-selection_activate(G_GNUC_UNUSED GntWidget *widget, FinchBuddyList *ggblist)
- GntTree *tree = GNT_TREE(ggblist->tree);
- PurpleBlistNode *node = gnt_tree_get_selection_data(tree);
- if (PURPLE_IS_META_CONTACT(node))
- node = PURPLE_BLIST_NODE(purple_meta_contact_get_priority_buddy(PURPLE_META_CONTACT(node)));
- if (PURPLE_IS_BUDDY(node))
- PurpleBuddy *buddy = (PurpleBuddy *)node;
- PurpleConversation *im;
- PurpleConversationManager *manager;
- manager = purple_conversation_manager_get_default();
- im = purple_conversation_manager_find_im(manager,
- purple_buddy_get_account(buddy),
- purple_buddy_get_name(buddy));
- if(!PURPLE_IS_IM_CONVERSATION(im)) {
- im = purple_im_conversation_new(purple_buddy_get_account(buddy),
- purple_buddy_get_name(buddy));
- FinchConv *ggconv = FINCH_CONV(im);
- gnt_window_present(ggconv->window);
- finch_conversation_set_active(im);
- else if (PURPLE_IS_CHAT(node))
- join_chat((PurpleChat*)node);
-append_proto_menu(GntMenu *menu, PurpleConnection *gc, PurpleBlistNode *node)
- PurpleProtocol *protocol = purple_connection_get_protocol(gc);
- if (!PURPLE_PROTOCOL_IMPLEMENTS(protocol, CLIENT, blist_node_menu)) {
- for(list = purple_protocol_client_blist_node_menu(PURPLE_PROTOCOL_CLIENT(protocol), node);
- list; list = g_list_delete_link(list, list))
- PurpleActionMenu *act = (PurpleActionMenu *) list->data;
- purple_action_menu_set_data(act, node);
- finch_append_menu_action(menu, act, node);
-add_custom_action(GntMenu *menu, const char *label, GCallback callback,
- PurpleActionMenu *action = purple_action_menu_new(label, callback, data, NULL);
- finch_append_menu_action(menu, action, NULL);
-chat_components_edit_ok(PurpleChat *chat, PurpleRequestPage *page) {
- n_groups = g_list_model_get_n_items(G_LIST_MODEL(page));
- for(guint group_index = 0; group_index < n_groups; group_index++) {
- GListModel *group = NULL;
- group = g_list_model_get_item(G_LIST_MODEL(page), group_index);
- n_fields = g_list_model_get_n_items(group);
- for(guint field_index = 0; field_index < n_fields; field_index++) {
- PurpleRequestField *field = NULL;
- field = g_list_model_get_item(group, field_index);
- id = purple_request_field_get_id(field);
- if(PURPLE_IS_REQUEST_FIELD_INT(field)) {
- PurpleRequestFieldInt *ifield = PURPLE_REQUEST_FIELD_INT(field);
- val = g_strdup_printf("%d",
- purple_request_field_int_get_value(ifield));
- val = g_strdup(purple_request_field_string_get_value(PURPLE_REQUEST_FIELD_STRING(field)));
- g_hash_table_remove(purple_chat_get_components(chat), id);
- g_hash_table_replace(purple_chat_get_components(chat), g_strdup(id), val); /* val should not be free'd */
-chat_components_edit(G_GNUC_UNUSED PurpleBlistNode *selected, PurpleChat *chat)
- PurpleRequestPage *page = purple_request_page_new();
- PurpleRequestGroup *group = purple_request_group_new(NULL);
- PurpleRequestField *field;
- PurpleProtocol *protocol;
- PurpleProtocolChatEntry *pce;
- purple_request_page_add_group(page, group);
- gc = purple_account_get_connection(purple_chat_get_account(chat));
- protocol = purple_connection_get_protocol(gc);
- parts = purple_protocol_chat_info(PURPLE_PROTOCOL_CHAT(protocol), gc);
- for (iter = parts; iter; iter = iter->next) {
- const char *str = g_hash_table_lookup(purple_chat_get_components(chat), pce->identifier);
- if (!str || sscanf(str, "%d", &val) != 1)
- field = purple_request_field_int_new(pce->identifier, pce->label, val, INT_MIN, INT_MAX);
- field = purple_request_field_string_new(pce->identifier, pce->label,
- g_hash_table_lookup(purple_chat_get_components(chat), pce->identifier), FALSE);
- purple_request_field_string_set_masked(PURPLE_REQUEST_FIELD_STRING(field),
- purple_request_field_set_required(field, TRUE);
- purple_request_group_add_field(group, field);
- purple_request_fields(NULL, _("Edit Chat"), NULL, _("Please Update the necessary fields."),
- page, _("Edit"), G_CALLBACK(chat_components_edit_ok), _("Cancel"), NULL,
-autojoin_toggled(GntMenuItem *item, gpointer data)
- PurpleActionMenu *action = data;
- purple_blist_node_set_bool(purple_action_menu_get_data(action), "gnt-autojoin",
- gnt_menuitem_check_get_checked(GNT_MENU_ITEM_CHECK(item)));
-create_chat_menu(GntMenu *menu, PurpleChat *chat)
- PurpleActionMenu *action = purple_action_menu_new(_("Auto-join"), NULL, chat, NULL);
- GntMenuItem *check = gnt_menuitem_check_new(
- purple_action_menu_get_label(action));
- gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(check),
- purple_blist_node_get_bool((PurpleBlistNode*)chat, "gnt-autojoin"));
- gnt_menu_add_item(menu, check);
- gnt_menuitem_set_callback(check, autojoin_toggled, action);
- g_signal_connect_swapped(G_OBJECT(menu), "destroy",
- G_CALLBACK(purple_action_menu_free), action);
- append_proto_menu(menu,
- purple_account_get_connection(purple_chat_get_account(chat)),
- (PurpleBlistNode*)chat);
- add_custom_action(menu, _("Edit Settings"), (GCallback)chat_components_edit, chat);
-finch_add_buddy(G_GNUC_UNUSED PurpleBlistNode *selected, PurpleGroup *grp)
- purple_blist_request_add_buddy(NULL, NULL, grp ? purple_group_get_name(grp) : NULL, NULL);
-finch_add_group(G_GNUC_UNUSED PurpleBlistNode *selected,
- G_GNUC_UNUSED PurpleGroup *grp)
- purple_blist_request_add_group();
-finch_add_chat(G_GNUC_UNUSED PurpleBlistNode *selected, PurpleGroup *grp)
- purple_blist_request_add_chat(NULL, grp, NULL, NULL);
-create_group_menu(GntMenu *menu, PurpleGroup *group)
- add_custom_action(menu, _("Add Buddy"),
- G_CALLBACK(finch_add_buddy), group);
- add_custom_action(menu, _("Add Chat"),
- G_CALLBACK(finch_add_chat), group);
- add_custom_action(menu, _("Add Group"),
- G_CALLBACK(finch_add_group), group);
-gpointer finch_retrieve_user_info(PurpleConnection *conn, const char *name)
- PurpleProtocol *protocol = NULL;
- PurpleNotifyUserInfo *info = NULL;
- protocol = purple_connection_get_protocol(conn);
- if(!PURPLE_IS_PROTOCOL_SERVER(protocol)) {
- purple_protocol_server_get_info(PURPLE_PROTOCOL_SERVER(protocol), conn,
- info = purple_notify_user_info_new();
- purple_notify_user_info_add_pair_plaintext(info, _("Information"), _("Retrieving..."));
- uihandle = purple_notify_userinfo(conn, name, info, NULL, NULL);
- purple_notify_user_info_destroy(info);
-finch_blist_get_buddy_info_cb(G_GNUC_UNUSED PurpleBlistNode *selected,
- finch_retrieve_user_info(purple_account_get_connection(purple_buddy_get_account(buddy)), purple_buddy_get_name(buddy));
-finch_blist_menu_send_file_cb(G_GNUC_UNUSED PurpleBlistNode *selected,
- purple_serv_send_file(purple_account_get_connection(purple_buddy_get_account(buddy)), purple_buddy_get_name(buddy), NULL);
-toggle_show_offline(G_GNUC_UNUSED GntMenuItem *item, gpointer buddy)
- purple_blist_node_set_bool(buddy, "show_offline",
- !purple_blist_node_get_bool(buddy, "show_offline"));
- if (!ggblist->manager->can_add_node(buddy))
- node_remove(purple_blist_get_default(), buddy);
- node_update(purple_blist_get_default(), buddy);
-create_buddy_menu(GntMenu *menu, PurpleBuddy *buddy)
- PurpleProtocol *protocol;
- PurpleConnection *gc = purple_account_get_connection(purple_buddy_get_account(buddy));
- protocol = purple_connection_get_protocol(gc);
- if (protocol && PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, get_info))
- add_custom_action(menu, _("Get Info"),
- G_CALLBACK(finch_blist_get_buddy_info_cb), buddy);
- if (PURPLE_IS_PROTOCOL_XFER(protocol))
- if (purple_protocol_xfer_can_receive(
- PURPLE_PROTOCOL_XFER(protocol),
- purple_buddy_get_name(buddy))
- add_custom_action(menu, _("Send File"),
- G_CALLBACK(finch_blist_menu_send_file_cb), buddy);
- item = gnt_menuitem_check_new(_("Show when offline"));
- gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item), purple_blist_node_get_bool((PurpleBlistNode*)buddy, "show_offline"));
- gnt_menuitem_set_callback(item, toggle_show_offline, buddy);
- gnt_menu_add_item(menu, item);
- append_proto_menu(menu,
- purple_account_get_connection(purple_buddy_get_account(buddy)),
- (PurpleBlistNode*)buddy);
-append_extended_menu(GntMenu *menu, PurpleBlistNode *node)
- for (iter = purple_blist_node_get_extended_menu(node);
- iter; iter = g_list_delete_link(iter, iter))
- finch_append_menu_action(menu, iter->data, node);
-/* Xerox'd from gtkdialogs.c:purple_gtkdialogs_remove_contact_cb */
-remove_contact(PurpleMetaContact *contact)
- PurpleBlistNode *bnode, *cnode;
- cnode = (PurpleBlistNode *)contact;
- group = (PurpleGroup*)purple_blist_node_get_parent(cnode);
- for (bnode = purple_blist_node_get_first_child(cnode); bnode; bnode = purple_blist_node_get_sibling_next(bnode)) {
- PurpleBuddy *buddy = (PurpleBuddy*)bnode;
- PurpleAccount *account = purple_buddy_get_account(buddy);
- if (purple_account_is_connected(account))
- purple_account_remove_buddy(account, buddy, group);
- purple_blist_remove_contact(contact);
-rename_blist_node(PurpleBlistNode *node, const char *newname)
- const char *name = newname;
- if (PURPLE_IS_META_CONTACT(node)) {
- PurpleMetaContact *contact = (PurpleMetaContact*)node;
- PurpleBuddy *buddy = purple_meta_contact_get_priority_buddy(contact);
- purple_meta_contact_set_alias(contact, name);
- purple_buddy_set_local_alias(buddy, name);
- purple_serv_alias_buddy(buddy);
- } else if (PURPLE_IS_BUDDY(node)) {
- purple_buddy_set_local_alias((PurpleBuddy*)node, name);
- purple_serv_alias_buddy((PurpleBuddy*)node);
- } else if (PURPLE_IS_CHAT(node))
- purple_chat_set_alias((PurpleChat*)node, name);
- else if (PURPLE_IS_GROUP(node) && (name != NULL))
- purple_group_set_name((PurpleGroup*)node, name);
-finch_blist_rename_node_cb(G_GNUC_UNUSED PurpleBlistNode *selected,
- const char *name = NULL;
- if (PURPLE_IS_META_CONTACT(node))
- name = purple_meta_contact_get_alias((PurpleMetaContact*)node);
- else if (PURPLE_IS_BUDDY(node))
- name = purple_buddy_get_contact_alias((PurpleBuddy*)node);
- else if (PURPLE_IS_CHAT(node))
- name = purple_chat_get_name((PurpleChat*)node);
- else if (PURPLE_IS_GROUP(node))
- name = purple_group_get_name((PurpleGroup*)node);
- prompt = g_strdup_printf(_("Please enter the new name for %s"), name);
- text = PURPLE_IS_GROUP(node) ? _("Rename") : _("Set Alias");
- purple_request_input(node, text, prompt, _("Enter empty string to reset the name."),
- name, FALSE, FALSE, NULL, text, G_CALLBACK(rename_blist_node),
-/* Xeroxed from gtkdialogs.c:purple_gtkdialogs_remove_group_cb*/
-remove_group(PurpleGroup *group)
- PurpleBlistNode *cnode, *bnode;
- cnode = purple_blist_node_get_first_child(((PurpleBlistNode*)group));
- if (PURPLE_IS_META_CONTACT(cnode)) {
- bnode = purple_blist_node_get_first_child(cnode);
- cnode = purple_blist_node_get_sibling_next(cnode);
- if (PURPLE_IS_BUDDY(bnode)) {
- PurpleAccount *account;
- buddy = (PurpleBuddy*)bnode;
- bnode = purple_blist_node_get_sibling_next(bnode);
- account = purple_buddy_get_account(buddy);
- if (purple_account_is_connected(account)) {
- purple_account_remove_buddy(account, buddy, group);
- purple_blist_remove_buddy(buddy);
- bnode = purple_blist_node_get_sibling_next(bnode);
- } else if (PURPLE_IS_CHAT(cnode)) {
- PurpleChat *chat = (PurpleChat *)cnode;
- cnode = purple_blist_node_get_sibling_next(cnode);
- if (purple_account_is_connected(purple_chat_get_account(chat)))
- purple_blist_remove_chat(chat);
- cnode = purple_blist_node_get_sibling_next(cnode);
- purple_blist_remove_group(group);
-finch_blist_remove_node(PurpleBlistNode *node)
- if (PURPLE_IS_META_CONTACT(node)) {
- remove_contact((PurpleMetaContact*)node);
- } else if (PURPLE_IS_BUDDY(node)) {
- PurpleBuddy *buddy = (PurpleBuddy*)node;
- PurpleGroup *group = purple_buddy_get_group(buddy);
- purple_account_remove_buddy(purple_buddy_get_account(buddy), buddy, group);
- purple_blist_remove_buddy(buddy);
- } else if (PURPLE_IS_CHAT(node)) {
- purple_blist_remove_chat((PurpleChat*)node);
- } else if (PURPLE_IS_GROUP(node)) {
- remove_group((PurpleGroup*)node);
-finch_blist_remove_node_cb(G_GNUC_UNUSED PurpleBlistNode *selected,
- PurpleAccount *account = NULL;
- const char *name, *sec = NULL;
- if (PURPLE_IS_META_CONTACT(node)) {
- PurpleMetaContact *c = (PurpleMetaContact*)node;
- name = purple_meta_contact_get_alias(c);
- if (purple_counting_node_get_total_size(PURPLE_COUNTING_NODE(c)) > 1)
- sec = _("Removing this contact will also remove all the buddies in the contact");
- } else if (PURPLE_IS_BUDDY(node)) {
- name = purple_buddy_get_name((PurpleBuddy*)node);
- account = purple_buddy_get_account((PurpleBuddy*)node);
- } else if (PURPLE_IS_CHAT(node)) {
- name = purple_chat_get_name((PurpleChat*)node);
- } else if (PURPLE_IS_GROUP(node)) {
- name = purple_group_get_name((PurpleGroup*)node);
- sec = _("Removing this group will also remove all the buddies in the group");
- primary = g_strdup_printf(_("Are you sure you want to remove %s?"), name);
- /* XXX: anything to do with the returned ui-handle? */
- purple_request_action(node, _("Confirm Remove"),
- purple_request_cpar_from_account(account),
- _("Remove"), finch_blist_remove_node,
-finch_blist_toggle_tag_buddy(PurpleBlistNode *node)
- if (ggblist->tagged && (iter = g_list_find(ggblist->tagged, node)) != NULL) {
- ggblist->tagged = g_list_delete_link(ggblist->tagged, iter);
- ggblist->tagged = g_list_prepend(ggblist->tagged, node);
- if (PURPLE_IS_META_CONTACT(node))
- update_buddy_display(purple_meta_contact_get_priority_buddy(PURPLE_META_CONTACT(node)), ggblist);
- else if (PURPLE_IS_BUDDY(node))
- update_buddy_display((PurpleBuddy*)node, ggblist);
- update_node_display(node, ggblist);
-finch_blist_place_tagged(PurpleBlistNode *target)
- PurpleGroup *tg = NULL;
- PurpleMetaContact *tc = NULL;
- if (PURPLE_IS_GROUP(target))
- tg = (PurpleGroup*)target;
- else if (PURPLE_IS_BUDDY(target)) {
- tc = (PurpleMetaContact*)purple_blist_node_get_parent(target);
- tg = (PurpleGroup*)purple_blist_node_get_parent((PurpleBlistNode*)tc);
- } else if (PURPLE_IS_META_CONTACT(target)) {
- tc = (PurpleMetaContact *)target;
- tg = (PurpleGroup *)purple_blist_node_get_parent(target);
- } else if (PURPLE_IS_CHAT(target)) {
- tg = (PurpleGroup*)purple_blist_node_get_parent(target);
- GList *list = ggblist->tagged;
- ggblist->tagged = NULL;
- PurpleBlistNode *node = list->data;
- list = g_list_delete_link(list, list);
- if (PURPLE_IS_GROUP(node)) {
- update_node_display(node, ggblist);
- /* Add the group after the current group */
- purple_blist_add_group((PurpleGroup*)node, (PurpleBlistNode*)tg);
- } else if (PURPLE_IS_META_CONTACT(node)) {
- update_buddy_display(purple_meta_contact_get_priority_buddy((PurpleMetaContact*)node), ggblist);
- if (PURPLE_BLIST_NODE(tg) == target) {
- /* The target is a group, just add the contact to the group. */
- purple_blist_add_contact((PurpleMetaContact*)node, tg, NULL);
- /* The target is either a buddy, or a contact. Merge with that contact. */
- purple_meta_contact_merge((PurpleMetaContact*)node, (PurpleBlistNode*)tc);
- /* The target is a chat. Add the contact to the group after this chat. */
- purple_blist_add_contact((PurpleMetaContact*)node, NULL, target);
- } else if (PURPLE_IS_BUDDY(node)) {
- update_buddy_display((PurpleBuddy*)node, ggblist);
- if (PURPLE_BLIST_NODE(tg) == target) {
- /* The target is a group. Add this buddy in a new contact under this group. */
- purple_blist_add_buddy((PurpleBuddy*)node, NULL, tg, NULL);
- } else if (PURPLE_IS_META_CONTACT(target)) {
- /* Add to the contact. */
- purple_blist_add_buddy((PurpleBuddy*)node, tc, NULL, NULL);
- } else if (PURPLE_IS_BUDDY(target)) {
- /* Add to the contact after the selected buddy. */
- purple_blist_add_buddy((PurpleBuddy*)node, NULL, NULL, target);
- } else if (PURPLE_IS_CHAT(target)) {
- /* Add to the selected chat's group. */
- purple_blist_add_buddy((PurpleBuddy*)node, NULL, tg, NULL);
- } else if (PURPLE_IS_CHAT(node)) {
- update_node_display(node, ggblist);
- if (PURPLE_BLIST_NODE(tg) == target)
- purple_blist_add_chat((PurpleChat*)node, tg, NULL);
- purple_blist_add_chat((PurpleChat*)node, NULL, target);
-context_menu_destroyed(G_GNUC_UNUSED GntWidget *widget,
- FinchBuddyList *ggblist)
- ggblist->context = NULL;
-draw_context_menu(FinchBuddyList *ggblist)
- PurpleBlistNode *node = NULL;
- GntWidget *context = NULL;
- tree = GNT_TREE(ggblist->tree);
- node = gnt_tree_get_selection_data(tree);
- if (node && !(PURPLE_IS_BUDDY(node) || PURPLE_IS_META_CONTACT(node) ||
- PURPLE_IS_GROUP(node) || PURPLE_IS_CHAT(node)))
- remove_tooltip(ggblist);
- ggblist->context = context = gnt_menu_new(GNT_MENU_POPUP);
- g_signal_connect(G_OBJECT(context), "destroy", G_CALLBACK(context_menu_destroyed), ggblist);
- g_signal_connect(G_OBJECT(context), "hide", G_CALLBACK(gnt_widget_destroy), NULL);
- create_group_menu(GNT_MENU(context), NULL);
- title = g_strdup(_("Buddy List"));
- } else if (PURPLE_IS_META_CONTACT(node)) {
- ggblist->cnode = PURPLE_BLIST_NODE(purple_meta_contact_get_priority_buddy(PURPLE_META_CONTACT(node)));
- create_buddy_menu(GNT_MENU(context), (PurpleBuddy*)ggblist->cnode);
- title = g_strdup(purple_meta_contact_get_alias((PurpleMetaContact*)node));
- } else if (PURPLE_IS_BUDDY(node)) {
- PurpleBuddy *buddy = (PurpleBuddy *)node;
- create_buddy_menu(GNT_MENU(context), buddy);
- title = g_strdup(purple_buddy_get_name(buddy));
- } else if (PURPLE_IS_CHAT(node)) {
- PurpleChat *chat = (PurpleChat*)node;
- create_chat_menu(GNT_MENU(context), chat);
- title = g_strdup(purple_chat_get_name(chat));
- } else if (PURPLE_IS_GROUP(node)) {
- PurpleGroup *group = (PurpleGroup *)node;
- create_group_menu(GNT_MENU(context), group);
- title = g_strdup(purple_group_get_name(group));
- append_extended_menu(GNT_MENU(context), node);
- /* These are common for everything */
- add_custom_action(GNT_MENU(context),
- PURPLE_IS_GROUP(node) ? _("Rename") : _("Alias"),
- G_CALLBACK(finch_blist_rename_node_cb), node);
- add_custom_action(GNT_MENU(context), _("Remove"),
- G_CALLBACK(finch_blist_remove_node_cb), node);
- if (ggblist->tagged && (PURPLE_IS_META_CONTACT(node)
- || PURPLE_IS_GROUP(node))) {
- add_custom_action(GNT_MENU(context), _("Place tagged"),
- G_CALLBACK(finch_blist_place_tagged), node);
- if (PURPLE_IS_BUDDY(node) || PURPLE_IS_META_CONTACT(node)) {
- add_custom_action(GNT_MENU(context), _("Toggle Tag"),
- G_CALLBACK(finch_blist_toggle_tag_buddy), node);
- /* Set the position for the popup */
- gnt_widget_get_position(GNT_WIDGET(tree), &x, &y);
- gnt_widget_get_size(GNT_WIDGET(tree), &width, NULL);
- top = gnt_tree_get_selection_visible_line(tree);
- gnt_widget_set_position(context, x, y);
- gnt_screen_menu_show(GNT_MENU(context));
-tooltip_for_buddy(PurpleBuddy *buddy, GString *str, gboolean full)
- PurpleAccount *account = NULL;
- PurpleContactInfo *info = NULL;
- PurpleNotifyUserInfo *user_info;
- PurplePresence *presence = NULL;
- const char *alias = purple_buddy_get_alias(buddy);
- user_info = purple_notify_user_info_new();
- account = purple_buddy_get_account(buddy);
- info = PURPLE_CONTACT_INFO(account);
- presence = purple_buddy_get_presence(buddy);
- if (!full || g_utf8_collate(purple_buddy_get_name(buddy), alias)) {
- purple_notify_user_info_add_pair_plaintext(user_info, _("Nickname"), alias);
- tmp = g_strdup_printf("%s (%s)",
- purple_contact_info_get_username(info),
- purple_account_get_protocol_name(account));
- purple_notify_user_info_add_pair_plaintext(user_info, _("Account"), tmp);
- if (purple_prefs_get_bool("/finch/blist/idletime")) {
- PurplePresence *pre = purple_buddy_get_presence(buddy);
- if (purple_presence_is_idle(pre)) {
- GDateTime *idle = purple_presence_get_idle_time(pre);
- now = g_date_time_new_now_local();
- since = g_date_time_difference(now, idle);
- g_date_time_unref(now);
- st = purple_str_seconds_to_string(since / G_TIME_SPAN_SECOND);
- purple_notify_user_info_add_pair_plaintext(user_info, _("Idle"), st);
- tmp = purple_notify_user_info_get_text_with_newline(user_info, "<BR>");
- purple_notify_user_info_destroy(user_info);
- strip = purple_markup_strip_html(tmp);
- g_string_append(str, strip);
- if (purple_presence_is_status_primitive_active(presence, PURPLE_STATUS_MOBILE)) {
- g_string_append(str, "\n");
- g_string_append(str, _("On Mobile"));
-make_sure_text_fits(GString *string)
- int maxw = getmaxx(stdscr) - 3;
- char *str = gnt_util_onscreen_fit_string(string->str, maxw);
- string = g_string_assign(string, str);
-draw_tooltip_real(FinchBuddyList *ggblist)
- int x, y, top, width, w, h;
- GntWidget *widget, *box, *tv;
- widget = ggblist->tree;
- tree = GNT_TREE(widget);
- if (!gnt_widget_has_focus(ggblist->tree) ||
- (ggblist->context && gnt_widget_get_visible(ggblist->context)))
- /* XXX: Once we can properly redraw on expose events, this can be removed at the end
- * to avoid the blinking*/
- remove_tooltip(ggblist);
- node = gnt_tree_get_selection_data(tree);
- if (!ggblist->manager->create_tooltip(node, &str, &title))
- gnt_widget_get_position(widget, &x, &y);
- gnt_widget_get_size(widget, &width, NULL);
- top = gnt_tree_get_selection_visible_line(tree);
- box = gnt_box_new(FALSE, FALSE);
- gnt_box_set_toplevel(GNT_BOX(box), TRUE);
- gnt_widget_set_has_shadow(box, FALSE);
- gnt_box_set_title(GNT_BOX(box), title);
- str = make_sure_text_fits(str);
- gnt_util_get_text_bound(str->str, &w, &h);
- tv = gnt_text_view_new();
- gnt_widget_set_size(tv, w + 1, h);
- gnt_text_view_set_flag(GNT_TEXT_VIEW(tv), GNT_TEXT_VIEW_NO_SCROLL);
- gnt_box_add_widget(GNT_BOX(box), tv);
- if (x + w >= getmaxx(stdscr))
- gnt_widget_set_position(box, x, y);
- gnt_widget_set_take_focus(box, FALSE);
- gnt_widget_set_transient(box, TRUE);
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), str->str, GNT_TEXT_FLAG_NORMAL);
- gnt_text_view_scroll(GNT_TEXT_VIEW(tv), 0);
- g_string_free(str, TRUE);
- ggblist->tooltip = box;
- gnt_widget_set_name(ggblist->tooltip, "tooltip");
-draw_tooltip(FinchBuddyList *ggblist)
- /* When an account has signed off, it removes one buddy at a time.
- * Drawing the tooltip after removing each buddy is expensive. On
- * top of that, if the selected buddy belongs to the disconnected
- * account, then retrieving the tooltip for that causes crash. So
- * let's make sure we wait for all the buddies to be removed first.*/
- int id = g_timeout_add(0, G_SOURCE_FUNC(draw_tooltip_real), ggblist);
- g_object_set_data_full(G_OBJECT(ggblist->window), "draw_tooltip_calback",
- GINT_TO_POINTER(id), (GDestroyNotify)g_source_remove);
-selection_changed(G_GNUC_UNUSED GntWidget *widget, G_GNUC_UNUSED gpointer old,
- G_GNUC_UNUSED gpointer current, FinchBuddyList *ggblist)
- remove_peripherals(ggblist);
-context_menu(G_GNUC_UNUSED GntWidget *widget, FinchBuddyList *ggblist)
- draw_context_menu(ggblist);
-key_pressed(G_GNUC_UNUSED GntWidget *widget, const char *text,
- FinchBuddyList *ggblist)
- if (text[0] == 27 && text[1] == 0) {
- /* Escape was pressed */
- if (gnt_tree_is_searching(GNT_TREE(ggblist->tree)))
- gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist->tree), "end-search", NULL);
- remove_peripherals(ggblist);
- } else if (purple_strequal(text, GNT_KEY_INS)) {
- PurpleBlistNode *node = gnt_tree_get_selection_data(GNT_TREE(ggblist->tree));
- purple_blist_request_add_buddy(NULL, NULL,
- node && PURPLE_IS_GROUP(node) ? purple_group_get_name(PURPLE_GROUP(node)) : NULL,
- } else if (!gnt_tree_is_searching(GNT_TREE(ggblist->tree))) {
- if (purple_strequal(text, "t")) {
- finch_blist_toggle_tag_buddy(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)));
- gnt_bindable_perform_action_named(GNT_BINDABLE(ggblist->tree), "move-down", NULL);
- } else if (purple_strequal(text, "a")) {
- finch_blist_place_tagged(gnt_tree_get_selection_data(GNT_TREE(ggblist->tree)));
-update_node_display(PurpleBlistNode *node, FinchBuddyList *ggblist)
- GntTextFormatFlags flag = get_blist_node_flag(ggblist, node);
- gnt_tree_set_row_flags(GNT_TREE(ggblist->tree), node, flag);
-update_buddy_display(PurpleBuddy *buddy, FinchBuddyList *ggblist)
- PurpleMetaContact *contact;
- contact = purple_buddy_get_contact(buddy);
- gnt_tree_change_text(GNT_TREE(ggblist->tree), buddy, 0, get_display_name((PurpleBlistNode*)buddy));
- gnt_tree_change_text(GNT_TREE(ggblist->tree), contact, 0, get_display_name((PurpleBlistNode*)contact));
- blist_update_row_flags(ggblist, (PurpleBlistNode *)buddy);
- if (buddy == purple_meta_contact_get_priority_buddy(contact))
- blist_update_row_flags(ggblist, (PurpleBlistNode *)contact);
- if (ggblist->tnode == (PurpleBlistNode *)buddy) {
-buddy_status_changed(PurpleBuddy *buddy, G_GNUC_UNUSED PurpleStatus *old,
- G_GNUC_UNUSED PurpleStatus *now, FinchBuddyList *ggblist)
- update_buddy_display(buddy, ggblist);
-buddy_idle_changed(PurpleBuddy *buddy, G_GNUC_UNUSED int old,
- G_GNUC_UNUSED int new, FinchBuddyList *ggblist)
- update_buddy_display(buddy, ggblist);
-remove_peripherals(FinchBuddyList *ggblist)
- remove_tooltip(ggblist);
- else if (ggblist->context)
- gnt_widget_destroy(ggblist->context);
-size_changed_cb(GntWidget *w, G_GNUC_UNUSED int wi, G_GNUC_UNUSED int h)
- gnt_widget_get_size(w, &width, &height);
- purple_prefs_set_int(PREF_ROOT "/size/width", width);
- purple_prefs_set_int(PREF_ROOT "/size/height", height);
-save_position_cb(G_GNUC_UNUSED GntWidget *w, int x, int y)
- purple_prefs_set_int(PREF_ROOT "/position/x", x);
- purple_prefs_set_int(PREF_ROOT "/position/y", y);
-reset_blist_window(G_GNUC_UNUSED GntWidget *window,
- G_GNUC_UNUSED gpointer data)
- purple_signals_disconnect_by_handle(finch_blist_get_handle());
- g_clear_handle_id(&ggblist->typing, g_source_remove);
- remove_peripherals(ggblist);
- g_clear_list(&ggblist->tagged, NULL);
- g_clear_handle_id(&ggblist->new_group_timeout, g_source_remove);
- g_clear_list(&ggblist->new_group, NULL);
-populate_buddylist(void)
- if (ggblist->manager->init)
- ggblist->manager->init();
- if (purple_strequal(purple_prefs_get_string(PREF_ROOT "/sort_type"), "text")) {
- gnt_tree_set_compare_func(GNT_TREE(ggblist->tree),
- (GCompareFunc)blist_node_compare_text);
- } else if (purple_strequal(purple_prefs_get_string(PREF_ROOT "/sort_type"), "status")) {
- gnt_tree_set_compare_func(GNT_TREE(ggblist->tree),
- (GCompareFunc)blist_node_compare_status);
- list = purple_blist_get_default();
- node = purple_blist_get_root(list);
- node_update(list, node);
- node = purple_blist_node_next(node, FALSE);
-destroy_status_list(GList *list)
- g_list_free_full(list, g_free);
-populate_status_dropdown(void)
- StatusBoxItem *item = NULL;
- /* First the primitives */
- PurpleStatusPrimitive prims[] = {PURPLE_STATUS_AVAILABLE, PURPLE_STATUS_AWAY,
- PURPLE_STATUS_INVISIBLE, PURPLE_STATUS_OFFLINE, PURPLE_STATUS_UNSET};
- gnt_combo_box_remove_all(GNT_COMBO_BOX(ggblist->status));
- for (i = 0; prims[i] != PURPLE_STATUS_UNSET; i++)
- item = g_new0(StatusBoxItem, 1);
- item->type = STATUS_PRIMITIVE;
- item->u.prim = prims[i];
- items = g_list_prepend(items, item);
- gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item,
- purple_primitive_get_name_from_type(prims[i]));
- /* Now the popular statuses */
- for (iter = purple_savedstatuses_get_popular(6); iter; iter = g_list_delete_link(iter, iter))
- item = g_new0(StatusBoxItem, 1);
- item->type = STATUS_SAVED_POPULAR;
- item->u.saved = iter->data;
- items = g_list_prepend(items, item);
- gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item,
- purple_savedstatus_get_title(iter->data));
- item = g_new0(StatusBoxItem, 1);
- item->type = STATUS_SAVED_NEW;
- items = g_list_prepend(items, item);
- gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item,
- /* More savedstatuses */
- item = g_new0(StatusBoxItem, 1);
- item->type = STATUS_SAVED_ALL;
- items = g_list_prepend(items, item);
- gnt_combo_box_add_data(GNT_COMBO_BOX(ggblist->status), item,
- /* The keys for the combobox are created here, and never used
- * anywhere else. So make sure the keys are freed when the widget
- g_object_set_data_full(G_OBJECT(ggblist->status), "list of statuses",
- items, (GDestroyNotify)destroy_status_list);
-redraw_blist(G_GNUC_UNUSED const char *name, G_GNUC_UNUSED PurplePrefType type,
- G_GNUC_UNUSED gconstpointer val, G_GNUC_UNUSED gpointer data)
- FinchBlistManager *manager;
- manager = finch_blist_manager_find(purple_prefs_get_string(PREF_ROOT "/grouping"));
- manager = &default_manager;
- if (ggblist->manager != manager) {
- if (ggblist->manager->uninit)
- ggblist->manager->uninit();
- ggblist->manager = manager;
- if (manager->can_add_node == NULL)
- manager->can_add_node = default_can_add_node;
- if (manager->find_parent == NULL)
- manager->find_parent = default_find_parent;
- if (manager->create_tooltip == NULL)
- manager->create_tooltip = default_create_tooltip;
- if (ggblist->window == NULL)
- sel = gnt_tree_get_selection_data(GNT_TREE(ggblist->tree));
- gnt_tree_remove_all(GNT_TREE(ggblist->tree));
- gnt_tree_set_selected(GNT_TREE(ggblist->tree), sel);
- color_available = gnt_style_get_color(NULL, "color-available");
- color_available = gnt_color_add_pair(COLOR_GREEN, -1);
- color_away = gnt_style_get_color(NULL, "color-away");
- color_away = gnt_color_add_pair(COLOR_BLUE, -1);
- color_idle = gnt_style_get_color(NULL, "color-idle");
- color_idle = gnt_color_add_pair(COLOR_CYAN, -1);
- color_offline = gnt_style_get_color(NULL, "color-offline");
- color_offline = gnt_color_add_pair(COLOR_RED, -1);
- purple_prefs_add_none(PREF_ROOT);
- purple_prefs_add_none(PREF_ROOT "/size");
- purple_prefs_add_int(PREF_ROOT "/size/width", 20);
- purple_prefs_add_int(PREF_ROOT "/size/height", 17);
- purple_prefs_add_none(PREF_ROOT "/position");
- purple_prefs_add_int(PREF_ROOT "/position/x", 0);
- purple_prefs_add_int(PREF_ROOT "/position/y", 0);
- purple_prefs_add_bool(PREF_ROOT "/idletime", TRUE);
- purple_prefs_add_bool(PREF_ROOT "/showoffline", FALSE);
- purple_prefs_add_bool(PREF_ROOT "/emptygroups", FALSE);
- purple_prefs_add_string(PREF_ROOT "/sort_type", "text");
- purple_prefs_add_string(PREF_ROOT "/grouping", "default");
- purple_prefs_connect_callback(finch_blist_get_handle(),
- PREF_ROOT "/emptygroups", redraw_blist, NULL);
- purple_prefs_connect_callback(finch_blist_get_handle(),
- PREF_ROOT "/showoffline", redraw_blist, NULL);
- purple_prefs_connect_callback(finch_blist_get_handle(),
- PREF_ROOT "/sort_type", redraw_blist, NULL);
- purple_prefs_connect_callback(finch_blist_get_handle(),
- PREF_ROOT "/grouping", redraw_blist, NULL);
- purple_signal_connect_priority(purple_connections_get_handle(),
- "autojoin", purple_blist_get_handle(),
- G_CALLBACK(account_autojoin_cb), NULL,
- PURPLE_SIGNAL_PRIORITY_HIGHEST);
- finch_blist_install_manager(&default_manager);
-remove_typing_cb(G_GNUC_UNUSED gpointer data)
- PurpleSavedStatus *current;
- const char *message, *newmessage;
- PurpleStatusPrimitive prim, newprim;
- current = purple_savedstatus_get_current();
- message = purple_savedstatus_get_message(current);
- prim = purple_savedstatus_get_primitive_type(current);
- newmessage = gnt_entry_get_text(GNT_ENTRY(ggblist->statustext));
- item = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(ggblist->status));
- escnewmessage = newmessage ? g_markup_escape_text(newmessage, -1) : NULL;
- newprim = item->u.prim;
- case STATUS_SAVED_POPULAR:
- newprim = purple_savedstatus_get_primitive_type(item->u.saved);
- goto end; /* 'New' or 'Saved' is selected, but this should never happen. */
- if (newprim != prim || ((message && !escnewmessage) ||
- (!message && escnewmessage) ||
- (message && escnewmessage && g_utf8_collate(message, escnewmessage) != 0)))
- PurpleSavedStatus *status = purple_savedstatus_find_transient_by_type_and_message(newprim, escnewmessage);
- /* Holy Crap! That's a LAWNG function name */
- status = purple_savedstatus_new(NULL, newprim);
- purple_savedstatus_set_message(status, escnewmessage);
- purple_savedstatus_activate(status);
- gnt_box_give_focus_to_child(GNT_BOX(ggblist->window), ggblist->tree);
- g_clear_handle_id(&ggblist->typing, g_source_remove);
-status_selection_changed(G_GNUC_UNUSED GntComboBox *box,
- G_GNUC_UNUSED StatusBoxItem *old,
- G_GNUC_UNUSED gpointer data)
- gnt_entry_set_text(GNT_ENTRY(ggblist->statustext), NULL);
- if (now->type == STATUS_SAVED_POPULAR)
- /* Set the status immediately */
- purple_savedstatus_activate(now->u.saved);
- else if (now->type == STATUS_PRIMITIVE)
- /* Move the focus to the entry box */
- /* XXX: Make sure the selected status can have a message */
- gnt_box_move_focus(GNT_BOX(ggblist->window), 1);
- ggblist->typing = g_timeout_add_seconds(TYPING_TIMEOUT_S,
- G_SOURCE_FUNC(remove_typing_cb),
- else if (now->type == STATUS_SAVED_ALL)
- /* Restore the selection to reflect current status. */
- savedstatus_changed(purple_savedstatus_get_current(), NULL);
- gnt_box_give_focus_to_child(GNT_BOX(ggblist->window), ggblist->tree);
- finch_savedstatus_show_all();
- else if (now->type == STATUS_SAVED_NEW)
- savedstatus_changed(purple_savedstatus_get_current(), NULL);
- gnt_box_give_focus_to_child(GNT_BOX(ggblist->window), ggblist->tree);
- finch_savedstatus_edit(NULL);
-status_text_changed(G_GNUC_UNUSED GntEntry *entry, const char *text,
- G_GNUC_UNUSED gpointer data)
- if ((text[0] == 27 || (text[0] == '\t' && text[1] == '\0')) && ggblist->typing == 0)
- g_clear_handle_id(&ggblist->typing, g_source_remove);
- if (text[0] == '\r' && text[1] == 0)
- /* Set the status only after you press 'Enter' */
- remove_typing_cb(NULL);
- ggblist->typing = g_timeout_add_seconds(TYPING_TIMEOUT_S,
- G_SOURCE_FUNC(remove_typing_cb),
-savedstatus_changed(PurpleSavedStatus *now,
- G_GNUC_UNUSED PurpleSavedStatus *old)
- PurpleStatusPrimitive prim;
- gboolean found = FALSE, saved = TRUE;
- /* Block the signals we don't want to emit */
- g_signal_handlers_block_matched(ggblist->status, G_SIGNAL_MATCH_FUNC,
- 0, 0, NULL, status_selection_changed, NULL);
- g_signal_handlers_block_matched(ggblist->statustext, G_SIGNAL_MATCH_FUNC,
- 0, 0, NULL, status_text_changed, NULL);
- prim = purple_savedstatus_get_primitive_type(now);
- message = purple_savedstatus_get_message(now);
- /* Rebuild the status dropdown */
- populate_status_dropdown();
- list = g_object_get_data(G_OBJECT(ggblist->status), "list of statuses");
- for (; list; list = list->next)
- StatusBoxItem *item = list->data;
- if ((saved && item->type != STATUS_PRIMITIVE && item->u.saved == now) ||
- (!saved && item->type == STATUS_PRIMITIVE && item->u.prim == prim))
- char *mess = purple_unescape_html(message);
- gnt_combo_box_set_selected(GNT_COMBO_BOX(ggblist->status), item);
- gnt_entry_set_text(GNT_ENTRY(ggblist->statustext), mess);
- gnt_widget_draw(ggblist->status);
- g_signal_handlers_unblock_matched(ggblist->status, G_SIGNAL_MATCH_FUNC,
- 0, 0, NULL, status_selection_changed, NULL);
- g_signal_handlers_unblock_matched(ggblist->statustext, G_SIGNAL_MATCH_FUNC,
- 0, 0, NULL, status_text_changed, NULL);
-blist_node_compare_position(PurpleBlistNode *n1, PurpleBlistNode *n2)
- while ((n1 = purple_blist_node_get_sibling_prev(n1)) != NULL)
-blist_node_compare_text(PurpleBlistNode *n1, PurpleBlistNode *n2)
- if (G_OBJECT_TYPE(n1) != G_OBJECT_TYPE(n2))
- return blist_node_compare_position(n1, n2);
- if (PURPLE_IS_CHAT(n1)) {
- s1 = purple_chat_get_name((PurpleChat*)n1);
- s2 = purple_chat_get_name((PurpleChat*)n2);
- } else if (PURPLE_IS_BUDDY(n1)) {
- return purple_buddy_presence_compare(
- PURPLE_BUDDY_PRESENCE(purple_buddy_get_presence(PURPLE_BUDDY(n1))),
- PURPLE_BUDDY_PRESENCE(purple_buddy_get_presence(PURPLE_BUDDY(n2))));
- } else if (PURPLE_IS_META_CONTACT(n1)) {
- s1 = purple_meta_contact_get_alias((PurpleMetaContact*)n1);
- s2 = purple_meta_contact_get_alias((PurpleMetaContact*)n2);
- return blist_node_compare_position(n1, n2);
- us1 = g_utf8_strup(s1, -1);
- us2 = g_utf8_strup(s2, -1);
- ret = g_utf8_collate(us1, us2);
-blist_node_compare_status(PurpleBlistNode *n1, PurpleBlistNode *n2)
- if (G_OBJECT_TYPE(n1) != G_OBJECT_TYPE(n2))
- return blist_node_compare_position(n1, n2);
- if (PURPLE_IS_META_CONTACT(n1))
- n1 = PURPLE_BLIST_NODE(purple_meta_contact_get_priority_buddy(PURPLE_META_CONTACT(n1)));
- if (PURPLE_IS_META_CONTACT(n2))
- n2 = PURPLE_BLIST_NODE(purple_meta_contact_get_priority_buddy(PURPLE_META_CONTACT(n2)));
- if (PURPLE_IS_BUDDY(n1) && PURPLE_IS_BUDDY(n2)) {
- ret = purple_buddy_presence_compare(
- PURPLE_BUDDY_PRESENCE(purple_buddy_get_presence(PURPLE_BUDDY(n1))),
- PURPLE_BUDDY_PRESENCE(purple_buddy_get_presence(PURPLE_BUDDY(n2))));
- return blist_node_compare_position(n1, n2);
- /* Sort alphabetically if presence is not comparable */
- ret = blist_node_compare_text(n1, n2);
-plugin_action(G_GNUC_UNUSED GntMenuItem *item, G_GNUC_UNUSED gpointer data)
- /* TODO: Convert to GAction/GMenu. */
- PurplePluginAction *action = data;
- if (action && action->callback)
- action->callback(action);
-build_plugin_actions(G_GNUC_UNUSED GntMenuItem *item,
- G_GNUC_UNUSED PurplePlugin *plugin)
- /* TODO: port to GAction/GMenu. */
- GntWidget *sub = gnt_menu_new(GNT_MENU_POPUP);
- PurplePluginActionsCb actions_cb;
- purple_plugin_info_get_actions_cb(purple_plugin_get_info(plugin));
- gnt_menuitem_set_submenu(item, GNT_MENU(sub));
- for (actions = actions_cb(plugin); actions;
- actions = g_list_delete_link(actions, actions)) {
- PurplePluginAction *action = actions->data;
- action->plugin = plugin;
- menuitem = gnt_menuitem_new(action->label);
- gnt_menu_add_item(GNT_MENU(sub), menuitem);
- gnt_menuitem_set_callback(menuitem, plugin_action, action);
- g_object_set_data_full(G_OBJECT(menuitem), "plugin_action",
- action, (GDestroyNotify)purple_plugin_action_free);
-protocol_action(G_GNUC_UNUSED GntMenuItem *item, gpointer data) {
- PurpleProtocolAction *action = data;
- if (action && action->callback)
- action->callback(action);
-build_protocol_actions(G_GNUC_UNUSED GntMenuItem *item,
- G_GNUC_UNUSED PurpleProtocol *protocol,
- G_GNUC_UNUSED PurpleConnection *gc)
- /* TODO: port to PurpleProtocolActions. */
- GntWidget *sub = gnt_menu_new(GNT_MENU_POPUP);
- gnt_menuitem_set_submenu(item, GNT_MENU(sub));
- for (actions = purple_protocol_client_get_actions(PURPLE_PROTOCOL_CLIENT(protocol), gc);
- actions; actions = g_list_delete_link(actions, actions)) {
- PurpleProtocolAction *action = actions->data;
- action->connection = gc;
- menuitem = gnt_menuitem_new(action->label);
- gnt_menu_add_item(GNT_MENU(sub), menuitem);
- gnt_menuitem_set_callback(menuitem, protocol_action, action);
- g_object_set_data_full(G_OBJECT(menuitem), "protocol_action",
- action, (GDestroyNotify)purple_protocol_action_free);
-buddy_recent_signed_on_off(gpointer data)
- PurpleBlistNode *node = data;
- FinchBlistNode *fnode = g_object_get_data(G_OBJECT(node), UI_DATA);
- g_clear_handle_id(&fnode->signed_timer, g_source_remove);
- if (!ggblist->manager->can_add_node(node)) {
- node_remove(purple_blist_get_default(), node);
- update_node_display(node, ggblist);
- if (purple_blist_node_get_parent(node) && PURPLE_IS_META_CONTACT(purple_blist_node_get_parent(node)))
- update_node_display(purple_blist_node_get_parent(node), ggblist);
-buddy_signed_on_off_cb(gpointer data)
- PurpleBlistNode *node = data;
- FinchBlistNode *fnode = g_object_get_data(G_OBJECT(node), UI_DATA);
- if(!ggblist || !fnode) {
- g_clear_handle_id(&fnode->signed_timer, g_source_remove);
- fnode->signed_timer = g_timeout_add_seconds(6,
- G_SOURCE_FUNC(buddy_recent_signed_on_off),
- update_node_display(node, ggblist);
- if (purple_blist_node_get_parent(node) && PURPLE_IS_META_CONTACT(purple_blist_node_get_parent(node)))
- update_node_display(purple_blist_node_get_parent(node), ggblist);
-buddy_signed_on_off(PurpleBuddy* buddy, G_GNUC_UNUSED gpointer data)
- g_idle_add(buddy_signed_on_off_cb, buddy);
-reconstruct_plugins_menu(void)
- if (ggblist->plugins == NULL)
- ggblist->plugins = gnt_menuitem_new(_("Plugins"));
- plg = ggblist->plugins;
- sub = gnt_menu_new(GNT_MENU_POPUP);
- gnt_menuitem_set_submenu(plg, GNT_MENU(sub));
- /* TODO: port to GAction/GMenu. */
- for (iter = purple_plugins_get_loaded(); iter; iter = iter->next) {
- PurplePlugin *plugin = iter->data;
- PurplePluginInfo *info = purple_plugin_get_info(plugin);
- if (!purple_plugin_info_get_actions_cb(info))
- item = gnt_menuitem_new(_(gplugin_plugin_info_get_name(
- GPLUGIN_PLUGIN_INFO(info))));
- gnt_menu_add_item(GNT_MENU(sub), item);
- build_plugin_actions(item, plugin);
-reconstruct_plugins_menu_cb(G_GNUC_UNUSED GObject *plugin_manager,
- G_GNUC_UNUSED GPluginPlugin *plugin,
- G_GNUC_UNUSED gpointer data)
- reconstruct_plugins_menu();
-reconstruct_accounts_menu(void) {
- PurpleAccountManager *manager = NULL;
- if (ggblist->accounts == NULL)
- ggblist->accounts = gnt_menuitem_new(_("Accounts"));
- acc = ggblist->accounts;
- sub = gnt_menu_new(GNT_MENU_POPUP);
- gnt_menuitem_set_submenu(acc, GNT_MENU(sub));
- manager = purple_account_manager_get_default();
- iter = purple_account_manager_get_enabled(manager);
- for (; iter; iter = g_list_delete_link(iter, iter)) {
- PurpleAccount *account = iter->data;
- PurpleConnection *gc = purple_account_get_connection(account);
- PurpleProtocol *protocol;
- if (!gc || !PURPLE_CONNECTION_IS_CONNECTED(gc))
- protocol = purple_connection_get_protocol(gc);
- /* TODO: port to PurpleProtocolActions */
- if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, CLIENT, get_actions)) {
- PurpleContactInfo *info = PURPLE_CONTACT_INFO(account);
- item = gnt_menuitem_new(purple_contact_info_get_username(info));
- gnt_menu_add_item(GNT_MENU(sub), item);
- build_protocol_actions(item, protocol, gc);
-reconstruct_grouping_menu(void)
- if (!ggblist || !ggblist->grouping)
- subsub = gnt_menu_new(GNT_MENU_POPUP);
- gnt_menuitem_set_submenu(ggblist->grouping, GNT_MENU(subsub));
- for (iter = managers; iter; iter = iter->next) {
- FinchBlistManager *manager = iter->data;
- GntMenuItem *item = gnt_menuitem_new(_(manager->name));
- g_snprintf(menuid, sizeof(menuid), "grouping-%s", manager->id);
- gnt_menuitem_set_id(GNT_MENU_ITEM(item), menuid);
- gnt_menu_add_item(GNT_MENU(subsub), item);
- g_object_set_data_full(G_OBJECT(item), "grouping-id", g_strdup(manager->id), g_free);
- gnt_menuitem_set_callback(item, menu_group_set_cb, NULL);
-auto_join_chats(gpointer data)
- PurpleConnection *pc = data;
- PurpleAccount *account = purple_connection_get_account(pc);
- for (node = purple_blist_get_default_root(); node;
- node = purple_blist_node_next(node, FALSE)) {
- if (PURPLE_IS_CHAT(node)) {
- PurpleChat *chat = (PurpleChat*)node;
- if (purple_chat_get_account(chat) == account &&
- purple_blist_node_get_bool(node, "gnt-autojoin"))
- purple_serv_join_chat(purple_account_get_connection(account), purple_chat_get_components(chat));
-account_autojoin_cb(PurpleConnection *gc, G_GNUC_UNUSED gpointer data)
- g_idle_add(auto_join_chats, gc);
-static void toggle_pref_cb(G_GNUC_UNUSED GntMenuItem *item, gpointer n)
- purple_prefs_set_bool(n, !purple_prefs_get_bool(n));
-static void sort_blist_change_cb(G_GNUC_UNUSED GntMenuItem *item, gpointer n)
- purple_prefs_set_string(PREF_ROOT "/sort_type", n);
-/* send_im_select* -- Xerox */
-send_im_select_cb(G_GNUC_UNUSED gpointer data, PurpleRequestPage *page) {
- PurpleAccount *account;
- PurpleConversation *im;
- account = purple_request_page_get_account(page, "account");
- username = purple_request_page_get_string(page, "screenname");
- im = purple_im_conversation_new(account, username);
- purple_conversation_present(im);
-send_im_select(G_GNUC_UNUSED GntMenuItem *item, G_GNUC_UNUSED gpointer n)
- PurpleRequestPage *page;
- PurpleRequestGroup *group;
- PurpleRequestField *field;
- page = purple_request_page_new();
- group = purple_request_group_new(NULL);
- purple_request_page_add_group(page, group);
- field = purple_request_field_string_new("screenname", _("Name"), NULL, FALSE);
- purple_request_field_set_type_hint(field, "screenname");
- purple_request_field_set_required(field, TRUE);
- purple_request_group_add_field(group, field);
- field = purple_request_field_account_new("account", _("Account"), NULL);
- purple_request_field_set_type_hint(field, "account");
- purple_request_field_set_visible(field,
- (purple_connections_get_all() != NULL &&
- purple_connections_get_all()->next != NULL));
- purple_request_field_set_required(field, TRUE);
- purple_request_group_add_field(group, field);
- purple_blist_get_default(), _("New Instant Message"), NULL,
- _("Please enter the username or alias of the person "
- "you would like to IM."),
- page, _("OK"), G_CALLBACK(send_im_select_cb), _("Cancel"),
-join_chat_select_cb(G_GNUC_UNUSED gpointer data, PurpleRequestPage *page) {
- PurpleAccount *account;
- PurpleConversationManager *manager;
- GHashTable *hash = NULL;
- PurpleConversation *conv;
- account = purple_request_page_get_account(page, "account");
- name = purple_request_page_get_string(page, "chat");
- if (!purple_account_is_connected(account))
- gc = purple_account_get_connection(account);
- manager = purple_conversation_manager_get_default();
- /* Create a new conversation now. This will give focus to the new window.
- * But it's necessary to pretend that we left the chat, because otherwise
- * a new conversation window will pop up when we finally join the chat. */
- conv = purple_conversation_manager_find_chat(manager, account, name);
- if(!PURPLE_IS_CHAT_CONVERSATION(conv)) {
- conv = purple_chat_conversation_new(account, name);
- purple_chat_conversation_leave(PURPLE_CHAT_CONVERSATION(conv));
- purple_conversation_present(conv);
- chat = purple_blist_find_chat(account, name);
- PurpleProtocol *protocol = purple_connection_get_protocol(gc);
- hash = purple_protocol_chat_info_defaults(PURPLE_PROTOCOL_CHAT(protocol), gc, name);
- hash = purple_chat_get_components(chat);
- purple_serv_join_chat(gc, hash);
- if (chat == NULL && hash != NULL)
- g_hash_table_destroy(hash);
-join_chat_select(G_GNUC_UNUSED GntMenuItem *item, G_GNUC_UNUSED gpointer n)
- PurpleRequestPage *page;
- PurpleRequestGroup *group;
- PurpleRequestField *field;
- page = purple_request_page_new();
- group = purple_request_group_new(NULL);
- purple_request_page_add_group(page, group);
- field = purple_request_field_string_new("chat", _("Channel"), NULL, FALSE);
- purple_request_field_set_required(field, TRUE);
- purple_request_group_add_field(group, field);
- field = purple_request_field_account_new("account", _("Account"), NULL);
- purple_request_field_set_type_hint(field, "account");
- purple_request_field_set_visible(field,
- (purple_connections_get_all() != NULL &&
- purple_connections_get_all()->next != NULL));
- purple_request_field_set_required(field, TRUE);
- purple_request_group_add_field(group, field);
- purple_blist_get_default(), _("Join a Chat"), NULL,
- _("Please enter the name of the chat you want to join."),
- page, _("Join"), G_CALLBACK(join_chat_select_cb), _("Cancel"),
-menu_add_buddy_cb(G_GNUC_UNUSED GntMenuItem *item, G_GNUC_UNUSED gpointer data)
- purple_blist_request_add_buddy(NULL, NULL, NULL, NULL);
-menu_add_chat_cb(G_GNUC_UNUSED GntMenuItem *item, G_GNUC_UNUSED gpointer data)
- purple_blist_request_add_chat(NULL, NULL, NULL, NULL);
-menu_add_group_cb(G_GNUC_UNUSED GntMenuItem *item, G_GNUC_UNUSED gpointer data)
- purple_blist_request_add_group();
-menu_group_set_cb(GntMenuItem *item, G_GNUC_UNUSED gpointer data)
- const char *id = g_object_get_data(G_OBJECT(item), "grouping-id");
- purple_prefs_set_string(PREF_ROOT "/grouping", id);
- GntWidget *menu, *sub, *subsub;
- window = GNT_WINDOW(ggblist->window);
- ggblist->menu = menu = gnt_menu_new(GNT_MENU_TOPLEVEL);
- gnt_window_set_menu(window, GNT_MENU(menu));
- item = gnt_menuitem_new(_("Options"));
- gnt_menu_add_item(GNT_MENU(menu), item);
- sub = gnt_menu_new(GNT_MENU_POPUP);
- gnt_menuitem_set_submenu(item, GNT_MENU(sub));
- item = gnt_menuitem_new(_("Send IM..."));
- gnt_menuitem_set_id(GNT_MENU_ITEM(item), "send-im");
- gnt_menu_add_item(GNT_MENU(sub), item);
- gnt_menuitem_set_callback(GNT_MENU_ITEM(item), send_im_select, NULL);
- item = gnt_menuitem_new(_("Join Chat..."));
- gnt_menuitem_set_id(GNT_MENU_ITEM(item), "join-chat");
- gnt_menu_add_item(GNT_MENU(sub), item);
- gnt_menuitem_set_callback(GNT_MENU_ITEM(item), join_chat_select, NULL);
- item = gnt_menuitem_new(_("Show"));
- gnt_menu_add_item(GNT_MENU(sub), item);
- subsub = gnt_menu_new(GNT_MENU_POPUP);
- gnt_menuitem_set_submenu(item, GNT_MENU(subsub));
- item = gnt_menuitem_check_new(_("Empty groups"));
- gnt_menuitem_set_id(GNT_MENU_ITEM(item), "show-empty-groups");
- gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item),
- purple_prefs_get_bool(PREF_ROOT "/emptygroups"));
- gnt_menu_add_item(GNT_MENU(subsub), item);
- gnt_menuitem_set_callback(GNT_MENU_ITEM(item), toggle_pref_cb, PREF_ROOT "/emptygroups");
- item = gnt_menuitem_check_new(_("Offline buddies"));
- gnt_menuitem_set_id(GNT_MENU_ITEM(item), "show-offline-buddies");
- gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item),
- purple_prefs_get_bool(PREF_ROOT "/showoffline"));
- gnt_menu_add_item(GNT_MENU(subsub), item);
- gnt_menuitem_set_callback(GNT_MENU_ITEM(item), toggle_pref_cb, PREF_ROOT "/showoffline");
- item = gnt_menuitem_new(_("Sort"));
- gnt_menu_add_item(GNT_MENU(sub), item);
- subsub = gnt_menu_new(GNT_MENU_POPUP);
- gnt_menuitem_set_submenu(item, GNT_MENU(subsub));
- item = gnt_menuitem_new(_("By Status"));
- gnt_menuitem_set_id(GNT_MENU_ITEM(item), "sort-status");
- gnt_menu_add_item(GNT_MENU(subsub), item);
- gnt_menuitem_set_callback(GNT_MENU_ITEM(item), sort_blist_change_cb, "status");
- item = gnt_menuitem_new(_("Alphabetically"));
- gnt_menuitem_set_id(GNT_MENU_ITEM(item), "sort-alpha");
- gnt_menu_add_item(GNT_MENU(subsub), item);
- gnt_menuitem_set_callback(GNT_MENU_ITEM(item), sort_blist_change_cb, "text");
- item = gnt_menuitem_new(_("By Log Size"));
- gnt_menuitem_set_id(GNT_MENU_ITEM(item), "sort-log");
- gnt_menu_add_item(GNT_MENU(subsub), item);
- gnt_menuitem_set_callback(GNT_MENU_ITEM(item), sort_blist_change_cb, "log");
- item = gnt_menuitem_new(_("Add"));
- gnt_menu_add_item(GNT_MENU(sub), item);
- subsub = gnt_menu_new(GNT_MENU_POPUP);
- gnt_menuitem_set_submenu(item, GNT_MENU(subsub));
- item = gnt_menuitem_new(_("Buddy"));
- gnt_menuitem_set_id(GNT_MENU_ITEM(item), "add-buddy");
- gnt_menu_add_item(GNT_MENU(subsub), item);
- gnt_menuitem_set_callback(item, menu_add_buddy_cb, NULL);
- item = gnt_menuitem_new(_("Chat"));
- gnt_menuitem_set_id(GNT_MENU_ITEM(item), "add-chat");
- gnt_menu_add_item(GNT_MENU(subsub), item);
- gnt_menuitem_set_callback(item, menu_add_chat_cb, NULL);
- item = gnt_menuitem_new(_("Group"));
- gnt_menuitem_set_id(GNT_MENU_ITEM(item), "add-group");
- gnt_menu_add_item(GNT_MENU(subsub), item);
- gnt_menuitem_set_callback(item, menu_add_group_cb, NULL);
- ggblist->grouping = item = gnt_menuitem_new(_("Grouping"));
- gnt_menu_add_item(GNT_MENU(sub), item);
- reconstruct_grouping_menu();
- reconstruct_accounts_menu();
- gnt_menu_add_item(GNT_MENU(menu), ggblist->accounts);
- reconstruct_plugins_menu();
- gnt_menu_add_item(GNT_MENU(menu), ggblist->plugins);
- blist_show(purple_blist_get_default());
-group_collapsed(G_GNUC_UNUSED GntWidget *widget, PurpleBlistNode *node,
- gboolean collapsed, G_GNUC_UNUSED gpointer data)
- if (PURPLE_IS_GROUP(node))
- purple_blist_node_set_bool(node, "collapsed", collapsed);
-blist_show(G_GNUC_UNUSED PurpleBuddyList *list)
- GPluginManager *plugin_manager = NULL;
- gnt_window_present(ggblist->window);
- ggblist->window = gnt_vwindow_new(FALSE);
- gnt_widget_set_name(ggblist->window, "buddylist");
- gnt_box_set_toplevel(GNT_BOX(ggblist->window), TRUE);
- gnt_box_set_title(GNT_BOX(ggblist->window), _("Buddy List"));
- gnt_box_set_pad(GNT_BOX(ggblist->window), 0);
- ggblist->tree = gnt_tree_new();
- gnt_widget_set_has_border(ggblist->tree, FALSE);
- gnt_widget_set_size(ggblist->tree, purple_prefs_get_int(PREF_ROOT "/size/width"),
- purple_prefs_get_int(PREF_ROOT "/size/height"));
- gnt_widget_set_position(ggblist->window, purple_prefs_get_int(PREF_ROOT "/position/x"),
- purple_prefs_get_int(PREF_ROOT "/position/y"));
- gnt_box_add_widget(GNT_BOX(ggblist->window), ggblist->tree);
- ggblist->status = gnt_combo_box_new();
- gnt_box_add_widget(GNT_BOX(ggblist->window), ggblist->status);
- ggblist->statustext = gnt_entry_new(NULL);
- gnt_box_add_widget(GNT_BOX(ggblist->window), ggblist->statustext);
- gnt_widget_show(ggblist->window);
- purple_signal_connect(purple_connections_get_handle(), "signed-on", finch_blist_get_handle(),
- G_CALLBACK(reconstruct_accounts_menu), NULL);
- purple_signal_connect(purple_connections_get_handle(), "signed-off", finch_blist_get_handle(),
- G_CALLBACK(reconstruct_accounts_menu), NULL);
- purple_signal_connect(purple_accounts_get_handle(), "account-actions-changed", finch_blist_get_handle(),
- G_CALLBACK(reconstruct_accounts_menu), NULL);
- purple_signal_connect(purple_blist_get_handle(), "buddy-status-changed", finch_blist_get_handle(),
- G_CALLBACK(buddy_status_changed), ggblist);
- purple_signal_connect(purple_blist_get_handle(), "buddy-idle-changed", finch_blist_get_handle(),
- G_CALLBACK(buddy_idle_changed), ggblist);
- plugin_manager = gplugin_manager_get_default();
- g_signal_connect_object(plugin_manager, "loaded-plugin",
- G_CALLBACK(reconstruct_plugins_menu_cb), ggblist, 0);
- g_signal_connect_object(plugin_manager, "unloaded-plugin",
- G_CALLBACK(reconstruct_plugins_menu_cb), ggblist, 0);
- purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", finch_blist_get_handle(),
- G_CALLBACK(buddy_signed_on_off), ggblist);
- purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", finch_blist_get_handle(),
- G_CALLBACK(buddy_signed_on_off), ggblist);
- g_signal_connect(G_OBJECT(ggblist->tree), "selection_changed", G_CALLBACK(selection_changed), ggblist);
- g_signal_connect(G_OBJECT(ggblist->tree), "key_pressed", G_CALLBACK(key_pressed), ggblist);
- g_signal_connect(G_OBJECT(ggblist->tree), "context-menu", G_CALLBACK(context_menu), ggblist);
- g_signal_connect(G_OBJECT(ggblist->tree), "collapse-toggled", G_CALLBACK(group_collapsed), NULL);
- g_signal_connect(G_OBJECT(ggblist->tree), "activate", G_CALLBACK(selection_activate), ggblist);
- g_signal_connect_data(G_OBJECT(ggblist->tree), "gained-focus", G_CALLBACK(draw_tooltip),
- ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
- g_signal_connect_data(G_OBJECT(ggblist->tree), "lost-focus", G_CALLBACK(remove_peripherals),
- ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
- g_signal_connect_data(G_OBJECT(ggblist->window), "workspace-hidden", G_CALLBACK(remove_peripherals),
- ggblist, 0, G_CONNECT_AFTER | G_CONNECT_SWAPPED);
- g_signal_connect(G_OBJECT(ggblist->tree), "size_changed", G_CALLBACK(size_changed_cb), NULL);
- g_signal_connect(G_OBJECT(ggblist->window), "position_set", G_CALLBACK(save_position_cb), NULL);
- g_signal_connect(G_OBJECT(ggblist->window), "destroy", G_CALLBACK(reset_blist_window), NULL);
- purple_signal_connect(purple_savedstatuses_get_handle(), "savedstatus-changed", finch_blist_get_handle(),
- G_CALLBACK(savedstatus_changed), NULL);
- g_signal_connect(G_OBJECT(ggblist->status), "selection_changed",
- G_CALLBACK(status_selection_changed), NULL);
- g_signal_connect(G_OBJECT(ggblist->statustext), "key_pressed",
- G_CALLBACK(status_text_changed), NULL);
- savedstatus_changed(purple_savedstatus_get_current(), NULL);
-finch_blist_uninit(void)
-gboolean finch_blist_get_position(int *x, int *y)
- if (!ggblist || !ggblist->window)
- gnt_widget_get_position(ggblist->window, x, y);
-void finch_blist_set_position(int x, int y)
- gnt_widget_set_position(ggblist->window, x, y);
-gboolean finch_blist_get_size(int *width, int *height)
- if (!ggblist || !ggblist->window)
- gnt_widget_get_size(ggblist->window, width, height);
-void finch_blist_set_size(int width, int height)
- gnt_widget_set_size(ggblist->window, width, height);
-void finch_blist_install_manager(const FinchBlistManager *manager)
- if (!g_list_find(managers, manager)) {
- managers = g_list_append(managers, (gpointer)manager);
- reconstruct_grouping_menu();
- if (purple_strequal(manager->id, purple_prefs_get_string(PREF_ROOT "/grouping")))
- purple_prefs_trigger_callback(PREF_ROOT "/grouping");
-void finch_blist_uninstall_manager(const FinchBlistManager *manager)
- if (g_list_find(managers, manager)) {
- managers = g_list_remove(managers, manager);
- reconstruct_grouping_menu();
- if (purple_strequal(manager->id, purple_prefs_get_string(PREF_ROOT "/grouping")))
- purple_prefs_trigger_callback(PREF_ROOT "/grouping");
-FinchBlistManager * finch_blist_manager_find(const char *id)
- GList *iter = managers;
- for (; iter; iter = iter->next) {
- FinchBlistManager *m = iter->data;
- if (purple_strequal(id, m->id))
-GntTree * finch_blist_get_tree(void)
- return ggblist ? GNT_TREE(ggblist->tree) : NULL;
-/**************************************************************************
- **************************************************************************/
-G_DEFINE_FINAL_TYPE(FinchBuddyList, finch_buddy_list, PURPLE_TYPE_BUDDY_LIST)
-finch_buddy_list_init(FinchBuddyList *self)
- /* The first buddy list object becomes the default. */
- self->manager = finch_blist_manager_find(
- purple_prefs_get_string(PREF_ROOT "/grouping"));
- self->manager = &default_manager;
-finch_buddy_list_finalize(GObject *obj)
- FinchBuddyList *ggblist = FINCH_BUDDY_LIST(obj);
- gnt_widget_destroy(ggblist->window);
- G_OBJECT_CLASS(finch_buddy_list_parent_class)->finalize(obj);
-finch_buddy_list_class_init(FinchBuddyListClass *klass)
- GObjectClass *obj_class = G_OBJECT_CLASS(klass);
- PurpleBuddyListClass *purple_blist_class;
- obj_class->finalize = finch_buddy_list_finalize;
- purple_blist_class = PURPLE_BUDDY_LIST_CLASS(klass);
- purple_blist_class->new_node = new_node;
- purple_blist_class->show = blist_show;
- purple_blist_class->update = node_update;
- purple_blist_class->remove = node_remove;
- purple_blist_class->request_add_buddy = finch_request_add_buddy;
- purple_blist_class->request_add_chat = finch_request_add_chat;
- purple_blist_class->request_add_group = finch_request_add_group;
-/**************************************************************************
- **************************************************************************/
-static FinchBlistManager *
-finch_blist_manager_copy(FinchBlistManager *manager)
- FinchBlistManager *manager_new;
- g_return_val_if_fail(manager != NULL, NULL);
- manager_new = g_new(FinchBlistManager, 1);
- *manager_new = *manager;
-finch_blist_manager_free(FinchBlistManager *manager)
- g_return_if_fail(manager != NULL);
-finch_blist_manager_get_type(void)
- type = g_boxed_type_register_static("FinchBlistManager",
- (GBoxedCopyFunc)finch_blist_manager_copy,
- (GBoxedFreeFunc)finch_blist_manager_free);
--- a/finch/gntblist.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,193 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-#define FINCH_TYPE_BUDDY_LIST (finch_buddy_list_get_type())
-#define FINCH_TYPE_BLIST_MANAGER (finch_blist_manager_get_type())
-/**********************************************************************
- **********************************************************************/
-typedef struct _FinchBlistManager FinchBlistManager;
- * @id: An identifier for the manager.
- * @name: Displayable name for the manager.
- * @init: Called right before it's being used.
- * @uninit: Called right after it's not being used any more.
- * @can_add_node: Whether a node should be added to the view.
- * @find_parent: Find the parent row for a node.
- * @create_tooltip: Create tooltip for a selected row.
- * Buddylist manager for finch. This decides the visility, ordering and hierarchy
- * of the buddylist nodes. This also manages the creation of tooltips.
-struct _FinchBlistManager
- gboolean (*init)(void);
- gboolean (*uninit)(void);
- gboolean (*can_add_node)(PurpleBlistNode *node);
- gpointer (*find_parent)(PurpleBlistNode *node);
- gboolean (*create_tooltip)(gpointer selected_row, GString **body, char **title);
-GType finch_blist_manager_get_type(void);
-G_DECLARE_FINAL_TYPE(FinchBuddyList, finch_buddy_list, FINCH, BUDDY_LIST,
- * Perform necessary initializations.
-void finch_blist_init(void);
- * Perform necessary uninitializations.
-void finch_blist_uninit(void);
-void finch_blist_show(void);
- * finch_blist_get_position:
- * @x: The x-coordinate is set here if not %NULL.
- * @y: The y-coordinate is set here if not %NULL.
- * Get the position of the buddy list.
- * Returns: Returns %TRUE if the values were set, %FALSE otherwise.
-gboolean finch_blist_get_position(int *x, int *y);
- * finch_blist_set_position:
- * @x: The x-coordinate of the buddy list.
- * @y: The y-coordinate of the buddy list.
- * Set the position of the buddy list.
-void finch_blist_set_position(int x, int y);
- * finch_blist_get_size:
- * @width: The width is set here if not %NULL.
- * @height: The height is set here if not %NULL.
- * Get the size of the buddy list.
- * Returns: Returns %TRUE if the values were set, %FALSE otherwise.
-gboolean finch_blist_get_size(int *width, int *height);
- * finch_blist_set_size:
- * @width: The width of the buddy list.
- * @height: The height of the buddy list.
- * Set the size of the buddy list.
-void finch_blist_set_size(int width, int height);
- * finch_retrieve_user_info:
- * @conn: The connection to get information from
- * @name: The user to get information about.
- * Get information about a user. Show immediate feedback.
- * Returns: (transfer none): Returns the ui-handle for the userinfo
-gpointer finch_retrieve_user_info(PurpleConnection *conn, const char *name);
- * finch_blist_get_tree:
- * Get the tree list of the buddy list.
- * Returns: (transfer none): The GntTree widget.
-GntTree * finch_blist_get_tree(void);
- * finch_blist_install_manager:
- * @manager: The alternate buddylist manager.
- * Add an alternate buddy list manager.
-void finch_blist_install_manager(const FinchBlistManager *manager);
- * finch_blist_uninstall_manager:
- * @manager: The buddy list manager to remove.
- * Remove an alternate buddy list manager.
-void finch_blist_uninstall_manager(const FinchBlistManager *manager);
- * finch_blist_manager_find:
- * @id: The identifier for the desired buddy list manager.
- * Find a buddy list manager.
- * Returns: The manager with the requested identifier, if available. %NULL
-FinchBlistManager * finch_blist_manager_find(const char *id);
- * finch_blist_manager_add_node:
- * @node: The node to add
- * Request the active buddy list manager to add a node.
-void finch_blist_manager_add_node(PurpleBlistNode *node);
-#endif /* FINCH_BLIST_H */
--- a/finch/gntconn.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,146 +0,0 @@
- * Finch 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>
-#define INITIAL_RECON_DELAY_MIN 8
-#define INITIAL_RECON_DELAY_MAX 60
-#define MAX_RECON_DELAY 600
- * Contains accounts that are auto-reconnecting.
- * The key is a pointer to the PurpleAccount and the
- * value is a pointer to a FinchAutoRecon.
-static GHashTable *hash = NULL;
-free_auto_recon(gpointer data)
- FinchAutoRecon *info = data;
- g_clear_handle_id(&info->timeout, g_source_remove);
-do_signon(gpointer data)
- PurpleAccount *account = data;
- purple_debug_info("autorecon", "do_signon called\n");
- g_return_val_if_fail(account != NULL, FALSE);
- info = g_hash_table_lookup(hash, account);
- status = purple_account_get_active_status(account);
- if (purple_status_is_online(status))
- purple_debug_info("autorecon", "calling purple_account_connect\n");
- purple_account_connect(account);
- purple_debug_info("autorecon", "done calling purple_account_connect\n");
-finch_connection_report_disconnect(PurpleConnection *gc,
- PurpleConnectionError reason,
- G_GNUC_UNUSED const char *text)
- PurpleAccount *account = purple_connection_get_account(gc);
- if (!purple_connection_error_is_fatal(reason)) {
- info = g_hash_table_lookup(hash, account);
- info = g_new0(FinchAutoRecon, 1);
- g_hash_table_insert(hash, account, info);
- info->delay = g_random_int_range(INITIAL_RECON_DELAY_MIN, INITIAL_RECON_DELAY_MAX);
- info->delay = MIN(2 * info->delay, MAX_RECON_DELAY);
- g_clear_handle_id(&info->timeout, g_source_remove);
- info->timeout = g_timeout_add_seconds(info->delay, do_signon, account);
- purple_account_set_enabled(account, FALSE);
-account_removed_cb(G_GNUC_UNUSED PurpleAccountManager *manager,
- PurpleAccount *account, G_GNUC_UNUSED gpointer data)
- g_hash_table_remove(hash, account);
-static PurpleConnectionUiOps ops = {
- .report_disconnect = finch_connection_report_disconnect,
-finch_connections_get_ui_ops(void)
-finch_connections_init(void)
- PurpleAccountManager *manager = purple_account_manager_get_default();
- hash = g_hash_table_new_full(
- g_direct_hash, g_direct_equal,
- NULL, free_auto_recon);
- g_signal_connect(manager, "removed", G_CALLBACK(account_removed_cb), NULL);
-finch_connections_uninit(void)
- PurpleAccountManager *manager = purple_account_manager_get_default();
- g_signal_handlers_disconnect_by_func(manager, account_removed_cb, NULL);
- g_clear_pointer(&hash, g_hash_table_destroy);
--- a/finch/gntconn.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-/**********************************************************************
- **********************************************************************/
- * finch_connections_get_ui_ops:
- * Get the ui-functions.
- * Returns: The PurpleConnectionUiOps structure populated with the appropriate functions.
-PurpleConnectionUiOps *finch_connections_get_ui_ops(void);
- * finch_connections_init:
- * Perform necessary initializations.
-void finch_connections_init(void);
- * finch_connections_uninit:
- * Perform necessary uninitializations.
-void finch_connections_uninit(void);
-#endif /* FINCH_CONN_H */
--- a/finch/gntconv.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1427 +0,0 @@
- * Finch 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 "purpleconfig.h"
-#include <glib/gi18n-lib.h>
-#include "gntmenuutil.h"
-#define PREF_ROOT "/finch/conversations"
-#define PREF_CHAT PREF_ROOT "/chats"
-#define PREF_USERLIST PREF_CHAT "/userlist"
-static void generate_send_to_menu(FinchConv *ggc);
-static int color_message_receive;
-static int color_message_send;
-static int color_message_highlight;
-static int color_message_action;
-static int color_timestamp;
-find_chat_for_conversation(PurpleConversation *conv)
- return purple_blist_find_chat(purple_conversation_get_account(conv),
- purple_conversation_get_name(conv));
-send_typing_notification(G_GNUC_UNUSED GntWidget *w, FinchConv *ggconv)
- const char *text = gnt_entry_get_text(GNT_ENTRY(ggconv->entry));
- gboolean empty = (!text || !*text || (*text == '/'));
- if (purple_prefs_get_bool("/finch/conversations/notify_typing")) {
- PurpleConversation *conv = ggconv->active_conv;
- PurpleIMConversation *im = PURPLE_IM_CONVERSATION(conv);
- gboolean send = (purple_im_conversation_get_send_typed_timeout(im) == 0);
- purple_im_conversation_stop_send_typed_timeout(im);
- purple_im_conversation_start_send_typed_timeout(im);
- if (send || (purple_im_conversation_get_type_again(im) != 0 &&
- time(NULL) > purple_im_conversation_get_type_again(im))) {
- timeout = purple_serv_send_typing(purple_conversation_get_connection(conv),
- purple_conversation_get_name(conv),
- purple_im_conversation_set_type_again(im, timeout);
- purple_im_conversation_stop_send_typed_timeout(im);
- purple_serv_send_typing(purple_conversation_get_connection(conv),
- purple_conversation_get_name(conv),
-entry_key_pressed(G_GNUC_UNUSED GntWidget *w, FinchConv *ggconv)
- const char *text = gnt_entry_get_text(GNT_ENTRY(ggconv->entry));
- if (*text == '/' && *(text + 1) != '/')
- PurpleConversation *conv = ggconv->active_conv;
- PurpleCmdStatus status;
- const char *cmdline = text + 1;
- char *error = NULL, *escape;
- escape = g_markup_escape_text(cmdline, -1);
- status = purple_cmd_do_command(conv, cmdline, escape, &error);
- case PURPLE_CMD_STATUS_OK:
- case PURPLE_CMD_STATUS_NOT_FOUND:
- purple_conversation_write_system_message(conv,
- _("No such command."), PURPLE_MESSAGE_NO_LOG);
- case PURPLE_CMD_STATUS_WRONG_ARGS:
- purple_conversation_write_system_message(conv,
- _("Syntax Error: You typed the wrong "
- "number of arguments to that command."),
- PURPLE_MESSAGE_NO_LOG);
- case PURPLE_CMD_STATUS_FAILED:
- purple_conversation_write_system_message(conv,
- error ? error : _("Your command failed for an unknown reason."),
- PURPLE_MESSAGE_NO_LOG);
- case PURPLE_CMD_STATUS_WRONG_TYPE:
- if(PURPLE_IS_IM_CONVERSATION(conv))
- purple_conversation_write_system_message(conv,
- _("That command only works in chats, not IMs."),
- PURPLE_MESSAGE_NO_LOG);
- purple_conversation_write_system_message(conv,
- _("That command only works in IMs, not chats."),
- PURPLE_MESSAGE_NO_LOG);
- case PURPLE_CMD_STATUS_WRONG_PROTOCOL:
- purple_conversation_write_system_message(conv,
- _("That command doesn't work on this protocol."),
- PURPLE_MESSAGE_NO_LOG);
- else if (!purple_account_is_connected(purple_conversation_get_account(ggconv->active_conv)))
- purple_conversation_write_system_message(ggconv->active_conv,
- _("Message was not sent, because you are not signed on."),
- PURPLE_MESSAGE_ERROR | PURPLE_MESSAGE_NO_LOG);
- char *escape = g_markup_escape_text((*text == '/' ? text + 1 : text), -1);
- purple_conversation_send(ggconv->active_conv, escape);
- gnt_entry_add_to_history(GNT_ENTRY(ggconv->entry), text);
- gnt_entry_clear(GNT_ENTRY(ggconv->entry));
-closing_window(G_GNUC_UNUSED GntWidget *window, FinchConv *ggconv)
- GList *list = ggconv->list;
- PurpleConversation *conv = list->data;
-size_changed_cb(GntWidget *widget, G_GNUC_UNUSED int width,
- G_GNUC_UNUSED int height)
- gnt_widget_get_size(widget, &w, &h);
- purple_prefs_set_int(PREF_ROOT "/size/width", w);
- purple_prefs_set_int(PREF_ROOT "/size/height", h);
-save_position_cb(G_GNUC_UNUSED GntWidget *w, int x, int y)
- purple_prefs_set_int(PREF_ROOT "/position/x", x);
- purple_prefs_set_int(PREF_ROOT "/position/y", y);
-static PurpleConversation *
-find_im_with_contact(PurpleAccount *account, const char *name)
- PurpleBuddy *buddy = purple_blist_find_buddy(account, name);
- PurpleMetaContact *contact;
- PurpleConversation *im = NULL;
- if(!PURPLE_IS_BUDDY(buddy)) {
- contact = purple_buddy_get_contact(buddy);
- node = purple_blist_node_get_first_child(PURPLE_BLIST_NODE(contact));
- PurpleConversationManager *manager;
- if(node == PURPLE_BLIST_NODE(buddy)) {
- cbuddy = PURPLE_BUDDY(node);
- manager = purple_conversation_manager_get_default();
- im = purple_conversation_manager_find_im(manager,
- purple_buddy_get_account(cbuddy),
- purple_buddy_get_name(cbuddy));
- if(PURPLE_IS_IM_CONVERSATION(im)) {
-get_conversation_title(PurpleConversation *conv, PurpleAccount *account) {
- PurpleContactInfo *info = PURPLE_CONTACT_INFO(account);
- return g_strdup_printf(_("%s (%s -- %s)"),
- purple_conversation_get_title(conv),
- purple_contact_info_get_username(info),
- purple_account_get_protocol_name(account));
-update_buddy_typing(PurpleAccount *account, const char *who,
- G_GNUC_UNUSED gpointer data)
- PurpleConversation *conv;
- PurpleConversationManager *manager;
- PurpleIMConversation *im;
- manager = purple_conversation_manager_get_default();
- conv = purple_conversation_manager_find_im(manager, account, who);
- im = PURPLE_IM_CONVERSATION(conv);
- ggc = FINCH_CONV(conv);
- if (purple_im_conversation_get_typing_state(im) == PURPLE_IM_TYPING) {
- str = get_conversation_title(conv, account);
- title = g_strdup_printf(_("%s [%s]"), str,
- gnt_ascii_only() ? "T" : "\342\243\277");
- scroll = gnt_text_view_get_lines_below(GNT_TEXT_VIEW(ggc->tv));
- str = g_strdup_printf(_("\n%s is typing..."), purple_conversation_get_title(conv));
- /* Updating is a little buggy. So just remove and add a new one */
- gnt_text_view_tag_change(GNT_TEXT_VIEW(ggc->tv), "typing", NULL, TRUE);
- gnt_text_view_append_text_with_tag(GNT_TEXT_VIEW(ggc->tv),
- str, GNT_TEXT_FLAG_DIM, "typing");
- gnt_text_view_scroll(GNT_TEXT_VIEW(ggc->tv), 0);
- title = get_conversation_title(conv, account);
- gnt_text_view_tag_change(GNT_TEXT_VIEW(ggc->tv), "typing", " ", TRUE);
- gnt_screen_rename_widget(ggc->window, title);
-chat_left_cb(PurpleConversation *conv, G_GNUC_UNUSED gpointer data)
- purple_conversation_write_system_message(conv,
- _("You have left this chat."), 0);
-buddy_signed_on_off(PurpleBuddy *buddy, G_GNUC_UNUSED gpointer data)
- PurpleConversation *im = find_im_with_contact(purple_buddy_get_account(buddy), purple_buddy_get_name(buddy));
- generate_send_to_menu(FINCH_CONV(im));
-account_signed_on_off(PurpleConnection *gc, G_GNUC_UNUSED gpointer data)
- PurpleConversationManager *manager;
- manager = purple_conversation_manager_get_default();
- list = purple_conversation_manager_get_all(manager);
- for(l = list; l != NULL; l = l->next) {
- PurpleConversation *conv = NULL;
- PurpleConversation *cc = NULL;
- if(!PURPLE_IS_IM_CONVERSATION(l->data)) {
- conv = PURPLE_CONVERSATION(l->data);
- cc = find_im_with_contact(purple_conversation_get_account(conv),
- purple_conversation_get_name(conv));
- generate_send_to_menu(FINCH_CONV(cc));
- /* If we disconnected we're done for now. */
- if(!PURPLE_CONNECTION_IS_CONNECTED(gc)) {
- /* Since we just signed on. Let's see if there's any chat that we have open,
- * and hadn't left before the disconnect.
- for(l = list; l != NULL; l = l->next) {
- PurpleConversation *conv = NULL;
- GHashTable *comps = NULL;
- conv = PURPLE_CONVERSATION(l->data);
- if(!PURPLE_IS_CHAT_CONVERSATION(conv)) {
- if (purple_conversation_get_account(conv) != purple_connection_get_account(gc) ||
- !g_object_get_data(G_OBJECT(conv), "want-to-rejoin"))
- chat = find_chat_for_conversation(conv);
- PurpleProtocol *protocol = purple_connection_get_protocol(gc);
- comps = purple_protocol_chat_info_defaults(PURPLE_PROTOCOL_CHAT(protocol), gc,
- purple_conversation_get_name(conv));
- comps = purple_chat_get_components(chat);
- purple_serv_join_chat(gc, comps);
- if(chat == NULL && comps != NULL) {
- g_hash_table_destroy(comps);
-account_signing_off(PurpleConnection *gc)
- PurpleConversationManager *manager;
- PurpleAccount *account = purple_connection_get_account(gc);
- manager = purple_conversation_manager_get_default();
- list = purple_conversation_manager_get_all(manager);
- /* We are about to sign off. See which chats we are currently in, and mark
- * them for rejoin on reconnect. */
- if(PURPLE_IS_CHAT_CONVERSATION(list->data)) {
- PurpleConversation *conv;
- PurpleChatConversation *chat;
- conv = PURPLE_CONVERSATION(list->data);
- chat = PURPLE_CHAT_CONVERSATION(conv);
- left = purple_chat_conversation_has_left(chat);
- if(!left && purple_conversation_get_account(conv) == account) {
- g_object_set_data(G_OBJECT(conv), "want-to-rejoin",
- GINT_TO_POINTER(TRUE));
- purple_conversation_write_system_message(
- _("The account has disconnected and you are no longer in "
- "this chat. You will be automatically rejoined in the "
- "chat when the account reconnects."),
- PURPLE_MESSAGE_NO_LOG);
- list = g_list_delete_link(list, list);
-finch_conv_get_handle(void)
-cleared_message_history_cb(PurpleConversation *conv,
- G_GNUC_UNUSED gpointer data)
- FinchConv *ggc = FINCH_CONV(conv);
- gnt_text_view_clear(GNT_TEXT_VIEW(ggc->tv));
-gg_extended_menu(FinchConv *ggc)
- gboolean is_empty = TRUE;
- g_return_if_fail(ggc != NULL);
- sub = GNT_MENU(gnt_menu_new(GNT_MENU_POPUP));
- gnt_menuitem_set_submenu(ggc->plugins, sub);
- for (list = purple_conversation_get_extended_menu(ggc->active_conv);
- list; list = g_list_delete_link(list, list))
- finch_append_menu_action(sub, list->data, ggc->active_conv);
- gnt_menuitem_set_visible(ggc->plugins, !is_empty);
-conv_updated(PurpleConversation *conv, PurpleConversationUpdateType type)
- FinchConv *finch_conv = FINCH_CONV(conv);
- if(finch_conv == NULL) {
- if(type == PURPLE_CONVERSATION_UPDATE_FEATURES) {
- gg_extended_menu(finch_conv);
-send_file_cb(G_GNUC_UNUSED GntMenuItem *item, gpointer ggconv)
- FinchConv *ggc = ggconv;
- purple_serv_send_file(purple_conversation_get_connection(ggc->active_conv),
- purple_conversation_get_name(ggc->active_conv), NULL);
-get_info_cb(G_GNUC_UNUSED GntMenuItem *item, gpointer ggconv)
- FinchConv *ggc = ggconv;
- finch_retrieve_user_info(purple_conversation_get_connection(ggc->active_conv),
- purple_conversation_get_name(ggc->active_conv));
-toggle_timestamps_cb(G_GNUC_UNUSED GntMenuItem *item,
- G_GNUC_UNUSED gpointer data)
- purple_prefs_set_bool(PREF_ROOT "/timestamps",
- !purple_prefs_get_bool(PREF_ROOT "/timestamps"));
-send_to_cb(GntMenuItem *m, G_GNUC_UNUSED gpointer n)
- PurpleAccount *account = g_object_get_data(G_OBJECT(m), "purple_account");
- gchar *buddy = g_object_get_data(G_OBJECT(m), "purple_buddy_name");
- PurpleConversation *im = purple_im_conversation_new(account, buddy);
- finch_conversation_set_active(im);
-generate_send_to_menu(FinchConv *ggc)
- GntWidget *sub, *menu = ggc->menu;
- buds = purple_blist_find_buddies(purple_conversation_get_account(ggc->active_conv),
- purple_conversation_get_name(ggc->active_conv));
- if ((item = ggc->u.im->sendto) == NULL) {
- item = gnt_menuitem_new(_("Send To"));
- gnt_menu_add_item(GNT_MENU(menu), item);
- ggc->u.im->sendto = item;
- sub = gnt_menu_new(GNT_MENU_POPUP);
- gnt_menuitem_set_submenu(item, GNT_MENU(sub));
- for (; buds; buds = g_slist_delete_link(buds, buds)) {
- PurpleBlistNode *node = PURPLE_BLIST_NODE(purple_buddy_get_contact(PURPLE_BUDDY(buds->data)));
- for (node = purple_blist_node_get_first_child(node); node != NULL;
- node = purple_blist_node_get_sibling_next(node)) {
- PurpleBuddy *buddy = (PurpleBuddy *)node;
- PurpleAccount *account = purple_buddy_get_account(buddy);
- if (purple_account_is_connected(account)) {
- /* Use the PurplePresence to get unique buddies. */
- PurplePresence *presence = purple_buddy_get_presence(buddy);
- if (!g_list_find(list, presence))
- list = g_list_prepend(list, presence);
- for (list = g_list_reverse(list); list != NULL; list = g_list_delete_link(list, list)) {
- PurplePresence *pre = list->data;
- PurpleBuddy *buddy = purple_buddy_presence_get_buddy(PURPLE_BUDDY_PRESENCE(pre));
- PurpleAccount *account = purple_buddy_get_account(buddy);
- PurpleContactInfo *info = PURPLE_CONTACT_INFO(account);
- gchar *name = g_strdup(purple_buddy_get_name(buddy));
- gchar *text = g_strdup_printf("%s (%s)", purple_buddy_get_name(buddy), purple_contact_info_get_username(info));
- item = gnt_menuitem_new(text);
- gnt_menu_add_item(GNT_MENU(sub), item);
- gnt_menuitem_set_callback(item, send_to_cb, NULL);
- g_object_set_data(G_OBJECT(item), "purple_account", account);
- g_object_set_data_full(G_OBJECT(item), "purple_buddy_name", name, g_free);
-invite_cb(G_GNUC_UNUSED GntMenuItem *item, gpointer ggconv)
- FinchConv *fc = ggconv;
- PurpleChatConversation *chat = PURPLE_CHAT_CONVERSATION(fc->active_conv);
- purple_chat_conversation_invite_user(chat, NULL, NULL, TRUE);
-plugin_changed_cb(G_GNUC_UNUSED GObject *plugin_manager,
- G_GNUC_UNUSED GPluginPlugin *p, gpointer data)
- gg_extended_menu(data);
-gg_create_menu(FinchConv *ggc)
- ggc->menu = menu = gnt_menu_new(GNT_MENU_TOPLEVEL);
- gnt_window_set_menu(GNT_WINDOW(ggc->window), GNT_MENU(menu));
- item = gnt_menuitem_new(_("Conversation"));
- gnt_menu_add_item(GNT_MENU(menu), item);
- sub = gnt_menu_new(GNT_MENU_POPUP);
- gnt_menuitem_set_submenu(item, GNT_MENU(sub));
- item = gnt_menuitem_check_new(_("Show Timestamps"));
- gnt_menuitem_check_set_checked(GNT_MENU_ITEM_CHECK(item),
- purple_prefs_get_bool(PREF_ROOT "/timestamps"));
- gnt_menu_add_item(GNT_MENU(sub), item);
- gnt_menuitem_set_callback(item, toggle_timestamps_cb, ggc);
- if (PURPLE_IS_IM_CONVERSATION(ggc->active_conv)) {
- PurpleAccount *account = purple_conversation_get_account(ggc->active_conv);
- PurpleConnection *gc = purple_account_get_connection(account);
- PurpleProtocol *protocol =
- gc ? purple_connection_get_protocol(gc) : NULL;
- if (protocol && PURPLE_PROTOCOL_IMPLEMENTS(protocol, SERVER, get_info)) {
- item = gnt_menuitem_new(_("Get Info"));
- gnt_menu_add_item(GNT_MENU(sub), item);
- gnt_menuitem_set_callback(item, get_info_cb, ggc);
- if (PURPLE_IS_PROTOCOL_XFER(protocol) &&
- purple_protocol_xfer_can_receive(
- PURPLE_PROTOCOL_XFER(protocol),
- purple_conversation_get_name(ggc->active_conv)
- item = gnt_menuitem_new(_("Send File"));
- gnt_menu_add_item(GNT_MENU(sub), item);
- gnt_menuitem_set_callback(item, send_file_cb, ggc);
- generate_send_to_menu(ggc);
- } else if (PURPLE_IS_CHAT_CONVERSATION(ggc->active_conv)) {
- item = gnt_menuitem_new(_("Invite..."));
- gnt_menu_add_item(GNT_MENU(sub), item);
- gnt_menuitem_set_callback(item, invite_cb, ggc);
- item = gnt_menuitem_new(_("Plugins"));
- gnt_menu_add_item(GNT_MENU(menu), item);
-create_conv_from_userlist(GntWidget *widget, FinchConv *fc)
- PurpleAccount *account = purple_conversation_get_account(fc->active_conv);
- PurpleConnection *gc = purple_account_get_connection(account);
- PurpleProtocol *protocol = NULL;
- char *name, *realname = NULL;
- purple_conversation_write_system_message(fc->active_conv,
- _("You are not connected."), 0);
- name = gnt_tree_get_selection_data(GNT_TREE(widget));
- protocol = purple_connection_get_protocol(gc);
- realname = purple_protocol_chat_get_user_real_name(PURPLE_PROTOCOL_CHAT(protocol), gc,
- purple_chat_conversation_get_id(
- PURPLE_CHAT_CONVERSATION(fc->active_conv)), name);
- purple_im_conversation_new(account, realname ? realname : name);
-gained_focus_cb(G_GNUC_UNUSED GntWindow *window, FinchConv *fc)
- for (iter = fc->list; iter; iter = iter->next) {
- g_object_set_data(G_OBJECT(iter->data), "unseen-count", 0);
- purple_conversation_update(iter->data, PURPLE_CONVERSATION_UPDATE_UNSEEN);
-completion_cb(GntEntry *entry, const char *start, G_GNUC_UNUSED const char *end)
- if (start == gnt_entry_get_text(entry) && *start != '/')
- gnt_widget_key_pressed(GNT_WIDGET(entry), ": ");
-gg_setup_commands(FinchConv *fconv, gboolean remove_first)
- char command[256] = "/";
- commands = purple_cmd_list(NULL);
- for (; commands; commands = g_list_delete_link(commands, commands)) {
- g_strlcpy(command + 1, commands->data, sizeof(command) - 1);
- gnt_entry_remove_suggest(GNT_ENTRY(fconv->entry), command);
- commands = purple_cmd_list(fconv->active_conv);
- for (; commands; commands = g_list_delete_link(commands, commands)) {
- g_strlcpy(command + 1, commands->data, sizeof(command) - 1);
- gnt_entry_add_suggest(GNT_ENTRY(fconv->entry), command);
-cmd_added_cb(G_GNUC_UNUSED const char *cmd,
- G_GNUC_UNUSED PurpleCmdPriority prior,
- G_GNUC_UNUSED PurpleCmdFlag flags,
- gg_setup_commands(fconv, TRUE);
-cmd_removed_cb(const char *cmd, FinchConv *fconv)
- char command[256] = "/";
- g_strlcpy(command + 1, cmd, sizeof(command) - 1);
- gnt_entry_remove_suggest(GNT_ENTRY(fconv->entry), command);
- gg_setup_commands(fconv, TRUE);
-finch_create_conversation(PurpleConversation *conv)
- FinchConv *ggc = FINCH_CONV(conv);
- GPluginManager *plugin_manager = NULL;
- PurpleConversation *cc;
- PurpleAccount *account;
- gnt_window_present(ggc->window);
- account = purple_conversation_get_account(conv);
- cc = find_im_with_contact(account, purple_conversation_get_name(conv));
- if (cc && FINCH_CONV(cc))
- ggc = g_new0(FinchConv, 1);
- ggc->list = g_list_prepend(ggc->list, conv);
- ggc->active_conv = conv;
- g_object_set_data(G_OBJECT(conv), "finch", ggc);
- if (cc && FINCH_CONV(cc) && cc != conv) {
- finch_conversation_set_active(conv);
- title = get_conversation_title(conv, account);
- ggc->window = gnt_vwindow_new(FALSE);
- gnt_box_set_title(GNT_BOX(ggc->window), title);
- gnt_box_set_toplevel(GNT_BOX(ggc->window), TRUE);
- gnt_box_set_pad(GNT_BOX(ggc->window), 0);
- if (PURPLE_IS_IM_CONVERSATION(conv))
- gnt_widget_set_name(ggc->window, "conversation-window-im");
- else if (PURPLE_IS_CHAT_CONVERSATION(conv))
- gnt_widget_set_name(ggc->window, "conversation-window-chat");
- gnt_widget_set_name(ggc->window, "conversation-window-other");
- ggc->tv = gnt_text_view_new();
- gnt_widget_set_name(ggc->tv, "conversation-window-textview");
- gnt_widget_set_size(ggc->tv, purple_prefs_get_int(PREF_ROOT "/size/width"),
- purple_prefs_get_int(PREF_ROOT "/size/height"));
- if (PURPLE_IS_CHAT_CONVERSATION(conv)) {
- GntWidget *hbox, *tree;
- FinchConvChat *fc = ggc->u.chat = g_new0(FinchConvChat, 1);
- hbox = gnt_hbox_new(FALSE);
- gnt_box_set_pad(GNT_BOX(hbox), 0);
- tree = fc->userlist = gnt_tree_new_with_columns(2);
- gnt_tree_set_col_width(GNT_TREE(tree), 0, 1); /* The flag column */
- gnt_tree_set_compare_func(GNT_TREE(tree), (GCompareFunc)g_utf8_collate);
- gnt_tree_set_hash_fns(GNT_TREE(tree), g_str_hash, g_str_equal, g_free);
- gnt_tree_set_search_column(GNT_TREE(tree), 1);
- gnt_widget_set_has_border(tree, FALSE);
- gnt_box_add_widget(GNT_BOX(hbox), ggc->tv);
- gnt_box_add_widget(GNT_BOX(hbox), tree);
- gnt_box_add_widget(GNT_BOX(ggc->window), hbox);
- g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(create_conv_from_userlist), ggc);
- gnt_widget_set_visible(tree, purple_prefs_get_bool(PREF_USERLIST));
- ggc->u.im = g_new0(FinchConvIm, 1);
- gnt_box_add_widget(GNT_BOX(ggc->window), ggc->tv);
- ggc->info = gnt_vbox_new(FALSE);
- gnt_box_add_widget(GNT_BOX(ggc->window), ggc->info);
- ggc->entry = gnt_entry_new(NULL);
- gnt_box_add_widget(GNT_BOX(ggc->window), ggc->entry);
- gnt_widget_set_name(ggc->entry, "conversation-window-entry");
- gnt_entry_set_history_length(GNT_ENTRY(ggc->entry), -1);
- gnt_entry_set_word_suggest(GNT_ENTRY(ggc->entry), TRUE);
- gnt_entry_set_always_suggest(GNT_ENTRY(ggc->entry), FALSE);
- gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(ggc->tv), ggc->entry);
- gnt_text_view_attach_pager_widget(GNT_TEXT_VIEW(ggc->tv), ggc->entry);
- g_signal_connect_after(G_OBJECT(ggc->entry), "activate", G_CALLBACK(entry_key_pressed), ggc);
- g_signal_connect(G_OBJECT(ggc->entry), "completion", G_CALLBACK(completion_cb), NULL);
- g_signal_connect(G_OBJECT(ggc->window), "destroy", G_CALLBACK(closing_window), ggc);
- gnt_widget_set_position(ggc->window, purple_prefs_get_int(PREF_ROOT "/position/x"),
- purple_prefs_get_int(PREF_ROOT "/position/y"));
- gnt_widget_show(ggc->window);
- g_signal_connect(G_OBJECT(ggc->tv), "size_changed", G_CALLBACK(size_changed_cb), NULL);
- g_signal_connect(G_OBJECT(ggc->window), "position_set", G_CALLBACK(save_position_cb), NULL);
- if (PURPLE_IS_IM_CONVERSATION(conv))
- g_signal_connect(G_OBJECT(ggc->entry), "text_changed", G_CALLBACK(send_typing_notification), ggc);
- gg_setup_commands(ggc, FALSE);
- purple_signal_connect(purple_cmds_get_handle(), "cmd-added", ggc,
- G_CALLBACK(cmd_added_cb), ggc);
- purple_signal_connect(purple_cmds_get_handle(), "cmd-removed", ggc,
- G_CALLBACK(cmd_removed_cb), ggc);
- plugin_manager = gplugin_manager_get_default();
- g_signal_connect_object(plugin_manager, "loaded-plugin",
- G_CALLBACK(plugin_changed_cb), ggc, 0);
- g_signal_connect_object(plugin_manager, "unloaded-plugin",
- G_CALLBACK(plugin_changed_cb), ggc, 0);
- gnt_box_give_focus_to_child(GNT_BOX(ggc->window), ggc->entry);
- g_signal_connect(G_OBJECT(ggc->window), "gained-focus", G_CALLBACK(gained_focus_cb), ggc);
-finch_destroy_conversation(PurpleConversation *conv)
- FinchConv *ggc = FINCH_CONV(conv);
- ggc->list = g_list_remove(ggc->list, conv);
- if (ggc->list && conv == ggc->active_conv)
- finch_conversation_set_active(ggc->list->data);
- if (ggc->list == NULL) {
- purple_signals_disconnect_by_handle(ggc);
- gnt_widget_destroy(ggc->window);
-finch_write_conv(PurpleConversation *conv, PurpleMessage *msg)
- FinchConv *ggconv = FINCH_CONV(conv);
- GntTextFormatFlags fl = 0;
- PurpleMessageFlags flags = purple_message_get_flags(msg);
- g_return_if_fail(ggconv != NULL);
- if ((flags & PURPLE_MESSAGE_SYSTEM) && !(flags & PURPLE_MESSAGE_NOTIFY)) {
- flags &= ~(PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV);
- if (ggconv->active_conv != conv) {
- if (flags & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV))
- finch_conversation_set_active(conv);
- pos = gnt_text_view_get_lines_below(GNT_TEXT_VIEW(ggconv->tv));
- gnt_text_view_tag_change(GNT_TEXT_VIEW(ggconv->tv), "typing", NULL, TRUE);
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), "\n", GNT_TEXT_FLAG_NORMAL);
- /* Unnecessary to print the timestamp for delayed message */
- if (purple_prefs_get_bool("/finch/conversations/timestamps")) {
- gchar *timestamp = NULL;
- timestamp = purple_message_format_timestamp(msg, "(%H:%M:%S)");
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv),
- gnt_color_pair(color_timestamp));
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), " ", GNT_TEXT_FLAG_NORMAL);
- if (flags & PURPLE_MESSAGE_AUTO_RESP)
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv),
- _("<AUTO-REPLY> "), GNT_TEXT_FLAG_BOLD);
- if (purple_message_get_author(msg) && (flags & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_RECV)) &&
- !(flags & PURPLE_MESSAGE_NOTIFY))
- GntTextFormatFlags msgflags = GNT_TEXT_FLAG_NORMAL;
- gchar *msg_text = g_strdup(purple_message_get_contents(msg));
- if(purple_message_get_action(msg)) {
- name = g_strdup_printf("*** %s", purple_message_get_author_alias(msg));
- if (!(flags & PURPLE_MESSAGE_SEND) &&
- (flags & PURPLE_MESSAGE_NICK))
- msgflags = gnt_color_pair(color_message_highlight);
- msgflags = gnt_color_pair(color_message_action);
- name = g_strdup(purple_message_get_author_alias(msg));
- if (flags & PURPLE_MESSAGE_SEND)
- msgflags = gnt_color_pair(color_message_send);
- else if (flags & PURPLE_MESSAGE_NICK)
- msgflags = gnt_color_pair(color_message_highlight);
- msgflags = gnt_color_pair(color_message_receive);
- purple_message_set_contents(msg, msg_text); /* might be "meified" */
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv),
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv), me ? " " : ": ", GNT_TEXT_FLAG_NORMAL);
- fl = GNT_TEXT_FLAG_DIM;
- if (flags & PURPLE_MESSAGE_ERROR)
- fl |= GNT_TEXT_FLAG_BOLD;
- /* XXX: Remove this workaround when textview can parse messages. */
- newline = purple_strdup_withhtml(purple_message_get_contents(msg));
- strip = purple_markup_strip_html(newline);
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(ggconv->tv),
- if (PURPLE_IS_IM_CONVERSATION(conv) && purple_im_conversation_get_typing_state(
- PURPLE_IM_CONVERSATION(conv)) == PURPLE_IM_TYPING) {
- strip = g_strdup_printf(_("\n%s is typing..."), purple_conversation_get_title(conv));
- gnt_text_view_append_text_with_tag(GNT_TEXT_VIEW(ggconv->tv),
- strip, GNT_TEXT_FLAG_DIM, "typing");
- gnt_text_view_scroll(GNT_TEXT_VIEW(ggconv->tv), 0);
- if (flags & (PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_NICK | PURPLE_MESSAGE_ERROR))
- gnt_widget_set_urgent(ggconv->tv);
- if (flags & PURPLE_MESSAGE_RECV && !gnt_widget_has_focus(ggconv->window)) {
- int count = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(conv), "unseen-count"));
- g_object_set_data(G_OBJECT(conv), "unseen-count", GINT_TO_POINTER(count + 1));
- purple_conversation_update(conv, PURPLE_CONVERSATION_UPDATE_UNSEEN);
-chat_flag_text(PurpleChatUserFlags flags)
- if (flags & PURPLE_CHAT_USER_FOUNDER)
- if (flags & PURPLE_CHAT_USER_OP)
- if (flags & PURPLE_CHAT_USER_HALFOP)
- if (flags & PURPLE_CHAT_USER_VOICE)
-finch_chat_add_users(PurpleChatConversation *chat, GList *users, gboolean new_arrivals)
- PurpleConversation *conv = PURPLE_CONVERSATION(chat);
- FinchConv *ggc = FINCH_CONV(conv);
- GntEntry *entry = GNT_ENTRY(ggc->entry);
- /* Print the list of users in the room */
- GString *string = g_string_new(NULL);
- gint count = g_list_length(users);
- g_string_printf(string,
- ngettext("List of %d user:\n", "List of %d users:\n", count), count);
- for (iter = users; iter; iter = iter->next)
- PurpleChatUser *chatuser = iter->data;
- if ((str = purple_chat_user_get_alias(chatuser)) == NULL)
- str = purple_chat_user_get_name(chatuser);
- g_string_append_printf(string, "[ %s ]", str);
- purple_conversation_write_system_message(
- g_string_free(string, TRUE);
- for (; users; users = users->next)
- PurpleChatUser *chatuser = users->data;
- GntTree *tree = GNT_TREE(ggc->u.chat->userlist);
- gnt_entry_add_suggest(entry, purple_chat_user_get_name(chatuser));
- gnt_entry_add_suggest(entry, purple_chat_user_get_alias(chatuser));
- gnt_tree_add_row_after(tree, g_strdup(purple_chat_user_get_name(chatuser)),
- gnt_tree_create_row(tree, chat_flag_text(purple_chat_user_get_flags(chatuser)), purple_chat_user_get_alias(chatuser)), NULL, NULL);
-finch_chat_rename_user(PurpleChatConversation *chat, const char *old, const char *new_n, const char *new_a)
- /* Update the name for string completion */
- FinchConv *ggc = FINCH_CONV(PURPLE_CONVERSATION(chat));
- GntEntry *entry = GNT_ENTRY(ggc->entry);
- GntTree *tree = GNT_TREE(ggc->u.chat->userlist);
- PurpleChatUser *cb = purple_chat_conversation_find_user(chat, new_n);
- gnt_entry_remove_suggest(entry, old);
- gnt_tree_remove(tree, (gpointer)old);
- gnt_entry_add_suggest(entry, new_n);
- gnt_entry_add_suggest(entry, new_a);
- gnt_tree_add_row_after(tree, g_strdup(new_n),
- gnt_tree_create_row(tree, chat_flag_text(purple_chat_user_get_flags(cb)), new_a), NULL, NULL);
-finch_chat_remove_users(PurpleChatConversation *chat, GList *list)
- /* Remove the name from string completion */
- FinchConv *ggc = FINCH_CONV(PURPLE_CONVERSATION(chat));
- GntEntry *entry = GNT_ENTRY(ggc->entry);
- for (; list; list = list->next) {
- GntTree *tree = GNT_TREE(ggc->u.chat->userlist);
- gnt_entry_remove_suggest(entry, list->data);
- gnt_tree_remove(tree, list->data);
-finch_chat_update_user(PurpleChatUser *cb)
- PurpleChatConversation *chat;
- chat = purple_chat_user_get_chat(cb);
- ggc = FINCH_CONV(PURPLE_CONVERSATION(chat));
- gnt_tree_change_text(GNT_TREE(ggc->u.chat->userlist),
- (gpointer)purple_chat_user_get_name(cb), 0,
- chat_flag_text(purple_chat_user_get_flags(cb)));
-finch_conv_present(PurpleConversation *conv)
- FinchConv *fc = FINCH_CONV(conv);
- gnt_window_present(fc->window);
-finch_conv_has_focus(PurpleConversation *conv)
- FinchConv *fc = FINCH_CONV(conv);
- return gnt_widget_has_focus(fc->window);
-static PurpleConversationUiOps conv_ui_ops = {
- .create_conversation = finch_create_conversation,
- .destroy_conversation = finch_destroy_conversation,
- .write_conv = finch_write_conv,
- .chat_add_users = finch_chat_add_users,
- .chat_rename_user = finch_chat_rename_user,
- .chat_remove_users = finch_chat_remove_users,
- .chat_update_user = finch_chat_update_user,
- .present = finch_conv_present,
- .has_focus = finch_conv_has_focus,
-PurpleConversationUiOps *
-finch_conv_get_ui_ops(void)
-say_command_cb(PurpleConversation *conv, G_GNUC_UNUSED const char *cmd,
- char **args, G_GNUC_UNUSED char **error,
- G_GNUC_UNUSED gpointer data)
- purple_conversation_send(conv, args[0]);
- return PURPLE_CMD_RET_OK;
-me_command_cb(PurpleConversation *conv, G_GNUC_UNUSED const char *cmd,
- char **args, G_GNUC_UNUSED char **error,
- G_GNUC_UNUSED gpointer data)
- tmp = g_strdup_printf("/me %s", args[0]);
- purple_conversation_send(conv, tmp);
- return PURPLE_CMD_RET_OK;
-debug_command_cb(PurpleConversation *conv, G_GNUC_UNUSED const char *cmd,
- char **args, G_GNUC_UNUSED char **error,
- G_GNUC_UNUSED gpointer data)
- if (!g_ascii_strcasecmp(args[0], "version")) {
- tmp = g_strdup_printf("Using Finch v%s with libpurple v%s.",
- DISPLAY_VERSION, purple_core_get_version());
- } else if (!g_ascii_strcasecmp(args[0], "plugins")) {
- /* Show all the loaded plugins, including plugins marked internal.
- * This is intentional, since third party protocols are often sources of bugs, and some
- * loaders can also be buggy.
- GString *str = g_string_new("Loaded Plugins: ");
- const GList *plugins = purple_plugins_get_loaded();
- for (; plugins; plugins = plugins->next) {
- GPluginPluginInfo *plugin_info =
- purple_plugin_get_info(
- str, gplugin_plugin_info_get_name(
- str = g_string_append(str, ", ");
- str = g_string_append(str, "(none)");
- tmp = g_string_free(str, FALSE);
- purple_conversation_write_system_message(conv,
- _("Supported debug options are: plugins version"),
- PURPLE_MESSAGE_NO_LOG | PURPLE_MESSAGE_ERROR);
- return PURPLE_CMD_RET_OK;
- markup = g_markup_escape_text(tmp, -1);
- purple_conversation_send(conv, markup);
- return PURPLE_CMD_RET_OK;
-help_command_cb(PurpleConversation *conv, G_GNUC_UNUSED const char *cmd,
- char **args, G_GNUC_UNUSED char **error,
- G_GNUC_UNUSED gpointer data)
- text = purple_cmd_help(conv, args[0]);
- for (l = text; l; l = l->next)
- g_string_append_printf(s, "%s\n", (char *)l->data);
- g_string_append_printf(s, "%s", (char *)l->data);
- g_string_append(s, _("No such command (in this context)."));
- s = g_string_new(_("Use \"/help <command>\" for help with a "
- "specific command.\nThe following commands are available in "
- text = purple_cmd_list(conv);
- for (l = text; l; l = l->next)
- g_string_append_printf(s, "%s, ", (char *)l->data);
- g_string_append_printf(s, "%s.", (char *)l->data);
- purple_conversation_write_system_message(conv, s->str, PURPLE_MESSAGE_NO_LOG);
- g_string_free(s, TRUE);
- return PURPLE_CMD_RET_OK;
-cmd_show_window(G_GNUC_UNUSED PurpleConversation *conv,
- G_GNUC_UNUSED const char *cmd, G_GNUC_UNUSED char **args,
- G_GNUC_UNUSED char **error, gpointer data)
- void (*callback)(void) = data;
- return PURPLE_CMD_RET_OK;
-cmd_message_color(G_GNUC_UNUSED PurpleConversation *conv,
- G_GNUC_UNUSED const char *cmd, char **args, char **error,
- G_GNUC_UNUSED gpointer data)
- if (purple_strequal(args[0], "receive"))
- msgclass = &color_message_receive;
- else if (purple_strequal(args[0], "send"))
- msgclass = &color_message_send;
- else if (purple_strequal(args[0], "highlight"))
- msgclass = &color_message_highlight;
- else if (purple_strequal(args[0], "action"))
- msgclass = &color_message_action;
- else if (purple_strequal(args[0], "timestamp"))
- msgclass = &color_timestamp;
- *error = g_strdup_printf(_("%s is not a valid message class. See '/help msgcolor' for valid message classes."), args[0]);
- return PURPLE_CMD_RET_FAILED;
- fg = gnt_colors_get_color(args[1]);
- *error = g_strdup_printf(_("%s is not a valid color. See '/help msgcolor' for valid colors."), args[1]);
- return PURPLE_CMD_RET_FAILED;
- bg = gnt_colors_get_color(args[2]);
- *error = g_strdup_printf(_("%s is not a valid color. See '/help msgcolor' for valid colors."), args[2]);
- return PURPLE_CMD_RET_FAILED;
- init_pair(*msgclass, fg, bg);
- return PURPLE_CMD_RET_OK;
-users_command_cb(PurpleConversation *conv, G_GNUC_UNUSED const char *cmd,
- G_GNUC_UNUSED char **args, G_GNUC_UNUSED char **error,
- G_GNUC_UNUSED gpointer data)
- FinchConv *fc = FINCH_CONV(conv);
- return PURPLE_CMD_RET_FAILED;
- gnt_widget_set_visible(ch->userlist,
- !gnt_widget_get_visible(ch->userlist));
- gnt_box_readjust(GNT_BOX(fc->window));
- gnt_box_give_focus_to_child(GNT_BOX(fc->window), fc->entry);
- purple_prefs_set_bool(PREF_USERLIST, gnt_widget_get_visible(ch->userlist));
- return PURPLE_CMD_RET_OK;
-finch_conversation_init(void)
- color_message_send = gnt_style_get_color(NULL, "color-message-sent");
- if (!color_message_send)
- color_message_send = gnt_color_add_pair(COLOR_CYAN, -1);
- color_message_receive = gnt_style_get_color(NULL, "color-message-received");
- if (!color_message_receive)
- color_message_receive = gnt_color_add_pair(COLOR_RED, -1);
- color_message_highlight = gnt_style_get_color(NULL, "color-message-highlight");
- if (!color_message_highlight)
- color_message_highlight = gnt_color_add_pair(COLOR_GREEN, -1);
- color_timestamp = gnt_style_get_color(NULL, "color-timestamp");
- color_timestamp = gnt_color_add_pair(COLOR_BLUE, -1);
- color_message_action = gnt_style_get_color(NULL, "color-message-action");
- if (!color_message_action)
- color_message_action = gnt_color_add_pair(COLOR_YELLOW, -1);
- purple_prefs_add_none(PREF_ROOT);
- purple_prefs_add_none(PREF_ROOT "/size");
- purple_prefs_add_int(PREF_ROOT "/size/width", 70);
- purple_prefs_add_int(PREF_ROOT "/size/height", 20);
- purple_prefs_add_none(PREF_ROOT "/position");
- purple_prefs_add_int(PREF_ROOT "/position/x", 0);
- purple_prefs_add_int(PREF_ROOT "/position/y", 0);
- purple_prefs_add_none(PREF_CHAT);
- purple_prefs_add_bool(PREF_USERLIST, FALSE);
- /* Xerox the commands */
- purple_cmd_register("say", "S", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL,
- say_command_cb, _("say <message>: Send a message normally as if you weren't using a command."), NULL);
- purple_cmd_register("me", "S", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL,
- me_command_cb, _("me <action>: Send an IRC style action to a buddy or chat."), NULL);
- purple_cmd_register("debug", "w", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL,
- debug_command_cb, _("debug <option>: Send various debug information to the current conversation."), NULL);
- purple_cmd_register("help", "w", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, NULL,
- help_command_cb, _("help <command>: Help on a specific command."), NULL);
- purple_cmd_register("users", "", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_ALLOW_WRONG_ARGS, NULL,
- users_command_cb, _("users: Show the list of users in the chat."), NULL);
- /* Now some commands to bring up some other windows */
- purple_cmd_register("plugins", "", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL,
- cmd_show_window, _("plugins: Show the plugins window."), finch_plugins_show_all);
- purple_cmd_register("buddylist", "", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL,
- cmd_show_window, _("buddylist: Show the buddylist."), finch_blist_show);
- purple_cmd_register("accounts", "", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL,
- cmd_show_window, _("accounts: Show the accounts window."), finch_accounts_show_all);
- purple_cmd_register("debugwin", "", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL,
- cmd_show_window, _("debugwin: Show the debug window."), finch_debug_window_show);
- purple_cmd_register("prefs", "", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL,
- cmd_show_window, _("prefs: Show the preference window."), finch_prefs_show_all);
- purple_cmd_register("status", "", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL,
- cmd_show_window, _("statuses: Show the savedstatuses window."), finch_savedstatus_show_all);
- /* Allow customizing the message colors using a command during run-time */
- purple_cmd_register("msgcolor", "www", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL,
- cmd_message_color, _("msgcolor <class> <foreground> <background>: "
- "Set the color for different classes of messages in the conversation window.<br>"
- " <class>: receive, send, highlight, action, timestamp<br>"
- " <foreground/background>: black, red, green, blue, white, gray, darkgray, magenta, cyan, default<br><br>"
- "EXAMPLE:<br> msgcolor send cyan default"),
- purple_cmd_register("msgcolour", "www", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL,
- cmd_message_color, _("msgcolor <class> <foreground> <background>: "
- "Set the color for different classes of messages in the conversation window.<br>"
- " <class>: receive, send, highlight, action, timestamp<br>"
- " <foreground/background>: black, red, green, blue, white, gray, darkgray, magenta, cyan, default<br><br>"
- "EXAMPLE:<br> msgcolor send cyan default"),
- purple_signal_connect(purple_conversations_get_handle(), "buddy-typing", finch_conv_get_handle(),
- G_CALLBACK(update_buddy_typing), NULL);
- purple_signal_connect(purple_conversations_get_handle(), "buddy-typing-stopped", finch_conv_get_handle(),
- G_CALLBACK(update_buddy_typing), NULL);
- purple_signal_connect(purple_conversations_get_handle(), "chat-left", finch_conv_get_handle(),
- G_CALLBACK(chat_left_cb), NULL);
- purple_signal_connect(purple_conversations_get_handle(), "cleared-message-history", finch_conv_get_handle(),
- G_CALLBACK(cleared_message_history_cb), NULL);
- purple_signal_connect(purple_conversations_get_handle(), "conversation-updated", finch_conv_get_handle(),
- G_CALLBACK(conv_updated), NULL);
- purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", finch_conv_get_handle(),
- G_CALLBACK(buddy_signed_on_off), NULL);
- purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", finch_conv_get_handle(),
- G_CALLBACK(buddy_signed_on_off), NULL);
- purple_signal_connect(purple_connections_get_handle(), "signed-on", finch_conv_get_handle(),
- G_CALLBACK(account_signed_on_off), NULL);
- purple_signal_connect(purple_connections_get_handle(), "signed-off", finch_conv_get_handle(),
- G_CALLBACK(account_signed_on_off), NULL);
- purple_signal_connect(purple_connections_get_handle(), "signing-off", finch_conv_get_handle(),
- G_CALLBACK(account_signing_off), NULL);
-finch_conversation_uninit(void)
- purple_signals_disconnect_by_handle(finch_conv_get_handle());
-void finch_conversation_set_active(PurpleConversation *conv)
- FinchConv *ggconv = FINCH_CONV(conv);
- PurpleAccount *account;
- g_return_if_fail(ggconv);
- g_return_if_fail(g_list_find(ggconv->list, conv));
- if (ggconv->active_conv == conv)
- ggconv->active_conv = conv;
- gg_setup_commands(ggconv, TRUE);
- account = purple_conversation_get_account(conv);
- title = get_conversation_title(conv, account);
- gnt_screen_rename_widget(ggconv->window, title);
-void finch_conversation_set_info_widget(PurpleConversation *conv, GntWidget *widget)
- FinchConv *fc = FINCH_CONV(conv);
- gnt_box_remove_all(GNT_BOX(fc->info));
- gnt_box_add_widget(GNT_BOX(fc->info), widget);
- gnt_box_readjust(GNT_BOX(fc->info));
- gnt_widget_get_size(fc->window, &width, &height);
- gnt_box_readjust(GNT_BOX(fc->window));
- gnt_screen_resize_widget(fc->window, width, height);
- gnt_box_give_focus_to_child(GNT_BOX(fc->window), fc->entry);
--- a/finch/gntconv.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-/* Grabs the conv out of a PurpleConverstation */
-#define FINCH_CONV(conv) ((FinchConv *)g_object_get_data(G_OBJECT(conv), "finch"))
-/***************************************************************************
- * GNT Conversations API
- ***************************************************************************/
-typedef struct _FinchConv FinchConv;
-typedef struct _FinchConvChat FinchConvChat;
-typedef struct _FinchConvIm FinchConvIm;
- * FinchConversationFlag:
- * @FINCH_CONV_NO_SOUND: A flag to mute a conversation.
- * Flags that can be set for each conversation.
- FINCH_CONV_NO_SOUND = 1 << 0,
-} FinchConversationFlag;
- * @list: A list of conversations being displayed in this window.
- * @active_conv: The active conversation.
- * @window: The #GntWindow for the conversation.
- * @entry: The #GntEntry for input.
- * @tv: The #GntTextView that displays the history.
- * @menu: The menu for the conversation.
- * @info: The info widget that shows the information about the conversation.
- * @plugins: The #GntMenuItem for plugins.
- * @flags: The flags for the conversation.
- * A Finch conversation.
- PurpleConversation *active_conv;
- GntWidget *window; /* the container */
- GntWidget *entry; /* entry */
- GntWidget *tv; /* text-view */
- FinchConversationFlag flags;
- * @userlist: The widget that displays the users in the chat.
- * The chat specific implementation for a conversation.
- GntWidget *userlist; /* the userlist */
- * @sendto: The sendto widget which allows the user to select who they're
- * The instant message implementation for a conversation.
- * finch_conv_get_ui_ops:
- * Get the ui-functions.
- * Returns: The PurpleConversationUiOps populated with the appropriate functions.
-PurpleConversationUiOps *finch_conv_get_ui_ops(void);
- * finch_conversation_init:
- * Perform the necessary initializations.
-void finch_conversation_init(void);
- * finch_conversation_uninit:
- * Perform the necessary uninitializations.
-void finch_conversation_uninit(void);
- * finch_conversation_set_active:
- * @conv: The conversation to make active.
- * Set a conversation as active in a contactized conversation
-void finch_conversation_set_active(PurpleConversation *conv);
- * finch_conversation_set_info_widget:
- * @conv: The conversation.
- * @widget: The widget containing the information. If %NULL,
- * the current information widget is removed.
- * Sets the information widget for the conversation window.
-void finch_conversation_set_info_widget(PurpleConversation *conv, GntWidget *widget);
-#endif /* FINCH_CONV_H */
--- a/finch/gntdebug.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,359 +0,0 @@
- * Finch 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 <purpleconfig.h>
-#include <glib/gi18n-lib.h>
-#include <glib/gstdio.h>
-#define PREF_ROOT "/finch/debug"
- /* Other members, including private data. */
-handle_fprintf_stderr_cb(GIOChannel *source, G_GNUC_UNUSED GIOCondition cond,
- G_GNUC_UNUSED gpointer data)
- size = read(g_io_channel_unix_get_fd(source), message, sizeof(message) - 1);
- /* Something bad probably happened elsewhere ... let's ignore */
- g_log("stderr", G_LOG_LEVEL_WARNING, "%s", message);
-handle_fprintf_stderr(gboolean stop)
- static int readhandle = -1;
- g_source_remove(readhandle);
- if (purple_input_pipe(pipes)) {
- dup2(pipes[1], STDERR_FILENO);
- stderrch = g_io_channel_unix_new(pipes[0]);
- g_io_channel_set_close_on_unref(stderrch, TRUE);
- readhandle = g_io_add_watch_full(stderrch, G_PRIORITY_HIGH,
- G_IO_IN | G_IO_ERR | G_IO_PRI,
- handle_fprintf_stderr_cb, NULL, NULL);
- g_io_channel_unref(stderrch);
-reset_debug_win(G_GNUC_UNUSED GntWidget *w, G_GNUC_UNUSED gpointer data)
- debug.window = debug.tview = debug.search = NULL;
-clear_debug_win(G_GNUC_UNUSED GntWidget *w, GntTextView *tv)
- gnt_text_view_clear(tv);
-print_stderr(const char *string)
- g_printerr("%s", string);
-toggle_pause(G_GNUC_UNUSED GntWidget *w, G_GNUC_UNUSED gpointer n)
- debug.paused = !debug.paused;
-finch_debug_g_log_handler(GLogLevelFlags log_level, const GLogField *fields,
- gsize n_fields, G_GNUC_UNUSED gpointer user_data)
- const gchar *domain = NULL;
- const gchar *msg = NULL;
- const gchar *search_str = NULL;
- GntTextFormatFlags flag = 0;
- GDateTime *local_date_time = NULL;
- gchar *local_time = NULL;
- if (debug.window == NULL || debug.paused) {
- return G_LOG_WRITER_UNHANDLED;
- for (i = 0; i < n_fields; i++) {
- if (purple_strequal(fields[i].key, "GLIB_DOMAIN")) {
- domain = fields[i].value;
- } else if (purple_strequal(fields[i].key, "MESSAGE")) {
- return G_LOG_WRITER_UNHANDLED;
- /* Filter out log line if we have a search term, and it doesn't match
- * the domain or message. */
- search_str = gnt_entry_get_text(GNT_ENTRY(debug.search));
- if (search_str != NULL && *search_str != '\0') {
- if (g_strrstr(domain, search_str) == NULL &&
- g_strrstr(msg, search_str) == NULL)
- return G_LOG_WRITER_UNHANDLED;
- pos = gnt_text_view_get_lines_below(GNT_TEXT_VIEW(debug.tview));
- local_date_time = g_date_time_new_now_local();
- local_time = g_date_time_format(local_date_time, "%H:%M:%S ");
- g_date_time_unref(local_date_time);
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), local_time,
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), domain,
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), ": ",
- flag = GNT_TEXT_FLAG_NORMAL;
- switch (log_level & G_LOG_LEVEL_MASK) {
- case G_LOG_LEVEL_WARNING:
- flag |= GNT_TEXT_FLAG_UNDERLINE;
- case G_LOG_LEVEL_ERROR:
- flag |= GNT_TEXT_FLAG_BOLD;
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), msg,
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug.tview), "\n",
- gnt_text_view_scroll(GNT_TEXT_VIEW(debug.tview), 0);
- return G_LOG_WRITER_HANDLED;
-size_changed_cb(GntWidget *widget, G_GNUC_UNUSED int oldw,
- G_GNUC_UNUSED int oldh)
- gnt_widget_get_size(widget, &w, &h);
- purple_prefs_set_int(PREF_ROOT "/size/width", w);
- purple_prefs_set_int(PREF_ROOT "/size/height", h);
-for_real(gpointer entry)
- purple_prefs_set_string(PREF_ROOT "/filter", gnt_entry_get_text(entry));
-update_filter_string(GntEntry *entry, G_GNUC_UNUSED gpointer data)
- int id = g_timeout_add_seconds(1, for_real, entry);
- g_object_set_data_full(G_OBJECT(entry), "update-filter", GINT_TO_POINTER(id),
- (GDestroyNotify)g_source_remove);
-file_save(GntFileSel *fs, const char *path, G_GNUC_UNUSED const char *file,
- GDateTime *date = NULL;
- gchar *date_str = NULL;
- if ((fp = g_fopen(path, "w+")) == NULL) {
- purple_notify_error(NULL, NULL, _("Unable to open file."), NULL, NULL);
- date = g_date_time_new_now_local();
- date_str = g_date_time_format(date, "%c");
- fprintf(fp, "Finch Debug Log : %s\n", date_str);
- fprintf(fp, "%s", gnt_text_view_get_text(tv));
- gnt_widget_destroy(GNT_WIDGET(fs));
- g_date_time_unref(date);
-save_debug_win(G_GNUC_UNUSED GntWidget *w, GntTextView *tv)
- GntWidget *window = gnt_file_sel_new();
- GntFileSel *sel = GNT_FILE_SEL(window);
- gnt_file_sel_set_current_location(sel, g_get_home_dir());
- gnt_file_sel_set_suggested_filename(sel, "debug.txt");
- g_signal_connect(G_OBJECT(sel), "file_selected", G_CALLBACK(file_save), tv);
- g_signal_connect(G_OBJECT(sel), "cancelled", G_CALLBACK(gnt_widget_destroy), NULL);
- gnt_widget_show(window);
-finch_debug_window_show(void)
- GntWidget *wid, *box, *label;
- gnt_window_present(debug.window);
- debug.window = gnt_vbox_new(FALSE);
- gnt_box_set_toplevel(GNT_BOX(debug.window), TRUE);
- gnt_box_set_title(GNT_BOX(debug.window), _("Debug Window"));
- gnt_box_set_pad(GNT_BOX(debug.window), 0);
- gnt_box_set_alignment(GNT_BOX(debug.window), GNT_ALIGN_MID);
- debug.tview = gnt_text_view_new();
- gnt_box_add_widget(GNT_BOX(debug.window), debug.tview);
- gnt_widget_set_size(debug.tview,
- purple_prefs_get_int(PREF_ROOT "/size/width"),
- purple_prefs_get_int(PREF_ROOT "/size/height"));
- g_signal_connect(G_OBJECT(debug.tview), "size_changed", G_CALLBACK(size_changed_cb), NULL);
- gnt_box_add_widget(GNT_BOX(debug.window), gnt_line_new(FALSE));
- box = gnt_hbox_new(FALSE);
- gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_MID);
- gnt_box_set_fill(GNT_BOX(box), FALSE);
- /* XXX: Setting the GROW_Y for the following widgets don't make sense. But right now
- * it's necessary to make the width of the debug window resizable ... like I said,
- * it doesn't make sense. The bug is likely in the packing in gntbox.c.
- wid = gnt_button_new(_("Clear"));
- g_signal_connect(G_OBJECT(wid), "activate", G_CALLBACK(clear_debug_win), debug.tview);
- gnt_widget_set_grow_y(wid, TRUE);
- gnt_box_add_widget(GNT_BOX(box), wid);
- wid = gnt_button_new(_("Save"));
- g_signal_connect(G_OBJECT(wid), "activate", G_CALLBACK(save_debug_win), debug.tview);
- gnt_widget_set_grow_y(wid, TRUE);
- gnt_box_add_widget(GNT_BOX(box), wid);
- debug.search = gnt_entry_new(purple_prefs_get_string(PREF_ROOT "/filter"));
- label = gnt_label_new(_("Filter:"));
- gnt_widget_set_grow_x(label, FALSE);
- gnt_box_add_widget(GNT_BOX(box), label);
- gnt_box_add_widget(GNT_BOX(box), debug.search);
- g_signal_connect(G_OBJECT(debug.search), "text_changed", G_CALLBACK(update_filter_string), NULL);
- wid = gnt_check_box_new(_("Pause"));
- g_signal_connect(G_OBJECT(wid), "toggled", G_CALLBACK(toggle_pause), NULL);
- gnt_widget_set_grow_y(wid, TRUE);
- gnt_box_add_widget(GNT_BOX(box), wid);
- gnt_box_add_widget(GNT_BOX(debug.window), box);
- gnt_widget_set_grow_y(box, TRUE);
- gnt_widget_set_name(debug.window, "debug-window");
- g_signal_connect(G_OBJECT(debug.window), "destroy", G_CALLBACK(reset_debug_win), NULL);
- gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(debug.tview), debug.window);
- gnt_text_view_attach_pager_widget(GNT_TEXT_VIEW(debug.tview), debug.window);
- gnt_widget_show(debug.window);
-finch_debug_init_handler(void)
- g_log_set_writer_func(finch_debug_g_log_handler, NULL, NULL);
- g_set_print_handler(print_stderr); /* Redirect the debug messages to stderr */
- handle_fprintf_stderr(FALSE);
- purple_prefs_add_none(PREF_ROOT);
- purple_prefs_add_string(PREF_ROOT "/filter", "");
- purple_prefs_add_none(PREF_ROOT "/size");
- purple_prefs_add_int(PREF_ROOT "/size/width", 60);
- purple_prefs_add_int(PREF_ROOT "/size/height", 15);
-finch_debug_uninit(void)
- handle_fprintf_stderr(TRUE);
--- a/finch/gntdebug.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-/**********************************************************************
- **********************************************************************/
- * finch_debug_init_handler:
- * Initialize handler for GLib logging system.
- * This must be called early if you want to capture logs at startup, and avoid
-void finch_debug_init_handler(void);
- * Perform necessary initializations.
-void finch_debug_init(void);
- * Perform necessary uninitialization.
-void finch_debug_uninit(void);
- * finch_debug_window_show:
- * Show the debug window.
-void finch_debug_window_show(void);
-#endif /* FINCH_DEBUG_H */
--- a/finch/gntidle.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
- * Finch - Universal Text Chat Client
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- * 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, see <https://www.gnu.org/licenses/>.
-/******************************************************************************
- * PurpleIdleUi implementation
- *****************************************************************************/
-finch_idle_get_idle_time(G_GNUC_UNUSED PurpleIdleUi *ui) {
- return gnt_wm_get_idle_time();
-finch_idle_purple_idle_ui_init(PurpleIdleUiInterface *iface) {
- iface->get_idle_time = finch_idle_get_idle_time;
-/******************************************************************************
- * GObject Implementation
- *****************************************************************************/
-G_DEFINE_FINAL_TYPE_WITH_CODE(
- finch_idle_purple_idle_ui_init
-finch_idle_init(G_GNUC_UNUSED FinchIdle *idle) {
-finch_idle_class_init(G_GNUC_UNUSED FinchIdleClass *klass) {
-/******************************************************************************
- *****************************************************************************/
- return g_object_new(FINCH_TYPE_IDLE, NULL);
--- a/finch/gntidle.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
- * Finch - Universal Text Chat Client
- * Copyright (C) Pidgin Developers <devel@pidgin.im>
- * 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, see <https://www.gnu.org/licenses/>.
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
- * An implementation of [iface@Purple.IdleUi] for Finch.
-#define FINCH_TYPE_IDLE (finch_idle_get_type())
-G_DECLARE_FINAL_TYPE(FinchIdle, finch_idle, FINCH, IDLE, GObject)
- * Creates a new [class@Idle].
- * Returns: (transfer full): The new instance.
-PurpleIdleUi *finch_idle_new(void);
-#endif /* FINCH_IDLE_H */
--- a/finch/gntmedia.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,426 +0,0 @@
- * Finch 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 <purpleconfig.h>
-#include <glib/gi18n-lib.h>
-/* An incredibly large part of the following is from gtkmedia.c */
-#define FINCH_TYPE_MEDIA (finch_media_get_type())
-#define FINCH_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), FINCH_TYPE_MEDIA, FinchMedia))
-#define FINCH_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), FINCH_TYPE_MEDIA, FinchMediaClass))
-#define FINCH_IS_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), FINCH_TYPE_MEDIA))
-#define FINCH_IS_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), FINCH_TYPE_MEDIA))
-#define FINCH_MEDIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), FINCH_TYPE_MEDIA, FinchMediaClass))
-typedef struct _FinchMedia FinchMedia;
-typedef struct _FinchMediaClass FinchMediaClass;
-typedef enum _FinchMediaState FinchMediaState;
- GntBoxClass parent_class;
- PurpleConversation *conv;
-static GType finch_media_get_type (void);
-static void finch_media_class_init (FinchMediaClass *klass);
-static void finch_media_init (FinchMedia *media);
-static void finch_media_finalize (GObject *object);
-static void finch_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
-static void finch_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
-static guint finch_media_signals[N_SIGNALS] = {0, };
-G_DEFINE_TYPE(FinchMedia, finch_media, GNT_TYPE_BOX);
-finch_media_class_init (FinchMediaClass *klass)
- GObjectClass *gobject_class = (GObjectClass*)klass;
- gobject_class->finalize = finch_media_finalize;
- gobject_class->set_property = finch_media_set_property;
- gobject_class->get_property = finch_media_get_property;
- g_object_class_install_property(gobject_class, PROP_MEDIA,
- g_param_spec_object("media",
- "The PurpleMedia associated with this media.",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
- finch_media_signals[SIG_MESSAGE] = g_signal_new("message", G_TYPE_FROM_CLASS(klass),
- G_SIGNAL_RUN_LAST, 0, NULL, NULL,
- g_cclosure_marshal_VOID__STRING,
- G_TYPE_NONE, 1, G_TYPE_STRING);
-finch_media_init (FinchMedia *media)
- media->calling = gnt_label_new(_("Calling..."));
- media->hangup = gnt_button_new(_("Hangup"));
- media->accept = gnt_button_new(_("Accept"));
- media->reject = gnt_button_new(_("Reject"));
- gnt_box_set_alignment(GNT_BOX(media), GNT_ALIGN_MID);
- gnt_box_add_widget(GNT_BOX(media), media->accept);
- gnt_box_add_widget(GNT_BOX(media), media->reject);
-finch_media_finalize (GObject *media)
- FinchMedia *gntmedia = FINCH_MEDIA(media);
- purple_debug_info("gntmedia", "finch_media_finalize");
- g_clear_object(&gntmedia->media);
-finch_media_emit_message(FinchMedia *gntmedia, const char *msg)
- g_signal_emit(gntmedia, finch_media_signals[SIG_MESSAGE], 0, msg);
-finch_media_connected_cb(G_GNUC_UNUSED PurpleMedia *media,
- finch_media_emit_message(gntmedia, _("Call in progress."));
- gnt_box_remove(GNT_BOX(gntmedia), gntmedia->accept);
- gnt_box_remove(GNT_BOX(gntmedia), gntmedia->reject);
- gnt_box_remove(GNT_BOX(gntmedia), gntmedia->hangup);
- gnt_box_remove(GNT_BOX(gntmedia), gntmedia->calling);
- gnt_box_add_widget(GNT_BOX(gntmedia), gntmedia->hangup);
- g_clear_pointer(&gntmedia->accept, gnt_widget_destroy);
- g_clear_pointer(&gntmedia->reject, gnt_widget_destroy);
- g_clear_pointer(&gntmedia->calling, gnt_widget_destroy);
- parent = gnt_widget_get_toplevel(GNT_WIDGET(gntmedia));
- gnt_box_readjust(GNT_BOX(parent));
- gnt_widget_draw(parent);
-finch_media_wait_cb(G_GNUC_UNUSED PurpleMedia *media, FinchMedia *gntmedia)
- gnt_box_remove(GNT_BOX(gntmedia), gntmedia->accept);
- gnt_box_remove(GNT_BOX(gntmedia), gntmedia->reject);
- gnt_box_remove(GNT_BOX(gntmedia), gntmedia->hangup);
- gnt_box_remove(GNT_BOX(gntmedia), gntmedia->calling);
- gnt_box_add_widget(GNT_BOX(gntmedia), gntmedia->calling);
- gnt_box_add_widget(GNT_BOX(gntmedia), gntmedia->hangup);
- parent = gnt_widget_get_toplevel(GNT_WIDGET(gntmedia));
- gnt_box_readjust(GNT_BOX(parent));
- gnt_widget_draw(parent);
-finch_media_state_changed_cb(PurpleMedia *media, PurpleMediaState state,
- gchar *sid, gchar *name, FinchMedia *gntmedia)
- purple_debug_info("gntmedia", "state: %d sid: %s name: %s\n",
- if (sid == NULL && name == NULL) {
- if (state == PURPLE_MEDIA_STATE_END) {
- finch_media_emit_message(gntmedia,
- _("The call has been terminated."));
- finch_conversation_set_info_widget(gntmedia->conv, NULL);
- gnt_widget_destroy(GNT_WIDGET(gntmedia));
- * XXX: This shouldn't have to be here
- * to free the FinchMedia widget.
- g_object_unref(gntmedia);
- } else if (state == PURPLE_MEDIA_STATE_CONNECTED) {
- finch_media_connected_cb(media, gntmedia);
- } else if (state == PURPLE_MEDIA_STATE_NEW &&
- sid != NULL && name != NULL &&
- purple_media_is_initiator(media, sid, name) == FALSE) {
- PurpleAccount *account;
- PurpleMediaSessionType type =
- purple_media_get_session_type(media, sid);
- account = purple_media_get_account(gntmedia->media);
- buddy = purple_blist_find_buddy(account, name);
- alias = buddy ? purple_buddy_get_contact_alias(buddy) : name;
- if (type & PURPLE_MEDIA_AUDIO) {
- message = g_strdup_printf(
- _("%s wishes to start an audio session with you."),
- message = g_strdup_printf(
- _("%s is trying to start an unsupported media session type with you."),
- finch_media_emit_message(gntmedia, message);
-finch_media_stream_info_cb(G_GNUC_UNUSED PurpleMedia *media,
- PurpleMediaInfoType type,
- G_GNUC_UNUSED gchar *sid,
- G_GNUC_UNUSED gchar *name,
- G_GNUC_UNUSED gboolean local,
- if (type == PURPLE_MEDIA_INFO_REJECT) {
- finch_media_emit_message(gntmedia,
- _("You have rejected the call."));
-finch_media_accept_cb(PurpleMedia *media, G_GNUC_UNUSED GntWidget *widget)
- purple_media_stream_info(media, PURPLE_MEDIA_INFO_ACCEPT,
-finch_media_hangup_cb(PurpleMedia *media, G_GNUC_UNUSED GntWidget *widget)
- purple_media_stream_info(media, PURPLE_MEDIA_INFO_HANGUP,
-finch_media_reject_cb(PurpleMedia *media, G_GNUC_UNUSED GntWidget *widget)
- purple_media_stream_info(media, PURPLE_MEDIA_INFO_REJECT,
-finch_media_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
- g_return_if_fail(FINCH_IS_MEDIA(object));
- media = FINCH_MEDIA(object);
- g_set_object(&media->media, g_value_get_object(value));
- g_signal_connect_swapped(G_OBJECT(media->accept), "activate",
- G_CALLBACK(finch_media_accept_cb), media->media);
- g_signal_connect_swapped(G_OBJECT(media->reject), "activate",
- G_CALLBACK(finch_media_reject_cb), media->media);
- g_signal_connect_swapped(G_OBJECT(media->hangup), "activate",
- G_CALLBACK(finch_media_hangup_cb), media->media);
- if (purple_media_is_initiator(media->media, NULL, NULL)) {
- finch_media_wait_cb(media->media, media);
- g_signal_connect(G_OBJECT(media->media), "state-changed",
- G_CALLBACK(finch_media_state_changed_cb), media);
- g_signal_connect(G_OBJECT(media->media), "stream-info",
- G_CALLBACK(finch_media_stream_info_cb), media);
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-finch_media_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
- g_return_if_fail(FINCH_IS_MEDIA(object));
- media = FINCH_MEDIA(object);
- g_value_set_object(value, media->media);
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-finch_media_new(PurpleMedia *media)
-gntmedia_message_cb(G_GNUC_UNUSED FinchMedia *gntmedia, const char *msg,
- PurpleConversation *conv)
- if (PURPLE_IS_IM_CONVERSATION(conv)) {
- purple_conversation_write_system_message(conv, msg, 0);
-finch_new_media(G_GNUC_UNUSED PurpleMediaManager *manager, PurpleMedia *media,
- PurpleAccount *account, gchar *name,
- G_GNUC_UNUSED gpointer data)
- PurpleConversation *conv;
- conv = PURPLE_CONVERSATION(purple_im_conversation_new(account, name));
- gntmedia = finch_media_new(media);
- g_signal_connect(G_OBJECT(gntmedia), "message", G_CALLBACK(gntmedia_message_cb), conv);
- FINCH_MEDIA(gntmedia)->conv = conv;
- finch_conversation_set_info_widget(conv, gntmedia);
-call_cmd_cb(PurpleConversation *conv, G_GNUC_UNUSED const char *cmd,
- G_GNUC_UNUSED char **args, G_GNUC_UNUSED char **error,
- G_GNUC_UNUSED gpointer data)
- PurpleAccount *account = purple_conversation_get_account(conv);
- if (!purple_protocol_initiate_media(account,
- purple_conversation_get_name(conv),
- return PURPLE_CMD_RET_FAILED;
- return PURPLE_CMD_RET_OK;
-void finch_media_manager_init(void)
- PurpleMediaManager *manager = purple_media_manager_get();
- PurpleMediaElementInfo *audio_src = NULL;
- PurpleMediaElementInfo *audio_sink = NULL;
- purple_prefs_add_none(FINCH_PREFS_ROOT "/vvconfig");
- purple_prefs_add_none(FINCH_PREFS_ROOT "/vvconfig/audio");
- purple_prefs_add_none(FINCH_PREFS_ROOT "/vvconfig/audio/src");
- purple_prefs_add_none(FINCH_PREFS_ROOT "/vvconfig/audio/sink");
- purple_prefs_add_string(FINCH_PREFS_ROOT "/vvconfig/audio/src/device", "");
- purple_prefs_add_string(FINCH_PREFS_ROOT "/vvconfig/audio/sink/device", "");
- pref = purple_prefs_get_string(
- FINCH_PREFS_ROOT "/vvconfig/audio/src/device");
- audio_src = purple_media_manager_get_element_info(manager, pref);
- purple_prefs_set_string(
- FINCH_PREFS_ROOT "/vvconfig/audio/src/device", pref);
- audio_src = purple_media_manager_get_element_info(manager,
- pref = purple_prefs_get_string(
- FINCH_PREFS_ROOT "/vvconfig/audio/sink/device");
- audio_sink = purple_media_manager_get_element_info(manager, pref);
- pref = "autoaudiosink";
- purple_prefs_set_string(
- FINCH_PREFS_ROOT "/vvconfig/audio/sink/device", pref);
- audio_sink = purple_media_manager_get_element_info(manager,
- g_signal_connect(G_OBJECT(manager), "init-media", G_CALLBACK(finch_new_media), NULL);
- purple_cmd_register("call", "", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_IM, NULL,
- call_cmd_cb, _("call: Make an audio call."), NULL);
- purple_media_manager_set_ui_caps(manager,
- PURPLE_MEDIA_CAPS_AUDIO |
- PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION);
- purple_debug_info("gntmedia", "Registering media element types\n");
- purple_media_manager_set_active_element(manager, audio_src);
- purple_media_manager_set_active_element(manager, audio_sink);
- g_object_unref(audio_src);
- g_object_unref(audio_sink);
-void finch_media_manager_uninit(void)
- PurpleMediaManager *manager = purple_media_manager_get();
- g_signal_handlers_disconnect_by_func(manager, finch_new_media, NULL);
--- a/finch/gntmedia.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,38 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-void finch_media_manager_init(void);
-void finch_media_manager_uninit(void);
-#endif /* FINCH_MEDIA_H */
--- a/finch/gntmenuutil.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
- * Finch 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 "gntmenuutil.h"
-context_menu_callback(GntMenuItem *item, gpointer data)
- PurpleActionMenu *action = data;
- void (*callback)(gpointer, gpointer);
- callback = (void (*)(gpointer, gpointer))
- purple_action_menu_get_callback(action);
- gpointer ctx = g_object_get_data(G_OBJECT(item), "menuctx");
- callback(ctx, purple_action_menu_get_data(action));
-finch_append_menu_action(GntMenu *menu, PurpleActionMenu *action, gpointer ctx)
- gchar *clean_label = NULL;
- label = purple_action_menu_get_label(action);
- if (strchr(label, '_') != NULL) {
- clean_label = g_strdup(label);
- purple_str_strip_char(clean_label, '_');
- item = gnt_menuitem_new(label);
- if (purple_action_menu_get_callback(action)) {
- gnt_menuitem_set_callback(item, context_menu_callback, action);
- g_object_set_data(G_OBJECT(item), "menuctx", ctx);
- gnt_menu_add_item(menu, item);
- list = purple_action_menu_get_children(action);
- GntWidget *sub = gnt_menu_new(GNT_MENU_POPUP);
- gnt_menuitem_set_submenu(item, GNT_MENU(sub));
- for (; list; list = g_list_delete_link(list, list))
- finch_append_menu_action(GNT_MENU(sub), list->data, action);
- purple_action_menu_set_children(action, NULL);
- g_signal_connect_swapped(G_OBJECT(menu), "destroy",
- G_CALLBACK(purple_action_menu_free), action);
--- a/finch/gntmenuutil.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-#ifndef FINCH_MENUUTIL_H
-#define FINCH_MENUUTIL_H
-/***************************************************************************
- * GNT Menu Utility Functions
- ***************************************************************************/
- * finch_append_menu_action:
- * @menu: the GntMenu to add to
- * @action: the PurpleActionMenu to add
- * @ctx: the callback context, passed as the first argument to
- * the PurpleActionMenu's GCallback function.
- * Add a PurpleActionMenu to a GntMenu.
-void finch_append_menu_action(GntMenu *menu, PurpleActionMenu *action, gpointer ctx);
-#endif /* FINCH_MENUUTIL_H */
--- a/finch/gntnotify.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,429 +0,0 @@
- * Finch 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>
-notify_msg_window_destroy_cb(GntWidget *window, PurpleNotifyType type)
- purple_notify_close(type, window);
-finch_notify_common(PurpleNotifyType ntype, PurpleNotifyMessageType msgtype,
- const char *title, const char *primary,
- G_GNUC_UNUSED PurpleRequestCommonParameters *cpar)
- GntWidget *window, *button;
- GntTextFormatFlags pf = 0, sf = 0;
- case PURPLE_NOTIFY_MSG_ERROR:
- sf |= GNT_TEXT_FLAG_BOLD;
- case PURPLE_NOTIFY_MSG_WARNING:
- pf |= GNT_TEXT_FLAG_UNDERLINE;
- case PURPLE_NOTIFY_MSG_INFO:
- pf |= GNT_TEXT_FLAG_BOLD;
- window = gnt_window_box_new(FALSE, TRUE);
- gnt_box_set_title(GNT_BOX(window), title);
- gnt_box_set_fill(GNT_BOX(window), FALSE);
- gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
- gnt_box_set_pad(GNT_BOX(window), 0);
- gnt_box_add_widget(GNT_BOX(window),
- gnt_label_new_with_format(primary, pf));
- button = gnt_button_new(_("OK"));
- if (ntype == PURPLE_NOTIFY_FORMATTED) {
- int width = -1, height = -1;
- char *plain = (char*)secondary;
- msg = gnt_text_view_new();
- gnt_text_view_set_flag(GNT_TEXT_VIEW(msg), GNT_TEXT_VIEW_TOP_ALIGN | GNT_TEXT_VIEW_NO_SCROLL);
- plain = purple_markup_strip_html(secondary);
- if (!gnt_util_parse_xhtml_to_textview(secondary, GNT_TEXT_VIEW(msg)))
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(msg), plain, sf);
- gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(msg), button);
- gnt_util_get_text_bound(plain, &width, &height);
- gnt_widget_set_size(msg, width + 3, height + 1);
- if (plain != secondary)
- msg = gnt_label_new_with_format(secondary, sf);
- gnt_box_add_widget(GNT_BOX(window), msg);
- g_object_set_data(G_OBJECT(window), "info-widget", msg);
- gnt_box_add_widget(GNT_BOX(window), button);
- g_signal_connect_swapped(G_OBJECT(button), "activate",
- G_CALLBACK(gnt_widget_destroy), window);
- g_signal_connect(G_OBJECT(window), "destroy",
- G_CALLBACK(notify_msg_window_destroy_cb), GINT_TO_POINTER(ntype));
- gnt_widget_show(window);
-/* handle is, in all/most occasions, a GntWidget * */
-static void finch_close_notify(PurpleNotifyType type, void *handle)
- GntWidget *widget = handle;
- widget = gnt_widget_get_toplevel(widget);
- if (type == PURPLE_NOTIFY_SEARCHRESULTS)
- purple_notify_searchresults_free(g_object_get_data(handle, "notify-results"));
- /* This did not seem to be necessary */
- g_signal_handlers_disconnect_by_func(widget, notify_msg_window_destroy_cb,
- GINT_TO_POINTER(type));
- gnt_widget_destroy(widget);
-finch_notify_message(PurpleNotifyMessageType type, const char *title,
- const char *primary, const char *secondary,
- PurpleRequestCommonParameters *cpar)
- return finch_notify_common(PURPLE_NOTIFY_MESSAGE, type, title, primary,
-static void *finch_notify_formatted(const char *title, const char *primary,
- const char *secondary, const char *text)
- char *t = g_strdup_printf("<span>%s%s%s</span>",
- secondary ? secondary : "",
- purple_markup_html_to_xhtml(t, &xhtml, NULL);
- ret = finch_notify_common(PURPLE_NOTIFY_FORMATTED,
- PURPLE_NOTIFY_MSG_INFO, title, primary, xhtml, NULL);
-/** User information. **/
-static GHashTable *userinfo;
-userinfo_hash(PurpleAccount *account, const char *who)
- g_snprintf(key, sizeof(key), "%s - %s",
- purple_contact_info_get_username(PURPLE_CONTACT_INFO(account)),
- purple_normalize(account, who));
- return g_utf8_strup(key, -1);
-remove_userinfo(G_GNUC_UNUSED GntWidget *widget, gpointer key)
- g_hash_table_remove(userinfo, key);
-purple_notify_user_info_get_xhtml(PurpleNotifyUserInfo *user_info)
- text = g_string_new("<span>");
- for (l = purple_notify_user_info_get_entries(user_info)->head; l != NULL;
- PurpleNotifyUserInfoEntry *user_info_entry = l->data;
- PurpleNotifyUserInfoEntryType type = purple_notify_user_info_entry_get_entry_type(user_info_entry);
- const char *label = purple_notify_user_info_entry_get_label(user_info_entry);
- const char *value = purple_notify_user_info_entry_get_value(user_info_entry);
- /* Handle the label/value pair itself */
- if (type == PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER)
- g_string_append(text, "<u>");
- g_string_append_printf(text, "<b>%s</b>", label);
- g_string_append(text, "<span>");
- g_string_append(text, ": ");
- char *strip = purple_markup_strip_html(value);
- g_string_append(text, strip);
- g_string_append(text, "</span>");
- if (type == PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_HEADER)
- g_string_append(text, "</u>");
- else if (type == PURPLE_NOTIFY_USER_INFO_ENTRY_SECTION_BREAK)
- g_string_append(text, "<HR/>");
- g_string_append(text, "<BR/>");
- g_string_append(text, "</span>");
- return g_string_free(text, FALSE);
-finch_notify_userinfo(PurpleConnection *gc, const char *who, PurpleNotifyUserInfo *user_info)
- char *key = userinfo_hash(purple_connection_get_account(gc), who);
- info = purple_notify_user_info_get_xhtml(user_info);
- ui_handle = g_hash_table_lookup(userinfo, key);
- if (ui_handle != NULL) {
- GntTextView *msg = GNT_TEXT_VIEW(g_object_get_data(G_OBJECT(ui_handle), "info-widget"));
- char *strip = purple_markup_strip_html(info);
- int tvw, tvh, width, height, ntvw, ntvh;
- ui_handle = window = gnt_widget_get_toplevel(GNT_WIDGET(ui_handle));
- gnt_widget_get_size(window, &width, &height);
- gnt_widget_get_size(GNT_WIDGET(msg), &tvw, &tvh);
- gnt_text_view_clear(msg);
- if (!gnt_util_parse_xhtml_to_textview(info, msg))
- gnt_text_view_append_text_with_flags(msg, strip, GNT_TEXT_FLAG_NORMAL);
- gnt_text_view_scroll(msg, 0);
- gnt_util_get_text_bound(strip, &ntvw, &ntvh);
- gnt_screen_resize_widget(window, width + MAX(0, ntvw - tvw), height + MAX(0, ntvh - tvh));
- primary = g_strdup_printf(_("Info for %s"), who);
- ui_handle = finch_notify_formatted(_("Buddy Information"), primary, NULL, info);
- g_hash_table_insert(userinfo, key, ui_handle);
- g_signal_connect(G_OBJECT(ui_handle), "destroy", G_CALLBACK(remove_userinfo), key);
-notify_button_activated(GntWidget *widget, PurpleNotifySearchButton *b)
- PurpleAccount *account = g_object_get_data(G_OBJECT(widget), "notify-account");
- gpointer data = g_object_get_data(G_OBJECT(widget), "notify-data");
- list = gnt_tree_get_selection_text_list(GNT_TREE(g_object_get_data(G_OBJECT(widget), "notify-tree")));
- b->callback(purple_account_get_connection(account), list, data);
- g_list_free_full(list, g_free);
-finch_notify_sr_new_rows(G_GNUC_UNUSED PurpleConnection *gc,
- PurpleNotifySearchResults *results, gpointer data)
- GntWindow *window = GNT_WINDOW(data);
- GntTree *tree = GNT_TREE(g_object_get_data(G_OBJECT(window), "tree-widget"));
- GntTreeRow *prev = NULL;
- gnt_tree_remove_all(GNT_TREE(tree));
- for (o = results->rows; o; o = o->next)
- gnt_tree_add_row_after(GNT_TREE(tree), o->data,
- gnt_tree_create_row_from_list(GNT_TREE(tree), o->data),
-notify_sr_destroy_cb(GntWidget *window, G_GNUC_UNUSED gpointer data)
- purple_notify_close(PURPLE_NOTIFY_SEARCHRESULTS, window);
-finch_notify_searchresults(PurpleConnection *gc, const char *title,
- const char *primary, const char *secondary,
- PurpleNotifySearchResults *results, gpointer data)
- GntWidget *window, *tree, *box, *button;
- window = gnt_vbox_new(FALSE);
- gnt_box_set_toplevel(GNT_BOX(window), TRUE);
- gnt_box_set_title(GNT_BOX(window), title);
- gnt_box_set_fill(GNT_BOX(window), TRUE);
- gnt_box_set_pad(GNT_BOX(window), 0);
- gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
- gnt_box_add_widget(GNT_BOX(window),
- gnt_label_new_with_format(primary, GNT_TEXT_FLAG_BOLD));
- gnt_box_add_widget(GNT_BOX(window),
- gnt_label_new_with_format(secondary, GNT_TEXT_FLAG_NORMAL));
- columns = g_list_length(results->columns);
- tree = gnt_tree_new_with_columns(columns);
- gnt_tree_set_show_title(GNT_TREE(tree), TRUE);
- gnt_box_add_widget(GNT_BOX(window), tree);
- for (iter = results->columns; iter; iter = iter->next)
- PurpleNotifySearchColumn *column = iter->data;
- gnt_tree_set_column_title(GNT_TREE(tree), i, purple_notify_searchresult_column_get_title(column));
- if (!purple_notify_searchresult_column_is_visible(column))
- gnt_tree_set_column_visible(GNT_TREE(tree), i, FALSE);
- box = gnt_hbox_new(TRUE);
- for (iter = results->buttons; iter; iter = iter->next)
- PurpleNotifySearchButton *b = iter->data;
- case PURPLE_NOTIFY_BUTTON_LABELED:
- case PURPLE_NOTIFY_BUTTON_CONTINUE:
- case PURPLE_NOTIFY_BUTTON_ADD:
- case PURPLE_NOTIFY_BUTTON_INFO:
- case PURPLE_NOTIFY_BUTTON_IM:
- case PURPLE_NOTIFY_BUTTON_JOIN:
- case PURPLE_NOTIFY_BUTTON_INVITE:
- button = gnt_button_new(text);
- g_object_set_data(G_OBJECT(button), "notify-account", purple_connection_get_account(gc));
- g_object_set_data(G_OBJECT(button), "notify-data", data);
- g_object_set_data(G_OBJECT(button), "notify-tree", tree);
- g_signal_connect(G_OBJECT(button), "activate",
- G_CALLBACK(notify_button_activated), b);
- gnt_box_add_widget(GNT_BOX(box), button);
- gnt_box_add_widget(GNT_BOX(window), box);
- g_signal_connect(G_OBJECT(tree), "destroy",
- G_CALLBACK(notify_sr_destroy_cb), NULL);
- g_object_set_data(G_OBJECT(window), "tree-widget", tree);
- finch_notify_sr_new_rows(gc, results, window);
- g_signal_connect(G_OBJECT(window), "destroy",
- G_CALLBACK(notify_msg_window_destroy_cb), GINT_TO_POINTER(PURPLE_NOTIFY_SEARCHRESULTS));
- gnt_widget_show(window);
- g_object_set_data(G_OBJECT(window), "notify-results", results);
-finch_notify_uri(const char *url)
- return finch_notify_common(PURPLE_NOTIFY_URI, PURPLE_NOTIFY_MSG_INFO,
- _("URI"), url, NULL, NULL);
-static PurpleNotifyUiOps ops = {
- .notify_message = finch_notify_message,
- .notify_formatted = finch_notify_formatted,
- .notify_searchresults = finch_notify_searchresults,
- .notify_searchresults_new_rows = finch_notify_sr_new_rows,
- .notify_userinfo = finch_notify_userinfo,
- .notify_uri = finch_notify_uri,
- .close_notify = finch_close_notify,
-finch_notify_get_ui_ops(void)
- userinfo = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
-finch_notify_uninit(void) {
- g_clear_pointer(&userinfo, g_hash_table_destroy);
--- a/finch/gntnotify.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,60 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-/**********************************************************************
- **********************************************************************/
- * finch_notify_get_ui_ops:
- * Get the ui-functions.
- * Returns: The PurpleNotifyUiOps structure populated with the appropriate functions.
-PurpleNotifyUiOps *finch_notify_get_ui_ops(void);
- * Perform necessary initializations.
-void finch_notify_init(void);
- * Perform necessary uninitializations.
-void finch_notify_uninit(void);
-#endif /* FINCH_NOTIFY_H */
--- a/finch/gntplugin.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,614 +0,0 @@
- * Finch 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>
- FinchPluginPrefFrameCb pref_frame_cb;
-} FinchPluginInfoPrivate;
- PROP_GNT_PREF_FRAME_CB,
- FINCH_PLUGIN_UI_DATA_TYPE_WINDOW,
- FINCH_PLUGIN_UI_DATA_TYPE_REQUEST
- gpointer request_handle;
-G_DEFINE_TYPE_WITH_PRIVATE(FinchPluginInfo, finch_plugin_info,
- PURPLE_TYPE_PLUGIN_INFO);
-/* Set method for GObject properties */
-finch_plugin_info_set_property(GObject *obj, guint param_id, const GValue *value,
- FinchPluginInfoPrivate *priv = finch_plugin_info_get_instance_private(
- FINCH_PLUGIN_INFO(obj));
- case PROP_GNT_PREF_FRAME_CB:
- priv->pref_frame_cb = g_value_get_pointer(value);
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-/* Get method for GObject properties */
-finch_plugin_info_get_property(GObject *obj, guint param_id, GValue *value,
- FinchPluginInfoPrivate *priv = finch_plugin_info_get_instance_private(
- FINCH_PLUGIN_INFO(obj));
- case PROP_GNT_PREF_FRAME_CB:
- g_value_set_pointer(value, priv->pref_frame_cb);
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
-finch_plugin_info_init(G_GNUC_UNUSED FinchPluginInfo *info)
-/* Class initializer function */
-static void finch_plugin_info_class_init(FinchPluginInfoClass *klass)
- GObjectClass *obj_class = G_OBJECT_CLASS(klass);
- obj_class->get_property = finch_plugin_info_get_property;
- obj_class->set_property = finch_plugin_info_set_property;
- g_object_class_install_property(obj_class, PROP_GNT_PREF_FRAME_CB,
- g_param_spec_pointer("gnt-pref-frame-cb",
- "GNT preferences frame callback",
- "Callback that returns a GNT preferences frame",
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-finch_plugin_info_new(const char *first_property, ...)
- /* at least ID is required */
- va_start(var_args, first_property);
- info = g_object_new_valist(FINCH_TYPE_PLUGIN_INFO, first_property,
- return GPLUGIN_PLUGIN_INFO(info);
-has_prefs(PurplePlugin *plugin)
- PurplePluginInfo *info = purple_plugin_get_info(plugin);
- FinchPluginInfoPrivate *priv = NULL;
- g_return_val_if_fail(plugin != NULL, FALSE);
- if (!purple_plugin_is_loaded(plugin))
- if (FINCH_IS_PLUGIN_INFO(info))
- priv = finch_plugin_info_get_instance_private(
- FINCH_PLUGIN_INFO(info));
- ret = (priv && priv->pref_frame_cb);
-decide_conf_button(PurplePlugin *plugin)
- gnt_widget_set_visible(plugins.conf, TRUE);
- gnt_widget_set_visible(plugins.conf, FALSE);
- gnt_box_readjust(GNT_BOX(plugins.window));
- gnt_widget_draw(plugins.window);
-finch_plugin_pref_close(PurplePlugin *plugin)
- PurplePluginInfo *info;
- FinchPluginUiData *ui_data;
- g_return_if_fail(plugin != NULL);
- info = purple_plugin_get_info(plugin);
- ui_data = g_object_get_data(G_OBJECT(info), "finch-ui-data");
- if (ui_data->type == FINCH_PLUGIN_UI_DATA_TYPE_REQUEST) {
- purple_request_close(PURPLE_REQUEST_FIELDS,
- ui_data->u.request_handle);
- g_return_if_fail(ui_data->type == FINCH_PLUGIN_UI_DATA_TYPE_WINDOW);
- gnt_widget_destroy(ui_data->u.window);
- g_object_set_data(G_OBJECT(info), "finch-ui-data", NULL);
-plugin_toggled_cb(GntWidget *tree, PurplePlugin *plugin,
- G_GNUC_UNUSED gpointer data)
- if (gnt_tree_get_choice(GNT_TREE(tree), plugin))
- if (!purple_plugin_load(plugin, &error)) {
- purple_notify_error(NULL, _("ERROR"), _("loading plugin failed"), error->message, NULL);
- gnt_tree_set_choice(GNT_TREE(tree), plugin, FALSE);
- if (!purple_plugin_unload(plugin, &error)) {
- purple_notify_error(NULL, _("ERROR"), _("unloading plugin failed"), error->message, NULL);
- purple_plugin_disable(plugin);
- gnt_tree_set_choice(GNT_TREE(tree), plugin, TRUE);
- finch_plugin_pref_close(plugin);
- decide_conf_button(plugin);
- finch_plugins_save_loaded();
-finch_plugins_save_loaded(void)
- purple_plugins_save_loaded("/finch/plugins/loaded");
-selection_changed(GntWidget *widget, G_GNUC_UNUSED gpointer old,
- gpointer current, G_GNUC_UNUSED gpointer data)
- PurplePlugin *plugin = current;
- GPluginPluginInfo *info;
- char *text, *authors = NULL;
- const char * const *authorlist;
- GList *list = NULL, *iter = NULL;
- filename = gplugin_plugin_get_filename(GPLUGIN_PLUGIN(plugin));
- info = GPLUGIN_PLUGIN_INFO(purple_plugin_get_info(plugin));
- authorlist = gplugin_plugin_info_get_authors(info);
- authors = g_strjoinv(", ", (gchar **)authorlist);
- /* If the selected plugin was unseen before, mark it as seen. But save the list
- * only when the plugin list is closed. So if the user enables a plugin, and it
- * crashes, it won't get marked as seen so the user can fix the bug and still
- * quickly find the plugin in the list.
- * I probably mean 'plugin developers' by 'users' here. */
- list = g_object_get_data(G_OBJECT(widget), "seen-list");
- iter = g_list_find_custom(list, filename, (GCompareFunc)strcmp);
- list = g_list_prepend(list, g_strdup(filename));
- g_object_set_data(G_OBJECT(widget), "seen-list", list);
- /* XXX: Use formatting and stuff */
- gnt_text_view_clear(GNT_TEXT_VIEW(plugins.aboot));
- text = g_strdup_printf(
- (authorlist && g_strv_length((gchar **)authorlist) > 1
- ? _("Name: %s\nVersion: %s\nDescription: %s\nAuthors: "
- "%s\nWebsite: %s\nFilename: %s\n")
- : _("Name: %s\nVersion: %s\nDescription: %s\nAuthor: "
- "%s\nWebsite: %s\nFilename: %s\n")),
- _(gplugin_plugin_info_get_name(info)),
- _(gplugin_plugin_info_get_version(info)),
- _(gplugin_plugin_info_get_description(info)), authors,
- _(gplugin_plugin_info_get_website(info)), filename);
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(plugins.aboot),
- text, GNT_TEXT_FLAG_NORMAL);
- gnt_text_view_scroll(GNT_TEXT_VIEW(plugins.aboot), 0);
- decide_conf_button(plugin);
-reset_plugin_window(G_GNUC_UNUSED GntWidget *window,
- G_GNUC_UNUSED gpointer data)
- GList *list = g_object_get_data(G_OBJECT(plugins.tree), "seen-list");
- purple_prefs_set_path_list("/finch/plugins/seen", list);
- g_list_free_full(list, g_free);
-plugin_compare(PurplePlugin *p1, PurplePlugin *p2)
- g_utf8_strup(gplugin_plugin_info_get_name(GPLUGIN_PLUGIN_INFO(
- purple_plugin_get_info(p1))),
- g_utf8_strup(gplugin_plugin_info_get_name(GPLUGIN_PLUGIN_INFO(
- purple_plugin_get_info(p2))),
- int ret = g_utf8_collate(s1, s2);
-remove_confwin(G_GNUC_UNUSED GntWidget *window, gpointer _plugin)
- PurplePlugin *plugin = _plugin;
- PurplePluginInfo *info = purple_plugin_get_info(plugin);
- g_object_set_data(G_OBJECT(info), "finch-ui-data", NULL);
-configure_plugin_cb(G_GNUC_UNUSED GntWidget *button,
- G_GNUC_UNUSED gpointer data)
- PurplePluginInfo *info;
- FinchPluginInfoPrivate *priv = NULL;
- FinchPluginUiData *ui_data;
- g_return_if_fail(plugins.tree != NULL);
- plugin = gnt_tree_get_selection_data(GNT_TREE(plugins.tree));
- if (!purple_plugin_is_loaded(plugin))
- purple_notify_error(plugin, _("Error"),
- _("Plugin need to be loaded before you can configure it."), NULL, NULL);
- info = purple_plugin_get_info(plugin);
- if (g_object_get_data(G_OBJECT(info), "finch-ui-data")) {
- ui_data = g_new0(FinchPluginUiData, 1);
- g_object_set_data_full(G_OBJECT(info), "finch-ui-data", ui_data, g_free);
- if (FINCH_IS_PLUGIN_INFO(info))
- priv = finch_plugin_info_get_instance_private(
- FINCH_PLUGIN_INFO(info));
- if (priv && priv->pref_frame_cb != NULL)
- GntWidget *window = gnt_vbox_new(FALSE);
- GntWidget *box, *button;
- gnt_box_set_toplevel(GNT_BOX(window), TRUE);
- gnt_box_set_title(GNT_BOX(window),
- gplugin_plugin_info_get_name(
- GPLUGIN_PLUGIN_INFO(info)));
- gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
- box = priv->pref_frame_cb();
- gnt_box_add_widget(GNT_BOX(window), box);
- box = gnt_hbox_new(FALSE);
- gnt_box_add_widget(GNT_BOX(window), box);
- button = gnt_button_new(_("Close"));
- gnt_box_add_widget(GNT_BOX(box), button);
- g_signal_connect_swapped(G_OBJECT(button), "activate",
- G_CALLBACK(gnt_widget_destroy), window);
- g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(remove_confwin), plugin);
- gnt_widget_show(window);
- ui_data->type = FINCH_PLUGIN_UI_DATA_TYPE_WINDOW;
- ui_data->u.window = window;
- purple_notify_info(plugin, _("Error"), _("No configuration "
- "options for this plugin."), NULL, NULL);
- g_object_set_data(G_OBJECT(info), "finch-ui-data", NULL);
-void finch_plugins_show_all(void)
- GntWidget *window, *tree, *box, *aboot, *button;
- GList *plugin_list, *iter;
- gnt_window_present(plugins.window);
- purple_plugins_refresh();
- plugins.window = window = gnt_vbox_new(FALSE);
- gnt_box_set_toplevel(GNT_BOX(window), TRUE);
- gnt_box_set_title(GNT_BOX(window), _("Plugins"));
- gnt_box_set_pad(GNT_BOX(window), 0);
- gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
- gnt_box_add_widget(GNT_BOX(window),
- gnt_label_new(_("You can (un)load plugins from the following list.")));
- gnt_box_add_widget(GNT_BOX(window), gnt_hline_new());
- box = gnt_hbox_new(FALSE);
- gnt_box_add_widget(GNT_BOX(window), box);
- gnt_box_add_widget(GNT_BOX(window), gnt_hline_new());
- gnt_box_set_pad(GNT_BOX(box), 0);
- plugins.tree = tree = gnt_tree_new();
- gnt_tree_set_compare_func(GNT_TREE(tree), (GCompareFunc)plugin_compare);
- gnt_widget_set_has_border(tree, FALSE);
- gnt_box_add_widget(GNT_BOX(box), tree);
- gnt_box_add_widget(GNT_BOX(box), gnt_vline_new());
- plugins.aboot = aboot = gnt_text_view_new();
- gnt_text_view_set_flag(GNT_TEXT_VIEW(aboot), GNT_TEXT_VIEW_TOP_ALIGN);
- gnt_widget_set_size(aboot, 40, 20);
- gnt_box_add_widget(GNT_BOX(box), aboot);
- seen = purple_prefs_get_path_list("/finch/plugins/seen");
- plugin_list = purple_plugins_find_all();
- for (iter = plugin_list; iter; iter = iter->next)
- PurplePlugin *plug = PURPLE_PLUGIN(iter->data);
- if (purple_plugin_is_internal(plug))
- gplugin_plugin_info_get_name(
- purple_plugin_get_info(plug)))),
- gnt_tree_set_choice(GNT_TREE(tree), plug, purple_plugin_is_loaded(plug));
- if (!g_list_find_custom(seen, gplugin_plugin_get_filename(plug),
- (GCompareFunc)strcmp)) {
- gnt_tree_set_row_flags(GNT_TREE(tree), plug, GNT_TEXT_FLAG_BOLD);
- g_list_free(plugin_list);
- gnt_tree_set_col_width(GNT_TREE(tree), 0, 30);
- g_signal_connect(G_OBJECT(tree), "toggled", G_CALLBACK(plugin_toggled_cb), NULL);
- g_signal_connect(G_OBJECT(tree), "selection_changed", G_CALLBACK(selection_changed), NULL);
- g_object_set_data(G_OBJECT(tree), "seen-list", seen);
- box = gnt_hbox_new(FALSE);
- gnt_box_add_widget(GNT_BOX(window), box);
- button = gnt_button_new(_("Close"));
- gnt_box_add_widget(GNT_BOX(box), button);
- g_signal_connect_swapped(G_OBJECT(button), "activate",
- G_CALLBACK(gnt_widget_destroy), window);
- plugins.conf = button = gnt_button_new(_("Configure Plugin"));
- gnt_box_add_widget(GNT_BOX(box), button);
- g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(configure_plugin_cb), NULL);
- g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(reset_plugin_window), NULL);
- gnt_widget_show(window);
- decide_conf_button(gnt_tree_get_selection_data(GNT_TREE(tree)));
-free_stringlist(GList *list) {
- g_list_free_full(list, g_free);
-process_pref_frame(PurplePluginPrefFrame *frame)
- PurpleRequestField *field;
- PurpleRequestPage *page;
- PurpleRequestGroup *group = NULL;
- GList *stringlist = NULL;
- page = purple_request_page_new();
- for (prefs = purple_plugin_pref_frame_get_prefs(frame); prefs; prefs = prefs->next) {
- PurplePluginPref *pref = prefs->data;
- const char *name = purple_plugin_pref_get_name(pref);
- const char *label = purple_plugin_pref_get_label(pref);
- if(purple_plugin_pref_get_pref_type(pref) == PURPLE_PLUGIN_PREF_INFO) {
- field = purple_request_field_label_new("*", purple_plugin_pref_get_label(pref));
- purple_request_group_add_field(group, field);
- group = purple_request_group_new(label);
- purple_request_page_add_group(page, group);
- type = purple_prefs_get_pref_type(name);
- if(purple_plugin_pref_get_pref_type(pref) == PURPLE_PLUGIN_PREF_CHOICE) {
- gpointer current_value = NULL;
- case PURPLE_PREF_BOOLEAN:
- current_value = g_strdup_printf("%d", (int)purple_prefs_get_bool(name));
- current_value = g_strdup_printf("%d", (int)purple_prefs_get_int(name));
- case PURPLE_PREF_STRING:
- current_value = g_strdup(purple_prefs_get_string(name));
- field = purple_request_field_list_new(name, label);
- purple_request_field_list_set_multi_select(PURPLE_REQUEST_FIELD_LIST(field),
- for (GList *list = purple_plugin_pref_get_choices(pref); list != NULL; list = list->next) {
- const PurpleKeyValuePair *choice = list->data;
- case PURPLE_PREF_BOOLEAN:
- value = g_strdup_printf("%d", GPOINTER_TO_INT(choice->value));
- value = g_strdup_printf("%d", GPOINTER_TO_INT(choice->value));
- case PURPLE_PREF_STRING:
- value = g_strdup(choice->value);
- stringlist = g_list_prepend(stringlist, value);
- purple_request_field_list_add_icon(PURPLE_REQUEST_FIELD_LIST(field),
- choice->key, NULL, value);
- if(purple_strequal(value, current_value)) {
- purple_request_field_list_add_selected(PURPLE_REQUEST_FIELD_LIST(field),
- case PURPLE_PREF_BOOLEAN:
- field = purple_request_field_bool_new(name, label, purple_prefs_get_bool(name));
- field = purple_request_field_int_new(name, label, purple_prefs_get_int(name), INT_MIN, INT_MAX);
- case PURPLE_PREF_STRING:
- field = purple_request_field_string_new(name, label, purple_prefs_get_string(name),
- purple_plugin_pref_get_format_type(pref) & PURPLE_STRING_FORMAT_TYPE_MULTILINE);
- group = purple_request_group_new(_("Preferences"));
- purple_request_page_add_group(page, group);
- purple_request_group_add_field(group, field);
- ret = purple_request_fields(NULL, _("Preferences"), NULL, NULL, page,
- _("Save"), G_CALLBACK(finch_request_save_in_prefs), _("Cancel"), NULL,
- g_signal_connect_swapped(G_OBJECT(ret), "destroy", G_CALLBACK(free_stringlist), stringlist);
--- a/finch/gntplugin.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-#define FINCH_TYPE_PLUGIN_INFO (finch_plugin_info_get_type())
-#define FINCH_PLUGIN_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), FINCH_TYPE_PLUGIN_INFO, FinchPluginInfo))
-#define FINCH_PLUGIN_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), FINCH_TYPE_PLUGIN_INFO, FinchPluginInfoClass))
-#define FINCH_IS_PLUGIN_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), FINCH_TYPE_PLUGIN_INFO))
-#define FINCH_IS_PLUGIN_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), FINCH_TYPE_PLUGIN_INFO))
-#define FINCH_PLUGIN_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), FINCH_TYPE_PLUGIN_INFO, FinchPluginInfoClass))
-typedef struct _FinchPluginInfo FinchPluginInfo;
-typedef struct _FinchPluginInfoClass FinchPluginInfoClass;
-typedef GntWidget* (*FinchPluginPrefFrameCb) (void);
- * Extends #PurplePluginInfo to hold UI information for finch.
-struct _FinchPluginInfo {
- PurplePluginInfo parent;
- * FinchPluginInfoClass:
- * The base class for all #FinchPluginInfo's.
-struct _FinchPluginInfoClass {
- PurplePluginInfoClass parent_class;
- void (*_gnt_reserved1)(void);
- void (*_gnt_reserved2)(void);
- void (*_gnt_reserved3)(void);
- void (*_gnt_reserved4)(void);
-/**********************************************************************
- **********************************************************************/
-GType finch_plugin_info_get_type(void);
- * finch_plugin_info_new:
- * @first_property: The first property name
- * @...: The value of the first property, followed optionally by more
- * name/value pairs, followed by %NULL
- * Creates a new #FinchPluginInfo instance to be returned from
- * #plugin_query of a finch plugin, using the provided name/value
- * See purple_plugin_info_new() for a list of available property names.
- * Additionally, you can provide the property
- * <literal>"gnt-pref-frame-cb"</literal>, which should be a callback that
- * returns a #GntWidget for the plugin's preferences
- * (see #FinchPluginPrefFrameCb).
- * See purple_plugin_info_new().
- * Returns: A new #FinchPluginInfo instance.
-GPluginPluginInfo *finch_plugin_info_new(const char *first_property, ...) G_GNUC_NULL_TERMINATED;
-/**********************************************************************
- **********************************************************************/
- * finch_plugins_show_all:
- * Show a list of plugins.
-void finch_plugins_show_all(void);
- * finch_plugins_save_loaded:
- * Save the list of loaded plugins.
-void finch_plugins_save_loaded(void);
-#endif /* FINCH_PLUGIN_H */
--- a/finch/gntprefs.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,328 +0,0 @@
- * Finch 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>
- GList *list_data; /* Data to be freed when the pref-window is closed */
- purple_prefs_add_none("/finch");
- purple_prefs_add_none("/finch/plugins");
- purple_prefs_add_path_list("/finch/plugins/loaded", NULL);
- purple_prefs_add_path_list("/finch/plugins/seen", NULL);
- purple_prefs_add_none("/finch/conversations");
- purple_prefs_add_bool("/finch/conversations/timestamps", TRUE);
- purple_prefs_add_bool("/finch/conversations/notify_typing", FALSE);
- purple_prefs_add_none("/finch/filelocations");
- purple_prefs_add_path("/finch/filelocations/last_save_folder", "");
- purple_prefs_add_path("/finch/filelocations/last_save_folder", "");
-finch_prefs_update_old(void)
- GList *(*choices)(void); /* If the value is to be selected from a number of choices */
-get_idle_options(void) {
- PurpleKeyValuePair *pair = NULL;
- pair = purple_key_value_pair_new(_("Based on keyboard use"), "system");
- list = g_list_append(list, pair);
- pair = purple_key_value_pair_new(_("From last sent message"), "purple");
- list = g_list_append(list, pair);
- pair = purple_key_value_pair_new(_("Never"), "never");
- list = g_list_append(list, pair);
-get_status_titles(void) {
- for(GList *iter = purple_savedstatuses_get_all(); iter; iter = iter->next) {
- PurpleKeyValuePair *pair = NULL;
- const char *title = NULL;
- if(purple_savedstatus_is_transient(iter->data)) {
- str = g_strdup_printf("%ld", purple_savedstatus_get_creation_time(iter->data));
- title = purple_savedstatus_get_title(iter->data);
- pair = purple_key_value_pair_new_full(title, str, g_free);
- list = g_list_append(list, pair);
-get_credential_provider_options_helper(PurpleCredentialProvider *provider,
- PurpleKeyValuePair *pair = NULL;
- name = purple_credential_provider_get_name(provider);
- id = purple_credential_provider_get_id(provider);
- pair = purple_key_value_pair_new(name, (gpointer)id);
- *list = g_list_append(*list, pair);
-get_credential_provider_options(void) {
- PurpleCredentialManager *manager = NULL;
- manager = purple_credential_manager_get_default();
- purple_credential_manager_foreach(manager,
- get_credential_provider_options_helper,
-static PurpleRequestField *
-get_pref_field(Prefs *prefs) {
- PurpleRequestField *field = NULL;
- if(prefs->choices == NULL) {
- case PURPLE_PREF_BOOLEAN:
- field = purple_request_field_bool_new(prefs->pref,
- purple_prefs_get_bool(prefs->pref));
- field = purple_request_field_int_new(prefs->pref,
- purple_prefs_get_int(prefs->pref),
- case PURPLE_PREF_STRING:
- field = purple_request_field_string_new(prefs->pref,
- purple_prefs_get_string(prefs->pref),
- PurpleRequestFieldChoice *choice = NULL;
- list = prefs->choices();
- field = purple_request_field_choice_new(prefs->pref,
- _(prefs->label), NULL);
- choice = PURPLE_REQUEST_FIELD_CHOICE(field);
- for(GList *iter = list; iter; iter = iter->next) {
- PurpleKeyValuePair *pair = iter->data;
- gboolean select = FALSE;
- case PURPLE_PREF_BOOLEAN:
- if(sscanf(pair->value, "%d", &idata) != 1) {
- if(purple_prefs_get_bool(prefs->pref) == idata) {
- if(sscanf(pair->value, "%d", &idata) != 1) {
- if(purple_prefs_get_int(prefs->pref) == idata) {
- case PURPLE_PREF_STRING:
- if(purple_strequal(purple_prefs_get_string(prefs->pref),
- purple_request_field_choice_add(choice, pair->key, pair->value);
- purple_request_field_choice_set_default_value(choice,
- purple_request_field_choice_set_value(choice, pair->value);
- pref_request.list_data = g_list_concat(pref_request.list_data, list);
-static Prefs blist[] = {
- .type = PURPLE_PREF_BOOLEAN,
- .pref = "/finch/blist/idletime",
- .label = N_("Show Idle Time"),
- .type = PURPLE_PREF_BOOLEAN,
- .pref = "/finch/blist/showoffline",
- .label = N_("Show Offline Buddies"),
-static Prefs convs[] = {
- .type = PURPLE_PREF_BOOLEAN,
- .pref = "/finch/conversations/timestamps",
- .label = N_("Show Timestamps"),
- .type = PURPLE_PREF_BOOLEAN,
- .pref = "/finch/conversations/notify_typing",
- .label = N_("Notify buddies when you are typing"),
- .type = PURPLE_PREF_STRING,
- .pref = "/purple/away/idle_reporting",
- .label = N_("Report Idle time"),
- .choices = get_idle_options,
- .type = PURPLE_PREF_BOOLEAN,
- .pref = "/purple/away/away_when_idle",
- .label = N_("Change status when idle"),
- .type = PURPLE_PREF_INT,
- .pref = "/purple/away/mins_before_away",
- .label = N_("Minutes before changing status"),
- .type = PURPLE_PREF_INT,
- .pref = "/purple/savedstatus/idleaway",
- .label = N_("Change status to"),
- .choices = get_status_titles,
-static Prefs credentials[] = {
- .type = PURPLE_PREF_STRING,
- .pref = "/purple/credentials/active-provider",
- .label = N_("Provider"),
- .choices = get_credential_provider_options,
- g_clear_list(&pref_request.list_data,
- (GDestroyNotify)purple_key_value_pair_free);
- pref_request.showing = FALSE;
-save_cb(void *data, PurpleRequestPage *page) {
- finch_request_save_in_prefs(data, page);
-add_pref_group(PurpleRequestPage *page, const char *title, Prefs *prefs,
- PurpleRequestGroup *group = NULL;
- group = purple_request_group_new(title);
- purple_request_page_add_group(page, group);
- for(guint i = 0; i < n_prefs; i++) {
- PurpleRequestField *field = get_pref_field(&prefs[i]);
- if(PURPLE_IS_REQUEST_FIELD(field)) {
- purple_request_group_add_field(group, field);
-finch_prefs_show_all(void)
- PurpleRequestPage *page;
- if (pref_request.showing) {
- gnt_window_present(pref_request.window);
- page = purple_request_page_new();
- add_pref_group(page, _("Buddy List"), blist, G_N_ELEMENTS(blist));
- add_pref_group(page, _("Conversations"), convs, G_N_ELEMENTS(convs));
- add_pref_group(page, _("Idle"), idle, G_N_ELEMENTS(idle));
- add_pref_group(page, _("Credentials"), credentials,
- G_N_ELEMENTS(credentials));
- pref_request.showing = TRUE;
- pref_request.window = purple_request_fields(NULL, _("Preferences"), NULL, NULL, page,
- _("Save"), G_CALLBACK(save_cb), _("Cancel"), free_strings,
--- a/finch/gntprefs.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-/**********************************************************************
- **********************************************************************/
- * Perform necessary initializations.
-void finch_prefs_init(void);
- * finch_prefs_show_all:
- * Show the preferences dialog.
-void finch_prefs_show_all(void);
- * finch_prefs_update_old:
- * You don't need to know about this.
-void finch_prefs_update_old(void);
-#endif /* FINCH_PREFS_H */
--- a/finch/gntrequest.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,979 +0,0 @@
- * Finch 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>
-setup_request_window(const char *title, const char *primary,
- const char *secondary, PurpleRequestType type)
- window = gnt_vbox_new(FALSE);
- gnt_box_set_toplevel(GNT_BOX(window), TRUE);
- gnt_box_set_title(GNT_BOX(window), title);
- gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
- gnt_box_add_widget(GNT_BOX(window),
- gnt_label_new_with_format(primary, GNT_TEXT_FLAG_BOLD));
- gnt_box_add_widget(GNT_BOX(window), gnt_label_new(secondary));
- g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(purple_request_close),
- GINT_TO_POINTER(type));
- * If the window is closed by the wm (ie, without triggering any of
- * the buttons, then do some default callback.
-setup_default_callback(GntWidget *window, gpointer default_cb, gpointer data)
- if (default_cb == NULL)
- g_object_set_data(G_OBJECT(window), "default-callback", default_cb);
- g_signal_connect_swapped(G_OBJECT(window), "destroy", G_CALLBACK(default_cb), data);
-action_performed(G_GNUC_UNUSED GntWidget *button, gpointer data)
- g_signal_handlers_disconnect_matched(data, G_SIGNAL_MATCH_FUNC,
- g_object_get_data(data, "default-callback"),
- * @win: this is the window
- * @userdata: the userdata to pass to the primary callbacks
- * @data: data for the callback
- * @...: (text, primary-callback) pairs, ended by a NULL
- * The cancellation callback should be the last callback sent.
-setup_button_box(GntWidget *win, gpointer userdata, gpointer cb, gpointer data, ...)
- GntWidget *button = NULL;
- box = gnt_hbox_new(FALSE);
- while ((text = va_arg(list, const char *)))
- callback = va_arg(list, gpointer);
- button = gnt_button_new(text);
- gnt_box_add_widget(GNT_BOX(box), button);
- g_object_set_data(G_OBJECT(button), "activate-callback", callback);
- g_object_set_data(G_OBJECT(button), "activate-userdata", userdata);
- g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(action_performed), win);
- g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(cb), data);
- g_object_set_data(G_OBJECT(button), "cancellation-function", GINT_TO_POINTER(TRUE));
-notify_input_cb(GntWidget *button, GntWidget *entry)
- PurpleRequestInputCb callback = g_object_get_data(G_OBJECT(button), "activate-callback");
- gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata");
- const char *text = gnt_entry_get_text(GNT_ENTRY(entry));
- window = gnt_widget_get_toplevel(button);
- purple_request_close(PURPLE_REQUEST_INPUT, window);
-finch_request_input(const char *title, const char *primary,
- const char *secondary, const char *default_value,
- G_GNUC_UNUSED gboolean multiline, gboolean masked,
- G_GNUC_UNUSED gchar *hint, const char *ok_text,
- GCallback ok_cb, const char *cancel_text,
- G_GNUC_UNUSED PurpleRequestCommonParameters *cpar,
- GntWidget *window, *box, *entry;
- window = setup_request_window(title, primary, secondary, PURPLE_REQUEST_INPUT);
- entry = gnt_entry_new(default_value);
- gnt_entry_set_masked(GNT_ENTRY(entry), TRUE);
- gnt_box_add_widget(GNT_BOX(window), entry);
- box = setup_button_box(window, user_data, notify_input_cb, entry,
- ok_text, ok_cb, cancel_text, cancel_cb, NULL);
- gnt_box_add_widget(GNT_BOX(window), box);
- setup_default_callback(window, cancel_cb, user_data);
- gnt_widget_show(window);
-finch_close_request(G_GNUC_UNUSED PurpleRequestType type, gpointer ui_handle) {
- GntWidget *widget = GNT_WIDGET(ui_handle);
- widget = gnt_widget_get_toplevel(widget);
- gnt_widget_destroy(widget);
-request_choice_cb(GntWidget *button, GntComboBox *combo)
- PurpleRequestChoiceCb callback = g_object_get_data(G_OBJECT(button), "activate-callback");
- gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata");
- gpointer choice = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo));
- callback(data, choice);
- window = gnt_widget_get_toplevel(button);
- purple_request_close(PURPLE_REQUEST_INPUT, window);
-finch_request_choice(const char *title, const char *primary,
- const char *secondary, gpointer default_value,
- const char *ok_text, GCallback ok_cb,
- const char *cancel_text, GCallback cancel_cb,
- G_GNUC_UNUSED PurpleRequestCommonParameters *cpar,
- void *user_data, va_list choices)
- GntWidget *window, *combo, *box;
- window = setup_request_window(title, primary, secondary, PURPLE_REQUEST_CHOICE);
- combo = gnt_combo_box_new();
- gnt_box_add_widget(GNT_BOX(window), combo);
- while ((text = va_arg(choices, const char *)))
- val = va_arg(choices, int);
- gnt_combo_box_add_data(GNT_COMBO_BOX(combo), GINT_TO_POINTER(val + 1), text);
- gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), default_value);
- box = setup_button_box(window, user_data, request_choice_cb, combo,
- ok_text, ok_cb, cancel_text, cancel_cb, NULL);
- gnt_box_add_widget(GNT_BOX(window), box);
- setup_default_callback(window, cancel_cb, user_data);
- gnt_widget_show(window);
-request_action_cb(GntWidget *button, GntWidget *window)
- PurpleRequestActionCb callback = g_object_get_data(G_OBJECT(button), "activate-callback");
- gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata");
- int id = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "activate-id"));
- purple_request_close(PURPLE_REQUEST_ACTION, window);
-finch_request_action(const char *title, const char *primary,
- const char *secondary, int default_value,
- G_GNUC_UNUSED PurpleRequestCommonParameters *cpar,
- void *user_data, size_t actioncount, va_list actions)
- GntWidget *window, *box, *button, *focus = NULL;
- window = setup_request_window(title, primary, secondary, PURPLE_REQUEST_ACTION);
- box = gnt_hbox_new(FALSE);
- gnt_box_add_widget(GNT_BOX(window), box);
- for (i = 0; i < actioncount; i++)
- const char *text = va_arg(actions, const char *);
- PurpleRequestActionCb callback = va_arg(actions, PurpleRequestActionCb);
- button = gnt_button_new(text);
- gnt_box_add_widget(GNT_BOX(box), button);
- g_object_set_data(G_OBJECT(button), "activate-callback", callback);
- g_object_set_data(G_OBJECT(button), "activate-userdata", user_data);
- g_object_set_data(G_OBJECT(button), "activate-id", GINT_TO_POINTER(i));
- g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(request_action_cb), window);
- if (default_value >= 0 && i == (gsize)default_value)
- gnt_widget_show(window);
- gnt_box_give_focus_to_child(GNT_BOX(window), focus);
-request_fields_cb(GntWidget *button, PurpleRequestPage *page) {
- PurpleRequestFieldsCb callback = g_object_get_data(G_OBJECT(button), "activate-callback");
- gpointer data = g_object_get_data(G_OBJECT(button), "activate-userdata");
- /* Update the data of the fields. Pidgin does this differently. Instead of
- * updating the fields at the end like here, it updates the appropriate field
- * instantly whenever a change is made. That allows it to make sure the
- * 'required' fields are entered before the user can hit OK. It's not the case
- * here, although it can be done. */
- n_groups = g_list_model_get_n_items(G_LIST_MODEL(page));
- for(guint group_index = 0; group_index < n_groups; group_index++) {
- GListModel *group = NULL;
- group = g_list_model_get_item(G_LIST_MODEL(page), group_index);
- n_fields = g_list_model_get_n_items(group);
- for(guint field_index = 0; field_index < n_fields; field_index++) {
- PurpleRequestField *field = NULL;
- field = g_list_model_get_item(group, field_index);
- if(!purple_request_field_is_visible(field)) {
- if(PURPLE_IS_REQUEST_FIELD_BOOL(field)) {
- GntWidget *check = g_object_get_data(G_OBJECT(field),
- gboolean value = gnt_check_box_get_checked(GNT_CHECK_BOX(check));
- purple_request_field_bool_set_value(PURPLE_REQUEST_FIELD_BOOL(field),
- } else if(PURPLE_IS_REQUEST_FIELD_STRING(field)) {
- GntWidget *entry = g_object_get_data(G_OBJECT(field),
- const char *text = gnt_entry_get_text(GNT_ENTRY(entry));
- if(purple_strempty(text)) {
- purple_request_field_string_set_value(PURPLE_REQUEST_FIELD_STRING(field),
- } else if(PURPLE_IS_REQUEST_FIELD_INT(field)) {
- GntWidget *entry = g_object_get_data(G_OBJECT(field),
- const char *text = gnt_entry_get_text(GNT_ENTRY(entry));
- int value = (text && *text) ? atoi(text) : 0;
- purple_request_field_int_set_value(PURPLE_REQUEST_FIELD_INT(field),
- } else if(PURPLE_IS_REQUEST_FIELD_CHOICE(field)) {
- GntWidget *combo = g_object_get_data(G_OBJECT(field),
- gpointer value = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo));
- purple_request_field_choice_set_value(PURPLE_REQUEST_FIELD_CHOICE(field),
- } else if(PURPLE_IS_REQUEST_FIELD_LIST(field)) {
- PurpleRequestFieldList *lfield = PURPLE_REQUEST_FIELD_LIST(field);
- GList *selected = NULL;
- GList *list = purple_request_field_list_get_items(lfield);
- if(purple_request_field_list_get_multi_select(lfield)) {
- GntWidget *tree = g_object_get_data(G_OBJECT(field),
- for (; list; list = list->next)
- PurpleKeyValuePair *item = list->data;
- const char *text = item->key;
- key = purple_request_field_list_get_data(lfield, text);
- if (gnt_tree_get_choice(GNT_TREE(tree), key)) {
- selected = g_list_prepend(selected, (gpointer)text);
- GntWidget *combo = g_object_get_data(G_OBJECT(field),
- gpointer data = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo));
- for (; list; list = list->next) {
- PurpleKeyValuePair *item = list->data;
- const char *text = item->key;
- key = purple_request_field_list_get_data(lfield, text);
- selected = g_list_prepend(selected, (gpointer)text);
- purple_request_field_list_set_selected(lfield, selected);
- } else if (PURPLE_IS_REQUEST_FIELD_ACCOUNT(field)) {
- GntWidget *combo = NULL;
- PurpleAccount *acc = NULL;
- PurpleRequestFieldAccount *afield = NULL;
- combo = g_object_get_data(G_OBJECT(field), "finch-ui-data");
- acc = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(combo));
- afield = PURPLE_REQUEST_FIELD_ACCOUNT(field);
- purple_request_field_account_set_value(afield, acc);
- purple_notify_close_with_handle(button);
- if(!g_object_get_data(G_OBJECT(button), "cancellation-function") &&
- !purple_request_page_is_valid(page))
- purple_notify_error(button, _("Error"),
- _("You must properly fill all the required fields."),
- _("The required fields are underlined."), NULL);
- window = gnt_widget_get_toplevel(button);
- purple_request_close(PURPLE_REQUEST_FIELDS, window);
-update_selected_account(GntEntry *username, G_GNUC_UNUSED const char *start,
- G_GNUC_UNUSED const char *end,
- GntComboBox *accountlist)
- gnt_tree_get_rows(GNT_TREE(gnt_combo_box_get_dropdown(accountlist)));
- const char *name = gnt_entry_get_text(username);
- if (purple_blist_find_buddy(accounts->data, name)) {
- gnt_combo_box_set_selected(accountlist, accounts->data);
- gnt_widget_draw(GNT_WIDGET(accountlist));
- accounts = accounts->next;
-create_boolean_field(PurpleRequestField *field)
- PurpleRequestFieldBool *boolfield = PURPLE_REQUEST_FIELD_BOOL(field);
- const char *label = purple_request_field_get_label(field);
- GntWidget *check = gnt_check_box_new(label);
- gnt_check_box_set_checked(GNT_CHECK_BOX(check),
- purple_request_field_bool_get_default_value(boolfield));
-create_string_field(PurpleRequestField *field, GntWidget **username)
- PurpleRequestFieldString *strfield = PURPLE_REQUEST_FIELD_STRING(field);
- const char *hint = purple_request_field_get_type_hint(field);
- GntWidget *entry = gnt_entry_new(
- purple_request_field_string_get_default_value(strfield));
- gnt_entry_set_masked(GNT_ENTRY(entry),
- purple_request_field_string_is_masked(strfield));
- if (hint && g_str_has_prefix(hint, "screenname")) {
- PurpleBlistNode *node = purple_blist_get_default_root();
- gboolean offline = g_str_has_suffix(hint, "all");
- for (; node; node = purple_blist_node_next(node, offline)) {
- if (!PURPLE_IS_BUDDY(node))
- gnt_entry_add_suggest(GNT_ENTRY(entry), purple_buddy_get_name((PurpleBuddy*)node));
- gnt_entry_set_always_suggest(GNT_ENTRY(entry), TRUE);
- } else if (purple_strequal(hint, "group")) {
- for (node = purple_blist_get_default_root(); node;
- node = purple_blist_node_get_sibling_next(node)) {
- if (PURPLE_IS_GROUP(node))
- gnt_entry_add_suggest(GNT_ENTRY(entry), purple_group_get_name((PurpleGroup *)node));
-create_integer_field(PurpleRequestField *field)
- PurpleRequestFieldInt *intfield = PURPLE_REQUEST_FIELD_INT(field);
- int val = purple_request_field_int_get_default_value(intfield);
- g_snprintf(str, sizeof(str), "%d", val);
- entry = gnt_entry_new(str);
- gnt_entry_set_flag(GNT_ENTRY(entry), GNT_ENTRY_FLAG_INT);
-create_choice_field(PurpleRequestField *field)
- PurpleRequestFieldChoice *cfield = PURPLE_REQUEST_FIELD_CHOICE(field);
- GntWidget *combo = gnt_combo_box_new();
- for(GList *it = purple_request_field_choice_get_elements(cfield);
- it != NULL; it = g_list_next(it))
- PurpleKeyValuePair *choice = it->data;
- gnt_combo_box_add_data(GNT_COMBO_BOX(combo), choice->value, choice->key);
- gnt_combo_box_set_selected(GNT_COMBO_BOX(combo),
- purple_request_field_choice_get_default_value(cfield));
-create_list_field(PurpleRequestField *field)
- PurpleRequestFieldList *lfield = PURPLE_REQUEST_FIELD_LIST(field);
- GList *list = purple_request_field_list_get_items(lfield);
- if(purple_request_field_list_get_multi_select(lfield)) {
- GntWidget *tree = gnt_tree_new();
- for (; list; list = list->next)
- PurpleKeyValuePair *item = list->data;
- const char *text = item->key;
- gpointer key = purple_request_field_list_get_data(lfield, text);
- gnt_tree_add_choice(GNT_TREE(tree), key,
- gnt_tree_create_row(GNT_TREE(tree), text), NULL, NULL);
- if(purple_request_field_list_is_selected(lfield, text)) {
- gnt_tree_set_choice(GNT_TREE(tree), key, TRUE);
- GntWidget *combo = gnt_combo_box_new();
- for (; list; list = list->next)
- PurpleKeyValuePair *item = list->data;
- const char *text = item->key;
- gpointer key = purple_request_field_list_get_data(lfield, text);
- gnt_combo_box_add_data(GNT_COMBO_BOX(combo), key, text);
- if(purple_request_field_list_is_selected(lfield, text)) {
- gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), key);
-add_account_to_combo(GntWidget *combo, PurpleAccount *account) {
- PurpleContactInfo *info = PURPLE_CONTACT_INFO(account);
- text = g_strdup_printf("%s (%s)",
- purple_contact_info_get_username(info),
- purple_account_get_protocol_name(account));
- gnt_combo_box_add_data(GNT_COMBO_BOX(combo), account, text);
-create_account_field(PurpleRequestField *field)
- PurpleRequestFieldAccount *afield = PURPLE_REQUEST_FIELD_ACCOUNT(field);
- GntWidget *combo = gnt_combo_box_new();
- all = purple_request_field_account_get_show_all(afield);
- def = purple_request_field_account_get_value(afield);
- if(!PURPLE_IS_ACCOUNT(def)) {
- def = purple_request_field_account_get_default_value(afield);
- GListModel *manager_model = NULL;
- manager_model = purple_account_manager_get_default_as_model();
- n_items = g_list_model_get_n_items(manager_model);
- for(guint index = 0; index < n_items; index++) {
- PurpleAccount *account;
- account = g_list_model_get_item(manager_model, index);
- add_account_to_combo(combo, account);
- gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), account);
- g_object_unref(account);
- GList *list = purple_connections_get_all();
- for(; list; list = list->next) {
- PurpleAccount *account = NULL;
- account = purple_connection_get_account(list->data);
- add_account_to_combo(combo, account);
- gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), account);
- gnt_widget_set_size(combo, 20, 3); /* ew */
-multifield_extra_cb(GntWidget *button, PurpleRequestPage *page) {
- PurpleRequestFieldsCb cb;
- handle = g_object_get_data(G_OBJECT(button), "ui-handle");
- cb = g_object_get_data(G_OBJECT(button), "extra-cb");
- cb_data = g_object_get_data(G_OBJECT(button), "extra-cb-data");
- action_performed(button, handle);
- purple_request_close(PURPLE_REQUEST_FIELDS, handle);
-finch_request_fields(const char *title, const char *primary,
- const char *secondary, PurpleRequestPage *page,
- const char *ok, GCallback ok_cb,
- const char *cancel, GCallback cancel_cb,
- PurpleRequestCommonParameters *cpar,
- GntWidget *window, *box;
- GntWidget *username = NULL, *accountlist = NULL;
- PurpleRequestHelpCb help_cb;
- window = setup_request_window(title, primary, secondary, PURPLE_REQUEST_FIELDS);
- /* This is how it's going to work: the request-groups are going to be
- * stacked vertically one after the other. A GntLine will be separating
- box = gnt_vbox_new(FALSE);
- gnt_box_set_pad(GNT_BOX(box), 0);
- gnt_box_set_fill(GNT_BOX(box), TRUE);
- n_groups = g_list_model_get_n_items(G_LIST_MODEL(page));
- for(guint group_index = 0; group_index < n_groups; group_index++) {
- PurpleRequestGroup *group = NULL;
- const char *title = NULL;
- group = g_list_model_get_item(G_LIST_MODEL(page), group_index);
- title = purple_request_group_get_title(group);
- gnt_box_add_widget(GNT_BOX(box),
- gnt_label_new_with_format(title, GNT_TEXT_FLAG_BOLD));
- n_fields = g_list_model_get_n_items(G_LIST_MODEL(group));
- for(guint field_index = 0; field_index < n_fields; field_index++) {
- PurpleRequestField *field = NULL;
- const char *label = NULL;
- GntWidget *widget = NULL;
- field = g_list_model_get_item(G_LIST_MODEL(group), field_index);
- label = purple_request_field_get_label(field);
- if(!purple_request_field_is_visible(field)) {
- hbox = gnt_hbox_new(TRUE); /* hrm */
- gnt_box_add_widget(GNT_BOX(box), hbox);
- if(!PURPLE_IS_REQUEST_FIELD_BOOL(field) && label) {
- if (purple_request_field_is_required(field))
- l = gnt_label_new_with_format(label, GNT_TEXT_FLAG_UNDERLINE);
- l = gnt_label_new(label);
- gnt_widget_set_size(l, 0, 1);
- gnt_box_add_widget(GNT_BOX(hbox), l);
- if(PURPLE_IS_REQUEST_FIELD_BOOL(field)) {
- widget = create_boolean_field(field);
- } else if(PURPLE_IS_REQUEST_FIELD_STRING(field)) {
- widget = create_string_field(field, &username);
- } else if(PURPLE_IS_REQUEST_FIELD_INT(field)) {
- widget = create_integer_field(field);
- } else if(PURPLE_IS_REQUEST_FIELD_CHOICE(field)) {
- widget = create_choice_field(field);
- } else if(PURPLE_IS_REQUEST_FIELD_LIST(field)) {
- widget = create_list_field(field);
- } else if(PURPLE_IS_REQUEST_FIELD_ACCOUNT(field)) {
- accountlist = create_account_field(field);
- widget = gnt_label_new_with_format(_("Not implemented yet."),
- gnt_box_set_alignment(GNT_BOX(hbox), GNT_ALIGN_MID);
- gnt_box_add_widget(GNT_BOX(hbox), widget);
- g_object_set_data(G_OBJECT(field), "finch-ui-data", widget);
- if(group_index < n_groups - 1) {
- gnt_box_add_widget(GNT_BOX(box), gnt_hline_new());
- gnt_box_add_widget(GNT_BOX(window), box);
- box = setup_button_box(window, userdata, request_fields_cb, page,
- ok, ok_cb, cancel, cancel_cb, NULL);
- extra_actions = purple_request_cpar_get_extra_actions(cpar);
- for (GSList *it = extra_actions; it; it = it->next) {
- PurpleKeyValuePair *extra_action = it->data;
- GntWidget *button = gnt_button_new(extra_action->key);
- gnt_box_add_widget_in_front(GNT_BOX(box), button);
- g_object_set_data(G_OBJECT(button), "ui-handle", window);
- g_object_set_data(G_OBJECT(button), "extra-cb", extra_action->value);
- g_object_set_data(G_OBJECT(button), "extra-cb-data", userdata);
- g_signal_connect(G_OBJECT(button), "activate",
- G_CALLBACK(multifield_extra_cb), page);
- help_cb = purple_request_cpar_get_help_cb(cpar, &help_data);
- GntWidget *button = gnt_button_new(_("Help"));
- gnt_box_add_widget_in_front(GNT_BOX(box), button);
- g_signal_connect_swapped(G_OBJECT(button), "activate",
- G_CALLBACK(help_cb), help_data);
- gnt_box_add_widget(GNT_BOX(window), box);
- setup_default_callback(window, cancel_cb, userdata);
- gnt_widget_show(window);
- if (username && accountlist) {
- g_signal_connect(username, "completion", G_CALLBACK(update_selected_account), accountlist);
- g_object_set_data_full(G_OBJECT(window), "fields", page, g_object_unref);
-file_cancel_cb(G_GNUC_UNUSED GntWidget *wid, gpointer fq)
- FinchFileRequest *data = fq;
- if (data->dialog == NULL) {
- /* We've already handled this request, and are in the destroy handler. */
- if (data->cbs[1] != NULL)
- ((PurpleRequestFileCb)data->cbs[1])(data->user_data, NULL);
- purple_request_close(PURPLE_REQUEST_FILE, data->dialog);
-file_ok_cb(G_GNUC_UNUSED GntWidget *widget, const char *path, const char *file,
- FinchFileRequest *data = fq;
- char *dir = g_path_get_dirname(path);
- if (data->cbs[0] != NULL)
- ((PurpleRequestFileCb)data->cbs[0])(data->user_data, file);
- purple_prefs_set_path(data->save ? "/finch/filelocations/last_save_folder" :
- "/finch/filelocations/last_open_folder", dir);
- purple_request_close(PURPLE_REQUEST_FILE, data->dialog);
-file_request_destroy(FinchFileRequest *data)
-static FinchFileRequest *
-finch_file_request_window(const char *title, const char *path,
- GCallback ok_cb, GCallback cancel_cb,
- GntWidget *window = gnt_file_sel_new();
- GntFileSel *sel = GNT_FILE_SEL(window);
- FinchFileRequest *data = g_new0(FinchFileRequest, 1);
- data->user_data = user_data;
- data->cbs = g_new0(GCallback, 2);
- data->cbs[1] = cancel_cb;
- gnt_box_set_title(GNT_BOX(window), title);
- gnt_file_sel_set_current_location(sel, (path && *path) ? path : g_get_home_dir());
- g_signal_connect(G_OBJECT(sel), "destroy",
- G_CALLBACK(file_cancel_cb), data);
- g_signal_connect(G_OBJECT(sel), "cancelled",
- G_CALLBACK(file_cancel_cb), data);
- g_signal_connect(G_OBJECT(sel), "file_selected",
- G_CALLBACK(file_ok_cb), data);
- g_object_set_data_full(G_OBJECT(window), "filerequestdata", data,
- (GDestroyNotify)file_request_destroy);
-finch_request_file(const char *title, const char *filename, gboolean savedialog,
- GCallback ok_cb, GCallback cancel_cb,
- G_GNUC_UNUSED PurpleRequestCommonParameters *cpar,
- FinchFileRequest *data;
- path = purple_prefs_get_path(savedialog ? "/finch/filelocations/last_save_folder" : "/finch/filelocations/last_open_folder");
- data = finch_file_request_window(title ? title : (savedialog ? _("Save File...") : _("Open File...")), path,
- ok_cb, cancel_cb, user_data);
- data->save = savedialog;
- gnt_file_sel_set_suggested_filename(GNT_FILE_SEL(data->dialog), filename);
- gnt_widget_show(data->dialog);
-finch_request_folder(const char *title, const char *dirname, GCallback ok_cb,
- G_GNUC_UNUSED PurpleRequestCommonParameters *cpar,
- FinchFileRequest *data;
- data = finch_file_request_window(title ? title : _("Choose Location..."), dirname,
- ok_cb, cancel_cb, user_data);
- gnt_file_sel_set_dirs_only(GNT_FILE_SEL(data->dialog), TRUE);
- gnt_widget_show(data->dialog);
-static PurpleRequestUiOps uiops = {
- .request_input = finch_request_input,
- .request_choice = finch_request_choice,
- .request_action = finch_request_action,
- .request_fields = finch_request_fields,
- .request_file = finch_request_file,
- .request_folder = finch_request_folder,
- .close_request = finch_close_request,
-finch_request_get_ui_ops(void)
-finch_request_init(void)
-finch_request_uninit(void)
-finch_request_save_in_prefs(G_GNUC_UNUSED gpointer data,
- PurpleRequestPage *page)
- n_groups = g_list_model_get_n_items(G_LIST_MODEL(page));
- for(guint group_index = 0; group_index < n_groups; group_index++) {
- GListModel *group = NULL;
- group = g_list_model_get_item(G_LIST_MODEL(page), group_index);
- n_fields = g_list_model_get_n_items(group);
- for(guint field_index = 0; field_index < n_fields; field_index++) {
- PurpleRequestField *field = NULL;
- field = g_list_model_get_item(group, field_index);
- id = purple_request_field_get_id(field);
- if(PURPLE_IS_REQUEST_FIELD_CHOICE(field)) {
- PurpleRequestFieldChoice *choice = PURPLE_REQUEST_FIELD_CHOICE(field);
- val = purple_request_field_choice_get_value(choice);
- } else if(PURPLE_IS_REQUEST_FIELD_LIST(field)) {
- PurpleRequestFieldList *lfield = PURPLE_REQUEST_FIELD_LIST(field);
- val = purple_request_field_list_get_selected(lfield)->data;
- val = purple_request_field_list_get_data(lfield, val);
- } else if(PURPLE_IS_REQUEST_FIELD_BOOL(field)) {
- PurpleRequestFieldBool *bfield = PURPLE_REQUEST_FIELD_BOOL(field);
- val = GINT_TO_POINTER(purple_request_field_bool_get_value(bfield));
- } else if(PURPLE_IS_REQUEST_FIELD_INT(field)) {
- PurpleRequestFieldInt *ifield = PURPLE_REQUEST_FIELD_INT(field);
- val = GINT_TO_POINTER(purple_request_field_int_get_value(ifield));
- } else if(PURPLE_IS_REQUEST_FIELD_STRING(field)) {
- PurpleRequestFieldString *sfield = PURPLE_REQUEST_FIELD_STRING(field);
- val = (gpointer)purple_request_field_string_get_value(sfield);
- pt = purple_prefs_get_pref_type(id);
- long int tmp = GPOINTER_TO_INT(val);
- if(PURPLE_IS_REQUEST_FIELD_LIST(field)) {
- /* Lists always return string */
- if (sscanf(val, "%ld", &tmp) != 1)
- purple_prefs_set_int(id, (gint)tmp);
- case PURPLE_PREF_BOOLEAN:
- purple_prefs_set_bool(id, GPOINTER_TO_INT(val));
- case PURPLE_PREF_STRING:
- purple_prefs_set_string(id, val);
-GntWidget *finch_request_field_get_widget(PurpleRequestField *field)
- if(PURPLE_IS_REQUEST_FIELD_BOOL(field)) {
- ret = create_boolean_field(field);
- } else if(PURPLE_IS_REQUEST_FIELD_STRING(field)) {
- ret = create_string_field(field, NULL);
- } else if(PURPLE_IS_REQUEST_FIELD_INT(field)) {
- ret = create_integer_field(field);
- } else if(PURPLE_IS_REQUEST_FIELD_CHOICE(field)) {
- ret = create_choice_field(field);
- } else if(PURPLE_IS_REQUEST_FIELD_ACCOUNT(field)) {
- ret = create_account_field(field);
- } else if(PURPLE_IS_REQUEST_FIELD_LIST(field)) {
- ret = create_list_field(field);
- purple_debug_error("GntRequest", "Unimplemented request-field %s",
- G_OBJECT_TYPE_NAME(field));
--- a/finch/gntrequest.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-/**********************************************************************
- **********************************************************************/
- * finch_request_get_ui_ops:
- * Get the ui-functions.
- * Returns: The PurpleRequestUiOps structure populated with the appropriate functions.
-PurpleRequestUiOps *finch_request_get_ui_ops(void);
- * Perform necessary initializations.
-void finch_request_init(void);
- * finch_request_uninit:
- * Perform necessary uninitializations.
-void finch_request_uninit(void);
- * finch_request_save_in_prefs:
- * @data: No longer used, set to %NULL.
- * @page: The #PurpleRequestPage to save.
- * Save the request fields in preferences where the id attribute of each field is the
-void finch_request_save_in_prefs(gpointer data, PurpleRequestPage *page);
- * finch_request_field_get_widget:
- * @field: The request field.
- * Create a widget field for a request-field.
- * Returns: (transfer full): A GntWidget for the request field.
-GntWidget *finch_request_field_get_widget(PurpleRequestField *field);
-#endif /* FINCH_REQUEST_H */
--- a/finch/gntroomlist.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,349 +0,0 @@
- * Finch 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 "gntroomlist.h"
-#define PREF_ROOT "/finch/roomlist"
-/* Yes, just one roomlist at a time. Let's not get greedy. Aight? */
- PurpleAccount *account;
- PurpleRoomlist *roomlist;
-typedef struct _FinchRoomlist FinchRoomlist;
-unset_roomlist(G_GNUC_UNUSED gpointer data)
- froomlist.window = NULL;
- g_clear_object(&froomlist.roomlist);
- froomlist.account = NULL;
-fl_stop(G_GNUC_UNUSED GntWidget *button, G_GNUC_UNUSED gpointer data) {
- if (froomlist.roomlist &&
- purple_roomlist_get_in_progress(froomlist.roomlist))
- purple_roomlist_cancel_get_list(froomlist.roomlist);
-fl_get_list(G_GNUC_UNUSED GntWidget *button, G_GNUC_UNUSED gpointer data) {
- PurpleAccount *account = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(froomlist.accounts));
- PurpleConnection *gc = purple_account_get_connection(account);
- g_clear_object(&froomlist.roomlist);
- froomlist.roomlist = purple_roomlist_get_list(gc);
- gnt_box_give_focus_to_child(GNT_BOX(froomlist.window), froomlist.tree);
-fl_add_chat(G_GNUC_UNUSED GntWidget *button, G_GNUC_UNUSED gpointer data) {
- PurpleRoomlistRoom *room = gnt_tree_get_selection_data(GNT_TREE(froomlist.tree));
- PurpleConnection *gc = purple_account_get_connection(froomlist.account);
- PurpleProtocol *protocol = NULL;
- if (gc == NULL || room == NULL)
- protocol = purple_connection_get_protocol(gc);
- if (PURPLE_PROTOCOL_IMPLEMENTS(protocol, ROOMLIST, room_serialize)) {
- name = purple_protocol_roomlist_room_serialize(PURPLE_PROTOCOL_ROOMLIST(protocol), room);
- name = g_strdup(purple_roomlist_room_get_name(room));
- purple_blist_request_add_chat(froomlist.account, NULL, NULL, name);
-fl_close(G_GNUC_UNUSED GntWidget *button, G_GNUC_UNUSED gpointer data)
- gnt_widget_destroy(froomlist.window);
-roomlist_activated(GntWidget *widget)
- PurpleRoomlistRoom *room = gnt_tree_get_selection_data(GNT_TREE(widget));
- purple_roomlist_join_room(froomlist.roomlist, room);
-roomlist_selection_changed(G_GNUC_UNUSED GntWidget *widget,
- G_GNUC_UNUSED gpointer old, gpointer current,
- G_GNUC_UNUSED gpointer data)
- PurpleRoomlistRoom *room = current;
- GntTextView *tv = GNT_TEXT_VIEW(froomlist.details);
- gnt_text_view_clear(tv);
- gnt_text_view_append_text_with_flags(tv,
- purple_roomlist_room_get_name(room),
-roomlist_account_changed(G_GNUC_UNUSED GntWidget *widget,
- G_GNUC_UNUSED gpointer old, gpointer current,
- G_GNUC_UNUSED gpointer data)
- if (froomlist.account == current) {
- froomlist.account = current;
- if (froomlist.roomlist) {
- if (purple_roomlist_get_in_progress(froomlist.roomlist))
- purple_roomlist_cancel_get_list(froomlist.roomlist);
- g_clear_object(&froomlist.roomlist);
- gnt_tree_remove_all(GNT_TREE(froomlist.tree));
- gnt_widget_draw(froomlist.tree);
-reset_account_list(G_GNUC_UNUSED PurpleAccount *account)
- GntComboBox *accounts = GNT_COMBO_BOX(froomlist.accounts);
- gnt_combo_box_remove_all(accounts);
- for (list = purple_connections_get_all(); list; list = list->next) {
- PurpleProtocol *protocol = NULL;
- PurpleConnection *gc = list->data;
- protocol = purple_connection_get_protocol(gc);
- if(PURPLE_CONNECTION_IS_CONNECTED(gc) &&
- PURPLE_PROTOCOL_IMPLEMENTS(protocol, ROOMLIST, get_list))
- PurpleAccount *account = purple_connection_get_account(gc);
- PurpleContactInfo *info = PURPLE_CONTACT_INFO(account);
- text = g_strdup_printf("%s (%s)",
- purple_contact_info_get_username(info),
- purple_account_get_protocol_name(account));
- gnt_combo_box_add_data(accounts, account, text);
-size_changed_cb(GntWidget *widget, G_GNUC_UNUSED int oldw,
- G_GNUC_UNUSED int oldh)
- gnt_widget_get_size(widget, &w, &h);
- purple_prefs_set_int(PREF_ROOT "/size/width", w);
- purple_prefs_set_int(PREF_ROOT "/size/height", h);
-setup_roomlist(PurpleAccount *account)
- GntWidget *window, *tree, *hbox, *accounts;
- {_("Stop"), G_CALLBACK(fl_stop), &froomlist.stop},
- {_("Get"), G_CALLBACK(fl_get_list), &froomlist.getlist},
- {_("Add"), G_CALLBACK(fl_add_chat), &froomlist.add},
- {_("Close"), G_CALLBACK(fl_close), &froomlist.close},
- froomlist.window = window = gnt_window_new();
- g_object_set(window, "vertical", TRUE, NULL);
- gnt_box_set_pad(GNT_BOX(window), 0);
- gnt_box_set_title(GNT_BOX(window), _("Room List"));
- gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
- froomlist.accounts = accounts = gnt_combo_box_new();
- reset_account_list(account);
- gnt_box_add_widget(GNT_BOX(window), accounts);
- g_signal_connect(G_OBJECT(accounts), "selection-changed",
- G_CALLBACK(roomlist_account_changed), NULL);
- froomlist.account = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(accounts));
- froomlist.tree = tree = gnt_tree_new_with_columns(2);
- gnt_tree_set_show_title(GNT_TREE(tree), TRUE);
- g_signal_connect(G_OBJECT(tree), "activate", G_CALLBACK(roomlist_activated), NULL);
- gnt_tree_set_column_titles(GNT_TREE(tree), _("Name"), "");
- gnt_tree_set_show_separator(GNT_TREE(tree), FALSE);
- gnt_tree_set_col_width(GNT_TREE(tree), 1, 1);
- gnt_tree_set_column_resizable(GNT_TREE(tree), 1, FALSE);
- gnt_tree_set_search_column(GNT_TREE(tree), 0);
- gnt_box_add_widget(GNT_BOX(window), tree);
- froomlist.details = gnt_text_view_new();
- gnt_text_view_set_flag(GNT_TEXT_VIEW(froomlist.details), GNT_TEXT_VIEW_TOP_ALIGN);
- gnt_box_add_widget(GNT_BOX(window), froomlist.details);
- gnt_widget_set_size(froomlist.details, -1, 8);
- hbox = gnt_hbox_new(FALSE);
- gnt_box_add_widget(GNT_BOX(window), hbox);
- for (iter = 0; buttons[iter].label; iter++) {
- GntWidget *button = gnt_button_new(buttons[iter].label);
- gnt_box_add_widget(GNT_BOX(hbox), button);
- g_signal_connect(G_OBJECT(button), "activate", buttons[iter].callback, NULL);
- *buttons[iter].widget = button;
- gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(froomlist.details), button);
- g_signal_connect(G_OBJECT(tree), "selection-changed", G_CALLBACK(roomlist_selection_changed), NULL);
- g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(unset_roomlist), NULL);
-fl_show_with_account(PurpleAccount *account)
- setup_roomlist(account);
- g_signal_handlers_disconnect_matched(froomlist.window, G_SIGNAL_MATCH_FUNC,
- 0, 0, NULL, size_changed_cb, NULL);
- gnt_widget_show(froomlist.window);
- gnt_screen_resize_widget(froomlist.window,
- purple_prefs_get_int(PREF_ROOT "/size/width"),
- purple_prefs_get_int(PREF_ROOT "/size/height"));
- g_signal_connect(G_OBJECT(froomlist.window), "size_changed", G_CALLBACK(size_changed_cb), NULL);
- gnt_window_present(froomlist.window);
-fl_destroy(G_GNUC_UNUSED gpointer data, GObject *list)
- if (!froomlist.window) {
- if (G_OBJECT(froomlist.roomlist) == list) {
- froomlist.roomlist = NULL;
- gnt_tree_remove_all(GNT_TREE(froomlist.tree));
- gnt_widget_draw(froomlist.tree);
-fl_create(PurpleRoomlist *list)
- g_object_set_data(G_OBJECT(list), "finch-ui", &froomlist);
- g_object_weak_ref(G_OBJECT(list), (GWeakNotify)fl_destroy, NULL);
- g_set_object(&froomlist.roomlist, list);
-fl_set_fields(G_GNUC_UNUSED PurpleRoomlist *list, G_GNUC_UNUSED GList *fields)
-fl_add_room(PurpleRoomlist *roomlist, PurpleRoomlistRoom *room)
- gchar *category = NULL;
- if (froomlist.roomlist != roomlist)
- gnt_tree_remove(GNT_TREE(froomlist.tree), room);
- gnt_tree_add_row_after(GNT_TREE(froomlist.tree), room,
- gnt_tree_create_row(GNT_TREE(froomlist.tree),
- purple_roomlist_room_get_name(room), ""),
- gnt_tree_set_expanded(GNT_TREE(froomlist.tree), room, category == NULL);
-static PurpleRoomlistUiOps ui_ops = {
- .show_with_account = fl_show_with_account,
- .set_fields = fl_set_fields,
- .add_room = fl_add_room,
-PurpleRoomlistUiOps *finch_roomlist_get_ui_ops(void)
-void finch_roomlist_show_all(void)
- purple_roomlist_show_with_account(NULL);
-void finch_roomlist_init(void)
- purple_prefs_add_none(PREF_ROOT);
- purple_prefs_add_none(PREF_ROOT "/size");
- purple_prefs_add_int(PREF_ROOT "/size/width", 60);
- purple_prefs_add_int(PREF_ROOT "/size/height", 15);
-void finch_roomlist_uninit(void)
--- a/finch/gntroomlist.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-#ifndef FINCH_ROOMLIST_H
-#define FINCH_ROOMLIST_H
-/**********************************************************************
- **********************************************************************/
- * Initialize the roomlist subsystem.
-void finch_roomlist_init(void);
- * finch_roomlist_get_ui_ops:
- * Get the ui-functions.
- * Returns: The PurpleRoomlistUiOps structure populated with the appropriate functions.
-PurpleRoomlistUiOps *finch_roomlist_get_ui_ops(void);
- * finch_roomlist_show_all:
- * Show the roomlist dialog.
-void finch_roomlist_show_all(void);
- * finch_roomlist_uninit:
- * Uninitialize the roomlist subsystem.
-void finch_roomlist_uninit(void);
-#endif /* FINCH_ROOMLIST_H */
--- a/finch/gntstatus.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,627 +0,0 @@
- * Finch 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>
- PurpleSavedStatus *saved;
- GHashTable *hash; /* list of windows for substatuses */
- PurpleAccount *account;
- const PurpleStatusType *type;
-static GList *edits; /* List of opened edit-status dialogs */
-reset_status_window(G_GNUC_UNUSED GntWidget *widget,
- G_GNUC_UNUSED gpointer data)
- statuses.window = NULL;
-populate_statuses(GntTree *tree)
- for (list = purple_savedstatuses_get_all(); list; list = list->next)
- PurpleSavedStatus *saved = list->data;
- const char *title, *type, *message;
- if (purple_savedstatus_is_transient(saved))
- title = purple_savedstatus_get_title(saved);
- type = purple_primitive_get_name_from_type(purple_savedstatus_get_primitive_type(saved));
- message = purple_savedstatus_get_message(saved); /* XXX: Strip possible markups */
- gnt_tree_add_row_last(tree, saved,
- gnt_tree_create_row(tree, title, type, message), NULL);
-really_delete_status(PurpleSavedStatus *saved)
- for (iter = edits; iter; iter = iter->next)
- EditStatus *edit = iter->data;
- if (edit->saved == saved)
- gnt_widget_destroy(edit->window);
- gnt_tree_remove(GNT_TREE(statuses.tree), saved);
- purple_savedstatus_delete(purple_savedstatus_get_title(saved));
-ask_before_delete(G_GNUC_UNUSED GntWidget *button,
- G_GNUC_UNUSED gpointer data)
- PurpleSavedStatus *saved;
- g_return_if_fail(statuses.tree != NULL);
- saved = gnt_tree_get_selection_data(GNT_TREE(statuses.tree));
- ask = g_strdup_printf(_("Are you sure you want to delete \"%s\""),
- purple_savedstatus_get_title(saved));
- purple_request_action(saved, _("Delete Status"), ask, NULL, 0,
- _("Delete"), really_delete_status,
-use_savedstatus_cb(G_GNUC_UNUSED GntWidget *widget,
- G_GNUC_UNUSED gpointer data)
- g_return_if_fail(statuses.tree != NULL);
- purple_savedstatus_activate(gnt_tree_get_selection_data(GNT_TREE(statuses.tree)));
-edit_savedstatus_cb(G_GNUC_UNUSED GntWidget *widget,
- G_GNUC_UNUSED gpointer data)
- g_return_if_fail(statuses.tree != NULL);
- finch_savedstatus_edit(gnt_tree_get_selection_data(GNT_TREE(statuses.tree)));
-finch_savedstatus_show_all(void)
- GntWidget *window, *tree, *box, *button;
- int widths[] = {25, 12, 35};
- gnt_window_present(statuses.window);
- statuses.window = window = gnt_vbox_new(FALSE);
- gnt_box_set_toplevel(GNT_BOX(window), TRUE);
- gnt_box_set_title(GNT_BOX(window), _("Saved Statuses"));
- gnt_box_set_fill(GNT_BOX(window), FALSE);
- gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
- gnt_box_set_pad(GNT_BOX(window), 0);
- /* XXX: Add some sorting function to sort alphabetically, perhaps */
- statuses.tree = tree = gnt_tree_new_with_columns(3);
- gnt_tree_set_column_titles(GNT_TREE(tree), _("Title"), _("Type"), _("Message"));
- gnt_tree_set_show_title(GNT_TREE(tree), TRUE);
- gnt_tree_set_column_width_ratio(GNT_TREE(tree), widths);
- gnt_widget_set_size(tree, 72, 0);
- gnt_box_add_widget(GNT_BOX(window), tree);
- populate_statuses(GNT_TREE(tree));
- box = gnt_hbox_new(FALSE);
- gnt_box_add_widget(GNT_BOX(window), box);
- button = gnt_button_new(_("Use"));
- gnt_box_add_widget(GNT_BOX(box), button);
- g_signal_connect(G_OBJECT(button), "activate",
- G_CALLBACK(use_savedstatus_cb), NULL);
- button = gnt_button_new(_("Add"));
- gnt_box_add_widget(GNT_BOX(box), button);
- gnt_util_set_trigger_widget(tree, GNT_KEY_INS, button);
- g_signal_connect_swapped(G_OBJECT(button), "activate",
- G_CALLBACK(finch_savedstatus_edit), NULL);
- button = gnt_button_new(_("Edit"));
- gnt_box_add_widget(GNT_BOX(box), button);
- g_signal_connect(G_OBJECT(button), "activate",
- G_CALLBACK(edit_savedstatus_cb), NULL);
- button = gnt_button_new(_("Delete"));
- gnt_box_add_widget(GNT_BOX(box), button);
- gnt_util_set_trigger_widget(tree, GNT_KEY_DEL, button);
- g_signal_connect(G_OBJECT(button), "activate",
- G_CALLBACK(ask_before_delete), NULL);
- button = gnt_button_new(_("Close"));
- gnt_box_add_widget(GNT_BOX(box), button);
- g_signal_connect_swapped(G_OBJECT(button), "activate",
- G_CALLBACK(gnt_widget_destroy), window);
- g_signal_connect(G_OBJECT(window), "destroy",
- G_CALLBACK(reset_status_window), NULL);
- gnt_widget_show(window);
-destroy_substatus_win(G_GNUC_UNUSED PurpleAccount *account, EditSubStatus *sub,
- G_GNUC_UNUSED gpointer data)
- gnt_widget_destroy(sub->window); /* the "destroy" callback will remove entry from the hashtable */
-free_key(gpointer key, G_GNUC_UNUSED gpointer n)
-update_edit_list(G_GNUC_UNUSED GntWidget *widget, EditStatus *edit)
- edits = g_list_remove(edits, edit);
- purple_notify_close_with_handle(edit);
- g_hash_table_foreach(edit->hash, (GHFunc)destroy_substatus_win, NULL);
- g_list_foreach((GList*)gnt_tree_get_rows(GNT_TREE(edit->tree)), free_key, NULL);
-set_substatuses(EditStatus *edit)
- for (iter = gnt_tree_get_rows(GNT_TREE(edit->tree)); iter; iter = iter->next) {
- RowInfo *key = iter->data;
- if (gnt_tree_get_choice(GNT_TREE(edit->tree), key)) {
- purple_savedstatus_set_substatus(edit->saved, key->account, key->type, key->message);
-use_trans_status_cb(G_GNUC_UNUSED GntWidget *button, EditStatus *edit)
- PurpleStatusPrimitive prim;
- PurpleSavedStatus *saved;
- message = gnt_entry_get_text(GNT_ENTRY(edit->message));
- prim = GPOINTER_TO_INT(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(edit->type)));
- saved = purple_savedstatus_find_transient_by_type_and_message(prim, message);
- saved = purple_savedstatus_new(NULL, prim);
- purple_savedstatus_set_message(saved, message);
- purple_savedstatus_activate(saved);
- gnt_widget_destroy(edit->window);
-save_savedstatus_cb(GntWidget *button, EditStatus *edit)
- const char *title, *message;
- PurpleStatusPrimitive prim;
- PurpleSavedStatus *find;
- title = gnt_entry_get_text(GNT_ENTRY(edit->title));
- message = gnt_entry_get_text(GNT_ENTRY(edit->message));
- if (!message || !*message)
- prim = GPOINTER_TO_INT(gnt_combo_box_get_selected_data(GNT_COMBO_BOX(edit->type)));
- purple_notify_error(edit, _("Error"), _("Invalid title"),
- _("Please enter a non-empty title for the status."), NULL);
- gnt_box_give_focus_to_child(GNT_BOX(edit->window), edit->title);
- find = purple_savedstatus_find(title);
- if (find && find != edit->saved)
- purple_notify_error(edit, _("Error"), _("Duplicate title"),
- _("Please enter a different title for the status."), NULL);
- gnt_box_give_focus_to_child(GNT_BOX(edit->window), edit->title);
- if (edit->saved == NULL)
- edit->saved = purple_savedstatus_new(title, prim);
- purple_savedstatus_set_message(edit->saved, message);
- gnt_tree_add_row_last(GNT_TREE(statuses.tree), edit->saved,
- gnt_tree_create_row(GNT_TREE(statuses.tree), title,
- purple_primitive_get_name_from_type(prim), message), NULL);
- purple_savedstatus_set_title(edit->saved, title);
- purple_savedstatus_set_primitive_type(edit->saved, prim);
- purple_savedstatus_set_message(edit->saved, message);
- gnt_tree_change_text(GNT_TREE(statuses.tree), edit->saved, 0, title);
- gnt_tree_change_text(GNT_TREE(statuses.tree), edit->saved, 1,
- purple_primitive_get_name_from_type(prim));
- gnt_tree_change_text(GNT_TREE(statuses.tree), edit->saved, 2, message);
- if (g_object_get_data(G_OBJECT(button), "use"))
- purple_savedstatus_activate(edit->saved);
- gnt_widget_destroy(edit->window);
-add_substatus(EditStatus *edit, PurpleAccount *account)
- PurpleContactInfo *info = PURPLE_CONTACT_INFO(account);
- PurpleSavedStatusSub *sub = NULL;
- GntTreeRow *row = NULL;
- const char *type = NULL, *message = NULL;
- if(!edit || !edit->tree) {
- sub = purple_savedstatus_get_substatus(edit->saved, account);
- key = g_new0(RowInfo, 1);
- key->account = account;
- key->type = purple_savedstatus_substatus_get_status_type(sub);
- type = purple_status_type_get_name(key->type);
- message = purple_savedstatus_substatus_get_message(sub);
- key->message = g_strdup(message);
- name = g_strdup_printf("%s (%s)",
- purple_contact_info_get_username(info),
- purple_account_get_protocol_name(account));
- row = gnt_tree_create_row(GNT_TREE(edit->tree), name,
- message ? message : "");
- gnt_tree_add_choice(GNT_TREE(edit->tree), key, row, NULL, NULL);
- gnt_tree_set_choice(GNT_TREE(edit->tree), key, TRUE);
-substatus_window_destroy_cb(G_GNUC_UNUSED GntWidget *window, EditSubStatus *sub)
- g_hash_table_remove(sub->parent->hash, sub->key->account);
-save_substatus_cb(G_GNUC_UNUSED GntWidget *widget, EditSubStatus *sub)
- PurpleSavedStatus *saved = sub->parent->saved;
- RowInfo *row = sub->key;
- PurpleStatusType *type;
- type = gnt_combo_box_get_selected_data(GNT_COMBO_BOX(sub->type));
- message = gnt_entry_get_text(GNT_ENTRY(sub->message));
- row->message = g_strdup(message);
- if (saved) /* Save the substatus if the savedstatus actually exists. */
- purple_savedstatus_set_substatus(saved, row->account, type, message);
- gnt_tree_set_choice(GNT_TREE(sub->parent->tree), row, TRUE);
- gnt_tree_change_text(GNT_TREE(sub->parent->tree), row, 1,
- purple_status_type_get_name(type));
- gnt_tree_change_text(GNT_TREE(sub->parent->tree), row, 2, message);
- gnt_widget_destroy(sub->window);
-popup_substatus(GntTree *tree, const char *key, EditStatus *edit)
- if (key[0] == ' ' && key[1] == 0)
- GntWidget *window, *combo, *entry, *box, *button, *l;
- PurpleContactInfo *info = NULL;
- PurpleSavedStatusSub *substatus = NULL;
- RowInfo *selected = gnt_tree_get_selection_data(tree);
- PurpleAccount *account = selected->account;
- if (gnt_tree_get_choice(tree, selected))
- /* There was a savedstatus for this account. Now remove it. */
- g_free(selected->message);
- selected->message = NULL;
- /* XXX: should we really be saving it right now? */
- purple_savedstatus_unset_substatus(edit->saved, account);
- gnt_tree_change_text(tree, account, 1, NULL);
- gnt_tree_change_text(tree, account, 2, NULL);
- if (g_hash_table_lookup(edit->hash, account))
- substatus = purple_savedstatus_get_substatus(edit->saved, account);
- sub = g_new0(EditSubStatus, 1);
- sub->window = window = gnt_vbox_new(FALSE);
- gnt_box_set_toplevel(GNT_BOX(window), TRUE);
- gnt_box_set_title(GNT_BOX(window), _("Substatus")); /* XXX: a better title */
- gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
- box = gnt_hbox_new(FALSE);
- gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Account:")));
- info = PURPLE_CONTACT_INFO(account);
- name = g_strdup_printf("%s (%s)",
- purple_contact_info_get_username(info),
- purple_account_get_protocol_name(account));
- gnt_box_add_widget(GNT_BOX(box), gnt_label_new(name));
- gnt_box_add_widget(GNT_BOX(window), box);
- box = gnt_hbox_new(FALSE);
- gnt_box_add_widget(GNT_BOX(box), (l = gnt_label_new(_("Status:"))));
- gnt_widget_set_size(l, 0, 1); /* I don't like having to do this */
- sub->type = combo = gnt_combo_box_new();
- gnt_box_add_widget(GNT_BOX(box), combo);
- gnt_box_add_widget(GNT_BOX(window), box);
- for (iter = purple_account_get_status_types(account); iter; iter = iter->next)
- PurpleStatusType *type = iter->data;
- if (!purple_status_type_is_user_settable(type))
- gnt_combo_box_add_data(GNT_COMBO_BOX(combo), type, purple_status_type_get_name(type));
- box = gnt_hbox_new(FALSE);
- gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Message:")));
- sub->message = entry = gnt_entry_new(substatus ? purple_savedstatus_substatus_get_message(substatus) : NULL);
- gnt_box_add_widget(GNT_BOX(box), entry);
- gnt_box_add_widget(GNT_BOX(window), box);
- box = gnt_hbox_new(FALSE);
- button = gnt_button_new(_("Cancel"));
- g_signal_connect_swapped(G_OBJECT(button), "activate", G_CALLBACK(gnt_widget_destroy), window);
- gnt_box_add_widget(GNT_BOX(box), button);
- button = gnt_button_new(_("Save"));
- g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(save_substatus_cb), sub);
- gnt_box_add_widget(GNT_BOX(box), button);
- gnt_box_add_widget(GNT_BOX(window), box);
- gnt_widget_show(window);
- g_hash_table_insert(edit->hash, account, sub);
- g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(substatus_window_destroy_cb), sub);
-void finch_savedstatus_edit(PurpleSavedStatus *saved)
- GListModel *manager_model = NULL;
- GntWidget *window, *box, *button, *entry, *combo, *label, *tree;
- PurpleStatusPrimitive prims[] = {PURPLE_STATUS_AVAILABLE, PURPLE_STATUS_AWAY,
- PURPLE_STATUS_INVISIBLE, PURPLE_STATUS_OFFLINE, PURPLE_STATUS_UNSET}, current;
- for (iter = edits; iter; iter = iter->next)
- if (edit->saved == saved)
- edit = g_new0(EditStatus, 1);
- edit->window = window = gnt_vbox_new(FALSE);
- gnt_box_set_toplevel(GNT_BOX(window), TRUE);
- gnt_box_set_title(GNT_BOX(window), _("Edit Status"));
- gnt_box_set_fill(GNT_BOX(window), TRUE);
- gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
- gnt_box_set_pad(GNT_BOX(window), 0);
- edits = g_list_append(edits, edit);
- box = gnt_hbox_new(FALSE);
- gnt_box_set_alignment(GNT_BOX(box), GNT_ALIGN_LEFT);
- gnt_box_add_widget(GNT_BOX(window), box);
- gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Title")));
- edit->title = entry = gnt_entry_new(saved ? purple_savedstatus_get_title(saved) : NULL);
- gnt_box_add_widget(GNT_BOX(box), entry);
- box = gnt_hbox_new(FALSE);
- gnt_box_add_widget(GNT_BOX(window), box);
- gnt_box_add_widget(GNT_BOX(box), label = gnt_label_new(_("Status")));
- gnt_widget_set_size(label, 0, 1);
- edit->type = combo = gnt_combo_box_new();
- gnt_box_add_widget(GNT_BOX(box), combo);
- current = saved ? purple_savedstatus_get_primitive_type(saved) : PURPLE_STATUS_UNSET;
- for (i = 0; prims[i] != PURPLE_STATUS_UNSET; i++)
- gnt_combo_box_add_data(GNT_COMBO_BOX(combo), GINT_TO_POINTER(prims[i]),
- purple_primitive_get_name_from_type(prims[i]));
- if (prims[i] == current)
- gnt_combo_box_set_selected(GNT_COMBO_BOX(combo), GINT_TO_POINTER(current));
- box = gnt_hbox_new(FALSE);
- gnt_box_add_widget(GNT_BOX(window), box);
- gnt_box_add_widget(GNT_BOX(box), gnt_label_new(_("Message")));
- edit->message = entry = gnt_entry_new(saved ? purple_savedstatus_get_message(saved) : NULL);
- gnt_box_add_widget(GNT_BOX(window), entry);
- gnt_box_add_widget(GNT_BOX(window), gnt_hline_new());
- gnt_box_add_widget(GNT_BOX(window), gnt_label_new(_("Use a different status for some accounts")));
- edit->hash = g_hash_table_new(g_direct_hash, g_direct_equal);
- edit->tree = tree = gnt_tree_new_with_columns(3);
- gnt_box_add_widget(GNT_BOX(window), tree);
- gnt_tree_set_show_title(GNT_TREE(tree), TRUE);
- gnt_tree_set_column_titles(GNT_TREE(tree), _("Account"), _("Status"), _("Message"));
- gnt_tree_set_col_width(GNT_TREE(tree), 0, 30);
- gnt_tree_set_col_width(GNT_TREE(tree), 1, 10);
- gnt_tree_set_col_width(GNT_TREE(tree), 2, 30);
- manager_model = purple_account_manager_get_default_as_model();
- n_items = g_list_model_get_n_items(manager_model);
- for(guint index = 0; index < n_items; index++) {
- PurpleAccount *account = g_list_model_get_item(manager_model, index);
- add_substatus(edit, account);
- g_object_unref(account);
- g_signal_connect(G_OBJECT(tree), "key_pressed", G_CALLBACK(popup_substatus), edit);
- box = gnt_hbox_new(FALSE);
- gnt_box_add_widget(GNT_BOX(window), box);
- button = gnt_button_new(_("Use"));
- gnt_box_add_widget(GNT_BOX(box), button);
- g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(use_trans_status_cb), edit);
- button = gnt_button_new(_("Save"));
- gnt_box_add_widget(GNT_BOX(box), button);
- g_object_set_data(G_OBJECT(button), "use", NULL);
- g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(save_savedstatus_cb), edit);
- button = gnt_button_new(_("Save and Use"));
- gnt_box_add_widget(GNT_BOX(box), button);
- g_object_set_data(G_OBJECT(button), "use", GINT_TO_POINTER(TRUE));
- g_signal_connect(G_OBJECT(button), "activate", G_CALLBACK(save_savedstatus_cb), edit);
- button = gnt_button_new(_("Cancel"));
- gnt_box_add_widget(GNT_BOX(box), button);
- g_signal_connect_swapped(G_OBJECT(button), "activate",
- G_CALLBACK(gnt_widget_destroy), window);
- g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(update_edit_list), edit);
- gnt_widget_show(window);
--- a/finch/gntstatus.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-/**********************************************************************
- **********************************************************************/
- * finch_savedstatus_show_all:
- * Show a dialog with all the saved statuses.
-void finch_savedstatus_show_all(void);
- * finch_savedstatus_edit:
- * @saved: The saved status to edit. Set it to %NULL to create a new status.
- * Show a dialog to edit a status.
-void finch_savedstatus_edit(PurpleSavedStatus *saved);
-#endif /* FINCH_STATUS_H */
--- a/finch/gntxfer.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,525 +0,0 @@
- * Finch 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>
- GntWidget *remove_button;
- GntWidget *stop_button;
- GntWidget *close_button;
-static PurpleGntXferDialog *xfer_dialog = NULL;
-#define UI_DATA "finch-ui-data"
- gint64 last_updated_time;
- gboolean notified; /* Has the completion of the transfer been notified? */
-/**************************************************************************
- **************************************************************************/
-update_title_progress(void)
- int num_active_xfers = 0;
- guint64 total_bytes_xferred = 0;
- guint64 total_file_size = 0;
- if (xfer_dialog == NULL || xfer_dialog->window == NULL)
- /* Find all active transfers */
- for (list = gnt_tree_get_rows(GNT_TREE(xfer_dialog->tree)); list; list = list->next) {
- PurpleXfer *xfer = (PurpleXfer *)list->data;
- if (purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_STARTED) {
- total_bytes_xferred += purple_xfer_get_bytes_sent(xfer);
- total_file_size += purple_xfer_get_size(xfer);
- if (num_active_xfers > 0) {
- if (total_file_size > 0) {
- total_pct = 100 * total_bytes_xferred / total_file_size;
- title = g_strdup_printf(ngettext("File Transfers - %d%% of %d file",
- "File Transfers - %d%% of %d files",
- total_pct, num_active_xfers);
- gnt_screen_rename_widget((xfer_dialog->window), title);
- gnt_screen_rename_widget((xfer_dialog->window), _("File Transfers"));
-/**************************************************************************
- **************************************************************************/
-toggle_keep_open_cb(G_GNUC_UNUSED GntWidget *w)
- xfer_dialog->keep_open = !xfer_dialog->keep_open;
- purple_prefs_set_bool("/finch/filetransfer/keep_open",
- xfer_dialog->keep_open);
-toggle_clear_finished_cb(G_GNUC_UNUSED GntWidget *w)
- xfer_dialog->auto_clear = !xfer_dialog->auto_clear;
- purple_prefs_set_bool("/finch/filetransfer/clear_finished",
- xfer_dialog->auto_clear);
- if (xfer_dialog->auto_clear) {
- GList *iter = purple_xfers_get_all();
- PurpleXfer *xfer = iter->data;
- if (purple_xfer_is_completed(xfer) || purple_xfer_is_cancelled(xfer))
- finch_xfer_dialog_remove_xfer(xfer);
-remove_button_cb(G_GNUC_UNUSED GntButton *button)
- PurpleXfer *selected_xfer = gnt_tree_get_selection_data(GNT_TREE(xfer_dialog->tree));
- if (selected_xfer && (purple_xfer_is_completed(selected_xfer) ||
- purple_xfer_is_cancelled(selected_xfer))) {
- finch_xfer_dialog_remove_xfer(selected_xfer);
-stop_button_cb(G_GNUC_UNUSED GntButton *button)
- PurpleXfer *selected_xfer = gnt_tree_get_selection_data(GNT_TREE(xfer_dialog->tree));
- PurpleXferStatus status;
- status = purple_xfer_get_status(selected_xfer);
- if (status != PURPLE_XFER_STATUS_CANCEL_LOCAL &&
- status != PURPLE_XFER_STATUS_CANCEL_REMOTE &&
- status != PURPLE_XFER_STATUS_DONE)
- purple_xfer_cancel_local(selected_xfer);
-/**************************************************************************
- * Dialog Building Functions
- **************************************************************************/
-finch_xfer_dialog_new(void)
- int widths[] = {8, 12, 8, 8, 8, 8, -1};
- xfer_dialog = g_new0(PurpleGntXferDialog, 1);
- xfer_dialog->keep_open =
- purple_prefs_get_bool("/finch/filetransfer/keep_open");
- xfer_dialog->auto_clear =
- purple_prefs_get_bool("/finch/filetransfer/clear_finished");
- /* Create the window. */
- xfer_dialog->window = window = gnt_vbox_new(FALSE);
- g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(finch_xfer_dialog_destroy), NULL);
- gnt_box_set_toplevel(GNT_BOX(window), TRUE);
- gnt_box_set_title(GNT_BOX(window), _("File Transfers"));
- gnt_box_set_fill(GNT_BOX(window), TRUE);
- gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
- xfer_dialog->tree = tree = gnt_tree_new_with_columns(NUM_COLUMNS);
- gnt_tree_set_column_titles(GNT_TREE(tree), _("Progress"), _("Filename"), _("Size"), _("Speed"), _("Remaining"), _("Status"));
- gnt_tree_set_column_width_ratio(GNT_TREE(tree), widths);
- gnt_tree_set_column_resizable(GNT_TREE(tree), COLUMN_PROGRESS, FALSE);
- gnt_tree_set_column_resizable(GNT_TREE(tree), COLUMN_SIZE, FALSE);
- gnt_tree_set_column_resizable(GNT_TREE(tree), COLUMN_SPEED, FALSE);
- gnt_tree_set_column_resizable(GNT_TREE(tree), COLUMN_REMAINING, FALSE);
- gnt_widget_set_size(tree, 70, -1);
- gnt_tree_set_show_title(GNT_TREE(tree), TRUE);
- gnt_box_add_widget(GNT_BOX(window), tree);
- checkbox = gnt_check_box_new( _("Close this window when all transfers finish"));
- gnt_check_box_set_checked(GNT_CHECK_BOX(checkbox),
- !xfer_dialog->keep_open);
- g_signal_connect(G_OBJECT(checkbox), "toggled",
- G_CALLBACK(toggle_keep_open_cb), NULL);
- gnt_box_add_widget(GNT_BOX(window), checkbox);
- checkbox = gnt_check_box_new(_("Clear finished transfers"));
- gnt_check_box_set_checked(GNT_CHECK_BOX(checkbox),
- xfer_dialog->auto_clear);
- g_signal_connect(G_OBJECT(checkbox), "toggled",
- G_CALLBACK(toggle_clear_finished_cb), NULL);
- gnt_box_add_widget(GNT_BOX(window), checkbox);
- bbox = gnt_hbox_new(FALSE);
- xfer_dialog->remove_button = button = gnt_button_new(_("Remove"));
- g_signal_connect(G_OBJECT(button), "activate",
- G_CALLBACK(remove_button_cb), NULL);
- gnt_box_add_widget(GNT_BOX(bbox), button);
- xfer_dialog->stop_button = button = gnt_button_new(_("Stop"));
- g_signal_connect(G_OBJECT(button), "activate",
- G_CALLBACK(stop_button_cb), NULL);
- gnt_box_add_widget(GNT_BOX(bbox), button);
- xfer_dialog->close_button = button = gnt_button_new(_("Close"));
- g_signal_connect(G_OBJECT(button), "activate",
- G_CALLBACK(finch_xfer_dialog_destroy), NULL);
- gnt_box_add_widget(GNT_BOX(bbox), button);
- gnt_box_add_widget(GNT_BOX(window), bbox);
- for (iter = purple_xfers_get_all(); iter; iter = iter->next) {
- PurpleXfer *xfer = (PurpleXfer *)iter->data;
- if (purple_xfer_get_visible(xfer)) {
- finch_xfer_dialog_add_xfer(xfer);
- finch_xfer_dialog_update_xfer(xfer);
- gnt_tree_set_selected(GNT_TREE(tree), xfer);
- gnt_widget_show(xfer_dialog->window);
-finch_xfer_dialog_destroy(void)
- gnt_widget_destroy(xfer_dialog->window);
-finch_xfer_dialog_show(void)
- if (xfer_dialog == NULL)
- finch_xfer_dialog_new();
- gnt_window_present(xfer_dialog->window);
-finch_xfer_dialog_add_xfer(PurpleXfer *xfer)
- PurpleGntXferUiData *data;
- char *size_str, *remaining_str;
- char *lfilename, *utf8;
- g_return_if_fail(xfer_dialog != NULL);
- g_return_if_fail(xfer != NULL);
- data = g_object_get_data(G_OBJECT(xfer), UI_DATA);
- finch_xfer_dialog_show();
- data->last_updated_time = 0;
- type = purple_xfer_get_xfer_type(xfer);
- size_str = g_format_size(purple_xfer_get_size(xfer));
- remaining_str = g_format_size(purple_xfer_get_bytes_remaining(xfer));
- lfilename = g_path_get_basename(purple_xfer_get_local_filename(xfer));
- utf8 = g_filename_to_utf8(lfilename, -1, NULL, NULL, NULL);
- gnt_tree_add_row_last(GNT_TREE(xfer_dialog->tree), xfer,
- gnt_tree_create_row(GNT_TREE(xfer_dialog->tree),
- "0.0", (type == PURPLE_XFER_TYPE_RECEIVE) ? purple_xfer_get_filename(xfer) : lfilename,
- size_str, "0.0", "",_("Waiting for transfer to begin")), NULL);
- xfer_dialog->num_transfers++;
- update_title_progress();
-finch_xfer_dialog_remove_xfer(PurpleXfer *xfer)
- g_return_if_fail(xfer_dialog != NULL);
- g_return_if_fail(xfer != NULL);
- if (!purple_xfer_get_visible(xfer)) {
- purple_xfer_set_visible(xfer, FALSE);
- gnt_tree_remove(GNT_TREE(xfer_dialog->tree), xfer);
- xfer_dialog->num_transfers--;
- if (xfer_dialog->num_transfers == 0 && !xfer_dialog->keep_open)
- finch_xfer_dialog_destroy();
- update_title_progress();
-finch_xfer_dialog_cancel_xfer(PurpleXfer *xfer)
- PurpleGntXferUiData *data;
- g_return_if_fail(xfer_dialog != NULL);
- g_return_if_fail(xfer != NULL);
- data = g_object_get_data(G_OBJECT(xfer), UI_DATA);
- if (!purple_xfer_get_visible(xfer)) {
- if ((purple_xfer_get_status(xfer) == PURPLE_XFER_STATUS_CANCEL_LOCAL) && (xfer_dialog->auto_clear)) {
- finch_xfer_dialog_remove_xfer(xfer);
- update_title_progress();
- if (purple_xfer_is_cancelled(xfer))
- status = _("Cancelled");
- gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_STATUS, status);
-finch_xfer_dialog_update_xfer(PurpleXfer *xfer)
- PurpleGntXferUiData *data;
- char *size_str, *remaining_str;
- char prog_str[G_ASCII_DTOSTR_BUF_SIZE];
- if (purple_xfer_get_start_time(xfer) > 0) {
- if ((now = purple_xfer_get_end_time(xfer)) == 0) {
- now = g_get_monotonic_time();
- elapsed = now - purple_xfer_get_start_time(xfer);
- kb_sent = purple_xfer_get_bytes_sent(xfer) / 1000.0;
- kbps = (elapsed > 0 ? (kb_sent * G_USEC_PER_SEC) / elapsed : 0);
- g_return_if_fail(xfer_dialog != NULL);
- g_return_if_fail(xfer != NULL);
- data = g_object_get_data(G_OBJECT(xfer), UI_DATA);
- if (data == NULL || !purple_xfer_get_visible(xfer) || data->notified) {
- current_time = g_get_monotonic_time();
- if (((current_time - data->last_updated_time) < G_USEC_PER_SEC) &&
- (!purple_xfer_is_completed(xfer))) {
- /* Don't update the window more than once per second */
- data->last_updated_time = current_time;
- send = (purple_xfer_get_xfer_type(xfer) == PURPLE_XFER_TYPE_SEND);
- size_str = g_format_size(purple_xfer_get_size(xfer));
- remaining_str = g_format_size(purple_xfer_get_bytes_remaining(xfer));
- kbsec = g_strdup_printf(_("%.2f KB/s"), kbps);
- gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_PROGRESS,
- g_ascii_dtostr(prog_str, G_ASCII_DTOSTR_BUF_SIZE, purple_xfer_get_progress(xfer) * 100.));
- gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_SIZE, size_str);
- gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_REMAINING, remaining_str);
- gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_SPEED, kbsec);
- if (purple_xfer_is_completed(xfer)) {
- gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_STATUS, send ? _("Sent") : _("Received"));
- gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_REMAINING, _("Finished"));
- char *msg = g_strdup_printf(_("The file was saved as %s."), purple_xfer_get_local_filename(xfer));
- purple_xfer_conversation_write(xfer, msg, FALSE);
- gnt_tree_change_text(GNT_TREE(xfer_dialog->tree), xfer, COLUMN_STATUS,
- send ? _("Sending") : _("Receiving"));
- update_title_progress();
- if (purple_xfer_is_completed(xfer) && xfer_dialog->auto_clear)
- finch_xfer_dialog_remove_xfer(xfer);
-/**************************************************************************
- **************************************************************************/
-finch_xfer_progress_notify(PurpleXfer *xfer, G_GNUC_UNUSED GParamSpec *pspec,
- G_GNUC_UNUSED gpointer data)
- finch_xfer_dialog_update_xfer(xfer);
-finch_xfer_status_notify(PurpleXfer *xfer, G_GNUC_UNUSED GParamSpec *pspec,
- G_GNUC_UNUSED gpointer data)
- if (purple_xfer_is_cancelled(xfer)) {
- finch_xfer_dialog_cancel_xfer(xfer);
-finch_xfer_visible_notify(PurpleXfer *xfer, G_GNUC_UNUSED GParamSpec *pspec,
- G_GNUC_UNUSED gpointer data)
- if (!purple_xfer_get_visible(xfer)) {
- finch_xfer_dialog_new();
- finch_xfer_dialog_add_xfer(xfer);
- gnt_tree_set_selected(GNT_TREE(xfer_dialog->tree), xfer);
-finch_xfer_new_xfer(PurpleXfer *xfer)
- PurpleGntXferUiData *data;
- /* This is where we're setting xfer's "ui_data" for the first time. */
- data = g_new0(PurpleGntXferUiData, 1);
- g_object_set_data_full(G_OBJECT(xfer), UI_DATA, data, g_free);
- g_signal_connect(xfer, "notify::progress",
- G_CALLBACK(finch_xfer_progress_notify), NULL);
- g_signal_connect(xfer, "notify::status",
- G_CALLBACK(finch_xfer_status_notify), NULL);
- g_signal_connect(xfer, "notify::visible",
- G_CALLBACK(finch_xfer_visible_notify), NULL);
-static PurpleXferUiOps ops = {
- .new_xfer = finch_xfer_new_xfer
-/**************************************************************************
- * GNT File Transfer API
- **************************************************************************/
- purple_prefs_add_none("/finch/filetransfer");
- purple_prefs_add_bool("/finch/filetransfer/clear_finished", TRUE);
- purple_prefs_add_bool("/finch/filetransfer/keep_open", FALSE);
-finch_xfers_uninit(void)
- if (xfer_dialog != NULL)
- finch_xfer_dialog_destroy();
-finch_xfers_get_ui_ops(void)
--- a/finch/gntxfer.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,125 +0,0 @@
- * Finch 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
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-/**************************************************************************/
-/* GNT File Transfer Dialog API */
-/**************************************************************************/
- * finch_xfer_dialog_new:
- * Creates a new file transfer dialog.
-void finch_xfer_dialog_new(void);
- * finch_xfer_dialog_destroy:
- * Destroys a file transfer dialog.
-void finch_xfer_dialog_destroy(void);
- * finch_xfer_dialog_show:
- * Displays the file transfer dialog given.
- * If dialog is %NULL, displays the default dialog, creating one if necessary
-void finch_xfer_dialog_show(void);
- * finch_xfer_dialog_hide:
- * Hides the file transfer dialog.
-void finch_xfer_dialog_hide(void);
- * finch_xfer_dialog_add_xfer:
- * @xfer: The file transfer.
- * Adds a file transfer to the dialog.
-void finch_xfer_dialog_add_xfer(PurpleXfer *xfer);
- * finch_xfer_dialog_remove_xfer:
- * @xfer: The file transfer.
- * Removes a file transfer from the dialog.
-void finch_xfer_dialog_remove_xfer(PurpleXfer *xfer);
- * finch_xfer_dialog_cancel_xfer:
- * @xfer: The file transfer that was cancelled.
- * Indicate in a file transfer dialog that a transfer was cancelled.
-void finch_xfer_dialog_cancel_xfer(PurpleXfer *xfer);
- * finch_xfer_dialog_update_xfer:
- * @xfer: The file transfer.
- * Updates the information for a transfer in the dialog.
-void finch_xfer_dialog_update_xfer(PurpleXfer *xfer);
-/**************************************************************************/
-/* GNT File Transfer API */
-/**************************************************************************/
- * Initializes the GNT file transfer system.
-void finch_xfers_init(void);
- * Uninitializes the GNT file transfer system.
-void finch_xfers_uninit(void);
- * finch_xfers_get_ui_ops:
- * Returns the UI operations structure for the GNT file transfer UI.
- * Returns: The GNT file transfer UI operations structure.
-PurpleXferUiOps *finch_xfers_get_ui_ops(void);
-#endif /* FINCH_XFER_H */
--- a/finch/libfinch.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,221 +0,0 @@
- * Finch 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 "purpleconfig.h"
-#include <glib/gi18n-lib.h>
-#include <glib/gstdio.h>
-#include "package_revision.h"
-start_with_debugwin(G_GNUC_UNUSED gpointer data)
- finch_debug_window_show();
-finch_plugins_init(void) {
- GPluginManager *manager = NULL;
- manager = gplugin_manager_get_default();
- gplugin_manager_append_paths_from_environment(manager,
- path = g_build_filename(purple_data_dir(), "plugins", NULL);
- if(g_mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR) != 0 && errno != EEXIST) {
- fprintf(stderr, "Couldn't create plugins dir\n");
- gplugin_manager_append_path(manager, path);
- gplugin_manager_append_path(manager, FINCH_LIBDIR);
- purple_plugins_refresh();
-init_libpurple(G_GNUC_UNUSED int argc, char **argv)
- gboolean opt_nologin = FALSE;
- gboolean opt_version = FALSE;
- gboolean opt_debug = FALSE;
- char *opt_config_dir_arg = NULL;
- GOptionContext *context;
- GOptionEntry option_entries[] = {
- G_OPTION_ARG_FILENAME, &opt_config_dir_arg,
- _("use DIR for config files"), _("DIR")},
- G_OPTION_ARG_NONE, &opt_debug,
- _("open debug window on startup"), NULL},
- G_OPTION_ARG_NONE, &opt_nologin,
- _("don't automatically login"), NULL},
- G_OPTION_ARG_NONE, &opt_version,
- _("display the current version and exit"), NULL},
- bindtextdomain(GETTEXT_PACKAGE, purple_get_locale_dir());
- bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
- textdomain(GETTEXT_PACKAGE);
- context = g_option_context_new(NULL);
- g_option_context_set_summary(context, DISPLAY_VERSION);
- g_option_context_add_main_entries(context, option_entries,
- g_option_context_add_group(context, purple_get_option_group());
- g_option_context_add_group(context, gplugin_get_option_group());
- /* Handle Unicode filenames on Windows. See GOptionContext docs. */
- args = g_win32_get_command_line();
- args = g_strdupv(argv);
- if (!g_option_context_parse_strv(context, &args, &error)) {
- g_printerr(_("%s: %s\nTry `%s -h' for more information.\n"),
- DISPLAY_VERSION, error->message, argv[0]);
- /* show version message */
- /* Translators may want to transliterate the name.
- It is not to be translated. */
- printf("%s %s (%s)\n", _("Finch"), DISPLAY_VERSION, REVISION);
- /* set a user-specified config directory */
- if (opt_config_dir_arg != NULL) {
- if (g_path_is_absolute(opt_config_dir_arg)) {
- purple_util_set_user_dir(opt_config_dir_arg);
- /* Make an absolute (if not canonical) path */
- char *cwd = g_get_current_dir();
- char *path = g_build_path(G_DIR_SEPARATOR_S, cwd, opt_config_dir_arg, NULL);
- purple_util_set_user_dir(path);
- g_free(opt_config_dir_arg);
- * We're done piddling around with command line arguments.
- /* We don't want debug-messages to show up and corrupt the display */
- finch_debug_init_handler();
- g_timeout_add(0, start_with_debugwin, NULL);
- purple_idle_set_ui(finch_idle_new());
- if (!purple_core_init(finch_ui_new(), &error))
- _("Finch3 initialization failed!\nError message: %s\n"),
- (error != NULL) ? error->message : "unknown error");
- /* TODO: should this be moved into finch_prefs_init() ? */
- finch_prefs_update_old();
- /* load plugins we had when we quit */
- purple_plugins_load_saved("/finch/plugins/loaded");
- /* Set all accounts to "offline" */
- PurpleSavedStatus *saved_status;
- /* If we've used this type+message before, lookup the transient status */
- saved_status = purple_savedstatus_find_transient_by_type_and_message(
- PURPLE_STATUS_OFFLINE, NULL);
- /* If this type+message is unique then create a new transient saved status */
- if (saved_status == NULL)
- saved_status = purple_savedstatus_new(NULL, PURPLE_STATUS_OFFLINE);
- /* Set the status for each account */
- purple_savedstatus_activate(saved_status);
- PurpleAccountManager *manager = NULL;
- /* Everything is good to go--sign on already */
- if(!purple_prefs_get_bool("/purple/savedstatus/startup_current_status")) {
- purple_savedstatus_activate(purple_savedstatus_get_startup());
- manager = purple_account_manager_get_default();
- purple_account_manager_set_online(manager, TRUE);
-gboolean finch_start(int *argc, char ***argv)
- /* Initialize the libpurple stuff */
- if (!init_libpurple(*argc, *argv))
--- a/finch/libfinch.h Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
- * Finch 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, see <https://www.gnu.org/licenses/>.
-#if !defined(FINCH_GLOBAL_HEADER_INSIDE) && !defined(FINCH_COMPILATION)
-# error "only <finch.h> may be included directly"
-#define FINCH_UI "gnt-purple"
-#define FINCH_PREFS_ROOT "/finch"
- * @argc: Address of the argc parameter of your main() function (or 0 if argv
- * is %NULL). This will be changed if any arguments were handled.
- * @argv: Address of the argv parameter of main(), or %NULL. Any options
- * understood by Finch are stripped before return.
- * Start finch with the given command line arguments.
-gboolean finch_start(int *argc, char ***argv);
--- a/finch/libfinch_winres.rc.in Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-VS_VERSION_INFO VERSIONINFO
- FILEVERSION @PURPLE_MAJOR_VERSION@,@PURPLE_MINOR_VERSION@,@PURPLE_MICRO_VERSION@,0
- PRODUCTVERSION @PURPLE_MAJOR_VERSION@,@PURPLE_MINOR_VERSION@,@PURPLE_MICRO_VERSION@,0
- FILESUBTYPE VFT2_UNKNOWN
- VALUE "CompanyName", "The Pidgin developer community"
- VALUE "FileDescription", "Finch UI library"
- VALUE "FileVersion", "@PURPLE_VERSION@"
- VALUE "InternalName", "libfinch"
- VALUE "LegalCopyright", "Copyright (C) 1998-2014 The Pidgin developer community (See the COPYRIGHT file in the source distribution)."
- VALUE "OriginalFilename", "libfinch-@PURPLE_API_VERSION@.dll"
- VALUE "ProductName", "Finch"
- VALUE "ProductVersion", "@PURPLE_VERSION@"
- VALUE "Translation", 0x409, 1200
--- a/finch/meson.build Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,237 +0,0 @@
-enable_consoleui = false
-if not get_option('consoleui')
-libgnt_dep = dependency('gnt3',
- fallback : ['libgnt', 'libgnt_dep'])
-#######################################################################
-# Check for ncurses and other things used by it
-# FIXME: This should be temporary until libgnt wraps the functionality.
-#######################################################################
-ncurses_available = true
-ncurses_header = 'ncurses.h'
-# Some distros put the headers in ncursesw/, some don't. These are ordered to
-# pick the last available as most-specific version.
-ncursesw_header_paths = ['', 'ncursesw/']
-ncurses = dependency('ncursesw', required : false)
- foreach location : ncursesw_header_paths
- f = location / 'ncurses.h'
- if compiler.has_header_symbol(f, 'get_wch',
- prefix : '#define _XOPEN_SOURCE_EXTENDED')
- ncurses_available = false
- ncurses_libs = compiler.find_library('ncursesw', required : false)
- if ncurses_libs.found()
- foreach location : ncursesw_header_paths
- f = location / 'ncurses.h'
- if compiler.has_header_symbol(f, 'get_wch',
- prefix : '#define _XOPEN_SOURCE_EXTENDED')
- ncurses_available = true
- ncurses = declare_dependency(
- include_directories : ncurses_inc,
- dependencies : ncurses_libs
-if not ncurses_available
- # ncursesw was not found. Look for plain old ncurses
- ncurses = dependency('ncurses', required : false)
- ncurses_available = true
- ncurses_libs = compiler.find_library('ncurses', required : false)
- ncurses_available = ncurses_libs.found()
- ncurses = declare_dependency(dependencies : ncurses_libs)
-if not ncurses_available and host_machine.system() == 'windows'
- ncurses_header = 'curses.h'
- ncurses_libs = compiler.find_library('pdcurses', required : false)
- ncurses_available = compiler.has_header(ncurses_header) and ncurses_libs.found()
- ncurses = declare_dependency(dependencies : ncurses_libs)
-if not ncurses_available
- error('ncurses could not be found!')
-ncurses_header = f'-DNCURSES_HEADER="@ncurses_header@"'
- 'finchnotifications.c',
- 'finchnotifications.h',
-libfinch_enum_headers = [
-# the built lists are append to below
-libfinch_built_sources = []
-libfinch_built_headers = []
-libfinch_generated_sources = []
- winmm = compiler.find_library('winmm')
- finch_winres = configure_file(
- input : 'finch_winres.rc.in',
- output : 'finch_winres.rc',
- configuration : version_conf)
- finch_SOURCES += windows.compile_resources(finch_winres)
- libfinch_winres = configure_file(
- input : 'libfinch_winres.rc.in',
- output : 'libfinch_winres.rc',
- configuration : version_conf)
- libfinch_SOURCES += windows.compile_resources(libfinch_winres)
-libfinch_enums = gnome.mkenums_simple('finchenums',
- sources: libfinch_enum_headers)
-libfinch_built_sources += libfinch_enums[0]
-libfinch_built_headers += libfinch_enums[1]
-foreach header : libfinch_headers + ['finchenums.h']
- FINCH_H_INCLUDES += f'#include <finch/@header@>'
-finch_h_conf = configuration_data()
-finch_h_conf.set('FINCH_H_INCLUDES', '\n'.join(FINCH_H_INCLUDES))
-finch_h = configure_file(input : 'finch.h.in',
- configuration : finch_h_conf,
- install_dir : get_option('includedir') / 'finch-3')
-libfinch_built_headers += finch_h
-install_headers(libfinch_headers, subdir : 'finch-3')
-libfinch_inc = include_directories('.')
-libfinch = shared_library('finch3',
- libfinch_SOURCES + libfinch_built_headers + libfinch_built_sources,
- '-DG_LOG_USE_STRUCTURED',
- '-DG_LOG_DOMAIN="Finch"',
- include_directories : [toplevel_inc],
- version : PURPLE_LIB_VERSION,
- dependencies : [libpurple_dep, libgnt_dep, ncurses, glib, winmm],
- introspection_sources = libfinch_headers
- libfinch_gir = gnome.generate_gir(libfinch,
- sources : introspection_sources,
- includes : ['GLib-2.0', 'GModule-2.0', 'GObject-2.0', libpurple_gir[0], 'Gnt-3.0'],
- symbol_prefix : 'finch',
- identifier_prefix : 'Finch',
- export_packages : 'finch-3',
- nsversion : f'@purple_major_version@.@purple_minor_version@',
- dependencies: [libgnt_dep, gplugin_dep, libpurple_dep],
- extra_args : ['-DFINCH_COMPILATION', '--quiet'])
- libfinch_generated_sources += libfinch_gir
-libfinch_dep = declare_dependency(
- include_directories : [toplevel_inc, libfinch_inc],
- sources: libfinch_built_headers + libfinch_generated_sources,
- dependencies : [libpurple_dep, libgnt_dep, glib])
- '-DG_LOG_USE_STRUCTURED',
- '-DG_LOG_DOMAIN="Finch"',
- dependencies : [libpurple_dep, libgnt_dep, libfinch_dep],
-meson.override_dependency('finch-3', libfinch_dep)
- description : 'Finch is an instant messenger application that uses libpurple for protocol support and ncurses (libgnt) for the UI.',
- version : meson.project_version(),
- libraries : [libgnt_dep, libpurple_dep],
- variables : [f'plugindir=${libdir}/finch-@purple_major_version@'])
--- a/finch/plugins/gntclipboard/gntclipboard.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,171 +0,0 @@
- * Copyright (C) 2007 Richard Nelson <wabz@whatsbeef.net>
- * 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
-#define _POSIX_C_SOURCE 200809L /* Needed to get kill(2). */
-#include <purpleconfig.h>
-#include <glib/gi18n-lib.h>
-#define PLUGIN_ID "gntclipboard"
-#define PLUGIN_DOMAIN (g_quark_from_static_string(PLUGIN_ID))
-static gulong sig_handle;
- XSelectionRequestEvent *req;
- Display *dpy = XOpenDisplay(NULL);
- ids = getenv("WINDOWID");
- XSetSelectionOwner(dpy, XA_PRIMARY, w, CurrentTime);
- XSelectInput(dpy, w, StructureNotifyMask);
- XNextEvent(dpy, &e); /* this blocks. */
- req = &e.xselectionrequest;
- if (e.type == SelectionRequest) {
- (unsigned char *)string,
- respond.xselection.property = req->property;
- respond.xselection.type = SelectionNotify;
- respond.xselection.display = req->display;
- respond.xselection.requestor = req->requestor;
- respond.xselection.selection = req->selection;
- respond.xselection.target= req->target;
- respond.xselection.time = req->time;
- XSendEvent(dpy, req->requestor, 0, 0, &respond);
- } else if (e.type == SelectionClear) {
-clipboard_changed(G_GNUC_UNUSED GntWM *wm, gchar *string)
- if ((child = fork()) == 0) {
-static GPluginPluginInfo *
-gnt_clipboard_query(G_GNUC_UNUSED GError **error) {
- const gchar * const authors[] = {
- "Richard Nelson <wabz@whatsbeef.net>",
- return finch_plugin_info_new(
- "name", N_("GntClipboard"),
- "version", DISPLAY_VERSION,
- "category", N_("Utility"),
- "summary", N_("Clipboard plugin"),
- "description", N_("When the gnt clipboard contents change, the "
- "contents are made available to X, if possible."),
- "website", PURPLE_WEBSITE,
- "abi-version", PURPLE_ABI_VERSION,
-gnt_clipboard_load(G_GNUC_UNUSED GPluginPlugin *plugin,
- G_GNUC_UNUSED GError **error)
- if (!XOpenDisplay(NULL)) {
- purple_debug_warning("gntclipboard", "Couldn't find X display\n");
- purple_notify_error(NULL, _("Error"), _("Error loading the plugin."),
- _("Couldn't find X display"), NULL);
- if (!getenv("WINDOWID")) {
- purple_debug_warning("gntclipboard", "Couldn't find window\n");
- purple_notify_error(NULL, _("Error"), _("Error loading the plugin."),
- _("Couldn't find window"), NULL);
- sig_handle = g_signal_connect(G_OBJECT(gnt_get_clipboard()), "clipboard_changed", G_CALLBACK(clipboard_changed), NULL);
- g_set_error(error, PLUGIN_DOMAIN, 0, _("This plugin cannot be loaded "
- "because it was not built with X11 support."));
-gnt_clipboard_unload(G_GNUC_UNUSED GPluginPlugin *plugin,
- G_GNUC_UNUSED gboolean shutdown,
- G_GNUC_UNUSED GError **error)
- g_signal_handler_disconnect(G_OBJECT(gnt_get_clipboard()), sig_handle);
-GPLUGIN_NATIVE_PLUGIN_DECLARE(gnt_clipboard)
--- a/finch/plugins/gntclipboard/meson.build Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
- library('gntclipboard', 'gntclipboard.c',
- c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Gnt-Clipboard"'],
- dependencies : [x11, libpurple_dep, libfinch_dep, glib],
- install : true, install_dir : FINCH_PLUGINDIR)
-devenv.append('FINCH_PLUGIN_PATH', meson.current_build_dir())
--- a/finch/plugins/gntgf/gntgf.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,422 +0,0 @@
- * Copyright (C) 2006 Sadrul Habib Chowdhury <sadrul@users.sourceforge.net>
- * 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
-#define PREFS_SCHEMA "im.pidgin.Finch.plugin.GntGf"
-#define PREFS_EVENT_SIGN_ON_OFF "event-sign-on-off"
-#define PREFS_EVENT_IM_MSG "event-im-message"
-#define PREFS_EVENT_CHAT_MSG "event-chat-message"
-#define PREFS_EVENT_CHAT_NICK "event-chat-nick"
-#define PREFS_BEEP "beep"
-#define PREFS_URGENT "urgent"
-#include <glib/gi18n-lib.h>
-static int gpsy[MAX_COLS];
-static int gpsw[MAX_COLS];
-destroy_toaster(GntToast *toast)
- toasters = g_list_remove(toasters, toast);
- gnt_widget_destroy(toast->window);
- g_source_remove(toast->timer);
-remove_toaster(GntToast *toast)
- gnt_widget_get_size(toast->window, NULL, &h);
- gpsy[toast->column] -= h;
- memset(&nwin, 0, sizeof(nwin));
- destroy_toaster(toast);
- for (iter = toasters; iter; iter = iter->next)
- if (toast->column != col) continue;
- gnt_widget_get_position(toast->window, &x, &y);
- gnt_screen_move_widget(toast->window, x, y);
-error_handler(Display *dpy, XErrorEvent *error)
- XGetErrorText(dpy, error->error_code, buffer, sizeof(buffer));
- purple_debug_error("gntgf", "Could not set urgent to the window: %s.\n", buffer);
- /* This is from deryni/tuomov's urgent_test.c */
- ids = getenv("WINDOWID");
- dpy = XOpenDisplay(NULL);
- XSetErrorHandler(error_handler);
- hints = XGetWMHints(dpy, id);
- hints->flags|=XUrgencyHint;
- XSetWMHints(dpy, id, hints);
- XSetErrorHandler(NULL);
-notify(PurpleConversation *conv, const char *fmt, ...)
- GSettings *settings = NULL;
- settings = g_settings_new_with_backend(PREFS_SCHEMA,
- purple_core_get_settings_backend());
- if(g_settings_get_boolean(settings, PREFS_BEEP)) {
- FinchConv *fc = FINCH_CONV(conv);
- if (gnt_widget_has_focus(fc->window)) {
- g_object_unref(settings);
- if(g_settings_get_boolean(settings, PREFS_URGENT)) {
- g_clear_object(&settings);
- window = gnt_vbox_new(FALSE);
- gnt_widget_set_transient(window, TRUE);
- gnt_widget_set_has_border(window, TRUE);
- str = g_strdup_vprintf(fmt, args);
- gnt_box_add_widget(GNT_BOX(window),
- gnt_label_new_with_format(str, GNT_TEXT_FLAG_HIGHLIGHT));
- gnt_widget_size_request(window);
- gnt_widget_get_size(window, &w, &h);
- for (i = 0; i < MAX_COLS && gpsy[i] + h >= getmaxy(stdscr) ; ++i)
- purple_debug_warning("GntGf", "Dude, that's way too many popups\n");
- gnt_widget_destroy(window);
- toast = g_new0(GntToast, 1);
- toast->window = window;
- gpsw[i] = gpsw[i - 1] + w + 1;
- if (i == 0 || (w + gpsw[i - 1] >= getmaxx(stdscr))) {
- /* if it's going to be too far left, overlap. */
- gnt_widget_set_position(window, getmaxx(stdscr) - w - 1,
- getmaxy(stdscr) - gpsy[i] - 1);
- gnt_widget_set_position(window, getmaxx(stdscr) - gpsw[i - 1] - w - 1,
- getmaxy(stdscr) - gpsy[i] - 1);
- gnt_widget_draw(window);
- toast->timer = g_timeout_add_seconds(4, G_SOURCE_FUNC(remove_toaster),
- toasters = g_list_prepend(toasters, toast);
-buddy_signed_on(PurpleBuddy *buddy, G_GNUC_UNUSED gpointer data)
- GSettings *settings = NULL;
- settings = g_settings_new_with_backend(PREFS_SCHEMA,
- purple_core_get_settings_backend());
- if(g_settings_get_boolean(settings, PREFS_EVENT_SIGN_ON_OFF)) {
- notify(NULL, _("%s just signed on"), purple_buddy_get_alias(buddy));
- g_object_unref(settings);
-buddy_signed_off(PurpleBuddy *buddy, G_GNUC_UNUSED gpointer data)
- GSettings *settings = NULL;
- settings = g_settings_new_with_backend(PREFS_SCHEMA,
- purple_core_get_settings_backend());
- if(g_settings_get_boolean(settings, PREFS_EVENT_SIGN_ON_OFF)) {
- notify(NULL, _("%s just signed off"), purple_buddy_get_alias(buddy));
- g_object_unref(settings);
-received_im_msg(G_GNUC_UNUSED PurpleAccount *account, const char *sender,
- G_GNUC_UNUSED const char *msg, PurpleIMConversation *im,
- G_GNUC_UNUSED PurpleMessageFlags flags,
- G_GNUC_UNUSED gpointer data)
- GSettings *settings = NULL;
- settings = g_settings_new_with_backend(PREFS_SCHEMA,
- purple_core_get_settings_backend());
- if(g_settings_get_boolean(settings, PREFS_EVENT_IM_MSG)) {
- notify(PURPLE_CONVERSATION(im), _("%s sent you a message"), sender);
- g_object_unref(settings);
-received_chat_msg(G_GNUC_UNUSED PurpleAccount *account, const char *sender,
- const char *msg, PurpleChatConversation *chat,
- G_GNUC_UNUSED PurpleMessageFlags flags,
- G_GNUC_UNUSED gpointer data)
- PurpleConversation *conv = PURPLE_CONVERSATION(chat);
- GSettings *settings = NULL;
- nick = purple_chat_conversation_get_nick(chat);
- if (g_utf8_collate(sender, nick) == 0) {
- settings = g_settings_new_with_backend(PREFS_SCHEMA,
- purple_core_get_settings_backend());
- if(g_settings_get_boolean(settings, PREFS_EVENT_CHAT_NICK) &&
- purple_utf8_has_word(msg, nick))
- notify(conv, _("%s said your nick in %s"), sender,
- purple_conversation_get_name(conv));
- } else if(g_settings_get_boolean(settings, PREFS_EVENT_CHAT_MSG)) {
- notify(conv, _("%s sent a message in %s"), sender,
- purple_conversation_get_name(conv));
- g_object_unref(settings);
- {PREFS_EVENT_SIGN_ON_OFF, N_("Buddy signs on/off")},
- {PREFS_EVENT_IM_MSG, N_("You receive an IM")},
- {PREFS_EVENT_CHAT_MSG, N_("Someone speaks in a chat")},
- {PREFS_EVENT_CHAT_NICK, N_("Someone says your name in a chat")},
-pref_toggled(GntTree *tree, char *key, G_GNUC_UNUSED gpointer data) {
- purple_prefs_set_bool(key, gnt_tree_get_choice(tree, key));
-toggle_option(GntCheckBox *check, gpointer str)
- purple_prefs_set_bool(str, gnt_check_box_get_checked(check));
- GntWidget *window, *tree, *check;
- window = gnt_vbox_new(FALSE);
- gnt_box_set_pad(GNT_BOX(window), 0);
- gnt_box_set_alignment(GNT_BOX(window), GNT_ALIGN_MID);
- gnt_box_set_fill(GNT_BOX(window), TRUE);
- gnt_box_add_widget(GNT_BOX(window),
- /* Translators: "toaster" here means "pop-up". */
- gnt_label_new(_("Notify with a toaster when")));
- gnt_box_add_widget(GNT_BOX(window), tree);
- for (i = 0; prefs[i].pref; i++)
- gnt_tree_add_choice(GNT_TREE(tree), prefs[i].pref,
- gnt_tree_create_row(GNT_TREE(tree), prefs[i].display), NULL, NULL);
- gnt_tree_set_choice(GNT_TREE(tree), prefs[i].pref,
- purple_prefs_get_bool(prefs[i].pref));
- gnt_tree_set_col_width(GNT_TREE(tree), 0, 40);
- g_signal_connect(G_OBJECT(tree), "toggled", G_CALLBACK(pref_toggled), NULL);
- check = gnt_check_box_new(_("Beep too!"));
- gnt_check_box_set_checked(GNT_CHECK_BOX(check), purple_prefs_get_bool(PREFS_BEEP));
- g_signal_connect(G_OBJECT(check), "toggled", G_CALLBACK(toggle_option), PREFS_BEEP);
- gnt_box_add_widget(GNT_BOX(window), check);
- check = gnt_check_box_new(_("Set URGENT for the terminal window."));
- gnt_check_box_set_checked(GNT_CHECK_BOX(check), purple_prefs_get_bool(PREFS_URGENT));
- g_signal_connect(G_OBJECT(check), "toggled", G_CALLBACK(toggle_option), PREFS_URGENT);
- gnt_box_add_widget(GNT_BOX(window), check);
-static GPluginPluginInfo *
-gnt_gf_query(G_GNUC_UNUSED GError **error) {
- const gchar * const authors[] = {
- "Sadrul H Chowdhury <sadrul@users.sourceforge.net>",
- return finch_plugin_info_new(
- "version", DISPLAY_VERSION,
- "category", N_("Notification"),
- "summary", N_("Toaster plugin"),
- "description", N_("Toaster plugin"),
- "website", PURPLE_WEBSITE,
- "abi-version", PURPLE_ABI_VERSION,
- "gnt-pref-frame-cb", config_frame,
-gnt_gf_load(GPluginPlugin *plugin, G_GNUC_UNUSED GError **error) {
- purple_signal_connect(purple_blist_get_handle(), "buddy-signed-on", plugin,
- G_CALLBACK(buddy_signed_on), NULL);
- purple_signal_connect(purple_blist_get_handle(), "buddy-signed-off", plugin,
- G_CALLBACK(buddy_signed_off), NULL);
- purple_signal_connect(purple_conversations_get_handle(), "received-im-msg", plugin,
- G_CALLBACK(received_im_msg), NULL);
- purple_signal_connect(purple_conversations_get_handle(), "received-chat-msg", plugin,
- G_CALLBACK(received_chat_msg), NULL);
- memset(&gpsy, 0, sizeof(gpsy));
- memset(&gpsw, 0, sizeof(gpsw));
-gnt_gf_unload(G_GNUC_UNUSED GPluginPlugin *plugin,
- G_GNUC_UNUSED gboolean shutdown,
- G_GNUC_UNUSED GError **error)
- GntToast *toast = toasters->data;
- destroy_toaster(toast);
-GPLUGIN_NATIVE_PLUGIN_DECLARE(gnt_gf)
--- a/finch/plugins/gntgf/im.pidgin.Finch.plugin.GntGf.gschema.xml Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
- <schema path="/finch/plugins/gntgf/" id="im.pidgin.Finch.plugin.GntGf">
- <key name="event-sign-on-off" type="b">
- <default>true</default>
- <summary>Notify buddy sign on/off</summary>
- Notify with a toaster when a buddy signs on/off.
- <key name="event-im-message" type="b">
- <default>true</default>
- <summary>Notify IM message</summary>
- Notify with a toaster when you receive an IM.
- <key name="event-chat-message" type="b">
- <default>true</default>
- <summary>Notify chat message</summary>
- Notify with a toaster when someone speaks in a chat.
- <key name="event-chat-nick" type="b">
- <default>true</default>
- <summary>Notify your nick in chat</summary>
- Notify with a toaster when someone says your name in a chat.
- <key name="beep" type="b">
- <default>true</default>
- <summary>Beep</summary>
- Also beep when notifying.
- <key name="urgent" type="b">
- <default>false</default>
- <summary>Set URGENT flag</summary>
- Set URGENT flag for the terminal window if X11 is supported.
--- a/finch/plugins/gntgf/meson.build Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
- library('gntgf', 'gntgf.c',
- '-DG_LOG_USE_STRUCTURED',
- '-DG_LOG_DOMAIN="Gnt-GF"',
- dependencies : [x11, libpurple_dep, libfinch_dep, ncurses, glib],
- install : true, install_dir : FINCH_PLUGINDIR)
- 'im.pidgin.Finch.plugin.GntGf.gschema.xml',
-install_data(settings_schemas, install_dir: schemas_dir)
-gnome.post_install(glib_compile_schemas: true)
-# Compile the schemas in the current directory; this is only useful for testing
-gnome.compile_schemas(depend_files: files(settings_schemas))
-devenv.append('FINCH_PLUGIN_PATH', meson.current_build_dir())
--- a/finch/plugins/gnttinyurl/gnttinyurl.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,560 +0,0 @@
- * Copyright (C) 2009 Richard Nelson <wabz@whatsbeef.net>
- * 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 <libsoup/soup.h>
-#define PREFS_SCHEMA "im.pidgin.Finch.plugin.TinyURL"
-#define PREF_LENGTH "length"
-static SoupSession *session = NULL;
-static GHashTable *tinyurl_cache = NULL;
- PurpleConversation *conv;
-static void process_urls(PurpleConversation *conv, GList *urls);
-/* 3 functions from util.c */
-badentity(const char *c)
- if (!g_ascii_strncasecmp(c, "<", 4) ||
- !g_ascii_strncasecmp(c, ">", 4) ||
- !g_ascii_strncasecmp(c, """, 6)) {
-static GList *extract_urls(const char *text)
- const char *t, *c, *q = NULL;
- gboolean inside_html = FALSE;
- if (*c == '(' && !inside_html) {
- } else if (!q && (*c == '\"' || *c == '\'')) {
- } else if (*c == '<') {
- if (!g_ascii_strncasecmp(c, "<A", 2)) {
- } else if ((*c=='h') && (!g_ascii_strncasecmp(c, "http://", 7) ||
- (!g_ascii_strncasecmp(c, "https://", 8)))) {
- if (badchar(*t) || badentity(t)) {
- if ((!g_ascii_strncasecmp(c, "http://", 7) && (t - c == 7)) ||
- (!g_ascii_strncasecmp(c, "https://", 8) && (t - c == 8))) {
- if (*(t) == ',' && (*(t + 1) != ' ')) {
- if ((*(t - 1) == ')' && (inside_paren > 0))) {
- url_buf = g_strndup(c, t - c);
- if (!g_list_find_custom(ret, url_buf, (GCompareFunc)strcmp)) {
- purple_debug_info("TinyURL", "Added URL %s\n", url_buf);
- ret = g_list_append(ret, url_buf);
- } else if (!g_ascii_strncasecmp(c, "www.", 4) && (c == text || badchar(c[-1]) || badentity(c-1))) {
- if (badchar(*t) || badentity(t)) {
- if (*(t) == ',' && (*(t + 1) != ' ')) {
- if ((*(t - 1) == ')' && (inside_paren > 0))) {
- url_buf = g_strndup(c, t - c);
- if (!g_list_find_custom(ret, url_buf, (GCompareFunc)strcmp)) {
- purple_debug_info("TinyURL", "Added URL %s\n", url_buf);
- ret = g_list_append(ret, url_buf);
- if (*c == ')' && !inside_html) {
-url_fetched(GObject *source, GAsyncResult *result, gpointer user_data) {
- CbInfo *data = (CbInfo *)user_data;
- PurpleConversation *conv = data->conv;
- PurpleConversationManager *manager;
- GBytes *response_body = NULL;
- manager = purple_conversation_manager_get_default();
- convs = purple_conversation_manager_get_all(manager);
- if(SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(data->msg))) {
- response_body = soup_session_send_and_read_finish(SOUP_SESSION(source),
- if (response_body != NULL) {
- /* Ensure URL is NUL-terminated. */
- url = g_bytes_get_data(response_body, &size);
- tmp = g_strndup(url, size);
- g_hash_table_insert(tinyurl_cache, data->original_url, tmp);
- g_bytes_unref(response_body);
- url = _("Error while querying TinyURL");
- g_free(data->original_url);
- /* ensure the conversation still exists */
- if (g_list_find(convs, conv)) {
- FinchConv *fconv = FINCH_CONV(conv);
- gchar *str = g_strdup_printf("[%d] %s", data->num, url);
- GntTextView *tv = GNT_TEXT_VIEW(fconv->tv);
- gnt_text_view_tag_change(tv, data->tag, str, FALSE);
- g_object_unref(data->msg);
- g_object_unref(data->msg);
- purple_debug_info("TinyURL", "Conversation no longer exists... :(\n");
-writing_msg(PurpleConversation *conv, PurpleMessage *msg,
- G_GNUC_UNUSED gpointer data)
- GList *iter, *urls, *next;
- GSettings *settings = NULL;
- if (purple_message_get_flags(msg) & (PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_INVISIBLE))
- urls = g_object_get_data(G_OBJECT(conv), "TinyURLs");
- g_list_free_full(urls, g_free);
- urls = extract_urls(purple_message_get_contents(msg));
- settings = g_settings_new_with_backend(PREFS_SCHEMA,
- purple_core_get_settings_backend());
- min_url_length = g_settings_get_int(settings, PREF_LENGTH);
- g_object_unref(settings);
- t = g_string_new(g_strdup(purple_message_get_contents(msg)));
- for (iter = urls; iter; iter = next) {
- if (g_utf8_strlen((char *)iter->data, -1) >= min_url_length) {
- gchar *j, *s, *str, *orig;
- glong len = g_utf8_strlen(iter->data, -1);
- str = g_strdup_printf("[%d]", ++c);
- while ((j = strstr(s, iter->data))) { /* replace all occurrences */
- pos = j - orig + (x++ * 3);
- t = g_string_insert(t, pos + len, str);
- urls = g_list_delete_link(urls, iter);
- purple_message_set_contents(msg, t->str);
- g_string_free(t, TRUE);
- g_object_set_data(G_OBJECT(conv), "TinyURLs", urls);
-wrote_msg(PurpleConversation *conv, PurpleMessage *pmsg,
- G_GNUC_UNUSED gpointer _unused)
- if (purple_message_get_flags(pmsg) & PURPLE_MESSAGE_SEND)
- urls = g_object_get_data(G_OBJECT(conv), "TinyURLs");
- process_urls(conv, urls);
- g_object_set_data(G_OBJECT(conv), "TinyURLs", NULL);
-process_urls(PurpleConversation *conv, GList *urls)
- FinchConv *fconv = FINCH_CONV(conv);
- GntTextView *tv = GNT_TEXT_VIEW(fconv->tv);
- GSettings *settings = NULL;
- gchar *tinyurl_prefix = NULL;
- settings = g_settings_new_with_backend(PREFS_SCHEMA,
- purple_core_get_settings_backend());
- tinyurl_prefix = g_settings_get_string(settings, PREF_URL);
- g_object_unref(settings);
- for (iter = urls, c = 1; iter; iter = iter->next, c++) {
- i = gnt_text_view_get_lines_below(tv);
- original_url = purple_unescape_html((char *)iter->data);
- tiny_url = g_hash_table_lookup(tinyurl_cache, original_url);
- gchar *str = g_strdup_printf("\n[%d] %s", c, tiny_url);
- gnt_text_view_append_text_with_flags(tv, str, GNT_TEXT_FLAG_DIM);
- gnt_text_view_scroll(tv, 0);
- cbdata = g_new(CbInfo, 1);
- cbdata->original_url = original_url;
- cbdata->tag = g_strdup_printf("%s%d", "tiny_", tag_num++);
- if (g_ascii_strncasecmp(original_url, "http://", 7) && g_ascii_strncasecmp(original_url, "https://", 8)) {
- url = g_strdup_printf("%shttp%%3A%%2F%%2F%s", tinyurl_prefix,
- purple_url_encode(original_url));
- url = g_strdup_printf("%s%s", tinyurl_prefix,
- purple_url_encode(original_url));
- cbdata->msg = msg = soup_message_new("GET", url);
- soup_session_send_and_read_async(session, msg, G_PRIORITY_DEFAULT,
- NULL, url_fetched, cbdata);
- gnt_text_view_append_text_with_tag((tv), _("\nFetching TinyURL..."),
- GNT_TEXT_FLAG_DIM, cbdata->tag);
- gnt_text_view_scroll(tv, 0);
- g_free(tinyurl_prefix);
-free_conv_urls(PurpleConversation *conv)
- GList *urls = g_object_get_data(G_OBJECT(conv), "TinyURLs");
- g_list_free_full(urls, g_free);
-tinyurl_notify_tinyuri(GntWidget *win, const gchar *url)
- GntWidget *label = g_object_get_data(G_OBJECT(win), "info-widget");
- message = g_strdup_printf(_("TinyURL for above: %s"), url);
- gnt_label_set_text(GNT_LABEL(label), message);
-tinyurl_notify_fetch_cb(GObject *source, GAsyncResult *result, gpointer data)
- SoupMessage *msg = data;
- GBytes *response_body = NULL;
- const gchar *tmp = NULL;
- const gchar *original_url = NULL;
- if(SOUP_STATUS_IS_SUCCESSFUL(soup_message_get_status(msg))) {
- response_body = soup_session_send_and_read_finish(SOUP_SESSION(source),
- if (response_body == NULL) {
- win = g_object_get_data(G_OBJECT(msg), "gnttinyurl-window");
- original_url = g_object_get_data(G_OBJECT(msg), "gnttinyurl-original");
- tmp = g_bytes_get_data(response_body, &size);
- url = g_strndup(tmp, size);
- g_hash_table_insert(tinyurl_cache, g_strdup(original_url), url);
- tinyurl_notify_tinyuri(win, url);
- g_bytes_unref(response_body);
-tinyurl_notify_uri(const char *uri)
- GCancellable *cancellable = NULL;
- GSettings *settings = NULL;
- gchar *tinyurl_prefix = NULL;
- /* XXX: The following expects that finch_notify_message gets called. This
- * may not always happen, e.g. when another plugin sets its own
- * notify_message. So tread carefully. */
- win = purple_notify_message(NULL, PURPLE_NOTIFY_MSG_INFO, _("URI"), uri,
- _("Please wait while TinyURL fetches a shorter URL ..."), NULL, NULL, NULL);
- if (!GNT_IS_WINDOW(win) || !g_object_get_data(G_OBJECT(win), "info-widget"))
- tiny_url = g_hash_table_lookup(tinyurl_cache, uri);
- tinyurl_notify_tinyuri(win, tiny_url);
- settings = g_settings_new_with_backend(PREFS_SCHEMA,
- purple_core_get_settings_backend());
- tinyurl_prefix = g_settings_get_string(settings, PREF_URL);
- g_object_unref(settings);
- if (g_ascii_strncasecmp(uri, "http://", 7) && g_ascii_strncasecmp(uri, "https://", 8)) {
- fullurl = g_strdup_printf("%shttp%%3A%%2F%%2F%s", tinyurl_prefix,
- purple_url_encode(uri));
- fullurl = g_strdup_printf("%s%s", tinyurl_prefix,
- purple_url_encode(uri));
- g_free(tinyurl_prefix);
- /* Make a cancellable and cancel it when the window is destroyed, so that
- * the callback does not try to use a non-existent window.
- cancellable = g_cancellable_new();
- msg = soup_message_new("GET", fullurl);
- g_object_set_data(G_OBJECT(msg), "gnttinyurl-window", win);
- g_object_set_data_full(G_OBJECT(msg), "gnttinyurl-original", g_strdup(uri),
- soup_session_send_and_read_async(session, msg, G_PRIORITY_DEFAULT,
- cancellable, tinyurl_notify_fetch_cb, msg);
- g_signal_connect_object(win, "destroy", G_CALLBACK(g_cancellable_cancel),
- cancellable, G_CONNECT_SWAPPED);
- g_object_unref(cancellable);
-static GPluginPluginInfo *
-tiny_url_query(G_GNUC_UNUSED GError **error) {
- const gchar * const authors[] = {
- "Richard Nelson <wabz@whatsbeef.net>",
- return finch_plugin_info_new(
- "version", DISPLAY_VERSION,
- "category", N_("Utility"),
- "summary", N_("TinyURL plugin"),
- "description", N_("When receiving a message with URL(s), "
- "use TinyURL for easier copying"),
- "website", PURPLE_WEBSITE,
- "abi-version", PURPLE_ABI_VERSION,
- "settings-schema", PREFS_SCHEMA,
-tiny_url_load(GPluginPlugin *plugin, G_GNUC_UNUSED GError **error) {
- PurpleNotifyUiOps *ops = purple_notify_get_ui_ops();
- session = soup_session_new();
- g_object_set_data(G_OBJECT(plugin), "notify-uri", ops->notify_uri);
- ops->notify_uri = tinyurl_notify_uri;
- tinyurl_cache = g_hash_table_new_full(g_str_hash, g_str_equal,
- purple_signal_connect(purple_conversations_get_handle(),
- plugin, G_CALLBACK(wrote_msg), NULL);
- purple_signal_connect(purple_conversations_get_handle(),
- plugin, G_CALLBACK(wrote_msg), NULL);
- purple_signal_connect(purple_conversations_get_handle(),
- plugin, G_CALLBACK(writing_msg), NULL);
- purple_signal_connect(purple_conversations_get_handle(),
- plugin, G_CALLBACK(writing_msg), NULL);
- purple_signal_connect(purple_conversations_get_handle(),
- "deleting-conversation",
- plugin, G_CALLBACK(free_conv_urls), NULL);
-tiny_url_unload(GPluginPlugin *plugin, G_GNUC_UNUSED gboolean shutdown,
- G_GNUC_UNUSED GError **error)
- PurpleNotifyUiOps *ops = purple_notify_get_ui_ops();
- if (ops->notify_uri == tinyurl_notify_uri)
- ops->notify_uri = g_object_get_data(G_OBJECT(plugin), "notify-uri");
- soup_session_abort(session);
- g_clear_object(&session);
- g_clear_pointer(&tinyurl_cache, g_hash_table_destroy);
-GPLUGIN_NATIVE_PLUGIN_DECLARE(tiny_url)
--- a/finch/plugins/gnttinyurl/im.pidgin.Finch.plugin.TinyURL.gschema.xml Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
- <schema path="/finch/plugins/tinyurl/" id="im.pidgin.Finch.plugin.TinyURL">
- <key name="length" type="i">
- <summary>Minimum conversion length</summary>
- Only create TinyURL for URLs of this length or greater.
- <key name="url" type="s">
- <default>"http://tinyurl.com/api-create.php?url="</default>
- <summary>URL generator prefix</summary>
- TinyURL (or other) address prefix.
--- a/finch/plugins/gnttinyurl/meson.build Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-library('gnttinyurl', 'gnttinyurl.c',
- c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Gnt-TinyURL"'],
- dependencies : [libpurple_dep, libfinch_dep, libsoup, glib],
- install : true, install_dir : FINCH_PLUGINDIR)
- 'im.pidgin.Finch.plugin.TinyURL.gschema.xml',
-install_data(settings_schemas, install_dir: schemas_dir)
-gnome.post_install(glib_compile_schemas: true)
-# Compile the schemas in the current directory; this is only useful for testing
-gnome.compile_schemas(depend_files: files(settings_schemas))
-devenv.append('FINCH_PLUGIN_PATH', meson.current_build_dir())
--- a/finch/plugins/grouping/grouping.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,400 +0,0 @@
- * Copyright (C) 2008 Sadrul Habib Chowdhury <sadrul@users.sourceforge.net>
- * 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 02110-1301, USA
-#include <glib/gi18n-lib.h>
-#define FINCH_TYPE_GROUPING_NODE (finch_grouping_node_get_type())
-#define FINCH_GROUPING_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), FINCH_TYPE_GROUPING_NODE, FinchGroupingNode))
-#define FINCH_IS_GROUPING_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), FINCH_TYPE_GROUPING_NODE))
- PurpleBlistNodeClass node_class;
-} FinchGroupingNodeClass;
-static FinchBlistManager *default_manager;
-finch_grouping_node_init(G_GNUC_UNUSED FinchGroupingNode *node)
-finch_grouping_node_class_init(G_GNUC_UNUSED FinchGroupingNodeClass *klass)
-finch_grouping_node_class_finalize(G_GNUC_UNUSED FinchGroupingNodeClass *klass)
-GType finch_grouping_node_get_type(void);
-G_DEFINE_DYNAMIC_TYPE(FinchGroupingNode, finch_grouping_node,
- PURPLE_TYPE_BLIST_NODE);
-static FinchGroupingNode *online, *offline;
- GntTree *tree = finch_blist_get_tree();
- gnt_tree_add_row_after(tree, online,
- gnt_tree_create_row(tree, _("Online")), NULL, NULL);
- gnt_tree_add_row_after(tree, offline,
- gnt_tree_create_row(tree, _("Offline")), NULL, online);
-static gboolean on_offline_can_add_node(PurpleBlistNode *node)
- if (PURPLE_IS_META_CONTACT(node)) {
- PurpleMetaContact *contact = PURPLE_META_CONTACT(node);
- if (purple_counting_node_get_current_size(PURPLE_COUNTING_NODE(contact)) > 0)
- } else if (PURPLE_IS_BUDDY(node)) {
- PurpleBuddy *buddy = PURPLE_BUDDY(node);
- if (PURPLE_BUDDY_IS_ONLINE(buddy))
- if (purple_prefs_get_bool("/finch/blist/showoffline") &&
- purple_account_is_connected(purple_buddy_get_account(buddy)))
- } else if (PURPLE_IS_CHAT(node)) {
- PurpleChat *chat = PURPLE_CHAT(node);
- return purple_account_is_connected(purple_chat_get_account(chat));
-static gpointer on_offline_find_parent(PurpleBlistNode *node)
- if (PURPLE_IS_META_CONTACT(node)) {
- node = PURPLE_BLIST_NODE(purple_meta_contact_get_priority_buddy(PURPLE_META_CONTACT(node)));
- ret = PURPLE_BUDDY_IS_ONLINE(PURPLE_BUDDY(node)) ? online : offline;
- } else if (PURPLE_IS_BUDDY(node)) {
- ret = purple_blist_node_get_parent(node);
- finch_blist_manager_add_node(ret);
- } else if (PURPLE_IS_CHAT(node)) {
-static gboolean on_offline_create_tooltip(gpointer selected_row, GString **body, char **tool_title)
- PurpleBlistNode *node = selected_row;
- if (FINCH_IS_GROUPING_NODE(node)) {
- /* There should be some easy way of getting the total online count,
- * or total number of chats. Doing a loop here will probably be pretty
- *body = g_string_new(FINCH_GROUPING_NODE(node) == online ?
- _("Online Buddies") : _("Offline Buddies"));
- return default_manager ? default_manager->create_tooltip(selected_row, body, tool_title) : FALSE;
-static FinchBlistManager on_offline =
- on_offline_can_add_node,
- on_offline_find_parent,
- on_offline_create_tooltip,
- {NULL, NULL, NULL, NULL}
-static FinchGroupingNode meebo;
- GntTree *tree = finch_blist_get_tree();
- if (!g_list_find(gnt_tree_get_rows(tree), &meebo)) {
- gnt_tree_add_row_last(tree, &meebo,
- gnt_tree_create_row(tree, _("Offline")), NULL);
-static gpointer meebo_find_parent(PurpleBlistNode *node)
- if (PURPLE_IS_META_CONTACT(node)) {
- PurpleBuddy *buddy = purple_meta_contact_get_priority_buddy(PURPLE_META_CONTACT(node));
- if (buddy && !PURPLE_BUDDY_IS_ONLINE(buddy)) {
- return default_manager->find_parent(node);
-static FinchBlistManager meebo_group =
- {NULL, NULL, NULL, NULL}
- GntTree *tree = finch_blist_get_tree();
- g_object_set(tree, "expander-level", 0, NULL);
- GntTree *tree = finch_blist_get_tree();
- g_object_set(tree, "expander-level", 1, NULL);
-static gboolean no_group_can_add_node(PurpleBlistNode *node)
- return on_offline_can_add_node(node); /* These happen to be the same */
-static gpointer no_group_find_parent(PurpleBlistNode *node)
- if (PURPLE_IS_BUDDY(node)) {
- ret = purple_blist_node_get_parent(node);
- finch_blist_manager_add_node(ret);
-static FinchBlistManager no_group =
- {NULL, NULL, NULL, NULL}
-static GHashTable *groups;
- groups = g_hash_table_new_full(g_str_hash, g_str_equal,
-nested_group_uninit(void)
- g_clear_pointer(&groups, g_hash_table_destroy);
-nested_group_find_parent(PurpleBlistNode *node)
- PurpleBlistNode *ret, *parent;
- if (!PURPLE_IS_GROUP(node))
- return default_manager->find_parent(node);
- group = PURPLE_GROUP(node);
- name = g_strdup(purple_group_get_name(group));
- if (!(sep = strchr(name, '/'))) {
- return default_manager->find_parent(node);
- tree = finch_blist_get_tree();
- if (*(sep + 1) && (ret = PURPLE_BLIST_NODE(purple_blist_find_group(name)))) {
- finch_blist_manager_add_node(ret);
- } else if (!(ret = g_hash_table_lookup(groups, name))) {
- ret = g_object_new(FINCH_TYPE_GROUPING_NODE, NULL);
- g_hash_table_insert(groups, g_strdup(name), ret);
- gnt_tree_add_row_last(tree, ret,
- gnt_tree_create_row(tree, name), parent);
- sep = strchr(sep + 1, '/');
-nested_group_create_tooltip(gpointer selected_row, GString **body, char **title)
- PurpleBlistNode *node = selected_row;
- if (!FINCH_IS_GROUPING_NODE(node)) {
- return default_manager->create_tooltip(selected_row, body, title);
- *body = g_string_new(_("Nested Subgroup")); /* Perhaps list the child groups/subgroups? */
-nested_group_can_add_node(PurpleBlistNode *node)
- PurpleBlistNode *group;
- if (!PURPLE_IS_GROUP(node))
- return default_manager->can_add_node(node);
- if (default_manager->can_add_node(node))
- len = strlen(purple_group_get_name(PURPLE_GROUP(node)));
- group = purple_blist_get_default_root();
- for (; group; group = purple_blist_node_get_sibling_next(group)) {
- if (strncmp(purple_group_get_name(PURPLE_GROUP(node)),
- purple_group_get_name(PURPLE_GROUP(group)), len) == 0 &&
- default_manager->can_add_node(group))
-static FinchBlistManager nested_group =
- N_("Nested Grouping (experimental)"),
- .init = nested_group_init,
- .uninit = nested_group_uninit,
- .find_parent = nested_group_find_parent,
- .create_tooltip = nested_group_create_tooltip,
- .can_add_node = nested_group_can_add_node,
-static GPluginPluginInfo *
-grouping_query(G_GNUC_UNUSED GError **error) {
- const gchar * const authors[] = {
- "Sadrul H Chowdhury <sadrul@users.sourceforge.net>",
- return finch_plugin_info_new(
- "name", N_("Grouping"),
- "category", N_("User interface"),
- "summary", N_("Provides alternate buddylist grouping options."),
- "description", N_("Provides alternate buddylist grouping options."),
- "website", PURPLE_WEBSITE,
- "abi-version", PURPLE_ABI_VERSION,
-grouping_load(GPluginPlugin *plugin, G_GNUC_UNUSED GError **error) {
- finch_grouping_node_register_type(G_TYPE_MODULE(plugin));
- default_manager = finch_blist_manager_find("default");
- online = g_object_new(FINCH_TYPE_GROUPING_NODE, NULL);
- offline = g_object_new(FINCH_TYPE_GROUPING_NODE, NULL);
- finch_blist_install_manager(&on_offline);
- finch_blist_install_manager(&meebo_group);
- finch_blist_install_manager(&no_group);
- finch_blist_install_manager(&nested_group);
-grouping_unload(G_GNUC_UNUSED GPluginPlugin *plugin,
- G_GNUC_UNUSED gboolean shutdown,
- G_GNUC_UNUSED GError **error)
- finch_blist_uninstall_manager(&on_offline);
- finch_blist_uninstall_manager(&meebo_group);
- finch_blist_uninstall_manager(&no_group);
- finch_blist_uninstall_manager(&nested_group);
- g_object_unref(online);
- g_object_unref(offline);
-GPLUGIN_NATIVE_PLUGIN_DECLARE(grouping)
--- a/finch/plugins/grouping/meson.build Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-library('grouping', 'grouping.c',
- c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Gnt-Grouping"'],
- dependencies : [libpurple_dep, libfinch_dep, glib],
- install : true, install_dir : FINCH_PLUGINDIR)
-devenv.append('FINCH_PLUGIN_PATH', meson.current_build_dir())
--- a/finch/plugins/lastlog/lastlog.c Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +0,0 @@
- * Copyright (C) 2006 Sadrul Habib Chowdhury <sadrul@users.sourceforge.net>
- * 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>
-window_kpress_cb(GntWidget *wid, const char *key, GntTextView *view)
- if (purple_strequal(key, GNT_KEY_DOWN)) {
- gnt_text_view_scroll(view, 1);
- } else if (purple_strequal(key, GNT_KEY_UP)) {
- gnt_text_view_scroll(view, -1);
- } else if (purple_strequal(key, GNT_KEY_PGDOWN)) {
- gnt_widget_get_size(wid, NULL, &height);
- gnt_text_view_scroll(view, height - 2);
- } else if (purple_strequal(key, GNT_KEY_PGUP)) {
- gnt_widget_get_size(wid, NULL, &height);
- gnt_text_view_scroll(view, -(height - 2));
-lastlog_cb(PurpleConversation *conv, G_GNUC_UNUSED const char *cmd,
- char **args, G_GNUC_UNUSED char **error,
- G_GNUC_UNUSED gpointer data)
- FinchConv *ggconv = FINCH_CONV(conv);
- char **strings = g_strsplit(gnt_text_view_get_text(GNT_TEXT_VIEW(ggconv->tv)),
- win = gnt_window_new();
- gnt_box_set_title(GNT_BOX(win), _("Lastlog"));
- tv = gnt_text_view_new();
- gnt_box_add_widget(GNT_BOX(win), tv);
- for (i = 0; strings[i]; i++) {
- if (strstr(strings[i], args[0]) != NULL) {
- char **finds = g_strsplit(strings[i], args[0], 0);
- for (j = 0; finds[j]; j++) {
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), args[0], GNT_TEXT_FLAG_BOLD);
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), finds[j], GNT_TEXT_FLAG_NORMAL);
- gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(tv), "\n", GNT_TEXT_FLAG_NORMAL);
- g_signal_connect(G_OBJECT(win), "key_pressed", G_CALLBACK(window_kpress_cb), tv);
- return PURPLE_CMD_RET_OK;
-static GPluginPluginInfo *
-gnt_last_log_query(G_GNUC_UNUSED GError **error) {
- const gchar * const authors[] = {
- "Sadrul H Chowdhury <sadrul@users.sourceforge.net>",
- return finch_plugin_info_new(
- "name", N_("GntLastlog"),
- "version", DISPLAY_VERSION,
- "category", N_("Utility"),
- "summary", N_("Lastlog plugin."),
- "description", N_("Lastlog plugin."),
- "website", PURPLE_WEBSITE,
- "abi-version", PURPLE_ABI_VERSION,
-gnt_last_log_load(G_GNUC_UNUSED GPluginPlugin *plugin,
- G_GNUC_UNUSED GError **error)
- cmd = purple_cmd_register("lastlog", "s", PURPLE_CMD_P_DEFAULT,
- PURPLE_CMD_FLAG_CHAT | PURPLE_CMD_FLAG_IM, NULL,
- /* Translators: The "backlog" here refers to the the conversation buffer/history. */
- lastlog_cb, _("lastlog: Searches for a substring in the backlog."), NULL);
-gnt_last_log_unload(G_GNUC_UNUSED GPluginPlugin *plugin,
- G_GNUC_UNUSED gboolean shutdown,
- G_GNUC_UNUSED GError **error)
- purple_cmd_unregister(cmd);
-GPLUGIN_NATIVE_PLUGIN_DECLARE(gnt_last_log)
\ No newline at end of file
--- a/finch/plugins/lastlog/meson.build Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,7 +0,0 @@
-library('gntlastlog', 'lastlog.c',
- c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Gnt-LastLog"'],
- dependencies : [libpurple_dep, libfinch_dep, ncurses, glib],
- install : true, install_dir : FINCH_PLUGINDIR)
-devenv.append('FINCH_PLUGIN_PATH', meson.current_build_dir())
--- a/finch/plugins/meson.build Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
--- a/meson.build Wed Apr 10 02:23:01 2024 -0500
+++ b/meson.build Wed Apr 10 22:19:38 2024 -0500
@@ -5,11 +5,11 @@
-# If any functions have been added to libpurple, Pidgin, or Finch:
+# If any functions have been added to libpurple or Pidgin: -# If backwards compatibility has been broken in libpurple, Pidgin, or Finch:
+# If backwards compatibility has been broken in libpurple or Pidgin: @@ -124,8 +124,6 @@
f'wpurple_lib_dir("purple-@purple_major_version@")')
conf.set('PIDGIN_LIBDIR',
f'wpurple_lib_dir("pidgin-@purple_major_version@")')
- conf.set('FINCH_LIBDIR',
- f'wpurple_lib_dir("finch-@purple_major_version@")')
conf.set('PURPLE_DATADIR', 'wpurple_data_dir()')
conf.set('PURPLE_SYSCONFDIR', 'wpurple_sysconf_dir()')
@@ -141,8 +139,6 @@
common_libdir / f'purple-@purple_major_version@')
conf.set_quoted('PIDGIN_LIBDIR',
common_libdir / f'pidgin-@purple_major_version@')
- conf.set_quoted('FINCH_LIBDIR',
- common_libdir / f'finch-@purple_major_version@')
abslibdir = get_option('prefix') / get_option('libdir')
@@ -150,8 +146,6 @@
conf.set_quoted('PURPLE_PLUGINDIR', PURPLE_PLUGINDIR)
PIDGIN_PLUGINDIR = abslibdir / f'pidgin-@purple_major_version@'
conf.set_quoted('PIDGIN_PLUGINDIR', PIDGIN_PLUGINDIR)
-FINCH_PLUGINDIR = abslibdir / f'finch-@purple_major_version@'
-conf.set_quoted('FINCH_PLUGINDIR', FINCH_PLUGINDIR)
# Windows and Haiku do not use libm for the math functions, they are part
@@ -205,16 +199,6 @@
#######################################################################
-# Check if we should compile with X support
-#######################################################################
- x11 = dependency('x11', required : get_option('x'))
-conf.set('HAVE_X11', x11.found())
-#######################################################################
# Check for LibXML2 (required)
#######################################################################
libxml = dependency('libxml-2.0', version : '>= 2.6.0')
@@ -290,7 +274,6 @@
'-DPURPLE_DISABLE_DEPRECATED',
'-DPIDGIN_DISABLE_DEPRECATED',
- '-DFINCH_DISABLE_DEPRECATED',
'-DGNT_DISABLE_DEPRECATED',
if get_option('buildtype') != 'plain' and compiler.get_id() == 'gcc'
@@ -434,7 +417,6 @@
@@ -466,8 +448,6 @@
# is merged and in a release that we require.
'GTK': get_option('gtkui'),
- 'console': enable_consoleui,
- 'X11 support': x11.found(),
}, section: 'User Interfaces', bool_yn: true)
--- a/meson_options.txt Wed Apr 10 02:23:01 2024 -0500
+++ b/meson_options.txt Wed Apr 10 22:19:38 2024 -0500
@@ -49,10 +49,3 @@
option('unity-integration', type : 'feature', value : 'disabled',
description : 'compile with support for unity integration plugin')
-##############################################################################
-option('consoleui', type : 'boolean', value : false,
- description : 'compile with console user interface')
-option('x', type : 'boolean', value : false)
--- a/po/POTFILES.in Wed Apr 10 02:23:01 2024 -0500
+++ b/po/POTFILES.in Wed Apr 10 22:19:38 2024 -0500
@@ -1,26 +1,3 @@
-finch/plugins/gntclipboard/gntclipboard.c
-finch/plugins/gntgf/gntgf.c
-finch/plugins/gnttinyurl/gnttinyurl.c
-finch/plugins/grouping/grouping.c
-finch/plugins/lastlog/lastlog.c
--- a/po/README Wed Apr 10 02:23:01 2024 -0500
+++ b/po/README Wed Apr 10 22:19:38 2024 -0500
@@ -1,2 +1,2 @@
-For information on translating Pidgin, libpurple, and Finch, please see
-our tranlsation page at https://pidgin.im/development/i18n/
+For information on translating Pidgin and libpurple please see our translation +page at https://pidgin.im/development/i18n/ --- a/subprojects/libgnt.wrap Wed Apr 10 02:23:01 2024 -0500
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-url = https://keep.imfreedom.org/libgnt/libgnt