~cjcurran/gnome-control-center/expose-card-ports

« back to all changes in this revision

Viewing changes to panels/user-accounts/um-user.c

  • Committer: Bazaar Package Importer
  • Author(s): Rodrigo Moya
  • Date: 2011-05-17 10:47:27 UTC
  • mfrom: (0.1.11 experimental) (1.1.45 upstream)
  • Revision ID: james.westby@ubuntu.com-20110517104727-lqel6m8vhfw5jby1
Tags: 1:3.0.1.1-1ubuntu1
* Rebase on Debian, remaining Ubuntu changes:
* debian/control:
  - Build-Depend on hardening-wrapper, dpkg-dev and dh-autoreconf
  - Add dependency on ubuntu-system-service
  - Remove dependency on gnome-icon-theme-symbolic
  - Move dependency on apg, gnome-icon-theme-symbolic and accountsservice to
    be a Recommends: until we get them in main
* debian/rules:
  - Use autoreconf
  - Add binary-post-install rule for gnome-control-center-data
  - Run dh-autoreconf
* debian/gnome-control-center.dirs:
* debian/gnome-control-center.links:
  - Add a link to the control center shell for indicators
* debian/patches/00_disable-nm.patch:
  - Temporary patch to disable building with NetworkManager until we get
    the new one in the archive
* debian/patches/01_git_remove_gettext_calls.patch:
  - Remove calls to AM_GNU_GETTEXT, IT_PROG_INTLTOOL should be enough
* debian/patches/01_git_kill_warning.patch:
  - Kill warning
* debian/patches/50_ubuntu_systemwide_prefs.patch:
  - Ubuntu specific proxy preferences
* debian/patches/51_ubuntu_system_keyboard.patch:
  - Implement the global keyboard spec at https://wiki.ubuntu.com/DefaultKeyboardSettings

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
 
2
  *
 
3
  * Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
 
4
  * Copyright (C) 2007-2008 William Jon McCann <mccann@jhu.edu>
 
5
  * Copyright (C) 2009 Red Hat, Inc.
 
6
  *
 
7
  * This program is free software; you can redistribute it and/or modify
 
8
  * it under the terms of the GNU General Public License as published by
 
9
  * the Free Software Foundation; either version 2 of the License, or
 
10
  * (at your option) any later version.
 
11
  *
 
12
  * This program is distributed in the hope that it will be useful,
 
13
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
  * GNU General Public License for more details.
 
16
  *
 
17
  * You should have received a copy of the GNU General Public License
 
18
  * along with this program; if not, write to the Free Software
 
19
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
20
  */
 
21
 
 
22
#define _XOPEN_SOURCE
 
23
 
 
24
#include "config.h"
 
25
 
 
26
#include <float.h>
 
27
#include <string.h>
 
28
#include <sys/types.h>
 
29
#include <sys/stat.h>
 
30
#include <unistd.h>
 
31
 
 
32
#include <glib.h>
 
33
#include <glib/gi18n.h>
 
34
#include <glib/gstdio.h>
 
35
#include <gio/gio.h>
 
36
#include <gtk/gtk.h>
 
37
 
 
38
#include <gio/gunixoutputstream.h>
 
39
 
 
40
#include <dbus/dbus-glib.h>
 
41
 
 
42
#include "um-user.h"
 
43
#include "um-account-type.h"
 
44
#include "um-utils.h"
 
45
 
 
46
 
 
47
 #define UM_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UM_TYPE_USER, UmUserClass))
 
48
 #define UM_IS_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UM_TYPE_USER))
 
49
#define UM_USER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), UM_TYPE_USER, UmUserClass))
 
50
 
 
51
#define MAX_FILE_SIZE     65536
 
52
 
 
53
typedef struct {
 
54
        uid_t           uid;
 
55
        gchar          *user_name;
 
56
        gchar          *real_name;
 
57
        gint            account_type;
 
58
        gint            password_mode;
 
59
        gchar          *password_hint;
 
60
        gchar          *email;
 
61
        gchar          *language;
 
62
        gchar          *location;
 
63
        guint64         login_frequency;
 
64
        gchar          *icon_file;
 
65
        gboolean        locked;
 
66
        gboolean        automatic_login;
 
67
        gboolean        system_account;
 
68
} UserProperties;
 
69
 
 
70
static void
 
71
collect_props (const gchar    *key,
 
72
               const GValue   *value,
 
73
               UserProperties *props)
 
