r1615: Fix massive security hole (alexander).
[rox-filer.git] / ROX-Filer / src / sc.c
blobc9d4be0bec89c4fe785abcd40f6817fbc6dd9bb4
1 /*
2 * $Id$
4 * ROX-Filer, filer for the ROX desktop project
5 * Copyright (C) 2002, the ROX-Filer team.
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
17 * You should have received a copy of the GNU General Public License along with
18 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
22 /* sc.c - XSMP client support */
24 #include <stdlib.h>
25 #include <fcntl.h>
26 #include <gtk/gtk.h>
27 #include <X11/Xlib.h>
28 #include <X11/SM/SMlib.h>
29 #include <pwd.h>
30 #include <string.h>
32 #include "sc.h"
34 static SmPropValue *make_list_of_array_value(const gchar *vals[], gint nvals)
36 SmPropValue *values = g_new(SmPropValue, nvals);
37 gint i;
39 for(i = 0; i < nvals; i++)
41 values[i].value = g_strdup(vals[i]);
42 values[i].length = strlen(vals[i]);
44 return values;
47 static SmPropValue *make_array_value(const gchar *val)
49 SmPropValue *value = g_new(SmPropValue, 1);
51 value->value = g_strdup(val);
52 value->length = strlen(val);
54 return value;
57 static SmPropValue *make_card_value(gchar val)
59 SmPropValue *value = g_new(SmPropValue, 1);
61 value->value = g_memdup(&val, sizeof(gchar));
62 value->length = 1;
64 return value;
67 static SmProperty *find_property(SmClient *client, const gchar *name)
69 GSList *list = client->props;
70 SmProperty *prop;
72 while(list)
74 prop = (SmProperty *)list->data;
75 if(strcmp(prop->prop.name, name) == 0)
76 return prop;
77 list = g_slist_next(list);
79 return NULL;
82 static SmProperty *new_property(SmClient *client,
83 const gchar *name, const gchar *type)
85 SmProperty *prop;
87 prop = g_new(SmProperty, 1);
88 prop->prop.name = g_strdup(name);
89 prop->prop.type = g_strdup(type);
90 prop->prop.vals = NULL;
91 prop->prop.num_vals = 0;
92 #ifdef DEBUG
93 g_printerr("appending prop %s\n", prop->prop.name);
94 #endif
95 client->props = g_slist_append(client->props, prop);
97 return prop;
100 static gint close_connection(gpointer data)
102 SmClient *client = (SmClient *)data;
104 SmcCloseConnection(client->conn, 0, NULL);
106 return 0;
109 /* Called when there's data to be read on the ICE file descriptor.
110 Unpacks the message and triggers the correct callback... I think */
112 static void poll_ice_messages(gpointer data, gint source,
113 GdkInputCondition condition)
115 SmClient *client = (SmClient *)data;
116 Bool ret;
118 if (IceProcessMessages(client->ice_conn, NULL, &ret) ==
119 IceProcessMessagesIOError)
120 SmcCloseConnection(client->conn, 0, NULL);
121 return;
124 /* Called whenever an ICE connection is opened or closed */
126 static void ice_watch_fn(IceConn conn, IcePointer client_data,
127 Bool opening, IcePointer *watch_data)
129 SmClient *client = (SmClient *)client_data;
131 if(opening)
133 #ifdef DEBUG
134 g_printerr("Ice connection opened for id %s\n", client->id);
135 #endif
136 client->fd = IceConnectionNumber(conn);
137 fcntl(client->fd, F_SETFD, FD_CLOEXEC);
138 client->input_tag = gdk_input_add(client->fd, GDK_INPUT_READ, &poll_ice_messages, client);
140 else
142 if (IceConnectionNumber(conn) == client->fd)
144 #ifdef DEBUG
145 g_printerr("Ice connection closed for id %s\n", client->id);
146 #endif
147 gdk_input_remove(client->input_tag);
148 sc_destroy(client);
153 /* Callbacks for different SM messages */
155 static void sc_save_yourself(SmcConn conn, SmPointer client_data, int save_type,
156 Bool shutdown, int interact_style, Bool fast)
158 SmClient *client = (SmClient *)client_data;
159 gboolean success = TRUE;
160 #ifdef DEBUG
161 g_printerr("%s saving state\n", client->id);
162 #endif
163 if(client->save_yourself_fn)
164 success = client->save_yourself_fn(client);
165 if(success)
166 sc_register_properties(client);
167 SmcSaveYourselfDone(client->conn, success);
170 static void sc_shutdown_cancelled(SmcConn conn, SmPointer client_data)
172 SmClient *client = (SmClient *)client_data;
173 #ifdef DEBUG
174 g_printerr("%s shutdown cancelled\n", client->id);
175 #endif
176 if(client->shutdown_cancelled_fn)
177 client->shutdown_cancelled_fn(client);
180 static void sc_save_complete(SmcConn conn, SmPointer client_data)
182 SmClient *client = (SmClient *)client_data;
183 #ifdef DEBUG
184 g_printerr("%s save complete\n", client->id);
185 #endif
186 if(client->save_complete_fn)
187 client->save_complete_fn(client);
190 static void sc_die(SmcConn conn, SmPointer client_data)
192 SmClient *client = (SmClient *)client_data;
193 #ifdef DEBUG
194 g_printerr("%s dying\n", client->id);
195 #endif
196 if(client->die_fn)
197 client->die_fn(client);
200 gboolean sc_session_up()
202 if(getenv("SESSION_MANAGER") == NULL)
203 return FALSE;
204 return TRUE;
207 SmClient *sc_new(const gchar *client_id)
209 SmClient *client;
211 #ifdef DEBUG
212 g_printerr("Creating new sm-client\n");
213 #endif
214 client = g_new(SmClient, 1);
215 client->id = g_strdup(client_id);
216 client->props = NULL;
217 client->conn = NULL;
218 client->ice_conn = NULL;
219 client->fd = -1;
221 return client;
224 void sc_destroy(SmClient *client)
226 GSList *list = client->props;
227 SmProperty *prop;
229 #ifdef DEBUG
230 g_printerr("destroying client\n");
231 #endif
232 while(list)
234 prop = (SmProperty *)list->data;
235 g_free(prop->prop.vals->value);
236 g_free(prop->prop.vals);
237 g_free(prop->prop.name);
238 g_free(prop->prop.type);
239 g_free(prop);
240 list = g_slist_next(list);
242 g_slist_free(client->props);
243 g_free(client->id);
244 g_free(client);
247 /* Set a property with a SmLISTofARRAY8 value as in SmRestartCommand,
248 SmCloneCommand and SmDiscardCommand */
250 void sc_set_list_of_array_prop(SmClient *client,
251 const gchar *name,
252 const char *vals[], gint nvals)
254 SmProperty *prop = find_property(client, name);
255 SmPropValue *value = make_list_of_array_value(vals, nvals);
257 if(prop == NULL)
258 prop = new_property(client, name, SmLISTofARRAY8);
260 else
261 g_free(prop->prop.vals);
263 prop->prop.vals = value;
264 prop->prop.num_vals = nvals;
265 prop->set = TRUE;
268 /* Set a prop with a SmARRAY8 value, SmProgram, SmUserID and
269 SmDiscardCommand (if using XSM) are suitable victims. */
271 void sc_set_array_prop(SmClient *client, const gchar *name, const gchar *vals)
273 SmProperty *prop = find_property(client, name);
274 SmPropValue *value = make_array_value(vals);
276 if(prop == NULL)
277 prop = new_property(client, name, SmARRAY8);
279 else
280 g_free(prop->prop.vals);
282 prop->prop.vals = value;
283 prop->prop.num_vals = 1;
284 prop->set = TRUE;
287 /* This one is for the SmRestarStyleHint */
289 void sc_set_card_prop(SmClient *client, const gchar *name, const gchar val)
291 SmProperty *prop = find_property(client, name);
292 SmPropValue *value = make_card_value(val);
294 if(prop == NULL)
295 prop = new_property(client, name, SmCARD8);
297 else
298 g_free(prop->prop.vals);
300 prop->prop.vals = value;
301 prop->prop.num_vals = 1;
302 prop->set = TRUE;
305 /* Puts a pointer to a SmPropValue in val_ret and
306 the number of values in nvals_ret (they are in an array ).
307 It looks like this:
308 typedef struct {
309 int length;
310 SmPointer value;
311 } SmPropValue;
312 The values are those stored in the SmClient struct,
313 They're not fetched from the session manager */
315 void sc_get_prop_value(SmClient *client, const gchar *name,
316 SmPropValue **val_ret, gint *nvals_ret)
318 SmProperty *prop = find_property(client, name);
320 if(!prop)
322 *val_ret = NULL;
323 *nvals_ret = 0;
325 else
327 *val_ret = prop->prop.vals;
328 *nvals_ret = prop->prop.num_vals;
332 /* Stores set properties in the session manager */
334 void sc_register_properties(SmClient *client)
336 GPtrArray *set_props= g_ptr_array_new();
337 GSList *list = client->props;
338 SmProperty *prop;
339 #ifdef DEBUG
340 gint i;
341 #endif
343 while(list)
345 prop = (SmProperty *)list->data;
346 if(prop->set == TRUE)
348 g_ptr_array_add(set_props, &prop->prop);
349 prop->set = FALSE;
351 list = g_slist_next(list);
353 #ifdef DEBUG
354 g_printerr("Registering props:\n");
355 for(i = 0; i < set_props->len; i++)
357 prop = g_ptr_array_index(set_props, i);
358 g_printerr("%s\n", prop->prop.name);
360 #endif
361 if(set_props->len > 0)
362 SmcSetProperties(client->conn, set_props->len, (SmProp **)set_props->pdata);
364 g_ptr_array_free(set_props, TRUE);
367 /* Connects to the session manager */
369 gboolean sc_connect(SmClient *client)
371 gchar error_str[256];
372 gchar *client_id_ret = NULL;
373 SmcConn conn = NULL;
374 SmcCallbacks callbacks;
376 callbacks.save_yourself.callback = &sc_save_yourself;
377 callbacks.save_yourself.client_data = (SmPointer)client;
378 callbacks.die.callback = &sc_die;
379 callbacks.die.client_data = (SmPointer)client;
380 callbacks.save_complete.callback = &sc_save_complete;
381 callbacks.save_complete.client_data = (SmPointer)client;
382 callbacks.shutdown_cancelled.callback = &sc_shutdown_cancelled;
383 callbacks.shutdown_cancelled.client_data = (SmPointer)client;
385 if(IceAddConnectionWatch(&ice_watch_fn, client) == 0)
387 g_printerr("Session Manager: IceAddConnectionWatch failed\n");
388 return FALSE;
391 if((conn = SmcOpenConnection(NULL, /* network ids */
392 NULL, /* context */
393 1, 0, /* protocol major, minor */
394 SmcSaveYourselfProcMask |
395 SmcSaveCompleteProcMask |
396 SmcShutdownCancelledProcMask |
397 SmcDieProcMask,
398 &callbacks,
399 client->id, &client_id_ret,
400 sizeof(error_str), error_str)) == NULL)
402 g_printerr("Session Manager: Init error\n");
403 return FALSE;
406 client->id = g_strdup(client_id_ret);
407 client->conn = conn;
408 client->ice_conn = SmcGetIceConnection(conn);
409 gdk_set_sm_client_id(client->id);
410 XFree(client_id_ret);
412 gtk_quit_add(0, &close_connection, client);
414 return TRUE;