~unity8-desktop-session-team/indicator-session/indicator-session-using-upstart

« back to all changes in this revision

Viewing changes to src/users-service-dbus.c

  • Committer: Charles Kerr
  • Date: 2012-07-05 15:40:24 UTC
  • Revision ID: charles.kerr@canonical.com-20120705154024-2ay685pqbusuzp76
Remove the etched border effect for user icons.

They looked good before, but look cluttered with the new reduced icon size, and lessening clutter was the reason for shrinking the icons in the first place.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */
 
2
/*
 
3
 * Copyright 2009 Canonical Ltd.
 
4
 *
 
5
 * Authors:
 
6
 *     Cody Russell <crussell@canonical.com>
 
7
 *     Charles Kerr <charles.kerr@canonical.com>
 
8
 *
 
9
 * This program is free software: you can redistribute it and/or modify it
 
10
 * under the terms of the GNU General Public License version 3, as published
 
11
 * by the Free Software Foundation.
 
12
 *
 
13
 * This program is distributed in the hope that it will be useful, but
 
14
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 
15
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
16
 * PURPOSE.  See the GNU General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU General Public License along
 
19
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 
20
 */
 
21
 
 
22
#ifdef HAVE_CONFIG_H
 
23
 #include "config.h"
 
24
#endif
 
25
 
 
26
#include <glib.h>
 
27
 
 
28
#include <errno.h>
 
29
 
 
30
#include <pwd.h> /* getpwuid() */
 
31
 
 
32
#include "dbus-accounts.h"
 
33
#include "dbus-consolekit-manager.h"
 
34
#include "dbus-consolekit-seat.h"
 
35
#include "dbus-consolekit-session.h"
 
36
#include "dbus-display-manager.h"
 
37
#include "dbus-user.h"
 
38
#include "shared-names.h"
 
39
#include "users-service-dbus.h"
 
40
 
 
41
#define CK_ADDR             "org.freedesktop.ConsoleKit"
 
42
#define CK_SESSION_IFACE    "org.freedesktop.ConsoleKit.Session"
 
43
 
 
44
/**
 
45
***
 
46
**/
 
47
 
 
48
static void     update_user_list     (UsersServiceDbus  * self);
 
49
 
 
50
static gchar*   get_seat             (UsersServiceDbus  * service);
 
51
 
 
52
static void     on_user_added        (Accounts          * o,
 
53
                                      const gchar       * user_object_path,
 
54
                                      UsersServiceDbus  * service);
 
55
 
 
56
static void     on_user_deleted      (Accounts          * o,
 
57
                                      const gchar       * user_object_path,
 
58
                                      UsersServiceDbus  * service);
 
59
 
 
60
static void     on_session_added     (ConsoleKitSeat    * seat,
 
61
                                      const gchar       * ssid,
 
62
                                      UsersServiceDbus  * service);
 
63
 
 
64
static void     on_session_removed   (ConsoleKitSeat    * seat,
 
65
                                      const gchar       * ssid,
 
66
                                      UsersServiceDbus  * service);
 
67
 
 
68
static void     on_session_list      (ConsoleKitSeat    * seat,
 
69
                                      GAsyncResult      * result,
 
70
                                      UsersServiceDbus  * service);
 
71
 
 
72
/***
 
73
****  Priv Struct
 
74
***/
 
75
 
 
76
struct _UsersServiceDbusPrivate
 
77
{
 
78
  gchar * seat;
 
79
  gchar * guest_ssid;
 
80
 
 
81
  /* ssid -> AccountsUser lookup */
 
82
  GHashTable * sessions;
 
83
 
 
84
  /* user object path -> AccountsUser lookup */
 
85
  GHashTable * users;
 
86
 
 
87
  GCancellable * cancellable;
 
88
  ConsoleKitSeat * seat_proxy;
 
89
  ConsoleKitManager * ck_manager_proxy;
 
90
  Accounts * accounts_proxy;
 
91
};
 
92
 
 
93
/***
 
94
****  GObject
 
95
***/
 
96
 
 
97
enum
 
98
{
 
99
  USER_LIST_CHANGED,
 
100
  USER_LOGGED_IN_CHANGED,
 
101
  GUEST_LOGGED_IN_CHANGED,
 
102
  N_SIGNALS
 
103
};
 
104
 
 
105
static guint signals[N_SIGNALS] = { 0 };
 
106
 
 
107
G_DEFINE_TYPE (UsersServiceDbus, users_service_dbus, G_TYPE_OBJECT);
 
108
 
 
109
static void
 
110
users_service_dbus_dispose (GObject *object)
 
111
{
 
112
  UsersServiceDbusPrivate * priv = USERS_SERVICE_DBUS(object)->priv;
 
113
 
 
114
  g_clear_object (&priv->accounts_proxy);
 
115
  g_clear_object (&priv->seat_proxy);
 
116
  g_clear_object (&priv->ck_manager_proxy);
 
117
 
 
118
  if (priv->cancellable != NULL)
 
119
    {
 
120
      g_cancellable_cancel (priv->cancellable);
 
121
      g_clear_object (&priv->cancellable);
 
122
    }
 
123
 
 
124
  if (priv->users != NULL)
 
125
    {
 
126
      g_hash_table_destroy (priv->users);
 
127
      priv->users = NULL;
 
128
    }
 
129
 
 
130
  if (priv->sessions != NULL)
 
131
    {
 
132
      g_hash_table_destroy (priv->sessions);
 
133
      priv->sessions = NULL;
 
134
    }
 
135
 
 
136
  G_OBJECT_CLASS (users_service_dbus_parent_class)->dispose (object);
 
137
}
 
138
 
 
139
static void
 
140
users_service_dbus_finalize (GObject *object)
 
141
{
 
142
  UsersServiceDbusPrivate * priv = USERS_SERVICE_DBUS(object)->priv;
 
143
 
 
144
  g_free (priv->guest_ssid);
 
145
  g_free (priv->seat);
 
146
 
 
147
  G_OBJECT_CLASS (users_service_dbus_parent_class)->finalize (object);
 
148
}
 
149
 
 
150
static void
 
151
users_service_dbus_class_init (UsersServiceDbusClass *klass)
 
152
{
 
153
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
154
 
 
155
  g_type_class_add_private (object_class, sizeof (UsersServiceDbusPrivate));
 
156
 
 
157
  object_class->dispose = users_service_dbus_dispose;
 
158
  object_class->finalize = users_service_dbus_finalize;
 
159
 
 
160
  signals[USER_LIST_CHANGED] = g_signal_new (
 
161
              "user-list-changed",
 
162
              G_TYPE_FROM_CLASS (klass),
 
163
              G_SIGNAL_RUN_LAST,
 
164
              G_STRUCT_OFFSET (UsersServiceDbusClass, user_list_changed),
 
165
              NULL, NULL,
 
166
              g_cclosure_marshal_VOID__VOID,
 
167
              G_TYPE_NONE, 0);
 
168
 
 
169
  signals[USER_LOGGED_IN_CHANGED] = g_signal_new (
 
170
              "user-logged-in-changed",
 
171
              G_TYPE_FROM_CLASS (klass),
 
172
              G_SIGNAL_RUN_LAST,
 
173
              G_STRUCT_OFFSET (UsersServiceDbusClass, user_logged_in_changed),
 
174
              NULL, NULL,
 
175
              g_cclosure_marshal_VOID__OBJECT,
 
176
              G_TYPE_NONE, 1, G_TYPE_OBJECT);
 
177
 
 
178
  signals[GUEST_LOGGED_IN_CHANGED] = g_signal_new (
 
179
              "guest-logged-in-changed",
 
180
              G_TYPE_FROM_CLASS (klass),
 
181
              G_SIGNAL_RUN_LAST,
 
182
              G_STRUCT_OFFSET (UsersServiceDbusClass, guest_logged_in_changed),
 
183
              NULL, NULL,
 
184
              g_cclosure_marshal_VOID__VOID,
 
185
              G_TYPE_NONE, 0);
 
186
}
 
187
 
 
188
static void
 
189
users_service_dbus_init (UsersServiceDbus *self)
 
190
{
 
191
  GError * error = NULL;
 
192
 
 
193
  self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
 
194
                                            USERS_SERVICE_DBUS_TYPE,
 
195
                                            UsersServiceDbusPrivate);
 
196
 
 
197
  UsersServiceDbusPrivate * p  = self->priv;
 
198
 
 
199
  p->cancellable = g_cancellable_new ();
 
200
 
 
201
  /* ssid -> AccountsUser */
 
202
  p->sessions = g_hash_table_new_full (g_str_hash,
 
203
                                       g_str_equal,
 
204
                                       g_free,
 
205
                                       g_object_unref);
 
206
 
 
207
  /* user object path -> AccountsUser */
 
208
  p->users = g_hash_table_new_full (g_str_hash,
 
209
                                    g_str_equal,
 
210
                                    g_free,
 
211
                                    g_object_unref);
 
212
 
 
213
  /**
 
214
  ***  create the consolekit manager proxy...
 
215
  **/
 
216
 
 
217
  p->ck_manager_proxy = console_kit_manager_proxy_new_for_bus_sync (
 
218
                             G_BUS_TYPE_SYSTEM,
 
219
                             G_DBUS_PROXY_FLAGS_NONE,
 
220
                             "org.freedesktop.ConsoleKit",
 
221
                             "/org/freedesktop/ConsoleKit/Manager",
 
222
                             NULL,
 
223
                             &error);
 
224
  if (error != NULL)
 
225
    {
 
226
      g_warning ("%s: %s", G_STRLOC, error->message);
 
227
      g_clear_error (&error);
 
228
    }
 
229
 
 
230
  p->seat = get_seat (self);
 
231
 
 
232
  /**
 
233
  ***  create the consolekit seat proxy...
 
234
  **/
 
235
 
 
236
  if (p->seat != NULL)
 
237
    {
 
238
      ConsoleKitSeat * proxy = console_kit_seat_proxy_new_for_bus_sync (
 
239
                                 G_BUS_TYPE_SYSTEM,
 
240
                                 G_DBUS_PROXY_FLAGS_NONE,
 
241
                                 "org.freedesktop.ConsoleKit",
 
242
                                 p->seat,
 
243
                                 NULL,
 
244
                                 &error);
 
245
 
 
246
      if (error != NULL)
 
247
        {
 
248
          g_warning ("Failed to connect to the ConsoleKit seat: %s", error->message);
 
249
          g_clear_error (&error);
 
250
        }
 
251
      else
 
252
        {
 
253
          g_signal_connect (proxy, "session-added",
 
254
                            G_CALLBACK (on_session_added), self);
 
255
          g_signal_connect (proxy, "session-removed",
 
256
                            G_CALLBACK (on_session_removed), self);
 
257
          console_kit_seat_call_get_sessions (proxy, p->cancellable,
 
258
                            (GAsyncReadyCallback)on_session_list, self);
 
259
          p->seat_proxy = proxy;
 
260
        }
 
261
    }
 
262
 
 
263
  /**
 
264
  ***  create the accounts manager proxy...
 
265
  **/
 
266
 
 
267
  Accounts * proxy = accounts_proxy_new_for_bus_sync (
 
268
                       G_BUS_TYPE_SYSTEM,
 
269
                       G_DBUS_PROXY_FLAGS_NONE,
 
270
                       "org.freedesktop.Accounts",
 
271
                       "/org/freedesktop/Accounts",
 
272
                       NULL,
 
273
                       &error);
 
274
  if (error != NULL)
 
275
    {
 
276
      g_warning ("%s: %s", G_STRFUNC, error->message);
 
277
      g_clear_error (&error);
 
278
    }
 
279
  else
 
280
    {
 
281
      g_signal_connect (proxy, "user-added", G_CALLBACK(on_user_added), self);
 
282
      g_signal_connect (proxy, "user-deleted", G_CALLBACK(on_user_deleted), self);
 
283
      p->accounts_proxy = proxy;
 
284
      update_user_list (self);
 
285
    }
 
286
}
 
287
 
 
288
/***
 
289
****
 
290
***/
 
291
 
 
292
static void
 
293
emit_user_list_changed (UsersServiceDbus * self)
 
294
{
 
295
  g_signal_emit (self, signals[USER_LIST_CHANGED], 0);
 
296
}
 
297
 
 
298
static void
 
299
emit_user_login_changed (UsersServiceDbus * self, AccountsUser * user)
 
300
{
 
301
  g_signal_emit (self, signals[USER_LOGGED_IN_CHANGED], 0, user);
 
302
}
 
303
 
 
304
static void
 
305
emit_guest_login_changed (UsersServiceDbus * self)
 
306
{
 
307
  g_signal_emit (self, signals[GUEST_LOGGED_IN_CHANGED], 0);
 
308
}
 
309
 
 
310
/***
 
311
****
 
312
***/
 
313
 
 
314
static ConsoleKitSession*
 
315
create_consolekit_session_proxy (const char * ssid)
 
316
{
 
317
  GError * error = NULL;
 
318
 
 
319
  ConsoleKitSession * p = console_kit_session_proxy_new_for_bus_sync (
 
320
                            G_BUS_TYPE_SYSTEM,
 
321
                            G_DBUS_PROXY_FLAGS_NONE,
 
322
                            CK_ADDR,
 
323
                            ssid,
 
324
                            NULL,
 
325
                            &error);
 
326
  if (error != NULL)
 
327
    {
 
328
      g_warning ("%s: %s", G_STRLOC, error->message);
 
329
      g_error_free (error);
 
330
    }
 
331
 
 
332
  return p;
 
333
}
 
334
 
 
335
static gchar *
 
336
get_seat_from_session_proxy (ConsoleKitSession * session_proxy)
 
337
{
 
338
  gchar * seat = NULL;
 
339
 
 
340
  GError * error = NULL;
 
341
  console_kit_session_call_get_seat_id_sync (session_proxy,
 
342
                                             &seat,
 
343
                                             NULL,
 
344
                                             &error);
 
345
  if (error != NULL)
 
346
    {
 
347
      g_debug ("%s: %s", G_STRLOC, error->message);
 
348
      g_error_free (error);
 
349
    }
 
350
 
 
351
  return seat;
 
352
}
 
353
 
 
354
static gchar *
 
355
get_seat (UsersServiceDbus *service)
 
356
{
 
357
  gchar * seat = NULL;
 
358
  gchar * ssid = NULL;
 
359
  GError * error = NULL;
 
360
  UsersServiceDbusPrivate * priv = service->priv;
 
361
 
 
362
  console_kit_manager_call_get_current_session_sync (priv->ck_manager_proxy,
 
363
                                                     &ssid,
 
364
                                                     NULL,
 
365
                                                     &error);
 
366
 
 
367
  if (error != NULL)
 
368
    {
 
369
      g_debug ("%s: %s", G_STRLOC, error->message);
 
370
      g_error_free (error);
 
371
    }
 
372
  else
 
373
    {
 
374
      ConsoleKitSession * session = create_consolekit_session_proxy (ssid);
 
375
 
 
376
      if (session != NULL)
 
377
        {
 
378
          seat = get_seat_from_session_proxy (session);
 
379
          g_object_unref (session);
 
380
        }
 
381
    }
 
382
 
 
383
  return seat;
 
384
}
 
385
 
 
386
/***
 
387
****  AccountsUser add-ons for tracking sessions
 
388
***/
 
389
 
 
390
static GHashTable*
 
391
user_get_sessions_hashset (AccountsUser * user)
 
392
{
 
393
  static GQuark q = 0;
 
394
 
 
395
  if (G_UNLIKELY(!q))
 
396
    {
 
397
      q = g_quark_from_static_string ("sessions");
 
398
    }
 
399
 
 
400
  GObject * o = G_OBJECT (user);
 
401
  GHashTable * h = g_object_get_qdata (o, q);
 
402
  if (h == NULL)
 
403
    {
 
404
      h = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
405
      g_object_set_qdata_full (o, q, h, (GDestroyNotify)g_hash_table_destroy);
 
406
    }
 
407
 
 
408
  return h;
 
409
}
 
410
 
 
411
static void
 
412
user_add_session (AccountsUser * user, const char * ssid)
 
413
{
 
414
  g_hash_table_add (user_get_sessions_hashset(user), g_strdup(ssid));
 
415
}
 
416
 
 
417
static void
 
418
user_remove_session (AccountsUser * user, const char * ssid)
 
419
{
 
420
  g_hash_table_remove (user_get_sessions_hashset(user), ssid);
 
421
}
 
422
 
 
423
static guint
 
424
user_count_sessions (AccountsUser * user)
 
425
{
 
426
  return g_hash_table_size (user_get_sessions_hashset(user));
 
427
}
 
428
 
 
429
/***
 
430
****  Users
 
431
***/
 
432
 
 
433
/* adds this user session to the user's and service's session tables */
 
434
static void
 
435
add_user_session (UsersServiceDbus  * service,
 
436
                  AccountsUser      * user,
 
437
                  const gchar       * ssid)
 
438
{
 
439
  ConsoleKitSession * session_proxy = create_consolekit_session_proxy (ssid);
 
440
  if (session_proxy != NULL)
 
441
    {
 
442
      UsersServiceDbusPrivate * priv = service->priv;
 
443
      gchar * seat = get_seat_from_session_proxy (session_proxy);
 
444
 
 
445
      /* is this session in our seat? */
 
446
      if (seat && priv->seat && !g_strcmp0 (seat, priv->seat))
 
447
        {
 
448
          /* does this session have a display? */
 
449
          gchar * display = NULL;
 
450
          console_kit_session_call_get_x11_display_sync (session_proxy,
 
451
                                                         &display,
 
452
                                                         NULL, NULL);
 
453
          const gboolean has_display = display && *display;
 
454
          g_free (display);
 
455
 
 
456
          if (has_display)
 
457
            {
 
458
              const gchar * username = accounts_user_get_user_name (user);
 
459
              g_debug ("%s adding %s's session '%s' to our tables",
 
460
                       G_STRLOC, username, ssid);
 
461
 
 
462
              g_hash_table_insert (priv->sessions,
 
463
                                   g_strdup (ssid),
 
464
                                   g_object_ref (user));
 
465
 
 
466
              user_add_session (user, ssid);
 
467
            }
 
468
        }
 
469
 
 
470
      g_free (seat);
 
471
      g_object_unref (session_proxy);
 
472
    }
 
473
}
 
474
 
 
475
/* calls add_user_session() for each of this user's sessions */
 
476
static void
 
477
add_user_sessions (UsersServiceDbus *self, AccountsUser * user)
 
478
{
 
479
  const guint64 uid = accounts_user_get_uid (user);
 
480
  const char * username = accounts_user_get_user_name (user);
 
481
  g_debug ("%s adding %s (%i)", G_STRLOC, username, (int)uid);
 
482
 
 
483
  GError * error = NULL;
 
484
  gchar ** sessions = NULL;
 
485
  console_kit_manager_call_get_sessions_for_unix_user_sync (
 
486
                                              self->priv->ck_manager_proxy,
 
487
                                              uid,
 
488
                                              &sessions,
 
489
                                              NULL,
 
490
                                              &error);
 
491
 
 
492
  if (error != NULL)
 
493
    {
 
494
      g_debug ("%s: %s", G_STRLOC, error->message);
 
495
      g_error_free (error);
 
496
    }
 
497
  else if (sessions != NULL)
 
498
    {
 
499
      int i;
 
500
 
 
501
      for (i=0; sessions[i]; i++)
 
502
        {
 
503
          const char * const ssid = sessions[i];
 
504
          g_debug ("%s adding %s's session %s", G_STRLOC, username, ssid);
 
505
          add_user_session (self, user, ssid);
 
506
        }
 
507
 
 
508
      g_strfreev (sessions);
 
509
    }
 
510
}
 
511
 
 
512
static void
 
513
copy_proxy_properties (GDBusProxy * source, GDBusProxy * target)
 
514
{
 
515
  gchar ** keys = g_dbus_proxy_get_cached_property_names (source);
 
516
 
 
517
  if (keys != NULL)
 
518
    {
 
519
      int i;
 
520
      GVariantBuilder builder;
 
521
      g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
 
522
 
 
523
      for (i=0; keys[i]; i++)
 
524
        {
 
525
          const gchar * const key = keys[i];
 
526
          GVariant * value = g_dbus_proxy_get_cached_property (source, key);
 
527
          g_dbus_proxy_set_cached_property (target, key, value);
 
528
          g_variant_builder_add (&builder, "{sv}", key, value);
 
529
          g_variant_unref (value);
 
530
        }
 
531
 
 
532
      g_signal_emit_by_name (target, "g-properties-changed", g_variant_builder_end(&builder), keys);
 
533
      g_strfreev (keys);
 
534
    }
 
535
}
 
536
 
 
537
/**
 
538
 * The AccountsUserProxy's properties aren't being updated automatically
 
539
 * for some reason... the only update we get is the 'changed' signal.
 
540
 * This function is a workaround to update our User object's properties.
 
541
 */
 
542
static void
 
543
on_user_changed (AccountsUser * user, UsersServiceDbus * service)
 
544
{
 
545
  AccountsUser * tmp = accounts_user_proxy_new_for_bus_sync (
 
546
                          G_BUS_TYPE_SYSTEM,
 
547
                          G_DBUS_PROXY_FLAGS_NONE,
 
548
                          "org.freedesktop.Accounts",
 
549
                          g_dbus_proxy_get_object_path (G_DBUS_PROXY(user)),
 
550
                          NULL,
 
551
                          NULL);
 
552
  if (tmp != NULL)
 
553
    {
 
554
      copy_proxy_properties (G_DBUS_PROXY(tmp), G_DBUS_PROXY(user));
 
555
      g_object_unref (tmp);
 
556
    }
 
557
}
 
558
 
 
559
static void
 
560
add_user_from_object_path (UsersServiceDbus  * self,
 
561
                           const char        * user_object_path)
 
562
{
 
563
  GError * error = NULL;
 
564
 
 
565
  AccountsUser * user = accounts_user_proxy_new_for_bus_sync (
 
566
                          G_BUS_TYPE_SYSTEM,
 
567
                          G_DBUS_PROXY_FLAGS_NONE,
 
568
                          "org.freedesktop.Accounts",
 
569
                          user_object_path,
 
570
                          NULL,
 
571
                          &error);
 
572
 
 
573
  if (error != NULL)
 
574
    {
 
575
      g_warning ("%s: %s", G_STRLOC, error->message);
 
576
      g_clear_error (&error);
 
577
    }
 
578
  else
 
579
    {
 
580
      AccountsUser * prev = g_hash_table_lookup (self->priv->users, user_object_path);
 
581
 
 
582
      if (prev != NULL) /* we've already got this user... sync its properties */
 
583
        {
 
584
          copy_proxy_properties (G_DBUS_PROXY(user), G_DBUS_PROXY(prev));
 
585
          g_object_unref (user);
 
586
          user = prev;
 
587
        }
 
588
      else /* ooo, we got a new user */
 
589
        {
 
590
          g_signal_connect (user, "changed", G_CALLBACK(on_user_changed), self);
 
591
          g_hash_table_insert (self->priv->users, g_strdup(user_object_path), user);
 
592
        }
 
593
 
 
594
      add_user_sessions (self, user);
 
595
    }
 
596
}
 
597
 
 
598
 
 
599
/* asks org.freedesktop.Accounts for a list of users and
 
600
 * calls add_user_from_object_path() on each of those users */
 
601
static void
 
602
update_user_list (UsersServiceDbus *self)
 