74
{
 
75
        gboolean handled = TRUE;
 
76
 
 
77
        if (strcmp (key, "Uid") == 0) {
 
78
                props->uid = g_value_get_uint64 (value);
 
79
        }
 
80
        else if (strcmp (key, "UserName") == 0) {
 
81
                props->user_name = g_value_dup_string (value);
 
82
        }
 
83
        else if (strcmp (key, "RealName") == 0) {
 
84
                props->real_name = g_value_dup_string (value);
 
85
        }
 
86
        else if (strcmp (key, "AccountType") == 0) {
 
87
                props->account_type = g_value_get_int (value);
 
88
        }
 
89
        else if (strcmp (key, "Email") == 0) {
 
90
                props->email = g_value_dup_string (value);
 
91
        }
 
92
        else if (strcmp (key, "Language") == 0) {
 
93
                props->language = g_value_dup_string (value);
 
94
        }
 
95
        else if (strcmp (key, "Location") == 0) {
 
96
                props->location = g_value_dup_string (value);
 
97
        }
 
98
        else if (strcmp (key, "LoginFrequency") == 0) {
 
99
                props->login_frequency = g_value_get_uint64 (value);
 
100
        }
 
101
        else if (strcmp (key, "IconFile") == 0) {
 
102
                props->icon_file = g_value_dup_string (value);
 
103
        }
 
104
        else if (strcmp (key, "Locked") == 0) {
 
105
                props->locked = g_value_get_boolean (value);
 
106
        }
 
107
        else if (strcmp (key, "AutomaticLogin") == 0) {
 
108
                props->automatic_login = g_value_get_boolean (value);
 
109
        }
 
110
        else if (strcmp (key, "SystemAccount") == 0) {
 
111
                props->system_account = g_value_get_boolean (value);
 
112
        }
 
113
        else if (strcmp (key, "PasswordMode") == 0) {
 
114
                props->password_mode = g_value_get_int (value);
 
115
        }
 
116
        else if (strcmp (key, "PasswordHint") == 0) {
 
117
                props->password_hint = g_value_dup_string (value);
 
118
        }
 
119
        else if (strcmp (key, "HomeDirectory") == 0) {
 
120
                /* ignore */
 
121
        }
 
122
        else if (strcmp (key, "Shell") == 0) {
 
123
                /* ignore */
 
124
        }
 
125
        else {
 
126
                handled = FALSE;
 
127
        }
 
128
 
 
129
        if (!handled)
 
130
                g_debug ("unhandled property %s", key);
 
131
}
 
132
 
 
133
static void
 
134
user_properties_free (UserProperties *props)
 
135
{
 
136
        g_free (props->user_name);
 
137
        g_free (props->real_name);
 
138
        g_free (props->password_hint);
 
139
        g_free (props->email);
 
140
        g_free (props->language);
 
141
        g_free (props->location);
 
142
        g_free (props->icon_file);
 
143
        g_free (props);
 
144
}
 
145
 
 
146
static UserProperties *
 
147
user_properties_get (DBusGConnection *bus,
 
148
                     const gchar     *object_path)
 
149
{
 
150
        UserProperties *props;
 
151
        GError *error;
 
152
        DBusGProxy *proxy;
 
153
        GHashTable *hash_table;
 
154
 
 
155
        props = g_new0 (UserProperties, 1);
 
156
 
 
157
        proxy = dbus_g_proxy_new_for_name (bus,
 
158
                                           "org.freedesktop.Accounts",
 
159
                                           object_path,
 
160
                                           "org.freedesktop.DBus.Properties");
 
161
        error = NULL;
 
162
        if (!dbus_g_proxy_call (proxy,
 
163
                                "GetAll",
 
164
                                &error,
 
165
                                G_TYPE_STRING,
 
166
                                "org.freedesktop.Accounts.User",
 
167
                                G_TYPE_INVALID,
 
168
                                dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
 
169
                                &hash_table,
 
170
                                G_TYPE_INVALID)) {
 
171
                g_debug ("Error calling GetAll() when retrieving properties for %s: %s", object_path, error->message);
 
172
                g_error_free (error);
 
173
                g_free (props);
 
174
                props = NULL;
 
175
                goto out;
 
176
        }
 
177
        g_hash_table_foreach (hash_table, (GHFunc) collect_props, props);
 
178
        g_hash_table_unref (hash_table);
 
179
 
 
180
 out:
 
181
        g_object_unref (proxy);
 
182
        return props;
 
183
}
 
184
 
 
185
 
 
186
struct _UmUser {
 
187
        GObject         parent;
 
188
 
 
189
        DBusGConnection *bus;
 
190
        DBusGProxy      *proxy;
 
191
        gchar           *object_path;
 
192
 
 
193
        UserProperties  *props;
 
194
 
 
195
        gchar           *display_name;
 
196
};
 
197
 
 
198
typedef struct _UmUserClass
 
199
{
 
200
        GObjectClass parent_class;
 
201
} UmUserClass;
 
202
 
 
203
enum {
 
204
        CHANGED,
 
205
        LAST_SIGNAL
 
206
};
 
207
 
 
208
static guint signals[LAST_SIGNAL] = { 0 };
 
209
 
 
210
static void um_user_finalize (GObject *object);
 
211
 
 
212
G_DEFINE_TYPE (UmUser, um_user, G_TYPE_OBJECT)
 
213
 
 
214
static void
 
215
um_user_class_init (UmUserClass *class)
 
216
{
 
217
        GObjectClass *gobject_class;
 
218
 
 
219
        gobject_class = G_OBJECT_CLASS (class);
 
220
 
 
221
        gobject_class->finalize = um_user_finalize;
 
222
 
 
223
        signals[CHANGED] = g_signal_new ("changed",
 
224
                                         G_TYPE_FROM_CLASS (class),
 
225
                                         G_SIGNAL_RUN_LAST,
 
226
                                         0,
 
227
                                         NULL, NULL,
 
228
                                         g_cclosure_marshal_VOID__VOID,
 
229
                                         G_TYPE_NONE, 0);
 
230
}
 
231
 
 
232
 
 
233
static void
 
234
um_user_init (UmUser *user)
 
