Merge lp:~bratsche/indicator-session/users-service into lp:indicator-session/0.1

Proposed by Cody Russell
Status: Merged
Merged at revision: not available
Proposed branch: lp:~bratsche/indicator-session/users-service
Merge into: lp:indicator-session/0.1
Diff against target: 1768 lines
9 files modified
AUTHORS (+2/-0)
src/Makefile.am (+27/-2)
src/dbus-shared-names.h (+8/-6)
src/status-service.c (+8/-8)
src/users-service-dbus.c (+1147/-0)
src/users-service-dbus.h (+81/-0)
src/users-service.c (+191/-62)
src/users-service.list (+1/-0)
src/users-service.xml (+56/-0)
To merge this branch: bzr merge lp:~bratsche/indicator-session/users-service
Reviewer Review Type Date Requested Status
Ted Gould (community) Approve
Indicator Applet Developers Pending
Review via email: mp+12316@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Ted Gould (ted) wrote :

      * In users-service.c I don't see where count is updated. I think
        it should be incremented/decremented on user added/removed.
      * There should be icons on the users if they are set (probably
        should go in another branch/bug)
      * There doesn't seem to be any sorting of the user list. They
        should be sorted alphabetical by first name.
      * There are six signals defined in the Class structure but only 4
        created on class init.
      * I don't think that you need a call to
        dbus_g_object_type_install_info, that should only be needed if
        this object is being shared over DBus (server) but I think it's
        only a client.
      * Confirm with Robert, but I'm pretty sure the excludes list is
        already being applied on the GDM side. We shouldn't need to
        apply it on this side as well. That way there's only one copy
        of the list.
      * I think that dbus_g_connection_register_g_object can be dropped
        as well. Which I think is the only reason you're using the
        session bus, so I think that can be dropped.
      * Oh, now realizing more of the issue. Makefile.am shouldn't even
        be generating user-service-server.h. Drop that file.
      * I don't think that dbus_proxy_system and dbus_proxy_session are
        needed as we're not asking DBus itself for any information.
        We're just using it to communicate. We'd only need those
        proxies to query information about the bus itself.
      * Can session_compare be replaced with g_strcmp0? It seems about
        the same.
      * I was looking at "CanActivateSessions" call to ConsoleKit. Do
        you think we should check this earlier and make the menu items
        sensitive or insensitive based on this?
      * It looks like you're always getting the information on all the
        users. I think that we really don't care if it's over our max,
        so can we just not bother getting all that data if we're in
        overflow?
      * The guest user needs to be handled as well. If there is a guest
        already logged in selecting the guest on the menu shouldn't
        start a new session, but should go to the guest that is already
        running.

  review needs-fixing

review: Needs Fixing
42. By Cody Russell

modify count in user_added()/user_removed()

Revision history for this message
Cody Russell (bratsche) wrote :

> * I was looking at "CanActivateSessions" call to ConsoleKit. Do
> you think we should check this earlier and make the menu items
> sensitive or insensitive based on this?

Should the menuitems even be there if you can never click them? I went ahead and made an API on UsersServiceDbus that can check if the seat can activate sessions, and we can either make the menuitems insensitive or not add them or whatever. For now I didn't change the menu, just added the API.

I'm fixing up the remaining issues now.

Revision history for this message
Cody Russell (bratsche) wrote :

I'm going to sleep, but figured I'd document the status of this now.

> * In users-service.c I don't see where count is updated. I think
> it should be incremented/decremented on user added/removed.

Fixed.

> * There should be icons on the users if they are set (probably
> should go in another branch/bug)

TODO. Can we do this in a separate branch?

> * There doesn't seem to be any sorting of the user list. They
> should be sorted alphabetical by first name.

Fixed.

> * There are six signals defined in the Class structure but only 4
> created on class init.

TODO.

> * I don't think that you need a call to
> dbus_g_object_type_install_info, that should only be needed if
> this object is being shared over DBus (server) but I think it's
> only a client.

Fixed.

> * Confirm with Robert, but I'm pretty sure the excludes list is
> already being applied on the GDM side. We shouldn't need to
> apply it on this side as well. That way there's only one copy
> of the list.

Confirmed with Robert, and fixed.

> * I think that dbus_g_connection_register_g_object can be dropped
> as well. Which I think is the only reason you're using the
> session bus, so I think that can be dropped.

Fixed.

> * Oh, now realizing more of the issue. Makefile.am shouldn't even
> be generating user-service-server.h. Drop that file.

Fixed.

> * I don't think that dbus_proxy_system and dbus_proxy_session are
> needed as we're not asking DBus itself for any information.
> We're just using it to communicate. We'd only need those
> proxies to query information about the bus itself.

Fixed.

> * Can session_compare be replaced with g_strcmp0? It seems about
> the same.

Fixed.

> * I was looking at "CanActivateSessions" call to ConsoleKit. Do
> you think we should check this earlier and make the menu items
> sensitive or insensitive based on this?

See previous comment.

> * It looks like you're always getting the information on all the
> users. I think that we really don't care if it's over our max,
> so can we just not bother getting all that data if we're in
> overflow?

Fixed.

> * The guest user needs to be handled as well. If there is a guest
> already logged in selecting the guest on the menu shouldn't
> start a new session, but should go to the guest that is already
> running.

TODO.

Revision history for this message
Ted Gould (ted) wrote :

On Thu, 2009-09-24 at 06:31 +0000, Cody Russell wrote:
> > * There should be icons on the users if they are set (probably
> > should go in another branch/bug)
>
> TODO. Can we do this in a separate branch?

Yeah, sounds good.

> > * The guest user needs to be handled as well. If there is a guest
> > already logged in selecting the guest on the menu shouldn't
> > start a new session, but should go to the guest that is already
> > running.
>
> TODO.

Let's put this in a new branch as well. We screwed this up in Jaunty,
so it's not a regression :)

43. By Cody Russell

don't need to dbus_g_object_type_install_info()

44. By Cody Russell

remove unnecessary stuff

45. By Cody Russell

remove session proxy fu

46. By Cody Russell

remove the server code

47. By Cody Russell

remove system proxy

48. By Cody Russell

use g_strcmp0

49. By Cody Russell

expose users_service_dbus_can_activate_session()

50. By Cody Russell

don't load all the users unless needed

51. By Cody Russell

cleanup

52. By Cody Russell

sort users

Revision history for this message
Ted Gould (ted) wrote :

On Thu, 2009-09-24 at 04:37 +0000, Cody Russell wrote:
> > * I was looking at "CanActivateSessions" call to ConsoleKit. Do
> > you think we should check this earlier and make the menu items
> > sensitive or insensitive based on this?
>
> Should the menuitems even be there if you can never click them? I
> went ahead and made an API on UsersServiceDbus that can check if
> the seat can activate sessions, and we can either make the menuitems
> insensitive or not add them or whatever. For now I didn't change the
> menu, just added the API.

My thought is let's just hide them. The reason being that then sys
admins can use this as a lockdown mode. We have a bug on this from OEM
as well. But we need to hide all the switching items.

CC'ing MPT as well to get his comments.

Revision history for this message
Matthew Paul Thomas (mpt) wrote :

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Ted Gould wrote on 24/09/09 14:59:
> On Thu, 2009-09-24 at 04:37 +0000, Cody Russell wrote:
>...
>> Should the menuitems even be there if you can never click them? I
>> went ahead and made an API on UsersServiceDbus that can check if
>> the seat can activate sessions, and we can either make the menuitems
>> insensitive or not add them or whatever. For now I didn't change the
>> menu, just added the API.
>
> My thought is let's just hide them. The reason being that then sys
> admins can use this as a lockdown mode. We have a bug on this from OEM
> as well. But we need to hide all the switching items.
>
> CC'ing MPT as well to get his comments.

What menu items are you talking about?

- --
Matthew Paul Thomas
http://mpt.net.nz/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkq7fPAACgkQ6PUxNfU6ecrSFACfT4ei1ceDUHLVHTXLZL3RRG47
tKoAoIUnp8iDhrj2GuDM8fMgH+5+dm4q
=9HY0
-----END PGP SIGNATURE-----

Revision history for this message
Ted Gould (ted) wrote :