603
{
 
604
  g_return_if_fail(IS_USERS_SERVICE_DBUS(self));
 
605
 
 
606
  GError * error = NULL;
 
607
  char ** object_paths = NULL;
 
608
  UsersServiceDbusPrivate * priv = self->priv;
 
609
 
 
610
  accounts_call_list_cached_users_sync (priv->accounts_proxy,
 
611
                                        &object_paths,
 
612
                                        NULL,
 
613
                                        &error);
 
614
 
 
615
  if (error != NULL)
 
616
    {
 
617
      g_warning ("%s: %s", G_STRFUNC, error->message);
 
618
      g_clear_error (&error);
 
619
    }
 
620
  else if (object_paths != NULL)
 
621
    {
 
622
      gint i;
 
623
 
 
624
      for (i=0; object_paths[i] != NULL; ++i)
 
625
        {
 
626
          add_user_from_object_path (self, object_paths[i]);
 
627
        }
 
628
 
 
629
      emit_user_list_changed (self);
 
630
 
 
631
      g_strfreev (object_paths);
 
632
    }
 
633
 
 
634
  g_debug ("%s finished updating the user list", G_STRLOC);
 
635
}
 
636
 
 
637
static void
 
638
on_user_added (Accounts          * o          G_GNUC_UNUSED,
 
639
               const gchar       * user_path  G_GNUC_UNUSED,
 
640
               UsersServiceDbus  * service)
 
641
{
 
642
  /* We see a new user but we might not want to list it --
 
643
     for example, lightdm shows up when we switch to the greeter.
 
644
     So instead of adding the user directly here, let's ask
 
645
     org.freedesktop.Accounts for a fresh list of users
 
646
     because it filters out special cases. */
 
647
  update_user_list (service);
 
648
}
 
649
 
 
650
static void
 
651
on_user_deleted (Accounts          * o                  G_GNUC_UNUSED,
 
652
                 const gchar       * user_path,
 
653
                 UsersServiceDbus  * service)
 
654
{
 
655
  AccountsUser * user = g_hash_table_lookup (service->priv->users, user_path);
 
656
 
 
657
  if (user != NULL)
 
658
    {
 
659
      GObject * o = g_object_ref (G_OBJECT(user));
 
660
      g_hash_table_remove (service->priv->users, user_path);
 
661
      emit_user_list_changed (service);
 
662
      g_object_unref (o);
 
663
    }
 
664
}
 
665
 
 
666
static AccountsUser *
 
667
find_user_from_username (UsersServiceDbus  * self,
 
668
                         const gchar       * username)
 
669
{
 
670
  AccountsUser * match = NULL;
 
671
 
 
672
  g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), match);
 
673
 
 
674
  gpointer user;
 
675
  GHashTableIter iter;
 
676
  g_hash_table_iter_init (&iter, self->priv->users);
 
677
  while (!match && g_hash_table_iter_next (&iter, NULL, &user))
 
678
    {
 
679
      if (!g_strcmp0 (username, accounts_user_get_user_name (user)))
 
680
        {
 
681
          match = user;
 
682
        }
 
683
    }
 
684
 
 
685
  return match;
 
686
}
 
687
 
 
688
/***
 
689
****  Sessions
 
690
***/
 
691
 
 
692
static void
 
693
on_session_removed (ConsoleKitSeat   * seat_proxy,
 
694
                    const gchar      * ssid,
 
695
                    UsersServiceDbus * service)
 
696
{
 
697
  g_return_if_fail (IS_USERS_SERVICE_DBUS (service));
 
698
 
 
699
  UsersServiceDbusPrivate * priv = service->priv;
 
700
  g_debug ("%s %s() session removed %s", G_STRLOC, G_STRFUNC, ssid);
 
701
 
 
702
  if (!g_strcmp0 (ssid, priv->guest_ssid))
 
703
    {
 
704
      g_debug ("%s removing guest session %s", G_STRLOC, ssid);
 
705
      g_clear_pointer (&priv->guest_ssid, g_free);
 
706
      emit_guest_login_changed (service);
 
707
    }
 
708
  else
 
709
    {
 
710
      AccountsUser * user = g_hash_table_lookup (priv->sessions, ssid);
 
711
      if (user == NULL)
 
712
        {
 
713
          g_debug ("%s we're not tracking ssid %s", G_STRLOC, ssid);
 
714
        }
 
715
      else
 
716
        {
 
717
          GObject * o = g_object_ref (G_OBJECT(user));
 
718
          g_hash_table_remove (service->priv->users, ssid);
 
719
          user_remove_session (user, ssid);
 
720
          emit_user_login_changed (service, user);
 
721
          g_object_unref (o);
 
722
        }
 
723
    }
 
724
}
 
725
 
 
726
static gchar*
 
727
get_unix_username_from_ssid (UsersServiceDbus * self,
 
728
                             const gchar      * ssid)
 
