From: Xavier Claessens Date: Sun, 17 Feb 2008 23:38:19 +0000 (+0000) Subject: Merge commit 'cassidy/irc' X-Git-Url: https://git.0d.be/?p=empathy.git;a=commitdiff_plain;h=8107cb72c02be53157fc87955b4bc4f454662182 Merge commit 'cassidy/irc' svn path=/trunk/; revision=649 --- diff --git a/TODO b/TODO index 187f6191..ebeb081a 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,5 @@ Things you can do if you want to help: - - Specialised UI for configuring IRC accounts. (Guillaume is already working - on IRC widget). - UI for inviting a contact in a chatroom. - UI for accept/refuse invitation to join a chatroom and VoIP calls. - UI to send a message directly to a contact. @@ -25,7 +23,7 @@ Things you can do if you want to help: - See with Gnome Online Desktop project how to implement meta-contacts and merge information from multiple contacts. - Testing and Bugfixing. - + If you want to contribute you can ask for information at - #telepathy on freenode - Telepathy's mailing list: telepathy@lists.freedesktop.org diff --git a/configure.ac b/configure.ac index 2c0f90e1..ac012243 100644 --- a/configure.ac +++ b/configure.ac @@ -291,6 +291,7 @@ AM_CONDITIONAL(HAVE_VOIP, test "x$enable_voip" = "xyes") # ----------------------------------------------------------- AC_DEFINE_UNQUOTED([UNINSTALLED_GLADE_DIR], ["`pwd`/libempathy-gtk"], [path to glade files]) AC_DEFINE_UNQUOTED([UNINSTALLED_DTD_DIR], ["`pwd`/libempathy"], [path to dtd files]) +AC_DEFINE_UNQUOTED([UNINSTALLED_IRC_DIR], ["`pwd`/libempathy"], [path to IRC network file]) # ----------------------------------------------------------- diff --git a/docs/libempathy-gtk/libempathy-gtk-docs.sgml b/docs/libempathy-gtk/libempathy-gtk-docs.sgml index e2f09b5c..ac591a78 100644 --- a/docs/libempathy-gtk/libempathy-gtk-docs.sgml +++ b/docs/libempathy-gtk/libempathy-gtk-docs.sgml @@ -52,6 +52,8 @@ + + diff --git a/docs/libempathy/libempathy-docs.sgml b/docs/libempathy/libempathy-docs.sgml index dbc8cb57..2b71a7da 100644 --- a/docs/libempathy/libempathy-docs.sgml +++ b/docs/libempathy/libempathy-docs.sgml @@ -39,6 +39,9 @@ + + + diff --git a/docs/libempathy/libempathy.types b/docs/libempathy/libempathy.types index 657fa006..fed32f1e 100644 --- a/docs/libempathy/libempathy.types +++ b/docs/libempathy/libempathy.types @@ -15,4 +15,6 @@ empathy_tp_contact_factory_get_type empathy_tp_contact_list_get_type empathy_tp_group_get_type empathy_tp_roomlist_get_type - +empathy_irc_server_get_type +empathy_irc_network_get_type +empathy_irc_network_manager_get_type diff --git a/libempathy-gtk/Makefile.am b/libempathy-gtk/Makefile.am index 24c93371..f5321517 100644 --- a/libempathy-gtk/Makefile.am +++ b/libempathy-gtk/Makefile.am @@ -23,6 +23,7 @@ libempathy_gtk_la_SOURCES = \ empathy-contact-dialogs.c \ empathy-accounts-dialog.c \ empathy-account-widget.c \ + empathy-account-widget-irc.c \ empathy-profile-chooser.c \ empathy-cell-renderer-expander.c \ empathy-cell-renderer-text.c \ @@ -53,7 +54,9 @@ libempathy_gtk_la_SOURCES = \ empathy-avatar-chooser.c \ empathy-avatar-image.c \ empathy-ui-utils.c \ - empathy-new-message-dialog.c + empathy-new-message-dialog.c \ + empathy-irc-network-dialog.c \ + totem-subtitle-encoding.c totem-subtitle-encoding.h # do not distribute generated files nodist_libempathy_gtk_la_SOURCES =\ @@ -76,6 +79,7 @@ libempathy_gtk_headers = \ empathy-contact-dialogs.h \ empathy-accounts-dialog.h \ empathy-account-widget.h \ + empathy-account-widget-irc.h \ empathy-profile-chooser.h \ empathy-cell-renderer-expander.h \ empathy-cell-renderer-text.h \ @@ -106,7 +110,8 @@ libempathy_gtk_headers = \ empathy-avatar-chooser.h \ empathy-avatar-image.h \ empathy-ui-utils.h \ - empathy-new-message-dialog.h + empathy-new-message-dialog.h \ + empathy-irc-network-dialog.h libempathy_gtk_includedir = $(includedir)/libempathy-gtk/ libempathy_gtk_include_HEADERS = \ @@ -125,6 +130,7 @@ glade_DATA = \ empathy-account-widget-jabber.glade \ empathy-account-widget-msn.glade \ empathy-account-widget-salut.glade \ + empathy-account-widget-irc.glade \ empathy-new-chatroom-dialog.glade \ empathy-group-chat.glade \ empathy-chatrooms-window.glade \ diff --git a/libempathy-gtk/empathy-account-widget-irc.c b/libempathy-gtk/empathy-account-widget-irc.c new file mode 100644 index 00000000..35fa7697 --- /dev/null +++ b/libempathy-gtk/empathy-account-widget-irc.c @@ -0,0 +1,511 @@ +/* + * Copyright (C) 2007-2008 Guillaume Desmottes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Guillaume Desmottes + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "empathy-irc-network-dialog.h" +#include "empathy-account-widget.h" +#include "empathy-account-widget-irc.h" +#include "empathy-ui-utils.h" + +#define DEBUG_DOMAIN "AccountWidgetIRC" + +#define IRC_NETWORKS_FILENAME "irc-networks.xml" + +typedef struct { + McAccount *account; + EmpathyIrcNetworkManager *network_manager; + + GtkWidget *vbox_settings; + + GtkWidget *combobox_network; + GtkWidget *button_add_network; + GtkWidget *button_network; + GtkWidget *button_remove; +} EmpathyAccountWidgetIrc; + +enum { + COL_NETWORK_OBJ, + COL_NETWORK_NAME, +}; + +static void +account_widget_irc_destroy_cb (GtkWidget *widget, + EmpathyAccountWidgetIrc *settings) +{ + g_object_unref (settings->network_manager); + g_object_unref (settings->account); + g_slice_free (EmpathyAccountWidgetIrc, settings); +} + +static void +unset_server_params (EmpathyAccountWidgetIrc *settings) +{ + empathy_debug (DEBUG_DOMAIN, "Unset server, port and use-ssl"); + mc_account_unset_param (settings->account, "server"); + mc_account_unset_param (settings->account, "port"); + mc_account_unset_param (settings->account, "use-ssl"); +} + +static void +update_server_params (EmpathyAccountWidgetIrc *settings) +{ + GtkTreeIter iter; + GtkTreeModel *model; + EmpathyIrcNetwork *network; + GSList *servers; + gchar *charset; + + if (!gtk_combo_box_get_active_iter ( + GTK_COMBO_BOX (settings->combobox_network), &iter)) + { + unset_server_params (settings); + return; + } + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network)); + gtk_tree_model_get (model, &iter, COL_NETWORK_OBJ, &network, -1); + + g_assert (network != NULL); + + g_object_get (network, "charset", &charset, NULL); + empathy_debug (DEBUG_DOMAIN, "Setting charset to %s", charset); + mc_account_set_param_string (settings->account, "charset", charset); + g_free (charset); + + servers = empathy_irc_network_get_servers (network); + if (g_slist_length (servers) > 0) + { + /* set the first server as CM server */ + EmpathyIrcServer *server = servers->data; + gchar *address; + guint port; + gboolean ssl; + + g_object_get (server, + "address", &address, + "port", &port, + "ssl", &ssl, + NULL); + + empathy_debug (DEBUG_DOMAIN, "Setting server to %s", address); + mc_account_set_param_string (settings->account, "server", address); + empathy_debug (DEBUG_DOMAIN, "Setting port to %u", port); + mc_account_set_param_int (settings->account, "port", port); + empathy_debug (DEBUG_DOMAIN, "Setting use-ssl to %s", + ssl ? "TRUE": "FALSE" ); + mc_account_set_param_boolean (settings->account, "use-ssl", ssl); + + g_free (address); + } + else + { + /* No server. Unset values */ + unset_server_params (settings); + } + + g_slist_foreach (servers, (GFunc) g_object_unref, NULL); + g_slist_free (servers); + g_object_unref (network); +} + +static void +irc_network_dialog_destroy_cb (GtkWidget *widget, + EmpathyAccountWidgetIrc *settings) +{ + GtkTreeIter iter; + GtkTreeModel *model; + EmpathyIrcNetwork *network; + gchar *name; + + /* name could be changed */ + gtk_combo_box_get_active_iter (GTK_COMBO_BOX (settings->combobox_network), + &iter); + model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network)); + gtk_tree_model_get (model, &iter, COL_NETWORK_OBJ, &network, -1); + + g_object_get (network, "name", &name, NULL); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + COL_NETWORK_NAME, name, -1); + + update_server_params (settings); + + g_object_unref (network); + g_free (name); +} + +static void +display_irc_network_dialog (EmpathyAccountWidgetIrc *settings, + EmpathyIrcNetwork *network) +{ + GtkWindow *window; + GtkWidget *dialog; + + window = empathy_get_toplevel_window (settings->vbox_settings); + dialog = empathy_irc_network_dialog_show (network, GTK_WIDGET (window)); + g_signal_connect (dialog, "destroy", + G_CALLBACK (irc_network_dialog_destroy_cb), settings); +} + +static void +account_widget_irc_button_edit_network_clicked_cb ( + GtkWidget *button, + EmpathyAccountWidgetIrc *settings) +{ + GtkTreeIter iter; + GtkTreeModel *model; + EmpathyIrcNetwork *network; + + gtk_combo_box_get_active_iter (GTK_COMBO_BOX (settings->combobox_network), + &iter); + model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network)); + gtk_tree_model_get (model, &iter, COL_NETWORK_OBJ, &network, -1); + + g_assert (network != NULL); + + display_irc_network_dialog (settings, network); + + g_object_unref (network); +} + +static void +account_widget_irc_button_remove_clicked_cb (GtkWidget *button, + EmpathyAccountWidgetIrc *settings) +{ + EmpathyIrcNetwork *network; + GtkTreeIter iter; + GtkTreeModel *model; + gchar *name; + + gtk_combo_box_get_active_iter (GTK_COMBO_BOX (settings->combobox_network), + &iter); + model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network)); + gtk_tree_model_get (model, &iter, COL_NETWORK_OBJ, &network, -1); + + g_assert (network != NULL); + + g_object_get (network, "name", &name, NULL); + empathy_debug (DEBUG_DOMAIN, "Remove network %s", name); + + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + empathy_irc_network_manager_remove (settings->network_manager, network); + + /* Select the first network */ + if (gtk_tree_model_get_iter_first (model, &iter)) + { + gtk_combo_box_set_active_iter ( + GTK_COMBO_BOX (settings->combobox_network), &iter); + } + + g_free (name); + g_object_unref (network); +} + +static void +account_widget_irc_button_add_network_clicked_cb (GtkWidget *button, + EmpathyAccountWidgetIrc *settings) +{ + EmpathyIrcNetwork *network; + GtkTreeModel *model; + GtkListStore *store; + gchar *name; + GtkTreeIter iter; + + network = empathy_irc_network_new (_("New Network")); + empathy_irc_network_manager_add (settings->network_manager, network); + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network)); + store = GTK_LIST_STORE (model); + + g_object_get (network, "name", &name, NULL); + + gtk_list_store_insert_with_values (store, &iter, -1, + COL_NETWORK_OBJ, network, + COL_NETWORK_NAME, name, + -1); + + gtk_combo_box_set_active_iter (GTK_COMBO_BOX (settings->combobox_network), + &iter); + + display_irc_network_dialog (settings, network); + + g_free (name); + g_object_unref (network); +} + +static void +account_widget_irc_combobox_network_changed_cb (GtkWidget *combobox, + EmpathyAccountWidgetIrc *settings) +{ + update_server_params (settings); +} + +static void +fill_networks_model (EmpathyAccountWidgetIrc *settings, + EmpathyIrcNetwork *network_to_select) +{ + GSList *networks, *l; + GtkTreeModel *model; + GtkListStore *store; + + networks = empathy_irc_network_manager_get_networks ( + settings->network_manager); + + model = gtk_combo_box_get_model (GTK_COMBO_BOX (settings->combobox_network)); + store = GTK_LIST_STORE (model); + + for (l = networks; l != NULL; l = g_slist_next (l)) + { + gchar *name; + EmpathyIrcNetwork *network = l->data; + GtkTreeIter iter; + + g_object_get (network, "name", &name, NULL); + + gtk_list_store_insert_with_values (store, &iter, -1, + COL_NETWORK_OBJ, network, + COL_NETWORK_NAME, name, + -1); + + if (network == network_to_select) + { + gtk_combo_box_set_active_iter ( + GTK_COMBO_BOX (settings->combobox_network), &iter); + } + + g_free (name); + g_object_unref (network); + } + + if (network_to_select == NULL) + { + /* Select the first network */ + GtkTreeIter iter; + + if (gtk_tree_model_get_iter_first (model, &iter)) + { + gtk_combo_box_set_active_iter ( + GTK_COMBO_BOX (settings->combobox_network), &iter); + + update_server_params (settings); + } + } + + g_slist_free (networks); +} + +static void +account_widget_irc_setup (EmpathyAccountWidgetIrc *settings) +{ + gchar *nick = NULL; + gchar *fullname = NULL; + gchar *server = NULL; + gint port = 6667; + gchar *charset; + gboolean ssl = FALSE; + EmpathyIrcNetwork *network = NULL; + + mc_account_get_param_string (settings->account, "account", &nick); + mc_account_get_param_string (settings->account, "fullname", &fullname); + mc_account_get_param_string (settings->account, "server", &server); + mc_account_get_param_string (settings->account, "charset", &charset); + mc_account_get_param_int (settings->account, "port", &port); + mc_account_get_param_boolean (settings->account, "use-ssl", &ssl); + + if (!nick) + { + nick = g_strdup (g_get_user_name ()); + mc_account_set_param_string (settings->account, "account", nick); + } + + if (!fullname) + { + fullname = g_strdup (g_get_real_name ()); + if (!fullname) + { + fullname = g_strdup (nick); + } + mc_account_set_param_string (settings->account, "fullname", fullname); + } + + if (server != NULL) + { + GtkListStore *store; + + network = empathy_irc_network_manager_find_network_by_address ( + settings->network_manager, server); + + + store = GTK_LIST_STORE (gtk_combo_box_get_model ( + GTK_COMBO_BOX (settings->combobox_network))); + + if (network != NULL) + { + gchar *name; + + g_object_set (network, "charset", charset, NULL); + + g_object_get (network, "name", &name, NULL); + empathy_debug (DEBUG_DOMAIN, "Account use network %s", name); + + g_free (name); + } + else + { + /* We don't have this network. Let's create it */ + EmpathyIrcServer *srv; + GtkTreeIter iter; + + empathy_debug (DEBUG_DOMAIN, "Create a network %s", server); + network = empathy_irc_network_new (server); + srv = empathy_irc_server_new (server, port, ssl); + + empathy_irc_network_append_server (network, srv); + empathy_irc_network_manager_add (settings->network_manager, network); + + gtk_list_store_insert_with_values (store, &iter, -1, + COL_NETWORK_OBJ, network, + COL_NETWORK_NAME, server, + -1); + + gtk_combo_box_set_active_iter ( + GTK_COMBO_BOX (settings->combobox_network), &iter); + + g_object_unref (srv); + g_object_unref (network); + } + } + + + fill_networks_model (settings, network); + + g_free (nick); + g_free (fullname); + g_free (server); + g_free (charset); +} + +/** + * empathy_account_widget_irc_new: + * @account: the #McAccount to configure + * + * Creates a new IRC account widget to configure a given #McAccount + * + * Returns: The toplevel container of the configuration widget + */ +GtkWidget * +empathy_account_widget_irc_new (McAccount *account) +{ + EmpathyAccountWidgetIrc *settings; + gchar *dir, *user_file_with_path, *global_file_with_path; + GladeXML *glade; + GtkListStore *store; + GtkCellRenderer *renderer; + + settings = g_slice_new0 (EmpathyAccountWidgetIrc); + settings->account = g_object_ref (account); + + dir = g_build_filename (g_get_home_dir (), ".gnome2", PACKAGE_NAME, NULL); + g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR); + user_file_with_path = g_build_filename (dir, IRC_NETWORKS_FILENAME, NULL); + g_free (dir); + + global_file_with_path = g_build_filename (UNINSTALLED_IRC_DIR, + IRC_NETWORKS_FILENAME, NULL); + if (!g_file_test (global_file_with_path, G_FILE_TEST_EXISTS)) + { + g_free (global_file_with_path); + global_file_with_path = g_build_filename (DATADIR, "empathy", + IRC_NETWORKS_FILENAME, NULL); + } + + settings->network_manager = empathy_irc_network_manager_new ( + global_file_with_path, + user_file_with_path); + + g_free (global_file_with_path); + g_free (user_file_with_path); + + glade = empathy_glade_get_file ("empathy-account-widget-irc.glade", + "vbox_irc_settings", + NULL, + "vbox_irc_settings", &settings->vbox_settings, + "combobox_network", &settings->combobox_network, + "button_network", &settings->button_network, + "button_add_network", &settings->button_add_network, + "button_remove", &settings->button_remove, + NULL); + + /* Fill the networks combobox */ + store = gtk_list_store_new (2, G_TYPE_OBJECT, G_TYPE_STRING); + + gtk_cell_layout_clear (GTK_CELL_LAYOUT (settings->combobox_network)); + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (settings->combobox_network), + renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (settings->combobox_network), + renderer, + "text", COL_NETWORK_NAME, + NULL); + + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + COL_NETWORK_NAME, + GTK_SORT_ASCENDING); + + gtk_combo_box_set_model (GTK_COMBO_BOX (settings->combobox_network), + GTK_TREE_MODEL (store)); + g_object_unref (store); + + account_widget_irc_setup (settings); + + empathy_account_widget_handle_params (account, glade, + "entry_nick", "account", + "entry_fullname", "fullname", + "entry_password", "password", + "entry_quit_message", "quit-message", + NULL); + + empathy_glade_connect (glade, settings, + "vbox_irc_settings", "destroy", account_widget_irc_destroy_cb, + "button_network", "clicked", account_widget_irc_button_edit_network_clicked_cb, + "button_add_network", "clicked", account_widget_irc_button_add_network_clicked_cb, + "button_remove", "clicked", account_widget_irc_button_remove_clicked_cb, + "combobox_network", "changed", account_widget_irc_combobox_network_changed_cb, + NULL); + + g_object_unref (glade); + + return settings->vbox_settings; +} diff --git a/libempathy-gtk/empathy-account-widget-irc.glade b/libempathy-gtk/empathy-account-widget-irc.glade new file mode 100644 index 00000000..14c757ce --- /dev/null +++ b/libempathy-gtk/empathy-account-widget-irc.glade @@ -0,0 +1,451 @@ + + + + + + irc account settings + False + + + True + 5 + 2 + 12 + 6 + + + True + 0 + Network: + True + + + GTK_FILL + + + + + + True + 2 + + + True + + + + + + True + True + Create a new IRC network + 0 + + + True + gtk-add + + + + + False + False + 1 + + + + + True + True + Edit the selected IRC network + 0 + + + True + gtk-edit + + + + + False + False + 2 + + + + + True + True + Remove the selected IRC network + 0 + + + True + gtk-remove + + + + + False + False + 3 + + + + + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + 0 + Nickname: + True + entry_nick + + + 1 + 2 + GTK_FILL + + + + + + True + True + * + + + 1 + 2 + 1 + 2 + + + + + + True + 0 + Real name: + + + 3 + 4 + GTK_FILL + + + + + + True + 0 + Password: + + + 2 + 3 + GTK_FILL + + + + + + True + True + False + * + + + 1 + 2 + 2 + 3 + + + + + + True + True + + + 1 + 2 + 3 + 4 + + + + + + True + 0 + Quit message: + + + 4 + 5 + GTK_FILL + + + + + + True + True + + + 1 + 2 + 4 + 5 + + + + + + + + True + 5 + Network + GTK_WIN_POS_CENTER_ON_PARENT + gtk-edit + GDK_WINDOW_TYPE_HINT_DIALOG + True + True + False + + + True + 2 + + + True + 0 + GTK_SHADOW_NONE + + + True + 6 + 12 + + + True + 2 + 2 + 12 + 6 + + + True + + + 1 + 2 + 1 + 2 + GTK_FILL + GTK_FILL + + + + + True + True + + + 1 + 2 + + + + + + True + 0 + Charset: + + + 1 + 2 + GTK_FILL + + + + + + True + 0 + Network: + + + GTK_FILL + + + + + + + + + + True + <b>Network</b> + True + + + label_item + + + + + 1 + + + + + True + 0 + GTK_SHADOW_NONE + + + True + 6 + 12 + + + True + 1 + 2 + 6 + 6 + + + True + 6 + GTK_BUTTONBOX_START + + + True + True + True + gtk-add + True + 0 + + + + + True + True + True + gtk-remove + True + 0 + + + 1 + + + + + True + True + True + gtk-go-up + True + 0 + + + 2 + + + + + True + True + True + gtk-go-down + True + 0 + + + 3 + + + + + 1 + 2 + GTK_FILL + + + + + True + True + GTK_POLICY_NEVER + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + + + True + True + False + + + + + GTK_FILL + + + + + + + + + True + <b>Servers</b> + True + + + label_item + + + + + 2 + + + + + True + GTK_BUTTONBOX_END + + + True + True + True + gtk-close + True + -7 + + + + + False + GTK_PACK_END + + + + + + diff --git a/libempathy-gtk/empathy-account-widget-irc.h b/libempathy-gtk/empathy-account-widget-irc.h new file mode 100644 index 00000000..6ead048e --- /dev/null +++ b/libempathy-gtk/empathy-account-widget-irc.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2007-2008 Guillaume Desmottes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Guillaume Desmottes + */ + +#ifndef __EMPATHY_ACCOUNT_WIDGET_IRC_H__ +#define __EMPATHY_ACCOUNT_WIDGET_IRC_H__ + +#include +#include + +G_BEGIN_DECLS + +GtkWidget * empathy_account_widget_irc_new (McAccount *account); + +G_END_DECLS + +#endif /* __EMPATHY_ACCOUNT_WIDGET_IRC_H__ */ diff --git a/libempathy-gtk/empathy-accounts-dialog.c b/libempathy-gtk/empathy-accounts-dialog.c index 93b7b005..83206337 100644 --- a/libempathy-gtk/empathy-accounts-dialog.c +++ b/libempathy-gtk/empathy-accounts-dialog.c @@ -46,6 +46,7 @@ #include "empathy-accounts-dialog.h" #include "empathy-profile-chooser.h" #include "empathy-account-widget.h" +#include "empathy-account-widget-irc.h" #define DEBUG_DOMAIN "AccountDialog" @@ -269,6 +270,10 @@ accounts_dialog_update_account (EmpathyAccountsDialog *dialog, dialog->settings_widget = empathy_account_widget_salut_new (account); } + else if (!tp_strdiff (config_ui, "irc")) { + dialog->settings_widget = + empathy_account_widget_irc_new (account); + } else { dialog->settings_widget = empathy_account_widget_generic_new (account); diff --git a/libempathy-gtk/empathy-irc-network-dialog.c b/libempathy-gtk/empathy-irc-network-dialog.c new file mode 100644 index 00000000..9a42c649 --- /dev/null +++ b/libempathy-gtk/empathy-irc-network-dialog.c @@ -0,0 +1,579 @@ +/* + * Copyright (C) 2007-2008 Guillaume Desmottes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Guillaume Desmottes + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include "empathy-ui-utils.h" +#include "totem-subtitle-encoding.h" + +#include "empathy-irc-network-dialog.h" + +#define DEBUG_DOMAIN "AccountWidgetIRC" + +typedef struct { + EmpathyIrcNetwork *network; + + GtkWidget *dialog; + GtkWidget *button_close; + + GtkWidget *entry_network; + GtkWidget *combobox_charset; + + GtkWidget *treeview_servers; + GtkWidget *button_add; + GtkWidget *button_remove; + GtkWidget *button_up; + GtkWidget *button_down; +} EmpathyIrcNetworkDialog; + +static void +irc_network_dialog_destroy_cb (GtkWidget *widget, + EmpathyIrcNetworkDialog *dialog) +{ + g_object_unref (dialog->network); + + g_slice_free (EmpathyIrcNetworkDialog, dialog); +} + +static void +irc_network_dialog_close_clicked_cb (GtkWidget *widget, + EmpathyIrcNetworkDialog *dialog) +{ + gtk_widget_destroy (dialog->dialog); +} + +enum { + COL_SRV_OBJ, + COL_ADR, + COL_PORT, + COL_SSL +}; + +static void +add_server_to_store (GtkListStore *store, + EmpathyIrcServer *server, + GtkTreeIter *iter) +{ + gchar *address; + guint port; + gboolean ssl; + + g_object_get (server, + "address", &address, + "port", &port, + "ssl", &ssl, + NULL); + + gtk_list_store_insert_with_values (store, iter, -1, + COL_SRV_OBJ, server, + COL_ADR, address, + COL_PORT, port, + COL_SSL, ssl, + -1); + + g_free (address); +} + +static void +irc_network_dialog_setup (EmpathyIrcNetworkDialog *dialog) +{ + gchar *name, *charset; + GSList *servers, *l; + GtkListStore *store; + + g_object_get (dialog->network, + "name", &name, + "charset", &charset, + NULL); + gtk_entry_set_text (GTK_ENTRY (dialog->entry_network), name); + + store = GTK_LIST_STORE (gtk_tree_view_get_model ( + GTK_TREE_VIEW (dialog->treeview_servers))); + + servers = empathy_irc_network_get_servers (dialog->network); + for (l = servers; l != NULL; l = g_slist_next (l)) + { + EmpathyIrcServer *server = l->data; + GtkTreeIter iter; + + add_server_to_store (store, server, &iter); + } + + totem_subtitle_encoding_set (GTK_COMBO_BOX (dialog->combobox_charset), + charset); + + g_slist_foreach (servers, (GFunc) g_object_unref, NULL); + g_slist_free (servers); + g_free (name); + g_free (charset); +} + +static void +irc_network_dialog_address_edited_cb (GtkCellRendererText *renderer, + gchar *path, + gchar *new_text, + EmpathyIrcNetworkDialog *dialog) +{ + EmpathyIrcServer *server; + GtkTreeModel *model; + GtkTreePath *treepath; + GtkTreeIter iter; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_servers)); + treepath = gtk_tree_path_new_from_string (path); + gtk_tree_model_get_iter (model, &iter, treepath); + gtk_tree_model_get (model, &iter, + COL_SRV_OBJ, &server, + -1); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + COL_ADR, new_text, + -1); + + g_object_set (server, "address", new_text, NULL); + + gtk_tree_path_free (treepath); + g_object_unref (server); +} + +static void +irc_network_dialog_port_edited_cb (GtkCellRendererText *renderer, + gchar *path, + gchar *new_text, + EmpathyIrcNetworkDialog *dialog) +{ + EmpathyIrcServer *server; + GtkTreeModel *model; + GtkTreePath *treepath; + GtkTreeIter iter; + guint port; + + port = strtoul (new_text, NULL, 10); + model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_servers)); + treepath = gtk_tree_path_new_from_string (path); + gtk_tree_model_get_iter (model, &iter, treepath); + gtk_tree_model_get (model, &iter, + COL_SRV_OBJ, &server, + -1); + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + COL_PORT, port, + -1); + + g_object_set (server, "port", port, NULL); + + gtk_tree_path_free (treepath); + g_object_unref (server); +} + +static void +irc_network_dialog_ssl_toggled_cb (GtkCellRendererText *renderer, + gchar *path, + EmpathyIrcNetworkDialog *dialog) +{ + EmpathyIrcServer *server; + GtkTreeModel *model; + GtkTreePath *treepath; + GtkTreeIter iter; + gboolean ssl; + + model = gtk_tree_view_get_model (GTK_TREE_VIEW (dialog->treeview_servers)); + treepath = gtk_tree_path_new_from_string (path); + gtk_tree_model_get_iter (model, &iter, treepath); + gtk_tree_model_get (model, &iter, + COL_SRV_OBJ, &server, + COL_SSL, &ssl, + -1); + ssl = !ssl; + gtk_list_store_set (GTK_LIST_STORE (model), &iter, + COL_SSL, ssl, + -1); + + g_object_set (server, "ssl", ssl, NULL); + + gtk_tree_path_free (treepath); + g_object_unref (server); +} + +static gboolean +irc_network_dialog_network_focus_cb (GtkWidget *widget, + GdkEventFocus *event, + EmpathyIrcNetworkDialog *dialog) +{ + const gchar *str; + + str = gtk_entry_get_text (GTK_ENTRY (widget)); + + g_object_set (dialog->network, "name", str, NULL); + + return FALSE; +} + +static void +irc_network_dialog_network_update_buttons (EmpathyIrcNetworkDialog *dialog) +{ + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreePath *path; + GtkTreeIter iter; + gboolean can_remove = FALSE, can_move_up = FALSE, can_move_down = FALSE; + int selected; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW ( + dialog->treeview_servers)); + + if (gtk_tree_selection_get_selected (selection, &model, &iter)) + { + path = gtk_tree_model_get_path (model, &iter); + + selected = gtk_tree_path_get_indices (path)[0]; + + can_remove = TRUE; + can_move_up = selected > 0; + can_move_down = + selected < gtk_tree_model_iter_n_children (model, NULL) - 1; + + gtk_tree_path_free (path); + } + + gtk_widget_set_sensitive (dialog->button_remove, can_remove); + gtk_widget_set_sensitive (dialog->button_up, can_move_up); + gtk_widget_set_sensitive (dialog->button_down, can_move_down); +} + +static void +irc_network_dialog_button_add_clicked_cb (GtkWidget *widget, + EmpathyIrcNetworkDialog *dialog) +{ + EmpathyIrcServer *server; + GtkListStore *store; + GtkTreeIter iter; + GtkTreePath *path; + GtkTreeViewColumn *column; + + store = GTK_LIST_STORE (gtk_tree_view_get_model ( + GTK_TREE_VIEW (dialog->treeview_servers))); + + server = empathy_irc_server_new (_("new server"), 6667, FALSE); + empathy_irc_network_append_server (dialog->network, server); + add_server_to_store (store, server, &iter); + + path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter); + column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->treeview_servers), + 0); + gtk_tree_view_set_cursor (GTK_TREE_VIEW (dialog->treeview_servers), path, + column, TRUE); + + irc_network_dialog_network_update_buttons (dialog); + + gtk_tree_path_free (path); + g_object_unref (server); +} + +static void +irc_network_dialog_button_remove_clicked_cb (GtkWidget *widget, + EmpathyIrcNetworkDialog *dialog) +{ + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + EmpathyIrcServer *server; + + selection = gtk_tree_view_get_selection ( + GTK_TREE_VIEW (dialog->treeview_servers)); + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + gtk_tree_model_get (model, &iter, COL_SRV_OBJ, &server, -1); + + gtk_list_store_remove (GTK_LIST_STORE (model), &iter); + empathy_irc_network_remove_server (dialog->network, server); + + irc_network_dialog_network_update_buttons (dialog); + + g_object_unref (server); +} + +static void +irc_network_dialog_button_up_clicked_cb (GtkWidget *widget, + EmpathyIrcNetworkDialog *dialog) +{ + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter, iter_prev; + GtkTreePath *path; + gint *pos; + EmpathyIrcServer *server; + + selection = gtk_tree_view_get_selection ( + GTK_TREE_VIEW (dialog->treeview_servers)); + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + path = gtk_tree_model_get_path (model, &iter); + + if (!gtk_tree_path_prev (path)) + { + gtk_tree_path_free (path); + return; + } + + gtk_tree_model_get (model, &iter, COL_SRV_OBJ, &server, -1); + + gtk_tree_model_get_iter (model, &iter_prev, path); + gtk_list_store_swap (GTK_LIST_STORE (model), &iter_prev, &iter); + + pos = gtk_tree_path_get_indices (path); + empathy_irc_network_set_server_position (dialog->network, server, *pos); + + irc_network_dialog_network_update_buttons (dialog); + + g_object_unref (server); + gtk_tree_path_free (path); +} + +static void +irc_network_dialog_button_down_clicked_cb (GtkWidget *widget, + EmpathyIrcNetworkDialog *dialog) +{ + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter, iter_prev; + GtkTreePath *path; + EmpathyIrcServer *server; + gint *pos; + + selection = gtk_tree_view_get_selection ( + GTK_TREE_VIEW (dialog->treeview_servers)); + + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + path = gtk_tree_model_get_path (model, &iter); + + gtk_tree_path_next (path); + if (!gtk_tree_model_get_iter (model, &iter_prev, path)) + { + gtk_tree_path_free (path); + return; + } + + gtk_tree_model_get (model, &iter, COL_SRV_OBJ, &server, -1); + + gtk_list_store_swap (GTK_LIST_STORE (model), &iter_prev, &iter); + + pos = gtk_tree_path_get_indices (path); + empathy_irc_network_set_server_position (dialog->network, server, *pos); + + irc_network_dialog_network_update_buttons (dialog); + + gtk_tree_path_free (path); +} + +static void +irc_network_dialog_selection_changed_cb (GtkTreeSelection *treeselection, + EmpathyIrcNetworkDialog *dialog) +{ + irc_network_dialog_network_update_buttons (dialog); +} + +static void +irc_network_dialog_combobox_charset_changed_cb (GtkWidget *combobox, + EmpathyIrcNetworkDialog *dialog) +{ + const gchar *charset; + + charset = totem_subtitle_encoding_get_selected (GTK_COMBO_BOX (combobox)); + g_object_set (dialog->network, "charset", charset, NULL); +} + +static void +change_network (EmpathyIrcNetworkDialog *dialog, + EmpathyIrcNetwork *network) +{ + GtkListStore *store; + + if (dialog->network == network) + /* No need to change */ + return; + + if (dialog->network != NULL) + { + g_object_unref (dialog->network); + } + + dialog->network = network; + g_object_ref (network); + + store = GTK_LIST_STORE (gtk_tree_view_get_model ( + GTK_TREE_VIEW (dialog->treeview_servers))); + gtk_list_store_clear (store); + + irc_network_dialog_setup (dialog); +} + +/** + * empathy_irc_network_dialog_show: + * @network: the #EmpathyIrcNetwork to configure + * @parent: the parent of this dialog + * + * Display a dialog to configure a given #EmpathyIrcNetwork. + * This function is a singleton so if a configuration dialog already + * exists we use this one to edit the network. + * + * Returns: The displayed #GtkDialog + */ +GtkWidget * +empathy_irc_network_dialog_show (EmpathyIrcNetwork *network, + GtkWidget *parent) +{ + static EmpathyIrcNetworkDialog *dialog = NULL; + GladeXML *glade; + GtkListStore *store; + GtkCellRenderer *renderer; + GtkAdjustment *adjustment; + GtkTreeSelection *selection; + GtkTreeViewColumn *column; + + g_return_val_if_fail (network != NULL, NULL); + + if (dialog != NULL) + { + change_network (dialog, network); + gtk_window_present (GTK_WINDOW (dialog->dialog)); + + return dialog->dialog; + } + + dialog = g_slice_new0 (EmpathyIrcNetworkDialog); + + dialog->network = network; + g_object_ref (dialog->network); + + glade = empathy_glade_get_file ("empathy-account-widget-irc.glade", + "irc_network_dialog", + NULL, + "irc_network_dialog", &dialog->dialog, + "button_close", &dialog->button_close, + "entry_network", &dialog->entry_network, + "combobox_charset", &dialog->combobox_charset, + "treeview_servers", &dialog->treeview_servers, + "button_add", &dialog->button_add, + "button_remove", &dialog->button_remove, + "button_up", &dialog->button_up, + "button_down", &dialog->button_down, + NULL); + + store = gtk_list_store_new (4, G_TYPE_OBJECT, G_TYPE_STRING, + G_TYPE_UINT, G_TYPE_BOOLEAN); + gtk_tree_view_set_model (GTK_TREE_VIEW (dialog->treeview_servers), + GTK_TREE_MODEL (store)); + g_object_unref (store); + + /* address */ + renderer = gtk_cell_renderer_text_new (); + g_object_set (renderer, "editable", TRUE, NULL); + g_signal_connect (renderer, "edited", + G_CALLBACK (irc_network_dialog_address_edited_cb), dialog); + gtk_tree_view_insert_column_with_attributes ( + GTK_TREE_VIEW (dialog->treeview_servers), + -1, _("Server"), renderer, "text", COL_ADR, + NULL); + + /* port */ + adjustment = (GtkAdjustment *) gtk_adjustment_new (6667, 1, G_MAXUINT16, + 1, 10, 0); + renderer = gtk_cell_renderer_spin_new (); + g_object_set (renderer, + "editable", TRUE, + "adjustment", adjustment, + NULL); + g_signal_connect (renderer, "edited", + G_CALLBACK (irc_network_dialog_port_edited_cb), dialog); + gtk_tree_view_insert_column_with_attributes ( + GTK_TREE_VIEW (dialog->treeview_servers), + -1, _("Port"), renderer, "text", COL_PORT, + NULL); + column = gtk_tree_view_get_column (GTK_TREE_VIEW (dialog->treeview_servers), + 1); + gtk_tree_view_column_set_expand (column, TRUE); + + /* SSL */ + renderer = gtk_cell_renderer_toggle_new (); + g_object_set (renderer, "activatable", TRUE, NULL); + g_signal_connect (renderer, "toggled", + G_CALLBACK (irc_network_dialog_ssl_toggled_cb), dialog); + gtk_tree_view_insert_column_with_attributes ( + GTK_TREE_VIEW (dialog->treeview_servers), + -1, _("SSL"), renderer, "active", COL_SSL, + NULL); + + selection = gtk_tree_view_get_selection ( + GTK_TREE_VIEW (dialog->treeview_servers)); + gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); + + /* charset */ + totem_subtitle_encoding_init (GTK_COMBO_BOX (dialog->combobox_charset)); + + irc_network_dialog_setup (dialog); + + empathy_glade_connect (glade, dialog, + "irc_network_dialog", "destroy", irc_network_dialog_destroy_cb, + "button_close", "clicked", irc_network_dialog_close_clicked_cb, + "entry_network", "focus-out-event", irc_network_dialog_network_focus_cb, + "button_add", "clicked", irc_network_dialog_button_add_clicked_cb, + "button_remove", "clicked", irc_network_dialog_button_remove_clicked_cb, + "button_up", "clicked", irc_network_dialog_button_up_clicked_cb, + "button_down", "clicked", irc_network_dialog_button_down_clicked_cb, + "combobox_charset", "changed", irc_network_dialog_combobox_charset_changed_cb, + NULL); + + g_object_unref (glade); + + g_object_add_weak_pointer (G_OBJECT (dialog->dialog), + (gpointer) &dialog); + + g_signal_connect (selection, "changed", + G_CALLBACK (irc_network_dialog_selection_changed_cb), + dialog); + + gtk_window_set_transient_for (GTK_WINDOW (dialog->dialog), + GTK_WINDOW (parent)); + gtk_window_set_modal (GTK_WINDOW (dialog->dialog), TRUE); + + irc_network_dialog_network_update_buttons (dialog); + + return dialog->dialog; +} diff --git a/libempathy-gtk/empathy-irc-network-dialog.h b/libempathy-gtk/empathy-irc-network-dialog.h new file mode 100644 index 00000000..98584969 --- /dev/null +++ b/libempathy-gtk/empathy-irc-network-dialog.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2007-2008 Guillaume Desmottes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Guillaume Desmottes + */ + +#ifndef __EMPATHY_IRC_NETWORK_DIALOG_H__ +#define __EMPATHY_IRC_NETWORK_DIALOG_H__ + +#include + +#include + +G_BEGIN_DECLS + +GtkWidget * empathy_irc_network_dialog_show (EmpathyIrcNetwork *network, + GtkWidget *parent); + +G_END_DECLS + +#endif /* __EMPATHY_IRC_NETWORK_DIALOG_H__ */ diff --git a/libempathy-gtk/totem-subtitle-encoding.c b/libempathy-gtk/totem-subtitle-encoding.c new file mode 100644 index 00000000..e0eef082 --- /dev/null +++ b/libempathy-gtk/totem-subtitle-encoding.c @@ -0,0 +1,585 @@ +/* + * Copyright (C) 2001-2006 Bastien Nocera + * + * encoding list copied from gnome-terminal/encoding.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Totem project hereby grant permission for non-gpl compatible GStreamer + * plugins to be used and distributed together with GStreamer and Totem. This + * permission are above and beyond the permissions granted by the GPL license + * Totem is covered by. + * + * Monday 7th February 2005: Christian Schaller: Add exception clause. + * See license_change file for details. + * + */ + +#include "config.h" +#include +#include "totem-subtitle-encoding.h" +#include + +typedef enum +{ + SUBTITLE_ENCODING_CURRENT_LOCALE, + + SUBTITLE_ENCODING_ISO_8859_6, + SUBTITLE_ENCODING_IBM_864, + SUBTITLE_ENCODING_MAC_ARABIC, + SUBTITLE_ENCODING_WINDOWS_1256, + + SUBTITLE_ENCODING_ARMSCII_8, + + SUBTITLE_ENCODING_ISO_8859_4, + SUBTITLE_ENCODING_ISO_8859_13, + SUBTITLE_ENCODING_WINDOWS_1257, + + SUBTITLE_ENCODING_ISO_8859_14, + + SUBTITLE_ENCODING_ISO_8859_2, + SUBTITLE_ENCODING_IBM_852, + SUBTITLE_ENCODING_MAC_CE, + SUBTITLE_ENCODING_WINDOWS_1250, + + SUBTITLE_ENCODING_GB18030, + SUBTITLE_ENCODING_GB2312, + SUBTITLE_ENCODING_GBK, + SUBTITLE_ENCODING_HZ, + + SUBTITLE_ENCODING_BIG5, + SUBTITLE_ENCODING_BIG5_HKSCS, + SUBTITLE_ENCODING_EUC_TW, + + SUBTITLE_ENCODING_MAC_CROATIAN, + + SUBTITLE_ENCODING_ISO_8859_5, + SUBTITLE_ENCODING_IBM_855, + SUBTITLE_ENCODING_ISO_IR_111, + SUBTITLE_ENCODING_KOI8_R, + SUBTITLE_ENCODING_MAC_CYRILLIC, + SUBTITLE_ENCODING_WINDOWS_1251, + + SUBTITLE_ENCODING_CP_866, + + SUBTITLE_ENCODING_MAC_UKRAINIAN, + SUBTITLE_ENCODING_KOI8_U, + + SUBTITLE_ENCODING_GEOSTD8, + + SUBTITLE_ENCODING_ISO_8859_7, + SUBTITLE_ENCODING_MAC_GREEK, + SUBTITLE_ENCODING_WINDOWS_1253, + + SUBTITLE_ENCODING_MAC_GUJARATI, + + SUBTITLE_ENCODING_MAC_GURMUKHI, + + SUBTITLE_ENCODING_ISO_8859_8_I, + SUBTITLE_ENCODING_IBM_862, + SUBTITLE_ENCODING_MAC_HEBREW, + SUBTITLE_ENCODING_WINDOWS_1255, + + SUBTITLE_ENCODING_ISO_8859_8, + + SUBTITLE_ENCODING_MAC_DEVANAGARI, + + SUBTITLE_ENCODING_MAC_ICELANDIC, + + SUBTITLE_ENCODING_EUC_JP, + SUBTITLE_ENCODING_ISO_2022_JP, + SUBTITLE_ENCODING_SHIFT_JIS, + + SUBTITLE_ENCODING_EUC_KR, + SUBTITLE_ENCODING_ISO_2022_KR, + SUBTITLE_ENCODING_JOHAB, + SUBTITLE_ENCODING_UHC, + + SUBTITLE_ENCODING_ISO_8859_10, + + SUBTITLE_ENCODING_MAC_FARSI, + + SUBTITLE_ENCODING_ISO_8859_16, + SUBTITLE_ENCODING_MAC_ROMANIAN, + + SUBTITLE_ENCODING_ISO_8859_3, + + SUBTITLE_ENCODING_TIS_620, + + SUBTITLE_ENCODING_ISO_8859_9, + SUBTITLE_ENCODING_IBM_857, + SUBTITLE_ENCODING_MAC_TURKISH, + SUBTITLE_ENCODING_WINDOWS_1254, + + SUBTITLE_ENCODING_UTF_7, + SUBTITLE_ENCODING_UTF_8, + SUBTITLE_ENCODING_UTF_16, + SUBTITLE_ENCODING_UCS_2, + SUBTITLE_ENCODING_UCS_4, + + SUBTITLE_ENCODING_ISO_8859_1, + SUBTITLE_ENCODING_ISO_8859_15, + SUBTITLE_ENCODING_IBM_850, + SUBTITLE_ENCODING_MAC_ROMAN, + SUBTITLE_ENCODING_WINDOWS_1252, + + SUBTITLE_ENCODING_TCVN, + SUBTITLE_ENCODING_VISCII, + SUBTITLE_ENCODING_WINDOWS_1258, + + SUBTITLE_ENCODING_LAST +} SubtitleEncodingIndex; + + +typedef struct +{ + int index; + gboolean valid; + char *charset; + char *name; +} SubtitleEncoding; + + +static SubtitleEncoding encodings[] = { + + {SUBTITLE_ENCODING_CURRENT_LOCALE, TRUE, + NULL, N_("Current Locale")}, + + {SUBTITLE_ENCODING_ISO_8859_6, FALSE, + "ISO-8859-6", N_("Arabic")}, + {SUBTITLE_ENCODING_IBM_864, FALSE, + "IBM864", N_("Arabic")}, + {SUBTITLE_ENCODING_MAC_ARABIC, FALSE, + "MAC_ARABIC", N_("Arabic")}, + {SUBTITLE_ENCODING_WINDOWS_1256, FALSE, + "WINDOWS-1256", N_("Arabic")}, + + {SUBTITLE_ENCODING_ARMSCII_8, FALSE, + "ARMSCII-8", N_("Armenian")}, + + {SUBTITLE_ENCODING_ISO_8859_4, FALSE, + "ISO-8859-4", N_("Baltic")}, + {SUBTITLE_ENCODING_ISO_8859_13, FALSE, + "ISO-8859-13", N_("Baltic")}, + {SUBTITLE_ENCODING_WINDOWS_1257, FALSE, + "WINDOWS-1257", N_("Baltic")}, + + {SUBTITLE_ENCODING_ISO_8859_14, FALSE, + "ISO-8859-14", N_("Celtic")}, + + {SUBTITLE_ENCODING_ISO_8859_2, FALSE, + "ISO-8859-2", N_("Central European")}, + {SUBTITLE_ENCODING_IBM_852, FALSE, + "IBM852", N_("Central European")}, + {SUBTITLE_ENCODING_MAC_CE, FALSE, + "MAC_CE", N_("Central European")}, + {SUBTITLE_ENCODING_WINDOWS_1250, FALSE, + "WINDOWS-1250", N_("Central European")}, + + {SUBTITLE_ENCODING_GB18030, FALSE, + "GB18030", N_("Chinese Simplified")}, + {SUBTITLE_ENCODING_GB2312, FALSE, + "GB2312", N_("Chinese Simplified")}, + {SUBTITLE_ENCODING_GBK, FALSE, + "GBK", N_("Chinese Simplified")}, + {SUBTITLE_ENCODING_HZ, FALSE, + "HZ", N_("Chinese Simplified")}, + + {SUBTITLE_ENCODING_BIG5, FALSE, + "BIG5", N_("Chinese Traditional")}, + {SUBTITLE_ENCODING_BIG5_HKSCS, FALSE, + "BIG5-HKSCS", N_("Chinese Traditional")}, + {SUBTITLE_ENCODING_EUC_TW, FALSE, + "EUC-TW", N_("Chinese Traditional")}, + + {SUBTITLE_ENCODING_MAC_CROATIAN, FALSE, + "MAC_CROATIAN", N_("Croatian")}, + + {SUBTITLE_ENCODING_ISO_8859_5, FALSE, + "ISO-8859-5", N_("Cyrillic")}, + {SUBTITLE_ENCODING_IBM_855, FALSE, + "IBM855", N_("Cyrillic")}, + {SUBTITLE_ENCODING_ISO_IR_111, FALSE, + "ISO-IR-111", N_("Cyrillic")}, + {SUBTITLE_ENCODING_KOI8_R, FALSE, + "KOI8-R", N_("Cyrillic")}, + {SUBTITLE_ENCODING_MAC_CYRILLIC, FALSE, + "MAC-CYRILLIC", N_("Cyrillic")}, + {SUBTITLE_ENCODING_WINDOWS_1251, FALSE, + "WINDOWS-1251", N_("Cyrillic")}, + + {SUBTITLE_ENCODING_CP_866, FALSE, + "CP866", N_("Cyrillic/Russian")}, + + {SUBTITLE_ENCODING_MAC_UKRAINIAN, FALSE, + "MAC_UKRAINIAN", N_("Cyrillic/Ukrainian")}, + {SUBTITLE_ENCODING_KOI8_U, FALSE, + "KOI8-U", N_("Cyrillic/Ukrainian")}, + + {SUBTITLE_ENCODING_GEOSTD8, FALSE, + "GEORGIAN-PS", N_("Georgian")}, + + {SUBTITLE_ENCODING_ISO_8859_7, FALSE, + "ISO-8859-7", N_("Greek")}, + {SUBTITLE_ENCODING_MAC_GREEK, FALSE, + "MAC_GREEK", N_("Greek")}, + {SUBTITLE_ENCODING_WINDOWS_1253, FALSE, + "WINDOWS-1253", N_("Greek")}, + + {SUBTITLE_ENCODING_MAC_GUJARATI, FALSE, + "MAC_GUJARATI", N_("Gujarati")}, + + {SUBTITLE_ENCODING_MAC_GURMUKHI, FALSE, + "MAC_GURMUKHI", N_("Gurmukhi")}, + + {SUBTITLE_ENCODING_ISO_8859_8_I, FALSE, + "ISO-8859-8-I", N_("Hebrew")}, + {SUBTITLE_ENCODING_IBM_862, FALSE, + "IBM862", N_("Hebrew")}, + {SUBTITLE_ENCODING_MAC_HEBREW, FALSE, + "MAC_HEBREW", N_("Hebrew")}, + {SUBTITLE_ENCODING_WINDOWS_1255, FALSE, + "WINDOWS-1255", N_("Hebrew")}, + + {SUBTITLE_ENCODING_ISO_8859_8, FALSE, + "ISO-8859-8", N_("Hebrew Visual")}, + + {SUBTITLE_ENCODING_MAC_DEVANAGARI, FALSE, + "MAC_DEVANAGARI", N_("Hindi")}, + + {SUBTITLE_ENCODING_MAC_ICELANDIC, FALSE, + "MAC_ICELANDIC", N_("Icelandic")}, + + {SUBTITLE_ENCODING_EUC_JP, FALSE, + "EUC-JP", N_("Japanese")}, + {SUBTITLE_ENCODING_ISO_2022_JP, FALSE, + "ISO2022JP", N_("Japanese")}, + {SUBTITLE_ENCODING_SHIFT_JIS, FALSE, + "SHIFT-JIS", N_("Japanese")}, + + {SUBTITLE_ENCODING_EUC_KR, FALSE, + "EUC-KR", N_("Korean")}, + {SUBTITLE_ENCODING_ISO_2022_KR, FALSE, + "ISO2022KR", N_("Korean")}, + {SUBTITLE_ENCODING_JOHAB, FALSE, + "JOHAB", N_("Korean")}, + {SUBTITLE_ENCODING_UHC, FALSE, + "UHC", N_("Korean")}, + + {SUBTITLE_ENCODING_ISO_8859_10, FALSE, + "ISO-8859-10", N_("Nordic")}, + + {SUBTITLE_ENCODING_MAC_FARSI, FALSE, + "MAC_FARSI", N_("Persian")}, + + {SUBTITLE_ENCODING_ISO_8859_16, FALSE, + "ISO-8859-16", N_("Romanian")}, + {SUBTITLE_ENCODING_MAC_ROMANIAN, FALSE, + "MAC_ROMANIAN", N_("Romanian")}, + + {SUBTITLE_ENCODING_ISO_8859_3, FALSE, + "ISO-8859-3", N_("South European")}, + + {SUBTITLE_ENCODING_TIS_620, FALSE, + "TIS-620", N_("Thai")}, + + {SUBTITLE_ENCODING_ISO_8859_9, FALSE, + "ISO-8859-9", N_("Turkish")}, + {SUBTITLE_ENCODING_IBM_857, FALSE, + "IBM857", N_("Turkish")}, + {SUBTITLE_ENCODING_MAC_TURKISH, FALSE, + "MAC_TURKISH", N_("Turkish")}, + {SUBTITLE_ENCODING_WINDOWS_1254, FALSE, + "WINDOWS-1254", N_("Turkish")}, + + {SUBTITLE_ENCODING_UTF_7, FALSE, + "UTF-7", N_("Unicode")}, + {SUBTITLE_ENCODING_UTF_8, FALSE, + "UTF-8", N_("Unicode")}, + {SUBTITLE_ENCODING_UTF_16, FALSE, + "UTF-16", N_("Unicode")}, + {SUBTITLE_ENCODING_UCS_2, FALSE, + "UCS-2", N_("Unicode")}, + {SUBTITLE_ENCODING_UCS_4, FALSE, + "UCS-4", N_("Unicode")}, + + {SUBTITLE_ENCODING_ISO_8859_1, FALSE, + "ISO-8859-1", N_("Western")}, + {SUBTITLE_ENCODING_ISO_8859_15, FALSE, + "ISO-8859-15", N_("Western")}, + {SUBTITLE_ENCODING_IBM_850, FALSE, + "IBM850", N_("Western")}, + {SUBTITLE_ENCODING_MAC_ROMAN, FALSE, + "MAC_ROMAN", N_("Western")}, + {SUBTITLE_ENCODING_WINDOWS_1252, FALSE, + "WINDOWS-1252", N_("Western")}, + + {SUBTITLE_ENCODING_TCVN, FALSE, + "TCVN", N_("Vietnamese")}, + {SUBTITLE_ENCODING_VISCII, FALSE, + "VISCII", N_("Vietnamese")}, + {SUBTITLE_ENCODING_WINDOWS_1258, FALSE, + "WINDOWS-1258", N_("Vietnamese")} +}; + +static const SubtitleEncoding * +find_encoding_by_charset (const char *charset) +{ + int i; + + i = 1; /* skip current locale */ + while (i < SUBTITLE_ENCODING_LAST) { + if (strcasecmp (charset, encodings[i].charset) == 0) + return &encodings[i]; + + ++i; + } + + if (strcasecmp (charset, + encodings[SUBTITLE_ENCODING_CURRENT_LOCALE].charset) == 0) + return &encodings[SUBTITLE_ENCODING_CURRENT_LOCALE]; + + return NULL; +} + +static void +subtitle_encoding_init (void) +{ + int i; + gsize bytes_read, bytes_written; + gchar *converted; + gchar ascii_sample[96]; + + g_get_charset ((const char **) + &encodings[SUBTITLE_ENCODING_CURRENT_LOCALE].charset); + + g_assert (G_N_ELEMENTS (encodings) == SUBTITLE_ENCODING_LAST); + + /* Initialize the sample text with all of the printing ASCII characters + * from space (32) to the tilde (126), 95 in all. */ + for (i = 0; i < (int) sizeof (ascii_sample); i++) + ascii_sample[i] = i + 32; + + ascii_sample[sizeof (ascii_sample) - 1] = '\0'; + + i = 0; + while (i < SUBTITLE_ENCODING_LAST) { + bytes_read = 0; + bytes_written = 0; + + g_assert (encodings[i].index == i); + + /* Translate the names */ + encodings[i].name = _(encodings[i].name); + + /* Test that the encoding is a proper superset of ASCII (which naive + * apps are going to use anyway) by attempting to validate the text + * using the current encoding. This also flushes out any encodings + * which the underlying GIConv implementation can't support. + */ + converted = g_convert (ascii_sample, sizeof (ascii_sample) - 1, + encodings[i].charset, encodings[i].charset, + &bytes_read, &bytes_written, NULL); + + /* The encoding is only valid if ASCII passes through cleanly. */ + if (i == SUBTITLE_ENCODING_CURRENT_LOCALE) + encodings[i].valid = TRUE; + else + encodings[i].valid = + (bytes_read == (sizeof (ascii_sample) - 1)) && + (converted != NULL) && (strcmp (converted, ascii_sample) == 0); + +#ifdef DEBUG_ENCODINGS + if (!encodings[i].valid) { + g_print ("Rejecting encoding %s as invalid:\n", encodings[i].charset); + g_print (" input \"%s\"\n", ascii_sample); + g_print (" output \"%s\"\n\n", converted ? converted : "(null)"); + } +#endif + + /* Discard the converted string. */ + g_free (converted); + + ++i; + } +} + +static int +subtitle_encoding_get_index (const char *charset) +{ + const SubtitleEncoding *e; + + e = find_encoding_by_charset (charset); + if (e != NULL) + return e->index; + else + return SUBTITLE_ENCODING_CURRENT_LOCALE; +} + +static const char * +subtitle_encoding_get_charset (int index) +{ + const SubtitleEncoding *e; + + if (index >= SUBTITLE_ENCODING_LAST) + e = &encodings[SUBTITLE_ENCODING_CURRENT_LOCALE]; + else if (index < SUBTITLE_ENCODING_CURRENT_LOCALE) + e = &encodings[SUBTITLE_ENCODING_CURRENT_LOCALE]; + else if (!encodings[index].valid) + e = &encodings[SUBTITLE_ENCODING_CURRENT_LOCALE]; + else + e = &encodings[index]; + return e->charset; +} + +enum +{ + INDEX_COL, + NAME_COL +}; + +static gint +compare (GtkTreeModel * model, GtkTreeIter * a, GtkTreeIter * b, gpointer data) +{ + gchar *str_a, *str_b; + gint result; + + gtk_tree_model_get (model, a, NAME_COL, &str_a, -1); + gtk_tree_model_get (model, b, NAME_COL, &str_b, -1); + + result = strcmp (str_a, str_b); + + g_free (str_a); + g_free (str_b); + + return result; +} + +static void +is_encoding_sensitive (GtkCellLayout * cell_layout, + GtkCellRenderer * cell, + GtkTreeModel * tree_model, GtkTreeIter * iter, gpointer data) +{ + + gboolean sensitive; + + sensitive = !gtk_tree_model_iter_has_child (tree_model, iter); + g_object_set (cell, "sensitive", sensitive, NULL); +} + +static GtkTreeModel * +subtitle_encoding_create_store (void) +{ + gchar *label; + gchar *lastlang = ""; + GtkTreeIter iter, iter2; + GtkTreeStore *store; + int i; + + store = gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_STRING); + + for (i = 0; i < SUBTITLE_ENCODING_LAST; i++) { + if (encodings[i].valid) { + if (strcmp (lastlang, encodings[i].name)) { + lastlang = encodings[i].name; + gtk_tree_store_append (store, &iter, NULL); + gtk_tree_store_set (store, &iter, INDEX_COL, + -1, NAME_COL, lastlang, -1); + } + label = g_strdup_printf("%s (%s)", lastlang, encodings[i].charset); + gtk_tree_store_append (store, &iter2, &iter); + gtk_tree_store_set (store, &iter2, INDEX_COL, + encodings[i].index, NAME_COL, label, -1); + g_free(label); + } + } + gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (store), + compare, NULL, NULL); + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store), + NAME_COL, GTK_SORT_ASCENDING); + return GTK_TREE_MODEL (store); +} + +static void +subtitle_encoding_combo_render (GtkComboBox * combo) +{ + GtkCellRenderer *renderer; + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer, + "text", NAME_COL, NULL); + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo), + renderer, is_encoding_sensitive, NULL, NULL); +} + +const char * +totem_subtitle_encoding_get_selected (GtkComboBox * combo) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gint index = -1; + + model = gtk_combo_box_get_model (combo); + if (gtk_combo_box_get_active_iter (combo, &iter)) { + gtk_tree_model_get (model, &iter, INDEX_COL, &index, -1); + } + if (index == -1) + return NULL; + return subtitle_encoding_get_charset (index); +} + +void +totem_subtitle_encoding_set (GtkComboBox * combo, const char *encoding) +{ + GtkTreeModel *model; + GtkTreeIter iter, iter2; + gint index, i; + + g_return_if_fail (encoding != NULL); + + model = gtk_combo_box_get_model (combo); + index = subtitle_encoding_get_index (encoding); + gtk_tree_model_get_iter_first (model, &iter); + do { + if (!gtk_tree_model_iter_has_child (model, &iter)) + continue; + if (!gtk_tree_model_iter_children (model, &iter2, &iter)) + continue; + do { + gtk_tree_model_get (model, &iter2, INDEX_COL, &i, -1); + if (i == index) + break; + } while (gtk_tree_model_iter_next (model, &iter2)); + if (i == index) + break; + } while (gtk_tree_model_iter_next (model, &iter)); + gtk_combo_box_set_active_iter (combo, &iter2); +} + +void +totem_subtitle_encoding_init (GtkComboBox *combo) +{ + GtkTreeModel *model; + subtitle_encoding_init (); + model = subtitle_encoding_create_store (); + gtk_combo_box_set_model (combo, model); + g_object_unref (model); + subtitle_encoding_combo_render (combo); +} + +/* + * vim: sw=2 ts=8 cindent noai bs=2 + */ diff --git a/libempathy-gtk/totem-subtitle-encoding.h b/libempathy-gtk/totem-subtitle-encoding.h new file mode 100644 index 00000000..7283f003 --- /dev/null +++ b/libempathy-gtk/totem-subtitle-encoding.h @@ -0,0 +1,12 @@ +/* Encoding stuff */ + +#ifndef TOTEM_SUBTITLE_ENCODING_H +#define TOTEM_SUBTITLE_ENCODING_H + +#include + +void totem_subtitle_encoding_init (GtkComboBox *combo); +void totem_subtitle_encoding_set (GtkComboBox *combo, const char *encoding); +const char * totem_subtitle_encoding_get_selected (GtkComboBox *combo); + +#endif /* SUBTITLE_ENCODING_H */ diff --git a/libempathy/Makefile.am b/libempathy/Makefile.am index 5d0c021b..b952be27 100644 --- a/libempathy/Makefile.am +++ b/libempathy/Makefile.am @@ -41,7 +41,10 @@ libempathy_la_SOURCES = \ empathy-chandler.c \ empathy-filter.c \ empathy-idle.c \ - empathy-log-manager.c + empathy-log-manager.c \ + empathy-irc-network-manager.c \ + empathy-irc-network.c \ + empathy-irc-server.c # do not distribute generated files nodist_libempathy_la_SOURCES =\ @@ -78,7 +81,10 @@ libempathy_headers = \ empathy-chandler.h \ empathy-filter.h \ empathy-idle.h \ - empathy-log-manager.h + empathy-log-manager.h \ + empathy-irc-network-manager.h \ + empathy-irc-network.h \ + empathy-irc-server.h libempathy_includedir = $(includedir)/libempathy/ libempathy_include_HEADERS = \ @@ -154,12 +160,17 @@ dtddir = $(datadir)/empathy dtd_DATA = \ empathy-status-presets.dtd \ empathy-contact-groups.dtd \ - empathy-chatroom-manager.dtd + empathy-chatroom-manager.dtd \ + empathy-irc-networks.dtd stylesheetdir = $(datadir)/empathy stylesheet_DATA = \ empathy-log-manager.xsl +ircnetworksdir = $(datadir)/empathy +ircnetworks_DATA = \ + irc-networks.xml + pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libempathy.pc @@ -169,7 +180,8 @@ EXTRA_DIST = \ empathy-filter.xml \ tp-stream-engine.xml \ $(stylesheet_DATA) \ - $(dtd_DATA) + $(dtd_DATA) \ + $(ircnetworks_DATA) CLEANFILES = \ $(BUILT_SOURCES) \ diff --git a/libempathy/empathy-irc-network-manager.c b/libempathy/empathy-irc-network-manager.c new file mode 100644 index 00000000..f88b93bc --- /dev/null +++ b/libempathy/empathy-irc-network-manager.c @@ -0,0 +1,801 @@ +/* + * Copyright (C) 2007-2008 Guillaume Desmottes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Guillaume Desmottes + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "empathy-utils.h" +#include "empathy-irc-network-manager.h" + +#define DEBUG_DOMAIN "IrcNetworkManager" +#define IRC_NETWORKS_DTD_FILENAME "empathy-irc-networks.dtd" +#define SAVE_TIMER 4 + +G_DEFINE_TYPE (EmpathyIrcNetworkManager, empathy_irc_network_manager, + G_TYPE_OBJECT); + +/* properties */ +enum +{ + PROP_GLOBAL_FILE = 1, + PROP_USER_FILE, + LAST_PROPERTY +}; + +typedef struct _EmpathyIrcNetworkManagerPrivate + EmpathyIrcNetworkManagerPrivate; + +struct _EmpathyIrcNetworkManagerPrivate { + GHashTable *networks; + + gchar *global_file; + gchar *user_file; + guint last_id; + + /* Do we have to save modifications to the user file ? */ + gboolean have_to_save; + /* Are we loading networks from XML files ? */ + gboolean loading; + /* source id of the autosave timer */ + gint save_timer_id; +}; + +#define EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE(obj)\ + ((EmpathyIrcNetworkManagerPrivate *) obj->priv) + +static void irc_network_manager_load_servers ( + EmpathyIrcNetworkManager *manager); +static gboolean irc_network_manager_file_parse ( + EmpathyIrcNetworkManager *manager, const gchar *filename, + gboolean user_defined); +static gboolean irc_network_manager_file_save ( + EmpathyIrcNetworkManager *manager); + +static void +empathy_irc_network_manager_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyIrcNetworkManager *self = EMPATHY_IRC_NETWORK_MANAGER (object); + EmpathyIrcNetworkManagerPrivate *priv = + EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + + switch (property_id) + { + case PROP_GLOBAL_FILE: + g_value_set_string (value, priv->global_file); + break; + case PROP_USER_FILE: + g_value_set_string (value, priv->user_file); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +empathy_irc_network_manager_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyIrcNetworkManager *self = EMPATHY_IRC_NETWORK_MANAGER (object); + EmpathyIrcNetworkManagerPrivate *priv = + EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + + switch (property_id) + { + case PROP_GLOBAL_FILE: + g_free (priv->global_file); + priv->global_file = g_value_dup_string (value); + break; + case PROP_USER_FILE: + g_free (priv->user_file); + priv->user_file = g_value_dup_string (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static GObject * +empathy_irc_network_manager_constructor (GType type, + guint n_props, + GObjectConstructParam *props) +{ + GObject *obj; + EmpathyIrcNetworkManager *self; + + /* Parent constructor chain */ + obj = G_OBJECT_CLASS (empathy_irc_network_manager_parent_class)-> + constructor (type, n_props, props); + + self = EMPATHY_IRC_NETWORK_MANAGER (obj); + irc_network_manager_load_servers (self); + + return obj; +} + +static void +empathy_irc_network_manager_finalize (GObject *object) +{ + EmpathyIrcNetworkManager *self = EMPATHY_IRC_NETWORK_MANAGER (object); + EmpathyIrcNetworkManagerPrivate *priv = + EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + + if (priv->save_timer_id > 0) + { + g_source_remove (priv->save_timer_id); + } + + if (priv->have_to_save) + { + irc_network_manager_file_save (self); + } + + g_free (priv->global_file); + g_free (priv->user_file); + + g_hash_table_destroy (priv->networks); + + G_OBJECT_CLASS (empathy_irc_network_manager_parent_class)->finalize (object); +} + +static void +empathy_irc_network_manager_init (EmpathyIrcNetworkManager *self) +{ + EmpathyIrcNetworkManagerPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + EMPATHY_TYPE_IRC_NETWORK_MANAGER, EmpathyIrcNetworkManagerPrivate); + + self->priv = priv; + + priv->networks = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref); + + priv->last_id = 0; + + priv->have_to_save = FALSE; + priv->loading = FALSE; + priv->save_timer_id = 0; +} + +static void +empathy_irc_network_manager_class_init (EmpathyIrcNetworkManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *param_spec; + + object_class->constructor = empathy_irc_network_manager_constructor; + object_class->get_property = empathy_irc_network_manager_get_property; + object_class->set_property = empathy_irc_network_manager_set_property; + + g_type_class_add_private (object_class, + sizeof (EmpathyIrcNetworkManagerPrivate)); + + object_class->finalize = empathy_irc_network_manager_finalize; + + param_spec = g_param_spec_string ( + "global-file", + "path of the global networks file", + "The path of the system-wide filename from which we have to load" + " the networks list", + NULL, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB); + g_object_class_install_property (object_class, PROP_GLOBAL_FILE, param_spec); + + param_spec = g_param_spec_string ( + "user-file", + "path of the user networks file", + "The path of user's filename from which we have to load" + " the networks list and to which we'll save his modifications", + NULL, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB); + g_object_class_install_property (object_class, PROP_USER_FILE, param_spec); +} + +/** + * empathy_irc_network_manager_new: + * @global_file: the path of the global networks file, or %NULL + * @user_file: the path of the user networks file, or %NULL + * + * Creates a new #EmpathyIrcNetworkManager + * + * Returns: a new #EmpathyIrcNetworkManager + */ +EmpathyIrcNetworkManager * +empathy_irc_network_manager_new (const gchar *global_file, + const gchar *user_file) +{ + EmpathyIrcNetworkManager *manager; + + manager = g_object_new (EMPATHY_TYPE_IRC_NETWORK_MANAGER, + "global-file", global_file, + "user-file", user_file, + NULL); + + return manager; +} + +static gboolean +save_timeout (EmpathyIrcNetworkManager *self) +{ + EmpathyIrcNetworkManagerPrivate *priv = + EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + + priv->save_timer_id = 0; + irc_network_manager_file_save (self); + + return FALSE; +} + +static void +reset_save_timeout (EmpathyIrcNetworkManager *self) +{ + EmpathyIrcNetworkManagerPrivate *priv = + EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + + if (priv->save_timer_id > 0) + { + g_source_remove (priv->save_timer_id); + } + + priv->save_timer_id = g_timeout_add_seconds (SAVE_TIMER, + (GSourceFunc) save_timeout, self); +} + +static void +network_modified (EmpathyIrcNetwork *network, + EmpathyIrcNetworkManager *self) +{ + EmpathyIrcNetworkManagerPrivate *priv = + EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + + network->user_defined = TRUE; + + if (!priv->loading) + { + priv->have_to_save = TRUE; + reset_save_timeout (self); + } +} + +static void +add_network (EmpathyIrcNetworkManager *self, + EmpathyIrcNetwork *network, + const gchar *id) +{ + EmpathyIrcNetworkManagerPrivate *priv = + EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + + g_hash_table_insert (priv->networks, g_strdup (id), g_object_ref (network)); + + g_signal_connect (network, "modified", G_CALLBACK (network_modified), self); +} + +/** + * empathy_irc_network_manager_add: + * @manager: an #EmpathyIrcNetworkManager + * @network: the #EmpathyIrcNetwork to add + * + * Add an #EmpathyIrcNetwork to the given #EmpathyIrcNetworkManager. + * + */ +void +empathy_irc_network_manager_add (EmpathyIrcNetworkManager *self, + EmpathyIrcNetwork *network) +{ + EmpathyIrcNetworkManagerPrivate *priv; + gchar *id = NULL; + + g_return_if_fail (EMPATHY_IS_IRC_NETWORK_MANAGER (self)); + g_return_if_fail (EMPATHY_IS_IRC_NETWORK (network)); + + priv = EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + + /* generate an id for this network */ + do + { + g_free (id); + id = g_strdup_printf ("id%u", ++priv->last_id); + } while (g_hash_table_lookup (priv->networks, id) != NULL && + priv->last_id < G_MAXUINT); + + if (priv->last_id == G_MAXUINT) + { + empathy_debug (DEBUG_DOMAIN, + "Can't add network: too many networks using a similiar ID"); + return; + } + + empathy_debug (DEBUG_DOMAIN, "add server with \"%s\" as ID", id); + + network->user_defined = TRUE; + add_network (self, network, id); + + priv->have_to_save = TRUE; + reset_save_timeout (self); + + g_free (id); +} + +/** + * empathy_irc_network_manager_remove: + * @manager: an #EmpathyIrcNetworkManager + * @network: the #EmpathyIrcNetwork to remove + * + * Remove an #EmpathyIrcNetwork from the given #EmpathyIrcNetworkManager. + * + */ +void +empathy_irc_network_manager_remove (EmpathyIrcNetworkManager *self, + EmpathyIrcNetwork *network) +{ + EmpathyIrcNetworkManagerPrivate *priv; + + g_return_if_fail (EMPATHY_IS_IRC_NETWORK_MANAGER (self)); + g_return_if_fail (EMPATHY_IS_IRC_NETWORK (network)); + + priv = EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + + network->user_defined = TRUE; + network->dropped = TRUE; + + priv->have_to_save = TRUE; + reset_save_timeout (self); +} + +static void +append_network_to_list (const gchar *id, + EmpathyIrcNetwork *network, + GSList **list) +{ + if (network->dropped) + return; + + *list = g_slist_prepend (*list, g_object_ref (network)); +} + +/** + * empathy_irc_network_manager_get_networks: + * @manager: an #EmpathyIrcNetworkManager + * + * Get the list of #EmpathyIrcNetwork associated with the given + * manager. + * + * Returns: a new #GSList of refed #EmpathyIrcNetwork + */ +GSList * +empathy_irc_network_manager_get_networks (EmpathyIrcNetworkManager *self) +{ + EmpathyIrcNetworkManagerPrivate *priv; + GSList *irc_networks = NULL; + + g_return_val_if_fail (EMPATHY_IS_IRC_NETWORK_MANAGER (self), NULL); + + priv = EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + + g_hash_table_foreach (priv->networks, (GHFunc) append_network_to_list, + &irc_networks); + + return irc_networks; +} + +/* + * API to save/load and parse the irc_networks file. + */ + +static void +load_global_file (EmpathyIrcNetworkManager *self) +{ + EmpathyIrcNetworkManagerPrivate *priv = + EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + + if (priv->global_file == NULL) + return; + + if (!g_file_test (priv->global_file, G_FILE_TEST_EXISTS)) + { + empathy_debug (DEBUG_DOMAIN, "Global networks file %s doesn't exist", + priv->global_file); + return; + } + + irc_network_manager_file_parse (self, priv->global_file, FALSE); +} + +static void +load_user_file (EmpathyIrcNetworkManager *self) +{ + EmpathyIrcNetworkManagerPrivate *priv = + EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + + if (priv->user_file == NULL) + return; + + if (!g_file_test (priv->user_file, G_FILE_TEST_EXISTS)) + { + empathy_debug (DEBUG_DOMAIN, "User networks file %s doesn't exist", + priv->global_file); + return; + } + + irc_network_manager_file_parse (self, priv->user_file, TRUE); +} + +static void +irc_network_manager_load_servers (EmpathyIrcNetworkManager *self) +{ + EmpathyIrcNetworkManagerPrivate *priv = + EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + + priv->loading = TRUE; + + load_global_file (self); + load_user_file (self); + + priv->loading = FALSE; + priv->have_to_save = FALSE; +} + +static void +irc_network_manager_parse_irc_server (EmpathyIrcNetwork *network, + xmlNodePtr node) +{ + xmlNodePtr server_node; + + for (server_node = node->children; server_node; + server_node = server_node->next) + { + gchar *address = NULL, *port = NULL, *ssl = NULL; + + if (strcmp (server_node->name, "server") != 0) + continue; + + address = xmlGetProp (server_node, "address"); + port = xmlGetProp (server_node, "port"); + ssl = xmlGetProp (server_node, "ssl"); + + if (address != NULL) + { + gint port_nb = 0; + gboolean have_ssl = FALSE; + EmpathyIrcServer *server; + + if (port != NULL) + port_nb = strtol (port, NULL, 10); + + if (port_nb <= 0 || port_nb > G_MAXUINT16) + port_nb = 6667; + + if (ssl == NULL || strcmp (ssl, "TRUE") == 0) + have_ssl = TRUE; + + empathy_debug (DEBUG_DOMAIN, "parsed server %s port %d ssl %d", + address, port_nb, have_ssl); + + server = empathy_irc_server_new (address, port_nb, have_ssl); + empathy_irc_network_append_server (network, server); + } + + if (address) + xmlFree (address); + if (port) + xmlFree (port); + if (ssl) + xmlFree (ssl); + } +} + +static void +irc_network_manager_parse_irc_network (EmpathyIrcNetworkManager *self, + xmlNodePtr node, + gboolean user_defined) +{ + EmpathyIrcNetworkManagerPrivate *priv = + EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + EmpathyIrcNetwork *network; + xmlNodePtr child; + gchar *str; + gchar *id, *name; + + id = xmlGetProp (node, "id"); + if (xmlHasProp (node, "dropped")) + { + if (!user_defined) + { + empathy_debug (DEBUG_DOMAIN, "the \"dropped\" attribute shouldn't be" + " used in the global file"); + } + + network = g_hash_table_lookup (priv->networks, id); + if (network != NULL) + { + network->dropped = TRUE; + network->user_defined = TRUE; + } + xmlFree (id); + return; + } + + if (!xmlHasProp (node, "name")) + return; + + name = xmlGetProp (node, "name"); + network = empathy_irc_network_new (name); + + if (xmlHasProp (node, "network_charset")) + { + gchar *charset; + charset = xmlGetProp (node, "network_charset"); + g_object_set (network, "charset", charset, NULL); + xmlFree (charset); + } + + add_network (self, network, id); + empathy_debug (DEBUG_DOMAIN, "add network %s (id %s)", name, id); + + for (child = node->children; child; child = child->next) + { + gchar *tag; + + tag = (gchar *) child->name; + str = (gchar *) xmlNodeGetContent (child); + + if (!str) + continue; + + if (strcmp (tag, "servers") == 0) + { + irc_network_manager_parse_irc_server (network, child); + } + + xmlFree (str); + } + + network->user_defined = user_defined; + g_object_unref (network); + xmlFree (name); + xmlFree (id); +} + +static gboolean +irc_network_manager_file_parse (EmpathyIrcNetworkManager *self, + const gchar *filename, + gboolean user_defined) +{ + EmpathyIrcNetworkManagerPrivate *priv; + xmlParserCtxtPtr ctxt; + xmlDocPtr doc; + xmlNodePtr networks; + xmlNodePtr node; + + priv = EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + + empathy_debug (DEBUG_DOMAIN, "Attempting to parse file:'%s'...", filename); + + ctxt = xmlNewParserCtxt (); + + /* Parse and validate the file. */ + doc = xmlCtxtReadFile (ctxt, filename, NULL, 0); + if (!doc) + { + g_warning ("Failed to parse file:'%s'", filename); + xmlFreeParserCtxt (ctxt); + return FALSE; + } + + if (!empathy_xml_validate (doc, IRC_NETWORKS_DTD_FILENAME)) { + g_warning ("Failed to validate file:'%s'", filename); + xmlFreeDoc (doc); + xmlFreeParserCtxt (ctxt); + return FALSE; + } + + /* The root node, networks. */ + networks = xmlDocGetRootElement (doc); + + for (node = networks->children; node; node = node->next) + { + irc_network_manager_parse_irc_network (self, node, user_defined); + } + + xmlFreeDoc(doc); + xmlFreeParserCtxt (ctxt); + + return TRUE; +} + +static void +write_network_to_xml (const gchar *id, + EmpathyIrcNetwork *network, + xmlNodePtr root) +{ + xmlNodePtr network_node, servers_node; + GSList *servers, *l; + gchar *name, *charset; + + if (!network->user_defined) + /* no need to write this network to the XML */ + return; + + network_node = xmlNewChild (root, NULL, "network", NULL); + xmlNewProp (network_node, "id", id); + + if (network->dropped) + { + xmlNewProp (network_node, "dropped", "1"); + return; + } + + g_object_get (network, + "name", &name, + "charset", &charset, + NULL); + xmlNewProp (network_node, "name", name); + xmlNewProp (network_node, "network_charset", charset); + g_free (name); + g_free (charset); + + servers = empathy_irc_network_get_servers (network); + + servers_node = xmlNewChild (network_node, NULL, "servers", NULL); + for (l = servers; l != NULL; l = g_slist_next (l)) + { + EmpathyIrcServer *server; + xmlNodePtr server_node; + gchar *address, *tmp; + guint port; + gboolean ssl; + + server = l->data; + + server_node = xmlNewChild (servers_node, NULL, "server", NULL); + + g_object_get (server, + "address", &address, + "port", &port, + "ssl", &ssl, + NULL); + + xmlNewProp (server_node, "address", address); + + tmp = g_strdup_printf ("%u", port); + xmlNewProp (server_node, "port", tmp); + g_free (tmp); + + xmlNewProp (server_node, "ssl", ssl ? "TRUE": "FALSE"); + + g_free (address); + } + + /* free the list */ + g_slist_foreach (servers, (GFunc) g_object_unref, NULL); + g_slist_free (servers); +} + +static gboolean +irc_network_manager_file_save (EmpathyIrcNetworkManager *self) +{ + EmpathyIrcNetworkManagerPrivate *priv = + EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + xmlDocPtr doc; + xmlNodePtr root; + + if (priv->user_file == NULL) + { + empathy_debug (DEBUG_DOMAIN, "can't save: no user file defined"); + return FALSE; + } + + empathy_debug (DEBUG_DOMAIN, "Saving IRC networks"); + + doc = xmlNewDoc ("1.0"); + root = xmlNewNode (NULL, "networks"); + xmlDocSetRootElement (doc, root); + + g_hash_table_foreach (priv->networks, (GHFunc) write_network_to_xml, root); + + /* Make sure the XML is indented properly */ + xmlIndentTreeOutput = 1; + + xmlSaveFormatFileEnc (priv->user_file, doc, "utf-8", 1); + xmlFreeDoc (doc); + + xmlCleanupParser (); + xmlMemoryDump (); + + priv->have_to_save = FALSE; + + return TRUE; +} + +static gboolean +find_network_by_address (const gchar *id, + EmpathyIrcNetwork *network, + const gchar *address) +{ + GSList *servers, *l; + gboolean found = FALSE; + + if (network->dropped) + return FALSE; + + servers = empathy_irc_network_get_servers (network); + + for (l = servers; l != NULL && !found; l = g_slist_next (l)) + { + EmpathyIrcServer *server = l->data; + gchar *_address; + + g_object_get (server, "address", &_address, NULL); + found = (_address != NULL && strcmp (address, _address) == 0); + + g_free (_address); + } + + g_slist_foreach (servers, (GFunc) g_object_unref, NULL); + g_slist_free (servers); + + return found; +} + +/** + * empathy_irc_network_manager_find_network_by_address: + * @manager: an #EmpathyIrcNetworkManager + * @address: the server address to look for + * + * Find the #EmpathyIrcNetwork which owns an #EmpathyIrcServer + * that has the given address. + * + * Returns: the found #EmpathyIrcNetwork, or %NULL if not found. + */ +EmpathyIrcNetwork * +empathy_irc_network_manager_find_network_by_address ( + EmpathyIrcNetworkManager *self, + const gchar *address) +{ + EmpathyIrcNetworkManagerPrivate *priv = + EMPATHY_IRC_NETWORK_MANAGER_GET_PRIVATE (self); + EmpathyIrcNetwork *network; + + g_return_val_if_fail (address != NULL, NULL); + + network = g_hash_table_find (priv->networks, + (GHRFunc) find_network_by_address, (gchar *) address); + + return network; +} diff --git a/libempathy/empathy-irc-network-manager.h b/libempathy/empathy-irc-network-manager.h new file mode 100644 index 00000000..a853a074 --- /dev/null +++ b/libempathy/empathy-irc-network-manager.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2007-2008 Guillaume Desmottes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Guillaume Desmottes + */ + +#ifndef __EMPATHY_IRC_NETWORK_MANAGER_H__ +#define __EMPATHY_IRC_NETWORK_MANAGER_H__ + +#include + +#include "empathy-irc-network.h" + +G_BEGIN_DECLS + +typedef struct _EmpathyIrcNetworkManager EmpathyIrcNetworkManager; +typedef struct _EmpathyIrcNetworkManagerClass EmpathyIrcNetworkManagerClass; + +struct _EmpathyIrcNetworkManager +{ + GObject parent; + + gpointer priv; +}; + +struct _EmpathyIrcNetworkManagerClass +{ + GObjectClass parent_class; +}; + +GType +empathy_irc_network_manager_get_type (void); + +/* TYPE MACROS */ +#define EMPATHY_TYPE_IRC_NETWORK_MANAGER \ + (empathy_irc_network_manager_get_type ()) +#define EMPATHY_IRC_NETWORK_MANAGER(o) \ + (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_IRC_NETWORK_MANAGER, \ + EmpathyIrcNetworkManager)) +#define EMPATHY_IRC_NETWORK_MANAGER_CLASS(k) \ + (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_IRC_NETWORK_MANAGER, \ + EmpathyIrcNetworkManagerClass)) +#define EMPATHY_IS_IRC_NETWORK_MANAGER(o) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_IRC_NETWORK_MANAGER)) +#define EMPATHY_IS_IRC_NETWORK_MANAGER_CLASS(k) \ + (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_IRC_NETWORK_MANAGER)) +#define EMPATHY_IRC_NETWORK_MANAGER_GET_CLASS(o) \ + (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_IRC_NETWORK_MANAGER, \ + EmpathyIrcNetworkManagerClass)) + +EmpathyIrcNetworkManager * empathy_irc_network_manager_new ( + const gchar *global_file, const gchar *user_file); + +void empathy_irc_network_manager_add (EmpathyIrcNetworkManager *manager, + EmpathyIrcNetwork *network); + +void empathy_irc_network_manager_remove (EmpathyIrcNetworkManager *manager, + EmpathyIrcNetwork *network); + +GSList * empathy_irc_network_manager_get_networks ( + EmpathyIrcNetworkManager *manager); + +EmpathyIrcNetwork * empathy_irc_network_manager_find_network_by_address ( + EmpathyIrcNetworkManager *manager, const gchar *address); + +G_END_DECLS + +#endif /* __EMPATHY_IRC_NETWORK_MANAGER_H__ */ diff --git a/libempathy/empathy-irc-network.c b/libempathy/empathy-irc-network.c new file mode 100644 index 00000000..f754adef --- /dev/null +++ b/libempathy/empathy-irc-network.c @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2007 Guillaume Desmottes + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Guillaume Desmottes + */ + +#include +#include +#include +#include +#include + +#include + +#include "empathy-marshal.h" +#include "empathy-irc-network.h" + +G_DEFINE_TYPE (EmpathyIrcNetwork, empathy_irc_network, G_TYPE_OBJECT); + +/* properties */ +enum +{ + PROP_NAME = 1, + PROP_CHARSET, + LAST_PROPERTY +}; + +/* signals */ +enum +{ + MODIFIED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = {0}; + +typedef struct _EmpathyIrcNetworkPrivate EmpathyIrcNetworkPrivate; + +struct _EmpathyIrcNetworkPrivate +{ + gchar *name; + gchar *charset; + GSList *servers; +}; + +#define EMPATHY_IRC_NETWORK_GET_PRIVATE(obj)\ + ((EmpathyIrcNetworkPrivate *) obj->priv) + +static void +server_modified_cb (EmpathyIrcServer *server, + EmpathyIrcNetwork *self) +{ + g_signal_emit (self, signals[MODIFIED], 0); +} + +static void +empathy_irc_network_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyIrcNetwork *self = EMPATHY_IRC_NETWORK (object); + EmpathyIrcNetworkPrivate *priv = EMPATHY_IRC_NETWORK_GET_PRIVATE (self); + + switch (property_id) + { + case PROP_NAME: + g_value_set_string (value, priv->name); + break; + case PROP_CHARSET: + g_value_set_string (value, priv->charset); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +empathy_irc_network_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyIrcNetwork *self = EMPATHY_IRC_NETWORK (object); + EmpathyIrcNetworkPrivate *priv = EMPATHY_IRC_NETWORK_GET_PRIVATE (self); + + switch (property_id) + { + case PROP_NAME: + if (tp_strdiff (priv->name, g_value_get_string (value))) + { + g_free (priv->name); + priv->name = g_value_dup_string (value); + g_signal_emit (object, signals[MODIFIED], 0); + } + break; + case PROP_CHARSET: + if (tp_strdiff (priv->charset, g_value_get_string (value))) + { + g_free (priv->charset); + priv->charset = g_value_dup_string (value); + g_signal_emit (object, signals[MODIFIED], 0); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +empathy_irc_network_dispose (GObject *object) +{ + EmpathyIrcNetwork *self = EMPATHY_IRC_NETWORK (object); + EmpathyIrcNetworkPrivate *priv = EMPATHY_IRC_NETWORK_GET_PRIVATE (self); + GSList *l; + + for (l = priv->servers; l != NULL; l = g_slist_next (l)) + { + g_signal_handlers_disconnect_by_func (l->data, + G_CALLBACK (server_modified_cb), self); + g_object_unref (l->data); + } + + G_OBJECT_CLASS (empathy_irc_network_parent_class)->dispose (object); +} + +static void +empathy_irc_network_finalize (GObject *object) +{ + EmpathyIrcNetwork *self = EMPATHY_IRC_NETWORK (object); + EmpathyIrcNetworkPrivate *priv = EMPATHY_IRC_NETWORK_GET_PRIVATE (self); + + g_slist_free (priv->servers); + g_free (priv->name); + g_free (priv->charset); + + G_OBJECT_CLASS (empathy_irc_network_parent_class)->finalize (object); +} + +static void +empathy_irc_network_init (EmpathyIrcNetwork *self) +{ + EmpathyIrcNetworkPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + EMPATHY_TYPE_IRC_NETWORK, EmpathyIrcNetworkPrivate); + + self->priv = priv; + + priv->servers = NULL; + + self->user_defined = TRUE; + self->dropped = FALSE; +} + +static void +empathy_irc_network_class_init (EmpathyIrcNetworkClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *param_spec; + + object_class->get_property = empathy_irc_network_get_property; + object_class->set_property = empathy_irc_network_set_property; + + g_type_class_add_private (object_class, + sizeof (EmpathyIrcNetworkPrivate)); + + object_class->dispose = empathy_irc_network_dispose; + object_class->finalize = empathy_irc_network_finalize; + + param_spec = g_param_spec_string ( + "name", + "Network name", + "The displayed name of this network", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB); + g_object_class_install_property (object_class, PROP_NAME, param_spec); + + param_spec = g_param_spec_string ( + "charset", + "Charset", + "The charset to use on this network", + "UTF-8", + G_PARAM_CONSTRUCT | + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB); + g_object_class_install_property (object_class, PROP_CHARSET, param_spec); + + /** + * EmpathyIrcNetwork::modified: + * @network: the object that received the signal + * + * Emitted when either a property or a server of the network is modified. + * + */ + signals[MODIFIED] = g_signal_new ( + "modified", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +/** + * empathy_irc_network_new: + * @name: the name of the network + * + * Creates a new #EmpathyIrcNetwork. + * + * Returns: a new #EmpathyIrcNetwork + */ +EmpathyIrcNetwork * +empathy_irc_network_new (const gchar *name) +{ + return g_object_new (EMPATHY_TYPE_IRC_NETWORK, + "name", name, + NULL); +} + +/** + * empathy_irc_network_get_servers: + * @network: an #EmpathyIrcNetwork + * + * Get the list of #EmpathyIrcServer that belongs to this network. + * These servers are sorted according their priority. + * So the first one will be the first used when trying to connect to + * the network. + * + * Returns: a new #GSList of refed #EmpathyIrcServer. + */ +GSList * +empathy_irc_network_get_servers (EmpathyIrcNetwork *self) +{ + EmpathyIrcNetworkPrivate *priv; + GSList *servers = NULL, *l; + + g_return_val_if_fail (EMPATHY_IS_IRC_NETWORK (self), NULL); + priv = EMPATHY_IRC_NETWORK_GET_PRIVATE (self); + + for (l = priv->servers; l != NULL; l = g_slist_next (l)) + { + servers = g_slist_prepend (servers, g_object_ref (l->data)); + } + + return g_slist_reverse (servers); +} + +/** + * empathy_irc_network_append_server: + * @network: an #EmpathyIrcNetwork + * @server: the #EmpathyIrcServer to add + * + * Add an #EmpathyIrcServer to the given #EmpathyIrcNetwork. The server + * is added at the last position in network's servers list. + * + */ +void +empathy_irc_network_append_server (EmpathyIrcNetwork *self, + EmpathyIrcServer *server) +{ + EmpathyIrcNetworkPrivate *priv; + + g_return_if_fail (EMPATHY_IS_IRC_NETWORK (self)); + g_return_if_fail (server != NULL && EMPATHY_IS_IRC_SERVER (server)); + + priv = EMPATHY_IRC_NETWORK_GET_PRIVATE (self); + + g_return_if_fail (g_slist_find (priv->servers, server) == NULL); + + priv->servers = g_slist_append (priv->servers, g_object_ref (server)); + + g_signal_connect (server, "modified", G_CALLBACK (server_modified_cb), self); + + g_signal_emit (self, signals[MODIFIED], 0); +} + +/** + * empathy_irc_network_remove_server: + * @network: an #EmpathyIrcNetwork + * @server: the #EmpathyIrcServer to remove + * + * Remove an #EmpathyIrcServer from the servers list of the + * given #EmpathyIrcNetwork. + * + */ +void +empathy_irc_network_remove_server (EmpathyIrcNetwork *self, + EmpathyIrcServer *server) +{ + EmpathyIrcNetworkPrivate *priv; + GSList *l; + + g_return_if_fail (EMPATHY_IS_IRC_NETWORK (self)); + g_return_if_fail (server != NULL && EMPATHY_IS_IRC_SERVER (server)); + + priv = EMPATHY_IRC_NETWORK_GET_PRIVATE (self); + + l = g_slist_find (priv->servers, server); + if (l == NULL) + return; + + g_object_unref (l->data); + priv->servers = g_slist_delete_link (priv->servers, l); + g_signal_handlers_disconnect_by_func (server, G_CALLBACK (server_modified_cb), + self); + + g_signal_emit (self, signals[MODIFIED], 0); +} + +/** + * empathy_irc_network_set_server_position: + * @network: an #EmpathyIrcNetwork + * @server: the #EmpathyIrcServer to move + * @pos: the position to move the server. If this is negative, or is larger than + * the number of servers in the list, the server is moved to the end of the + * list. + * + * Move an #EmpathyIrcServer in the servers list of the given + * #EmpathyIrcNetwork. + * + */ +void +empathy_irc_network_set_server_position (EmpathyIrcNetwork *self, + EmpathyIrcServer *server, + gint pos) +{ + EmpathyIrcNetworkPrivate *priv; + GSList *l; + + g_return_if_fail (EMPATHY_IS_IRC_NETWORK (self)); + g_return_if_fail (server != NULL && EMPATHY_IS_IRC_SERVER (server)); + + priv = EMPATHY_IRC_NETWORK_GET_PRIVATE (self); + + l = g_slist_find (priv->servers, server); + if (l == NULL) + return; + + priv->servers = g_slist_delete_link (priv->servers, l); + priv->servers = g_slist_insert (priv->servers, server, pos); + + g_signal_emit (self, signals[MODIFIED], 0); +} diff --git a/libempathy/empathy-irc-network.h b/libempathy/empathy-irc-network.h new file mode 100644 index 00000000..ac146a18 --- /dev/null +++ b/libempathy/empathy-irc-network.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2007-2008 Guillaume Desmottes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Guillaume Desmottes + */ + +#ifndef __EMPATHY_IRC_NETWORK_H__ +#define __EMPATHY_IRC_NETWORK_H__ + +#include + +#include "empathy-irc-server.h" + +G_BEGIN_DECLS + +typedef struct _EmpathyIrcNetwork EmpathyIrcNetwork; +typedef struct _EmpathyIrcNetworkClass EmpathyIrcNetworkClass; + +struct _EmpathyIrcNetwork +{ + GObject parent; + + gpointer priv; + + gboolean user_defined; + gboolean dropped; +}; + +struct _EmpathyIrcNetworkClass +{ + GObjectClass parent_class; +}; + +GType empathy_irc_network_get_type (void); + +/* TYPE MACROS */ +#define EMPATHY_TYPE_IRC_NETWORK (empathy_irc_network_get_type ()) +#define EMPATHY_IRC_NETWORK(o) \ + (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_IRC_NETWORK, \ + EmpathyIrcNetwork)) +#define EMPATHY_IRC_NETWORK_CLASS(k) \ + (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_IRC_NETWORK,\ + EmpathyIrcNetworkClass)) +#define EMPATHY_IS_IRC_NETWORK(o) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_IRC_NETWORK)) +#define EMPATHY_IS_IRC_NETWORK_CLASS(k) \ + (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_IRC_NETWORK)) +#define EMPATHY_IRC_NETWORK_GET_CLASS(o) \ + (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_IRC_NETWORK, \ + EmpathyIrcNetworkClass)) + +EmpathyIrcNetwork * empathy_irc_network_new (const gchar *name); + +GSList * empathy_irc_network_get_servers (EmpathyIrcNetwork *network); + +void empathy_irc_network_append_server (EmpathyIrcNetwork *network, + EmpathyIrcServer *server); + +void empathy_irc_network_remove_server (EmpathyIrcNetwork *network, + EmpathyIrcServer *server); + +void empathy_irc_network_set_server_position (EmpathyIrcNetwork *network, + EmpathyIrcServer *server, gint pos); + +G_END_DECLS + +#endif /* __EMPATHY_IRC_NETWORK_H__ */ diff --git a/libempathy/empathy-irc-networks.dtd b/libempathy/empathy-irc-networks.dtd new file mode 100644 index 00000000..692e613c --- /dev/null +++ b/libempathy/empathy-irc-networks.dtd @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + diff --git a/libempathy/empathy-irc-server.c b/libempathy/empathy-irc-server.c new file mode 100644 index 00000000..510acc77 --- /dev/null +++ b/libempathy/empathy-irc-server.c @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2007-2008 Guillaume Desmottes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Guillaume Desmottes + */ + +#include +#include +#include +#include +#include + +#include + +#include "empathy-marshal.h" +#include "empathy-irc-server.h" + +G_DEFINE_TYPE (EmpathyIrcServer, empathy_irc_server, G_TYPE_OBJECT); + +/* properties */ +enum +{ + PROP_ADDRESS = 1, + PROP_PORT, + PROP_SSL, + LAST_PROPERTY +}; + +/* signals */ +enum +{ + MODIFIED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = {0}; + +typedef struct _EmpathyIrcServerPrivate EmpathyIrcServerPrivate; + +struct _EmpathyIrcServerPrivate +{ + gchar *address; + gint port; + gboolean ssl; +}; + +#define EMPATHY_IRC_SERVER_GET_PRIVATE(obj)\ + ((EmpathyIrcServerPrivate *) obj->priv) + +static void +empathy_irc_server_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + EmpathyIrcServer *self = EMPATHY_IRC_SERVER (object); + EmpathyIrcServerPrivate *priv = EMPATHY_IRC_SERVER_GET_PRIVATE (self); + + switch (property_id) + { + case PROP_ADDRESS: + g_value_set_string (value, priv->address); + break; + case PROP_PORT: + g_value_set_uint (value, priv->port); + break; + case PROP_SSL: + g_value_set_boolean (value, priv->ssl); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +empathy_irc_server_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + EmpathyIrcServer *self = EMPATHY_IRC_SERVER (object); + EmpathyIrcServerPrivate *priv = EMPATHY_IRC_SERVER_GET_PRIVATE (self); + + switch (property_id) + { + case PROP_ADDRESS: + if (tp_strdiff (priv->address, g_value_get_string (value))) + { + g_free (priv->address); + priv->address = g_value_dup_string (value); + g_signal_emit (object, signals[MODIFIED], 0); + } + break; + case PROP_PORT: + if (priv->port != g_value_get_uint (value)) + { + priv->port = g_value_get_uint (value); + g_signal_emit (object, signals[MODIFIED], 0); + } + break; + case PROP_SSL: + if (priv->ssl != g_value_get_boolean (value)) + { + priv->ssl = g_value_get_boolean (value); + g_signal_emit (object, signals[MODIFIED], 0); + } + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +empathy_irc_server_finalize (GObject *object) +{ + EmpathyIrcServer *self = EMPATHY_IRC_SERVER (object); + EmpathyIrcServerPrivate *priv = EMPATHY_IRC_SERVER_GET_PRIVATE (self); + + g_free (priv->address); + + G_OBJECT_CLASS (empathy_irc_server_parent_class)->finalize (object); +} + +static void +empathy_irc_server_init (EmpathyIrcServer *self) +{ + EmpathyIrcServerPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + EMPATHY_TYPE_IRC_SERVER, EmpathyIrcServerPrivate); + + self->priv = priv; +} + +static void +empathy_irc_server_class_init (EmpathyIrcServerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GParamSpec *param_spec; + + object_class->get_property = empathy_irc_server_get_property; + object_class->set_property = empathy_irc_server_set_property; + + g_type_class_add_private (object_class, + sizeof (EmpathyIrcServerPrivate)); + + object_class->finalize = empathy_irc_server_finalize; + + param_spec = g_param_spec_string ( + "address", + "Server address", + "The address of this server", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB); + g_object_class_install_property (object_class, PROP_ADDRESS, param_spec); + + param_spec = g_param_spec_uint ( + "port", + "Server port", + "The port to use to connect on this server", + 1, G_MAXUINT16, 6667, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB); + g_object_class_install_property (object_class, PROP_PORT, param_spec); + + param_spec = g_param_spec_boolean ( + "ssl", + "SSL", + "If this server needs SSL connection", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB); + g_object_class_install_property (object_class, PROP_SSL, param_spec); + + /** + * EmpathyIrcServer::modified: + * @server: the object that received the signal + * + * Emitted when a property of the server is modified. + * + */ + signals[MODIFIED] = g_signal_new ( + "modified", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +/** + * empathy_irc_server_new: + * @address: the address + * @port: the port + * @ssl: %TRUE if the server needs a SSL connection + * + * Creates a new #EmpathyIrcServer + * + * Returns: a new #EmpathyIrcServer + */ +EmpathyIrcServer * +empathy_irc_server_new (const gchar *address, + guint port, + gboolean ssl) +{ + return g_object_new (EMPATHY_TYPE_IRC_SERVER, + "address", address, + "port", port, + "ssl", ssl, + NULL); +} diff --git a/libempathy/empathy-irc-server.h b/libempathy/empathy-irc-server.h new file mode 100644 index 00000000..09f8c1ef --- /dev/null +++ b/libempathy/empathy-irc-server.h @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2007-2008 Guillaume Desmottes + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Guillaume Desmottes + */ + +#ifndef __EMPATHY_IRC_SERVER_H__ +#define __EMPATHY_IRC_SERVER_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _EmpathyIrcServer EmpathyIrcServer; +typedef struct _EmpathyIrcServerClass EmpathyIrcServerClass; + +struct _EmpathyIrcServer +{ + GObject parent; + + gpointer priv; +}; + +struct _EmpathyIrcServerClass +{ + GObjectClass parent_class; +}; + +GType empathy_irc_server_get_type (void); + +/* TYPE MACROS */ +#define EMPATHY_TYPE_IRC_SERVER (empathy_irc_server_get_type ()) +#define EMPATHY_IRC_SERVER(o) \ + (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_IRC_SERVER, EmpathyIrcServer)) +#define EMPATHY_IRC_SERVER_CLASS(k) \ + (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_IRC_SERVER, \ + EmpathyIrcServerClass)) +#define EMPATHY_IS_IRC_SERVER(o) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_IRC_SERVER)) +#define EMPATHY_IS_IRC_SERVER_CLASS(k) \ + (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_IRC_SERVER)) +#define EMPATHY_IRC_SERVER_GET_CLASS(o) \ + (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_IRC_SERVER,\ + EmpathyIrcServerClass)) + +EmpathyIrcServer * empathy_irc_server_new (const gchar *address, guint port, + gboolean ssl); + +G_END_DECLS + +#endif /* __EMPATHY_IRC_SERVER_H__ */ diff --git a/libempathy/irc-networks.xml b/libempathy/irc-networks.xml new file mode 100644 index 00000000..383ba25f --- /dev/null +++ b/libempathy/irc-networks.xml @@ -0,0 +1,543 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/m4/Makefile.am b/m4/Makefile.am new file mode 100644 index 00000000..e69de29b diff --git a/po/POTFILES.in b/po/POTFILES.in index bc36d382..6efa6b06 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -53,6 +53,10 @@ libempathy-gtk/empathy-status-icon.glade libempathy-gtk/empathy-theme-boxes.c libempathy-gtk/empathy-theme-irc.c libempathy-gtk/empathy-theme-manager.c +libempathy-gtk/empathy-account-widget-irc.c +libempathy-gtk/empathy-account-widget-irc.glade +libempathy-gtk/empathy-irc-network-dialog.c +libempathy-gtk/totem-subtitle-encoding.c megaphone/data/GNOME_Megaphone_Applet.schemas.in megaphone/data/GNOME_Megaphone_Applet.server.in.in diff --git a/tests/Makefile.am b/tests/Makefile.am index c7217381..9eb54132 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -26,7 +26,12 @@ check_main_SOURCES = \ check-helpers.c \ check-helpers.h \ check-libempathy.h \ - check-empathy-utils.c + check-empathy-utils.c \ + check-irc-helper.h \ + check-irc-helper.c \ + check-empathy-irc-server.c \ + check-empathy-irc-network.c \ + check-empathy-irc-network-manager.c check_main_LDADD = \ @CHECK_LIBS@ \ diff --git a/tests/check-empathy-irc-network-manager.c b/tests/check-empathy-irc-network-manager.c new file mode 100644 index 00000000..c3e85313 --- /dev/null +++ b/tests/check-empathy-irc-network-manager.c @@ -0,0 +1,824 @@ +#include +#include +#include +#include + +#include +#include "check-helpers.h" +#include "check-libempathy.h" +#include "check-irc-helper.h" + +#include + +#define GLOBAL_SAMPLE "xml/default-irc-networks-sample.xml" +#define USER_SAMPLE "xml/user-irc-networks-sample.xml" +#define USER_FILE "xml/user-irc-networks.xml" + +START_TEST (test_empathy_irc_network_manager_add) +{ + EmpathyIrcNetworkManager *mgr; + EmpathyIrcNetwork *network; + GSList *networks; + gchar *name; + + mgr = empathy_irc_network_manager_new (NULL, NULL); + fail_if (mgr == NULL); + + networks = empathy_irc_network_manager_get_networks (mgr); + fail_if (networks != NULL); + + /* add a network */ + network = empathy_irc_network_new ("My Network"); + fail_if (network == NULL); + empathy_irc_network_manager_add (mgr, network); + g_object_unref (network); + + networks = empathy_irc_network_manager_get_networks (mgr); + fail_if (g_slist_length (networks) != 1); + g_object_get (networks->data, "name", &name, NULL); + fail_if (name == NULL || strcmp (name, "My Network") != 0); + g_free (name); + g_slist_foreach (networks, (GFunc) g_object_unref, NULL); + g_slist_free (networks); + + /* add another network having the same name */ + network = empathy_irc_network_new ("My Network"); + fail_if (network == NULL); + empathy_irc_network_manager_add (mgr, network); + g_object_unref (network); + + networks = empathy_irc_network_manager_get_networks (mgr); + fail_if (g_slist_length (networks) != 2); + g_object_get (networks->data, "name", &name, NULL); + fail_if (name == NULL || strcmp (name, "My Network") != 0); + g_free (name); + g_object_get (g_slist_next(networks)->data, "name", &name, NULL); + fail_if (name == NULL || strcmp (name, "My Network") != 0); + g_free (name); + g_slist_foreach (networks, (GFunc) g_object_unref, NULL); + g_slist_free (networks); + + g_object_unref (mgr); +} +END_TEST + +START_TEST (test_load_global_file) +{ + EmpathyIrcNetworkManager *mgr; + gchar *global_file, *user_file; + GSList *networks, *l; + struct server_t freenode_servers[] = { + { "irc.freenode.net", 6667, FALSE }, + { "irc.eu.freenode.net", 6667, FALSE }}; + struct server_t gimpnet_servers[] = { + { "irc.gimp.org", 6667, FALSE }, + { "irc.us.gimp.org", 6667, FALSE }}; + struct server_t test_servers[] = { + { "irc.test.org", 6669, TRUE }}; + struct server_t undernet_servers[] = { + { "eu.undernet.org", 6667, FALSE }}; + gboolean network_checked[4]; + + mgr = empathy_irc_network_manager_new (GLOBAL_SAMPLE, NULL); + + g_object_get (mgr, + "global-file", &global_file, + "user-file", &user_file, + NULL); + fail_if (global_file == NULL || strcmp (global_file, GLOBAL_SAMPLE) != 0); + fail_if (user_file != NULL); + g_free (global_file); + g_free (user_file); + + networks = empathy_irc_network_manager_get_networks (mgr); + fail_if (g_slist_length (networks) != 4); + + network_checked[0] = network_checked[1] = network_checked[2] = + network_checked[3] = FALSE; + /* check networks and servers */ + for (l = networks; l != NULL; l = g_slist_next (l)) + { + gchar *name; + + g_object_get (l->data, "name", &name, NULL); + fail_if (name == NULL); + + if (strcmp (name, "Freenode") == 0) + { + check_network (l->data, "Freenode", "UTF-8", freenode_servers, 2); + network_checked[0] = TRUE; + } + else if (strcmp (name, "GIMPNet") == 0) + { + check_network (l->data, "GIMPNet", "UTF-8", gimpnet_servers, 2); + network_checked[1] = TRUE; + } + else if (strcmp (name, "Test Server") == 0) + { + check_network (l->data, "Test Server", "ISO-8859-1", test_servers, 1); + network_checked[2] = TRUE; + } + else if (strcmp (name, "Undernet") == 0) + { + check_network (l->data, "Undernet", "UTF-8", undernet_servers, 1); + network_checked[3] = TRUE; + } + else + { + fail_if (TRUE); + } + + g_free (name); + } + fail_if (!network_checked[0] || !network_checked[1] || !network_checked[2] || + !network_checked[3]); + + g_slist_foreach (networks, (GFunc) g_object_unref, NULL); + g_slist_free (networks); + g_object_unref (mgr); +} +END_TEST + +static gboolean +remove_network_named (EmpathyIrcNetworkManager *mgr, + const gchar *network_name) +{ + GSList *networks, *l; + gboolean removed = FALSE; + + networks = empathy_irc_network_manager_get_networks (mgr); + + /* check networks and servers */ + for (l = networks; l != NULL && !removed; l = g_slist_next (l)) + { + EmpathyIrcNetwork *network = l->data; + gchar *name; + + g_object_get (network, "name", &name, NULL); + fail_if (name == NULL); + + if (strcmp (name, network_name) == 0) + { + empathy_irc_network_manager_remove (mgr, network); + removed = TRUE; + } + + g_free (name); + } + + g_slist_foreach (networks, (GFunc) g_object_unref, NULL); + g_slist_free (networks); + + return removed; +} + +START_TEST (test_empathy_irc_network_manager_remove) +{ + EmpathyIrcNetworkManager *mgr; + GSList *networks, *l; + struct server_t freenode_servers[] = { + { "irc.freenode.net", 6667, FALSE }, + { "irc.eu.freenode.net", 6667, FALSE }}; + struct server_t test_servers[] = { + { "irc.test.org", 6669, TRUE }}; + struct server_t undernet_servers[] = { + { "eu.undernet.org", 6667, FALSE }}; + gboolean network_checked[3]; + gboolean result; + + mgr = empathy_irc_network_manager_new (GLOBAL_SAMPLE, NULL); + + result = remove_network_named (mgr, "GIMPNet"); + fail_if (!result); + + networks = empathy_irc_network_manager_get_networks (mgr); + fail_if (g_slist_length (networks) != 3); + + network_checked[0] = network_checked[1] = network_checked[2] = FALSE; + /* check networks and servers */ + for (l = networks; l != NULL; l = g_slist_next (l)) + { + gchar *name; + + g_object_get (l->data, "name", &name, NULL); + fail_if (name == NULL); + + if (strcmp (name, "Freenode") == 0) + { + check_network (l->data, "Freenode", "UTF-8", freenode_servers, 2); + network_checked[0] = TRUE; + } + else if (strcmp (name, "Test Server") == 0) + { + check_network (l->data, "Test Server", "ISO-8859-1", test_servers, 1); + network_checked[1] = TRUE; + } + else if (strcmp (name, "Undernet") == 0) + { + check_network (l->data, "Undernet", "UTF-8", undernet_servers, 1); + network_checked[2] = TRUE; + } + else + { + fail_if (TRUE); + } + + g_free (name); + } + fail_if (!network_checked[0] || !network_checked[1] || !network_checked[2]); + + g_slist_foreach (networks, (GFunc) g_object_unref, NULL); + g_slist_free (networks); + g_object_unref (mgr); +} +END_TEST + +static void +copy_user_file (void) +{ + gboolean result; + gchar *buffer; + gsize length; + + result = g_file_get_contents (USER_SAMPLE, &buffer, &length, NULL); + fail_if (!result); + + result = g_file_set_contents (USER_FILE, buffer, length, NULL); + fail_if (!result); + + g_free (buffer); +} + +START_TEST (test_load_user_file) +{ + EmpathyIrcNetworkManager *mgr; + gchar *global_file, *user_file; + GSList *networks, *l; + struct server_t gimpnet_servers[] = { + { "irc.gimp.org", 6667, FALSE }, + { "irc.us.gimp.org", 6667, FALSE }, + { "irc.au.gimp.org", 6667, FALSE }}; + struct server_t my_server[] = { + { "irc.mysrv.net", 7495, TRUE }}; + struct server_t another_server[] = { + { "irc.anothersrv.be", 6660, FALSE }}; + gboolean network_checked[3]; + + copy_user_file (); + mgr = empathy_irc_network_manager_new (NULL, USER_FILE); + + g_object_get (mgr, + "global-file", &global_file, + "user-file", &user_file, + NULL); + fail_if (global_file != NULL); + fail_if (user_file == NULL || strcmp (user_file, USER_FILE) != 0); + g_free (global_file); + g_free (user_file); + + networks = empathy_irc_network_manager_get_networks (mgr); + fail_if (g_slist_length (networks) != 3); + + network_checked[0] = network_checked[1] = network_checked[2] = FALSE; + /* check networks and servers */ + for (l = networks; l != NULL; l = g_slist_next (l)) + { + gchar *name; + + g_object_get (l->data, "name", &name, NULL); + fail_if (name == NULL); + + if (strcmp (name, "GIMPNet") == 0) + { + check_network (l->data, "GIMPNet", "UTF-8", gimpnet_servers, 3); + network_checked[0] = TRUE; + } + else if (strcmp (name, "My Server") == 0) + { + check_network (l->data, "My Server", "UTF-8", my_server, 1); + network_checked[1] = TRUE; + } + else if (strcmp (name, "Another Server") == 0) + { + check_network (l->data, "Another Server", "UTF-8", another_server, 1); + network_checked[2] = TRUE; + } + else + { + fail_if (TRUE); + } + + g_free (name); + } + fail_if (!network_checked[0] || !network_checked[1] || !network_checked[2]); + + g_slist_foreach (networks, (GFunc) g_object_unref, NULL); + g_slist_free (networks); + g_object_unref (mgr); +} +END_TEST + +START_TEST (test_load_both_files) +{ + EmpathyIrcNetworkManager *mgr; + gchar *global_file, *user_file; + GSList *networks, *l; + struct server_t freenode_servers[] = { + { "irc.freenode.net", 6667, FALSE }, + { "irc.eu.freenode.net", 6667, FALSE }}; + struct server_t gimpnet_servers[] = { + { "irc.gimp.org", 6667, FALSE }, + { "irc.us.gimp.org", 6667, FALSE }, + { "irc.au.gimp.org", 6667, FALSE }}; + struct server_t my_server[] = { + { "irc.mysrv.net", 7495, TRUE }}; + struct server_t another_server[] = { + { "irc.anothersrv.be", 6660, FALSE }}; + struct server_t undernet_servers[] = { + { "eu.undernet.org", 6667, FALSE }}; + gboolean network_checked[5]; + + mgr = empathy_irc_network_manager_new (GLOBAL_SAMPLE, USER_FILE); + + g_object_get (mgr, + "global-file", &global_file, + "user-file", &user_file, + NULL); + fail_if (global_file == NULL || strcmp (global_file, GLOBAL_SAMPLE) != 0); + fail_if (user_file == NULL || strcmp (user_file, USER_FILE) != 0); + g_free (global_file); + g_free (user_file); + + networks = empathy_irc_network_manager_get_networks (mgr); + fail_if (g_slist_length (networks) != 5); + + network_checked[0] = network_checked[1] = network_checked[2] = + network_checked[3] = network_checked[4] = FALSE; + /* check networks and servers */ + for (l = networks; l != NULL; l = g_slist_next (l)) + { + gchar *name; + + g_object_get (l->data, "name", &name, NULL); + fail_if (name == NULL); + + if (strcmp (name, "Freenode") == 0) + { + check_network (l->data, "Freenode", "UTF-8", freenode_servers, 2); + network_checked[0] = TRUE; + } + else if (strcmp (name, "GIMPNet") == 0) + { + check_network (l->data, "GIMPNet", "UTF-8", gimpnet_servers, 3); + network_checked[1] = TRUE; + } + else if (strcmp (name, "My Server") == 0) + { + check_network (l->data, "My Server", "UTF-8", my_server, 1); + network_checked[2] = TRUE; + } + else if (strcmp (name, "Another Server") == 0) + { + check_network (l->data, "Another Server", "UTF-8", another_server, 1); + network_checked[3] = TRUE; + } + else if (strcmp (name, "Undernet") == 0) + { + check_network (l->data, "Undernet", "UTF-8", undernet_servers, 1); + network_checked[4] = TRUE; + } + else + { + fail_if (TRUE); + } + + g_free (name); + } + fail_if (!network_checked[0] || !network_checked[1] || !network_checked[2] || + !network_checked[3] || !network_checked[4]); + + g_slist_foreach (networks, (GFunc) g_object_unref, NULL); + g_slist_free (networks); + g_object_unref (mgr); +} +END_TEST + +START_TEST (test_modify_user_file) +{ + EmpathyIrcNetworkManager *mgr; + EmpathyIrcNetwork *network; + EmpathyIrcServer *server; + gchar *global_file, *user_file; + GSList *networks, *l; + struct server_t gimpnet_servers[] = { + { "irc.gimp.org", 6667, TRUE }, + { "irc.us.gimp.org", 6668, FALSE }}; + struct server_t great_server[] = { + { "irc.greatserver.com", 7873, TRUE }}; + struct server_t another_server[] = { + { "irc.anothersrv.be", 6660, FALSE }}; + gboolean network_modified[2]; + gboolean network_checked[3]; + + copy_user_file (); + mgr = empathy_irc_network_manager_new (NULL, USER_FILE); + + g_object_get (mgr, + "global-file", &global_file, + "user-file", &user_file, + NULL); + fail_if (global_file != NULL); + fail_if (user_file == NULL || strcmp (user_file, USER_FILE) != 0); + g_free (global_file); + g_free (user_file); + + networks = empathy_irc_network_manager_get_networks (mgr); + fail_if (g_slist_length (networks) != 3); + + network_modified[0] = network_modified[1] = FALSE; + /* check networks and servers */ + for (l = networks; l != NULL; l = g_slist_next (l)) + { + EmpathyIrcNetwork *network; + gchar *name; + + network = l->data; + g_object_get (network, "name", &name, NULL); + fail_if (name == NULL); + + if (strcmp (name, "GIMPNet") == 0) + { + GSList *servers, *ll; + + /* change charset */ + g_object_set (network, "charset", "ISO-8859-1", NULL); + + servers = empathy_irc_network_get_servers (network); + for (ll = servers; ll != NULL; ll = g_slist_next (ll)) + { + EmpathyIrcServer *server; + gchar *address; + + server = ll->data; + g_object_get (server, "address", &address, NULL); + if (strcmp (address, "irc.gimp.org") == 0) + { + /* change SSL */ + g_object_set (server, "ssl", TRUE, NULL); + } + else if (strcmp (address, "irc.us.gimp.org") == 0) + { + /* change port */ + g_object_set (server, "port", 6668, NULL); + } + else if (strcmp (address, "irc.au.gimp.org") == 0) + { + /* remove this server */ + empathy_irc_network_remove_server (network, server); + } + else + { + fail_if (TRUE); + } + + g_free (address); + } + + network_modified[0] = TRUE; + + g_slist_foreach (servers, (GFunc) g_object_unref, NULL); + g_slist_free (servers); + } + else if (strcmp (name, "My Server") == 0) + { + /* remove this network */ + empathy_irc_network_manager_remove (mgr, network); + network_modified[1] = TRUE; + } + else if (strcmp (name, "Another Server") == 0) + { + /* Don't change this one */ + } + else + { + fail_if (TRUE); + } + + g_free (name); + } + fail_if (!network_modified[0] || !network_modified[1]); + + /* Add a new network */ + network = empathy_irc_network_new ("Great Server"); + server = empathy_irc_server_new ("irc.greatserver.com", 7873, TRUE); + empathy_irc_network_append_server (network, server); + empathy_irc_network_manager_add (mgr, network); + g_object_unref (server); + g_object_unref (network); + + g_slist_foreach (networks, (GFunc) g_object_unref, NULL); + g_slist_free (networks); + g_object_unref (mgr); + + + /* Now let's reload the file and check its contain */ + mgr = empathy_irc_network_manager_new (NULL, USER_FILE); + + networks = empathy_irc_network_manager_get_networks (mgr); + fail_if (g_slist_length (networks) != 3); + + network_checked[0] = network_checked[1] = network_checked[2] = FALSE; + /* check networks and servers */ + for (l = networks; l != NULL; l = g_slist_next (l)) + { + gchar *name; + + g_object_get (l->data, "name", &name, NULL); + fail_if (name == NULL); + + if (strcmp (name, "GIMPNet") == 0) + { + check_network (l->data, "GIMPNet", "ISO-8859-1", gimpnet_servers, 2); + network_checked[0] = TRUE; + } + else if (strcmp (name, "Great Server") == 0) + { + check_network (l->data, "Great Server", "UTF-8", great_server, 1); + network_checked[1] = TRUE; + } + else if (strcmp (name, "Another Server") == 0) + { + check_network (l->data, "Another Server", "UTF-8", another_server, 1); + network_checked[2] = TRUE; + } + else + { + fail_if (TRUE); + } + + g_free (name); + } + fail_if (!network_checked[0] || !network_checked[1] || !network_checked[2]); + + g_slist_foreach (networks, (GFunc) g_object_unref, NULL); + g_slist_free (networks); + g_object_unref (mgr); +} +END_TEST + +START_TEST (test_modify_both_files) +{ + EmpathyIrcNetworkManager *mgr; + EmpathyIrcNetwork *network; + EmpathyIrcServer *server; + gchar *global_file, *user_file; + GSList *networks, *l; + struct server_t gimpnet_servers[] = { + { "irc.gimp.org", 6667, TRUE }, + { "irc.us.gimp.org", 6668, FALSE }}; + struct server_t great_server[] = { + { "irc.greatserver.com", 7873, TRUE }}; + struct server_t another_server[] = { + { "irc.anothersrv.be", 6660, FALSE }}; + struct server_t undernet_servers[] = { + { "eu.undernet.org", 6667, FALSE }, + { "us.undernet.org", 6667, FALSE }}; + gboolean network_modified[4]; + gboolean network_checked[4]; + + copy_user_file (); + mgr = empathy_irc_network_manager_new (GLOBAL_SAMPLE, USER_FILE); + + g_object_get (mgr, + "global-file", &global_file, + "user-file", &user_file, + NULL); + fail_if (global_file == NULL || strcmp (global_file, GLOBAL_SAMPLE) != 0); + fail_if (user_file == NULL || strcmp (user_file, USER_FILE) != 0); + g_free (global_file); + g_free (user_file); + + networks = empathy_irc_network_manager_get_networks (mgr); + fail_if (g_slist_length (networks) != 5); + + network_modified[0] = network_modified[1] = network_modified[2] = + network_modified[3] = FALSE; + /* check networks and servers */ + for (l = networks; l != NULL; l = g_slist_next (l)) + { + EmpathyIrcNetwork *network; + gchar *name; + + network = l->data; + g_object_get (network, "name", &name, NULL); + fail_if (name == NULL); + + if (strcmp (name, "GIMPNet") == 0) + { + /* Modify user network */ + GSList *servers, *ll; + + servers = empathy_irc_network_get_servers (network); + for (ll = servers; ll != NULL; ll = g_slist_next (ll)) + { + EmpathyIrcServer *server; + gchar *address; + + server = ll->data; + g_object_get (server, "address", &address, NULL); + if (strcmp (address, "irc.gimp.org") == 0) + { + /* change SSL */ + g_object_set (server, "ssl", TRUE, NULL); + } + else if (strcmp (address, "irc.us.gimp.org") == 0) + { + /* change port */ + g_object_set (server, "port", 6668, NULL); + } + else if (strcmp (address, "irc.au.gimp.org") == 0) + { + /* remove this server */ + empathy_irc_network_remove_server (network, server); + } + else + { + fail_if (TRUE); + } + + g_free (address); + } + + network_modified[0] = TRUE; + + g_slist_foreach (servers, (GFunc) g_object_unref, NULL); + g_slist_free (servers); + } + else if (strcmp (name, "My Server") == 0) + { + /* remove user network */ + empathy_irc_network_manager_remove (mgr, network); + network_modified[1] = TRUE; + } + else if (strcmp (name, "Freenode") == 0) + { + /* remove global network */ + empathy_irc_network_manager_remove (mgr, network); + network_modified[2] = TRUE; + } + else if (strcmp (name, "Undernet") == 0) + { + /* modify global network */ + EmpathyIrcServer *server; + + server = empathy_irc_server_new ("us.undernet.org", 6667, FALSE); + empathy_irc_network_append_server (network, server); + g_object_unref (server); + + network_modified[3] = TRUE; + } + else if (strcmp (name, "Another Server") == 0) + { + /* Don't change this one */ + } + else + { + fail_if (TRUE); + } + + g_free (name); + } + fail_if (!network_modified[0] || !network_modified[1] || !network_modified[2] + || !network_modified[3]); + + /* Add a new network */ + network = empathy_irc_network_new ("Great Server"); + server = empathy_irc_server_new ("irc.greatserver.com", 7873, TRUE); + empathy_irc_network_append_server (network, server); + empathy_irc_network_manager_add (mgr, network); + g_object_unref (server); + g_object_unref (network); + + g_slist_foreach (networks, (GFunc) g_object_unref, NULL); + g_slist_free (networks); + g_object_unref (mgr); + + + /* Now let's reload the file and check its contain */ + mgr = empathy_irc_network_manager_new (GLOBAL_SAMPLE, USER_FILE); + + networks = empathy_irc_network_manager_get_networks (mgr); + fail_if (g_slist_length (networks) != 4); + + network_checked[0] = network_checked[1] = network_checked[2] = + network_checked[3] = FALSE; + /* check networks and servers */ + for (l = networks; l != NULL; l = g_slist_next (l)) + { + gchar *name; + + g_object_get (l->data, "name", &name, NULL); + fail_if (name == NULL); + + if (strcmp (name, "GIMPNet") == 0) + { + check_network (l->data, "GIMPNet", "UTF-8", gimpnet_servers, 2); + network_checked[0] = TRUE; + } + else if (strcmp (name, "Great Server") == 0) + { + check_network (l->data, "Great Server", "UTF-8", great_server, 1); + network_checked[1] = TRUE; + } + else if (strcmp (name, "Another Server") == 0) + { + check_network (l->data, "Another Server", "UTF-8", another_server, 1); + network_checked[2] = TRUE; + } + else if (strcmp (name, "Undernet") == 0) + { + check_network (l->data, "Undernet", "UTF-8", undernet_servers, 2); + network_checked[3] = TRUE; + } + else + { + fail_if (TRUE); + } + + g_free (name); + } + fail_if (!network_checked[0] || !network_checked[1] || !network_checked[2] || + !network_checked[3]); + + g_slist_foreach (networks, (GFunc) g_object_unref, NULL); + g_slist_free (networks); + g_object_unref (mgr); +} +END_TEST + +START_TEST (test_empathy_irc_network_manager_find_network_by_address) +{ + EmpathyIrcNetworkManager *mgr; + EmpathyIrcNetwork *network; + struct server_t freenode_servers[] = { + { "irc.freenode.net", 6667, FALSE }, + { "irc.eu.freenode.net", 6667, FALSE }}; + + mgr = empathy_irc_network_manager_new (GLOBAL_SAMPLE, NULL); + + network = empathy_irc_network_manager_find_network_by_address (mgr, + "irc.freenode.net"); + fail_if (network == NULL); + check_network (network, "Freenode", "UTF-8", freenode_servers, 2); + + network = empathy_irc_network_manager_find_network_by_address (mgr, + "irc.eu.freenode.net"); + fail_if (network == NULL); + check_network (network, "Freenode", "UTF-8", freenode_servers, 2); + + network = empathy_irc_network_manager_find_network_by_address (mgr, + "unknown"); + fail_if (network != NULL); + + g_object_unref (mgr); +} +END_TEST + +START_TEST (test_no_modify_with_empty_user_file) +{ + EmpathyIrcNetworkManager *mgr; + GSList *networks; + + /* user don't have a networks file yet */ + g_unlink (USER_FILE); + + mgr = empathy_irc_network_manager_new (GLOBAL_SAMPLE, USER_FILE); + g_object_unref (mgr); + + /* We didn't modify anything so USER_FILE should be empty */ + mgr = empathy_irc_network_manager_new (NULL, USER_FILE); + + networks = empathy_irc_network_manager_get_networks (mgr); + fail_if (g_slist_length (networks) != 0); + + g_slist_foreach (networks, (GFunc) g_object_unref, NULL); + g_slist_free (networks); + g_object_unref (mgr); +} +END_TEST + +TCase * +make_empathy_irc_network_manager_tcase (void) +{ + TCase *tc = tcase_create ("empathy-irc-network-manager"); + tcase_add_test (tc, test_empathy_irc_network_manager_add); + tcase_add_test (tc, test_load_global_file); + tcase_add_test (tc, test_empathy_irc_network_manager_remove); + tcase_add_test (tc, test_load_user_file); + tcase_add_test (tc, test_load_both_files); + tcase_add_test (tc, test_modify_user_file); + tcase_add_test (tc, test_modify_both_files); + tcase_add_test (tc, test_empathy_irc_network_manager_find_network_by_address); + tcase_add_test (tc, test_no_modify_with_empty_user_file); + return tc; +} diff --git a/tests/check-empathy-irc-network.c b/tests/check-empathy-irc-network.c new file mode 100644 index 00000000..b8124a30 --- /dev/null +++ b/tests/check-empathy-irc-network.c @@ -0,0 +1,240 @@ +#include +#include +#include + +#include +#include "check-helpers.h" +#include "check-libempathy.h" +#include "check-irc-helper.h" + +#include + +START_TEST (test_empathy_irc_network_new) +{ + EmpathyIrcNetwork *network; + + network = empathy_irc_network_new ("Network1"); + check_network (network, "Network1", "UTF-8", NULL, 0); + + g_object_unref (network); +} +END_TEST + +START_TEST (test_property_change) +{ + EmpathyIrcNetwork *network; + + network = empathy_irc_network_new ("Network1"); + check_network (network, "Network1", "UTF-8", NULL, 0); + + g_object_set (network, + "name", "Network2", + "charset", "ISO-8859-1", + NULL); + + check_network (network, "Network2", "ISO-8859-1", NULL, 0); + + g_object_unref (network); + +} +END_TEST + +static gboolean modified; + +static void +modified_cb (EmpathyIrcNetwork *network, + gpointer unused) +{ + modified = TRUE; +} + +START_TEST (test_modified_signal) +{ + EmpathyIrcNetwork *network; + + network = empathy_irc_network_new ("Network1"); + check_network (network, "Network1", "UTF-8", NULL, 0); + + modified = FALSE; + g_signal_connect (network, "modified", G_CALLBACK (modified_cb), NULL); + + g_object_set (network, "name", "Network2", NULL); + fail_if (!modified); + modified = FALSE; + g_object_set (network, "name", "Network2", NULL); + fail_if (modified); + + g_object_unref (network); +} +END_TEST + +static void +add_servers (EmpathyIrcNetwork *network, + struct server_t *servers, + guint nb_servers) +{ + guint i; + + for (i = 0; i < nb_servers; i ++) + { + EmpathyIrcServer *server; + + server = empathy_irc_server_new (servers[i].address, + servers[i].port, servers[i].ssl); + modified = FALSE; + empathy_irc_network_append_server (network, server); + fail_if (!modified); + g_object_unref (server); + } +} + +START_TEST (test_add_server) +{ + EmpathyIrcNetwork *network; + EmpathyIrcServer *server; + GSList *servers, *l; + struct server_t test_servers[] = { + { "server1", 6667, FALSE }, + { "server2", 6668, TRUE }, + { "server3", 6667, FALSE }, + { "server4", 6669, TRUE }}; + struct server_t servers_without_3[] = { + { "server1", 6667, FALSE }, + { "server2", 6668, TRUE }, + { "server4", 6669, TRUE }}; + + network = empathy_irc_network_new ("Network1"); + check_network (network, "Network1", "UTF-8", NULL, 0); + + modified = FALSE; + g_signal_connect (network, "modified", G_CALLBACK (modified_cb), NULL); + + check_network (network, "Network1", "UTF-8", NULL, 0); + + /* add the servers */ + add_servers (network, test_servers, 4); + + check_network (network, "Network1", "UTF-8", test_servers, 4); + + /* Now let's remove the 3rd server */ + servers = empathy_irc_network_get_servers (network); + l = g_slist_nth (servers, 2); + fail_if (l == NULL); + server = l->data; + modified = FALSE; + empathy_irc_network_remove_server (network, server); + fail_if (!modified); + + /* free the list */ + g_slist_foreach (servers, (GFunc) g_object_unref, NULL); + g_slist_free (servers); + + /* The 3rd server should have disappear */ + check_network (network, "Network1", "UTF-8", servers_without_3, 3); + + g_object_unref (network); +} +END_TEST + +START_TEST (test_modified_signal_because_of_server) +{ + EmpathyIrcNetwork *network; + EmpathyIrcServer *server; + + network = empathy_irc_network_new ("Network1"); + check_network (network, "Network1", "UTF-8", NULL, 0); + + g_signal_connect (network, "modified", G_CALLBACK (modified_cb), NULL); + + server = empathy_irc_server_new ("server1", 6667, FALSE); + empathy_irc_network_append_server (network, server); + + /* Change server properties */ + modified = FALSE; + g_object_set (server, "address", "server2", NULL); + fail_if (!modified); + modified = FALSE; + g_object_set (server, "port", 6668, NULL); + fail_if (!modified); + modified = FALSE; + g_object_set (server, "ssl", TRUE, NULL); + fail_if (!modified); + + empathy_irc_network_remove_server (network, server); + modified = FALSE; + g_object_set (server, "address", "server3", NULL); + /* We removed the server so the network is not modified anymore */ + fail_if (modified); + + g_object_unref (network); +} +END_TEST + +START_TEST (test_empathy_irc_network_set_server_position) +{ + EmpathyIrcNetwork *network; + GSList *servers, *l; + struct server_t test_servers[] = { + { "server1", 6667, FALSE }, + { "server2", 6668, TRUE }, + { "server3", 6667, FALSE }, + { "server4", 6669, TRUE }}; + struct server_t test_servers_sorted[] = { + { "server2", 6668, TRUE }, + { "server4", 6669, TRUE }, + { "server3", 6667, FALSE }, + { "server1", 6667, FALSE }}; + + network = empathy_irc_network_new ("Network1"); + check_network (network, "Network1", "UTF-8", NULL, 0); + + modified = FALSE; + g_signal_connect (network, "modified", G_CALLBACK (modified_cb), NULL); + + /* add the servers */ + add_servers (network, test_servers, 4); + check_network (network, "Network1", "UTF-8", test_servers, 4); + + /* get servers list */ + servers = empathy_irc_network_get_servers (network); + fail_if (g_slist_length (servers) != 4); + modified = FALSE; + + /* server1 go to the last position */ + empathy_irc_network_set_server_position (network, servers->data, -1); + + /* server2 go to the first position */ + l = servers->next; + empathy_irc_network_set_server_position (network, l->data, 0); + + /* server3 go to the third position */ + l = l->next; + empathy_irc_network_set_server_position (network, l->data, 2); + + /* server4 go to the second position*/ + l = l->next; + empathy_irc_network_set_server_position (network, l->data, 1); + + fail_if (!modified); + + /* free the list */ + g_slist_foreach (servers, (GFunc) g_object_unref, NULL); + g_slist_free (servers); + + /* Check if servers are sorted */ + check_network (network, "Network1", "UTF-8", test_servers_sorted, 4); +} +END_TEST + +TCase * +make_empathy_irc_network_tcase (void) +{ + TCase *tc = tcase_create ("empathy-irc-network"); + tcase_add_test (tc, test_empathy_irc_network_new); + tcase_add_test (tc, test_property_change); + tcase_add_test (tc, test_modified_signal); + tcase_add_test (tc, test_add_server); + tcase_add_test (tc, test_modified_signal_because_of_server); + tcase_add_test (tc, test_empathy_irc_network_set_server_position); + return tc; +} diff --git a/tests/check-empathy-irc-server.c b/tests/check-empathy-irc-server.c new file mode 100644 index 00000000..52607f22 --- /dev/null +++ b/tests/check-empathy-irc-server.c @@ -0,0 +1,93 @@ +#include +#include +#include + +#include +#include "check-helpers.h" +#include "check-libempathy.h" +#include "check-irc-helper.h" + +#include + +START_TEST (test_empathy_irc_server_new) +{ + EmpathyIrcServer *server; + + server = empathy_irc_server_new ("test.localhost", 6667, TRUE); + check_server (server, "test.localhost", 6667, TRUE); + + g_object_unref (server); +} +END_TEST + +START_TEST (test_property_change) +{ + EmpathyIrcServer *server; + + server = empathy_irc_server_new ("test.localhost", 6667, TRUE); + fail_if (server == NULL); + + g_object_set (server, + "address", "test2.localhost", + "port", 6668, + "ssl", FALSE, + NULL); + + check_server (server, "test2.localhost", 6668, FALSE); + + g_object_unref (server); +} +END_TEST + +static gboolean modified = FALSE; + +static void +modified_cb (EmpathyIrcServer *server, + gpointer unused) +{ + modified = TRUE; +} + +START_TEST (test_modified_signal) +{ + EmpathyIrcServer *server; + + server = empathy_irc_server_new ("test.localhost", 6667, TRUE); + fail_if (server == NULL); + + g_signal_connect (server, "modified", G_CALLBACK (modified_cb), NULL); + + /* address */ + g_object_set (server, "address", "test2.localhost", NULL); + fail_if (!modified); + modified = FALSE; + g_object_set (server, "address", "test2.localhost", NULL); + fail_if (modified); + + /* port */ + g_object_set (server, "port", 6668, NULL); + fail_if (!modified); + modified = FALSE; + g_object_set (server, "port", 6668, NULL); + fail_if (modified); + + /* ssl */ + g_object_set (server, "ssl", FALSE, NULL); + fail_if (!modified); + modified = FALSE; + g_object_set (server, "ssl", FALSE, NULL); + fail_if (modified); + + g_object_unref (server); +} +END_TEST + +TCase * +make_empathy_irc_server_tcase (void) +{ + TCase *tc = tcase_create ("empathy-irc-server"); + tcase_add_test (tc, test_empathy_irc_server_new); + tcase_add_test (tc, test_property_change); + tcase_add_test (tc, test_modified_signal); + return tc; +} diff --git a/tests/check-irc-helper.c b/tests/check-irc-helper.c new file mode 100644 index 00000000..477b134c --- /dev/null +++ b/tests/check-irc-helper.c @@ -0,0 +1,80 @@ +#include "check-irc-helper.h" + +void +check_server (EmpathyIrcServer *server, + const gchar *_address, + guint _port, + gboolean _ssl) +{ + gchar *address; + guint port; + gboolean ssl; + + fail_if (server == NULL); + + g_object_get (server, + "address", &address, + "port", &port, + "ssl", &ssl, + NULL); + + fail_if (address == NULL || strcmp (address, _address) != 0); + fail_if (port != _port); + fail_if (ssl != _ssl); + + g_free (address); +} + +void +check_network (EmpathyIrcNetwork *network, + const gchar *_name, + const gchar *_charset, + struct server_t *_servers, + guint nb_servers) +{ + gchar *name, *charset; + GSList *servers, *l; + guint i; + + fail_if (network == NULL); + + g_object_get (network, + "name", &name, + "charset", &charset, + NULL); + + fail_if (name == NULL || strcmp (name, _name) != 0); + fail_if (charset == NULL || strcmp (charset, _charset) != 0); + + servers = empathy_irc_network_get_servers (network); + fail_if (g_slist_length (servers) != nb_servers); + + /* Is that the right servers ? */ + for (l = servers, i = 0; l != NULL; l = g_slist_next (l), i++) + { + EmpathyIrcServer *server; + gchar *address; + guint port; + gboolean ssl; + + server = l->data; + + g_object_get (server, + "address", &address, + "port", &port, + "ssl", &ssl, + NULL); + + fail_if (address == NULL || strcmp (address, _servers[i].address) + != 0); + fail_if (port != _servers[i].port); + fail_if (ssl != _servers[i].ssl); + + g_free (address); + } + + g_slist_foreach (servers, (GFunc) g_object_unref, NULL); + g_slist_free (servers); + g_free (name); + g_free (charset); +} diff --git a/tests/check-irc-helper.h b/tests/check-irc-helper.h new file mode 100644 index 00000000..32a34b60 --- /dev/null +++ b/tests/check-irc-helper.h @@ -0,0 +1,27 @@ +#include +#include + +#include +#include "check-helpers.h" + +#include +#include +#include + +#ifndef __CHECK_IRC_HELPER_H__ +#define __CHECK_IRC_HELPER_H__ + +struct server_t +{ + gchar *address; + guint port; + gboolean ssl; +}; + +void check_server (EmpathyIrcServer *server, const gchar *_address, + guint _port, gboolean _ssl); + +void check_network (EmpathyIrcNetwork *network, const gchar *_name, + const gchar *_charset, struct server_t *_servers, guint nb_servers); + +#endif /* __CHECK_IRC_HELPER_H__ */ diff --git a/tests/check-libempathy.h b/tests/check-libempathy.h index 1f330258..0f9388dc 100644 --- a/tests/check-libempathy.h +++ b/tests/check-libempathy.h @@ -2,5 +2,8 @@ #define __CHECK_LIBEMPATHY__ TCase * make_empathy_utils_tcase (void); +TCase * make_empathy_irc_server_tcase (void); +TCase * make_empathy_irc_network_tcase (void); +TCase * make_empathy_irc_network_manager_tcase (void); #endif /* #ifndef __CHECK_LIBEMPATHY__ */ diff --git a/tests/check-main.c b/tests/check-main.c index 6dcfe323..f0e366d0 100644 --- a/tests/check-main.c +++ b/tests/check-main.c @@ -16,6 +16,9 @@ make_libempathy_suite (void) Suite *s = suite_create ("libempathy"); suite_add_tcase (s, make_empathy_utils_tcase ()); + suite_add_tcase (s, make_empathy_irc_server_tcase ()); + suite_add_tcase (s, make_empathy_irc_network_tcase ()); + suite_add_tcase (s, make_empathy_irc_network_manager_tcase ()); return s; } diff --git a/tests/xml/.gitignore b/tests/xml/.gitignore new file mode 100644 index 00000000..01af91dc --- /dev/null +++ b/tests/xml/.gitignore @@ -0,0 +1 @@ +user-irc-networks.xml diff --git a/tests/xml/default-irc-networks-sample.xml b/tests/xml/default-irc-networks-sample.xml new file mode 100644 index 00000000..257919c2 --- /dev/null +++ b/tests/xml/default-irc-networks-sample.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/xml/user-irc-networks-sample.xml b/tests/xml/user-irc-networks-sample.xml new file mode 100644 index 00000000..9e4f0869 --- /dev/null +++ b/tests/xml/user-irc-networks-sample.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +