changeset 12246:b7a51e68d0b8

[gaim-migrate @ 14548] Make some things static and namespace session_init and session_end committer: Tailor Script <tailor@pidgin.im>
author Mark Doliner <mark@kingant.net>
date Mon, 28 Nov 2005 06:20:06 +0000
parents 465ddcb3e9e8
children 99416d2f609f
files src/gtkblist.c src/gtkdialogs.h src/gtkmain.c src/gtkplugin.c src/gtksavedstatuses.c src/gtksession.c src/gtksession.h src/proxy.c src/session.c
diffstat 9 files changed, 470 insertions(+), 418 deletions(-) [+]
line wrap: on
line diff
--- a/src/gtkblist.c	Mon Nov 28 05:28:01 2005 +0000
+++ b/src/gtkblist.c	Mon Nov 28 06:20:06 2005 +0000
@@ -5446,7 +5446,8 @@
 	}
 }
 
-void sortmethod_act(GtkCheckMenuItem *checkmenuitem, char *id)
+static void
+sortmethod_act(GtkCheckMenuItem *checkmenuitem, char *id)
 {
 	if (gtk_check_menu_item_get_active(checkmenuitem))
 	{
--- a/src/gtkdialogs.h	Mon Nov 28 05:28:01 2005 +0000
+++ b/src/gtkdialogs.h	Mon Nov 28 06:20:06 2005 +0000
@@ -54,9 +54,4 @@
 			gtk_window_set_type_hint(GTK_WINDOW(x), GDK_WINDOW_TYPE_HINT_DIALOG)
 #define GAIM_WINDOW_ICONIFIED(x) (gdk_window_get_state(GTK_WIDGET(x)->window) & GDK_WINDOW_STATE_ICONIFIED)
 
-/* Functions in session.c */
-extern void session_init(gchar *, gchar *, gchar *);
-extern void session_end();
-
-
 #endif /* _GAIM_GTKDIALOGS_H_ */
--- a/src/gtkmain.c	Mon Nov 28 05:28:01 2005 +0000
+++ b/src/gtkmain.c	Mon Nov 28 06:20:06 2005 +0000
@@ -58,6 +58,7 @@
 #include "gtkrequest.h"
 #include "gtkroomlist.h"
 #include "gtksavedstatuses.h"
+#include "gtksession.h"
 #include "gtksound.h"
 #include "gtkthemes.h"
 #include "gtkutils.h"
@@ -280,7 +281,7 @@
 {
 #ifdef USE_SM
 	/* unplug */
-	session_end();
+	gaim_gtk_session_end();
 #endif
 
 	/* Save the plugins we have loaded for next time. */
@@ -647,7 +648,7 @@
 	ui_main();
 
 #ifdef USE_SM
-	session_init(argv[0], opt_session_arg, opt_config_dir_arg);
+	gaim_gtk_session_init(argv[0], opt_session_arg, opt_config_dir_arg);
 #endif
 	if (opt_session_arg != NULL) {
 		g_free(opt_session_arg);
--- a/src/gtkplugin.c	Mon Nov 28 05:28:01 2005 +0000
+++ b/src/gtkplugin.c	Mon Nov 28 06:20:06 2005 +0000
@@ -31,6 +31,8 @@
 
 #include <string.h>
 
+#define GAIM_RESPONSE_CONFIGURE 98121
+
 static GtkWidget *plugin_dialog = NULL;
 static GtkWidget *plugin_details = NULL;
 static GtkWidget *pref_button = NULL;
@@ -206,8 +208,8 @@
 	g_free(description);
 
 
-	gtk_list_store_set (GTK_LIST_STORE (model), &iter, 
- 			    0, gaim_plugin_is_loaded(plug),
+	gtk_list_store_set (GTK_LIST_STORE (model), &iter,
+			    0, gaim_plugin_is_loaded(plug),
 			    -1);
 
 	gtk_tree_path_free(path);
@@ -217,7 +219,7 @@
 static gboolean ensure_plugin_visible(void *data)
 {
 	GtkTreeSelection *sel = GTK_TREE_SELECTION(data);
-      	GtkTreeView *tv = gtk_tree_selection_get_tree_view(sel);
+	GtkTreeView *tv = gtk_tree_selection_get_tree_view(sel);
 	GtkTreeModel *model = gtk_tree_view_get_model(tv);
 	GtkTreePath *path;
 	GtkTreeIter iter;
@@ -301,7 +303,7 @@
 		}
 		plugin_dialog = NULL;
 		break;
-	case 98121:
+	case GAIM_RESPONSE_CONFIGURE:
 		if (! gtk_tree_selection_get_selected (sel, &model, &iter))
 			return;
 		gtk_tree_model_get_value (model, &iter, 2, &val);
@@ -346,14 +348,14 @@
 
 	if (!gtk_tree_selection_get_selected(sel, &model, &iter))
 		return;
-	
+
 	gtk_tree_model_get(model, &iter, 2, &plugin, -1);
 
 	if (!gaim_plugin_is_loaded(plugin))
 		return;
 
 	/* Now show the pref-dialog for the plugin */
-	plugin_dialog_response_cb(NULL, 98121, sel);
+	plugin_dialog_response_cb(NULL, GAIM_RESPONSE_CONFIGURE, sel);
 }
 
 void gaim_gtk_plugin_dialog_show()
@@ -375,8 +377,10 @@
 						    NULL,
 						    GTK_DIALOG_NO_SEPARATOR,
 						    NULL);
-	pref_button = gtk_dialog_add_button(GTK_DIALOG(plugin_dialog), GTK_STOCK_PREFERENCES, 98121);
-	gtk_dialog_add_button(GTK_DIALOG(plugin_dialog), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
+	pref_button = gtk_dialog_add_button(GTK_DIALOG(plugin_dialog),
+						_("_Configure Plugin"), GAIM_RESPONSE_CONFIGURE);
+	gtk_dialog_add_button(GTK_DIALOG(plugin_dialog),
+						GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
 	gtk_widget_set_sensitive(pref_button, FALSE);
 	gtk_window_set_role(GTK_WINDOW(plugin_dialog), "plugins");
 
@@ -408,7 +412,7 @@
 	gtk_tree_view_column_set_sort_column_id(col, 0);
 	g_signal_connect (G_OBJECT(rend), "toggled",
 			  G_CALLBACK(plugin_load), ls);
-   
+
 	rendt = gtk_cell_renderer_text_new();
 	col = gtk_tree_view_column_new_with_attributes (_("Name"),
 							rendt,
@@ -422,7 +426,7 @@
 	gtk_tree_view_column_set_sort_column_id(col, 1);
 	g_object_unref(G_OBJECT(ls));
 	gtk_container_add(GTK_CONTAINER(sw), event_view);
-	
+
 	expander = gtk_expander_new(_("<b>Plugin Details</b>"));
 	gtk_expander_set_use_markup(GTK_EXPANDER(expander), TRUE);
 	plugin_details = gtk_label_new(NULL);
--- a/src/gtksavedstatuses.c	Mon Nov 28 05:28:01 2005 +0000
+++ b/src/gtksavedstatuses.c	Mon Nov 28 06:20:06 2005 +0000
@@ -1194,7 +1194,7 @@
 	return FALSE;
 }
 
-void
+static void
 substatus_editor_cancel_cb(GtkButton *button, gpointer user_data)
 {
 	SubStatusEditor *dialog = user_data;
@@ -1234,7 +1234,7 @@
 	return FALSE;
 }
 
-void
+static void
 substatus_editor_ok_cb(GtkButton *button, gpointer user_data)
 {
 	SubStatusEditor *dialog = user_data;
@@ -1452,7 +1452,8 @@
  * Utilities                                                              *
  **************************************************************************/
 
-void status_menu_cb(GtkComboBox *widget, void(*callback)(GaimSavedStatus*))
+static void
+status_menu_cb(GtkComboBox *widget, void(*callback)(GaimSavedStatus*))
 {
 	GtkTreeIter iter;
 	gchar *title = NULL;
@@ -1487,7 +1488,7 @@
 			i++;
 		}
 	}
-	
+
 	gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), index);
 	g_signal_connect(G_OBJECT(combobox), "changed", G_CALLBACK(status_menu_cb), callback);
 	return combobox;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gtksession.c	Mon Nov 28 06:20:06 2005 +0000
@@ -0,0 +1,399 @@
+/*
+ * @file gtksession.c X Windows session management API
+ * @ingroup gtkui
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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
+ *
+ */
+#include "internal.h"
+
+#include "core.h"
+#include "debug.h"
+#include "eventloop.h"
+
+#ifdef USE_SM
+
+#include <X11/ICE/ICElib.h>
+#include <X11/SM/SMlib.h>
+#include <gdk/gdkx.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define ERROR_LENGTH 512
+
+static IceIOErrorHandler ice_installed_io_error_handler;
+static SmcConn session = NULL;
+static gchar *myself = NULL;
+static gboolean had_first_save = FALSE;
+static gboolean session_managed = FALSE;
+
+/* ICE belt'n'braces stuff */
+
+struct ice_connection_info {
+	IceConn connection;
+	guint input_id;
+};
+
+static void ice_process_messages(gpointer data, gint fd,
+								 GaimInputCondition condition) {
+	struct ice_connection_info *conninfo = (struct ice_connection_info*) data;
+	IceProcessMessagesStatus status;
+
+	/* please don't block... please! */
+	status = IceProcessMessages(conninfo->connection, NULL, NULL);
+
+	if (status == IceProcessMessagesIOError) {
+		gaim_debug(GAIM_DEBUG_INFO, "Session Management",
+				   "ICE IO error, closing connection... ");
+
+		/* IO error, please disconnect */
+		IceSetShutdownNegotiation(conninfo->connection, False);
+		IceCloseConnection(conninfo->connection);
+
+		gaim_debug(GAIM_DEBUG_INFO, NULL, "done.\n");
+
+		/* cancel the handler */
+		gaim_input_remove(conninfo->input_id);
+	}
+}
+
+static void ice_connection_watch(IceConn connection, IcePointer client_data,
+	      Bool opening, IcePointer *watch_data) {
+	struct ice_connection_info *conninfo = NULL;
+
+	if (opening) {
+		gaim_debug(GAIM_DEBUG_INFO, "Session Management",
+				   "Handling new ICE connection... ");
+
+		/* ensure ICE connection is not passed to child processes */
+		fcntl(IceConnectionNumber(connection), F_SETFD, FD_CLOEXEC);
+
+		conninfo = g_new(struct ice_connection_info, 1);
+		conninfo->connection = connection;
+
+		/* watch the connection */
+		conninfo->input_id = gaim_input_add(IceConnectionNumber(connection), GAIM_INPUT_READ,
+											ice_process_messages, conninfo);
+		*watch_data = conninfo;
+	} else {
+		gaim_debug(GAIM_DEBUG_INFO, "Session Management",
+				   "Handling closed ICE connection... ");
+
+		/* get the input ID back and stop watching it */
+		conninfo = (struct ice_connection_info*) *watch_data;
+		gaim_input_remove(conninfo->input_id);
+		g_free(conninfo);
+	}
+
+	gaim_debug(GAIM_DEBUG_INFO, NULL, "done.\n");
+}
+
+/* We call any handler installed before (or after) ice_init but 
+ * avoid calling the default libICE handler which does an exit().
+ *
+ * This means we do nothing by default, which is probably correct,
+ * the connection will get closed by libICE
+ */
+
+static void ice_io_error_handler(IceConn connection) {
+	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
+			   "Handling ICE IO error... ");
+
+	if (ice_installed_io_error_handler)
+		(*ice_installed_io_error_handler)(connection);
+
+	gaim_debug(GAIM_DEBUG_INFO, NULL, "done.\n");
+}
+
+static void ice_init() {
+	IceIOErrorHandler default_handler;
+
+	ice_installed_io_error_handler = IceSetIOErrorHandler(NULL);
+	default_handler = IceSetIOErrorHandler(ice_io_error_handler);
+
+	if (ice_installed_io_error_handler == default_handler)
+		ice_installed_io_error_handler = NULL;
+
+	IceAddConnectionWatch(ice_connection_watch, NULL);
+
+	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
+			   "ICE initialized.\n");
+}
+
+/* my magic utility function */
+
+static gchar **session_make_command(gchar *client_id, gchar *config_dir) {
+	gint i = 2;
+	gint j = 0;
+	gchar **ret;
+
+	if (client_id) i += 2;
+	if (config_dir)	i += 2; /* we will specify gaim's user dir */
+
+	ret = g_new(gchar *, i);
+	ret[j++] = g_strdup(myself);
+
+	if (client_id) {
+		ret[j++] = g_strdup("--session");
+		ret[j++] = g_strdup(client_id);
+	}
+
+	if (config_dir) {
+		ret[j++] = g_strdup("--config");
+		ret[j++] = g_strdup(config_dir);
+	}
+
+	ret[j++] = NULL;
+
+	return ret;
+}
+
+/* SM callback handlers */
+
+static void session_save_yourself(SmcConn conn, SmPointer data, int save_type,
+       Bool shutdown, int interact_style, Bool fast) {
+	if (had_first_save == FALSE && save_type == SmSaveLocal &&
+	      interact_style == SmInteractStyleNone && !shutdown &&
+	      !fast) {
+		/* this is just a dry run, spit it back */
+		gaim_debug(GAIM_DEBUG_INFO, "Session Management",
+				   "Received first save_yourself\n");
+		SmcSaveYourselfDone(conn, True);
+		had_first_save = TRUE;
+		return;
+	}
+
+	/* tum ti tum... don't add anything else here without *
+         * reading SMlib.PS from an X.org ftp server near you */
+
+	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
+			   "Received save_yourself\n");
+
+	if (save_type == SmSaveGlobal || save_type == SmSaveBoth) {
+		/* may as well do something ... */
+		/* or not -- save_prefs(); */
+	}
+
+	SmcSaveYourselfDone(conn, True);
+}
+
+static void session_die(SmcConn conn, SmPointer data) {
+	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
+			   "Received die\n");
+	gaim_core_quit();
+}
+
+static void session_save_complete(SmcConn conn, SmPointer data) {
+	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
+			   "Received save_complete\n");
+}
+
+static void session_shutdown_cancelled(SmcConn conn, SmPointer data) {
+	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
+			   "Received shutdown_cancelled\n");
+}
+
+/* utility functions stolen from Gnome-client */
+
+static void session_set_value(SmcConn conn, gchar *name, char *type,
+	      int num_vals, SmPropValue *vals) {
+	SmProp *proplist[1];
+	SmProp prop;
+
+	g_return_if_fail(conn);
+
+	prop.name = name;
+	prop.type = type;
+	prop.num_vals = num_vals;
+	prop.vals = vals;
+
+	proplist[0] = &prop;
+	SmcSetProperties(conn, 1, proplist);
+}
+
+static void session_set_string(SmcConn conn, gchar *name, gchar *value) {
+	SmPropValue val;
+
+	g_return_if_fail(name);
+
+	val.length = strlen (value)+1;
+	val.value  = value;
+
+	session_set_value(conn, name, SmARRAY8, 1, &val);
+}
+
+static void session_set_gchar(SmcConn conn, gchar *name, gchar value) {
+	SmPropValue val;
+
+	g_return_if_fail(name);
+
+	val.length = 1;
+	val.value  = &value;
+
+	session_set_value(conn, name, SmCARD8, 1, &val);
+}
+
+static void session_set_array(SmcConn conn, gchar *name, gchar *array[]) {
+	gint    argc;
+	gchar **ptr;
+	gint    i;
+
+	SmPropValue *vals;
+
+	g_return_if_fail (name);
+
+	/* We count the number of elements in our array.  */
+	for (ptr = array, argc = 0; *ptr ; ptr++, argc++) /* LOOP */;
+
+	/* Now initialize the 'vals' array.  */
+	vals = g_new (SmPropValue, argc);
+	for (ptr = array, i = 0 ; i < argc ; ptr++, i++) {
+		vals[i].length = strlen (*ptr);
+		vals[i].value  = *ptr;
+	}
+
+	session_set_value(conn, name, SmLISTofARRAY8, argc, vals);
+
+	g_free (vals);
+}
+
+#endif /* USE_SM */
+
+/* setup functions */
+
+void
+gaim_gtk_session_init(gchar *argv0, gchar *previous_id, gchar *config_dir)
+{
+#ifdef USE_SM
+	SmcCallbacks callbacks;
+	gchar *client_id = NULL;
+	gchar error[ERROR_LENGTH] = "";
+	gchar *tmp = NULL;
+	gchar **cmd = NULL;
+
+	if (session != NULL) {
+		/* session is already established, what the hell is going on? */
+		gaim_debug(GAIM_DEBUG_WARNING, "Session Management",
+				   "Duplicated call to gaim_gtk_session_init!\n");
+		return;
+	}
+
+	if (g_getenv("SESSION_MANAGER") == NULL) {
+		gaim_debug(GAIM_DEBUG_ERROR, "Session Management",
+				   "No SESSION_MANAGER found, aborting.\n");
+		return;
+	}
+
+	ice_init();
+
+	callbacks.save_yourself.callback         = session_save_yourself;
+	callbacks.die.callback                   = session_die;
+	callbacks.save_complete.callback         = session_save_complete;
+	callbacks.shutdown_cancelled.callback    = session_shutdown_cancelled;
+
+	callbacks.save_yourself.client_data      = NULL;
+	callbacks.die.client_data                = NULL;
+	callbacks.save_complete.client_data      = NULL;
+	callbacks.shutdown_cancelled.client_data = NULL;
+
+	if (previous_id) {
+		gaim_debug(GAIM_DEBUG_INFO, "Session Management",
+				   "Connecting with previous ID %s\n", previous_id);
+	} else {
+		gaim_debug(GAIM_DEBUG_INFO, "Session Management",
+				   "Connecting with no previous ID\n");
+	}
+
+	session = SmcOpenConnection(NULL, "session", SmProtoMajor, SmProtoMinor, SmcSaveYourselfProcMask |
+		    SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
+		    &callbacks, previous_id, &client_id, ERROR_LENGTH, error);
+
+	if (session == NULL) {
+		if (error[0] != '\0') {
+			gaim_debug(GAIM_DEBUG_ERROR, "Session Management",
+					   "Connection failed with error: %s\n", error);
+		} else {
+			gaim_debug(GAIM_DEBUG_ERROR, "Session Management",
+					   "Connetion failed with unknown error.\n");
+		}
+		return;
+	}
+
+	tmp = SmcVendor(session);
+	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
+			   "Connected to manager (%s) with client ID %s\n",
+			   tmp, client_id);
+	g_free(tmp);
+
+	session_managed = TRUE;
+	gdk_set_sm_client_id(client_id);
+
+	tmp = g_get_current_dir();
+	session_set_string(session, SmCurrentDirectory, tmp);
+	g_free(tmp);
+
+	tmp = g_strdup_printf("%d", (int) getpid());
+	session_set_string(session, SmProcessID, tmp);
+	g_free(tmp);
+
+	tmp = g_strdup(g_get_user_name());
+	session_set_string(session, SmUserID, tmp);
+	g_free(tmp);
+
+	session_set_gchar(session, SmRestartStyleHint, (gchar) SmRestartIfRunning);
+	session_set_string(session, SmProgram, g_get_prgname());
+
+	myself = g_strdup(argv0);
+	gaim_debug(GAIM_DEBUG_MISC, "Session Management",
+			   "Using %s as command\n", myself);
+
+	cmd = session_make_command(NULL, config_dir);
+	session_set_array(session, SmCloneCommand, cmd);
+	g_strfreev(cmd);
+
+	/* this is currently useless, but gnome-session warns 'the following applications will not
+	   save their current status' bla bla if we don't have it and the user checks 'Save Session'
+	   when they log out */
+	cmd = g_new(gchar *, 2);
+	cmd[0] = g_strdup("/bin/true");
+	cmd[1] = NULL;
+	session_set_array(session, SmDiscardCommand, cmd);
+	g_strfreev(cmd);
+
+	cmd = session_make_command(client_id, config_dir);
+	session_set_array(session, SmRestartCommand, cmd);
+	g_strfreev(cmd);
+
+	g_free(client_id);
+#endif /* USE_SM */
+}
+
+void
+gaim_gtk_session_end()
+{
+#ifdef USE_SM
+	if (session == NULL) /* no session to close */
+		return;
+
+	SmcCloseConnection(session, 0, NULL);
+
+	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
+			   "Connection closed.\n");
+#endif /* USE_SM */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/gtksession.h	Mon Nov 28 06:20:06 2005 +0000
@@ -0,0 +1,45 @@
+/**
+ * @file gtksession.h X Windows session management API
+ * @ingroup gtkui
+ *
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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
+ */
+#ifndef _GAIM_GTKSESSION_H_
+#define _GAIM_GTKSESSION_H_
+
+/**************************************************************************/
+/** @name X Windows session subsystem                                     */
+/**************************************************************************/
+/*@{*/
+
+/**
+ * TODO
+ */
+void gaim_gtk_session_init(gchar *argv0, gchar *previous_id, gchar *config_dir);
+
+/**
+ * TODO
+ */
+void gaim_gtk_session_end();
+
+/*@}*/
+
+#endif /* _GAIM_GTKSESSION_H_ */
--- a/src/proxy.c	Mon Nov 28 05:28:01 2005 +0000
+++ b/src/proxy.c	Mon Nov 28 06:20:06 2005 +0000
@@ -52,7 +52,7 @@
 
 static void try_connect(struct PHB *);
 
