source: proiecte/PPPP/gdm/debian/patches/09_gdmsetup.patch @ 134

Last change on this file since 134 was 134, checked in by (none), 14 years ago

gdm sources with the modifications for webcam

File size: 133.9 KB
  • configure.ac

    #
    # Description: Add GDM Setup
    # Ubuntu: https://bugs.launchpad.net/ubuntu/+source/gdm/+bug/395299
    # Upstream: http://bugzilla.gnome.org/show_bug.cgi?id=587750
    #
    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/configure.ac gdm-2.28.0.new/configure.ac
    old new  
    107107AC_SUBST(GCONF_CFLAGS)
    108108AC_SUBST(GCONF_LIBS)
    109109
     110PKG_CHECK_MODULES(GDMSETUP,
     111        dbus-glib-1 >= $DBUS_GLIB_REQUIRED_VERSION
     112        gtk+-2.0 >= $GTK_REQUIRED_VERSION
     113        gmodule-2.0
     114)
     115AC_SUBST(GDMSETUP_CFLAGS)
     116AC_SUBST(GDMSETUP_LIBS)
     117
    110118PKG_CHECK_MODULES(SIMPLE_GREETER,
    111119        dbus-glib-1 >= $DBUS_GLIB_REQUIRED_VERSION
    112120        gtk+-2.0 >= $GTK_REQUIRED_VERSION
     
    13521360daemon/Makefile
    13531361docs/Makefile
    13541362gui/Makefile
     1363gui/gdmsetup/Makefile
    13551364gui/simple-greeter/Makefile
    13561365gui/simple-greeter/libnotificationarea/Makefile
    13571366gui/simple-chooser/Makefile
    13581367gui/user-switch-applet/Makefile
    13591368utils/Makefile
    13601369data/gdm.conf
     1370data/gdm.policy
    13611371data/Makefile
    13621372data/faces/Makefile
    13631373data/greeter-autostart/Makefile
  • gui/gdmsetup/gdmsetup.c

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/gui/gdmsetup/gdmsetup.c gdm-2.28.0.new/gui/gdmsetup/gdmsetup.c
    old new  
     1#ifdef HAVE_CONFIG_H
     2#include "config.h"
     3#endif
     4
     5#include <string.h>
     6#include <stdlib.h>
     7#include <gtk/gtk.h>
     8#include <gdk/gdkkeysyms.h>
     9#include <dbus/dbus-glib.h>
     10#include <glib/gi18n.h>
     11
     12#include "gdm-user-manager.h"
     13
     14#define MAX_USERS_IN_COMBO_BOX 20
     15
     16/* User interface */
     17static GtkBuilder *ui;
     18static GtkWidget *dialog, *unlock_button, *option_vbox;
     19static GtkWidget *user_combo, *user_entry, *delay_spin;
     20static GtkWidget *auto_login_radio, *login_delay_box, *login_delay_check;
     21
     22/* Timer to delay application of configuration */
     23static guint apply_timeout = 0;
     24
     25/* Flag to show when information is loaded */
     26static gboolean loaded = FALSE;
     27
     28/* Flag to show when information is loaded */
     29static gboolean locked = TRUE;
     30
     31/* True if the user selection method is a combo box, False if an entry */
     32static gboolean user_list_is_combo = TRUE;
     33
     34/* User information */
     35static GdmUserManager *user_manager;
     36
     37/* Proxy to GDM settings */
     38static DBusGProxy *proxy = NULL;
     39
     40
     41static gchar *
     42get_value (const gchar *key, gchar *def)
     43{
     44    gchar *value;
     45    GError *error = NULL;
     46   
     47    if (!dbus_g_proxy_call (proxy, "GetValue", &error,
     48                            G_TYPE_STRING, key, G_TYPE_INVALID,
     49                            G_TYPE_STRING, &value, G_TYPE_INVALID)) {
     50        g_warning ("Error calling GetValue('%s'): %s", key, error->message);
     51        return def;
     52    }
     53   
     54    return value;
     55}
     56
     57
     58static gboolean
     59set_value (const gchar *key, const gchar *value)
     60{
     61    GError *error = NULL;
     62   
     63    dbus_g_proxy_call (proxy, "SetValue", &error,
     64                       G_TYPE_STRING, key,
     65                       G_TYPE_STRING, value, G_TYPE_INVALID, G_TYPE_INVALID);
     66    if (error) {
     67        g_warning ("Error calling SetValue('%s', '%s'): %s", key, value, error->message);
     68        return FALSE;
     69    }
     70   
     71    return TRUE;
     72}
     73
     74
     75static gboolean
     76get_boolean_value (const gchar *key, gboolean def)
     77{
     78    gchar *value;
     79    gboolean result;
     80   
     81    value = get_value (key, NULL);
     82    if (!value)
     83        return def;
     84    result = strcmp (value, "true") == 0;
     85    g_free (value);
     86    return result;
     87}
     88
     89
     90static gint
     91get_integer_value (const gchar *key, gint def)
     92{
     93    gchar *value;
     94    gint result;
     95    char *end;
     96   
     97    value = get_value (key, NULL);
     98    if (!value || value[0] == '\0')
     99        result = def;
     100    else {
     101        result = strtol (value, &end, 10);
     102        if (*end != '\0')
     103            result = def;
     104    }
     105
     106    if (value)
     107        g_free (value);
     108    return result;
     109}
     110
     111
     112static gboolean
     113set_boolean_value (const gchar *key, gboolean value)
     114{
     115    return set_value (key, value ? "true" : "false");
     116}
     117
     118
     119static gboolean
     120set_integer_value (const gchar *key, gint value)
     121{
     122    char value_string[1024];
     123    snprintf(value_string, 1024, "%d", value);
     124    return set_value (key, value_string);
     125}
     126
     127
     128static void
     129update_config ()
     130{
     131    GtkTreeModel *model;
     132    GtkTreeIter iter;
     133    gchar *user = NULL;
     134    gint delay = 0;
     135    gboolean auto_login = FALSE, timed_login = FALSE, error = FALSE;
     136   
     137    if (apply_timeout != 0) {
     138        g_source_remove (apply_timeout);
     139        apply_timeout = 0;
     140    }
     141
     142    if (user_list_is_combo) {
     143        model = gtk_combo_box_get_model (GTK_COMBO_BOX (user_combo));
     144        if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (user_combo), &iter))
     145            gtk_tree_model_get (model, &iter, 1, &user, -1);
     146    }
     147    else
     148        user = g_strdup (gtk_entry_get_text (GTK_ENTRY (user_entry)));
     149
     150    if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (auto_login_radio))) {
     151        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (login_delay_check)))
     152            timed_login = TRUE;
     153        else
     154            auto_login = TRUE;
     155    }
     156   
     157    delay = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (delay_spin));
     158
     159    g_debug ("set user='%s', auto=%s, timed=%s, delay=%d",
     160             user,
     161             auto_login ? "True" : "False",
     162             timed_login ? "True" : "False", delay);
     163   
     164    if (!set_boolean_value ("daemon/TimedLoginEnable", timed_login) ||
     165        !set_boolean_value ("daemon/AutomaticLoginEnable", auto_login) ||
     166        !set_value ("daemon/TimedLogin", user) ||
     167        !set_value ("daemon/AutomaticLogin", user) ||   
     168        !set_integer_value ("daemon/TimedLoginDelay", delay))
     169        error = FALSE;
     170
     171    if (user)
     172        g_free (user);
     173}
     174
     175
     176G_MODULE_EXPORT
     177void
     178gdm_capplet_response_cb (GtkWidget *widget, gint response_id)
     179{
     180    if (response_id != 1)
     181        gtk_main_quit ();
     182}
     183
     184
     185static void
     186unlock_response_cb (DBusGProxy     *proxy,
     187                    DBusGProxyCall *call_id,
     188                    void           *user_data)
     189{
     190    gboolean is_unlocked;
     191    GError *error = NULL;
     192   
     193    dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_BOOLEAN, &is_unlocked, G_TYPE_INVALID);
     194    if (error) {
     195        g_warning ("Failed to unlock: %s", error->message);
     196        g_error_free (error);
     197        return;
     198    }
     199   
     200    if (!is_unlocked)
     201        return;
     202   
     203    locked = FALSE;
     204    gtk_widget_set_sensitive (unlock_button, FALSE);
     205    gtk_widget_set_sensitive (option_vbox, loaded && !locked);
     206}
     207
     208
     209G_MODULE_EXPORT
     210void
     211unlock_button_clicked_cb (GtkWidget *widget)
     212{
     213    dbus_g_proxy_begin_call (proxy, "Unlock", unlock_response_cb, NULL, NULL, G_TYPE_INVALID);
     214}
     215
     216
     217G_MODULE_EXPORT
     218void
     219login_delay_check_toggled_cb (GtkWidget *widget)
     220{
     221    gtk_widget_set_sensitive (delay_spin,
     222                              gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (login_delay_check)));
     223   
     224    if (loaded)
     225        update_config ();
     226}
     227
     228
     229static gboolean
     230delayed_apply_cb ()
     231{
     232    update_config ();
     233    return FALSE;
     234}
     235
     236
     237G_MODULE_EXPORT
     238void
     239apply_config_cb (GtkWidget *widget)
     240{
     241    if (loaded) {
     242        if (apply_timeout != 0)
     243            g_source_remove (apply_timeout);
     244        apply_timeout = g_timeout_add (200, (GSourceFunc)delayed_apply_cb, NULL);
     245    }
     246}
     247
     248
     249static void
     250init_login_delay ()
     251{
     252    gint delay;
     253   
     254    if (get_boolean_value ("daemon/TimedLoginEnable", FALSE))
     255        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (login_delay_check), TRUE);
     256   
     257    delay = get_integer_value ("daemon/TimedLoginDelay", 30);
     258
     259    g_debug ("init delay=%d", delay);
     260
     261    gtk_spin_button_set_value (GTK_SPIN_BUTTON (delay_spin), delay);
     262}
     263
     264
     265G_MODULE_EXPORT
     266void
     267automatic_login_toggle_cb (GtkWidget *automatic_login_toggle)   
     268{
     269    gboolean automatic_login;
     270
     271    automatic_login = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (automatic_login_toggle));
     272    gtk_widget_set_sensitive (login_delay_box, automatic_login);
     273    gtk_widget_set_sensitive (user_combo, automatic_login);
     274    gtk_widget_set_sensitive (user_entry, automatic_login);
     275   
     276    if (loaded)
     277        update_config ();
     278}
     279
     280
     281G_MODULE_EXPORT
     282void
     283default_user_combo_box_changed_cb (void)
     284{
     285    if (loaded) {
     286        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (auto_login_radio), TRUE);
     287        update_config ();
     288    }
     289}
     290
     291
     292static void
     293init_default_user (void)
     294{
     295    GtkTreeModel *model;
     296    GtkTreeIter iter;
     297    gboolean auto_login, timed_login, active;
     298    gchar *user = NULL;
     299   
     300    auto_login = get_boolean_value ("daemon/AutomaticLoginEnable", FALSE);
     301    timed_login = get_boolean_value ("daemon/TimedLoginEnable", FALSE);
     302   
     303    if (auto_login)
     304        user = get_value ("daemon/AutomaticLogin", NULL);
     305    if (user == NULL)
     306        user = get_value ("daemon/TimedLogin", NULL);
     307
     308    g_debug ("init user='%s' auto=%s", user, auto_login || timed_login ? "True" : "False");
     309
     310    if (auto_login || timed_login)
     311        gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (auto_login_radio), TRUE);
     312   
     313    if (!user_list_is_combo) {
     314        if (user != NULL)
     315            gtk_entry_set_text (GTK_ENTRY (user_entry), user);
     316    }
     317    else {
     318        model = gtk_combo_box_get_model (GTK_COMBO_BOX (user_combo));
     319        active = gtk_tree_model_get_iter_first (model, &iter);
     320       
     321        /* If no user then use first available */
     322        if (user == NULL) {
     323            if (active)
     324                gtk_combo_box_set_active_iter (GTK_COMBO_BOX (user_combo), &iter);
     325        }
     326        else {
     327            while (user != NULL && active) {
     328                gchar *u;
     329                gboolean matched;
     330           
     331                gtk_tree_model_get (model, &iter, 1, &u, -1);
     332                matched = strcmp (user, u) == 0;
     333                g_free (u);
     334                if (matched) {
     335                    gtk_combo_box_set_active_iter (GTK_COMBO_BOX (user_combo), &iter);
     336                    break;
     337                }
     338           
     339                active = gtk_tree_model_iter_next (model, &iter);
     340            }
     341        }
     342    }
     343   
     344    g_free (user);
     345}
     346
     347
     348static void add_user (GdmUser *user)
     349{
     350    GtkListStore *model;
     351    GtkTreeIter iter;
     352    GString *label;   
     353
     354    model = GTK_LIST_STORE (gtk_builder_get_object (ui, "login_user_model"));
     355    gtk_list_store_append (model, &iter);
     356    label = g_string_new("");
     357    g_string_printf (label, "%s (%s)", gdm_user_get_real_name (user), gdm_user_get_user_name (user));
     358    gtk_list_store_set (model, &iter,
     359                        0, label->str,
     360                        1, gdm_user_get_user_name (user),
     361                        -1);
     362    g_string_free (label, TRUE);
     363}
     364
     365
     366static void
     367users_loaded_cb(GdmUserManager *manager)
     368{
     369    GSList *users, *item;
     370
     371    users = gdm_user_manager_list_users (user_manager);
     372   
     373    if (g_slist_length (users) > MAX_USERS_IN_COMBO_BOX) {
     374        user_list_is_combo = FALSE;
     375        gtk_widget_hide (user_combo);
     376        gtk_widget_show (user_entry);
     377    }
     378    else {
     379        for (item = users; item; item = item->next)
     380            add_user ((GdmUser *) item->data);
     381    }
     382
     383    init_default_user ();
     384
     385    loaded = TRUE;
     386    gtk_widget_set_sensitive (option_vbox, loaded && !locked);
     387}
     388
     389
     390static void
     391user_added_cb (GdmUserManager *manager, GdmUser *user)
     392{
     393    if (loaded)
     394        add_user (user);
     395}
     396
     397
     398static void
     399split_text (const gchar *text, const gchar *prefix_label_name, const gchar *suffix_label_name)
     400{
     401    gchar **tokens;
     402    GtkWidget *prefix_label, *suffix_label;
     403   
     404    prefix_label = GTK_WIDGET (gtk_builder_get_object (ui, prefix_label_name));
     405    suffix_label = GTK_WIDGET (gtk_builder_get_object (ui, suffix_label_name));
     406   
     407    tokens = g_strsplit (text, "%s", 2);
     408    if (tokens[0] != NULL && tokens[1] != NULL) {
     409        if (tokens[0][0] != '\0')
     410            gtk_label_set_text (GTK_LABEL (prefix_label), g_strstrip (tokens[0]));
     411        else
     412            gtk_widget_hide (prefix_label);
     413        if (tokens[1][0] != '\0')
     414            gtk_label_set_text (GTK_LABEL (suffix_label), g_strstrip (tokens[1]));
     415        else
     416            gtk_widget_hide (suffix_label);
     417    }
     418    g_strfreev (tokens);
     419}
     420
     421
     422int main (int argc, char **argv)
     423{
     424    GtkCellRenderer *renderer;
     425    DBusGConnection *connection;   
     426    GError *error = NULL;
     427   
     428    bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
     429    bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
     430    textdomain (GETTEXT_PACKAGE);
     431
     432    gtk_init (&argc, &argv);
     433   
     434    connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
     435    if (error) {
     436        g_warning ("Failed to get system bus: %s", error->message);
     437        return 1;
     438    }
     439    proxy = dbus_g_proxy_new_for_name (connection,
     440                                       "org.gnome.DisplayManager",
     441                                       "/org/gnome/DisplayManager/Settings",
     442                                       "org.gnome.DisplayManager.Settings");
     443
     444    ui = gtk_builder_new ();
     445    gtk_builder_add_from_file (ui, UIDIR "/gdmsetup.ui", &error);
     446    if (error) {
     447        g_warning ("Failed to load UI: %s", error->message);
     448        return 1;
     449    }
     450    dialog = GTK_WIDGET (gtk_builder_get_object (ui, "gdm_capplet"));
     451    unlock_button = GTK_WIDGET (gtk_builder_get_object (ui, "unlock_button"));
     452    option_vbox = GTK_WIDGET (gtk_builder_get_object (ui, "gdm_capplet_vbox"));
     453    user_combo = GTK_WIDGET (gtk_builder_get_object (ui, "default_user_combo_box"));
     454    user_entry = GTK_WIDGET (gtk_builder_get_object (ui, "default_user_entry"));
     455    delay_spin = GTK_WIDGET (gtk_builder_get_object (ui, "login_delay_spin"));
     456    auto_login_radio = GTK_WIDGET (gtk_builder_get_object (ui, "automatic_login_radio"));
     457    login_delay_box = GTK_WIDGET (gtk_builder_get_object (ui, "login_delay_box"));
     458    login_delay_check = GTK_WIDGET (gtk_builder_get_object (ui, "login_delay_check"));
     459    gtk_builder_connect_signals (ui, NULL);
     460
     461    /* Translators: Label for choosing which user to log in as. '%s' is replaced with an input field. */
     462    split_text (_("Log in as %s automatically"), "user_prefix_label", "user_suffix_label");
     463    /* Translators: Label for choosing the login delay. '%s' is replaced with an input field. */
     464    split_text (_("Allow %s seconds for anyone else to log in first"), "delay_prefix_label", "delay_suffix_label");
     465   
     466    init_login_delay ();
     467
     468    renderer = gtk_cell_renderer_text_new ();
     469    gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (user_combo), renderer, TRUE);
     470    gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (user_combo), renderer, "text", 0);
     471
     472    user_manager = gdm_user_manager_ref_default ();
     473    g_signal_connect (user_manager, "users-loaded", G_CALLBACK (users_loaded_cb), NULL);
     474    g_signal_connect (user_manager, "user-added", G_CALLBACK (user_added_cb), NULL);
     475   
     476    gtk_widget_hide (user_entry);
     477
     478    gtk_widget_set_sensitive (option_vbox, FALSE);
     479    gtk_widget_show (dialog);
     480
     481    gtk_main ();
     482   
     483    return 0;
     484}
  • gui/gdmsetup/gdmsetup.desktop.in

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/gui/gdmsetup/gdmsetup.desktop.in gdm-2.28.0.new/gui/gdmsetup/gdmsetup.desktop.in
    old new  
     1[Desktop Entry]
     2_Name=Login Screen
     3_Comment=Configure login screen behavior
     4Exec=gdmsetup
     5Icon=gdm-setup
     6StartupNotify=true
     7Terminal=false
     8Type=Application
     9Categories=GNOME;GTK;Settings;System;
     10X-GNOME-Bugzilla-Bugzilla=GNOME
     11X-GNOME-Bugzilla-Product=gdm
     12X-GNOME-Bugzilla-Component=general
  • gui/gdmsetup/gdmsetup.ui

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/gui/gdmsetup/gdmsetup.ui gdm-2.28.0.new/gui/gdmsetup/gdmsetup.ui
    old new  
     1<?xml version="1.0"?>
     2<interface>
     3  <requires lib="gtk+" version="2.16"/>
     4  <!-- interface-naming-policy project-wide -->
     5  <object class="GtkListStore" id="login_user_model">
     6    <columns>
     7      <!-- column-name label -->
     8      <column type="gchararray"/>
     9      <!-- column-name user -->
     10      <column type="gchararray"/>
     11      <!-- column-name icon -->
     12      <column type="GdkPixbuf"/>
     13    </columns>
     14  </object>
     15  <object class="GtkDialog" id="gdm_capplet">
     16    <property name="border_width">5</property>
     17    <property name="title" translatable="yes" comments="Title of login screen settings dialog">Login Screen Settings</property>
     18    <property name="resizable">False</property>
     19    <property name="window_position">center</property>
     20    <property name="icon_name">gdm-setup</property>
     21    <property name="type_hint">normal</property>
     22    <property name="has_separator">False</property>
     23    <signal name="response" handler="gdm_capplet_response_cb"/>
     24    <child internal-child="vbox">
     25      <object class="GtkVBox" id="dialog-vbox1">
     26        <property name="visible">True</property>
     27        <property name="orientation">vertical</property>
     28        <property name="spacing">12</property>
     29        <child>
     30          <object class="GtkVBox" id="gdm_capplet_vbox">
     31            <property name="visible">True</property>
     32            <property name="orientation">vertical</property>
     33            <property name="spacing">18</property>
     34            <child>
     35              <object class="GtkLabel" id="intro_label">
     36                <property name="visible">True</property>
     37                <property name="xalign">0</property>
     38                <property name="label" translatable="yes" comments="Description above login option radio buttons">When the computer starts up:</property>
     39              </object>
     40              <packing>
     41                <property name="expand">False</property>
     42                <property name="position">0</property>
     43              </packing>
     44            </child>
     45            <child>
     46              <object class="GtkVBox" id="vbox3">
     47                <property name="visible">True</property>
     48                <property name="orientation">vertical</property>
     49                <property name="spacing">12</property>
     50                <child>
     51                  <object class="GtkRadioButton" id="manual_login_radio">
     52                    <property name="label" translatable="yes" comments="Radio option to set login screen to prompt for user">_Show the screen for choosing who will log in</property>
     53                    <property name="visible">True</property>
     54                    <property name="can_focus">True</property>
     55                    <property name="receives_default">False</property>
     56                    <property name="use_underline">True</property>
     57                    <property name="active">True</property>
     58                    <property name="draw_indicator">True</property>
     59                  </object>
     60                  <packing>
     61                    <property name="expand">False</property>
     62                    <property name="position">0</property>
     63                  </packing>
     64                </child>
     65                <child>
     66                  <object class="GtkVBox" id="vbox4">
     67                    <property name="visible">True</property>
     68                    <property name="orientation">vertical</property>
     69                    <property name="spacing">6</property>
     70                    <child>
     71                      <object class="GtkHBox" id="hbox1">
     72                        <property name="visible">True</property>
     73                        <property name="spacing">6</property>
     74                        <child>
     75                          <object class="GtkRadioButton" id="automatic_login_radio">
     76                            <property name="visible">True</property>
     77                            <property name="can_focus">True</property>
     78                            <property name="receives_default">False</property>
     79                            <property name="draw_indicator">True</property>
     80                            <property name="group">manual_login_radio</property>
     81                            <signal name="toggled" handler="automatic_login_toggle_cb"/>
     82                            <child>
     83                              <object class="GtkLabel" id="user_prefix_label">
     84                                <property name="visible">True</property>
     85                                <property name="label">_Log in as</property>
     86                                <property name="use_underline">True</property>
     87                              </object>
     88                            </child>
     89                          </object>
     90                          <packing>
     91                            <property name="expand">False</property>
     92                            <property name="position">0</property>
     93                          </packing>
     94                        </child>
     95                        <child>
     96                          <object class="GtkComboBox" id="default_user_combo_box">
     97                            <property name="visible">True</property>
     98                            <property name="sensitive">False</property>
     99                            <property name="model">login_user_model</property>
     100                            <signal name="changed" handler="default_user_combo_box_changed_cb"/>
     101                          </object>
     102                          <packing>
     103                            <property name="expand">False</property>
     104                            <property name="position">1</property>
     105                          </packing>
     106                        </child>
     107                        <child>
     108                          <object class="GtkEntry" id="default_user_entry">
     109                            <property name="visible">True</property>
     110                            <property name="sensitive">False</property>
     111                            <property name="can_focus">True</property>
     112                            <property name="invisible_char">&#x2022;</property>
     113                            <signal name="changed" handler="apply_config_cb"/>
     114                          </object>
     115                          <packing>
     116                            <property name="position">2</property>
     117                          </packing>
     118                        </child>
     119                        <child>
     120                          <object class="GtkLabel" id="user_suffix_label">
     121                            <property name="visible">True</property>
     122                            <property name="label">automatically</property>
     123                          </object>
     124                          <packing>
     125                            <property name="expand">False</property>
     126                            <property name="position">3</property>
     127                          </packing>
     128                        </child>
     129                      </object>
     130                      <packing>
     131                        <property name="expand">False</property>
     132                        <property name="position">0</property>
     133                      </packing>
     134                    </child>
     135                    <child>
     136                      <object class="GtkAlignment" id="alignment1">
     137                        <property name="visible">True</property>
     138                        <property name="left_padding">16</property>
     139                        <child>
     140                          <object class="GtkHBox" id="login_delay_box">
     141                            <property name="visible">True</property>
     142                            <property name="sensitive">False</property>
     143                            <property name="spacing">6</property>
     144                            <child>
     145                              <object class="GtkCheckButton" id="login_delay_check">
     146                                <property name="visible">True</property>
     147                                <property name="can_focus">True</property>
     148                                <property name="receives_default">False</property>
     149                                <property name="draw_indicator">True</property>
     150                                <signal name="toggled" handler="login_delay_check_toggled_cb"/>
     151                                <child>
     152                                  <object class="GtkLabel" id="delay_prefix_label">
     153                                    <property name="visible">True</property>
     154                                    <property name="label">_Allow</property>
     155                                    <property name="use_underline">True</property>
     156                                  </object>
     157                                </child>
     158                              </object>
     159                              <packing>
     160                                <property name="expand">False</property>
     161                                <property name="position">0</property>
     162                              </packing>
     163                            </child>
     164                            <child>
     165                              <object class="GtkSpinButton" id="login_delay_spin">
     166                                <property name="visible">True</property>
     167                                <property name="sensitive">False</property>
     168                                <property name="can_focus">True</property>
     169                                <property name="invisible_char">&#x2022;</property>
     170                                <property name="adjustment">adjustment1</property>
     171                                <signal name="value_changed" handler="apply_config_cb"/>
     172                              </object>
     173                              <packing>
     174                                <property name="position">1</property>
     175                              </packing>
     176                            </child>
     177                            <child>
     178                              <object class="GtkLabel" id="delay_suffix_label">
     179                                <property name="visible">True</property>
     180                                <property name="label">seconds for anyone else to log in first</property>
     181                              </object>
     182                              <packing>
     183                                <property name="expand">False</property>
     184                                <property name="position">2</property>
     185                              </packing>
     186                            </child>
     187                          </object>
     188                        </child>
     189                      </object>
     190                      <packing>
     191                        <property name="expand">False</property>
     192                        <property name="position">1</property>
     193                      </packing>
     194                    </child>
     195                  </object>
     196                  <packing>
     197                    <property name="expand">False</property>
     198                    <property name="position">1</property>
     199                  </packing>
     200                </child>
     201              </object>
     202              <packing>
     203                <property name="expand">False</property>
     204                <property name="position">1</property>
     205              </packing>
     206            </child>
     207          </object>
     208          <packing>
     209            <property name="position">1</property>
     210          </packing>
     211        </child>
     212        <child internal-child="action_area">
     213          <object class="GtkHButtonBox" id="dialog-action_area1">
     214            <property name="visible">True</property>
     215            <property name="layout_style">end</property>
     216            <child>
     217              <object class="GtkButton" id="unlock_button">
     218                <property name="label" translatable="yes">_Unlock</property>
     219                <property name="visible">True</property>
     220                <property name="can_focus">True</property>
     221                <property name="receives_default">True</property>
     222                <property name="image">image1</property>
     223                <property name="use_underline">True</property>
     224                <signal name="clicked" handler="unlock_button_clicked_cb"/>
     225              </object>
     226              <packing>
     227                <property name="expand">False</property>
     228                <property name="fill">False</property>
     229                <property name="position">0</property>
     230              </packing>
     231            </child>
     232            <child>
     233              <object class="GtkButton" id="close_button">
     234                <property name="label">gtk-close</property>
     235                <property name="visible">True</property>
     236                <property name="can_focus">True</property>
     237                <property name="receives_default">True</property>
     238                <property name="use_stock">True</property>
     239              </object>
     240              <packing>
     241                <property name="expand">False</property>
     242                <property name="fill">False</property>
     243                <property name="position">1</property>
     244              </packing>
     245            </child>
     246          </object>
     247          <packing>
     248            <property name="expand">False</property>
     249            <property name="pack_type">end</property>
     250            <property name="position">0</property>
     251          </packing>
     252        </child>
     253      </object>
     254    </child>
     255    <action-widgets>
     256      <action-widget response="1">unlock_button</action-widget>
     257      <action-widget response="-7">close_button</action-widget>
     258    </action-widgets>
     259  </object>
     260  <object class="GtkImage" id="image1">
     261    <property name="visible">True</property>
     262    <property name="stock">gtk-dialog-authentication</property>
     263  </object>
     264  <object class="GtkSizeGroup" id="combo_size_group"/>
     265  <object class="GtkSizeGroup" id="radio_size_group"/>
     266  <object class="GtkAdjustment" id="adjustment1">
     267    <property name="lower">1</property>
     268    <property name="upper">600</property>
     269    <property name="step_increment">1</property>
     270  </object>
     271</interface>
  • gui/gdmsetup/gdm-user.c

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/gui/gdmsetup/gdm-user.c gdm-2.28.0.new/gui/gdmsetup/gdm-user.c
    old new  
     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 *
     6 * This program is free software; you can redistribute it and/or modify
     7 * it under the terms of the GNU General Public License as published by
     8 * the Free Software Foundation; either version 2 of the License, or
     9 * (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this program; if not, write to the Free Software
     18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     19 */
     20
     21#include <config.h>
     22
     23#include <float.h>
     24#include <string.h>
     25#include <sys/types.h>
     26#include <sys/stat.h>
     27#include <unistd.h>
     28
     29#include <glib/gi18n.h>
     30#include <gio/gio.h>
     31#include <gtk/gtk.h>
     32
     33#include "gdm-user-manager.h"
     34#include "gdm-user-private.h"
     35
     36#define GDM_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_USER, GdmUserClass))
     37#define GDM_IS_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_USER))
     38#define GDM_USER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), GDM_TYPE_USER, GdmUserClass))
     39
     40#define GLOBAL_FACEDIR    DATADIR "/faces"
     41#define MAX_ICON_SIZE     128
     42#define MAX_FILE_SIZE     65536
     43#define MINIMAL_UID       100
     44#define RELAX_GROUP       TRUE
     45#define RELAX_OTHER       TRUE
     46
     47enum {
     48        PROP_0,
     49        PROP_MANAGER,
     50        PROP_REAL_NAME,
     51        PROP_USER_NAME,
     52        PROP_UID,
     53        PROP_HOME_DIR,
     54        PROP_SHELL,
     55        PROP_LOGIN_FREQUENCY,
     56};
     57
     58enum {
     59        ICON_CHANGED,
     60        SESSIONS_CHANGED,
     61        LAST_SIGNAL
     62};
     63
     64struct _GdmUser {
     65        GObject         parent;
     66
     67        GdmUserManager *manager;
     68
     69        uid_t           uid;
     70        char           *user_name;
     71        char           *real_name;
     72        char           *home_dir;
     73        char           *shell;
     74        GList          *sessions;
     75        gulong          login_frequency;
     76
     77        GFileMonitor   *icon_monitor;
     78};
     79
     80typedef struct _GdmUserClass
     81{
     82        GObjectClass parent_class;
     83
     84        void (* icon_changed)     (GdmUser *user);
     85        void (* sessions_changed) (GdmUser *user);
     86} GdmUserClass;
     87
     88static void gdm_user_finalize     (GObject      *object);
     89
     90static guint signals[LAST_SIGNAL] = { 0 };
     91
     92G_DEFINE_TYPE (GdmUser, gdm_user, G_TYPE_OBJECT)
     93
     94static int
     95session_compare (const char *a,
     96                 const char *b)
     97{
     98        if (a == NULL) {
     99                return 1;
     100        } else if (b == NULL) {
     101                return -1;
     102        }
     103
     104        return strcmp (a, b);
     105}
     106
     107void
     108_gdm_user_add_session (GdmUser    *user,
     109                       const char *ssid)
     110{
     111        GList *li;
     112
     113        g_return_if_fail (GDM_IS_USER (user));
     114        g_return_if_fail (ssid != NULL);
     115
     116        li = g_list_find_custom (user->sessions, ssid, (GCompareFunc)session_compare);
     117        if (li == NULL) {
     118                g_debug ("GdmUser: adding session %s", ssid);
     119                user->sessions = g_list_prepend (user->sessions, g_strdup (ssid));
     120                g_signal_emit (user, signals[SESSIONS_CHANGED], 0);
     121        } else {
     122                g_debug ("GdmUser: session already present: %s", ssid);
     123        }
     124}
     125
     126void
     127_gdm_user_remove_session (GdmUser    *user,
     128                          const char *ssid)
     129{
     130        GList *li;
     131
     132        g_return_if_fail (GDM_IS_USER (user));
     133        g_return_if_fail (ssid != NULL);
     134
     135        li = g_list_find_custom (user->sessions, ssid, (GCompareFunc)session_compare);
     136        if (li != NULL) {
     137                g_debug ("GdmUser: removing session %s", ssid);
     138                g_free (li->data);
     139                user->sessions = g_list_delete_link (user->sessions, li);
     140                g_signal_emit (user, signals[SESSIONS_CHANGED], 0);
     141        } else {
     142                g_debug ("GdmUser: session not found: %s", ssid);
     143        }
     144}
     145
     146guint
     147gdm_user_get_num_sessions (GdmUser    *user)
     148{
     149        return g_list_length (user->sessions);
     150}
     151
     152GList *
     153gdm_user_get_sessions (GdmUser *user)
     154{
     155        return user->sessions;
     156}
     157
     158static void
     159_gdm_user_set_login_frequency (GdmUser *user,
     160                               gulong   login_frequency)
     161{
     162        user->login_frequency = login_frequency;
     163        g_object_notify (G_OBJECT (user), "login-frequency");
     164}
     165
     166static void
     167gdm_user_set_property (GObject      *object,
     168                       guint         param_id,
     169                       const GValue *value,
     170                       GParamSpec   *pspec)
     171{
     172        GdmUser *user;
     173
     174        user = GDM_USER (object);
     175
     176        switch (param_id) {
     177        case PROP_MANAGER:
     178                user->manager = g_value_get_object (value);
     179                g_assert (user->manager);
     180                break;
     181        case PROP_LOGIN_FREQUENCY:
     182                _gdm_user_set_login_frequency (user, g_value_get_ulong (value));
     183                break;
     184        default:
     185                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
     186                break;
     187        }
     188}
     189
     190static void
     191gdm_user_get_property (GObject    *object,
     192                       guint       param_id,
     193                       GValue     *value,
     194                       GParamSpec *pspec)
     195{
     196        GdmUser *user;
     197
     198        user = GDM_USER (object);
     199
     200        switch (param_id) {
     201        case PROP_MANAGER:
     202                g_value_set_object (value, user->manager);
     203                break;
     204        case PROP_USER_NAME:
     205                g_value_set_string (value, user->user_name);
     206                break;
     207        case PROP_REAL_NAME:
     208                g_value_set_string (value, user->real_name);
     209                break;
     210        case PROP_HOME_DIR:
     211                g_value_set_string (value, user->home_dir);
     212                break;
     213        case PROP_UID:
     214                g_value_set_ulong (value, user->uid);
     215                break;
     216        case PROP_SHELL:
     217                g_value_set_string (value, user->shell);
     218                break;
     219        case PROP_LOGIN_FREQUENCY:
     220                g_value_set_ulong (value, user->login_frequency);
     221                break;
     222        default:
     223                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
     224                break;
     225        }
     226}
     227
     228static void
     229gdm_user_class_init (GdmUserClass *class)
     230{
     231        GObjectClass *gobject_class;
     232
     233        gobject_class = G_OBJECT_CLASS (class);
     234
     235        gobject_class->set_property = gdm_user_set_property;
     236        gobject_class->get_property = gdm_user_get_property;
     237        gobject_class->finalize = gdm_user_finalize;
     238
     239        g_object_class_install_property (gobject_class,
     240                                         PROP_MANAGER,
     241                                         g_param_spec_object ("manager",
     242                                                              _("Manager"),
     243                                                              _("The user manager object this user is controlled by."),
     244                                                              GDM_TYPE_USER_MANAGER,
     245                                                              (G_PARAM_READWRITE |
     246                                                               G_PARAM_CONSTRUCT_ONLY)));
     247
     248        g_object_class_install_property (gobject_class,
     249                                         PROP_REAL_NAME,
     250                                         g_param_spec_string ("real-name",
     251                                                              "Real Name",
     252                                                              "The real name to display for this user.",
     253                                                              NULL,
     254                                                              G_PARAM_READABLE));
     255
     256        g_object_class_install_property (gobject_class,
     257                                         PROP_UID,
     258                                         g_param_spec_ulong ("uid",
     259                                                             "User ID",
     260                                                             "The UID for this user.",
     261                                                             0, G_MAXULONG, 0,
     262                                                             G_PARAM_READABLE));
     263        g_object_class_install_property (gobject_class,
     264                                         PROP_USER_NAME,
     265                                         g_param_spec_string ("user-name",
     266                                                              "User Name",
     267                                                              "The login name for this user.",
     268                                                              NULL,
     269                                                              G_PARAM_READABLE));
     270        g_object_class_install_property (gobject_class,
     271                                         PROP_HOME_DIR,
     272                                         g_param_spec_string ("home-directory",
     273                                                              "Home Directory",
     274                                                              "The home directory for this user.",
     275                                                              NULL,
     276                                                              G_PARAM_READABLE));
     277        g_object_class_install_property (gobject_class,
     278                                         PROP_SHELL,
     279                                         g_param_spec_string ("shell",
     280                                                              "Shell",
     281                                                              "The shell for this user.",
     282                                                              NULL,
     283                                                              G_PARAM_READABLE));
     284        g_object_class_install_property (gobject_class,
     285                                         PROP_LOGIN_FREQUENCY,
     286                                         g_param_spec_ulong ("login-frequency",
     287                                                             "login frequency",
     288                                                             "login frequency",
     289                                                             0,
     290                                                             G_MAXULONG,
     291                                                             0,
     292                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
     293
     294        signals [ICON_CHANGED] =
     295                g_signal_new ("icon-changed",
     296                              G_TYPE_FROM_CLASS (class),
     297                              G_SIGNAL_RUN_LAST,
     298                              G_STRUCT_OFFSET (GdmUserClass, icon_changed),
     299                              NULL, NULL,
     300                              g_cclosure_marshal_VOID__VOID,
     301                              G_TYPE_NONE, 0);
     302        signals [SESSIONS_CHANGED] =
     303                g_signal_new ("sessions-changed",
     304                              G_TYPE_FROM_CLASS (class),
     305                              G_SIGNAL_RUN_LAST,
     306                              G_STRUCT_OFFSET (GdmUserClass, sessions_changed),
     307                              NULL, NULL,
     308                              g_cclosure_marshal_VOID__VOID,
     309                              G_TYPE_NONE, 0);
     310}
     311
     312
     313static void
     314on_icon_monitor_changed (GFileMonitor     *monitor,
     315                         GFile            *file,
     316                         GFile            *other_file,
     317                         GFileMonitorEvent event_type,
     318                         GdmUser          *user)
     319{
     320        g_debug ("Icon changed: %d", event_type);
     321
     322        if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
     323            event_type != G_FILE_MONITOR_EVENT_CREATED) {
     324                return;
     325        }
     326
     327        _gdm_user_icon_changed (user);
     328}
     329
     330static void
     331update_icon_monitor (GdmUser *user)
     332{
     333        GFile  *file;
     334        GError *error;
     335        char   *path;
     336
     337        if (user->home_dir == NULL) {
     338                return;
     339        }
     340
     341        if (user->icon_monitor != NULL) {
     342                g_file_monitor_cancel (user->icon_monitor);
     343                user->icon_monitor = NULL;
     344        }
     345
     346        path = g_build_filename (user->home_dir, ".face", NULL);
     347        g_debug ("adding monitor for '%s'", path);
     348        file = g_file_new_for_path (path);
     349        error = NULL;
     350        user->icon_monitor = g_file_monitor_file (file,
     351                                                  G_FILE_MONITOR_NONE,
     352                                                  NULL,
     353                                                  &error);
     354        if (user->icon_monitor != NULL) {
     355                g_signal_connect (user->icon_monitor,
     356                                  "changed",
     357                                  G_CALLBACK (on_icon_monitor_changed),
     358                                  user);
     359        } else {
     360                g_warning ("Unable to monitor %s: %s", path, error->message);
     361                g_error_free (error);
     362        }
     363        g_object_unref (file);
     364        g_free (path);
     365}
     366
     367static void
     368gdm_user_init (GdmUser *user)
     369{
     370        user->manager = NULL;
     371        user->user_name = NULL;
     372        user->real_name = NULL;
     373        user->sessions = NULL;
     374}
     375
     376static void
     377gdm_user_finalize (GObject *object)
     378{
     379        GdmUser *user;
     380
     381        user = GDM_USER (object);
     382
     383        g_file_monitor_cancel (user->icon_monitor);
     384
     385        g_free (user->user_name);
     386        g_free (user->real_name);
     387
     388        if (G_OBJECT_CLASS (gdm_user_parent_class)->finalize)
     389                (*G_OBJECT_CLASS (gdm_user_parent_class)->finalize) (object);
     390}
     391
     392/**
     393 * _gdm_user_update:
     394 * @user: the user object to update.
     395 * @pwent: the user data to use.
     396 *
     397 * Updates the properties of @user using the data in @pwent.
     398 *
     399 * Since: 1.0
     400 **/
     401void
     402_gdm_user_update (GdmUser             *user,
     403                  const struct passwd *pwent)
     404{
     405        gchar *real_name;
     406
     407        g_return_if_fail (GDM_IS_USER (user));
     408        g_return_if_fail (pwent != NULL);
     409
     410        g_object_freeze_notify (G_OBJECT (user));
     411
     412        /* Display Name */
     413        if (pwent->pw_gecos && pwent->pw_gecos[0] != '\0') {
     414                gchar *first_comma;
     415
     416                first_comma = strchr (pwent->pw_gecos, ',');
     417                if (first_comma) {
     418                        real_name = g_strndup (pwent->pw_gecos,
     419                                                  (first_comma - pwent->pw_gecos));
     420                } else {
     421                        real_name = g_strdup (pwent->pw_gecos);
     422                }
     423
     424                if (real_name[0] == '\0') {
     425                        g_free (real_name);
     426                        real_name = NULL;
     427                }
     428        } else {
     429                real_name = NULL;
     430        }
     431
     432        if ((real_name && !user->real_name) ||
     433            (!real_name && user->real_name) ||
     434            (real_name &&
     435             user->real_name &&
     436             strcmp (real_name, user->real_name) != 0)) {
     437                g_free (user->real_name);
     438                user->real_name = real_name;
     439                g_object_notify (G_OBJECT (user), "real-name");
     440        } else {
     441                g_free (real_name);
     442        }
     443
     444        /* UID */
     445        if (pwent->pw_uid != user->uid) {
     446                user->uid = pwent->pw_uid;
     447                g_object_notify (G_OBJECT (user), "uid");
     448        }
     449
     450        /* Username */
     451        if ((pwent->pw_name && !user->user_name) ||
     452            (!pwent->pw_name && user->user_name) ||
     453            (pwent->pw_name &&
     454             user->user_name &&
     455             strcmp (user->user_name, pwent->pw_name) != 0)) {
     456                g_free (user->user_name);
     457                user->user_name = g_strdup (pwent->pw_name);
     458                g_object_notify (G_OBJECT (user), "user-name");
     459        }
     460
     461        /* Home Directory */
     462        if ((pwent->pw_dir && !user->home_dir) ||
     463            (!pwent->pw_dir && user->home_dir) ||
     464            strcmp (user->home_dir, pwent->pw_dir) != 0) {
     465                g_free (user->home_dir);
     466                user->home_dir = g_strdup (pwent->pw_dir);
     467                g_object_notify (G_OBJECT (user), "home-directory");
     468                g_signal_emit (user, signals[ICON_CHANGED], 0);
     469        }
     470
     471        /* Shell */
     472        if ((pwent->pw_shell && !user->shell) ||
     473            (!pwent->pw_shell && user->shell) ||
     474            (pwent->pw_shell &&
     475             user->shell &&
     476             strcmp (user->shell, pwent->pw_shell) != 0)) {
     477                g_free (user->shell);
     478                user->shell = g_strdup (pwent->pw_shell);
     479                g_object_notify (G_OBJECT (user), "shell");
     480        }
     481
     482        update_icon_monitor (user);
     483
     484        g_object_thaw_notify (G_OBJECT (user));
     485}
     486
     487/**
     488 * _gdm_user_icon_changed:
     489 * @user: the user to emit the signal for.
     490 *
     491 * Emits the "icon-changed" signal for @user.
     492 *
     493 * Since: 1.0
     494 **/
     495void
     496_gdm_user_icon_changed (GdmUser *user)
     497{
     498        g_return_if_fail (GDM_IS_USER (user));
     499
     500        g_signal_emit (user, signals[ICON_CHANGED], 0);
     501}
     502
     503/**
     504 * gdm_user_get_uid:
     505 * @user: the user object to examine.
     506 *
     507 * Retrieves the ID of @user.
     508 *
     509 * Returns: a pointer to an array of characters which must not be modified or
     510 *  freed, or %NULL.
     511 *
     512 * Since: 1.0
     513 **/
     514
     515uid_t
     516gdm_user_get_uid (GdmUser *user)
     517{
     518        g_return_val_if_fail (GDM_IS_USER (user), -1);
     519
     520        return user->uid;
     521}
     522
     523/**
     524 * gdm_user_get_real_name:
     525 * @user: the user object to examine.
     526 *
     527 * Retrieves the display name of @user.
     528 *
     529 * Returns: a pointer to an array of characters which must not be modified or
     530 *  freed, or %NULL.
     531 *
     532 * Since: 1.0
     533 **/
     534G_CONST_RETURN gchar *
     535gdm_user_get_real_name (GdmUser *user)
     536{
     537        g_return_val_if_fail (GDM_IS_USER (user), NULL);
     538
     539        return (user->real_name ? user->real_name : user->user_name);
     540}
     541
     542/**
     543 * gdm_user_get_user_name:
     544 * @user: the user object to examine.
     545 *
     546 * Retrieves the login name of @user.
     547 *
     548 * Returns: a pointer to an array of characters which must not be modified or
     549 *  freed, or %NULL.
     550 *
     551 * Since: 1.0
     552 **/
     553
     554G_CONST_RETURN gchar *
     555gdm_user_get_user_name (GdmUser *user)
     556{
     557        g_return_val_if_fail (GDM_IS_USER (user), NULL);
     558
     559        return user->user_name;
     560}
     561
     562/**
     563 * gdm_user_get_home_directory:
     564 * @user: the user object to examine.
     565 *
     566 * Retrieves the home directory of @user.
     567 *
     568 * Returns: a pointer to an array of characters which must not be modified or
     569 *  freed, or %NULL.
     570 *
     571 * Since: 1.0
     572 **/
     573
     574G_CONST_RETURN gchar *
     575gdm_user_get_home_directory (GdmUser *user)
     576{
     577        g_return_val_if_fail (GDM_IS_USER (user), NULL);
     578
     579        return user->home_dir;
     580}
     581
     582/**
     583 * gdm_user_get_shell:
     584 * @user: the user object to examine.
     585 *
     586 * Retrieves the login shell of @user.
     587 *
     588 * Returns: a pointer to an array of characters which must not be modified or
     589 *  freed, or %NULL.
     590 *
     591 * Since: 1.0
     592 **/
     593
     594G_CONST_RETURN gchar *
     595gdm_user_get_shell (GdmUser *user)
     596{
     597        g_return_val_if_fail (GDM_IS_USER (user), NULL);
     598
     599        return user->shell;
     600}
     601
     602gulong
     603gdm_user_get_login_frequency (GdmUser *user)
     604{
     605        g_return_val_if_fail (GDM_IS_USER (user), 0);
     606
     607        return user->login_frequency;
     608}
     609
     610int
     611gdm_user_collate (GdmUser *user1,
     612                  GdmUser *user2)
     613{
     614        const char *str1;
     615        const char *str2;
     616        gulong      num1;
     617        gulong      num2;
     618
     619        g_return_val_if_fail (user1 == NULL || GDM_IS_USER (user1), 0);
     620        g_return_val_if_fail (user2 == NULL || GDM_IS_USER (user2), 0);
     621
     622        if (user1->real_name != NULL) {
     623                str1 = user1->real_name;
     624        } else {
     625                str1 = user1->user_name;
     626        }
     627
     628        if (user2->real_name != NULL) {
     629                str2 = user2->real_name;
     630        } else {
     631                str2 = user2->user_name;
     632        }
     633
     634        num1 = user1->login_frequency;
     635        num2 = user2->login_frequency;
     636        g_debug ("Login freq 1=%u 2=%u", (guint)num1, (guint)num2);
     637        if (num1 > num2) {
     638                return -1;
     639        }
     640
     641        if (num1 < num2) {
     642                return 1;
     643        }
     644
     645        /* if login frequency is equal try names */
     646        if (str1 == NULL && str2 != NULL) {
     647                return -1;
     648        }
     649
     650        if (str1 != NULL && str2 == NULL) {
     651                return 1;
     652        }
     653
     654        if (str1 == NULL && str2 == NULL) {
     655                return 0;
     656        }
     657
     658        return g_utf8_collate (str1, str2);
     659}
     660
     661static gboolean
     662check_user_file (const char *filename,
     663                 uid_t       user,
     664                 gssize      max_file_size,
     665                 gboolean    relax_group,
     666                 gboolean    relax_other)
     667{
     668        struct stat fileinfo;
     669
     670        if (max_file_size < 0) {
     671                max_file_size = G_MAXSIZE;
     672        }
     673
     674        /* Exists/Readable? */
     675        if (stat (filename, &fileinfo) < 0) {
     676                return FALSE;
     677        }
     678
     679        /* Is a regular file */
     680        if (G_UNLIKELY (!S_ISREG (fileinfo.st_mode))) {
     681                return FALSE;
     682        }
     683
     684        /* Owned by user? */
     685        if (G_UNLIKELY (fileinfo.st_uid != user)) {
     686                return FALSE;
     687        }
     688
     689        /* Group not writable or relax_group? */
     690        if (G_UNLIKELY ((fileinfo.st_mode & S_IWGRP) == S_IWGRP && !relax_group)) {
     691                return FALSE;
     692        }
     693
     694        /* Other not writable or relax_other? */
     695        if (G_UNLIKELY ((fileinfo.st_mode & S_IWOTH) == S_IWOTH && !relax_other)) {
     696                return FALSE;
     697        }
     698
     699        /* Size is kosher? */
     700        if (G_UNLIKELY (fileinfo.st_size > max_file_size)) {
     701                return FALSE;
     702        }
     703
     704        return TRUE;
     705}
     706
     707static char *
     708get_filesystem_type (const char *path)
     709{
     710        GFile      *file;
     711        GFileInfo  *file_info;
     712        GError     *error;
     713        char       *filesystem_type;
     714
     715        file = g_file_new_for_path (path);
     716        error = NULL;
     717        file_info = g_file_query_filesystem_info (file,
     718                                                  G_FILE_ATTRIBUTE_FILESYSTEM_TYPE,
     719                                                  NULL,
     720                                                  &error);
     721        if (file_info == NULL) {
     722                g_warning ("Unable to query filesystem type for %s: %s", path, error->message);
     723                g_error_free (error);
     724                g_object_unref (file);
     725                return NULL;
     726        }
     727
     728        filesystem_type = g_strdup (g_file_info_get_attribute_string (file_info,
     729                                                                      G_FILE_ATTRIBUTE_FILESYSTEM_TYPE));
     730        if (filesystem_type == NULL) {
     731                g_warning ("GIO returned NULL filesystem type for %s", path);
     732        }
     733
     734        g_object_unref (file);
     735        g_object_unref (file_info);
     736
     737        return filesystem_type;
     738}
     739
     740static GdkPixbuf *
     741render_icon_from_home (GdmUser *user,
     742                       int      icon_size)
     743{
     744        GdkPixbuf  *retval;
     745        char       *path;
     746        gboolean    is_local;
     747        gboolean    is_autofs;
     748        gboolean    res;
     749        char       *filesystem_type;
     750
     751        is_local = FALSE;
     752
     753        /* special case: look at parent of home to detect autofs
     754           this is so we don't try to trigger an automount */
     755        path = g_path_get_dirname (user->home_dir);
     756        filesystem_type = get_filesystem_type (path);
     757        is_autofs = (filesystem_type != NULL && strcmp (filesystem_type, "autofs") == 0);
     758        g_free (filesystem_type);
     759        g_free (path);
     760
     761        if (is_autofs) {
     762                return NULL;
     763        }
     764
     765        /* now check that home dir itself is local */
     766        filesystem_type = get_filesystem_type (user->home_dir);
     767        is_local = ((filesystem_type != NULL) &&
     768                    (strcmp (filesystem_type, "nfs") != 0) &&
     769                    (strcmp (filesystem_type, "afs") != 0) &&
     770                    (strcmp (filesystem_type, "autofs") != 0) &&
     771                    (strcmp (filesystem_type, "unknown") != 0) &&
     772                    (strcmp (filesystem_type, "ncpfs") != 0));
     773        g_free (filesystem_type);
     774
     775        /* only look at local home directories so we don't try to
     776           read from remote (e.g. NFS) volumes */
     777        if (! is_local) {
     778                return NULL;
     779        }
     780
     781        /* First, try "~/.face" */
     782        path = g_build_filename (user->home_dir, ".face", NULL);
     783        res = check_user_file (path,
     784                               user->uid,
     785                               MAX_FILE_SIZE,
     786                               RELAX_GROUP,
     787                               RELAX_OTHER);
     788        if (res) {
     789                retval = gdk_pixbuf_new_from_file_at_size (path,
     790                                                           icon_size,
     791                                                           icon_size,
     792                                                           NULL);
     793        } else {
     794                retval = NULL;
     795        }
     796        g_free (path);
     797
     798        /* Next, try "~/.face.icon" */
     799        if (retval == NULL) {
     800                path = g_build_filename (user->home_dir,
     801                                         ".face.icon",
     802                                         NULL);
     803                res = check_user_file (path,
     804                                       user->uid,
     805                                       MAX_FILE_SIZE,
     806                                       RELAX_GROUP,
     807                                       RELAX_OTHER);
     808                if (res) {
     809                        retval = gdk_pixbuf_new_from_file_at_size (path,
     810                                                                   icon_size,
     811                                                                   icon_size,
     812                                                                   NULL);
     813                } else {
     814                        retval = NULL;
     815                }
     816
     817                g_free (path);
     818        }
     819
     820        /* Still nothing, try the user's personal GDM config */
     821        if (retval == NULL) {
     822                path = g_build_filename (user->home_dir,
     823                                         ".gnome",
     824                                         "gdm",
     825                                         NULL);
     826                res = check_user_file (path,
     827                                       user->uid,
     828                                       MAX_FILE_SIZE,
     829                                       RELAX_GROUP,
     830                                       RELAX_OTHER);
     831                if (res) {
     832                        GKeyFile *keyfile;
     833                        char     *icon_path;
     834
     835                        keyfile = g_key_file_new ();
     836                        g_key_file_load_from_file (keyfile,
     837                                                   path,
     838                                                   G_KEY_FILE_NONE,
     839                                                   NULL);
     840
     841                        icon_path = g_key_file_get_string (keyfile,
     842                                                           "face",
     843                                                           "picture",
     844                                                           NULL);
     845                        res = check_user_file (icon_path,
     846                                               user->uid,
     847                                               MAX_FILE_SIZE,
     848                                               RELAX_GROUP,
     849                                               RELAX_OTHER);
     850                        if (icon_path && res) {
     851                                retval = gdk_pixbuf_new_from_file_at_size (path,
     852                                                                           icon_size,
     853                                                                           icon_size,
     854                                                                           NULL);
     855                        } else {
     856                                retval = NULL;
     857                        }
     858
     859                        g_free (icon_path);
     860                        g_key_file_free (keyfile);
     861                } else {
     862                        retval = NULL;
     863                }
     864
     865                g_free (path);
     866        }
     867
     868        return retval;
     869}
     870
     871static void
     872curved_rectangle (cairo_t *cr,
     873                  double   x0,
     874                  double   y0,
     875                  double   width,
     876                  double   height,
     877                  double   radius)
     878{
     879        double x1;
     880        double y1;
     881
     882        x1 = x0 + width;
     883        y1 = y0 + height;
     884
     885        if (width < FLT_EPSILON || height < FLT_EPSILON) {
     886                return;
     887        }
     888
     889        if (width / 2 < radius) {
     890                if (height / 2 < radius) {
     891                        cairo_move_to  (cr, x0, (y0 + y1) / 2);
     892                        cairo_curve_to (cr, x0 ,y0, x0, y0, (x0 + x1) / 2, y0);
     893                        cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
     894                        cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
     895                        cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
     896                } else {
     897                        cairo_move_to  (cr, x0, y0 + radius);
     898                        cairo_curve_to (cr, x0, y0, x0, y0, (x0 + x1) / 2, y0);
     899                        cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
     900                        cairo_line_to (cr, x1, y1 - radius);
     901                        cairo_curve_to (cr, x1, y1, x1, y1, (x1 + x0) / 2, y1);
     902                        cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
     903                }
     904        } else {
     905                if (height / 2 < radius) {
     906                        cairo_move_to  (cr, x0, (y0 + y1) / 2);
     907                        cairo_curve_to (cr, x0, y0, x0 , y0, x0 + radius, y0);
     908                        cairo_line_to (cr, x1 - radius, y0);
     909                        cairo_curve_to (cr, x1, y0, x1, y0, x1, (y0 + y1) / 2);
     910                        cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
     911                        cairo_line_to (cr, x0 + radius, y1);
     912                        cairo_curve_to (cr, x0, y1, x0, y1, x0, (y0 + y1) / 2);
     913                } else {
     914                        cairo_move_to  (cr, x0, y0 + radius);
     915                        cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + radius, y0);
     916                        cairo_line_to (cr, x1 - radius, y0);
     917                        cairo_curve_to (cr, x1, y0, x1, y0, x1, y0 + radius);
     918                        cairo_line_to (cr, x1, y1 - radius);
     919                        cairo_curve_to (cr, x1, y1, x1, y1, x1 - radius, y1);
     920                        cairo_line_to (cr, x0 + radius, y1);
     921                        cairo_curve_to (cr, x0, y1, x0, y1, x0, y1 - radius);
     922                }
     923        }
     924
     925        cairo_close_path (cr);
     926}
     927
     928static cairo_surface_t *
     929surface_from_pixbuf (GdkPixbuf *pixbuf)
     930{
     931        cairo_surface_t *surface;
     932        cairo_t         *cr;
     933
     934        surface = cairo_image_surface_create (gdk_pixbuf_get_has_alpha (pixbuf) ?
     935                                              CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
     936                                              gdk_pixbuf_get_width (pixbuf),
     937                                              gdk_pixbuf_get_height (pixbuf));
     938        cr = cairo_create (surface);
     939        gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
     940        cairo_paint (cr);
     941        cairo_destroy (cr);
     942
     943        return surface;
     944}
     945
     946/**
     947 * go_cairo_convert_data_to_pixbuf:
     948 * @src: a pointer to pixel data in cairo format
     949 * @dst: a pointer to pixel data in pixbuf format
     950 * @width: image width
     951 * @height: image height
     952 * @rowstride: data rowstride
     953 *
     954 * Converts the pixel data stored in @src in CAIRO_FORMAT_ARGB32 cairo format
     955 * to GDK_COLORSPACE_RGB pixbuf format and move them
     956 * to @dst. If @src == @dst, pixel are converted in place.
     957 **/
     958
     959static void
     960go_cairo_convert_data_to_pixbuf (unsigned char *dst,
     961                                 unsigned char const *src,
     962                                 int width,
     963                                 int height,
     964                                 int rowstride)
     965{
     966        int i,j;
     967        unsigned int t;
     968        unsigned char a, b, c;
     969
     970        g_return_if_fail (dst != NULL);
     971
     972#define MULT(d,c,a,t) G_STMT_START { t = (a)? c * 255 / a: 0; d = t;} G_STMT_END
     973
     974        if (src == dst || src == NULL) {
     975                for (i = 0; i < height; i++) {
     976                        for (j = 0; j < width; j++) {
     977#if G_BYTE_ORDER == G_LITTLE_ENDIAN
     978                                MULT(a, dst[2], dst[3], t);
     979                                MULT(b, dst[1], dst[3], t);
     980                                MULT(c, dst[0], dst[3], t);
     981                                dst[0] = a;
     982                                dst[1] = b;
     983                                dst[2] = c;
     984#else
     985                                MULT(a, dst[1], dst[0], t);
     986                                MULT(b, dst[2], dst[0], t);
     987                                MULT(c, dst[3], dst[0], t);
     988                                dst[3] = dst[0];
     989                                dst[0] = a;
     990                                dst[1] = b;
     991                                dst[2] = c;
     992#endif
     993                                dst += 4;
     994                        }
     995                        dst += rowstride - width * 4;
     996                }
     997        } else {
     998                for (i = 0; i < height; i++) {
     999                        for (j = 0; j < width; j++) {
     1000#if G_BYTE_ORDER == G_LITTLE_ENDIAN
     1001                                MULT(dst[0], src[2], src[3], t);
     1002                                MULT(dst[1], src[1], src[3], t);
     1003                                MULT(dst[2], src[0], src[3], t);
     1004                                dst[3] = src[3];
     1005#else
     1006                                MULT(dst[0], src[1], src[0], t);
     1007                                MULT(dst[1], src[2], src[0], t);
     1008                                MULT(dst[2], src[3], src[0], t);
     1009                                dst[3] = src[0];
     1010#endif
     1011                                src += 4;
     1012                                dst += 4;
     1013                        }
     1014                        src += rowstride - width * 4;
     1015                        dst += rowstride - width * 4;
     1016                }
     1017        }
     1018#undef MULT
     1019}
     1020
     1021static void
     1022cairo_to_pixbuf (guint8    *src_data,
     1023                 GdkPixbuf *dst_pixbuf)
     1024{
     1025        unsigned char *src;
     1026        unsigned char *dst;
     1027        guint          w;
     1028        guint          h;
     1029        guint          rowstride;
     1030
     1031        w = gdk_pixbuf_get_width (dst_pixbuf);
     1032        h = gdk_pixbuf_get_height (dst_pixbuf);
     1033        rowstride = gdk_pixbuf_get_rowstride (dst_pixbuf);
     1034
     1035        dst = gdk_pixbuf_get_pixels (dst_pixbuf);
     1036        src = src_data;
     1037
     1038        go_cairo_convert_data_to_pixbuf (dst, src, w, h, rowstride);
     1039}
     1040
     1041static GdkPixbuf *
     1042frame_pixbuf (GdkPixbuf *source)
     1043{
     1044        GdkPixbuf       *dest;
     1045        cairo_t         *cr;
     1046        cairo_surface_t *surface;
     1047        guint            w;
     1048        guint            h;
     1049        guint            rowstride;
     1050        int              frame_width;
     1051        double           radius;
     1052        guint8          *data;
     1053
     1054        frame_width = 2;
     1055
     1056        w = gdk_pixbuf_get_width (source) + frame_width * 2;
     1057        h = gdk_pixbuf_get_height (source) + frame_width * 2;
     1058        radius = w / 3.0;
     1059
     1060        dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB,
     1061                               TRUE,
     1062                               8,
     1063                               w,
     1064                               h);
     1065        rowstride = gdk_pixbuf_get_rowstride (dest);
     1066
     1067
     1068        data = g_new0 (guint8, h * rowstride);
     1069
     1070        surface = cairo_image_surface_create_for_data (data,
     1071                                                       CAIRO_FORMAT_ARGB32,
     1072                                                       w,
     1073                                                       h,
     1074                                                       rowstride);
     1075        cr = cairo_create (surface);
     1076        cairo_surface_destroy (surface);
     1077
     1078        /* set up image */
     1079        cairo_rectangle (cr, 0, 0, w, h);
     1080        cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0);
     1081        cairo_fill (cr);
     1082
     1083        curved_rectangle (cr, frame_width, frame_width,
     1084                          w - frame_width * 2, h - frame_width * 2,
     1085                          radius);
     1086        cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.3);
     1087        cairo_fill_preserve (cr);
     1088
     1089        surface = surface_from_pixbuf (source);
     1090        cairo_set_source_surface (cr, surface, frame_width, frame_width);
     1091        cairo_fill (cr);
     1092        cairo_surface_destroy (surface);
     1093
     1094        cairo_to_pixbuf (data, dest);
     1095
     1096        cairo_destroy (cr);
     1097        g_free (data);
     1098
     1099        return dest;
     1100}
     1101
     1102GdkPixbuf *
     1103gdm_user_render_icon (GdmUser   *user,
     1104                      gint       icon_size)
     1105{
     1106        GdkPixbuf    *pixbuf;
     1107        GdkPixbuf    *framed;
     1108        char         *path;
     1109        char         *tmp;
     1110        gboolean      res;
     1111
     1112        g_return_val_if_fail (GDM_IS_USER (user), NULL);
     1113        g_return_val_if_fail (icon_size > 12, NULL);
     1114
     1115        path = NULL;
     1116
     1117        pixbuf = render_icon_from_home (user, icon_size);
     1118        if (pixbuf != NULL) {
     1119                goto out;
     1120        }
     1121
     1122        /* Try ${GlobalFaceDir}/${username} */
     1123        path = g_build_filename (GLOBAL_FACEDIR, user->user_name, NULL);
     1124        res = check_user_file (path,
     1125                               user->uid,
     1126                               MAX_FILE_SIZE,
     1127                               RELAX_GROUP,
     1128                               RELAX_OTHER);
     1129        if (res) {
     1130                pixbuf = gdk_pixbuf_new_from_file_at_size (path,
     1131                                                           icon_size,
     1132                                                           icon_size,
     1133                                                           NULL);
     1134        } else {
     1135                pixbuf = NULL;
     1136        }
     1137
     1138        g_free (path);
     1139        if (pixbuf != NULL) {
     1140                goto out;
     1141        }
     1142
     1143        /* Finally, ${GlobalFaceDir}/${username}.png */
     1144        tmp = g_strconcat (user->user_name, ".png", NULL);
     1145        path = g_build_filename (GLOBAL_FACEDIR, tmp, NULL);
     1146        g_free (tmp);
     1147        res = check_user_file (path,
     1148                               user->uid,
     1149                               MAX_FILE_SIZE,
     1150                               RELAX_GROUP,
     1151                               RELAX_OTHER);
     1152        if (res) {
     1153                pixbuf = gdk_pixbuf_new_from_file_at_size (path,
     1154                                                           icon_size,
     1155                                                           icon_size,
     1156                                                           NULL);
     1157        } else {
     1158                pixbuf = NULL;
     1159        }
     1160        g_free (path);
     1161 out:
     1162
     1163        if (pixbuf != NULL) {
     1164                framed = frame_pixbuf (pixbuf);
     1165                if (framed != NULL) {
     1166                        g_object_unref (pixbuf);
     1167                        pixbuf = framed;
     1168                }
     1169        }
     1170
     1171        return pixbuf;
     1172}
  • gui/gdmsetup/gdm-user.h

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/gui/gdmsetup/gdm-user.h gdm-2.28.0.new/gui/gdmsetup/gdm-user.h
    old new  
     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 *
     6 * This program is free software; you can redistribute it and/or modify
     7 * it under the terms of the GNU General Public License as published by
     8 * the Free Software Foundation; either version 2 of the License, or
     9 * (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this program; if not, write to the Free Software
     18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     19 */
     20
     21/*
     22 * Facade object for user data, owned by GdmUserManager
     23 */
     24
     25#ifndef __GDM_USER__
     26#define __GDM_USER__ 1
     27
     28#include <sys/types.h>
     29#include <gtk/gtk.h>
     30#include <gdk-pixbuf/gdk-pixbuf.h>
     31
     32G_BEGIN_DECLS
     33
     34#define GDM_TYPE_USER (gdm_user_get_type ())
     35#define GDM_USER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDM_TYPE_USER, GdmUser))
     36#define GDM_IS_USER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDM_TYPE_USER))
     37
     38typedef struct _GdmUser GdmUser;
     39
     40GType                 gdm_user_get_type            (void) G_GNUC_CONST;
     41
     42uid_t                 gdm_user_get_uid             (GdmUser   *user);
     43G_CONST_RETURN char  *gdm_user_get_user_name       (GdmUser   *user);
     44G_CONST_RETURN char  *gdm_user_get_real_name       (GdmUser   *user);
     45G_CONST_RETURN char  *gdm_user_get_home_directory  (GdmUser   *user);
     46G_CONST_RETURN char  *gdm_user_get_shell           (GdmUser   *user);
     47guint                 gdm_user_get_num_sessions    (GdmUser   *user);
     48GList                *gdm_user_get_sessions        (GdmUser   *user);
     49gulong                gdm_user_get_login_frequency (GdmUser   *user);
     50
     51GdkPixbuf            *gdm_user_render_icon         (GdmUser   *user,
     52                                                    gint       icon_size);
     53
     54gint                  gdm_user_collate             (GdmUser   *user1,
     55                                                    GdmUser   *user2);
     56
     57G_END_DECLS
     58
     59#endif
  • gui/gdmsetup/gdm-user-manager.c

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/gui/gdmsetup/gdm-user-manager.c gdm-2.28.0.new/gui/gdmsetup/gdm-user-manager.c
    old new  
     1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
     2 *
     3 * Copyright (C) 2007-2008 William Jon McCann <mccann@jhu.edu>
     4 *
     5 * This program is free software; you can redistribute it and/or modify
     6 * it under the terms of the GNU General Public License as published by
     7 * the Free Software Foundation; either version 2 of the License, or
     8 * (at your option) any later version.
     9 *
     10 * This program is distributed in the hope that it will be useful,
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 * GNU General Public License for more details.
     14 *
     15 * You should have received a copy of the GNU General Public License
     16 * along with this program; if not, write to the Free Software
     17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     18 *
     19 */
     20
     21#include "config.h"
     22
     23#include <stdlib.h>
     24#include <stdio.h>
     25#include <fcntl.h>
     26#include <unistd.h>
     27#include <string.h>
     28#include <signal.h>
     29#include <errno.h>
     30#include <sys/stat.h>
     31#include <sys/types.h>
     32
     33#ifdef HAVE_PATHS_H
     34#include <paths.h>
     35#endif /* HAVE_PATHS_H */
     36
     37#include <glib.h>
     38#include <glib/gi18n.h>
     39#include <glib/gstdio.h>
     40#include <glib-object.h>
     41#include <gio/gio.h>
     42
     43#include <dbus/dbus.h>
     44#include <dbus/dbus-glib.h>
     45#include <dbus/dbus-glib-lowlevel.h>
     46
     47#include "gdm-user-manager.h"
     48#include "gdm-user-private.h"
     49
     50#define GDM_USER_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_USER_MANAGER, GdmUserManagerPrivate))
     51
     52#define CK_NAME      "org.freedesktop.ConsoleKit"
     53#define CK_PATH      "/org/freedesktop/ConsoleKit"
     54#define CK_INTERFACE "org.freedesktop.ConsoleKit"
     55
     56#define CK_MANAGER_PATH      "/org/freedesktop/ConsoleKit/Manager"
     57#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager"
     58#define CK_SEAT_INTERFACE    "org.freedesktop.ConsoleKit.Seat"
     59#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session"
     60
     61/* Prefs Defaults */
     62#define DEFAULT_ALLOW_ROOT      TRUE
     63#define DEFAULT_MAX_ICON_SIZE   128
     64#define DEFAULT_USER_MAX_FILE   65536
     65
     66#ifdef __sun
     67#define DEFAULT_MINIMAL_UID     100
     68#else
     69#define DEFAULT_MINIMAL_UID     500
     70#endif
     71
     72#ifndef _PATH_SHELLS
     73#define _PATH_SHELLS    "/etc/shells"
     74#endif
     75#define PATH_PASSWD     "/etc/passwd"
     76
     77#define DEFAULT_GLOBAL_FACE_DIR DATADIR "/faces"
     78#define DEFAULT_USER_ICON       "stock_person"
     79#define DEFAULT_EXCLUDE         { "bin",        \
     80                                  "root",       \
     81                                  "daemon",     \
     82                                  "adm",        \
     83                                  "lp",         \
     84                                  "sync",       \
     85                                  "shutdown",   \
     86                                  "halt",       \
     87                                  "mail",       \
     88                                  "news",       \
     89                                  "uucp",       \
     90                                  "operator",   \
     91                                  "nobody",     \
     92                                  GDM_USERNAME, \
     93                                  "postgres",   \
     94                                  "pvm",        \
     95                                  "rpm",        \
     96                                  "nfsnobody",  \
     97                                  "pcap",       \
     98                                  NULL }
     99
     100struct GdmUserManagerPrivate
     101{
     102        GHashTable            *users;
     103        GHashTable            *sessions;
     104        GHashTable            *exclusions;
     105        GHashTable            *shells;
     106        DBusGConnection       *connection;
     107        DBusGProxy            *seat_proxy;
     108        char                  *seat_id;
     109
     110        GFileMonitor          *passwd_monitor;
     111        GFileMonitor          *shells_monitor;
     112
     113        guint                  reload_id;
     114        guint                  ck_history_id;
     115
     116        guint8                 users_dirty : 1;
     117};
     118
     119enum {
     120        LOADING_USERS,
     121        USERS_LOADED,
     122        USER_ADDED,
     123        USER_REMOVED,
     124        USER_IS_LOGGED_IN_CHANGED,
     125        USER_LOGIN_FREQUENCY_CHANGED,
     126        LAST_SIGNAL
     127};
     128
     129static guint signals [LAST_SIGNAL] = { 0, };
     130
     131static void     gdm_user_manager_class_init (GdmUserManagerClass *klass);
     132static void     gdm_user_manager_init       (GdmUserManager      *user_manager);
     133static void     gdm_user_manager_finalize   (GObject             *object);
     134
     135static gpointer user_manager_object = NULL;
     136
     137G_DEFINE_TYPE (GdmUserManager, gdm_user_manager, G_TYPE_OBJECT)
     138
     139GQuark
     140gdm_user_manager_error_quark (void)
     141{
     142        static GQuark ret = 0;
     143        if (ret == 0) {
     144                ret = g_quark_from_static_string ("gdm_user_manager_error");
     145        }
     146
     147        return ret;
     148}
     149
     150static gboolean
     151start_new_login_session (GdmUserManager *manager)
     152{
     153        GError  *error;
     154        gboolean res;
     155
     156        res = g_spawn_command_line_async ("gdmflexiserver -s", &error);
     157        if (! res) {
     158                g_warning ("Unable to start new login: %s", error->message);
     159                g_error_free (error);
     160        }
     161
     162        return res;
     163}
     164
     165/* needs to stay in sync with gdm-slave */
     166static char *
     167_get_primary_user_session_id (GdmUserManager *manager,
     168                              GdmUser        *user)
     169{
     170        gboolean    res;
     171        gboolean    can_activate_sessions;
     172        GError     *error;
     173        GList      *sessions;
     174        GList      *l;
     175        char       *primary_ssid;
     176
     177        if (manager->priv->seat_id == NULL || manager->priv->seat_id[0] == '\0') {
     178                g_debug ("GdmUserManager: display seat id is not set; can't switch sessions");
     179                return NULL;
     180        }
     181
     182        primary_ssid = NULL;
     183        sessions = NULL;
     184
     185        g_debug ("GdmUserManager: checking if seat can activate sessions");
     186
     187        error = NULL;
     188        res = dbus_g_proxy_call (manager->priv->seat_proxy,
     189                                 "CanActivateSessions",
     190                                 &error,
     191                                 G_TYPE_INVALID,
     192                                 G_TYPE_BOOLEAN, &can_activate_sessions,
     193                                 G_TYPE_INVALID);
     194        if (! res) {
     195                g_warning ("unable to determine if seat can activate sessions: %s",
     196                           error->message);
     197                g_error_free (error);
     198                goto out;
     199        }
     200
     201        if (! can_activate_sessions) {
     202                g_debug ("GdmUserManager: seat is unable to activate sessions");
     203                goto out;
     204        }
     205
     206        sessions = gdm_user_get_sessions (user);
     207        if (sessions == NULL) {
     208                g_warning ("unable to determine sessions for user: %s",
     209                           gdm_user_get_user_name (user));
     210                goto out;
     211        }
     212
     213        for (l = sessions; l != NULL; l = l->next) {
     214                const char *ssid;
     215
     216                ssid = l->data;
     217
     218                /* FIXME: better way to choose? */
     219                if (ssid != NULL) {
     220                        primary_ssid = g_strdup (ssid);
     221                        break;
     222                }
     223        }
     224
     225 out:
     226
     227        return primary_ssid;
     228}
     229
     230static gboolean
     231activate_session_id (GdmUserManager *manager,
     232                     const char     *seat_id,
     233                     const char     *session_id)
     234{
     235        DBusError    local_error;
     236        DBusMessage *message;
     237        DBusMessage *reply;
     238        gboolean     ret;
     239
     240        ret = FALSE;
     241        reply = NULL;
     242
     243        dbus_error_init (&local_error);
     244        message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit",
     245                                                seat_id,
     246                                                "org.freedesktop.ConsoleKit.Seat",
     247                                                "ActivateSession");
     248        if (message == NULL) {
     249                goto out;
     250        }
     251
     252        if (! dbus_message_append_args (message,
     253                                        DBUS_TYPE_OBJECT_PATH, &session_id,
     254                                        DBUS_TYPE_INVALID)) {
     255                goto out;
     256        }
     257
     258
     259        dbus_error_init (&local_error);
     260        reply = dbus_connection_send_with_reply_and_block (dbus_g_connection_get_connection (manager->priv->connection),
     261                                                           message,
     262                                                           -1,
     263                                                           &local_error);
     264        if (reply == NULL) {
     265                if (dbus_error_is_set (&local_error)) {
     266                        g_warning ("Unable to activate session: %s", local_error.message);
     267                        dbus_error_free (&local_error);
     268                        goto out;
     269                }
     270        }
     271
     272        ret = TRUE;
     273 out:
     274        if (message != NULL) {
     275                dbus_message_unref (message);
     276        }
     277        if (reply != NULL) {
     278                dbus_message_unref (reply);
     279        }
     280
     281        return ret;
     282}
     283
     284static gboolean
     285session_is_login_window (GdmUserManager *manager,
     286                         const char     *session_id)
     287{
     288        DBusGProxy      *proxy;
     289        GError          *error;
     290        gboolean         res;
     291        gboolean         ret;
     292        char            *session_type;
     293
     294        ret = FALSE;
     295
     296        proxy = dbus_g_proxy_new_for_name (manager->priv->connection,
     297                                           CK_NAME,
     298                                           session_id,
     299                                           CK_SESSION_INTERFACE);
     300        if (proxy == NULL) {
     301                g_warning ("Failed to connect to the ConsoleKit seat object");
     302                goto out;
     303        }
     304
     305        session_type = NULL;
     306        error = NULL;
     307        res = dbus_g_proxy_call (proxy,
     308                                 "GetSessionType",
     309                                 &error,
     310                                 G_TYPE_INVALID,
     311                                 G_TYPE_STRING, &session_type,
     312                                 G_TYPE_INVALID);
     313        if (! res) {
     314                g_debug ("Failed to identify the session type: %s", error->message);
     315                g_error_free (error);
     316                goto out;
     317        }
     318
     319        if (session_type == NULL || session_type[0] == '\0' || strcmp (session_type, "LoginWindow") != 0) {
     320                goto out;
     321        }
     322
     323        ret = TRUE;
     324
     325 out:
     326        if (proxy != NULL) {
     327                g_object_unref (proxy);
     328        }
     329
     330        return ret;
     331}
     332
     333static char *
     334_get_login_window_session_id (GdmUserManager *manager)
     335{
     336        gboolean    res;
     337        gboolean    can_activate_sessions;
     338        GError     *error;
     339        GPtrArray  *sessions;
     340        char       *primary_ssid;
     341        int         i;
     342
     343        if (manager->priv->seat_id == NULL || manager->priv->seat_id[0] == '\0') {
     344                g_debug ("GdmUserManager: display seat id is not set; can't switch sessions");
     345                return NULL;
     346        }
     347
     348        primary_ssid = NULL;
     349        sessions = NULL;
     350
     351        g_debug ("GdmSlave: checking if seat can activate sessions");
     352
     353        error = NULL;
     354        res = dbus_g_proxy_call (manager->priv->seat_proxy,
     355                                 "CanActivateSessions",
     356                                 &error,
     357                                 G_TYPE_INVALID,
     358                                 G_TYPE_BOOLEAN, &can_activate_sessions,
     359                                 G_TYPE_INVALID);
     360        if (! res) {
     361                g_warning ("unable to determine if seat can activate sessions: %s",
     362                           error->message);
     363                g_error_free (error);
     364                goto out;
     365        }
     366
     367        if (! can_activate_sessions) {
     368                g_debug ("GdmSlave: seat is unable to activate sessions");
     369                goto out;
     370        }
     371
     372        error = NULL;
     373        res = dbus_g_proxy_call (manager->priv->seat_proxy,
     374                                 "GetSessions",
     375                                 &error,
     376                                 G_TYPE_INVALID,
     377                                 dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &sessions,
     378                                 G_TYPE_INVALID);
     379        if (! res) {
     380                g_warning ("unable to determine sessions for user: %s",
     381                           error->message);
     382                g_error_free (error);
     383                goto out;
     384        }
     385
     386        for (i = 0; i < sessions->len; i++) {
     387                char *ssid;
     388
     389                ssid = g_ptr_array_index (sessions, i);
     390
     391                if (session_is_login_window (manager, ssid)) {
     392                        primary_ssid = g_strdup (ssid);
     393                        break;
     394                }
     395        }
     396        g_ptr_array_foreach (sessions, (GFunc)g_free, NULL);
     397        g_ptr_array_free (sessions, TRUE);
     398
     399 out:
     400
     401        return primary_ssid;
     402}
     403
     404gboolean
     405gdm_user_manager_goto_login_session (GdmUserManager *manager)
     406{
     407        gboolean ret;
     408        gboolean res;
     409        char    *ssid;
     410
     411        g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), FALSE);
     412
     413        ret = FALSE;
     414
     415        /* First look for any existing LoginWindow sessions on the seat.
     416           If none are found, create a new one. */
     417
     418        ssid = _get_login_window_session_id (manager);
     419        if (ssid != NULL) {
     420                res = activate_session_id (manager, manager->priv->seat_id, ssid);
     421                if (res) {
     422                        ret = TRUE;
     423                }
     424        }
     425
     426        if (! ret) {
     427                res = start_new_login_session (manager);
     428                if (res) {
     429                        ret = TRUE;
     430                }
     431        }
     432
     433        return ret;
     434}
     435
     436gboolean
     437gdm_user_manager_activate_user_session (GdmUserManager *manager,
     438                                        GdmUser        *user)
     439{
     440        gboolean ret;
     441        char    *ssid;
     442        gboolean res;
     443
     444        g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), FALSE);
     445        g_return_val_if_fail (GDM_IS_USER (user), FALSE);
     446
     447        ret = FALSE;
     448
     449        ssid = _get_primary_user_session_id (manager, user);
     450        if (ssid == NULL) {
     451                goto out;
     452        }
     453
     454        res = activate_session_id (manager, manager->priv->seat_id, ssid);
     455        if (! res) {
     456                g_debug ("GdmUserManager: unable to activate session: %s", ssid);
     457                goto out;
     458        }
     459
     460        ret = TRUE;
     461 out:
     462        return ret;
     463}
     464
     465static void
     466on_user_sessions_changed (GdmUser        *user,
     467                          GdmUserManager *manager)
     468{
     469        guint nsessions;
     470
     471        nsessions = gdm_user_get_num_sessions (user);
     472
     473        g_debug ("GdmUserManager: sessions changed user=%s num=%d",
     474                 gdm_user_get_user_name (user),
     475                 nsessions);
     476
     477        /* only signal on zero and one */
     478        if (nsessions > 1) {
     479                return;
     480        }
     481
     482        g_signal_emit (manager, signals [USER_IS_LOGGED_IN_CHANGED], 0, user);
     483}
     484
     485static void
     486on_user_icon_changed (GdmUser        *user,
     487                      GdmUserManager *manager)
     488{
     489        g_debug ("GdmUserManager: user icon changed");
     490}
     491
     492static char *
     493get_seat_id_for_session (DBusGConnection *connection,
     494                         const char      *session_id)
     495{
     496        DBusGProxy      *proxy;
     497        GError          *error;
     498        char            *seat_id;
     499        gboolean         res;
     500
     501        proxy = NULL;
     502        seat_id = NULL;
     503
     504        proxy = dbus_g_proxy_new_for_name (connection,
     505                                           CK_NAME,
     506                                           session_id,
     507                                           CK_SESSION_INTERFACE);
     508        if (proxy == NULL) {
     509                g_warning ("Failed to connect to the ConsoleKit session object");
     510                goto out;
     511        }
     512
     513        error = NULL;
     514        res = dbus_g_proxy_call (proxy,
     515                                 "GetSeatId",
     516                                 &error,
     517                                 G_TYPE_INVALID,
     518                                 DBUS_TYPE_G_OBJECT_PATH, &seat_id,
     519                                 G_TYPE_INVALID);
     520        if (! res) {
     521                g_debug ("Failed to identify the current seat: %s", error->message);
     522                g_error_free (error);
     523        }
     524 out:
     525        if (proxy != NULL) {
     526                g_object_unref (proxy);
     527        }
     528
     529        return seat_id;
     530}
     531
     532static char *
     533get_x11_display_for_session (DBusGConnection *connection,
     534                             const char      *session_id)
     535{
     536        DBusGProxy      *proxy;
     537        GError          *error;
     538        char            *x11_display;
     539        gboolean         res;
     540
     541        proxy = NULL;
     542        x11_display = NULL;
     543
     544        proxy = dbus_g_proxy_new_for_name (connection,
     545                                           CK_NAME,
     546                                           session_id,
     547                                           CK_SESSION_INTERFACE);
     548        if (proxy == NULL) {
     549                g_warning ("Failed to connect to the ConsoleKit session object");
     550                goto out;
     551        }
     552
     553        error = NULL;
     554        res = dbus_g_proxy_call (proxy,
     555                                 "GetX11Display",
     556                                 &error,
     557                                 G_TYPE_INVALID,
     558                                 G_TYPE_STRING, &x11_display,
     559                                 G_TYPE_INVALID);
     560        if (! res) {
     561                g_debug ("Failed to identify the x11 display: %s", error->message);
     562                g_error_free (error);
     563        }
     564 out:
     565        if (proxy != NULL) {
     566                g_object_unref (proxy);
     567        }
     568
     569        return x11_display;
     570}
     571
     572static gboolean
     573maybe_add_session_for_user (GdmUserManager *manager,
     574                            GdmUser        *user,
     575                            const char     *ssid)
     576{
     577        char    *sid;
     578        char    *x11_display;
     579        gboolean ret;
     580
     581        ret = FALSE;
     582        sid = NULL;
     583        x11_display = NULL;
     584
     585        /* skip if on another seat */
     586        sid = get_seat_id_for_session (manager->priv->connection, ssid);
     587        if (sid == NULL
     588            || manager->priv->seat_id == NULL
     589            || strcmp (sid, manager->priv->seat_id) != 0) {
     590                g_debug ("GdmUserManager: not adding session on other seat: %s", ssid);
     591                goto out;
     592        }
     593
     594        /* skip if doesn't have an x11 display */
     595        x11_display = get_x11_display_for_session (manager->priv->connection, ssid);
     596        if (x11_display == NULL || x11_display[0] == '\0') {
     597                g_debug ("GdmUserManager: not adding session without a x11 display: %s", ssid);
     598                goto out;
     599        }
     600
     601        if (g_hash_table_lookup (manager->priv->exclusions, gdm_user_get_user_name (user))) {
     602                g_debug ("GdmUserManager: excluding user '%s'", gdm_user_get_user_name (user));
     603                goto out;
     604        }
     605
     606        g_hash_table_insert (manager->priv->sessions,
     607                             g_strdup (ssid),
     608                             g_strdup (gdm_user_get_user_name (user)));
     609
     610        _gdm_user_add_session (user, ssid);
     611        g_debug ("GdmUserManager: added session for user: %s", gdm_user_get_user_name (user));
     612
     613        ret = TRUE;
     614
     615 out:
     616        g_free (sid);
     617        g_free (x11_display);
     618
     619        return ret;
     620}
     621
     622static void
     623add_sessions_for_user (GdmUserManager *manager,
     624                       GdmUser        *user)
     625{
     626        DBusGProxy      *proxy;
     627        GError          *error;
     628        gboolean         res;
     629        guint32          uid;
     630        GPtrArray       *sessions;
     631        int              i;
     632
     633        proxy = dbus_g_proxy_new_for_name (manager->priv->connection,
     634                                           CK_NAME,
     635                                           CK_MANAGER_PATH,
     636                                           CK_MANAGER_INTERFACE);
     637        if (proxy == NULL) {
     638                g_warning ("Failed to connect to the ConsoleKit manager object");
     639                goto out;
     640        }
     641
     642        uid = gdm_user_get_uid (user);
     643
     644        g_debug ("Getting list of sessions for user %u", uid);
     645
     646        error = NULL;
     647        res = dbus_g_proxy_call (proxy,
     648                                 "GetSessionsForUnixUser",
     649                                 &error,
     650                                 G_TYPE_UINT, uid,
     651                                 G_TYPE_INVALID,
     652                                 dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
     653                                 &sessions,
     654                                 G_TYPE_INVALID);
     655        if (! res) {
     656                g_debug ("Failed to find sessions for user: %s", error->message);
     657                g_error_free (error);
     658                goto out;
     659        }
     660
     661        g_debug ("Found %d sessions for user %s", sessions->len, gdm_user_get_user_name (user));
     662
     663        for (i = 0; i < sessions->len; i++) {
     664                char *ssid;
     665
     666                ssid = g_ptr_array_index (sessions, i);
     667                maybe_add_session_for_user (manager, user, ssid);
     668        }
     669
     670        g_ptr_array_foreach (sessions, (GFunc)g_free, NULL);
     671        g_ptr_array_free (sessions, TRUE);
     672
     673 out:
     674        if (proxy != NULL) {
     675                g_object_unref (proxy);
     676        }
     677}
     678
     679static GdmUser *
     680create_user (GdmUserManager *manager)
     681{
     682        GdmUser *user;
     683
     684        user = g_object_new (GDM_TYPE_USER, "manager", manager, NULL);
     685        g_signal_connect (user,
     686                          "sessions-changed",
     687                          G_CALLBACK (on_user_sessions_changed),
     688                          manager);
     689        g_signal_connect (user,
     690                          "icon-changed",
     691                          G_CALLBACK (on_user_icon_changed),
     692                          manager);
     693        return user;
     694}
     695
     696static void
     697add_user (GdmUserManager *manager,
     698          GdmUser        *user)
     699{
     700        add_sessions_for_user (manager, user);
     701        g_hash_table_insert (manager->priv->users,
     702                             g_strdup (gdm_user_get_user_name (user)),
     703                             g_object_ref (user));
     704
     705        g_signal_emit (manager, signals[USER_ADDED], 0, user);
     706}
     707
     708static GdmUser *
     709add_new_user_for_pwent (GdmUserManager *manager,
     710                        struct passwd  *pwent)
     711{
     712        GdmUser *user;
     713
     714        g_debug ("Creating new user");
     715
     716        user = create_user (manager);
     717        _gdm_user_update (user, pwent);
     718
     719        add_user (manager, user);
     720
     721        return user;
     722}
     723
     724static char *
     725get_current_seat_id (DBusGConnection *connection)
     726{
     727        DBusGProxy      *proxy;
     728        GError          *error;
     729        char            *session_id;
     730        char            *seat_id;
     731        gboolean         res;
     732
     733        proxy = NULL;
     734        session_id = NULL;
     735        seat_id = NULL;
     736
     737        proxy = dbus_g_proxy_new_for_name (connection,
     738                                           CK_NAME,
     739                                           CK_MANAGER_PATH,
     740                                           CK_MANAGER_INTERFACE);
     741        if (proxy == NULL) {
     742                g_warning ("Failed to connect to the ConsoleKit manager object");
     743                goto out;
     744        }
     745
     746        error = NULL;
     747        res = dbus_g_proxy_call (proxy,
     748                                 "GetCurrentSession",
     749                                 &error,
     750                                 G_TYPE_INVALID,
     751                                 DBUS_TYPE_G_OBJECT_PATH,
     752                                 &session_id,
     753                                 G_TYPE_INVALID);
     754        if (! res) {
     755                g_debug ("Failed to identify the current session: %s", error->message);
     756                g_error_free (error);
     757                goto out;
     758        }
     759
     760        seat_id = get_seat_id_for_session (connection, session_id);
     761
     762 out:
     763        if (proxy != NULL) {
     764                g_object_unref (proxy);
     765        }
     766        g_free (session_id);
     767
     768        return seat_id;
     769}
     770
     771static gboolean
     772get_uid_from_session_id (GdmUserManager *manager,
     773                         const char     *session_id,
     774                         uid_t          *uidp)
     775{
     776        DBusGProxy      *proxy;
     777        GError          *error;
     778        guint            uid;
     779        gboolean         res;
     780
     781        proxy = dbus_g_proxy_new_for_name (manager->priv->connection,
     782                                           CK_NAME,
     783                                           session_id,
     784                                           CK_SESSION_INTERFACE);
     785        if (proxy == NULL) {
     786                g_warning ("Failed to connect to the ConsoleKit session object");
     787                return FALSE;
     788        }
     789
     790        error = NULL;
     791        res = dbus_g_proxy_call (proxy,
     792                                 "GetUnixUser",
     793                                 &error,
     794                                 G_TYPE_INVALID,
     795                                 G_TYPE_UINT, &uid,
     796                                 G_TYPE_INVALID);
     797        g_object_unref (proxy);
     798
     799        if (! res) {
     800                g_warning ("Failed to query the session: %s", error->message);
     801                g_error_free (error);
     802                return FALSE;
     803        }
     804
     805        if (uidp != NULL) {
     806                *uidp = (uid_t) uid;
     807        }
     808
     809        return TRUE;
     810}
     811
     812static void
     813seat_session_added (DBusGProxy     *seat_proxy,
     814                    const char     *session_id,
     815                    GdmUserManager *manager)
     816{
     817        uid_t          uid;
     818        gboolean       res;
     819        struct passwd *pwent;
     820        GdmUser       *user;
     821        gboolean       is_new;
     822
     823        g_debug ("Session added: %s", session_id);
     824
     825        res = get_uid_from_session_id (manager, session_id, &uid);
     826        if (! res) {
     827                g_warning ("Unable to lookup user for session");
     828                return;
     829        }
     830
     831        errno = 0;
     832        pwent = getpwuid (uid);
     833        if (pwent == NULL) {
     834                g_warning ("Unable to lookup user id %d: %s", (int)uid, g_strerror (errno));
     835                return;
     836        }
     837
     838        /* check exclusions up front */
     839        if (g_hash_table_lookup (manager->priv->exclusions, pwent->pw_name)) {
     840                g_debug ("GdmUserManager: excluding user '%s'", pwent->pw_name);
     841                return;
     842        }
     843
     844        user = g_hash_table_lookup (manager->priv->users, pwent->pw_name);
     845        if (user == NULL) {
     846                g_debug ("Creating new user");
     847
     848                user = create_user (manager);
     849                _gdm_user_update (user, pwent);
     850                is_new = TRUE;
     851        } else {
     852                is_new = FALSE;
     853        }
     854
     855        res = maybe_add_session_for_user (manager, user, session_id);
     856
     857        /* only add the user if we added a session */
     858        if (is_new) {
     859                if (res) {
     860                        add_user (manager, user);
     861                } else {
     862                        g_object_unref (user);
     863                }
     864        }
     865}
     866
     867static void
     868seat_session_removed (DBusGProxy     *seat_proxy,
     869                      const char     *session_id,
     870                      GdmUserManager *manager)
     871{
     872        GdmUser *user;
     873        char    *username;
     874
     875        g_debug ("Session removed: %s", session_id);
     876
     877        /* since the session object may already be gone
     878         * we can't query CK directly */
     879
     880        username = g_hash_table_lookup (manager->priv->sessions, session_id);
     881        if (username == NULL) {
     882                return;
     883        }
     884
     885        user = g_hash_table_lookup (manager->priv->users, username);
     886        if (user == NULL) {
     887                /* nothing to do */
     888                return;
     889        }
     890
     891        g_debug ("GdmUserManager: Session removed for %s", username);
     892        _gdm_user_remove_session (user, session_id);
     893}
     894
     895static void
     896on_proxy_destroy (DBusGProxy     *proxy,
     897                  GdmUserManager *manager)
     898{
     899        g_debug ("GdmUserManager: seat proxy destroyed");
     900
     901        manager->priv->seat_proxy = NULL;
     902}
     903
     904static void
     905get_seat_proxy (GdmUserManager *manager)
     906{
     907        DBusGProxy      *proxy;
     908        GError          *error;
     909
     910        g_assert (manager->priv->seat_proxy == NULL);
     911
     912        error = NULL;
     913        manager->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
     914        if (manager->priv->connection == NULL) {
     915                g_warning ("Failed to connect to the D-Bus daemon: %s", error->message);
     916                g_error_free (error);
     917                return;
     918        }
     919
     920        manager->priv->seat_id = get_current_seat_id (manager->priv->connection);
     921        if (manager->priv->seat_id == NULL) {
     922                return;
     923        }
     924
     925        g_debug ("GdmUserManager: Found current seat: %s", manager->priv->seat_id);
     926
     927        error = NULL;
     928        proxy = dbus_g_proxy_new_for_name_owner (manager->priv->connection,
     929                                                 CK_NAME,
     930                                                 manager->priv->seat_id,
     931                                                 CK_SEAT_INTERFACE,
     932                                                 &error);
     933
     934        if (proxy == NULL) {
     935                g_warning ("Failed to connect to the ConsoleKit seat object: %s", error->message);
     936                g_error_free (error);
     937                return;
     938        }
     939
     940        g_signal_connect (proxy, "destroy", G_CALLBACK (on_proxy_destroy), manager);
     941
     942        dbus_g_proxy_add_signal (proxy,
     943                                 "SessionAdded",
     944                                 DBUS_TYPE_G_OBJECT_PATH,
     945                                 G_TYPE_INVALID);
     946        dbus_g_proxy_add_signal (proxy,
     947                                 "SessionRemoved",
     948                                 DBUS_TYPE_G_OBJECT_PATH,
     949                                 G_TYPE_INVALID);
     950        dbus_g_proxy_connect_signal (proxy,
     951                                     "SessionAdded",
     952                                     G_CALLBACK (seat_session_added),
     953                                     manager,
     954                                     NULL);
     955        dbus_g_proxy_connect_signal (proxy,
     956                                     "SessionRemoved",
     957                                     G_CALLBACK (seat_session_removed),
     958                                     manager,
     959                                     NULL);
     960        manager->priv->seat_proxy = proxy;
     961
     962}
     963
     964/**
     965 * gdm_manager_get_user:
     966 * @manager: the manager to query.
     967 * @username: the login name of the user to get.
     968 *
     969 * Retrieves a pointer to the #GdmUser object for the login named @username
     970 * from @manager. This pointer is not a reference, and should not be released.
     971 *
     972 * Returns: a pointer to a #GdmUser object.
     973 **/
     974GdmUser *
     975gdm_user_manager_get_user (GdmUserManager *manager,
     976                           const char     *username)
     977{
     978        GdmUser *user;
     979
     980        g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), NULL);
     981        g_return_val_if_fail (username != NULL && username[0] != '\0', NULL);
     982
     983        user = g_hash_table_lookup (manager->priv->users, username);
     984
     985        if (user == NULL) {
     986                struct passwd *pwent;
     987
     988                pwent = getpwnam (username);
     989
     990                if (pwent != NULL) {
     991                        user = add_new_user_for_pwent (manager, pwent);
     992                }
     993        }
     994
     995        return user;
     996}
     997
     998GdmUser *
     999gdm_user_manager_get_user_by_uid (GdmUserManager *manager,
     1000                                  uid_t           uid)
     1001{
     1002        GdmUser       *user;
     1003        struct passwd *pwent;
     1004
     1005        g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), NULL);
     1006
     1007        pwent = getpwuid (uid);
     1008        if (pwent == NULL) {
     1009                g_warning ("GdmUserManager: unable to lookup uid %d", (int)uid);
     1010                return NULL;
     1011        }
     1012
     1013        user = g_hash_table_lookup (manager->priv->users, pwent->pw_name);
     1014
     1015        if (user == NULL) {
     1016                user = add_new_user_for_pwent (manager, pwent);
     1017        }
     1018
     1019        return user;
     1020}
     1021
     1022static void
     1023listify_hash_values_hfunc (gpointer key,
     1024                           gpointer value,
     1025                           gpointer user_data)
     1026{
     1027        GSList **list = user_data;
     1028
     1029        *list = g_slist_prepend (*list, value);
     1030}
     1031
     1032GSList *
     1033gdm_user_manager_list_users (GdmUserManager *manager)
     1034{
     1035        GSList *retval;
     1036
     1037        g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), NULL);
     1038
     1039        retval = NULL;
     1040        g_hash_table_foreach (manager->priv->users, listify_hash_values_hfunc, &retval);
     1041
     1042        return g_slist_sort (retval, (GCompareFunc) gdm_user_collate);
     1043}
     1044
     1045static gboolean
     1046parse_value_as_ulong (const char *value,
     1047                      gulong     *ulongval)
     1048{
     1049        char  *end_of_valid_long;
     1050        glong  long_value;
     1051        gulong ulong_value;
     1052
     1053        errno = 0;
     1054        long_value = strtol (value, &end_of_valid_long, 10);
     1055
     1056        if (*value == '\0' || *end_of_valid_long != '\0') {
     1057                return FALSE;
     1058        }
     1059
     1060        ulong_value = long_value;
     1061        if (ulong_value != long_value || errno == ERANGE) {
     1062                return FALSE;
     1063        }
     1064
     1065        *ulongval = ulong_value;
     1066
     1067        return TRUE;
     1068}
     1069
     1070static gboolean
     1071parse_ck_history_line (const char *line,
     1072                       char      **user_namep,
     1073                       gulong     *frequencyp)
     1074{
     1075        GRegex     *re;
     1076        GMatchInfo *match_info;
     1077        gboolean    res;
     1078        gboolean    ret;
     1079        GError     *error;
     1080
     1081        ret = FALSE;
     1082        re = NULL;
     1083        match_info = NULL;
     1084
     1085        error = NULL;
     1086        re = g_regex_new ("(?P<username>[0-9a-zA-Z]+)[ ]+(?P<frequency>[0-9]+)", 0, 0, &error);
     1087        if (re == NULL) {
     1088                g_critical ("%s", error->message);
     1089                goto out;
     1090        }
     1091
     1092        g_regex_match (re, line, 0, &match_info);
     1093
     1094        res = g_match_info_matches (match_info);
     1095        if (! res) {
     1096                g_warning ("Unable to parse history: %s", line);
     1097                goto out;
     1098        }
     1099
     1100        if (user_namep != NULL) {
     1101                *user_namep = g_match_info_fetch_named (match_info, "username");
     1102        }
     1103
     1104        if (frequencyp != NULL) {
     1105                char *freq;
     1106                freq = g_match_info_fetch_named (match_info, "frequency");
     1107                res = parse_value_as_ulong (freq, frequencyp);
     1108                g_free (freq);
     1109                if (! res) {
     1110                        goto out;
     1111                }
     1112        }
     1113
     1114        ret = TRUE;
     1115
     1116 out:
     1117        if (match_info != NULL) {
     1118                g_match_info_free (match_info);
     1119        }
     1120        if (re != NULL) {
     1121                g_regex_unref (re);
     1122        }
     1123        return ret;
     1124}
     1125
     1126static void
     1127process_ck_history_line (GdmUserManager *manager,
     1128                         const char     *line)
     1129{
     1130        gboolean res;
     1131        char    *username;
     1132        gulong   frequency;
     1133        struct passwd *pwent;
     1134        GdmUser *user;
     1135
     1136        frequency = 0;
     1137        username = NULL;
     1138        res = parse_ck_history_line (line, &username, &frequency);
     1139        if (! res) {
     1140                return;
     1141        }
     1142
     1143        if (g_hash_table_lookup (manager->priv->exclusions, username)) {
     1144                g_debug ("GdmUserManager: excluding user '%s'", username);
     1145                g_free (username);
     1146                return;
     1147        }
     1148
     1149        /* https://bugzilla.gnome.org/show_bug.cgi?id=587708 */
     1150        /* do not show system users; we cannot use gdm_user_manager_get_user()
     1151         * here since this creates/signals users as a side effect */
     1152        pwent = getpwnam (username);
     1153        if (pwent == NULL) {
     1154                g_warning ("Unable to lookup user name %s: %s", username, g_strerror (errno));
     1155                return;
     1156        }
     1157        if (pwent->pw_uid < DEFAULT_MINIMAL_UID) {
     1158                g_debug ("GdmUserManager: excluding user '%s'", username);
     1159                return;
     1160        }
     1161
     1162        user = gdm_user_manager_get_user (manager, username);
     1163        if (user == NULL) {
     1164                g_debug ("GdmUserManager: unable to lookup user '%s'", username);
     1165                g_free (username);
     1166                return;
     1167        }
     1168
     1169        g_object_set (user, "login-frequency", frequency, NULL);
     1170        g_signal_emit (manager, signals [USER_LOGIN_FREQUENCY_CHANGED], 0, user);
     1171        g_free (username);
     1172}
     1173
     1174static gboolean
     1175ck_history_watch (GIOChannel     *source,
     1176                  GIOCondition    condition,
     1177                  GdmUserManager *manager)
     1178{
     1179        GIOStatus status;
     1180        gboolean  done  = FALSE;
     1181
     1182        g_return_val_if_fail (manager != NULL, FALSE);
     1183
     1184        if (condition & G_IO_IN) {
     1185                char   *str;
     1186                GError *error;
     1187
     1188                error = NULL;
     1189                status = g_io_channel_read_line (source, &str, NULL, NULL, &error);
     1190                if (error != NULL) {
     1191                        g_warning ("GdmUserManager: unable to read line: %s", error->message);
     1192                        g_error_free (error);
     1193                }
     1194
     1195                if (status == G_IO_STATUS_NORMAL) {
     1196                        g_debug ("GdmUserManager: history output: %s", str);
     1197                        process_ck_history_line (manager, str);
     1198                } else if (status == G_IO_STATUS_EOF) {
     1199                        done = TRUE;
     1200                }
     1201
     1202                g_free (str);
     1203        } else if (condition & G_IO_HUP) {
     1204                done = TRUE;
     1205        }
     1206
     1207        if (done) {
     1208                g_signal_emit (G_OBJECT (manager), signals[USERS_LOADED], 0);
     1209
     1210                manager->priv->ck_history_id = 0;
     1211                return FALSE;
     1212        }
     1213
     1214        return TRUE;
     1215}
     1216
     1217static void
     1218reload_ck_history (GdmUserManager *manager)
     1219{
     1220        char       *command;
     1221        const char *seat_id;
     1222        GError     *error;
     1223        gboolean    res;
     1224        char      **argv;
     1225        int         standard_out;
     1226        GIOChannel *channel;
     1227
     1228        seat_id = NULL;
     1229        if (manager->priv->seat_id != NULL
     1230            && g_str_has_prefix (manager->priv->seat_id, "/org/freedesktop/ConsoleKit/")) {
     1231
     1232                seat_id = manager->priv->seat_id + strlen ("/org/freedesktop/ConsoleKit/");
     1233        }
     1234
     1235        if (seat_id == NULL) {
     1236                g_warning ("Unable to find users: no seat-id found");
     1237                return;
     1238        }
     1239
     1240        command = g_strdup_printf ("ck-history --frequent --seat='%s' --session-type=''",
     1241                                   seat_id);
     1242        g_debug ("GdmUserManager: running '%s'", command);
     1243        error = NULL;
     1244        if (! g_shell_parse_argv (command, NULL, &argv, &error)) {
     1245                g_warning ("Could not parse command: %s", error->message);
     1246                g_error_free (error);
     1247                goto out;
     1248        }
     1249
     1250        error = NULL;
     1251        res = g_spawn_async_with_pipes (NULL,
     1252                                        argv,
     1253                                        NULL,
     1254                                        G_SPAWN_SEARCH_PATH,
     1255                                        NULL,
     1256                                        NULL,
     1257                                        NULL, /* pid */
     1258                                        NULL,
     1259                                        &standard_out,
     1260                                        NULL,
     1261                                        &error);
     1262        g_strfreev (argv);
     1263        if (! res) {
     1264                g_warning ("Unable to run ck-history: %s", error->message);
     1265                g_error_free (error);
     1266                goto out;
     1267        }
     1268
     1269        channel = g_io_channel_unix_new (standard_out);
     1270        g_io_channel_set_close_on_unref (channel, TRUE);
     1271        g_io_channel_set_flags (channel,
     1272                                g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK,
     1273                                NULL);
     1274        manager->priv->ck_history_id = g_io_add_watch (channel,
     1275                                                       G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
     1276                                                       (GIOFunc)ck_history_watch,
     1277                                                       manager);
     1278        g_io_channel_unref (channel);
     1279
     1280 out:
     1281        g_free (command);
     1282}
     1283
     1284static void
     1285reload_passwd (GdmUserManager *manager)
     1286{
     1287        struct passwd *pwent;
     1288        GSList        *old_users;
     1289        GSList        *new_users;
     1290        GSList        *list;
     1291        FILE          *fp;
     1292
     1293        old_users = NULL;
     1294        new_users = NULL;
     1295
     1296        errno = 0;
     1297        fp = fopen (PATH_PASSWD, "r");
     1298        if (fp == NULL) {
     1299                g_warning ("Unable to open %s: %s", PATH_PASSWD, g_strerror (errno));
     1300                goto out;
     1301        }
     1302
     1303        g_hash_table_foreach (manager->priv->users, listify_hash_values_hfunc, &old_users);
     1304        g_slist_foreach (old_users, (GFunc) g_object_ref, NULL);
     1305
     1306        /* Make sure we keep users who are logged in no matter what. */
     1307        for (list = old_users; list; list = list->next) {
     1308                if (gdm_user_get_num_sessions (list->data) > 0) {
     1309                        g_object_freeze_notify (G_OBJECT (list->data));
     1310                        new_users = g_slist_prepend (new_users, g_object_ref (list->data));
     1311                }
     1312        }
     1313
     1314        for (pwent = fgetpwent (fp); pwent != NULL; pwent = fgetpwent (fp)) {
     1315                GdmUser *user;
     1316
     1317                user = NULL;
     1318
     1319                /* Skip users below MinimalUID... */
     1320                if (pwent->pw_uid < DEFAULT_MINIMAL_UID) {
     1321                        continue;
     1322                }
     1323
     1324                /* ...And users w/ invalid shells... */
     1325                if (pwent->pw_shell == NULL ||
     1326                    !g_hash_table_lookup (manager->priv->shells, pwent->pw_shell)) {
     1327                        g_debug ("GdmUserManager: skipping user with bad shell: %s", pwent->pw_name);
     1328                        continue;
     1329                }
     1330
     1331                /* ...And explicitly excluded users */
     1332                if (g_hash_table_lookup (manager->priv->exclusions, pwent->pw_name)) {
     1333                        g_debug ("GdmUserManager: explicitly skipping user: %s", pwent->pw_name);
     1334                        continue;
     1335                }
     1336
     1337                user = g_hash_table_lookup (manager->priv->users, pwent->pw_name);
     1338
     1339                /* Update users already in the *new* list */
     1340                if (g_slist_find (new_users, user)) {
     1341                        _gdm_user_update (user, pwent);
     1342                        continue;
     1343                }
     1344
     1345                if (user == NULL) {
     1346                        user = create_user (manager);
     1347                } else {
     1348                        g_object_ref (user);
     1349                }
     1350
     1351                /* Freeze & update users not already in the new list */
     1352                g_object_freeze_notify (G_OBJECT (user));
     1353                _gdm_user_update (user, pwent);
     1354
     1355                new_users = g_slist_prepend (new_users, user);
     1356        }
     1357
     1358        /* Go through and handle added users */
     1359        for (list = new_users; list; list = list->next) {
     1360                if (! g_slist_find (old_users, list->data)) {
     1361                        add_user (manager, list->data);
     1362                }
     1363        }
     1364
     1365        /* Go through and handle removed users */
     1366        for (list = old_users; list; list = list->next) {
     1367                if (! g_slist_find (new_users, list->data)) {
     1368                        g_signal_emit (manager, signals[USER_REMOVED], 0, list->data);
     1369                        g_hash_table_remove (manager->priv->users,
     1370                                             gdm_user_get_user_name (list->data));
     1371                }
     1372        }
     1373
     1374 out:
     1375        /* Cleanup */
     1376
     1377        fclose (fp);
     1378
     1379        g_slist_foreach (new_users, (GFunc) g_object_thaw_notify, NULL);
     1380        g_slist_foreach (new_users, (GFunc) g_object_unref, NULL);
     1381        g_slist_free (new_users);
     1382
     1383        g_slist_foreach (old_users, (GFunc) g_object_unref, NULL);
     1384        g_slist_free (old_users);
     1385}
     1386
     1387static void
     1388reload_users (GdmUserManager *manager)
     1389{
     1390        reload_ck_history (manager);
     1391        reload_passwd (manager);
     1392}
     1393
     1394static gboolean
     1395reload_users_timeout (GdmUserManager *manager)
     1396{
     1397        reload_users (manager);
     1398        manager->priv->reload_id = 0;
     1399
     1400        return FALSE;
     1401}
     1402
     1403static void
     1404queue_reload_users (GdmUserManager *manager)
     1405{
     1406        if (manager->priv->reload_id > 0) {
     1407                return;
     1408        }
     1409
     1410        g_signal_emit (G_OBJECT (manager), signals[LOADING_USERS], 0);
     1411        manager->priv->reload_id = g_idle_add ((GSourceFunc)reload_users_timeout, manager);
     1412}
     1413
     1414static void
     1415reload_shells (GdmUserManager *manager)
     1416{
     1417        char *shell;
     1418
     1419        setusershell ();
     1420
     1421        g_hash_table_remove_all (manager->priv->shells);
     1422        for (shell = getusershell (); shell != NULL; shell = getusershell ()) {
     1423                /* skip well known not-real shells */
     1424                if (shell == NULL
     1425                    || strcmp (shell, "/sbin/nologin") == 0
     1426                    || strcmp (shell, "/bin/false") == 0) {
     1427                        g_debug ("GdmUserManager: skipping shell %s", shell);
     1428                        continue;
     1429                }
     1430                g_hash_table_insert (manager->priv->shells,
     1431                                     g_strdup (shell),
     1432                                     GUINT_TO_POINTER (TRUE));
     1433        }
     1434
     1435        endusershell ();
     1436}
     1437
     1438static void
     1439on_shells_monitor_changed (GFileMonitor     *monitor,
     1440                           GFile            *file,
     1441                           GFile            *other_file,
     1442                           GFileMonitorEvent event_type,
     1443                           GdmUserManager   *manager)
     1444{
     1445        if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
     1446            event_type != G_FILE_MONITOR_EVENT_CREATED) {
     1447                return;
     1448        }
     1449
     1450        reload_shells (manager);
     1451        reload_passwd (manager);
     1452}
     1453
     1454static void
     1455on_passwd_monitor_changed (GFileMonitor     *monitor,
     1456                           GFile            *file,
     1457                           GFile            *other_file,
     1458                           GFileMonitorEvent event_type,
     1459                           GdmUserManager   *manager)
     1460{
     1461        if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
     1462            event_type != G_FILE_MONITOR_EVENT_CREATED) {
     1463                return;
     1464        }
     1465
     1466        reload_passwd (manager);
     1467}
     1468
     1469static void
     1470gdm_user_manager_class_init (GdmUserManagerClass *klass)
     1471{
     1472        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
     1473
     1474        object_class->finalize = gdm_user_manager_finalize;
     1475
     1476        signals [LOADING_USERS] =
     1477                g_signal_new ("loading-users",
     1478                              G_TYPE_FROM_CLASS (klass),
     1479                              G_SIGNAL_RUN_LAST,
     1480                              G_STRUCT_OFFSET (GdmUserManagerClass, loading_users),
     1481                              NULL, NULL,
     1482                              g_cclosure_marshal_VOID__VOID,
     1483                              G_TYPE_NONE, 0);
     1484        signals [USERS_LOADED] =
     1485                g_signal_new ("users-loaded",
     1486                              G_TYPE_FROM_CLASS (klass),
     1487                              G_SIGNAL_RUN_LAST,
     1488                              G_STRUCT_OFFSET (GdmUserManagerClass, users_loaded),
     1489                              NULL, NULL,
     1490                              g_cclosure_marshal_VOID__VOID,
     1491                              G_TYPE_NONE, 0);
     1492        signals [USER_ADDED] =
     1493                g_signal_new ("user-added",
     1494                              G_TYPE_FROM_CLASS (klass),
     1495                              G_SIGNAL_RUN_LAST,
     1496                              G_STRUCT_OFFSET (GdmUserManagerClass, user_added),
     1497                              NULL, NULL,
     1498                              g_cclosure_marshal_VOID__OBJECT,
     1499                              G_TYPE_NONE, 1, GDM_TYPE_USER);
     1500        signals [USER_REMOVED] =
     1501                g_signal_new ("user-removed",
     1502                              G_TYPE_FROM_CLASS (klass),
     1503                              G_SIGNAL_RUN_LAST,
     1504                              G_STRUCT_OFFSET (GdmUserManagerClass, user_removed),
     1505                              NULL, NULL,
     1506                              g_cclosure_marshal_VOID__OBJECT,
     1507                              G_TYPE_NONE, 1, GDM_TYPE_USER);
     1508        signals [USER_IS_LOGGED_IN_CHANGED] =
     1509                g_signal_new ("user-is-logged-in-changed",
     1510                              G_TYPE_FROM_CLASS (klass),
     1511                              G_SIGNAL_RUN_LAST,
     1512                              G_STRUCT_OFFSET (GdmUserManagerClass, user_is_logged_in_changed),
     1513                              NULL, NULL,
     1514                              g_cclosure_marshal_VOID__OBJECT,
     1515                              G_TYPE_NONE, 1, GDM_TYPE_USER);
     1516        signals [USER_LOGIN_FREQUENCY_CHANGED] =
     1517                g_signal_new ("user-login-frequency-changed",
     1518                              G_TYPE_FROM_CLASS (klass),
     1519                              G_SIGNAL_RUN_LAST,
     1520                              G_STRUCT_OFFSET (GdmUserManagerClass, user_login_frequency_changed),
     1521                              NULL, NULL,
     1522                              g_cclosure_marshal_VOID__OBJECT,
     1523                              G_TYPE_NONE, 1, GDM_TYPE_USER);
     1524
     1525        g_type_class_add_private (klass, sizeof (GdmUserManagerPrivate));
     1526}
     1527
     1528static void
     1529gdm_user_manager_init (GdmUserManager *manager)
     1530{
     1531        int            i;
     1532        GFile         *file;
     1533        GError        *error;
     1534        const char    *exclude_default[] = DEFAULT_EXCLUDE;
     1535
     1536        manager->priv = GDM_USER_MANAGER_GET_PRIVATE (manager);
     1537
     1538        /* sessions */
     1539        manager->priv->sessions = g_hash_table_new_full (g_str_hash,
     1540                                                         g_str_equal,
     1541                                                         g_free,
     1542                                                         g_free);
     1543
     1544        /* exclusions */
     1545        manager->priv->exclusions = g_hash_table_new_full (g_str_hash,
     1546                                                           g_str_equal,
     1547                                                           g_free,
     1548                                                           NULL);
     1549        for (i = 0; exclude_default[i] != NULL; i++) {
     1550                g_hash_table_insert (manager->priv->exclusions,
     1551                                     g_strdup (exclude_default [i]),
     1552                                     GUINT_TO_POINTER (TRUE));
     1553        }
     1554
     1555        /* /etc/shells */
     1556        manager->priv->shells = g_hash_table_new_full (g_str_hash,
     1557                                                       g_str_equal,
     1558                                                       g_free,
     1559                                                       NULL);
     1560        reload_shells (manager);
     1561        file = g_file_new_for_path (_PATH_SHELLS);
     1562        error = NULL;
     1563        manager->priv->shells_monitor = g_file_monitor_file (file,
     1564                                                             G_FILE_MONITOR_NONE,
     1565                                                             NULL,
     1566                                                             &error);
     1567        if (manager->priv->shells_monitor != NULL) {
     1568                g_signal_connect (manager->priv->shells_monitor,
     1569                                  "changed",
     1570                                  G_CALLBACK (on_shells_monitor_changed),
     1571                                  manager);
     1572        } else {
     1573                g_warning ("Unable to monitor %s: %s", _PATH_SHELLS, error->message);
     1574                g_error_free (error);
     1575        }
     1576        g_object_unref (file);
     1577
     1578        /* /etc/passwd */
     1579        manager->priv->users = g_hash_table_new_full (g_str_hash,
     1580                                                      g_str_equal,
     1581                                                      g_free,
     1582                                                      (GDestroyNotify) g_object_run_dispose);
     1583        file = g_file_new_for_path (PATH_PASSWD);
     1584        manager->priv->passwd_monitor = g_file_monitor_file (file,
     1585                                                             G_FILE_MONITOR_NONE,
     1586                                                             NULL,
     1587                                                             &error);
     1588        if (manager->priv->passwd_monitor != NULL) {
     1589                g_signal_connect (manager->priv->passwd_monitor,
     1590                                  "changed",
     1591                                  G_CALLBACK (on_passwd_monitor_changed),
     1592                                  manager);
     1593        } else {
     1594                g_warning ("Unable to monitor %s: %s", PATH_PASSWD, error->message);
     1595                g_error_free (error);
     1596        }
     1597        g_object_unref (file);
     1598
     1599
     1600        get_seat_proxy (manager);
     1601
     1602        queue_reload_users (manager);
     1603
     1604        manager->priv->users_dirty = FALSE;
     1605}
     1606
     1607static void
     1608gdm_user_manager_finalize (GObject *object)
     1609{
     1610        GdmUserManager *manager;
     1611
     1612        g_return_if_fail (object != NULL);
     1613        g_return_if_fail (GDM_IS_USER_MANAGER (object));
     1614
     1615        manager = GDM_USER_MANAGER (object);
     1616
     1617        g_return_if_fail (manager->priv != NULL);
     1618
     1619        if (manager->priv->seat_proxy != NULL) {
     1620                g_object_unref (manager->priv->seat_proxy);
     1621        }
     1622
     1623        if (manager->priv->ck_history_id != 0) {
     1624                g_source_remove (manager->priv->ck_history_id);
     1625                manager->priv->ck_history_id = 0;
     1626        }
     1627
     1628        if (manager->priv->reload_id > 0) {
     1629                g_source_remove (manager->priv->reload_id);
     1630                manager->priv->reload_id = 0;
     1631        }
     1632
     1633        g_hash_table_destroy (manager->priv->sessions);
     1634
     1635        g_file_monitor_cancel (manager->priv->passwd_monitor);
     1636        g_hash_table_destroy (manager->priv->users);
     1637
     1638        g_file_monitor_cancel (manager->priv->shells_monitor);
     1639        g_hash_table_destroy (manager->priv->shells);
     1640
     1641        g_free (manager->priv->seat_id);
     1642
     1643        G_OBJECT_CLASS (gdm_user_manager_parent_class)->finalize (object);
     1644}
     1645
     1646GdmUserManager *
     1647gdm_user_manager_ref_default (void)
     1648{
     1649        if (user_manager_object != NULL) {
     1650                g_object_ref (user_manager_object);
     1651        } else {
     1652                user_manager_object = g_object_new (GDM_TYPE_USER_MANAGER, NULL);
     1653                g_object_add_weak_pointer (user_manager_object,
     1654                                           (gpointer *) &user_manager_object);
     1655        }
     1656
     1657        return GDM_USER_MANAGER (user_manager_object);
     1658}
  • gui/gdmsetup/gdm-user-manager.h

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/gui/gdmsetup/gdm-user-manager.h gdm-2.28.0.new/gui/gdmsetup/gdm-user-manager.h
    old new  
     1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
     2 *
     3 * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
     4 *
     5 * This program is free software; you can redistribute it and/or modify
     6 * it under the terms of the GNU General Public License as published by
     7 * the Free Software Foundation; either version 2 of the License, or
     8 * (at your option) any later version.
     9 *
     10 * This program is distributed in the hope that it will be useful,
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 * GNU General Public License for more details.
     14 *
     15 * You should have received a copy of the GNU General Public License
     16 * along with this program; if not, write to the Free Software
     17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     18 *
     19 */
     20
     21#ifndef __GDM_USER_MANAGER_H
     22#define __GDM_USER_MANAGER_H
     23
     24#include <glib-object.h>
     25
     26#include "gdm-user.h"
     27
     28G_BEGIN_DECLS
     29
     30#define GDM_TYPE_USER_MANAGER         (gdm_user_manager_get_type ())
     31#define GDM_USER_MANAGER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_USER_MANAGER, GdmUserManager))
     32#define GDM_USER_MANAGER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_USER_MANAGER, GdmUserManagerClass))
     33#define GDM_IS_USER_MANAGER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_USER_MANAGER))
     34#define GDM_IS_USER_MANAGER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_USER_MANAGER))
     35#define GDM_USER_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_USER_MANAGER, GdmUserManagerClass))
     36
     37typedef struct GdmUserManagerPrivate GdmUserManagerPrivate;
     38
     39typedef struct
     40{
     41        GObject                parent;
     42        GdmUserManagerPrivate *priv;
     43} GdmUserManager;
     44
     45typedef struct
     46{
     47        GObjectClass   parent_class;
     48
     49        void          (* loading_users)             (GdmUserManager *user_manager);
     50        void          (* users_loaded)              (GdmUserManager *user_manager);
     51        void          (* user_added)                (GdmUserManager *user_manager,
     52                                                     GdmUser        *user);
     53        void          (* user_removed)              (GdmUserManager *user_manager,
     54                                                     GdmUser        *user);
     55        void          (* user_is_logged_in_changed) (GdmUserManager *user_manager,
     56                                                     GdmUser        *user);
     57        void          (* user_login_frequency_changed) (GdmUserManager *user_manager,
     58                                                        GdmUser        *user);
     59} GdmUserManagerClass;
     60
     61typedef enum
     62{
     63        GDM_USER_MANAGER_ERROR_GENERAL,
     64        GDM_USER_MANAGER_ERROR_KEY_NOT_FOUND
     65} GdmUserManagerError;
     66
     67#define GDM_USER_MANAGER_ERROR gdm_user_manager_error_quark ()
     68
     69GQuark              gdm_user_manager_error_quark           (void);
     70GType               gdm_user_manager_get_type              (void);
     71
     72GdmUserManager *    gdm_user_manager_ref_default           (void);
     73
     74GSList *            gdm_user_manager_list_users            (GdmUserManager *manager);
     75GdmUser *           gdm_user_manager_get_user              (GdmUserManager *manager,
     76                                                            const char     *user_name);
     77GdmUser *           gdm_user_manager_get_user_by_uid       (GdmUserManager *manager,
     78                                                            uid_t           uid);
     79
     80gboolean            gdm_user_manager_activate_user_session (GdmUserManager *manager,
     81                                                            GdmUser        *user);
     82
     83gboolean            gdm_user_manager_goto_login_session    (GdmUserManager *manager);
     84
     85G_END_DECLS
     86
     87#endif /* __GDM_USER_MANAGER_H */
  • gui/gdmsetup/gdm-user-private.h

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/gui/gdmsetup/gdm-user-private.h gdm-2.28.0.new/gui/gdmsetup/gdm-user-private.h
    old new  
     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 *
     5 * This program is free software; you can redistribute it and/or modify
     6 * it under the terms of the GNU General Public License as published by
     7 * the Free Software Foundation; either version 2 of the License, or
     8 * (at your option) any later version.
     9 *
     10 * This program is distributed in the hope that it will be useful,
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 * GNU General Public License for more details.
     14 *
     15 * You should have received a copy of the GNU General Public License
     16 * along with this program; if not, write to the Free Software
     17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     18 */
     19
     20/*
     21 * Private interfaces to the GdmUser object
     22 */
     23
     24#ifndef __GDM_USER_PRIVATE__
     25#define __GDM_USER_PRIVATE__ 1
     26
     27#include <pwd.h>
     28
     29#include "gdm-user.h"
     30
     31G_BEGIN_DECLS
     32
     33void _gdm_user_update           (GdmUser             *user,
     34                                 const struct passwd *pwent);
     35void _gdm_user_add_session      (GdmUser             *user,
     36                                 const char          *session_id);
     37void _gdm_user_remove_session   (GdmUser             *user,
     38                                 const char          *session_id);
     39
     40void _gdm_user_icon_changed     (GdmUser             *user);
     41
     42G_END_DECLS
     43
     44#endif /* !__GDM_USER_PRIVATE__ */
  • gui/gdmsetup/Makefile.am

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/gui/gdmsetup/Makefile.am gdm-2.28.0.new/gui/gdmsetup/Makefile.am
    old new  
     1NULL =
     2
     3AM_CPPFLAGS = \
     4        -I$(top_srcdir)/common          \
     5        -DDATADIR=\""$(datadir)"\"      \
     6        -DUIDIR=\""$(uidir)"\"  \
     7        -DGNOMELOCALEDIR=\""$(gdmlocaledir)"\"  \
     8        $(GDMSETUP_CFLAGS)              \
     9        $(NULL)
     10
     11bin_PROGRAMS =                  \
     12        gdmsetup                \
     13        $(NULL)
     14
     15gdmsetup_SOURCES =              \
     16        gdmsetup.c              \
     17        gdm-user.c              \
     18        gdm-user-manager.c      \
     19        $(NULL)
     20
     21gdmsetup_LDADD =                \
     22        $(GDMSETUP_LIBS)        \
     23        $(NULL)
     24       
     25uidir = $(pkgdatadir)
     26ui_DATA =                       \
     27        gdmsetup.ui             \
     28        $(NULL)
     29
     30Utilitiesdir = $(datadir)/applications
     31Utilities_in_files = gdmsetup.desktop.in
     32Utilities_DATA = $(Utilities_in_files:.desktop.in=.desktop)
     33@INTLTOOL_DESKTOP_RULE@
     34
     35EXTRA_DIST =                    \
     36        $(ui_DATA)              \
     37        $(Utilities_in_files)   \
     38        $(NULL)
  • gui/Makefile.am

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/gui/Makefile.am gdm-2.28.0.new/gui/Makefile.am
    old new  
    11NULL =
    22
    33SUBDIRS =                       \
     4        gdmsetup                \
    45        simple-chooser          \
    56        simple-greeter          \
    67        user-switch-applet      \
  • po/POTFILES.in

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/po/POTFILES.in gdm-2.28.0.new/po/POTFILES.in
    old new  
    6060data/greeter-autostart/metacity.desktop.in
    6161data/greeter-autostart/orca-screen-reader.desktop.in
    6262data/greeter-autostart/polkit-gnome-authentication-agent-1.desktop.in
     63gui/gdmsetup/gdmsetup.desktop.in
     64gui/gdmsetup/gdmsetup.c
     65[type: gettext/glade]gui/gdmsetup/gdmsetup.ui
    6366gui/simple-chooser/gdm-host-chooser-dialog.c
    6467gui/simple-chooser/gdm-host-chooser-widget.c
    6568gui/simple-greeter/gdm-cell-renderer-timer.c
Note: See TracBrowser for help on using the repository browser.