729
{
 
730
  gchar * username = NULL;
 
731
 
 
732
  ConsoleKitSession * session_proxy = create_consolekit_session_proxy (ssid);
 
733
  if (session_proxy != NULL)
 
734
    {
 
735
      guint uid = 0;
 
736
      GError * error = NULL;
 
737
      console_kit_session_call_get_unix_user_sync (session_proxy,
 
738
                                                   &uid,
 
739
                                                   NULL, &error);
 
740
      if (error != NULL)
 
741
        {
 
742
          g_warning ("%s: %s", G_STRLOC, error->message);
 
743
          g_clear_error (&error);
 
744
        }
 
745
      else
 
746
        {
 
747
          errno = 0;
 
748
          const struct passwd * pwent = getpwuid (uid);
 
749
          if (pwent == NULL)
 
750
            {
 
751
              g_warning ("Failed to lookup user id %d: %s", (int)uid, g_strerror(errno));
 
752
            }
 
753
          else
 
754
            {
 
755
              username = g_strdup (pwent->pw_name);
 
756
            }
 
757
        }
 
758
 
 
759
      g_object_unref (session_proxy);
 
760
    }
 
761
 
 
762
  return username;
 
763
}
 
764
 
 
765
static gboolean
 
766
is_guest_username (const char * username)
 
767
{
 
768
  if (!g_strcmp0 (username, "guest"))
 
769
    return TRUE;
 
770
 
 
771
  if (username && g_str_has_prefix (username, "guest-"))
 
772
    return TRUE;
 
773
 
 
774
  return FALSE;
 
775
}
 
776
 
 
777
/* If the new session belongs to 'guest', update our guest_ssid.
 
778
   Otherwise, call add_user_session() to update our session tables */
 
779
static void
 
780
on_session_added (ConsoleKitSeat   * seat_proxy G_GNUC_UNUSED,
 
781
                  const gchar      * ssid,
 
782
                  UsersServiceDbus * service)
 
783
{
 
784
  g_return_if_fail (IS_USERS_SERVICE_DBUS(service));
 
785
 
 
786
  gchar * username = get_unix_username_from_ssid (service, ssid);
 
787
  g_debug ("%s %s() username %s has new session %s", G_STRLOC, G_STRFUNC, username, ssid);
 
788
 
 
789
  if (is_guest_username (username))
 
790
    {
 
791
      /* handle guest as a special case -- it's not in the GDM
 
792
         user tables and there isn't be an AccountsUser for it */
 
793
      g_debug("Found guest session: %s", ssid);
 
794
      g_free (service->priv->guest_ssid);
 
795
      service->priv->guest_ssid = g_strdup (ssid);
 
796
      emit_guest_login_changed (service);
 
797
    }
 
798
  else
 
799
    {
 
800
      AccountsUser * user = find_user_from_username (service, username);
 
801
 
 
802
      if (user != NULL)
 
803
        {
 
804
          add_user_session (service, user, ssid);
 
805
          emit_user_login_changed (service, user);
 
806
        }
 
807
    }
 
808
 
 
809
  g_free (username);
 
810
}
 
811
 
 
812
/* Receives a list of sessions and calls on_session_added() for each of them */
 
813
static void
 
814
on_session_list (ConsoleKitSeat   * seat_proxy,
 
815
                 GAsyncResult     * result,
 
816
                 UsersServiceDbus * self)
 
817
{
 
818
  GError * error = NULL;
 
819
  gchar ** sessions = NULL;
 
820
  g_debug ("%s bootstrapping the session list", G_STRLOC);
 
821
 
 
822
  console_kit_seat_call_get_sessions_finish (seat_proxy,
 
823
                                             &sessions,
 
824
                                             result,
 
825
                                             &error);
 
826
 
 
827
  if (error != NULL)
 
828
    {
 
829
      g_debug ("%s: %s", G_STRLOC, error->message);
 
830
      g_error_free (error);
 
831
    }
 
832
  else if (sessions != NULL)
 
833
    {
 
834
      int i;
 
835
 
 
836
      for (i=0; sessions[i]; i++)
 
837
        {
 
838
          g_debug ("%s adding initial session '%s'", G_STRLOC, sessions[i]);
 
839
          on_session_added (seat_proxy, sessions[i], self);
 
840
        }
 
841
 
 
842
      g_strfreev (sessions);
 
843
    }
 
844
 
 
845
  g_debug ("%s done bootstrapping the session list", G_STRLOC);
 
846
}
 
847
 
 
848
static DisplayManagerSeat *
 
849
create_display_proxy (UsersServiceDbus * self)
 
850
{
 
851
  const gchar * const seat = g_getenv ("XDG_SEAT_PATH");
 
852
  g_debug ("%s creating a DisplayManager proxy for seat %s", G_STRLOC, seat);
 
853
 
 
854
  GError * error = NULL;
 
855
  DisplayManagerSeat * p = display_manager_seat_proxy_new_for_bus_sync (
 
856
                             G_BUS_TYPE_SYSTEM,
 
857
                             G_DBUS_PROXY_FLAGS_NONE,
 
858
                             "org.freedesktop.DisplayManager",
 
859
                             seat,
 
860
                             NULL,
 
861
                             &error);
 
862
 
 
863
  if (error != NULL)
 
864
    {
 
865
      g_warning ("%s: %s", G_STRLOC, error->message);
 
866
      g_error_free (error);
 
867
    }
 
868
 
 
869
  return p;
 
870
}
 