235
{
 
236
}
 
237
 
 
238
static void
 
239
um_user_finalize (GObject *object)
 
240
{
 
241
        UmUser *user;
 
242
 
 
243
        user = UM_USER (object);
 
244
 
 
245
        dbus_g_connection_unref (user->bus);
 
246
        g_free (user->object_path);
 
247
 
 
248
        if (user->proxy != NULL)
 
249
                g_object_unref (user->proxy);
 
250
 
 
251
        if (user->props != NULL)
 
252
                user_properties_free (user->props);
 
253
 
 
254
        (*G_OBJECT_CLASS (um_user_parent_class)->finalize) (object);
 
255
}
 
256
 
 
257
uid_t
 
258
um_user_get_uid (UmUser *user)
 
259
{
 
260
        g_return_val_if_fail (UM_IS_USER (user), -1);
 
261
 
 
262
        return user->props->uid;
 
263
}
 
264
 
 
265
const gchar *
 
266
um_user_get_real_name (UmUser *user)
 
267
{
 
268
        g_return_val_if_fail (UM_IS_USER (user), NULL);
 
269
 
 
270
        return user->props->real_name;
 
271
}
 
272
 
 
273
const gchar *
 
274
um_user_get_display_name (UmUser *user)
 
275
{
 
276
        g_return_val_if_fail (UM_IS_USER (user), NULL);
 
277
 
 
278
       return user->display_name ? user->display_name
 
279
                                 : user->props->real_name;
 
280
}
 
281
 
 
282
const gchar *
 
283
um_user_get_user_name (UmUser *user)
 
284
{
 
285
        g_return_val_if_fail (UM_IS_USER (user), NULL);
 
286
 
 
287
        return user->props->user_name;
 
288
}
 
289
 
 
290
gint
 
291
um_user_get_account_type (UmUser *user)
 
292
{
 
293
        g_return_val_if_fail (UM_IS_USER (user), UM_ACCOUNT_TYPE_STANDARD);
 
294
 
 
295
        return user->props->account_type;
 
296
}
 
297
 
 
298
gulong
 
299
um_user_get_login_frequency (UmUser *user)
 
300
{
 
301
        g_return_val_if_fail (UM_IS_USER (user), 0);
 
302
 
 
303
        return user->props->login_frequency;
 
304
}
 
305
 
 
306
gint
 
307
um_user_collate (UmUser *user1,
 
308
                  UmUser *user2)
 
309
{
 
310
        const char *str1;
 
311
        const char *str2;
 
312
        gulong      num1;
 
313
        gulong      num2;
 
314
 
 
315
        g_return_val_if_fail (UM_IS_USER (user1), 0);
 
316
        g_return_val_if_fail (UM_IS_USER (user2), 0);
 
317
 
 
318
        num1 = user1->props->login_frequency;
 
319
        num2 = user2->props->login_frequency;
 
320
        if (num1 > num2) {
 
321
                return -1;
 
322
        }
 
323
 
 
324
        if (num1 < num2) {
 
325
                return 1;
 
326
        }
 
327
 
 
328
        /* if login frequency is equal try names */
 
329
        if (user1->props->real_name != NULL) {
 
330
                str1 = user1->props->real_name;
 
331
        } else {
 
332
                str1 = user1->props->user_name;
 
333
        }
 
334
 
 
335
        if (user2->props->real_name != NULL) {
 
336
                str2 = user2->props->real_name;
 
337
        } else {
 
338
                str2 = user2->props->user_name;
 
339
        }
 
340
 
 
341
        if (str1 == NULL && str2 != NULL) {
 
342
                return -1;
 
343
        }
 
344
 
 
345
        if (str1 != NULL && str2 == NULL) {
 
346
                return 1;
 
347
        }
 
348
 
 
349
        if (str1 == NULL && str2 == NULL) {
 
350
                return 0;
 
351
        }
 
352
 
 
353
        return g_utf8_collate (str1, str2);
 
354
}
 
355
 
 
356
static gboolean
 
357
check_user_file (const char *filename,
 
358
                 gssize      max_file_size)
 
359
{
 
360
        struct stat fileinfo;
 
361
 
 
362
        if (max_file_size < 0) {
 
363
                max_file_size = G_MAXSIZE;
 
364
        }
 
365
 
 
366
        /* Exists/Readable? */
 
367
        if (stat (filename, &fileinfo) < 0) {
 
368
                g_debug ("File does not exist");
 
369
                return FALSE;
 
370
        }
 
371
 
 
372
        /* Is a regular file */
 
373
        if (G_UNLIKELY (!S_ISREG (fileinfo.st_mode))) {
 
374
                g_debug ("File is not a regular file");
 
375
                return FALSE;
 
376
        }
 
377
 
 
378
        /* Size is kosher? */
 
379
        if (G_UNLIKELY (fileinfo.st_size > max_file_size)) {
 
380
                g_debug ("File is too large");
 
381
                return FALSE;
 
382
        }
 
383
 
 
384
        return TRUE;
 
385
}
 
386
 
 
387
static cairo_surface_t *
 
388
surface_from_pixbuf (GdkPixbuf *pixbuf)
 
