~charlesk/indicator-session/use-gslice

« back to all changes in this revision

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

  • Committer: Tarmac
  • Author(s): Charles Kerr, Lars Uebernickel
  • Date: 2013-07-12 14:58:31 UTC
  • mfrom: (384.2.112 ng-login1)
  • Revision ID: tarmac-20130712145831-n2bqrachsd9qa90n
This is the GMenu, login1 version of indicator-session.

This resubmission removes the prerequisite branch because the entire diff is contained in this ng-login1 branch.

Approved by PS Jenkins bot.

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