871
 
 
872
/***
 
873
****  Public API
 
874
***/
 
875
 
 
876
/**
 
877
 * users_service_dbus_get_user_list:
 
878
 *
 
879
 * Returns: (transfer container): a list of AccountsUser objects
 
880
 */
 
881
GList *
 
882
users_service_dbus_get_user_list (UsersServiceDbus * self)
 
883
{
 
884
  g_return_val_if_fail(IS_USERS_SERVICE_DBUS(self), NULL);
 
885
 
 
886
  return g_hash_table_get_values (self->priv->users);
 
887
}
 
888
 
 
889
/**
 
890
 * users_service_dbus_show_greeter:
 
891
 *
 
892
 * Ask the Display Mnaager to switch to the greeter screen.
 
893
 */
 
894
void
 
895
users_service_dbus_show_greeter (UsersServiceDbus * self)
 
896
{
 
897
  g_return_if_fail (IS_USERS_SERVICE_DBUS(self));
 
898
 
 
899
  DisplayManagerSeat * dp = create_display_proxy (self);
 
900
  display_manager_seat_call_switch_to_greeter_sync (dp, NULL, NULL);
 
901
  g_clear_object (&dp);
 
902
}
 
903
 
 
904
/**
 
905
 * users_service_dbus_activate_guest_session:
 
906
 *
 
907
 * Activates the guest account.
 
908
 */
 
909
void
 
910
users_service_dbus_activate_guest_session (UsersServiceDbus * self)
 
911
{
 
912
  g_return_if_fail(IS_USERS_SERVICE_DBUS(self));
 
913
 
 
914
  DisplayManagerSeat * dp = create_display_proxy (self);
 
915
  display_manager_seat_call_switch_to_guest_sync (dp, "", NULL, NULL);
 
916
  g_clear_object (&dp);
 
917
}
 
918
 
 
919
/**
 
920
 * users_service_dbus_activate_user_session:
 
921
 *
 
922
 * Activates a specific user.
 
923
 */
 
924
void
 
925
users_service_dbus_activate_user_session (UsersServiceDbus * self,
 
926
                                          AccountsUser     * user)
 
927
{
 
928
  g_return_if_fail (IS_USERS_SERVICE_DBUS(self));
 
929
 
 
930
  const char * const username = accounts_user_get_user_name (user);
 
931
  DisplayManagerSeat * dp = create_display_proxy (self);
 
932
  display_manager_seat_call_switch_to_user_sync (dp, username, "", NULL, NULL);
 
933
  g_clear_object (&dp);
 
934
}
 
935
 
 
936
/**
 
937
 * users_service_dbus_guest_session_enabled:
 
938
 *
 
939
 * Tells whether or not guest sessions are allowed.
 
940
 */
 
941
gboolean
 
942
users_service_dbus_guest_session_enabled (UsersServiceDbus * self)
 
943
{
 
944
  g_return_val_if_fail(IS_USERS_SERVICE_DBUS(self), FALSE);
 
945
 
 
946
  DisplayManagerSeat * dp = create_display_proxy (self);
 
947
  const gboolean enabled = display_manager_seat_get_has_guest_account (dp);
 
948
  g_clear_object (&dp);
 
949
  return enabled;
 
950
}
 
951
 
 
952
gboolean
 
953
users_service_dbus_can_activate_session (UsersServiceDbus * self)
 
954
{
 
955
  gboolean can_activate = FALSE;
 
956
 
 
957
  g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), can_activate);
 
958
 
 
959
  GError * error = NULL;
 
960
  console_kit_seat_call_can_activate_sessions_sync (self->priv->seat_proxy,
 
961
                                                    &can_activate,
 
962
                                                    NULL,
 
963
                                                    &error);
 
964
  if (error != NULL)
 
965
    {
 
966
      g_warning ("%s: %s", G_STRLOC, error->message);
 
967
      g_error_free (error);
 
968
    }
 
969
 
 
970
  return can_activate;
 
971
}
 
972
 
 
973
gboolean
 
974
users_service_dbus_is_guest_logged_in (UsersServiceDbus * self)
 
975
{
 
976
  g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), FALSE);
 
977
 
 
978
  return self->priv->guest_ssid != NULL;
 
979
}
 
980
 
 
981
gboolean
 
982
users_service_dbus_is_user_logged_in (UsersServiceDbus  * self,
 
983
                                      AccountsUser      * user)
 
984
{
 
985
  g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), FALSE);
 
986
  g_return_val_if_fail (IS_ACCOUNTS_USER(user), FALSE);
 
987
 
 
988
  return user_count_sessions (user) > 0;
 
989
}