389
{
 
390
        cairo_surface_t *surface;
 
391
        cairo_t         *cr;
 
392
 
 
393
        surface = cairo_image_surface_create (gdk_pixbuf_get_has_alpha (pixbuf) ?
 
394
                                              CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
 
395
                                              gdk_pixbuf_get_width (pixbuf),
 
396
                                              gdk_pixbuf_get_height (pixbuf));
 
397
        cr = cairo_create (surface);
 
398
        gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
 
399
        cairo_paint (cr);
 
400
        cairo_destroy (cr);
 
401
 
 
402
        return surface;
 
403
}
 
404
 
 
405
/**
 
406
 * go_cairo_convert_data_to_pixbuf:
 
407
 * @src: a pointer to pixel data in cairo format
 
408
 * @dst: a pointer to pixel data in pixbuf format
 
409
 * @width: image width
 
410
 * @height: image height
 
411
 * @rowstride: data rowstride
 
412
 *
 
413
 * Converts the pixel data stored in @src in CAIRO_FORMAT_ARGB32 cairo format
 
414
 * to GDK_COLORSPACE_RGB pixbuf format and move them
 
415
 * to @dst. If @src == @dst, pixel are converted in place.
 
416
 **/
 
417
 
 
418
static void
 
419
go_cairo_convert_data_to_pixbuf (unsigned char *dst,
 
420
                                 unsigned char const *src,
 
421
                                 int width,
 
422
                                 int height,
 
423
                                 int rowstride)
 
424
{
 
425
        int i,j;
 
426
        unsigned int t;
 
427
        unsigned char a, b, c;
 
428
 
 
429
        g_return_if_fail (dst != NULL);
 
430
 
 
431
#define MULT(d,c,a,t) G_STMT_START { t = (a)? c * 255 / a: 0; d = t;} G_STMT_END
 
432
 
 
433
        if (src == dst || src == NULL) {
 
434
                for (i = 0; i < height; i++) {
 
435
                        for (j = 0; j < width; j++) {
 
436
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
 
437
                                MULT(a, dst[2], dst[3], t);
 
438
                                MULT(b, dst[1], dst[3], t);
 
439
                                MULT(c, dst[0], dst[3], t);
 
440
                                dst[0] = a;
 
441
                                dst[1] = b;
 
442
                                dst[2] = c;
 
443
#else
 
444
                                MULT(a, dst[1], dst[0], t);
 
445
                                MULT(b, dst[2], dst[0], t);
 
446
                                MULT(c, dst[3], dst[0], t);
 
447
                                dst[3] = dst[0];
 
448
                                dst[0] = a;
 
449
                                dst[1] = b;
 
450
                                dst[2] = c;
 
451
#endif
 
452
                                dst += 4;
 
453
                        }
 
454
                        dst += rowstride - width * 4;
 
455
                }
 
456
        } else {
 
457
                for (i = 0; i < height; i++) {
 
458
                        for (j = 0; j < width; j++) {
 
459
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
 
460
                                MULT(dst[0], src[2], src[3], t);
 
461
                                MULT(dst[1], src[1], src[3], t);
 
462
                                MULT(dst[2], src[0], src[3], t);
 
463
                                dst[3] = src[3];
 
464
#else
 
465
                                MULT(dst[0], src[1], src[0], t);
 
466
                                MULT(dst[1], src[2], src[0], t);
 
467
                                MULT(dst[2], src[3], src[0], t);
 
468
                                dst[3] = src[0];
 
469
#endif
 
470
                                src += 4;
 
471
                                dst += 4;
 
472
                        }
 
473
                        src += rowstride - width * 4;
 
474
                        dst += rowstride - width * 4;
 
475
                }
 
476
        }
 
477
#undef MULT
 
478
}
 
479
 
 
480
static void
 
481
cairo_to_pixbuf (guint8    *src_data,
 
482
                 GdkPixbuf *dst_pixbuf)
 
483
{
 
484
        unsigned char *src;
 
485
        unsigned char *dst;
 
486
        guint          w;
 
487
        guint          h;
 
488
        guint          rowstride;
 
489
 
 
490
        w = gdk_pixbuf_get_width (dst_pixbuf);
 
491
        h = gdk_pixbuf_get_height (dst_pixbuf);
 
492
        rowstride = gdk_pixbuf_get_rowstride (dst_pixbuf);
 
493
 
 
494
        dst = gdk_pixbuf_get_pixels (dst_pixbuf);
 
495
        src = src_data;
 
496
 
 
497
        go_cairo_convert_data_to_pixbuf (dst, src, w, h, rowstride);
 
498
}
 
499
 
 
500
static GdkPixbuf *
 
501
frame_pixbuf (GdkPixbuf *source)
 
502
{
 
503
        GdkPixbuf       *dest;
 
504
        cairo_t         *cr;
 
505
        cairo_surface_t *surface;
 
506
        guint            w;
 
507
        guint            h;
 
508
        guint            rowstride;
 
509
        int              frame_width;
 
510
        double           radius;
 
511
        guint8          *data;
 
512
 
 
513
        frame_width = 2;
 
514
 
 
515
        w = gdk_pixbuf_get_width (source) + frame_width * 2;
 
516
        h = gdk_pixbuf_get_height (source) + frame_width * 2;
 
517
        radius = w / 10;
 
518
 
 
519
        dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
 
520
                               TRUE,
 
521
                               8,
 
522
                               w,
 
523
                               h);
 