-const char* socks5errors[] = {
+static const char *socks5errors[] = {
 	"succeeded\n",
 	"general SOCKS server failure\n",
 	"connection not allowed by ruleset\n",
@@ -271,7 +271,7 @@
 
 static int number_of_dns_children = 0;
 
-const int MAX_DNS_CHILDREN = 2;
+static const int MAX_DNS_CHILDREN = 2;
 
 typedef struct {
 	char hostname[512];
--- a/src/session.c	Mon Nov 28 05:28:01 2005 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,394 +0,0 @@
-/*
- * session management for Gaim
- *
- * Gaim is the legal property of its developers, whose names are too numerous
- * to list here.  Please refer to the COPYRIGHT file distributed with this
- * source distribution.
- *
- * 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
- *
- */
-#include "internal.h"
-
-#include "core.h"
-#include "debug.h"
-#include "eventloop.h"
-
-#ifdef USE_SM
-
-#include <X11/ICE/ICElib.h>
-#include <X11/SM/SMlib.h>
-#include <gdk/gdkx.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#define ERROR_LENGTH 512
-
-static IceIOErrorHandler ice_installed_io_error_handler;
-static SmcConn session = NULL;
-static gchar *myself = NULL;
-static gboolean had_first_save = FALSE;
-gboolean session_managed = FALSE;
-
-/* ICE belt'n'braces stuff */
-
-struct ice_connection_info {
-	IceConn connection;
-	guint input_id;
-};
-
-static void ice_process_messages(gpointer data, gint fd,
-								 GaimInputCondition condition) {
-	struct ice_connection_info *conninfo = (struct ice_connection_info*) data;
-	IceProcessMessagesStatus status;
-
-	/* please don't block... please! */
-	status = IceProcessMessages(conninfo->connection, NULL, NULL);
-
-	if (status == IceProcessMessagesIOError) {
-		gaim_debug(GAIM_DEBUG_INFO, "Session Management",
-				   "ICE IO error, closing connection... ");
-
-		/* IO error, please disconnect */
-		IceSetShutdownNegotiation(conninfo->connection, False);
-		IceCloseConnection(conninfo->connection);
-
-		gaim_debug(GAIM_DEBUG_INFO, NULL, "done.\n");
-
-		/* cancel the handler */
-		gaim_input_remove(conninfo->input_id);
-	}
-}
-
-static void ice_connection_watch(IceConn connection, IcePointer client_data,
-	      Bool opening, IcePointer *watch_data) {
-	struct ice_connection_info *conninfo = NULL;
-
-	if (opening) {
-		gaim_debug(GAIM_DEBUG_INFO, "Session Management",
-				   "Handling new ICE connection... ");
-
-		/* ensure ICE connection is not passed to child processes */
-		fcntl(IceConnectionNumber(connection), F_SETFD, FD_CLOEXEC);
-
-		conninfo = g_new(struct ice_connection_info, 1);
-		conninfo->connection = connection;
-
-		/* watch the connection */
-		conninfo->input_id = gaim_input_add(IceConnectionNumber(connection), GAIM_INPUT_READ,
-											ice_process_messages, conninfo);
-		*watch_data = conninfo;
-	} else {
-		gaim_debug(GAIM_DEBUG_INFO, "Session Management",
-				   "Handling closed ICE connection... ");
-
-		/* get the input ID back and stop watching it */
-		conninfo = (struct ice_connection_info*) *watch_data;
-		gaim_input_remove(conninfo->input_id);
-		g_free(conninfo);
-	}
-
-	gaim_debug(GAIM_DEBUG_INFO, NULL, "done.\n");
-}
-
-/* We call any handler installed before (or after) ice_init but 
- * avoid calling the default libICE handler which does an exit().
- *
- * This means we do nothing by default, which is probably correct,
- * the connection will get closed by libICE
- */
-
-static void ice_io_error_handler(IceConn connection) {
-	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
-			   "Handling ICE IO error... ");
-
-	if (ice_installed_io_error_handler)
-		(*ice_installed_io_error_handler)(connection);
-
-	gaim_debug(GAIM_DEBUG_INFO, NULL, "done.\n");
-}
-
-static void ice_init() {
-	IceIOErrorHandler default_handler;
-
-	ice_installed_io_error_handler = IceSetIOErrorHandler(NULL);
-	default_handler = IceSetIOErrorHandler(ice_io_error_handler);
-
-	if (ice_installed_io_error_handler == default_handler)
-		ice_installed_io_error_handler = NULL;
-
-	IceAddConnectionWatch(ice_connection_watch, NULL);
-
-	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
-			   "ICE initialized.\n");
-}
-
-/* my magic utility function */
-
-static gchar **session_make_command(gchar *client_id, gchar *config_dir) {
-	gint i = 2;
-	gint j = 0;
-	gchar **ret;
-
-	if (client_id) i += 2;
-	if (config_dir)	i += 2; /* we will specify gaim's user dir */
-
-	ret = g_new(gchar *, i);
-	ret[j++] = g_strdup(myself);
-
-	if (client_id) {
-		ret[j++] = g_strdup("--session");
-		ret[j++] = g_strdup(client_id);
-	}
-
-	if (config_dir) {
-		ret[j++] = g_strdup("--config");
-		ret[j++] = g_strdup(config_dir);
-	}
-
-	ret[j++] = NULL;
-
-	return ret;
-}
-
-/* SM callback handlers */
-
-static void session_save_yourself(SmcConn conn, SmPointer data, int save_type,
-       Bool shutdown, int interact_style, Bool fast) {
-	if (had_first_save == FALSE && save_type == SmSaveLocal &&
-	      interact_style == SmInteractStyleNone && !shutdown &&
-	      !fast) {
-		/* this is just a dry run, spit it back */
-		gaim_debug(GAIM_DEBUG_INFO, "Session Management",
-				   "Received first save_yourself\n");
-		SmcSaveYourselfDone(conn, True);
-		had_first_save = TRUE;
-		return;
-	}
-
-	/* tum ti tum... don't add anything else here without *
-         * reading SMlib.PS from an X.org ftp server near you */
-
-	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
-			   "Received save_yourself\n");
-
-	if (save_type == SmSaveGlobal || save_type == SmSaveBoth) {
-		/* may as well do something ... */
-		/* or not -- save_prefs(); */
-	}
-
-	SmcSaveYourselfDone(conn, True);
-}
-
-static void session_die(SmcConn conn, SmPointer data) {
-	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
-			   "Received die\n");
-	gaim_core_quit();
-}
-
-static void session_save_complete(SmcConn conn, SmPointer data) {
-	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
-			   "Received save_complete\n");
-}
-
-static void session_shutdown_cancelled(SmcConn conn, SmPointer data) {
-	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
-			   "Received shutdown_cancelled\n");
-}
-
-/* utility functions stolen from Gnome-client */
-
-static void session_set_value(SmcConn conn, gchar *name, char *type,
-	      int num_vals, SmPropValue *vals) {
-	SmProp *proplist[1];
-	SmProp prop;
-
-	g_return_if_fail(conn);
-
-	prop.name = name;
-	prop.type = type;
-	prop.num_vals = num_vals;
-	prop.vals = vals;
-
-	proplist[0] = &prop;
-	SmcSetProperties(conn, 1, proplist);
-}
-
-static void session_set_string(SmcConn conn, gchar *name, gchar *value) {
-	SmPropValue val;
-
-	g_return_if_fail(name);
-
-	val.length = strlen (value)+1;
-	val.value  = value;
-
-	session_set_value(conn, name, SmARRAY8, 1, &val);
-}
-
-static void session_set_gchar(SmcConn conn, gchar *name, gchar value) {
-	SmPropValue val;
-
-	g_return_if_fail(name);
-
-	val.length = 1;
-	val.value  = &value;
-
-	session_set_value(conn, name, SmCARD8, 1, &val);
-}
-
-static void session_set_array(SmcConn conn, gchar *name, gchar *array[]) {
-	gint    argc;
-	gchar **ptr;
-	gint    i;
-
-	SmPropValue *vals;
-
-	g_return_if_fail (name);
-
-	/* We count the number of elements in our array.  */
-	for (ptr = array, argc = 0; *ptr ; ptr++, argc++) /* LOOP */;
-
-	/* Now initialize the 'vals' array.  */
-	vals = g_new (SmPropValue, argc);
-	for (ptr = array, i = 0 ; i < argc ; ptr++, i++) {
-		vals[i].length = strlen (*ptr);
-		vals[i].value  = *ptr;
-	}
-
-	session_set_value(conn, name, SmLISTofARRAY8, argc, vals);
-
-	g_free (vals);
-}
-
-#endif /* USE_SM */
-
-/* setup functions */
-
-void session_init(gchar *argv0, gchar *previous_id, gchar *config_dir) {
-#ifdef USE_SM
-	SmcCallbacks callbacks;
-	gchar *client_id = NULL;
-	gchar error[ERROR_LENGTH] = "";
-	gchar *tmp = NULL;
-	gchar **cmd = NULL;
-
-	if (session != NULL) {
-		/* session is already established, what the hell is going on? */
-		gaim_debug(GAIM_DEBUG_WARNING, "Session Management",
-				   "Duplicated call to session_init!\n");
-		return;
-	}
-
-	if (g_getenv("SESSION_MANAGER") == NULL) {
-		gaim_debug(GAIM_DEBUG_ERROR, "Session Management",
-				   "No SESSION_MANAGER found, aborting.\n");
-		return;
-	}
-
-	ice_init();
-
-	callbacks.save_yourself.callback         = session_save_yourself;
-	callbacks.die.callback                   = session_die;
-	callbacks.save_complete.callback         = session_save_complete;
-	callbacks.shutdown_cancelled.callback    = session_shutdown_cancelled;
-
-	callbacks.save_yourself.client_data      = NULL;
-	callbacks.die.client_data                = NULL;
-	callbacks.save_complete.client_data      = NULL;
-	callbacks.shutdown_cancelled.client_data = NULL;
-
-	if (previous_id) {
-		gaim_debug(GAIM_DEBUG_INFO, "Session Management",
-				   "Connecting with previous ID %s\n", previous_id);
-	} else {
-		gaim_debug(GAIM_DEBUG_INFO, "Session Management",
-				   "Connecting with no previous ID\n");
-	}
-
-	session = SmcOpenConnection(NULL, "session", SmProtoMajor, SmProtoMinor, SmcSaveYourselfProcMask |
-		    SmcDieProcMask | SmcSaveCompleteProcMask | SmcShutdownCancelledProcMask,
-		    &callbacks, previous_id, &client_id, ERROR_LENGTH, error);
-
-	if (session == NULL) {
-		if (error[0] != '\0') {
-			gaim_debug(GAIM_DEBUG_ERROR, "Session Management",
-					   "Connection failed with error: %s\n", error);
-		} else {
-			gaim_debug(GAIM_DEBUG_ERROR, "Session Management",
-					   "Connetion failed with unknown error.\n");
-		}
-		return;
-	}
-
-	tmp = SmcVendor(session);
-	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
-			   "Connected to manager (%s) with client ID %s\n",
-			   tmp, client_id);
-	g_free(tmp);
-
-	session_managed = TRUE;
-	gdk_set_sm_client_id(client_id);
-
-	tmp = g_get_current_dir();
-	session_set_string(session, SmCurrentDirectory, tmp);
-	g_free(tmp);
-
-	tmp = g_strdup_printf("%d", (int) getpid());
-	session_set_string(session, SmProcessID, tmp);
-	g_free(tmp);
-
-	tmp = g_strdup(g_get_user_name());
-	session_set_string(session, SmUserID, tmp);
-	g_free(tmp);
-
-	session_set_gchar(session, SmRestartStyleHint, (gchar) SmRestartIfRunning);
-	session_set_string(session, SmProgram, g_get_prgname());
-
-	myself = g_strdup(argv0);
-	gaim_debug(GAIM_DEBUG_MISC, "Session Management",
-			   "Using %s as command\n", myself);
-
-	cmd = session_make_command(NULL, config_dir);
-	session_set_array(session, SmCloneCommand, cmd);
-	g_strfreev(cmd);
-
-	/* this is currently useless, but gnome-session warns 'the following applications will not
-	   save their current status' bla bla if we don't have it and the user checks 'Save Session'
-	   when they log out */
-	cmd = g_new(gchar *, 2);
-	cmd[0] = g_strdup("/bin/true");
-	cmd[1] = NULL;
-	session_set_array(session, SmDiscardCommand, cmd);
-	g_strfreev(cmd);
-
-	cmd = session_make_command(client_id, config_dir);
-	session_set_array(session, SmRestartCommand, cmd);
-	g_strfreev(cmd);
-
-	g_free(client_id);
-#endif /* USE_SM */
-}
-
-void session_end() {
-#ifdef USE_SM
-	if (session == NULL) /* no session to close */
-		return;
-
-	SmcCloseConnection(session, 0, NULL);
-
-	gaim_debug(GAIM_DEBUG_INFO, "Session Management",
-			   "Connection closed.\n");
-#endif /* USE_SM */
-}