On Thu, 2009-09-24 at 14:09 +0000, Matthew Paul Thomas wrote:
> Ted Gould wrote on 24/09/09 14:59:
> > On Thu, 2009-09-24 at 04:37 +0000, Cody Russell wrote:
> >...
> >> Should the menuitems even be there if you can never click them? I
> >> went ahead and made an API on UsersServiceDbus that can check if
> >> the seat can activate sessions, and we can either make the menuitems
> >> insensitive or not add them or whatever. For now I didn't change the
> >> menu, just added the API.
> >
> > My thought is let's just hide them. The reason being that then sys
> > admins can use this as a lockdown mode. We have a bug on this from OEM
> > as well. But we need to hide all the switching items.
> >
> > CC'ing MPT as well to get his comments.
>
> What menu items are you talking about?

Basically every menu item involved with user switching. The command
that we have to console kit is whether we can do VT switching. So we'd
be disabling Guess Session, Switching to any user, or starting a new
session without logging out.

Revision history for this message
Cody Russell (bratsche) wrote :

> > * There are six signals defined in the Class structure but only 4
> > created on class init.
>
> TODO.

I think these other two must have been left over from something, because they're not in the .xml file. So I'm removing them and committing.

53. By Cody Russell

Remove user_changed and users_icons_changed from the class

54. By Cody Russell

only add menuitems if the current seat can activate new sessions

Revision history for this message
Cody Russell (bratsche) wrote :

> My thought is let's just hide them. The reason being that then sys
> admins can use this as a lockdown mode. We have a bug on this from OEM
> as well. But we need to hide all the switching items.
>
> CC'ing MPT as well to get his comments.

Okay, I've gone ahead and committed/pushed a revision that will only add the menuitems if the user has the ability to activate new sessions. If it turns out MPT doesn't like this, it'll be easy enough to change.

55. By Cody Russell

Don't check range twice here

Revision history for this message
Ted Gould (ted) wrote :