524
        rowstride = gdk_pixbuf_get_rowstride (dest);
 
525
 
 
526
 
 
527
        data = g_new0 (guint8, h * rowstride);
 
528
 
 
529
        surface = cairo_image_surface_create_for_data (data,
 
530
                                                       CAIRO_FORMAT_ARGB32,
 
531
                                                       w,
 
532
                                                       h,
 
533
                                                       rowstride);
 
534
        cr = cairo_create (surface);
 
535
        cairo_surface_destroy (surface);
 
536
 
 
537
        /* set up image */
 
538
        cairo_rectangle (cr, 0, 0, w, h);
 
539
        cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
 
540
        cairo_fill (cr);
 
541
 
 
542
        rounded_rectangle (cr, 1.0, 0.5, 0.5, radius, w - 1, h - 1);
 
543
        cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.3);
 
544
        cairo_fill_preserve (cr);
 
545
 
 
546
        surface = surface_from_pixbuf (source);
 
547
        cairo_set_source_surface (cr, surface, frame_width, frame_width);
 
548
        cairo_fill (cr);
 
549
        cairo_surface_destroy (surface);
 
550
 
 
551
        cairo_to_pixbuf (data, dest);
 
552
 
 
553
        cairo_destroy (cr);
 
554
        g_free (data);
 
555
 
 
556
        return dest;
 
557
}
 
558
 
 
559
GdkPixbuf *
 
560
um_user_render_icon (UmUser   *user,
 
561
                     gboolean  with_frame,
 
562
                     gint      icon_size)
 
563
{
 
564
        GdkPixbuf    *pixbuf;
 
565
        GdkPixbuf    *framed;
 
566
        gboolean      res;
 
567
        GError       *error;
 
568
 
 
569
        g_return_val_if_fail (UM_IS_USER (user), NULL);
 
570
        g_return_val_if_fail (icon_size > 12, NULL);
 
571
 
 
572
        pixbuf = NULL;
 
573
        if (user->props->icon_file) {
 
574
                res = check_user_file (user->props->icon_file,
 
575
                                       MAX_FILE_SIZE);
 
576
                if (res) {
 
577
                        pixbuf = gdk_pixbuf_new_from_file_at_size (user->props->icon_file,
 
578
                                                                   icon_size,
 
579
                                                                   icon_size,
 
580
                                                                   NULL);
 
581
                }
 
582
                else {
 
583
                        pixbuf = NULL;
 
584
                }
 
585
        }
 
586
 
 
587
        if (pixbuf != NULL) {
 
588
                goto out;
 
589
        }
 
590
 
 
591
        error = NULL;
 
592
        pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
 
593
 
 
594
                                           "avatar-default",
 
595
                                           icon_size,
 
596
                                           GTK_ICON_LOOKUP_FORCE_SIZE,
 
597
                                           &error);
 
598
        if (error) {
 
599
                g_warning ("%s", error->message);
 
600
                g_error_free (error);
 
601
        }
 
602
 
 
603
 out:
 
604
 
 
605
        if (pixbuf != NULL && with_frame) {
 
606
                framed = frame_pixbuf (pixbuf);
 
607
                if (framed != NULL) {
 
608
                        g_object_unref (pixbuf);
 
609
                        pixbuf = framed;
 
610
                }
 
611
        }
 
612
 
 
613
        return pixbuf;
 
614
}
 
615
 
 
616
const gchar *
 
617
um_user_get_email (UmUser *user)
 
618
{
 
619
        g_return_val_if_fail (UM_IS_USER (user), NULL);
 
620
 
 
621
        return user->props->email;
 
622
}
 
623
 
 
624
const gchar *
 
625
um_user_get_language (UmUser *user)
 
626
{
 
627
        g_return_val_if_fail (UM_IS_USER (user), NULL);
 
628
 
 
629
        if (*user->props->language == '\0')
 
630
                return NULL;
 
631
        return user->props->language;
 
632
}
 
633
 
 
634
const gchar *
 
635
um_user_get_location (UmUser *user)
 
636
{
 
637
        g_return_val_if_fail (UM_IS_USER (user), NULL);
 
638
 
 
639
        return user->props->location;
 
640
}
 
641
 
 
642
gint
 
643
um_user_get_password_mode (UmUser *user)
 
644
{
 
645
        g_return_val_if_fail (UM_IS_USER (user), UM_PASSWORD_MODE_NONE);
 
646
 
 
647
        return user->props->password_mode;
 
648
}
 
649
 
 
650
const char *
 
651
um_user_get_password_hint (UmUser *user)
 
652
{
 
653
        g_return_val_if_fail (UM_IS_USER (user), NULL);
 
654
 
 
655
        return user->props->password_hint;
 
656
}
 
657
 
 
658
const char *
 
659
um_user_get_icon_file (UmUser *user)
 
660
{
 
661
        g_return_val_if_fail (UM_IS_USER (user), NULL);
 
662
 
 
663
        return user->props->icon_file;
 
664
}
 
665
 
 
666
gboolean
 
667
um_user_get_locked (UmUser *user)
 
668
{
 
669
        g_return_val_if_fail (UM_IS_USER (user), FALSE);
 
670
 
 
671
        return user->props->locked;
 
672
}
 
673
gboolean
 
674
um_user_get_automatic_login (UmUser *user)
 
