1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2007 Novell, Inc.
4  * Copyright (C) 2008 Red Hat, Inc.
5  * Copyright (C) 2012-2021 MATE Developers
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20  * 02110-1301, USA.
21  */
22 
23 #include "config.h"
24 
25 #include <fcntl.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29 #include <unistd.h>
30 #include <errno.h>
31 
32 #include <gio/gio.h>
33 #include <glib/gi18n.h>
34 
35 #include "gsm-xsmp-client.h"
36 #include "gsm-marshal.h"
37 
38 #include "gsm-util.h"
39 #include "gsm-autostart-app.h"
40 #include "gsm-manager.h"
41 
42 #define GsmDesktopFile "_GSM_DesktopFile"
43 
44 typedef struct {
45         GsmClient  parent;
46         SmsConn    conn;
47         IceConn    ice_connection;
48 
49         guint      watch_id;
50 
51         char      *description;
52         GPtrArray *props;
53 
54         /* SaveYourself state */
55         int        current_save_yourself;
56         int        next_save_yourself;
57         guint      next_save_yourself_allow_interact : 1;
58 } GsmXSMPClientPrivate;
59 
60 enum {
61         PROP_0,
62         PROP_ICE_CONNECTION
63 };
64 
65 enum {
66         REGISTER_REQUEST,
67         LOGOUT_REQUEST,
68         LAST_SIGNAL
69 };
70 
71 static guint signals[LAST_SIGNAL] = { 0 };
72 
G_DEFINE_TYPE_WITH_PRIVATE(GsmXSMPClient,gsm_xsmp_client,GSM_TYPE_CLIENT)73 G_DEFINE_TYPE_WITH_PRIVATE (GsmXSMPClient, gsm_xsmp_client, GSM_TYPE_CLIENT)
74 
75 static gboolean
76 client_iochannel_watch (GIOChannel    *channel,
77                         GIOCondition   condition,
78                         GsmXSMPClient *client)
79 {
80         gboolean keep_going;
81         GsmXSMPClientPrivate *priv;
82 
83         g_object_ref (client);
84         priv = gsm_xsmp_client_get_instance_private (client);
85 
86         switch (IceProcessMessages (priv->ice_connection, NULL, NULL)) {
87         case IceProcessMessagesSuccess:
88                 keep_going = TRUE;
89                 break;
90 
91         case IceProcessMessagesIOError:
92                 g_debug ("GsmXSMPClient: IceProcessMessagesIOError on '%s'", priv->description);
93                 gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_FAILED);
94                 /* Emitting "disconnected" will eventually cause
95                  * IceCloseConnection() to be called.
96                  */
97                 gsm_client_disconnected (GSM_CLIENT (client));
98                 keep_going = FALSE;
99                 break;
100 
101         case IceProcessMessagesConnectionClosed:
102                 g_debug ("GsmXSMPClient: IceProcessMessagesConnectionClosed on '%s'",
103                          priv->description);
104                 priv->ice_connection = NULL;
105                 keep_going = FALSE;
106                 break;
107 
108         default:
109                 g_assert_not_reached ();
110         }
111         g_object_unref (client);
112 
113         return keep_going;
114 }
115 
116 static SmProp *
find_property(GsmXSMPClient * client,const char * name,int * index)117 find_property (GsmXSMPClient *client,
118                const char    *name,
119                int           *index)
120 {
121         SmProp *prop;
122         int i;
123         GsmXSMPClientPrivate *priv;
124 
125         priv = gsm_xsmp_client_get_instance_private (client);
126 
127         for (i = 0; i < priv->props->len; i++) {
128                 prop = priv->props->pdata[i];
129 
130                 if (!strcmp (prop->name, name)) {
131                         if (index) {
132                                 *index = i;
133                         }
134                         return prop;
135                 }
136         }
137 
138         return NULL;
139 }
140 
141 static void
set_description(GsmXSMPClient * client)142 set_description (GsmXSMPClient *client)
143 {
144         SmProp     *prop;
145         const char *id;
146         GsmXSMPClientPrivate *priv;
147 
148         priv = gsm_xsmp_client_get_instance_private (client);
149         prop = find_property (client, SmProgram, NULL);
150         id = gsm_client_peek_startup_id (GSM_CLIENT (client));
151 
152         g_free (priv->description);
153         if (prop) {
154                 priv->description = g_strdup_printf ("%p [%.*s %s]",
155                                                      client,
156                                                      prop->vals[0].length,
157                                                      (char *)prop->vals[0].value,
158                                                      id);
159         } else if (id != NULL) {
160                 priv->description = g_strdup_printf ("%p [%s]", client, id);
161         } else {
162                 priv->description = g_strdup_printf ("%p", client);
163         }
164 }
165 
166 static void
setup_connection(GsmXSMPClient * client)167 setup_connection (GsmXSMPClient *client)
168 {
169         GIOChannel    *channel;
170         int            fd;
171         GsmXSMPClientPrivate *priv;
172 
173         priv = gsm_xsmp_client_get_instance_private (client);
174         g_debug ("GsmXSMPClient: Setting up new connection");
175 
176         fd = IceConnectionNumber (priv->ice_connection);
177         fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC);
178         channel = g_io_channel_unix_new (fd);
179         priv->watch_id = g_io_add_watch (channel,
180                                          G_IO_IN | G_IO_ERR,
181                                          (GIOFunc)client_iochannel_watch,
182                                          client);
183         g_io_channel_unref (channel);
184 
185         set_description (client);
186 
187         g_debug ("GsmXSMPClient: New client '%s'", priv->description);
188 }
189 
190 static GObject *
gsm_xsmp_client_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)191 gsm_xsmp_client_constructor (GType                  type,
192                              guint                  n_construct_properties,
193                              GObjectConstructParam *construct_properties)
194 {
195         GsmXSMPClient *client;
196 
197         client = GSM_XSMP_CLIENT (G_OBJECT_CLASS (gsm_xsmp_client_parent_class)->constructor (type,
198                                                                                               n_construct_properties,
199                                                                                               construct_properties));
200         setup_connection (client);
201 
202         return G_OBJECT (client);
203 }
204 
205 static void
gsm_xsmp_client_init(GsmXSMPClient * client)206 gsm_xsmp_client_init (GsmXSMPClient *client)
207 {
208         GsmXSMPClientPrivate *priv;
209 
210         priv = gsm_xsmp_client_get_instance_private (client);
211 
212         priv->props = g_ptr_array_new ();
213         priv->current_save_yourself = -1;
214         priv->next_save_yourself = -1;
215         priv->next_save_yourself_allow_interact = FALSE;
216 }
217 
218 
219 static void
delete_property(GsmXSMPClient * client,const char * name)220 delete_property (GsmXSMPClient *client,
221                  const char    *name)
222 {
223         int     index;
224         SmProp *prop;
225         GsmXSMPClientPrivate *priv;
226 
227         priv = gsm_xsmp_client_get_instance_private (client);
228 
229         prop = find_property (client, name, &index);
230         if (!prop) {
231                 return;
232         }
233 
234 #if 0
235         /* This is wrong anyway; we can't unconditionally run the current
236          * discard command; if this client corresponds to a GsmAppResumed,
237          * and the current discard command is identical to the app's
238          * discard_command, then we don't run the discard command now,
239          * because that would delete a saved state we may want to resume
240          * again later.
241          */
242         if (!strcmp (name, SmDiscardCommand)) {
243                 gsm_client_run_discard (GSM_CLIENT (client));
244         }
245 #endif
246 
247         g_ptr_array_remove_index_fast (priv->props, index);
248         SmFreeProperty (prop);
249 }
250 
251 
252 static void
debug_print_property(SmProp * prop)253 debug_print_property (SmProp *prop)
254 {
255         GString *tmp;
256         int      i;
257 
258         switch (prop->type[0]) {
259         case 'C': /* CARD8 */
260                 g_debug ("GsmXSMPClient:   %s = %d", prop->name, *(unsigned char *)prop->vals[0].value);
261                 break;
262 
263         case 'A': /* ARRAY8 */
264                 g_debug ("GsmXSMPClient:   %s = '%s'", prop->name, (char *)prop->vals[0].value);
265                 break;
266 
267         case 'L': /* LISTofARRAY8 */
268                 tmp = g_string_new (NULL);
269                 for (i = 0; i < prop->num_vals; i++) {
270                         g_string_append_printf (tmp, "'%.*s' ", prop->vals[i].length,
271                                                 (char *)prop->vals[i].value);
272                 }
273                 g_debug ("GsmXSMPClient:   %s = %s", prop->name, tmp->str);
274                 g_string_free (tmp, TRUE);
275                 break;
276 
277         default:
278                 g_debug ("GsmXSMPClient:   %s = ??? (%s)", prop->name, prop->type);
279                 break;
280         }
281 }
282 
283 
284 static void
set_properties_callback(SmsConn conn,SmPointer manager_data,int num_props,SmProp ** props)285 set_properties_callback (SmsConn     conn,
286                          SmPointer   manager_data,
287                          int         num_props,
288                          SmProp    **props)
289 {
290         int            i;
291         GsmXSMPClientPrivate *priv;
292         GsmXSMPClient *client = manager_data;
293 
294         priv = gsm_xsmp_client_get_instance_private (client);
295 
296         g_debug ("GsmXSMPClient: Set properties from client '%s'", priv->description);
297 
298         for (i = 0; i < num_props; i++) {
299                 delete_property (client, props[i]->name);
300                 g_ptr_array_add (priv->props, props[i]);
301 
302                 debug_print_property (props[i]);
303 
304                 if (!strcmp (props[i]->name, SmProgram))
305                         set_description (client);
306         }
307 
308         free (props);
309 
310 }
311 
312 static void
delete_properties_callback(SmsConn conn,SmPointer manager_data,int num_props,char ** prop_names)313 delete_properties_callback (SmsConn     conn,
314                             SmPointer   manager_data,
315                             int         num_props,
316                             char      **prop_names)
317 {
318         int i;
319         GsmXSMPClientPrivate *priv;
320         GsmXSMPClient *client = manager_data;
321 
322         priv = gsm_xsmp_client_get_instance_private (client);
323 
324         g_debug ("GsmXSMPClient: Delete properties from '%s'", priv->description);
325 
326         for (i = 0; i < num_props; i++) {
327                 delete_property (client, prop_names[i]);
328 
329                 g_debug ("  %s", prop_names[i]);
330         }
331 
332         free (prop_names);
333 }
334 
335 static void
get_properties_callback(SmsConn conn,SmPointer manager_data)336 get_properties_callback (SmsConn   conn,
337                          SmPointer manager_data)
338 {
339         GsmXSMPClientPrivate *priv;
340         GsmXSMPClient *client = manager_data;
341 
342         priv = gsm_xsmp_client_get_instance_private (client);
343 
344         g_debug ("GsmXSMPClient: Get properties request from '%s'", priv->description);
345 
346         SmsReturnProperties (conn,
347                              priv->props->len,
348                              (SmProp **)priv->props->pdata);
349 }
350 
351 static char *
prop_to_command(SmProp * prop)352 prop_to_command (SmProp *prop)
353 {
354         GString *str;
355         int i, j;
356         gboolean need_quotes;
357 
358         str = g_string_new (NULL);
359         for (i = 0; i < prop->num_vals; i++) {
360                 char *val = prop->vals[i].value;
361 
362                 need_quotes = FALSE;
363                 for (j = 0; j < prop->vals[i].length; j++) {
364                         if (!g_ascii_isalnum (val[j]) && !strchr ("-_=:./", val[j])) {
365                                 need_quotes = TRUE;
366                                 break;
367                         }
368                 }
369 
370                 if (i > 0) {
371                         g_string_append_c (str, ' ');
372                 }
373 
374                 if (!need_quotes) {
375                         g_string_append_printf (str,
376                                                 "%.*s",
377                                                 prop->vals[i].length,
378                                                 (char *)prop->vals[i].value);
379                 } else {
380                         g_string_append_c (str, '\'');
381                         while (val < (char *)prop->vals[i].value + prop->vals[i].length) {
382                                 if (*val == '\'') {
383                                         g_string_append (str, "'\''");
384                                 } else {
385                                         g_string_append_c (str, *val);
386                                 }
387                                 val++;
388                         }
389                         g_string_append_c (str, '\'');
390                 }
391         }
392 
393         return g_string_free (str, FALSE);
394 }
395 
396 static char *
xsmp_get_restart_command(GsmClient * client)397 xsmp_get_restart_command (GsmClient *client)
398 {
399         SmProp *prop;
400 
401         prop = find_property (GSM_XSMP_CLIENT (client), SmRestartCommand, NULL);
402 
403         if (!prop || strcmp (prop->type, SmLISTofARRAY8) != 0) {
404                 return NULL;
405         }
406 
407         return prop_to_command (prop);
408 }
409 
410 static char *
xsmp_get_discard_command(GsmClient * client)411 xsmp_get_discard_command (GsmClient *client)
412 {
413         SmProp *prop;
414 
415         prop = find_property (GSM_XSMP_CLIENT (client), SmDiscardCommand, NULL);
416 
417         if (!prop || strcmp (prop->type, SmLISTofARRAY8) != 0) {
418                 return NULL;
419         }
420 
421         return prop_to_command (prop);
422 }
423 
424 static void
do_save_yourself(GsmXSMPClient * client,int save_type,gboolean allow_interact)425 do_save_yourself (GsmXSMPClient *client,
426                   int            save_type,
427                   gboolean       allow_interact)
428 {
429         GsmXSMPClientPrivate *priv;
430 
431         priv = gsm_xsmp_client_get_instance_private (client);
432         g_assert (priv->conn != NULL);
433 
434         if (priv->next_save_yourself != -1) {
435                 /* Either we're currently doing a shutdown and there's a checkpoint
436                  * queued after it, or vice versa. Either way, the new SaveYourself
437                  * is redundant.
438                  */
439                 g_debug ("GsmXSMPClient:   skipping redundant SaveYourself for '%s'",
440                          priv->description);
441         } else if (priv->current_save_yourself != -1) {
442                 g_debug ("GsmXSMPClient:   queuing new SaveYourself for '%s'",
443                          priv->description);
444                 priv->next_save_yourself = save_type;
445                 priv->next_save_yourself_allow_interact = allow_interact;
446         } else {
447                 priv->current_save_yourself = save_type;
448                 /* make sure we don't have anything queued */
449                 priv->next_save_yourself = -1;
450                 priv->next_save_yourself_allow_interact = FALSE;
451 
452                 switch (save_type) {
453                 case SmSaveLocal:
454                         /* Save state */
455                         SmsSaveYourself (priv->conn,
456                                          SmSaveLocal,
457                                          FALSE,
458                                          SmInteractStyleNone,
459                                          FALSE);
460                         break;
461 
462                 default:
463                         /* Logout */
464                         if (!allow_interact) {
465                                 SmsSaveYourself (priv->conn,
466                                                  save_type, /* save type */
467                                                  TRUE, /* shutdown */
468                                                  SmInteractStyleNone, /* interact style */
469                                                  TRUE); /* fast */
470                         } else {
471                                 SmsSaveYourself (priv->conn,
472                                                  save_type, /* save type */
473                                                  TRUE, /* shutdown */
474                                                  SmInteractStyleAny, /* interact style */
475                                                  FALSE /* fast */);
476                         }
477                         break;
478                 }
479         }
480 }
481 
482 static void
xsmp_save_yourself_phase2(GsmClient * client)483 xsmp_save_yourself_phase2 (GsmClient *client)
484 {
485         GsmXSMPClientPrivate *priv;
486 
487         priv = gsm_xsmp_client_get_instance_private (GSM_XSMP_CLIENT(client));
488 
489         g_debug ("GsmXSMPClient: xsmp_save_yourself_phase2 ('%s')", priv->description);
490 
491         SmsSaveYourselfPhase2 (priv->conn);
492 }
493 
494 static void
xsmp_interact(GsmClient * client)495 xsmp_interact (GsmClient *client)
496 {
497         GsmXSMPClientPrivate *priv;
498 
499         priv = gsm_xsmp_client_get_instance_private (GSM_XSMP_CLIENT(client));
500 
501         g_debug ("GsmXSMPClient: xsmp_interact ('%s')", priv->description);
502 
503         SmsInteract (priv->conn);
504 }
505 
506 static gboolean
xsmp_cancel_end_session(GsmClient * client,GError ** error)507 xsmp_cancel_end_session (GsmClient *client,
508                          GError   **error)
509 {
510         GsmXSMPClientPrivate *priv;
511 
512         priv = gsm_xsmp_client_get_instance_private (GSM_XSMP_CLIENT(client));
513 
514         g_debug ("GsmXSMPClient: xsmp_cancel_end_session ('%s')", priv->description);
515 
516         if (priv->conn == NULL) {
517                 g_set_error (error,
518                              GSM_CLIENT_ERROR,
519                              GSM_CLIENT_ERROR_NOT_REGISTERED,
520                              "Client is not registered");
521                 return FALSE;
522         }
523 
524         SmsShutdownCancelled (priv->conn);
525 
526         /* reset the state */
527         priv->current_save_yourself = -1;
528         priv->next_save_yourself = -1;
529         priv->next_save_yourself_allow_interact = FALSE;
530 
531         return TRUE;
532 }
533 
534 static char *
get_desktop_file_path(GsmXSMPClient * client)535 get_desktop_file_path (GsmXSMPClient *client)
536 {
537         SmProp     *prop;
538         char       *desktop_file_path = NULL;
539         char      **dirs;
540         const char *program_name;
541 
542         /* XSMP clients using eggsmclient defines a special property
543          * pointing to their respective desktop entry file */
544         prop = find_property (client, GsmDesktopFile, NULL);
545 
546         if (prop) {
547                 GFile *file = g_file_new_for_uri (prop->vals[0].value);
548                 desktop_file_path = g_file_get_path (file);
549                 g_object_unref (file);
550                 goto out;
551         }
552 
553         /* If we can't get desktop file from GsmDesktopFile then we
554          * try to find the desktop file from its program name */
555         prop = find_property (client, SmProgram, NULL);
556 
557         if (!prop) {
558                 goto out;
559         }
560 
561         program_name = prop->vals[0].value;
562 
563         dirs = gsm_util_get_autostart_dirs ();
564 
565         desktop_file_path =
566                 gsm_util_find_desktop_file_for_app_name (program_name,
567                                                          dirs);
568 
569         g_strfreev (dirs);
570 
571 out:
572         g_debug ("GsmXSMPClient: desktop file for client %s is %s",
573                  gsm_client_peek_id (GSM_CLIENT (client)),
574                  desktop_file_path ? desktop_file_path : "(null)");
575 
576         return desktop_file_path;
577 }
578 
579 static void
set_desktop_file_keys_from_client(GsmClient * client,GKeyFile * keyfile)580 set_desktop_file_keys_from_client (GsmClient *client,
581                                    GKeyFile  *keyfile)
582 {
583         SmProp       *prop;
584         const char   *name;
585         char         *comment;
586 
587         prop = find_property (GSM_XSMP_CLIENT (client), SmProgram, NULL);
588 
589         if (prop) {
590                 name = prop->vals[0].value;
591         } else {
592             /* It'd be really surprising to reach this code: if we're here,
593              * then the XSMP client already has set several XSMP
594              * properties. But it could still be that SmProgram is not set.
595              */
596             name = _("Remembered Application");
597         }
598 
599         comment = g_strdup_printf ("Client %s which was automatically saved",
600                                    gsm_client_peek_startup_id (client));
601 
602         g_key_file_set_string (keyfile,
603                                G_KEY_FILE_DESKTOP_GROUP,
604                                G_KEY_FILE_DESKTOP_KEY_NAME,
605                                name);
606 
607         g_key_file_set_string (keyfile,
608                                G_KEY_FILE_DESKTOP_GROUP,
609                                G_KEY_FILE_DESKTOP_KEY_COMMENT,
610                                comment);
611 
612         g_key_file_set_string (keyfile,
613                                G_KEY_FILE_DESKTOP_GROUP,
614                                G_KEY_FILE_DESKTOP_KEY_ICON,
615                                "system-run");
616 
617         g_key_file_set_string (keyfile,
618                                G_KEY_FILE_DESKTOP_GROUP,
619                                G_KEY_FILE_DESKTOP_KEY_TYPE,
620                                "Application");
621 
622         g_key_file_set_boolean (keyfile,
623                                 G_KEY_FILE_DESKTOP_GROUP,
624                                 G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY,
625                                 TRUE);
626 
627         g_free (comment);
628 }
629 
630 static GKeyFile *
create_client_key_file(GsmClient * client,const char * desktop_file_path,GError ** error)631 create_client_key_file (GsmClient   *client,
632                         const char  *desktop_file_path,
633                         GError     **error) {
634         GKeyFile *keyfile;
635 
636         keyfile = g_key_file_new ();
637 
638         if (desktop_file_path != NULL) {
639                 g_key_file_load_from_file (keyfile,
640                                            desktop_file_path,
641                                            G_KEY_FILE_KEEP_COMMENTS |
642                                            G_KEY_FILE_KEEP_TRANSLATIONS,
643                                            error);
644         } else {
645                 set_desktop_file_keys_from_client (client, keyfile);
646         }
647 
648         return keyfile;
649 }
650 
651 static GsmClientRestartStyle
652 xsmp_get_restart_style_hint (GsmClient *client);
653 
654 static GKeyFile *
xsmp_save(GsmClient * client,GError ** error)655 xsmp_save (GsmClient *client,
656            GError   **error)
657 {
658         GsmClientRestartStyle restart_style;
659 
660         GKeyFile *keyfile = NULL;
661         char     *desktop_file_path = NULL;
662         char     *exec_program = NULL;
663         char     *exec_discard = NULL;
664         char     *startup_id = NULL;
665         GError   *local_error;
666 
667         g_debug ("GsmXSMPClient: saving client with id %s",
668                  gsm_client_peek_id (client));
669 
670         local_error = NULL;
671 
672         restart_style = xsmp_get_restart_style_hint (client);
673         if (restart_style == GSM_CLIENT_RESTART_NEVER) {
674                 goto out;
675         }
676 
677         exec_program = xsmp_get_restart_command (client);
678         if (!exec_program) {
679                 goto out;
680         }
681 
682         desktop_file_path = get_desktop_file_path (GSM_XSMP_CLIENT (client));
683 
684         /* this can accept desktop_file_path == NULL */
685         keyfile = create_client_key_file (client,
686                                           desktop_file_path,
687                                           &local_error);
688 
689         if (local_error) {
690                 goto out;
691         }
692 
693         g_object_get (client,
694                       "startup-id", &startup_id,
695                       NULL);
696 
697         g_key_file_set_string (keyfile,
698                                G_KEY_FILE_DESKTOP_GROUP,
699                                GSM_AUTOSTART_APP_STARTUP_ID_KEY,
700                                startup_id);
701 
702         g_key_file_set_string (keyfile,
703                                G_KEY_FILE_DESKTOP_GROUP,
704                                G_KEY_FILE_DESKTOP_KEY_EXEC,
705                                exec_program);
706 
707         exec_discard = xsmp_get_discard_command (client);
708         if (exec_discard)
709                 g_key_file_set_string (keyfile,
710                                        G_KEY_FILE_DESKTOP_GROUP,
711                                        GSM_AUTOSTART_APP_DISCARD_KEY,
712                                        exec_discard);
713 
714 out:
715         g_free (desktop_file_path);
716         g_free (exec_program);
717         g_free (exec_discard);
718         g_free (startup_id);
719 
720         if (local_error != NULL) {
721                 g_propagate_error (error, local_error);
722                 g_key_file_free (keyfile);
723 
724                 return NULL;
725         }
726 
727         return keyfile;
728 }
729 
730 static gboolean
xsmp_stop(GsmClient * client,GError ** error)731 xsmp_stop (GsmClient *client,
732            GError   **error)
733 {
734         GsmXSMPClientPrivate *priv;
735 
736         priv = gsm_xsmp_client_get_instance_private (GSM_XSMP_CLIENT(client));
737 
738         g_debug ("GsmXSMPClient: xsmp_stop ('%s')", priv->description);
739 
740         if (priv->conn == NULL) {
741                 g_set_error (error,
742                              GSM_CLIENT_ERROR,
743                              GSM_CLIENT_ERROR_NOT_REGISTERED,
744                              "Client is not registered");
745                 return FALSE;
746         }
747 
748         SmsDie (priv->conn);
749 
750         return TRUE;
751 }
752 
753 static gboolean
xsmp_query_end_session(GsmClient * client,guint flags,GError ** error)754 xsmp_query_end_session (GsmClient *client,
755                         guint      flags,
756                         GError   **error)
757 {
758         gboolean allow_interact;
759         int      save_type;
760         GsmXSMPClientPrivate *priv;
761 
762         priv = gsm_xsmp_client_get_instance_private (GSM_XSMP_CLIENT(client));
763 
764         if (priv->conn == NULL) {
765                 g_set_error (error,
766                              GSM_CLIENT_ERROR,
767                              GSM_CLIENT_ERROR_NOT_REGISTERED,
768                              "Client is not registered");
769                 return FALSE;
770         }
771 
772         allow_interact = !(flags & GSM_CLIENT_END_SESSION_FLAG_FORCEFUL);
773 
774         /* we don't want to save the session state, but we just want to know if
775          * there's user data the client has to save and we want to give the
776          * client a chance to tell the user about it. This is consistent with
777          * the manager not setting GSM_CLIENT_END_SESSION_FLAG_SAVE for this
778          * phase. */
779         save_type = SmSaveGlobal;
780 
781         do_save_yourself (GSM_XSMP_CLIENT (client), save_type, allow_interact);
782         return TRUE;
783 }
784 
785 static gboolean
xsmp_end_session(GsmClient * client,guint flags,GError ** error)786 xsmp_end_session (GsmClient *client,
787                   guint      flags,
788                   GError   **error)
789 {
790         gboolean phase2;
791         GsmXSMPClientPrivate *priv;
792 
793         priv = gsm_xsmp_client_get_instance_private (GSM_XSMP_CLIENT(client));
794 
795         if (priv->conn == NULL) {
796                 g_set_error (error,
797                              GSM_CLIENT_ERROR,
798                              GSM_CLIENT_ERROR_NOT_REGISTERED,
799                              "Client is not registered");
800                 return FALSE;
801         }
802 
803         phase2 = (flags & GSM_CLIENT_END_SESSION_FLAG_LAST);
804 
805         if (phase2) {
806                 xsmp_save_yourself_phase2 (client);
807         } else {
808                 gboolean allow_interact;
809                 int      save_type;
810 
811                 /* we gave a chance to interact to the app during
812                  * xsmp_query_end_session(), now it's too late to interact */
813                 allow_interact = FALSE;
814 
815                 if (flags & GSM_CLIENT_END_SESSION_FLAG_SAVE) {
816                         save_type = SmSaveBoth;
817                 } else {
818                         save_type = SmSaveGlobal;
819                 }
820 
821                 do_save_yourself (GSM_XSMP_CLIENT (client),
822                                   save_type, allow_interact);
823         }
824 
825         return TRUE;
826 }
827 
828 static char *
xsmp_get_app_name(GsmClient * client)829 xsmp_get_app_name (GsmClient *client)
830 {
831         SmProp *prop;
832         char   *name = NULL;
833 
834         prop = find_property (GSM_XSMP_CLIENT (client), SmProgram, NULL);
835         if (prop) {
836                 name = prop_to_command (prop);
837         }
838 
839         return name;
840 }
841 
842 static void
gsm_client_set_ice_connection(GsmXSMPClient * client,gpointer conn)843 gsm_client_set_ice_connection (GsmXSMPClient *client,
844                                gpointer       conn)
845 {
846         GsmXSMPClientPrivate *priv;
847 
848         priv = gsm_xsmp_client_get_instance_private (client);
849         priv->ice_connection = conn;
850 }
851 
852 static void
gsm_xsmp_client_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)853 gsm_xsmp_client_set_property (GObject       *object,
854                               guint          prop_id,
855                               const GValue  *value,
856                               GParamSpec    *pspec)
857 {
858         GsmXSMPClient *self;
859 
860         self = GSM_XSMP_CLIENT (object);
861 
862         switch (prop_id) {
863         case PROP_ICE_CONNECTION:
864                 gsm_client_set_ice_connection (self, g_value_get_pointer (value));
865                 break;
866         default:
867                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
868                 break;
869         }
870 }
871 
872 static void
gsm_xsmp_client_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)873 gsm_xsmp_client_get_property (GObject    *object,
874                               guint       prop_id,
875                               GValue     *value,
876                               GParamSpec *pspec)
877 {
878         GsmXSMPClientPrivate *priv;
879 
880         priv = gsm_xsmp_client_get_instance_private (GSM_XSMP_CLIENT(object));
881 
882         switch (prop_id) {
883         case PROP_ICE_CONNECTION:
884                 g_value_set_pointer (value, priv->ice_connection);
885                 break;
886         default:
887                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
888                 break;
889         }
890 }
891 
892 static void
gsm_xsmp_client_disconnect(GsmXSMPClient * client)893 gsm_xsmp_client_disconnect (GsmXSMPClient *client)
894 {
895         GsmXSMPClientPrivate *priv;
896 
897         priv = gsm_xsmp_client_get_instance_private (client);
898         if (priv->watch_id > 0) {
899                 g_source_remove (priv->watch_id);
900         }
901 
902         if (priv->conn != NULL) {
903                 SmsCleanUp (priv->conn);
904         }
905 
906         if (priv->ice_connection != NULL) {
907                 IceSetShutdownNegotiation (priv->ice_connection, FALSE);
908                 IceCloseConnection (priv->ice_connection);
909         }
910 }
911 
912 static void
gsm_xsmp_client_finalize(GObject * object)913 gsm_xsmp_client_finalize (GObject *object)
914 {
915         GsmXSMPClientPrivate *priv;
916         GsmXSMPClient *client;
917 
918         client = GSM_XSMP_CLIENT(object);
919 
920         priv = gsm_xsmp_client_get_instance_private (client);
921 
922         g_debug ("GsmXSMPClient: xsmp_finalize (%s)", priv->description);
923         gsm_xsmp_client_disconnect (client);
924 
925         g_free (priv->description);
926         g_ptr_array_foreach (priv->props, (GFunc)SmFreeProperty, NULL);
927         g_ptr_array_free (priv->props, TRUE);
928 
929         G_OBJECT_CLASS (gsm_xsmp_client_parent_class)->finalize (object);
930 }
931 
932 static gboolean
_boolean_handled_accumulator(GSignalInvocationHint * ihint,GValue * return_accu,const GValue * handler_return,gpointer dummy)933 _boolean_handled_accumulator (GSignalInvocationHint *ihint,
934                               GValue                *return_accu,
935                               const GValue          *handler_return,
936                               gpointer               dummy)
937 {
938         gboolean    continue_emission;
939         gboolean    signal_handled;
940 
941         signal_handled = g_value_get_boolean (handler_return);
942         g_value_set_boolean (return_accu, signal_handled);
943         continue_emission = !signal_handled;
944 
945         return continue_emission;
946 }
947 
948 static GsmClientRestartStyle
xsmp_get_restart_style_hint(GsmClient * client)949 xsmp_get_restart_style_hint (GsmClient *client)
950 {
951         SmProp               *prop;
952         GsmClientRestartStyle hint;
953 
954         g_debug ("GsmXSMPClient: getting restart style");
955         hint = GSM_CLIENT_RESTART_IF_RUNNING;
956 
957         prop = find_property (GSM_XSMP_CLIENT (client), SmRestartStyleHint, NULL);
958 
959         if (!prop || strcmp (prop->type, SmCARD8) != 0) {
960                 return GSM_CLIENT_RESTART_IF_RUNNING;
961         }
962 
963         switch (((unsigned char *)prop->vals[0].value)[0]) {
964         case SmRestartIfRunning:
965                 hint = GSM_CLIENT_RESTART_IF_RUNNING;
966                 break;
967         case SmRestartAnyway:
968                 hint = GSM_CLIENT_RESTART_ANYWAY;
969                 break;
970         case SmRestartImmediately:
971                 hint = GSM_CLIENT_RESTART_IMMEDIATELY;
972                 break;
973         case SmRestartNever:
974                 hint = GSM_CLIENT_RESTART_NEVER;
975                 break;
976         default:
977                 break;
978         }
979 
980         return hint;
981 }
982 
983 static gboolean
_parse_value_as_uint(const char * value,guint * uintval)984 _parse_value_as_uint (const char *value,
985                       guint      *uintval)
986 {
987         char  *end_of_valid_uint;
988         gulong ulong_value;
989         guint  uint_value;
990 
991         errno = 0;
992         ulong_value = strtoul (value, &end_of_valid_uint, 10);
993 
994         if (*value == '\0' || *end_of_valid_uint != '\0') {
995                 return FALSE;
996         }
997 
998         uint_value = ulong_value;
999         if (uint_value != ulong_value || errno == ERANGE) {
1000                 return FALSE;
1001         }
1002 
1003         *uintval = uint_value;
1004 
1005         return TRUE;
1006 }
1007 
1008 static guint
xsmp_get_unix_process_id(GsmClient * client)1009 xsmp_get_unix_process_id (GsmClient *client)
1010 {
1011         SmProp  *prop;
1012         guint    pid;
1013         gboolean res;
1014 
1015         g_debug ("GsmXSMPClient: getting pid");
1016 
1017         prop = find_property (GSM_XSMP_CLIENT (client), SmProcessID, NULL);
1018 
1019         if (!prop || strcmp (prop->type, SmARRAY8) != 0) {
1020                 return 0;
1021         }
1022 
1023         pid = 0;
1024         res = _parse_value_as_uint ((char *)prop->vals[0].value, &pid);
1025         if (! res) {
1026                 pid = 0;
1027         }
1028 
1029         return pid;
1030 }
1031 
1032 static void
gsm_xsmp_client_class_init(GsmXSMPClientClass * klass)1033 gsm_xsmp_client_class_init (GsmXSMPClientClass *klass)
1034 {
1035         GObjectClass   *object_class = G_OBJECT_CLASS (klass);
1036         GsmClientClass *client_class = GSM_CLIENT_CLASS (klass);
1037 
1038         object_class->finalize             = gsm_xsmp_client_finalize;
1039         object_class->constructor          = gsm_xsmp_client_constructor;
1040         object_class->get_property         = gsm_xsmp_client_get_property;
1041         object_class->set_property         = gsm_xsmp_client_set_property;
1042 
1043         client_class->impl_save                   = xsmp_save;
1044         client_class->impl_stop                   = xsmp_stop;
1045         client_class->impl_query_end_session      = xsmp_query_end_session;
1046         client_class->impl_end_session            = xsmp_end_session;
1047         client_class->impl_cancel_end_session     = xsmp_cancel_end_session;
1048         client_class->impl_get_app_name           = xsmp_get_app_name;
1049         client_class->impl_get_restart_style_hint = xsmp_get_restart_style_hint;
1050         client_class->impl_get_unix_process_id    = xsmp_get_unix_process_id;
1051 
1052         signals[REGISTER_REQUEST] =
1053                 g_signal_new ("register-request",
1054                               G_OBJECT_CLASS_TYPE (object_class),
1055                               G_SIGNAL_RUN_LAST,
1056                               G_STRUCT_OFFSET (GsmXSMPClientClass, register_request),
1057                               _boolean_handled_accumulator,
1058                               NULL,
1059                               gsm_marshal_BOOLEAN__POINTER,
1060                               G_TYPE_BOOLEAN,
1061                               1, G_TYPE_POINTER);
1062         signals[LOGOUT_REQUEST] =
1063                 g_signal_new ("logout-request",
1064                               G_OBJECT_CLASS_TYPE (object_class),
1065                               G_SIGNAL_RUN_LAST,
1066                               G_STRUCT_OFFSET (GsmXSMPClientClass, logout_request),
1067                               NULL,
1068                               NULL,
1069                               g_cclosure_marshal_VOID__BOOLEAN,
1070                               G_TYPE_NONE,
1071                               1, G_TYPE_BOOLEAN);
1072 
1073         g_object_class_install_property (object_class,
1074                                          PROP_ICE_CONNECTION,
1075                                          g_param_spec_pointer ("ice-connection",
1076                                                                "ice-connection",
1077                                                                "ice-connection",
1078                                                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1079 }
1080 
1081 GsmClient *
gsm_xsmp_client_new(IceConn ice_conn)1082 gsm_xsmp_client_new (IceConn ice_conn)
1083 {
1084         GsmXSMPClient *xsmp;
1085 
1086         xsmp = g_object_new (GSM_TYPE_XSMP_CLIENT,
1087                              "ice-connection", ice_conn,
1088                              NULL);
1089 
1090         return GSM_CLIENT (xsmp);
1091 }
1092 
1093 static Status
register_client_callback(SmsConn conn,SmPointer manager_data,char * previous_id)1094 register_client_callback (SmsConn    conn,
1095                           SmPointer  manager_data,
1096                           char      *previous_id)
1097 {
1098         gboolean       handled;
1099         char          *id;
1100         GsmXSMPClientPrivate *priv;
1101 
1102         GsmXSMPClient *client = manager_data;
1103         priv = gsm_xsmp_client_get_instance_private (client);
1104 
1105         g_debug ("GsmXSMPClient: Client '%s' received RegisterClient(%s)",
1106                  priv->description,
1107                  previous_id ? previous_id : "NULL");
1108 
1109 
1110         /* There are three cases:
1111          * 1. id is NULL - we'll use a new one
1112          * 2. id is known - we'll use known one
1113          * 3. id is unknown - this is an error
1114          */
1115         id = g_strdup (previous_id);
1116 
1117         handled = FALSE;
1118         g_signal_emit (client, signals[REGISTER_REQUEST], 0, &id, &handled);
1119         if (! handled) {
1120                 g_debug ("GsmXSMPClient:  RegisterClient not handled!");
1121                 g_free (id);
1122                 free (previous_id);
1123                 g_assert_not_reached ();
1124                 return FALSE;
1125         }
1126 
1127         if (IS_STRING_EMPTY (id)) {
1128                 g_debug ("GsmXSMPClient:   rejected: invalid previous_id");
1129                 free (previous_id);
1130                 return FALSE;
1131         }
1132 
1133         g_object_set (client, "startup-id", id, NULL);
1134 
1135         set_description (client);
1136 
1137         g_debug ("GsmXSMPClient: Sending RegisterClientReply to '%s'", priv->description);
1138 
1139         SmsRegisterClientReply (conn, id);
1140 
1141         if (IS_STRING_EMPTY (previous_id)) {
1142                 /* Send the initial SaveYourself. */
1143                 g_debug ("GsmXSMPClient: Sending initial SaveYourself");
1144                 SmsSaveYourself (conn, SmSaveLocal, False, SmInteractStyleNone, False);
1145                 priv->current_save_yourself = SmSaveLocal;
1146         }
1147 
1148         gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_REGISTERED);
1149 
1150         g_free (id);
1151         free (previous_id);
1152 
1153         return TRUE;
1154 }
1155 
1156 
1157 static void
save_yourself_request_callback(SmsConn conn,SmPointer manager_data,int save_type,Bool shutdown,int interact_style,Bool fast,Bool global)1158 save_yourself_request_callback (SmsConn   conn,
1159                                 SmPointer manager_data,
1160                                 int       save_type,
1161                                 Bool      shutdown,
1162                                 int       interact_style,
1163                                 Bool      fast,
1164                                 Bool      global)
1165 {
1166         GsmXSMPClientPrivate *priv;
1167         GsmXSMPClient *client = manager_data;
1168 
1169         priv = gsm_xsmp_client_get_instance_private (client);
1170 
1171         g_debug ("GsmXSMPClient: Client '%s' received SaveYourselfRequest(%s, %s, %s, %s, %s)",
1172                  priv->description,
1173                  save_type == SmSaveLocal ? "SmSaveLocal" :
1174                  save_type == SmSaveGlobal ? "SmSaveGlobal" : "SmSaveBoth",
1175                  shutdown ? "Shutdown" : "!Shutdown",
1176                  interact_style == SmInteractStyleAny ? "SmInteractStyleAny" :
1177                  interact_style == SmInteractStyleErrors ? "SmInteractStyleErrors" :
1178                  "SmInteractStyleNone", fast ? "Fast" : "!Fast",
1179                  global ? "Global" : "!Global");
1180 
1181         /* Examining the g_debug above, you can see that there are a total
1182          * of 72 different combinations of options that this could have been
1183          * called with. However, most of them are stupid.
1184          *
1185          * If @shutdown and @global are both TRUE, that means the caller is
1186          * requesting that a logout message be sent to all clients, so we do
1187          * that. We use @fast to decide whether or not to show a
1188          * confirmation dialog. (This isn't really what @fast is for, but
1189          * the old mate-session and ksmserver both interpret it that way,
1190          * so we do too.) We ignore @save_type because we pick the correct
1191          * save_type ourselves later based on user prefs, dialog choices,
1192          * etc, and we ignore @interact_style, because clients have not used
1193          * it correctly consistently enough to make it worth honoring.
1194          *
1195          * If @shutdown is TRUE and @global is FALSE, the caller is
1196          * confused, so we ignore the request.
1197          *
1198          * If @shutdown is FALSE and @save_type is SmSaveGlobal or
1199          * SmSaveBoth, then the client wants us to ask some or all open
1200          * applications to save open files to disk, but NOT quit. This is
1201          * silly and so we ignore the request.
1202          *
1203          * If @shutdown is FALSE and @save_type is SmSaveLocal, then the
1204          * client wants us to ask some or all open applications to update
1205          * their current saved state, but not log out. At the moment, the
1206          * code only supports this for the !global case (ie, a client
1207          * requesting that it be allowed to update *its own* saved state,
1208          * but not having everyone else update their saved state).
1209          */
1210 
1211         if (shutdown && global) {
1212                 g_debug ("GsmXSMPClient:   initiating shutdown");
1213                 g_signal_emit (client, signals[LOGOUT_REQUEST], 0, !fast);
1214         } else if (!shutdown && !global) {
1215                 g_debug ("GsmXSMPClient:   initiating checkpoint");
1216                 do_save_yourself (client, SmSaveLocal, TRUE);
1217         } else {
1218                 g_debug ("GsmXSMPClient:   ignoring");
1219         }
1220 }
1221 
1222 static void
save_yourself_phase2_request_callback(SmsConn conn,SmPointer manager_data)1223 save_yourself_phase2_request_callback (SmsConn   conn,
1224                                        SmPointer manager_data)
1225 {
1226         GsmXSMPClientPrivate *priv;
1227         GsmXSMPClient *client = manager_data;
1228 
1229         priv = gsm_xsmp_client_get_instance_private (client);
1230 
1231         g_debug ("GsmXSMPClient: Client '%s' received SaveYourselfPhase2Request",
1232                  priv->description);
1233 
1234         priv->current_save_yourself = -1;
1235 
1236         /* this is a valid response to SaveYourself and therefore
1237            may be a response to a QES or ES */
1238         gsm_client_end_session_response (GSM_CLIENT (client),
1239                                          TRUE, TRUE, FALSE,
1240                                          NULL);
1241 }
1242 
1243 static void
interact_request_callback(SmsConn conn,SmPointer manager_data,int dialog_type)1244 interact_request_callback (SmsConn   conn,
1245                            SmPointer manager_data,
1246                            int       dialog_type)
1247 {
1248         GsmXSMPClientPrivate *priv;
1249         GsmXSMPClient *client = manager_data;
1250 
1251         priv = gsm_xsmp_client_get_instance_private (client);
1252 #if 0
1253         gboolean       res;
1254         GError        *error;
1255 #endif
1256 
1257         g_debug ("GsmXSMPClient: Client '%s' received InteractRequest(%s)",
1258                  priv->description,
1259                  dialog_type == SmDialogNormal ? "Dialog" : "Errors");
1260 
1261         gsm_client_end_session_response (GSM_CLIENT (client),
1262                                          FALSE, FALSE, FALSE,
1263                                          _("This program is blocking logout."));
1264 
1265 #if 0
1266         /* Can't just call back with Interact because session client
1267            grabs the keyboard!  So, we try to get it to release
1268            grabs by telling it we've cancelled the shutdown.
1269            This grabbing is clearly bullshit and is not supported by
1270            the client spec or protocol spec.
1271         */
1272         res = xsmp_cancel_end_session (GSM_CLIENT (client), &error);
1273         if (! res) {
1274                 g_warning ("Unable to cancel end session: %s", error->message);
1275                 g_error_free (error);
1276         }
1277 #endif
1278         xsmp_interact (GSM_CLIENT (client));
1279 }
1280 
1281 static void
interact_done_callback(SmsConn conn,SmPointer manager_data,Bool cancel_shutdown)1282 interact_done_callback (SmsConn   conn,
1283                         SmPointer manager_data,
1284                         Bool      cancel_shutdown)
1285 {
1286         GsmXSMPClientPrivate *priv;
1287         GsmXSMPClient *client = manager_data;
1288 
1289         priv = gsm_xsmp_client_get_instance_private (client);
1290 
1291         g_debug ("GsmXSMPClient: Client '%s' received InteractDone(cancel_shutdown = %s)",
1292                  priv->description,
1293                  cancel_shutdown ? "True" : "False");
1294 
1295         gsm_client_end_session_response (GSM_CLIENT (client),
1296                                          TRUE, FALSE, cancel_shutdown,
1297                                          NULL);
1298 }
1299 
1300 static void
save_yourself_done_callback(SmsConn conn,SmPointer manager_data,Bool success)1301 save_yourself_done_callback (SmsConn   conn,
1302                              SmPointer manager_data,
1303                              Bool      success)
1304 {
1305         GsmXSMPClientPrivate *priv;
1306         GsmXSMPClient *client = manager_data;
1307 
1308         priv = gsm_xsmp_client_get_instance_private (client);
1309 
1310         g_debug ("GsmXSMPClient: Client '%s' received SaveYourselfDone(success = %s)",
1311                  priv->description,
1312                  success ? "True" : "False");
1313 
1314         if (priv->current_save_yourself != -1) {
1315                 SmsSaveComplete (priv->conn);
1316                 priv->current_save_yourself = -1;
1317         }
1318 
1319         /* If success is false then the application couldn't save data. Nothing
1320          * the session manager can do about, though. FIXME: we could display a
1321          * dialog about this, I guess. */
1322         gsm_client_end_session_response (GSM_CLIENT (client),
1323                                          TRUE, FALSE, FALSE,
1324                                          NULL);
1325 
1326         if (priv->next_save_yourself) {
1327                 int      save_type = priv->next_save_yourself;
1328                 gboolean allow_interact = priv->next_save_yourself_allow_interact;
1329 
1330                 priv->next_save_yourself = -1;
1331                 priv->next_save_yourself_allow_interact = -1;
1332                 do_save_yourself (client, save_type, allow_interact);
1333         }
1334 }
1335 
1336 static void
close_connection_callback(SmsConn conn,SmPointer manager_data,int count,char ** reason_msgs)1337 close_connection_callback (SmsConn     conn,
1338                            SmPointer   manager_data,
1339                            int         count,
1340                            char      **reason_msgs)
1341 {
1342         int            i;
1343         GsmXSMPClientPrivate *priv;
1344         GsmXSMPClient *client = manager_data;
1345 
1346         priv = gsm_xsmp_client_get_instance_private (client);
1347 
1348         g_debug ("GsmXSMPClient: Client '%s' received CloseConnection", priv->description);
1349         for (i = 0; i < count; i++) {
1350                 g_debug ("GsmXSMPClient:  close reason: '%s'", reason_msgs[i]);
1351         }
1352         SmFreeReasons (count, reason_msgs);
1353 
1354         gsm_client_set_status (GSM_CLIENT (client), GSM_CLIENT_FINISHED);
1355         gsm_client_disconnected (GSM_CLIENT (client));
1356 }
1357 
1358 void
gsm_xsmp_client_connect(GsmXSMPClient * client,SmsConn conn,unsigned long * mask_ret,SmsCallbacks * callbacks_ret)1359 gsm_xsmp_client_connect (GsmXSMPClient *client,
1360                          SmsConn        conn,
1361                          unsigned long *mask_ret,
1362                          SmsCallbacks  *callbacks_ret)
1363 {
1364         GsmXSMPClientPrivate *priv;
1365 
1366         priv = gsm_xsmp_client_get_instance_private (client);
1367         priv->conn = conn;
1368 
1369         g_debug ("GsmXSMPClient: Initializing client %s", priv->description);
1370 
1371         *mask_ret = 0;
1372 
1373         *mask_ret |= SmsRegisterClientProcMask;
1374         callbacks_ret->register_client.callback = register_client_callback;
1375         callbacks_ret->register_client.manager_data  = client;
1376 
1377         *mask_ret |= SmsInteractRequestProcMask;
1378         callbacks_ret->interact_request.callback = interact_request_callback;
1379         callbacks_ret->interact_request.manager_data = client;
1380 
1381         *mask_ret |= SmsInteractDoneProcMask;
1382         callbacks_ret->interact_done.callback = interact_done_callback;
1383         callbacks_ret->interact_done.manager_data = client;
1384 
1385         *mask_ret |= SmsSaveYourselfRequestProcMask;
1386         callbacks_ret->save_yourself_request.callback = save_yourself_request_callback;
1387         callbacks_ret->save_yourself_request.manager_data = client;
1388 
1389         *mask_ret |= SmsSaveYourselfP2RequestProcMask;
1390         callbacks_ret->save_yourself_phase2_request.callback = save_yourself_phase2_request_callback;
1391         callbacks_ret->save_yourself_phase2_request.manager_data = client;
1392 
1393         *mask_ret |= SmsSaveYourselfDoneProcMask;
1394         callbacks_ret->save_yourself_done.callback = save_yourself_done_callback;
1395         callbacks_ret->save_yourself_done.manager_data = client;
1396 
1397         *mask_ret |= SmsCloseConnectionProcMask;
1398         callbacks_ret->close_connection.callback = close_connection_callback;
1399         callbacks_ret->close_connection.manager_data  = client;
1400 
1401         *mask_ret |= SmsSetPropertiesProcMask;
1402         callbacks_ret->set_properties.callback = set_properties_callback;
1403         callbacks_ret->set_properties.manager_data = client;
1404 
1405         *mask_ret |= SmsDeletePropertiesProcMask;
1406         callbacks_ret->delete_properties.callback = delete_properties_callback;
1407         callbacks_ret->delete_properties.manager_data = client;
1408 
1409         *mask_ret |= SmsGetPropertiesProcMask;
1410         callbacks_ret->get_properties.callback = get_properties_callback;
1411         callbacks_ret->get_properties.manager_data = client;
1412 }
1413 
1414 void
gsm_xsmp_client_save_state(GsmXSMPClient * client)1415 gsm_xsmp_client_save_state (GsmXSMPClient *client)
1416 {
1417         g_return_if_fail (GSM_IS_XSMP_CLIENT (client));
1418 }
1419