Looks good!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'AUTHORS'
--- AUTHORS 2008-12-05 03:13:41 +0000
+++ AUTHORS 2009-09-24 16:28:09 +0000
@@ -0,0 +1,2 @@
1Ted Gould <ted@canonical.com>
2Cody Russell <crussell@canonical.com>
03
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2009-09-02 14:17:44 +0000
+++ src/Makefile.am 2009-09-24 16:28:09 +0000
@@ -11,7 +11,8 @@
11libsession_la_SOURCES = \11libsession_la_SOURCES = \
12 indicator-session.c \12 indicator-session.c \
13 dbus-shared-names.h \13 dbus-shared-names.h \
14 status-service-client.h14 status-service-client.h \
15 users-service-client.h
15libsession_la_CFLAGS = $(APPLET_CFLAGS) -Wall -Werror16libsession_la_CFLAGS = $(APPLET_CFLAGS) -Wall -Werror
16libsession_la_LIBADD = $(APPLET_LIBS)17libsession_la_LIBADD = $(APPLET_LIBS)
17libsession_la_LDFLAGS = -module -avoid-version18libsession_la_LDFLAGS = -module -avoid-version
@@ -25,6 +26,10 @@
25 status-service-dbus.h \26 status-service-dbus.h \
26 status-service-dbus.c \27 status-service-dbus.c \
27 status-service-server.h \28 status-service-server.h \
29 users-service-dbus.h \
30 users-service-dbus.c \
31 users-service-marshal.c \
32 users-service-marshal.h \
28 status-provider.h \33 status-provider.h \
29 status-provider.c \34 status-provider.c \
30 status-provider-pidgin.h \35 status-provider-pidgin.h \
@@ -38,6 +43,13 @@
38indicator_status_service_CFLAGS = $(STATUSSERVICE_CFLAGS) -Wall -Werror43indicator_status_service_CFLAGS = $(STATUSSERVICE_CFLAGS) -Wall -Werror
39indicator_status_service_LDADD = $(STATUSSERVICE_LIBS)44indicator_status_service_LDADD = $(STATUSSERVICE_LIBS)
4045
46users-service-client.h: $(srcdir)/users-service.xml
47 dbus-binding-tool \
48 --prefix=_users_service_client \
49 --mode=glib-client \
50 --output=users-service-client.h \
51 $(srcdir)/users-service.xml
52
41status-service-client.h: $(srcdir)/status-service.xml53status-service-client.h: $(srcdir)/status-service.xml
42 dbus-binding-tool \54 dbus-binding-tool \
43 --prefix=_status_service_client \55 --prefix=_status_service_client \
@@ -52,6 +64,16 @@
52 --output=status-service-server.h \64 --output=status-service-server.h \
53 $(srcdir)/status-service.xml65 $(srcdir)/status-service.xml
5466
67users-service-marshal.h: $(srcdir)/users-service.list
68 glib-genmarshal --header \
69 --prefix=_users_service_marshal $(srcdir)/users-service.list \
70 > users-service-marshal.h
71
72users-service-marshal.c: $(srcdir)/users-service.list
73 glib-genmarshal --body \
74 --prefix=_users_service_marshal $(srcdir)/users-service.list \
75 > users-service-marshal.c
76
55status-provider-pidgin-marshal.h: $(srcdir)/status-provider-pidgin.list77status-provider-pidgin-marshal.h: $(srcdir)/status-provider-pidgin.list
56 glib-genmarshal --header \78 glib-genmarshal --header \
57 --prefix=_status_provider_pidgin_marshal $(srcdir)/status-provider-pidgin.list \79 --prefix=_status_provider_pidgin_marshal $(srcdir)/status-provider-pidgin.list \
@@ -76,7 +98,7 @@
76# Users Stuff98# Users Stuff
77###############99###############
78100
79indicator_users_service_SOURCES = users-service.c101indicator_users_service_SOURCES = users-service.c users-service-dbus.c users-service-marshal.c
80indicator_users_service_CFLAGS = $(USERSSERVICE_CFLAGS) -Wall -Werror102indicator_users_service_CFLAGS = $(USERSSERVICE_CFLAGS) -Wall -Werror
81indicator_users_service_LDADD = $(USERSSERVICE_LIBS)103indicator_users_service_LDADD = $(USERSSERVICE_LIBS)
82104
@@ -93,8 +115,11 @@
93###############115###############
94116
95BUILT_SOURCES = \117BUILT_SOURCES = \
118 users-service-client.h \
96 status-service-client.h \119 status-service-client.h \
97 status-service-server.h \120 status-service-server.h \
121 users-service-marshal.h \
122 users-service-marshal.c \
98 status-provider-pidgin-marshal.h \123 status-provider-pidgin-marshal.h \
99 status-provider-pidgin-marshal.c \124 status-provider-pidgin-marshal.c \
100 status-provider-telepathy-marshal.h \125 status-provider-telepathy-marshal.h \
101126
=== modified file 'src/dbus-shared-names.h'
--- src/dbus-shared-names.h 2009-08-08 20:37:04 +0000
+++ src/dbus-shared-names.h 2009-09-24 16:28:09 +0000
@@ -7,16 +7,16 @@
7Authors:7Authors:
8 Ted Gould <ted@canonical.com>8 Ted Gould <ted@canonical.com>
99
10This program is free software: you can redistribute it and/or modify it 10This program is free software: you can redistribute it and/or modify it
11under the terms of the GNU General Public License version 3, as published 11under the terms of the GNU General Public License version 3, as published
12by the Free Software Foundation.12by the Free Software Foundation.
1313
14This program is distributed in the hope that it will be useful, but 14This program is distributed in the hope that it will be useful, but
15WITHOUT ANY WARRANTY; without even the implied warranties of 15WITHOUT ANY WARRANTY; without even the implied warranties of
16MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR 16MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
17PURPOSE. See the GNU General Public License for more details.17PURPOSE. See the GNU General Public License for more details.
1818
19You should have received a copy of the GNU General Public License along 19You should have received a copy of the GNU General Public License along
20with this program. If not, see <http://www.gnu.org/licenses/>.20with this program. If not, see <http://www.gnu.org/licenses/>.
21*/21*/
2222
@@ -31,6 +31,8 @@
3131
32#define INDICATOR_USERS_DBUS_NAME "org.ayatana.indicator.users"32#define INDICATOR_USERS_DBUS_NAME "org.ayatana.indicator.users"
33#define INDICATOR_USERS_DBUS_OBJECT "/org/ayatana/indicator/users/menu"33#define INDICATOR_USERS_DBUS_OBJECT "/org/ayatana/indicator/users/menu"
34#define INDICATOR_USERS_SERVICE_DBUS_OBJECT "/org/gnome/DisplayManager/UserManager"
35#define INDICATOR_USERS_SERVICE_DBUS_INTERFACE "org.gnome.DisplayManager.UserManager"
3436
35#define INDICATOR_SESSION_DBUS_NAME "org.ayatana.indicator.session"37#define INDICATOR_SESSION_DBUS_NAME "org.ayatana.indicator.session"
36#define INDICATOR_SESSION_DBUS_OBJECT "/org/ayatana/indicator/session/menu"38#define INDICATOR_SESSION_DBUS_OBJECT "/org/ayatana/indicator/session/menu"
3739
=== modified file 'src/status-service.c'
--- src/status-service.c 2009-09-16 21:00:17 +0000
+++ src/status-service.c 2009-09-24 16:28:09 +0000
@@ -7,16 +7,16 @@
7Authors:7Authors:
8 Ted Gould <ted@canonical.com>8 Ted Gould <ted@canonical.com>
99
10This program is free software: you can redistribute it and/or modify it 10This program is free software: you can redistribute it and/or modify it
11under the terms of the GNU General Public License version 3, as published 11under the terms of the GNU General Public License version 3, as published
12by the Free Software Foundation.12by the Free Software Foundation.
1313
14This program is distributed in the hope that it will be useful, but 14This program is distributed in the hope that it will be useful, but
15WITHOUT ANY WARRANTY; without even the implied warranties of 15WITHOUT ANY WARRANTY; without even the implied warranties of
16MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR 16MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
17PURPOSE. See the GNU General Public License for more details.17PURPOSE. See the GNU General Public License for more details.
1818
19You should have received a copy of the GNU General Public License along 19You should have received a copy of the GNU General Public License along
20with this program. If not, see <http://www.gnu.org/licenses/>.20with this program. If not, see <http://www.gnu.org/licenses/>.
21*/21*/
2222
@@ -238,12 +238,12 @@
238 if (!org_freedesktop_DBus_request_name(bus_proxy, INDICATOR_STATUS_DBUS_NAME, 0, &nameret, &error)) {238 if (!org_freedesktop_DBus_request_name(bus_proxy, INDICATOR_STATUS_DBUS_NAME, 0, &nameret, &error)) {
239 g_error("Unable to call to request name");239 g_error("Unable to call to request name");
240 return 1;240 return 1;
241 } 241 }
242242
243 if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {243 if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
244 g_error("Unable to get name");244 g_error("Unable to get name");
245 return 1;245 return 1;
246 } 246 }
247247
248 g_idle_add(build_providers, NULL);248 g_idle_add(build_providers, NULL);
249249
250250
=== added file 'src/users-service-dbus.c'
--- src/users-service-dbus.c 1970-01-01 00:00:00 +0000
+++ src/users-service-dbus.c 2009-09-24 16:28:09 +0000
@@ -0,0 +1,1147 @@
1/*
2 * Copyright 2009 Canonical Ltd.
3 *
4 * Authors:
5 * Cody Russell <crussell@canonical.com>
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 3, as published
9 * by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranties of
13 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
24#include <string.h>
25#include <errno.h>
26#include <pwd.h>
27
28#include <dbus/dbus-glib.h>
29#include <dbus/dbus-glib.h>
30#include <dbus/dbus-glib-lowlevel.h>
31
32#include "dbus-shared-names.h"
33#include "users-service-dbus.h"
34#include "users-service-client.h"
35#include "users-service-marshal.h"
36
37static void users_service_dbus_class_init (UsersServiceDbusClass *klass);
38static void users_service_dbus_init (UsersServiceDbus *self);
39static void users_service_dbus_dispose (GObject *object);
40static void users_service_dbus_finalize (GObject *object);
41static void create_gdm_proxy (UsersServiceDbus *self);
42static void create_seat_proxy (UsersServiceDbus *self);
43static void create_ck_proxy (UsersServiceDbus *self);
44static void create_cksession_proxy (UsersServiceDbus *self);
45static gchar *get_seat (UsersServiceDbus *service);
46static void users_loaded (DBusGProxy *proxy,
47 gpointer user_data);
48static void user_added (DBusGProxy *proxy,
49 guint uid,
50 gpointer user_data);
51static void user_removed (DBusGProxy *proxy,
52 guint uid,
53 gpointer user_data);
54static void user_updated (DBusGProxy *proxy,
55 guint uid,
56 gpointer user_data);
57static void seat_proxy_session_added (DBusGProxy *seat_proxy,
58 const gchar *session_id,
59 UsersServiceDbus *service);
60static void seat_proxy_session_removed (DBusGProxy *seat_proxy,
61 const gchar *session_id,
62 UsersServiceDbus *service);
63static gboolean do_add_session (UsersServiceDbus *service,
64 UserData *user,
65 const gchar *ssid);
66static gchar * get_seat_internal (UsersServiceDbus *self);
67
68/* Private */
69typedef struct _UsersServiceDbusPrivate UsersServiceDbusPrivate;
70
71struct _UsersServiceDbusPrivate
72{
73 GHashTable *users;
74 gint count;
75 gchar *seat;
76 gchar *ssid;
77
78 DBusGConnection *system_bus;
79
80 DBusGProxy *gdm_proxy;
81 DBusGProxy *ck_proxy;
82 DBusGProxy *seat_proxy;
83 DBusGProxy *session_proxy;
84
85 GHashTable *exclusions;
86 GHashTable *sessions;
87};
88
89#define USERS_SERVICE_DBUS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), USERS_SERVICE_DBUS_TYPE, UsersServiceDbusPrivate))
90
91/* Signals */
92enum {
93 USERS_LOADED,
94 USER_ADDED,
95 USER_REMOVED,
96 USER_UPDATED,
97 LAST_SIGNAL
98};
99
100static guint signals[LAST_SIGNAL] = { 0 };
101
102/* GObject Boilerplate */
103G_DEFINE_TYPE (UsersServiceDbus, users_service_dbus, G_TYPE_OBJECT);
104
105static void
106users_service_dbus_class_init (UsersServiceDbusClass *klass)
107{
108 GObjectClass *object_class = G_OBJECT_CLASS (klass);
109
110 g_type_class_add_private (object_class, sizeof (UsersServiceDbusPrivate));
111
112 object_class->dispose = users_service_dbus_dispose;
113 object_class->finalize = users_service_dbus_finalize;
114
115 signals[USERS_LOADED] = g_signal_new ("users-loaded",
116 G_TYPE_FROM_CLASS (klass),
117 G_SIGNAL_RUN_LAST,
118 G_STRUCT_OFFSET (UsersServiceDbusClass, users_loaded),
119 NULL, NULL,
120 g_cclosure_marshal_VOID__VOID,
121 G_TYPE_NONE, 0);
122
123 signals[USER_ADDED] = g_signal_new ("user-added",
124 G_TYPE_FROM_CLASS (klass),
125 G_SIGNAL_RUN_LAST,
126 G_STRUCT_OFFSET (UsersServiceDbusClass, user_added),
127 NULL, NULL,
128 _users_service_marshal_VOID__INT64,
129 G_TYPE_NONE, 1, G_TYPE_INT64);
130
131 signals[USER_REMOVED] = g_signal_new ("user-removed",
132 G_TYPE_FROM_CLASS (klass),
133 G_SIGNAL_RUN_LAST,
134 G_STRUCT_OFFSET (UsersServiceDbusClass, user_removed),
135 NULL, NULL,
136 _users_service_marshal_VOID__INT64,
137 G_TYPE_NONE, 1, G_TYPE_INT64);
138
139 signals[USER_UPDATED] = g_signal_new ("user-updated",
140 G_TYPE_FROM_CLASS (klass),
141 G_SIGNAL_RUN_LAST,
142 G_STRUCT_OFFSET (UsersServiceDbusClass, user_updated),
143 NULL, NULL,
144 _users_service_marshal_VOID__INT64,
145 G_TYPE_NONE, 1, G_TYPE_INT64);
146}
147
148static void
149users_service_dbus_init (UsersServiceDbus *self)
150{
151 GError *error = NULL;
152 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
153
154 priv->users = NULL;
155 priv->count = 0;
156
157 /* Get the system bus */
158 priv->system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
159 if (error != NULL)
160 {
161 g_error ("Unable to get system bus: %s", error->message);
162 g_error_free(error);
163
164 return;
165 }
166
167 priv->sessions = g_hash_table_new_full (g_str_hash,
168 g_str_equal,
169 g_free,
170 g_free);
171
172 priv->users = g_hash_table_new_full (g_str_hash,
173 g_str_equal,
174 g_free,
175 NULL);
176
177 dbus_g_object_register_marshaller (_users_service_marshal_VOID__INT64,
178 G_TYPE_NONE,
179 G_TYPE_INT64,
180 G_TYPE_INVALID);
181
182 create_gdm_proxy (self);
183 create_ck_proxy (self);
184 create_seat_proxy (self);
185
186 users_loaded (priv->gdm_proxy, self);
187}
188
189static void
190users_service_dbus_dispose (GObject *object)
191{
192 G_OBJECT_CLASS (users_service_dbus_parent_class)->dispose (object);
193}
194
195static void
196users_service_dbus_finalize (GObject *object)
197{
198 G_OBJECT_CLASS (users_service_dbus_parent_class)->finalize (object);
199}
200
201static void
202create_gdm_proxy (UsersServiceDbus *self)
203{
204 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
205 GError *error = NULL;
206
207 priv->gdm_proxy = dbus_g_proxy_new_for_name_owner (priv->system_bus,
208 "org.gnome.DisplayManager",
209 "/org/gnome/DisplayManager/UserManager",
210 "org.gnome.DisplayManager.UserManager",
211 &error);
212
213 if (!priv->gdm_proxy)
214 {
215 if (error != NULL)
216 {
217 g_error ("Unable to get DisplayManager proxy on system bus: %s", error->message);
218 g_error_free (error);
219 }
220
221 return;
222 }
223
224 dbus_g_proxy_add_signal (priv->gdm_proxy,
225 "UsersLoaded",
226 G_TYPE_INVALID);
227
228 dbus_g_proxy_add_signal (priv->gdm_proxy,
229 "UserAdded",
230 G_TYPE_INT64,
231 G_TYPE_INVALID);
232
233 dbus_g_proxy_add_signal (priv->gdm_proxy,
234 "UserRemoved",
235 G_TYPE_INT64,
236 G_TYPE_INVALID);
237
238 dbus_g_proxy_add_signal (priv->gdm_proxy,
239 "UserUpdated",
240 G_TYPE_INT64,
241 G_TYPE_INVALID);
242
243 dbus_g_proxy_connect_signal (priv->gdm_proxy,
244 "UsersLoaded",
245 G_CALLBACK (users_loaded),
246 self,
247 NULL);
248
249 dbus_g_proxy_connect_signal (priv->gdm_proxy,
250 "UserAdded",
251 G_CALLBACK (user_added),
252 self,
253 NULL);
254
255 dbus_g_proxy_connect_signal (priv->gdm_proxy,
256 "UserRemoved",
257 G_CALLBACK (user_removed),
258 self,
259 NULL);
260
261 dbus_g_proxy_connect_signal (priv->gdm_proxy,
262 "UserUpdated",
263 G_CALLBACK (user_updated),
264 self,
265 NULL);
266}
267
268static void
269create_ck_proxy (UsersServiceDbus *self)
270{
271 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
272
273 priv->ck_proxy = dbus_g_proxy_new_for_name (priv->system_bus,
274 "org.freedesktop.ConsoleKit",
275 "/org/freedesktop/ConsoleKit/Manager",
276 "org.freedesktop.ConsoleKit.Manager");
277
278 if (!priv->ck_proxy)
279 {
280 g_warning ("Failed to get ConsoleKit proxy.");
281 return;
282 }
283}
284
285static void
286create_seat_proxy (UsersServiceDbus *self)
287{
288 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
289 GError *error = NULL;
290
291 priv->seat = get_seat (self);
292 if (priv->seat == NULL)
293 {
294 return;
295 }
296
297 priv->seat_proxy = dbus_g_proxy_new_for_name_owner (priv->system_bus,
298 "org.freedesktop.ConsoleKit",
299 priv->seat,
300 "org.freedesktop.ConsoleKit.Seat",
301 &error);
302
303 if (!priv->seat_proxy)
304 {
305 if (error != NULL)
306 {
307 g_warning ("Failed to connect to the ConsoleKit seat: %s", error->message);
308 g_error_free (error);
309 }
310
311 return;
312 }
313
314 dbus_g_proxy_add_signal (priv->seat_proxy,
315 "SessionAdded",
316 DBUS_TYPE_G_OBJECT_PATH,
317 G_TYPE_INVALID);
318 dbus_g_proxy_add_signal (priv->seat_proxy,
319 "SessionRemoved",
320 DBUS_TYPE_G_OBJECT_PATH,
321 G_TYPE_INVALID);
322
323 dbus_g_proxy_connect_signal (priv->seat_proxy,
324 "SessionAdded",
325 G_CALLBACK (seat_proxy_session_added),
326 self,
327 NULL);
328 dbus_g_proxy_connect_signal (priv->seat_proxy,
329 "SessionRemoved",
330 G_CALLBACK (seat_proxy_session_removed),
331 self,
332 NULL);
333}
334
335static void
336create_cksession_proxy (UsersServiceDbus *service)
337{
338 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service);
339
340 priv->session_proxy = dbus_g_proxy_new_for_name (priv->system_bus,
341 "org.freedesktop.ConsoleKit",
342 priv->ssid,
343 "org.freedesktop.ConsoleKit.Session");
344
345 if (!priv->session_proxy)
346 {
347 g_warning ("Failed to get ConsoleKit session proxy");
348 return;
349 }
350}
351
352static gchar *
353get_seat (UsersServiceDbus *service)
354{
355 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service);
356 GError *error = NULL;
357 gchar *ssid = NULL;
358 gchar *seat;
359
360 if (!dbus_g_proxy_call (priv->ck_proxy,
361 "GetCurrentSession",
362 &error,
363 G_TYPE_INVALID,
364 DBUS_TYPE_G_OBJECT_PATH,
365 &ssid,
366 G_TYPE_INVALID))
367 {
368 if (error)
369 {
370 g_debug ("Failed to call GetCurrentSession: %s", error->message);
371 g_error_free (error);
372 }
373
374 if (ssid)
375 g_free (ssid);
376
377 return NULL;
378 }
379
380 priv->ssid = ssid;
381 create_cksession_proxy (service);
382
383 seat = get_seat_internal (service);
384
385 return seat;
386}
387
388static gchar *
389get_seat_internal (UsersServiceDbus *self)
390{
391 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
392 GError *error = NULL;
393 gchar *seat = NULL;
394
395 if (!dbus_g_proxy_call (priv->session_proxy,
396 "GetSeatId",
397 &error,
398 G_TYPE_INVALID,
399 DBUS_TYPE_G_OBJECT_PATH, &seat,
400 G_TYPE_INVALID))
401 {
402 if (error)
403 {
404 g_debug ("Failed to call GetSeatId: %s", error->message);
405
406 return NULL;
407 }
408 }
409
410 return seat;
411}
412
413static gboolean
414get_unix_user (UsersServiceDbus *service,
415 const gchar *session_id,
416 uid_t *uidp)
417{
418 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service);
419 GError *error = NULL;
420 guint uid;
421
422 if (dbus_g_proxy_call (priv->session_proxy,
423 "GetUnixUser",
424 &error,
425 G_TYPE_INVALID,
426 G_TYPE_UINT, &uid,
427 G_TYPE_INVALID))
428 {
429 if (error)
430 {
431 g_warning ("Failed to call GetUnixUser: %s", error->message);
432 g_error_free (error);
433 }
434
435 return FALSE;
436 }
437
438 if (uidp != NULL)
439 {
440 *uidp = (uid_t)uid;
441 }
442
443 return TRUE;
444}
445
446static gchar *
447get_session_for_user (UsersServiceDbus *service,
448 UserData *user)
449{
450 GList *l;
451
452 if (!users_service_dbus_can_activate_session (service))
453 {
454 return NULL;
455 }
456
457 if (!user->sessions || g_list_length (user->sessions) == 0)
458 {
459 return NULL;
460 }
461
462 for (l = user->sessions; l != NULL; l = l->next)
463 {
464 const char *ssid;
465
466 ssid = l->data;
467
468 if (ssid)
469 {
470 return g_strdup (ssid);
471 }
472 }
473
474 return NULL;
475}
476
477static gboolean
478do_add_session (UsersServiceDbus *service,
479 UserData *user,
480 const gchar *ssid)
481{
482 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service);
483 GError *error = NULL;
484 gchar *seat = NULL;
485 gchar *xdisplay = NULL;
486 GList *l;
487
488 seat = get_seat_internal (service);
489
490 if (!seat || !priv->seat || strcmp (seat, priv->seat) != 0)
491 return FALSE;
492
493 if (!dbus_g_proxy_call (priv->session_proxy,
494 "GetX11Display",
495 &error,
496 G_TYPE_INVALID,
497 G_TYPE_STRING, &xdisplay,
498 G_TYPE_INVALID))
499 {
500 if (error)
501 {
502 g_debug ("Failed to call GetX11Display: %s", error->message);
503 g_error_free (error);
504 }
505
506 return FALSE;
507 }
508
509 if (!xdisplay || xdisplay[0] == '\0')
510 return FALSE;
511
512 g_hash_table_insert (priv->sessions,
513 g_strdup (ssid),
514 g_strdup (user->user_name));
515
516 l = g_list_find_custom (user->sessions, ssid, (GCompareFunc)g_strcmp0);
517 if (l == NULL)
518 {
519 g_debug ("Adding session %s", ssid);
520
521 user->sessions = g_list_prepend (user->sessions, g_strdup (ssid));
522 }
523 else
524 {
525 g_debug ("User %s already has session %s", user->user_name, ssid);
526 }
527
528 return TRUE;
529}
530
531static void
532add_sessions_for_user (UsersServiceDbus *self,
533 UserData *user)
534{
535 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
536 GError *error;
537 GPtrArray *sessions;
538 int i;
539
540 error = NULL;
541 if (!dbus_g_proxy_call (priv->ck_proxy,
542 "GetSessionsForUnixUser",
543 &error,
544 G_TYPE_UINT, user->uid,
545 G_TYPE_INVALID,
546 dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
547 &sessions,
548 G_TYPE_INVALID))
549 {
550 g_debug ("Failed to call GetSessionsForUnixUser: %s", error->message);
551 g_error_free (error);
552
553 return;
554 }
555
556 for (i = 0; i < sessions->len; i++)
557 {
558 char *ssid;
559
560 ssid = g_ptr_array_index (sessions, i);
561 do_add_session (self, user, ssid);
562 }
563
564 g_ptr_array_foreach (sessions, (GFunc)g_free, NULL);
565 g_ptr_array_free (sessions, TRUE);
566}
567
568
569static void
570seat_proxy_session_added (DBusGProxy *seat_proxy,
571 const gchar *session_id,
572 UsersServiceDbus *service)
573{
574 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service);
575 uid_t uid;
576 gboolean res;
577 struct passwd *pwent;
578 UserData *user;
579
580 if (!get_unix_user (service, session_id, &uid))
581 {
582 g_warning ("Failed to lookup user for session");
583 return;
584 }
585
586 errno = 0;
587 pwent = getpwuid (uid);
588 if (!pwent)
589 {
590 g_warning ("Failed to lookup user id %d: %s", (int)uid, g_strerror (errno));
591 return;
592 }
593
594 user = g_hash_table_lookup (priv->users, pwent->pw_name);
595 if (!user)
596 {
597 return;
598 }
599
600 res = do_add_session (service, user, session_id);
601}
602
603static void
604seat_proxy_session_removed (DBusGProxy *seat_proxy,
605 const gchar *session_id,
606 UsersServiceDbus *service)
607{
608 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service);
609 UserData *user;
610 gchar *username;
611 GList *l;
612
613 username = g_hash_table_lookup (priv->sessions, session_id);
614 if (!username)
615 return;
616
617 user = g_hash_table_lookup (priv->users, username);
618 if (!user)
619 return;
620
621 l = g_list_find_custom (user->sessions,
622 session_id,
623 (GCompareFunc)g_strcmp0);
624 if (l)
625 {
626 g_debug ("Removing session %s", session_id);
627
628 g_free (l->data);
629 user->sessions = g_list_delete_link (user->sessions, l);
630 }
631 else
632 {
633 g_debug ("Session not found: %s", session_id);
634 }
635}
636
637static void
638sync_users (UsersServiceDbus *self)
639{
640 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
641
642 if (g_hash_table_size (priv->users) > 0)
643 {
644 return;
645 }
646
647 if (priv->count > MINIMUM_USERS && priv->count < MAXIMUM_USERS)
648 {
649 GArray *uids = NULL;
650 GPtrArray *users_info = NULL;
651 GError *error = NULL;
652 gint i;
653
654 uids = g_array_new (FALSE, FALSE, sizeof (gint64));
655
656 if (!org_gnome_DisplayManager_UserManager_get_user_list (priv->gdm_proxy,
657 &uids,
658 &error))
659 {
660 g_warning ("failed to retrieve user list: %s", error->message);
661 g_error_free (error);
662
663 return;
664 }
665
666 users_info = g_ptr_array_new ();
667
668 if (!org_gnome_DisplayManager_UserManager_get_users_info (priv->gdm_proxy,
669 uids,
670 &users_info,
671 &error))
672 {
673 g_warning ("failed to retrieve user info: %s", error->message);
674 g_error_free (error);
675
676 return;
677 }
678
679 for (i = 0; i < users_info->len; i++)
680 {
681 GValueArray *values;
682 UserData *user;
683
684 values = g_ptr_array_index (users_info, i);
685
686 user = g_new0 (UserData, 1);
687
688 user->uid = g_value_get_int64 (g_value_array_get_nth (values, 0));
689 user->user_name = g_strdup (g_value_get_string (g_value_array_get_nth (values, 1)));
690 user->real_name = g_strdup (g_value_get_string (g_value_array_get_nth (values, 2)));
691 user->shell = g_strdup (g_value_get_string (g_value_array_get_nth (values, 3)));
692 user->login_count = g_value_get_int (g_value_array_get_nth (values, 4));
693 user->icon_url = g_strdup (g_value_get_string (g_value_array_get_nth (values, 5)));
694
695 g_hash_table_insert (priv->users,
696 g_strdup (user->user_name),
697 user);
698
699 add_sessions_for_user (self, user);
700 }
701 }
702}
703
704static void
705users_loaded (DBusGProxy *proxy,
706 gpointer user_data)
707{
708 UsersServiceDbus *service;
709 UsersServiceDbusPrivate *priv;
710 GError *error = NULL;
711 gint count;
712
713 service = (UsersServiceDbus *)user_data;
714 priv = USERS_SERVICE_DBUS_GET_PRIVATE (service);
715
716 if (!org_gnome_DisplayManager_UserManager_count_users (proxy,
717 &count,
718 &error))
719 {
720 g_warning ("failed to retrieve user count: %s", error->message);
721 g_error_free (error);
722
723 return;
724 }
725
726 priv->count = count;
727
728 sync_users (service);
729}
730
731static gboolean
732session_is_login_window (UsersServiceDbus *self,
733 const char *ssid)
734{
735 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
736 DBusGProxy *proxy = NULL;
737 GError *error = NULL;
738 char *type = NULL;
739
740 if (!(proxy = dbus_g_proxy_new_for_name (priv->system_bus,
741 "org.freedesktop.ConsoleKit",
742 ssid,
743 "org.freedesktop.ConsoleKit.Session")))
744 {
745 g_warning ("Failed to get ConsoleKit proxy");
746
747 return FALSE;
748 }
749
750 if (!dbus_g_proxy_call (proxy,
751 "GetSessionType",
752 &error,
753 G_TYPE_INVALID,
754 G_TYPE_STRING, &type,
755 G_TYPE_INVALID))
756 {
757 g_warning ("Can't call GetSessionType: %s", error->message);
758 g_error_free (error);
759
760 if (proxy)
761 g_object_unref (proxy);
762
763 return FALSE;
764 }
765
766 if (proxy)
767 g_object_unref (proxy);
768
769 return (type && type[0] != '\0' && strcmp (type, "LoginWindow") == 0);
770}
771
772static char *
773get_login_session (UsersServiceDbus *self)
774{
775 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
776 gboolean can_activate;
777 GError *error = NULL;
778 GPtrArray *sessions = NULL;
779 char *ssid = NULL;
780 int i;
781
782 if (!priv->seat || priv->seat[0] == '\0')
783 {
784 return NULL;
785 }
786
787 if (!dbus_g_proxy_call (priv->seat_proxy,
788 "CanActivateSessions",
789 &error,
790 G_TYPE_INVALID,
791 G_TYPE_BOOLEAN, &can_activate,
792 G_TYPE_INVALID))
793 {
794 g_warning ("Failed to call CanActivateSessions: %s", error->message);
795 g_error_free (error);
796
797 return NULL;
798 }
799
800 if (!can_activate)
801 {
802 return NULL;
803 }
804
805 error = NULL;
806 if (!dbus_g_proxy_call (priv->seat_proxy,
807 "GetSessions",
808 &error,
809 G_TYPE_INVALID,
810 dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &sessions,
811 G_TYPE_INVALID))
812 {
813 g_warning ("Failed to call GetSessions: %s", error->message);
814 g_error_free (error);
815
816 return NULL;
817 }
818
819 for (i = 0; i < sessions->len; i++)
820 {
821 char *s = g_ptr_array_index (sessions, i);
822
823 if (session_is_login_window (self, s))
824 {
825 ssid = g_strdup (s);
826 break;
827 }
828 }
829
830 g_ptr_array_foreach (sessions, (GFunc)g_free, NULL);
831 g_ptr_array_free (sessions, TRUE);
832
833 return ssid;
834}
835
836static gboolean
837activate_user_session (UsersServiceDbus *self,
838 const char *seat,
839 const char *ssid)
840{
841 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
842 DBusMessage *message = NULL;
843 DBusMessage *reply = NULL;
844 DBusError error;
845
846 if (!(message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
847 seat,
848 "org.freedesktop.ConsoleKit.Seat",
849 "ActivateSession")))
850 {
851 return FALSE;
852 }
853
854 if (!dbus_message_append_args (message,
855 DBUS_TYPE_OBJECT_PATH, &ssid,
856 DBUS_TYPE_INVALID))
857 {
858 return FALSE;
859 }
860
861 dbus_error_init (&error);
862 if (!(reply = dbus_connection_send_with_reply_and_block (dbus_g_connection_get_connection (priv->system_bus),
863 message,
864 -1,
865 &error)))
866 {
867 if (dbus_error_is_set (&error))
868 {
869 g_warning ("Can't activate session: %s", error.message);
870 dbus_error_free (&error);
871
872 return FALSE;
873 }
874 }
875
876 if (message)
877 {
878 dbus_message_unref (message);
879 }
880
881 if (reply)
882 {
883 dbus_message_unref (reply);
884 }
885
886 return TRUE;
887}
888
889gboolean
890start_new_user_session (UsersServiceDbus *self,
891 UserData *user)
892{
893 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
894 GError *error = NULL;
895 char *ssid;
896
897 ssid = get_login_session (self);
898 if (ssid)
899 {
900 if (!activate_user_session (self, priv->seat, ssid))
901 {
902 return FALSE;
903 }
904 }
905
906 if (!g_spawn_command_line_async ("gdmflexiserver -s", &error))
907 {
908 g_warning ("Failed to start new login session: %s", error->message);
909 g_error_free (error);
910
911 return FALSE;
912 }
913
914 return TRUE;
915}
916
917static void
918user_added (DBusGProxy *proxy,
919 guint uid,
920 gpointer user_data)
921{
922 UsersServiceDbus *service = (UsersServiceDbus *)user_data;
923 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service);
924 UserData *user = g_new0 (UserData, 1);
925 GError *error = NULL;
926
927 priv->count++;
928
929 if (priv->count < MAXIMUM_USERS)
930 {
931 if ((priv->count - g_hash_table_size (priv->users)) > 1)
932 {
933 sync_users (service);
934 }
935 else
936 {
937 if (!org_gnome_DisplayManager_UserManager_get_user_info (proxy,
938 uid,
939 &user->user_name,
940 &user->real_name,
941 &user->shell,
942 &user->login_count,
943 &user->icon_url,
944 &error))
945 {
946 g_warning ("unable to retrieve user info: %s", error->message);
947 g_error_free (error);
948
949 g_free (user);
950
951 return;
952 }
953
954 user->uid = uid;
955
956 g_hash_table_insert (priv->users,
957 g_strdup (user->user_name),
958 user);
959
960 g_signal_emit (G_OBJECT (service), signals[USER_ADDED], 0, user, TRUE);
961 }
962 }
963}
964
965static gboolean
966compare_users_by_uid (gpointer key,
967 gpointer value,
968 gpointer user_data)
969{
970 return (GPOINTER_TO_UINT (value) == GPOINTER_TO_UINT (user_data));
971}
972
973static void
974user_removed (DBusGProxy *proxy,
975 guint uid,
976 gpointer user_data)
977{
978 UsersServiceDbus *service = (UsersServiceDbus *)user_data;
979 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service);
980 UserData *user;
981 gint size;
982
983 size = g_hash_table_size (priv->users);
984
985 priv->count--;
986
987 if (size == 0 || (size - priv->count) > 1)
988 {
989 sync_users (service);
990 }
991 else
992 {
993 user = g_hash_table_find (priv->users,
994 compare_users_by_uid,
995 GUINT_TO_POINTER (uid));
996
997 if (user != NULL)
998 {
999 g_hash_table_remove (priv->users,
1000 user->user_name);
1001 }
1002 }
1003}
1004
1005static void
1006user_updated (DBusGProxy *proxy,
1007 guint uid,
1008 gpointer user_data)
1009{
1010#if 0
1011 // XXX - TODO
1012 UsersServiceDbus *service = (UsersServiceDbus *)user_data;
1013 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service);
1014 UserData *user;
1015
1016 user = g_hash_table_find (priv->users,
1017 compare_users_by_uid,
1018 GUINT_TO_POINTER (uid));
1019#endif
1020}
1021
1022gint
1023users_service_dbus_get_user_count (UsersServiceDbus *self)
1024{
1025 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
1026
1027 return priv->count;
1028}
1029
1030GList *
1031users_service_dbus_get_user_list (UsersServiceDbus *self)
1032{
1033 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
1034
1035 return g_hash_table_get_values (priv->users);
1036}
1037
1038/*
1039 * XXX - TODO: Right now we switch to a session that another user
1040 * already has open, but if there are no open sessions
1041 * for this user we go to the login screen and the
1042 * user at the seat must select a user and enter a
1043 * password. This kind of defeats the purpose of
1044 * actually selecting a username, since selecting any
1045 * user will do the same thing here. We need to change
1046 * it so you only need to enter a password for the
1047 * specified user.
1048 */
1049gboolean
1050users_service_dbus_activate_user_session (UsersServiceDbus *self,
1051 UserData *user)
1052{
1053 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
1054 DBusMessage *message = NULL;
1055 DBusMessage *reply = NULL;
1056 DBusError error;
1057 gchar *ssid;
1058
1059 dbus_error_init (&error);
1060
1061 if (!priv->seat)
1062 priv->seat = get_seat (self);
1063
1064 ssid = get_session_for_user (self, user);
1065
1066 if (!ssid)
1067 {
1068 return start_new_user_session (self, user);
1069 }
1070
1071 if (!(message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
1072 priv->seat,
1073 "org.freedesktop.ConsoleKit.Seat",
1074 "ActivateSession")))
1075 {
1076 g_warning ("failed to create new message");
1077 return FALSE;
1078 }
1079
1080 if (!dbus_message_append_args (message,
1081 DBUS_TYPE_OBJECT_PATH,
1082 &ssid,
1083 DBUS_TYPE_INVALID))
1084 {
1085 g_warning ("failed to append args");
1086 return FALSE;
1087 }
1088
1089 if (!(reply = dbus_connection_send_with_reply_and_block (dbus_g_connection_get_connection (priv->system_bus),
1090 message,
1091 -1,
1092 &error)))
1093 {
1094 if (dbus_error_is_set (&error))
1095 {
1096 g_warning ("Failed to send message: %s", error.message);
1097 dbus_error_free (&error);
1098
1099 return FALSE;
1100 }
1101 }
1102
1103 if (message)
1104 {
1105 dbus_message_unref (message);
1106 }
1107
1108 if (reply)
1109 {
1110 dbus_message_unref (reply);
1111 }
1112
1113 return TRUE;
1114}
1115
1116gboolean
1117users_service_dbus_can_activate_session (UsersServiceDbus *self)
1118{
1119 UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self);
1120 gboolean can_activate = FALSE;
1121 GError *error = NULL;
1122
1123 if (!priv->seat_proxy)
1124 {
1125 create_seat_proxy (self);
1126 }
1127
1128 if (!priv->seat || priv->seat[0] == '\0')
1129 {
1130 return FALSE;
1131 }
1132
1133 if (!dbus_g_proxy_call (priv->seat_proxy,
1134 "CanActivateSessions",
1135 &error,
1136 G_TYPE_INVALID,
1137 G_TYPE_BOOLEAN, &can_activate,
1138 G_TYPE_INVALID))
1139 {
1140 g_warning ("Failed to determine if seat can activate sessions: %s", error->message);
1141 g_error_free (error);
1142
1143 return FALSE;
1144 }
1145
1146 return can_activate;
1147}
01148
=== added file 'src/users-service-dbus.h'
--- src/users-service-dbus.h 1970-01-01 00:00:00 +0000
+++ src/users-service-dbus.h 2009-09-24 16:28:09 +0000
@@ -0,0 +1,81 @@
1/*
2 * Copyright 2009 Canonical Ltd.
3 *
4 * Authors:
5 * Cody Russell <crussell@canonical.com>
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License version 3, as published
9 * by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranties of
13 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#ifndef __USERS_SERVICE_DBUS_H__
21#define __USERS_SERVICE_DBUS_H__
22
23#include <glib.h>
24#include <glib-object.h>
25
26G_BEGIN_DECLS
27
28#define USERS_SERVICE_DBUS_TYPE (users_service_dbus_get_type ())
29#define USERS_SERVICE_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), USERS_SERVICE_DBUS_TYPE, UsersServiceDbus))
30#define USERS_SERVICE_DBUS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), USERS_SERVICE_DBUS_TYPE, UsersServiceDbusClass))
31#define IS_USERS_SERVICE_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), USERS_SERVICE_DBUS_TYPE))
32#define IS_USERS_SERVICE_DBUS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), USERS_SERVICE_DBUS_TYPE))
33#define USERS_SERVICE_DBUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), USERS_SERVICE_DBUS_TYPE, UsersServiceDbusClass))
34
35typedef struct _UsersServiceDbus UsersServiceDbus;
36typedef struct _UsersServiceDbusClass UsersServiceDbusClass;
37typedef struct _UserData UserData;
38
39struct _UserData
40{
41 gint64 uid;
42 gchar *user_name;
43 gchar *real_name;
44 gchar *shell;
45 gint login_count;
46 gchar *icon_url;
47
48 GList *sessions;
49
50 UsersServiceDbus *service;
51};
52
53#define MINIMUM_USERS 1
54#define MAXIMUM_USERS 7
55
56struct _UsersServiceDbus {
57 GObject parent;
58};
59
60struct _UsersServiceDbusClass {
61 GObjectClass parent_class;
62
63 /* Signals */
64 void (* users_loaded) (UsersServiceDbus *self, gpointer user_data);
65
66 void (* user_added) (UsersServiceDbus *self, gint64 uid, gpointer user_data);
67 void (* user_removed) (UsersServiceDbus *self, gint64 uid, gpointer user_data);
68 void (* user_updated) (UsersServiceDbus *self, gint64 uid, gpointer user_data);
69};
70
71GType users_service_dbus_get_type (void) G_GNUC_CONST;
72
73gint users_service_dbus_get_user_count (UsersServiceDbus *self);
74GList *users_service_dbus_get_user_list (UsersServiceDbus *self);
75gboolean users_service_dbus_can_activate_session (UsersServiceDbus *self);
76gboolean users_service_dbus_activate_user_session (UsersServiceDbus *self,
77 UserData *user);
78
79G_END_DECLS
80
81#endif
082
=== modified file 'src/users-service.c'
--- src/users-service.c 2009-09-16 16:34:26 +0000
+++ src/users-service.c 2009-09-24 16:28:09 +0000
@@ -1,24 +1,25 @@
1/*1/*
2A small wrapper utility to load indicators and put them as menu items2 * A small wrapper utility to load indicators and put them as menu items
3into the gnome-panel using it's applet interface.3 * into the gnome-panel using it's applet interface.
44 *
5Copyright 2009 Canonical Ltd.5 * Copyright 2009 Canonical Ltd.
66 *
7Authors:7 * Authors:
8 Ted Gould <ted@canonical.com>8 * Ted Gould <ted@canonical.com>
99 * Cody Russell <crussell@canonical.com>
10This program is free software: you can redistribute it and/or modify it 10 *
11under the terms of the GNU General Public License version 3, as published 11 * This program is free software: you can redistribute it and/or modify it
12by the Free Software Foundation.12 * under the terms of the GNU General Public License version 3, as published
1313 * by the Free Software Foundation.
14This program is distributed in the hope that it will be useful, but 14 *
15WITHOUT ANY WARRANTY; without even the implied warranties of 15 * This program is distributed in the hope that it will be useful, but
16MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR 16 * WITHOUT ANY WARRANTY; without even the implied warranties of
17PURPOSE. See the GNU General Public License for more details.17 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1818 * PURPOSE. See the GNU General Public License for more details.
19You should have received a copy of the GNU General Public License along 19 *
20with this program. If not, see <http://www.gnu.org/licenses/>.20 * You should have received a copy of the GNU General Public License along
21*/21 *with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
2223
23#include <config.h>24#include <config.h>
2425
@@ -33,15 +34,27 @@
33#include <libdbusmenu-glib/menuitem.h>34#include <libdbusmenu-glib/menuitem.h>
3435
35#include "dbus-shared-names.h"36#include "dbus-shared-names.h"
37#include "users-service-dbus.h"
3638
37#define GUEST_SESSION_LAUNCHER "/usr/share/gdm/guest-session/guest-session-launch"39#define GUEST_SESSION_LAUNCHER "/usr/share/gdm/guest-session/guest-session-launch"
3840
39static DBusGConnection * session_bus = NULL;41typedef struct _ActivateData ActivateData;
40static DBusGConnection * system_bus = NULL;42struct _ActivateData
41static DBusGProxy * bus_proxy = NULL;43{
42static DBusGProxy * gdm_proxy = NULL;44 UsersServiceDbus *service;
43static DbusmenuMenuitem * root_menuitem = NULL;45 UserData *user;
44static GMainLoop * mainloop = NULL;46};
47
48static DBusGConnection *session_bus = NULL;
49static DBusGConnection *system_bus = NULL;
50static DBusGProxy *bus_proxy = NULL;
51static DBusGProxy *gdm_proxy = NULL;
52static DbusmenuMenuitem *root_menuitem = NULL;
53static GMainLoop *mainloop = NULL;
54static UsersServiceDbus *dbus_interface = NULL;
55
56static gint count;
57static GList *users;
4558
46static gboolean59static gboolean
47check_guest_session (void)60check_guest_session (void)
@@ -137,29 +150,134 @@
137}150}
138151
139static void152static void
140create_items (DbusmenuMenuitem * root) {153activate_user_session (DbusmenuMenuitem *mi, gpointer user_data)
141 DbusmenuMenuitem * mi = NULL;154{
142155 UserData *user = (UserData *)user_data;
143 mi = dbusmenu_menuitem_new();156 UsersServiceDbus *service = user->service;
144 dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Lock Screen"));157
145 g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(lock_screen), NULL);158 users_service_dbus_activate_user_session (service, user);
146 dbusmenu_menuitem_child_append(root, mi);159}
147160
148 if (check_guest_session()) {161static void
149 mi = dbusmenu_menuitem_new();162remove_menu_item (DbusmenuMenuitem *root, gpointer user_data)
150 dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Guest Session"));163{
151 dbusmenu_menuitem_child_append(root, mi);164 DbusmenuMenuitem *child = (DbusmenuMenuitem *)user_data;
152 g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_guest_session), NULL);165
153 }166 dbusmenu_menuitem_child_delete (root, child);
154167}
155 if (check_new_session()) {168
156 mi = dbusmenu_menuitem_new();169static gint
157 dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Switch User..."));170compare_users_by_username (const gchar *a,
158 dbusmenu_menuitem_child_append(root, mi);171 const gchar *b)
159 g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(activate_new_session), NULL);172{
160 }173 UserData *user1 = (UserData *)a;
161174 UserData *user2 = (UserData *)b;
162 return;175
176 return g_strcmp0 (user1->user_name, user2->user_name);
177}
178
179static void
180rebuild_items (DbusmenuMenuitem *root,
181 UsersServiceDbus *service)
182{
183 DbusmenuMenuitem *mi = NULL;
184 GList *u;
185 UserData *user;
186 gboolean can_activate;
187
188 can_activate = users_service_dbus_can_activate_session (service);
189
190 dbusmenu_menuitem_foreach (root, remove_menu_item, NULL);
191
192 mi = dbusmenu_menuitem_new();
193 dbusmenu_menuitem_property_set(mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Lock Screen"));
194 g_signal_connect(G_OBJECT(mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK(lock_screen), NULL);
195 dbusmenu_menuitem_child_append(root, mi);
196
197 if (can_activate == TRUE)
198 {
199 if (check_guest_session ())
200 {
201 mi = dbusmenu_menuitem_new ();
202 dbusmenu_menuitem_property_set (mi, DBUSMENU_MENUITEM_PROP_LABEL, _("Guest Session"));
203 dbusmenu_menuitem_child_append (root, mi);
204 g_signal_connect (G_OBJECT (mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK (activate_guest_session), NULL);
205 }
206
207 if (count > MINIMUM_USERS && count < MAXIMUM_USERS)
208 {
209 if (users != NULL)
210 {
211 GList *l = NULL;
212
213 for (l = users; l != NULL; l = l->next)
214 {
215 users = g_list_delete_link (users, l);
216 }
217
218 users = NULL;
219 }
220
221 users = users_service_dbus_get_user_list (service);
222
223 users = g_list_sort (users, (GCompareFunc)compare_users_by_username);
224
225 for (u = users; u != NULL; u = g_list_next (u))
226 {
227 user = u->data;
228
229 user->service = service;
230
231 mi = dbusmenu_menuitem_new ();
232 dbusmenu_menuitem_property_set (mi, DBUSMENU_MENUITEM_PROP_LABEL, user->real_name);
233 dbusmenu_menuitem_child_append (root, mi);
234 g_signal_connect (G_OBJECT (mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK (activate_user_session), user);
235 }
236 }
237
238 if (check_new_session ())
239 {
240 mi = dbusmenu_menuitem_new ();
241 dbusmenu_menuitem_property_set (mi, DBUSMENU_MENUITEM_PROP_LABEL, _("New Session..."));
242 dbusmenu_menuitem_child_append (root, mi);
243 g_signal_connect (G_OBJECT (mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK (activate_new_session), NULL);
244 }
245 }
246}
247
248static void
249user_added (UsersServiceDbus *service,
250 UserData *user,
251 gpointer user_data)
252{
253 DbusmenuMenuitem *root = (DbusmenuMenuitem *)user_data;
254
255 count++;
256
257 rebuild_items (root, service);
258}
259
260static void
261user_removed (UsersServiceDbus *service,
262 UserData *user,
263 gpointer user_data)
264{
265 DbusmenuMenuitem *root = (DbusmenuMenuitem *)user_data;
266
267 count--;
268
269 rebuild_items (root, service);
270}
271
272static void
273create_items (DbusmenuMenuitem *root,
274 UsersServiceDbus *service)
275{
276 g_return_if_fail (IS_USERS_SERVICE_DBUS (service));
277
278 count = users_service_dbus_get_user_count (service);
279
280 rebuild_items (root, service);
163}281}
164282
165int283int
@@ -167,35 +285,46 @@
167{285{
168 g_type_init();286 g_type_init();
169287
170 /* Setting up i18n and gettext. Apparently, we need288 /* Setting up i18n and gettext. Apparently, we need
171 all of these. */289 all of these. */
172 setlocale (LC_ALL, "");290 setlocale (LC_ALL, "");
173 bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);291 bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
174 textdomain (GETTEXT_PACKAGE);292 textdomain (GETTEXT_PACKAGE);
175293
176 session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);294 session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL);
177 bus_proxy = dbus_g_proxy_new_for_name(session_bus, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);295 bus_proxy = dbus_g_proxy_new_for_name (session_bus, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS);
178 GError * error = NULL;296 GError * error = NULL;
179 guint nameret = 0;297 guint nameret = 0;
180298
181 if (!org_freedesktop_DBus_request_name(bus_proxy, INDICATOR_USERS_DBUS_NAME, 0, &nameret, &error)) {299 if (!org_freedesktop_DBus_request_name(bus_proxy, INDICATOR_USERS_DBUS_NAME, 0, &nameret, &error)) {
182 g_error("Unable to call to request name");300 g_error("Unable to call to request name");
183 return 1;301 return 1;
184 } 302 }
185303
186 if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {304 if (nameret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
187 g_error("Unable to get name");305 g_error("Unable to get name");
188 return 1;306 return 1;
189 } 307 }
190308
191 root_menuitem = dbusmenu_menuitem_new();309 dbus_interface = g_object_new (USERS_SERVICE_DBUS_TYPE, NULL);
192 g_debug("Root ID: %d", dbusmenu_menuitem_get_id(root_menuitem));310
193311 root_menuitem = dbusmenu_menuitem_new ();
194 create_items(root_menuitem);312 g_debug ("Root ID: %d", dbusmenu_menuitem_get_id (root_menuitem));
313
314 create_items (root_menuitem, dbus_interface);
195315
196 DbusmenuServer * server = dbusmenu_server_new(INDICATOR_USERS_DBUS_OBJECT);316 DbusmenuServer * server = dbusmenu_server_new(INDICATOR_USERS_DBUS_OBJECT);
197 dbusmenu_server_set_root(server, root_menuitem);317 dbusmenu_server_set_root(server, root_menuitem);
198318
319 g_signal_connect (G_OBJECT (dbus_interface),
320 "user-added",
321 G_CALLBACK (user_added),
322 root_menuitem);
323 g_signal_connect (G_OBJECT (dbus_interface),
324 "user-removed",
325 G_CALLBACK (user_removed),
326 root_menuitem);
327
199 mainloop = g_main_loop_new(NULL, FALSE);328 mainloop = g_main_loop_new(NULL, FALSE);
200 g_main_loop_run(mainloop);329 g_main_loop_run(mainloop);
201330
202331
=== added file 'src/users-service.list'
--- src/users-service.list 1970-01-01 00:00:00 +0000
+++ src/users-service.list 2009-09-24 16:28:09 +0000
@@ -0,0 +1,1 @@
1VOID:INT64
02
=== added file 'src/users-service.xml'
--- src/users-service.xml 1970-01-01 00:00:00 +0000
+++ src/users-service.xml 2009-09-24 16:28:09 +0000
@@ -0,0 +1,56 @@
1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
2<node name="/org/gnome/DisplayManager/UserManager">
3 <interface name="org.gnome.DisplayManager.UserManager">
4
5 <!-- Get the number of known users -->
6 <method name="CountUsers">
7 <arg name="user_count" direction="out" type="i"/>
8 </method>
9
10 <!-- Get the list of known UIDs -->
11 <method name="GetUserList">
12 <arg name="uids" direction="out" type="ax"/>
13 </method>
14
15 <!-- Get user info for a user -->
16 <method name="GetUserInfo">
17 <arg name="uid" direction="in" type="x"/>
18 <arg name="user_name" direction="out" type="s"/>
19 <arg name="real_name" direction="out" type="s"/>
20 <arg name="shell" direction="out" type="s"/>
21 <arg name="login_count" direction="out" type="i"/>
22 <arg name="icon_url" direction="out" type="s"/>
23 </method>
24
25 <!-- Get user info for a list of users -->
26 <method name="GetUsersInfo">
27 <arg name="uid" direction="in" type="ax"/>
28 <!-- (uid, user_name, real_name, shell, icon_url) -->
29 <arg name="user_info" direction="out" type="a(xsssis)"/>
30 </method>
31
32 <!-- Query if the initial user list is loaded -->
33 <method name="GetUsersLoaded">
34 <arg name="is_loaded" direction="out" type="b"/>
35 </method>
36
37 <!-- Triggered when the initial user list is loaded -->
38 <signal name="UsersLoaded"></signal>
39
40 <!-- Triggered when a users are added to/removed from the system.
41 Clients should monitor these signals as soon as they connect to
42 this object -->
43 <signal name="UserAdded">
44 <arg name="uid" type="x"/>
45 </signal>
46 <signal name="UserRemoved">
47 <arg name="uid" type="x"/>
48 </signal>
49
50 <!-- Triggered when a user has updated information -->
51 <signal name="UserUpdated">
52 <arg name="uid" type="x"/>
53 </signal>
54
55 </interface>
56</node>

Subscribers

People subscribed via source and target branches