675
{
 
676
        g_return_val_if_fail (UM_IS_USER (user), FALSE);
 
677
 
 
678
        return user->props->automatic_login;
 
679
}
 
680
 
 
681
gboolean
 
682
um_user_is_system_account (UmUser *user)
 
683
{
 
684
        g_return_val_if_fail (UM_IS_USER (user), FALSE);
 
685
 
 
686
        return user->props->system_account;
 
687
}
 
688
 
 
689
const gchar *
 
690
um_user_get_object_path (UmUser *user)
 
691
{
 
692
        g_return_val_if_fail (UM_IS_USER (user), NULL);
 
693
 
 
694
        return user->object_path;
 
695
}
 
696
 
 
697
static gboolean
 
698
update_info (UmUser *user)
 
699
{
 
700
        UserProperties *props;
 
701
 
 
702
        props = user_properties_get (user->bus, user->object_path);
 
703
        if (props != NULL) {
 
704
                if (user->props != NULL)
 
705
                        user_properties_free (user->props);
 
706
                user->props = props;
 
707
                return TRUE;
 
708
        }
 
709
        else {
 
710
                return FALSE;
 
711
        }
 
712
}
 
713
 
 
714
static void
 
715
changed_handler (DBusGProxy *proxy,
 
716
                 gpointer   *data)
 
717
{
 
718
        UmUser *user = UM_USER (data);
 
719
 
 
720
        if (update_info (user)) {
 
721
                if (user->display_name != NULL) {
 
722
                        um_user_show_full_display_name (user);
 
723
                }
 
724
 
 
725
                g_signal_emit (user, signals[CHANGED], 0);
 
726
        }
 
727
}
 
728
 
 
729
UmUser *
 
730
um_user_new_from_object_path (const gchar *object_path)
 
731
{
 
732
        UmUser *user;
 
733
        GError *error;
 
734
 
 
735
        user = (UmUser *)g_object_new (UM_TYPE_USER, NULL);
 
736
        user->object_path = g_strdup (object_path);
 
737
 
 
738
        error = NULL;
 
739
        user->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
 
740
        if (user->bus == NULL) {
 
741
                g_warning ("Couldn't connect to system bus: %s", error->message);
 
742
                goto error;
 
743
        }
 
744
 
 
745
        user->proxy = dbus_g_proxy_new_for_name (user->bus,
 
746
                                                 "org.freedesktop.Accounts",
 
747
                                                 user->object_path,
 
748
                                                 "org.freedesktop.Accounts.User");
 
749
        dbus_g_proxy_set_default_timeout (user->proxy, INT_MAX);
 
750
        dbus_g_proxy_add_signal (user->proxy, "Changed", G_TYPE_INVALID);
 
751
 
 
752
        dbus_g_proxy_connect_signal (user->proxy, "Changed",
 
753
                                     G_CALLBACK (changed_handler), user, NULL);
 
754
 
 
755
        if (!update_info (user))
 
756
                goto error;
 
757
 
 
758
        return user;
 
759
 
 
760
 error:
 
761
        g_object_unref (user);
 
762
        return NULL;
 
763
}
 
764
 
 
765
void
 
766
um_user_set_email (UmUser      *user,
 
767
                   const gchar *email)
 
768
{
 
769
        GError *error = NULL;
 
770
 
 
771
        if (!dbus_g_proxy_call (user->proxy,
 
772
                                "SetEmail",
 
773
                                &error,
 
774
                                G_TYPE_STRING, email,
 
775
                                G_TYPE_INVALID,
 
776
                                G_TYPE_INVALID)) {
 
777
                g_warning ("SetEmail call failed: %s", error->message);
 
778
                g_error_free (error);
 
779
                return;
 
780
        }
 
781
}
 
782
 
 
783
void
 
784
um_user_set_language (UmUser      *user,
 
785
                      const gchar *language)
 
786
{
 
787
        GError *error = NULL;
 
788
 
 
789
        if (!dbus_g_proxy_call (user->proxy,
 
790
                                "SetLanguage",
 
791
                                &error,
 
792
                                G_TYPE_STRING, language,
 
793
                                G_TYPE_INVALID,
 
794
                                G_TYPE_INVALID)) {
 
795
                g_warning ("SetLanguage call failed: %s", error->message);
 
796
                g_error_free (error);
 
797
                return;
 
798
        }
 
799
}
 
800
 
 
801
void
 
802
um_user_set_location (UmUser      *user,
 
803
                      const gchar *location)
 
804
{
 
805
        GError *error = NULL;
 
806
 
 
807
        if (!dbus_g_proxy_call (user->proxy,
 
808
                                "SetLocation",
 
809
                                &error,
 
810
                                G_TYPE_STRING, location,
 
811
                                G_TYPE_INVALID,
 
812
                                G_TYPE_INVALID)) {
 
813
                g_warning ("SetLocation call failed: %s", error->message);
 
814
                g_error_free (error);
 
815
                return;
 
816
        }
 
817
}
 
818
 
 
819
void
 
820
um_user_set_user_name (UmUser      *user,
 
821
                       const gchar *user_name)
 
