]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/accounts.c
Language chooser modifications:
[sojka/lightdm.git] / src / accounts.c
1 /* -*- Mode: C; indent-tabs-mode: nil; tab-width: 4 -*-
2  *
3  * Copyright (C) 2010-2011 Robert Ancell.
4  * Author: Robert Ancell <robert.ancell@canonical.com>
5  * 
6  * This program is free software: you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License as published by the Free Software
8  * Foundation, either version 3 of the License, or (at your option) any later
9  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
10  * license.
11  */
12
13 #include <errno.h>
14 #include <pwd.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 #include "accounts.h"
19 #include "dmrc.h"
20
21 struct UserPrivate
22 {
23     /* Name of user */
24     gchar *name;
25
26     /* Accounts interface proxy */
27     GDBusProxy *proxy;
28
29     /* User ID */
30     uid_t uid;
31
32     /* Group ID */
33     gid_t gid;
34
35     /* GECOS information */
36     gchar *gecos;
37
38     /* Home directory */
39     gchar *home_directory;
40
41     /* Shell */
42     gchar *shell;
43
44     /* Language */
45     gchar *language;
46
47     /* Locale */
48     gchar *locale;
49
50     /* X session */
51     gchar *xsession;
52 };
53
54 G_DEFINE_TYPE (User, user, G_TYPE_OBJECT);
55
56 /* Connection to AccountsService */
57 static GDBusProxy *accounts_service_proxy = NULL;
58 static gboolean have_accounts_service_proxy = FALSE;
59
60 static gboolean
61 call_method (GDBusProxy *proxy, const gchar *method, GVariant *args,
62              const gchar *expected, GVariant **result)
63 {
64     GVariant *answer;
65     GError *error = NULL;
66
67     if (!proxy)
68         return FALSE;
69
70     answer = g_dbus_proxy_call_sync (proxy,
71                                      method,
72                                      args,
73                                      G_DBUS_CALL_FLAGS_NONE,
74                                      -1,
75                                      NULL,
76                                      &error);
77     if (error)
78         g_warning ("Could not call %s: %s", method, error->message);
79     g_clear_error (&error);
80
81     if (!answer)
82         return FALSE;
83
84     if (!g_variant_is_of_type (answer, G_VARIANT_TYPE (expected)))
85     {
86         g_warning ("Unexpected response from %s: %s",
87                    method, g_variant_get_type_string (answer));
88         g_variant_unref (answer);
89         return FALSE;
90     }
91
92     if (result)
93         *result = answer;
94     else
95         g_variant_unref (answer);
96
97     return TRUE;
98 }
99
100 static gboolean
101 get_property (GDBusProxy *proxy, const gchar *property,
102               const gchar *expected, GVariant **result)
103 {
104     GVariant *answer;
105
106     answer = g_dbus_proxy_get_cached_property (proxy, property);
107
108     if (!answer)
109     {
110         g_warning ("Could not get accounts property %s", property);
111         return FALSE;
112     }
113
114     if (!g_variant_is_of_type (answer, G_VARIANT_TYPE (expected)))
115     {
116         g_warning ("Unexpected accounts property type for %s: %s",
117                    property, g_variant_get_type_string (answer));
118         g_variant_unref (answer);
119         return FALSE;
120     }
121
122     if (result)
123         *result = answer;
124     else
125         g_variant_unref (answer);
126     return TRUE;
127 }
128
129 static void
130 save_string_to_dmrc (const gchar *username, const gchar *group,
131                      const gchar *key, const gchar *value)
132 {
133     GKeyFile *dmrc;
134
135     dmrc = dmrc_load (username);
136     g_key_file_set_string (dmrc, group, key, value);
137     dmrc_save (dmrc, username);
138
139     g_key_file_free (dmrc);
140 }
141
142 static gchar *
143 get_string_from_dmrc (const gchar *username, const gchar *group,
144                       const gchar *key)
145 {
146     GKeyFile *dmrc;
147     gchar *value;
148
149     dmrc = dmrc_load (username);
150     value = g_key_file_get_string (dmrc, group, key, NULL);
151
152     g_key_file_free (dmrc);
153     return value;
154 }
155
156 static GDBusProxy *
157 get_accounts_service_proxy ()
158 {
159     GError *error = NULL;
160
161     if (have_accounts_service_proxy)
162         return accounts_service_proxy;
163   
164     have_accounts_service_proxy = TRUE;
165     accounts_service_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
166                                                             G_DBUS_PROXY_FLAGS_NONE,
167                                                             NULL,
168                                                             "org.freedesktop.Accounts",
169                                                             "/org/freedesktop/Accounts",
170                                                             "org.freedesktop.Accounts",
171                                                             NULL, &error);
172     if (error)
173         g_warning ("Could not get accounts proxy: %s", error->message);
174     g_clear_error (&error);
175
176     if (accounts_service_proxy)
177     {
178         gchar *name;
179         name = g_dbus_proxy_get_name_owner (accounts_service_proxy);
180         if (!name)
181         {
182             g_debug ("org.freedesktop.Accounts does not exist, falling back to passwd file");
183             g_object_unref (accounts_service_proxy);
184             accounts_service_proxy = NULL;
185         }
186         g_free (name);
187     }  
188
189     return accounts_service_proxy;
190 }
191
192 static GDBusProxy *
193 get_accounts_proxy_for_user (const gchar *user)
194 {
195     GDBusProxy *proxy;
196     GError *error = NULL;
197     GVariant *result;
198     gboolean success;
199     gchar *user_path = NULL;
200
201     g_return_val_if_fail (user != NULL, NULL);  
202
203     proxy = get_accounts_service_proxy ();
204     if (!proxy)
205         return NULL;
206
207     success = call_method (proxy, "FindUserByName", g_variant_new ("(s)", user), "(o)", &result);
208
209     if (!success)
210         return NULL;
211
212     g_variant_get (result, "(o)", &user_path);
213     g_variant_unref (result);
214
215     if (!user_path)
216         return NULL;
217
218     proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
219                                            G_DBUS_PROXY_FLAGS_NONE,
220                                            NULL,
221                                            "org.freedesktop.Accounts",
222                                            user_path,
223                                            "org.freedesktop.Accounts.User",
224                                            NULL, &error);
225     if (error)
226         g_warning ("Could not get accounts user proxy: %s", error->message);
227     g_clear_error (&error);
228     g_free (user_path);
229
230     return proxy;
231 }
232
233 static User *
234 user_from_passwd (struct passwd *user_info)
235 {
236     User *user;
237
238     user = g_object_new (USER_TYPE, NULL);
239     user->priv->name = g_strdup (user_info->pw_name);
240     user->priv->uid = user_info->pw_uid;
241     user->priv->gid = user_info->pw_gid;
242     user->priv->gecos = g_strdup (user_info->pw_gecos);
243     user->priv->home_directory = g_strdup (user_info->pw_dir);
244     user->priv->shell = g_strdup (user_info->pw_shell);
245     user->priv->proxy = get_accounts_proxy_for_user (user->priv->name);
246
247     return user;
248 }
249
250 User *
251 accounts_get_user_by_name (const gchar *username)
252 {
253     struct passwd *user_info;
254     User *user = NULL;
255
256     g_return_val_if_fail (username != NULL, NULL);
257
258     errno = 0;
259     user_info = getpwnam (username);
260     if (user_info)
261         user = user_from_passwd (user_info);
262
263     if (!user && errno != 0)
264         g_warning ("Unable to get information on user %s: %s", username, strerror (errno));
265
266     return user;
267 }
268
269 User *
270 accounts_get_user_by_uid (uid_t uid)
271 {
272     User *user = NULL;
273
274     errno = 0;
275     struct passwd *user_info;
276
277     user_info = getpwuid (uid);
278     if (user_info)
279         user = user_from_passwd (user_info);
280
281     if (!user && errno != 0)
282         g_warning ("Unable to get information on user %d: %s", uid, strerror (errno));
283
284     return user;
285 }
286
287 User *
288 accounts_get_current_user ()
289 {
290     return user_from_passwd (getpwuid (getuid ()));
291 }
292
293 const gchar *
294 user_get_name (User *user)
295 {
296     g_return_val_if_fail (user != NULL, NULL);
297     return user->priv->name;
298 }
299
300 uid_t
301 user_get_uid (User *user)
302 {
303     g_return_val_if_fail (user != NULL, 0);
304     return user->priv->uid;
305 }
306
307 gid_t
308 user_get_gid (User *user)
309 {
310     g_return_val_if_fail (user != NULL, 0);
311     return user->priv->gid;
312 }
313
314 const gchar *
315 user_get_gecos (User *user)
316 {
317     g_return_val_if_fail (user != NULL, NULL);
318     return user->priv->gecos;
319 }
320
321 const gchar *
322 user_get_home_directory (User *user)
323 {
324     g_return_val_if_fail (user != NULL, NULL);
325     return user->priv->home_directory;
326 }
327
328 const gchar *
329 user_get_shell (User *user)
330 {
331     g_return_val_if_fail (user != NULL, NULL);
332     return user->priv->shell;
333 }
334
335 const gchar *
336 user_get_locale (User *user)
337 {
338     g_return_val_if_fail (user != NULL, NULL);
339
340     g_free (user->priv->locale);
341     if (user->priv->proxy)
342         user->priv->locale = NULL;
343     else
344         user->priv->locale = get_string_from_dmrc (user->priv->name, "Desktop", "Language");
345
346     /* Treat a blank locale as unset */
347     if (g_strcmp0 (user->priv->locale, "") == 0)
348     {
349         g_free (user->priv->locale);
350         user->priv->locale = NULL;
351     }
352
353     return user->priv->locale;
354 }
355
356 void
357 user_set_language (User *user, const gchar *language)
358 {
359     g_return_if_fail (user != NULL);
360
361     if (user->priv->proxy)
362         call_method (user->priv->proxy, "SetLanguage", g_variant_new ("(s)", language), "()", NULL);
363     else
364         save_string_to_dmrc (user->priv->name, "Desktop", "Language", language);
365 }
366
367 void
368 user_set_xsession (User *user, const gchar *xsession)
369 {
370     g_return_if_fail (user != NULL);
371
372     call_method (user->priv->proxy, "SetXSession", g_variant_new ("(s)", xsession), "()", NULL);
373     save_string_to_dmrc (user->priv->name, "Desktop", "Session", xsession);
374 }
375
376 const gchar *
377 user_get_xsession (User *user)
378 {
379     GVariant *result;
380
381     g_return_val_if_fail (user != NULL, NULL);
382
383     g_free (user->priv->xsession);
384     if (user->priv->proxy)
385     {
386         if (get_property (user->priv->proxy, "XSession", "s", &result))
387         {
388             g_variant_get (result, "s", &user->priv->xsession);
389             g_variant_unref (result);
390         }
391         else
392             user->priv->xsession = NULL;
393     }
394     else
395         user->priv->xsession = get_string_from_dmrc (user->priv->name, "Desktop", "Session");
396
397     if (g_strcmp0 (user->priv->xsession, "") == 0)
398     {
399         g_free (user->priv->xsession);
400         user->priv->xsession = NULL;
401     }
402
403     return user->priv->xsession;
404 }
405
406 static void
407 user_init (User *user)
408 {
409     user->priv = G_TYPE_INSTANCE_GET_PRIVATE (user, USER_TYPE, UserPrivate);
410 }
411
412 static void
413 user_dispose (GObject *object)
414 {
415     User *self;
416
417     self = USER (object);
418
419     if (self->priv->proxy)
420     {
421         g_object_unref (self->priv->proxy);
422         self->priv->proxy = NULL;
423     }
424
425     G_OBJECT_CLASS (user_parent_class)->dispose (object);
426 }
427
428 static void
429 user_finalize (GObject *object)
430 {
431     User *self;
432
433     self = USER (object);
434
435     g_free (self->priv->name);
436     g_free (self->priv->gecos);
437     g_free (self->priv->home_directory);
438     g_free (self->priv->shell);
439
440     G_OBJECT_CLASS (user_parent_class)->finalize (object);  
441 }
442
443 static void
444 user_class_init (UserClass *klass)
445 {
446     GObjectClass *object_class = G_OBJECT_CLASS (klass);
447
448     object_class->dispose = user_dispose;
449     object_class->finalize = user_finalize;  
450
451     g_type_class_add_private (klass, sizeof (UserPrivate));
452 }