822
{
 
823
        GError *error = NULL;
 
824
 
 
825
        if (!dbus_g_proxy_call (user->proxy,
 
826
                                "SetUserName",
 
827
                                &error,
 
828
                                G_TYPE_STRING, user_name,
 
829
                                G_TYPE_INVALID,
 
830
                                G_TYPE_INVALID)) {
 
831
                g_warning ("SetUserName call failed: %s", error->message);
 
832
                g_error_free (error);
 
833
                return;
 
834
        }
 
835
}
 
836
 
 
837
void
 
838
um_user_set_real_name (UmUser      *user,
 
839
                       const gchar *real_name)
 
840
{
 
841
        GError *error = NULL;
 
842
 
 
843
        if (!dbus_g_proxy_call (user->proxy,
 
844
                                "SetRealName",
 
845
                                &error,
 
846
                                G_TYPE_STRING, real_name,
 
847
                                G_TYPE_INVALID,
 
848
                                G_TYPE_INVALID)) {
 
849
                g_warning ("SetRealName call failed: %s", error->message);
 
850
                g_error_free (error);
 
851
                return;
 
852
        }
 
853
}
 
854
 
 
855
void
 
856
um_user_set_icon_file (UmUser      *user,
 
857
                       const gchar *icon_file)
 
858
{
 
859
        GError *error = NULL;
 
860
 
 
861
        if (!dbus_g_proxy_call (user->proxy,
 
862
                                "SetIconFile",
 
863
                                &error,
 
864
                                G_TYPE_STRING, icon_file,
 
865
                                G_TYPE_INVALID,
 
866
                                G_TYPE_INVALID)) {
 
867
                g_warning ("SetIconFile call failed: %s", error->message);
 
868
                g_error_free (error);
 
869
                return;
 
870
        }
 
871
}
 
872
 
 
873
void
 
874
um_user_set_icon_data (UmUser    *user,
 
875
                       GdkPixbuf *pixbuf)
 
876
{
 
877
        gchar *path;
 
878
        gint fd;
 
879
        GOutputStream *stream;
 
880
        GError *error;
 
881
 
 
882
        path = g_build_filename (g_get_tmp_dir (), "usericonXXXXXX", NULL);
 
883
        fd = g_mkstemp (path);
 
884
 
 
885
        if (fd == -1) {
 
886
                g_warning ("failed to create temporary file for image data");
 
887
                g_free (path);
 
888
                return;
 
889
        }
 
890
 
 
891
        stream = g_unix_output_stream_new (fd, TRUE);
 
892
 
 
893
        error = NULL;
 
894
        if (!gdk_pixbuf_save_to_stream (pixbuf, stream, "png", NULL, &error, NULL)) {
 
895
                g_warning ("failed to save image: %s", error->message);
 
896
                g_error_free (error);
 
897
                g_object_unref (stream);
 
898
                return;
 
899
        }
 
900
 
 
901
        g_object_unref (stream);
 
902
 
 
903
        um_user_set_icon_file (user, path);
 
904
 
 
905
        /* if we ever make the dbus call async, the g_remove call needs
 
906
         * to wait for its completion
 
907
         */
 
908
        g_remove (path);
 
909
 
 
910
        g_free (path);
 
911
}
 
912
 
 
913
void
 
914
um_user_set_account_type (UmUser *user,
 
915
                          gint    account_type)
 
916
{
 
917
        GError *error = NULL;
 
918
 
 
919
        if (!dbus_g_proxy_call (user->proxy,
 
920
                                "SetAccountType",
 
921
                                &error,
 
922
                                G_TYPE_INT, account_type,
 
923
                                G_TYPE_INVALID,
 
924
                                G_TYPE_INVALID)) {
 
925
                g_warning ("SetAccountType call failed: %s", error->message);
 
926
                g_error_free (error);
 
927
                return;
 
928
        }
 
929
}
 
930
 
 
931
static gchar
 
932
salt_char (GRand *rand)
 
933
{
 
934
        gchar salt[] = "ABCDEFGHIJKLMNOPQRSTUVXYZ"
 
935
                       "abcdefghijklmnopqrstuvxyz"
 
936
                       "./0123456789";
 
937
 
 
938
        return salt[g_rand_int_range (rand, 0, G_N_ELEMENTS (salt))];
 
939
}
 
940
 
 
941
static gchar *
 
942
make_crypted (const gchar *plain)
 
943
{
 
944
        GString *salt;
 
945
        gchar *result;
 
946
        GRand *rand;
 
947
        gint i;
 
948
 
 
949
        rand = g_rand_new ();
 
950
        salt = g_string_sized_new (21);
 
951
 
 
952
        /* SHA 256 */
 
953
        g_string_append (salt, "$6$");
 
954
        for (i = 0; i < 16; i++) {
 
955
                g_string_append_c (salt, salt_char (rand));
 
956
        }
 
957
        g_string_append_c (salt, '$');
 
958
 
 
959
        result = g_strdup (crypt (plain, salt->str));
 
960
 
 
961
        g_string_free (salt, TRUE);
 
962
        g_rand_free (rand);
 
963
 
 
964
        return result;
 
965
}
 
966
 
 
967
void
 
968
um_user_set_password (UmUser      *user,
 
969
                      gint         password_mode,
 
970
                      const gchar *password,
 
971
                      const gchar *hint)
 
972
{
 
973
        GError *error = NULL;
 
974
        gchar *crypted;
 
975
 
 
976
        if (password_mode == 0) {
 
977
                crypted = make_crypted (password);
 
978
                if (!dbus_g_proxy_call (user->proxy,
 
979
                                        "SetPassword",
 
980
                                        &error,
 
981
                                        G_TYPE_STRING, crypted,
 
982
                                        G_TYPE_STRING, hint,
 
983
                                        G_TYPE_INVALID,
 
984
                                        G_TYPE_INVALID)) {
 
985
                        g_warning ("SetPassword call failed: %s", error->message);
 
986
                        g_error_free (error);
 
987
                }
 
988
                memset (crypted, 0, strlen (crypted));
 
989
                g_free (crypted);
 
990
        }
 
991
        else if (password_mode == 3 || password_mode == 4) {
 
992
                if (!dbus_g_proxy_call (user->proxy,
 
993
                                        "SetLocked",
 
994
                                        &error,
 
995
                                        G_TYPE_BOOLEAN, (password_mode == 3),
 
996
                                        G_TYPE_INVALID,
 
997
                                        G_TYPE_INVALID)) {
 
998
                        g_warning ("SetLocked call failed: %s", error->message);
 
999
                        g_error_free (error);
 
1000
                }
 
1001
        }
 
1002
        else {
 
1003
                if (!dbus_g_proxy_call (user->proxy,
 
1004
                                        "SetPasswordMode",
 
1005
                                        &error,
 
1006
                                        G_TYPE_INT, password_mode,
 
1007
                                        G_TYPE_INVALID,
 
1008
                                        G_TYPE_INVALID)) {
 
1009
                        g_warning ("SetPasswordMode call failed: %s", error->message);
 
1010
                        g_error_free (error);
 
1011
                }
 
1012
        }
 
1013
}
 
1014
 
 
1015
gboolean
 
1016
um_user_is_logged_in (UmUser *user)
 
1017
{
 
1018
        DBusGProxy *proxy;
 
1019
        GPtrArray *array;
 
1020
        GError *error;
 
1021
        gint n_sessions;
 
1022
 
 
1023
        proxy = dbus_g_proxy_new_for_name (user->bus,
 
1024
                                           "org.freedesktop.ConsoleKit",
 
1025
                                           "/org/freedesktop/ConsoleKit/Manager",
 
1026
                                           "org.freedesktop.ConsoleKit.Manager");
 
1027
 
 
1028
        array = NULL;
 
1029
        error = NULL;
 
1030
        if (!dbus_g_proxy_call (proxy,
 
1031
                                "GetSessionsForUnixUser",
 
1032
                                &error,
 
1033
                                G_TYPE_UINT, um_user_get_uid (user),
 
1034
                                G_TYPE_INVALID,
 
1035
                                dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &array,
 
1036
                                G_TYPE_INVALID)) {
 
1037
                g_warning ("GetSessionsForUnixUser failed: %s", error->message);
 
1038
                g_error_free (error);
 
1039
                return FALSE;
 
1040
        }
 
1041
 
 
1042
        n_sessions = array->len;
 
1043
 
 
1044
        g_ptr_array_foreach (array, (GFunc)g_free, NULL);
 
1045
        g_ptr_array_free (array, TRUE);
 
1046
 
 
1047
        g_object_unref (proxy);
 
1048
 
 
1049
        return n_sessions > 0;
 
1050
}
 
1051
 
 
1052
 
 
1053
void
 
1054
um_user_set_automatic_login (UmUser   *user,
 
1055
                             gboolean  enabled)
 
1056
{
 
1057
        GError *error = NULL;
 
1058
 
 
1059
        if (!dbus_g_proxy_call (user->proxy,
 
1060
                                "SetAutomaticLogin",
 
1061
                                &error,
 
1062
                                G_TYPE_BOOLEAN, enabled,
 
1063
                                G_TYPE_INVALID,
 
1064
                                G_TYPE_INVALID)) {
 
1065
                g_warning ("SetAutomaticLogin call failed: %s", error->message);
 
1066
                g_error_free (error);
 
1067
        }
 
1068
}
 
1069
 
 
1070
void
 
1071
um_user_show_full_display_name (UmUser *user)
 
1072
{
 
1073
        char *uniq_name;
 
1074
 
 
1075
        g_return_if_fail (UM_IS_USER (user));
 
1076
 
 
1077
        if (user->props->real_name != NULL) {
 
1078
                uniq_name = g_strdup_printf ("%s (%s)",
 
1079
                                             user->props->real_name,
 
1080
                                             user->props->user_name);
 
1081
        } else {
 
1082
                uniq_name = NULL;
 
1083
        }
 
1084
 
 
1085
        if (uniq_name && g_strcmp0 (uniq_name, user->display_name) != 0) {
 
1086
                g_free (user->display_name);
 
1087
                user->display_name = uniq_name;
 
1088
        }
 
1089
        else {
 
1090
                g_free (uniq_name);
 
1091
        }
 
1092
}
 
1093
 
 
1094
void
 
1095
um_user_show_short_display_name (UmUser *user)
 
1096
{
 
1097
        g_return_if_fail (UM_IS_USER (user));
 
1098
 
 
1099
        if (user->display_name) {
 
1100
                g_free (user->display_name);
 
1101
                user->display_name = NULL;
 
1102
        }
 
1103
}
 
1104