[gdm-list] PoC for multiple pam prompts



Hi,

I've started to implement multiple pam prompts in gdmlogin. It looks
like this[1]:
http://www.suse.de/~lnussel/gdm/gdm1.png
http://www.suse.de/~lnussel/gdm/gdm2.png

The patch works but is not ready for production yet. gdmgreeter not
supported yet. I post it here for discussion and for the brave for
testing.

Something I am undecided about are convenience messages to the user
that are not originating from a pam conversation (like
authentication failed). verify-pam currently uses GDM_MSG and
GDM_ERRBOX for that. IMO there should be some dedicated way to show
such messages. I've added a status bar for the 'please enter your
username' message to see how that looks. Maybe a tooltip like popup
would be suitable for that as well.

cu
Ludwig

[1] might take a while until the web server actually mirrors it

-- 
 (o_   Ludwig Nussel
 //\   SUSE LINUX Products GmbH, Development
 V_/_  http://www.suse.de/




Index: gdm2/daemon/gdm.h
===================================================================
--- gdm2.orig/daemon/gdm.h
+++ gdm2/daemon/gdm.h
@@ -31,6 +31,7 @@
 				 * leaves MAX_PASS undefined. */
 
 #define STX 0x2			/* Start of txt */
+#define EOX 0x3			/* End of txt */
 #define BEL 0x7			/* Bell, used to interrupt login for
 				 * say timed login or something similar */
 
@@ -91,8 +92,9 @@ enum {
 
 /* This will change if there are incompatible
  * protocol changes */
-#define GDM_GREETER_PROTOCOL_VERSION "3"
+#define GDM_GREETER_PROTOCOL_VERSION "4"
 
+#define GDM_PAM_FORM   'p'
 #define GDM_MSG        'D'
 #define GDM_NOECHO     'U'
 #define GDM_PROMPT     'N'
Index: gdm2/daemon/slave.c
===================================================================
--- gdm2.orig/daemon/slave.c
+++ gdm2/daemon/slave.c
@@ -1995,10 +1995,12 @@ gdm_slave_wait_for_login (void)
 			g_free (login);
 			login = NULL;
 			/* clear any error */
+#if 0
 			gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, "");
 			gdm_slave_greeter_ctl_no_ret
 				(GDM_MSG,
 				 _("You must authenticate as root to run configuration."));
+#endif
 
 			/* we always allow root for this */
 			oldAllowRoot = gdm_get_value_bool (GDM_KEY_ALLOW_ROOT);
@@ -2018,8 +2020,10 @@ gdm_slave_wait_for_login (void)
 						 d->attached);
 			gdm_set_value_bool (GDM_KEY_ALLOW_ROOT, oldAllowRoot);
 
+#if 0
 			/* Clear message */
 			gdm_slave_greeter_ctl_no_ret (GDM_MSG, "");
+#endif
 
 			if G_UNLIKELY (do_restart_greeter) {
 				g_free (login);
Index: gdm2/daemon/verify-pam.c
===================================================================
--- gdm2.orig/daemon/verify-pam.c
+++ gdm2/daemon/verify-pam.c
@@ -468,6 +468,18 @@ perhaps_translate_message (const char *m
 /* Internal PAM conversation function. Interfaces between the PAM
  * authentication system and the actual greeter program */
 
+static inline char msg_style2gdm(int msg_style)
+{
+    switch (msg_style) {
+	case PAM_PROMPT_ECHO_ON: return GDM_PROMPT;
+	case PAM_PROMPT_ECHO_OFF: return GDM_NOECHO;
+	case PAM_ERROR_MSG: return GDM_ERRBOX;
+	case PAM_TEXT_INFO: return GDM_MSG;
+    }
+    gdm_assert_not_reached();
+    return 0;
+}
+
 static int 
 gdm_verify_pam_conv (int num_msg, const struct pam_message **msg,
 		     struct pam_response **resp,
@@ -476,10 +488,15 @@ gdm_verify_pam_conv (int num_msg, const 
     int replies = 0;
     int i;
     char *s = NULL;
+    char* str = NULL;
+    size_t sendbuflen = 0;
     struct pam_response *reply = NULL;
     const void *p;
     const char *login;
 
+    if(!num_msg) /* weird */
+	return PAM_SUCCESS;
+
     if (pamh == NULL)
 	return PAM_CONV_ERR;
     
@@ -491,18 +508,12 @@ gdm_verify_pam_conv (int num_msg, const 
     if ( ! gdm_slave_action_pending () || selected_user)
         return PAM_CONV_ERR;
 
-    reply = malloc (sizeof (struct pam_response) * num_msg);
-    
-    if (reply == NULL)
-	return PAM_CONV_ERR;
-
-    memset (reply, 0, sizeof (struct pam_response) * num_msg);
-
     /* Here we set the login if it wasn't already set,
      * this is kind of anal, but this way we guarantee that
      * the greeter always is up to date on the login */
     if (pam_get_item (pamh, PAM_USER, &p) == PAM_SUCCESS) {
-	    login = (const char *)p;
+	login = (const char *)p;
+	if(login)
 	    gdm_slave_greeter_ctl_no_ret (GDM_SETLOGIN, login);
     }
 
@@ -510,88 +521,105 @@ gdm_verify_pam_conv (int num_msg, const 
     closelog ();
     openlog ("gdm", LOG_PID, LOG_DAEMON);
     
+    if (gdm_slave_greeter_check_interruption ())
+	    return PAM_CONV_ERR;
+
+    /* check for valid form first */
+    if(num_msg > 255-'\n') {
+	gdm_error("too many prompts");
+	return PAM_CONV_ERR;
+    }
+    sendbuflen = 1 /* num_msg */;
+    for (replies = 0; replies < num_msg; replies++) {
+	switch ((*msg)[replies].msg_style) {
+	    case PAM_PROMPT_ECHO_OFF:
+	    case PAM_PROMPT_ECHO_ON:
+	    case PAM_ERROR_MSG:
+	    case PAM_TEXT_INFO:
+		{
+		    const char *m = (*msg)[replies].msg;
+		    size_t len;
+		    m = perhaps_translate_message (m);
+		    len = strlen(m);
+		    if(len > 255-'\n') {
+			gdm_error("pam prompt too long");
+			return PAM_CONV_ERR;
+		    }
+		    if (!len) len = 1;
+		    sendbuflen += 1 /* type */ + len + 1 /* \0 */;
+		}
+		break;
+	    default:
+		return PAM_CONV_ERR;
+	}
+    }
+
+    s = str = malloc(sendbuflen);
+
+    /* prevent low values from beeing interpreted as control chars */
+    *s++ = num_msg + '\n';
+
     for (replies = 0; replies < num_msg; replies++) {
+
 	const char *m = (*msg)[replies].msg;
 	m = perhaps_translate_message (m);
+	m = ve_sure_string(m);
 	
-	switch ((*msg)[replies].msg_style) {
-	    
-	/* PAM requested textual input with echo on */
-	case PAM_PROMPT_ECHO_ON:
- 	    if (strcmp (m, _("Username:")) == 0) {
-		    if ( ve_string_empty (selected_user)) {
-			    /* this is an evil hack, but really there is no way we'll
-			    know this is a username prompt.  However we SHOULD NOT
-			    rely on this working.  The pam modules can set their
-			    prompt to whatever they wish to */
-			    gdm_slave_greeter_ctl_no_ret
-				    (GDM_MSG, _("Please enter your username"));
-			    s = gdm_slave_greeter_ctl (GDM_PROMPT, m);
-			    /* this will clear the message */
-			    gdm_slave_greeter_ctl_no_ret (GDM_MSG, "");
-		    }
-	    } else {
-		    s = gdm_slave_greeter_ctl (GDM_PROMPT, m);
-	    }
+	*s++ = msg_style2gdm((*msg)[replies].msg_style);
+	strcpy(s, m);
+	// XXX: remove EOX from string
+	s[strlen(m)] = EOX;
+	s += strlen(m)+1;
+    }
 
-	    if (gdm_slave_greeter_check_interruption ()) {
-		    g_free (s);
-		    for (i = 0; i < replies; i++)
-			    if (reply[replies].resp != NULL)
-				    free (reply[replies].resp);
-		    free (reply);
-		    return PAM_CONV_ERR;
-	    }
+    s = gdm_slave_greeter_ctl(GDM_PAM_FORM, str);
 
-	    reply[replies].resp_retcode = PAM_SUCCESS;
-	    reply[replies].resp = strdup (ve_sure_string (s));
-	    g_free (s);
-	    break;
-	    
-	case PAM_PROMPT_ECHO_OFF:
-	    if (strcmp (m, _("Password:")) == 0)
-		    did_we_ask_for_password = TRUE;
-	    /* PAM requested textual input with echo off */
-	    s = gdm_slave_greeter_ctl (GDM_NOECHO, m);
-	    if (gdm_slave_greeter_check_interruption ()) {
-		    g_free (s);
-		    for (i = 0; i < replies; i++)
-			    if (reply[replies].resp != NULL)
-				    free (reply[replies].resp);
-		    free (reply);
-		    return PAM_CONV_ERR;
-	    }
-	    reply[replies].resp_retcode = PAM_SUCCESS;
-	    reply[replies].resp = strdup (ve_sure_string (s));
-	    g_free (s);
-	    break;
-	    
-	case PAM_ERROR_MSG:
-	    /* PAM sent a message that should displayed to the user */
-	    gdm_slave_greeter_ctl_no_ret (GDM_ERRDLG, m);
-	    reply[replies].resp_retcode = PAM_SUCCESS;
-	    reply[replies].resp = NULL;
-	    break;
-	case PAM_TEXT_INFO:
-	    /* PAM sent a message that should displayed to the user */
-	    gdm_slave_greeter_ctl_no_ret (GDM_MSG, m);
-	    reply[replies].resp_retcode = PAM_SUCCESS;
-	    reply[replies].resp = NULL;
-	    break;
-	    
-	default:
-	    /* PAM has been smoking serious crack */
-	    for (i = 0; i < replies; i++)
-		    if (reply[replies].resp != NULL)
-			    free (reply[replies].resp);
-	    free (reply);
-	    return PAM_CONV_ERR;
+    if (gdm_slave_greeter_check_interruption ())
+	    goto error;
+
+    if(!s || s[0] == '\n')
+    {
+	g_free(s);
+	gdm_error("empty reply from greeter");
+	goto error;
+    }
+
+    free(str);
+    str = s;
+
+    reply = malloc (sizeof (struct pam_response) * num_msg);
+    
+    if (reply == NULL)
+	return PAM_CONV_ERR;
+
+    memset (reply, 0, sizeof (struct pam_response) * num_msg);
+
+    for (replies = 0; replies < num_msg; ++replies) {
+	char* eos = strchr(s, EOX);
+	if(!eos || !s[0] || s[0] == '\n') {
+	    gdm_error("invalid reply from greeter");
+	    goto error;
 	}
-	
+	*eos = '\0';
+	gdm_info("%d %s", replies, s);
+	reply[replies].resp = strdup(s);
+	reply[replies].resp_retcode = PAM_SUCCESS;
+	s = eos + 1;
     }
 
     *resp = reply;
     return PAM_SUCCESS;
+
+error:
+    if(reply)
+	for (i = 0; i < replies; ++i)
+	    if (reply[replies].resp != NULL)
+		free (reply[replies].resp);
+
+    free (reply);
+    free(str);
+
+    return PAM_CONV_ERR;
 }
 
 
@@ -1133,7 +1161,7 @@ authenticate_again:
 		    } else {
 			    msg = g_strdup (basemsg);
 		    }
-		    gdm_slave_greeter_ctl_no_ret (GDM_ERRBOX, msg);
+		    gdm_slave_greeter_ctl_no_ret (GDM_ERRDLG, msg);
 		    g_free (msg);
 	    } else {
 		    gdm_slave_greeter_ctl_no_ret (GDM_ERRDLG, _("Authentication failed"));
Index: gdm2/gui/gdmlogin.c
===================================================================
--- gdm2.orig/gui/gdmlogin.c
+++ gdm2/gui/gdmlogin.c
@@ -95,21 +95,18 @@ static GtkWidget *logo_frame = NULL;
 static GtkWidget *logo_image = NULL;
 static GtkWidget *table = NULL;
 static GtkWidget *welcome;
-static GtkWidget *label;
 static GtkWidget *icon_button = NULL;
 static GtkWidget *title_box = NULL;
 static GtkWidget *clock_label = NULL;
-static GtkWidget *entry;
+static GtkWidget *gui_form_vbox;
 static GtkWidget *ok_button;
 static GtkWidget *start_again_button;
-static GtkWidget *msg;
 static GtkWidget *auto_timed_msg;
-static GtkWidget *err_box;
-static guint err_box_clear_handler = 0;
 static gboolean require_quarter = FALSE;
 static GtkWidget *icon_win = NULL;
 static GtkWidget *sessmenu;
 static GtkWidget *langmenu;
+static GtkWidget *statusbar;
 
 static gboolean login_is_local = FALSE;
 
@@ -148,6 +145,14 @@ static gboolean back_prog_delayed = FALS
 
 static guint timed_handler_id = 0;
 
+static struct {
+    unsigned style;
+    const char* msg;
+    GtkWidget* widget;
+} pam_form[256-'\n'] = {{0, NULL,  NULL}}; /* can't have more than that anyways */
+static unsigned num_pam_form = 0;
+GtkWidget* pam_form_vbox = NULL;
+
 #if FIXME
 static char *selected_browser_user = NULL;
 #endif
@@ -176,8 +181,18 @@ static void back_prog_launch_after_timeo
 static void back_prog_run (void);
 static void back_prog_stop (void);
 
+static void gui_process_form(void);
 static void process_operation (guchar op_code, const gchar *args);
 
+static gboolean pop_statusbar (gpointer data);
+static void update_statusbar_timeout (const char* text);
+static void update_statusbar (const char* text);
+static guint statusbar_timeout_id;
+
+
+static gboolean username_prompt_focus_in(GtkWidget *widget, GdkEventFocus *event);
+static gboolean username_prompt_focus_out (GtkWidget *widget, GdkEventFocus *event);
+
 /* 
  * This function is called when the background program exits.
  * It will add a timer to restart the program after the
@@ -519,6 +534,7 @@ gdm_event (GSignalInvocationHint *ihint,
 	    && event->button.button == 3)
 		event->button.button = 1;
 
+#if 0
 	/* Support Ctrl-U for blanking the username/password entry */
 	if (event->type == GDK_KEY_PRESS &&
 	    (event->key.state & GDK_CONTROL_MASK) &&
@@ -527,6 +543,7 @@ gdm_event (GSignalInvocationHint *ihint,
 
 		gtk_entry_set_text (GTK_ENTRY (entry), "");
 	}
+#endif
 
 	return TRUE;
 }      
@@ -835,6 +852,7 @@ dance (gpointer data)
 	return TRUE;
 }
 
+#if 0
 static gboolean
 evil (const char *user)
 {
@@ -878,7 +896,9 @@ evil (const char *user)
 
 	return FALSE;
 }
+#endif
 
+#if 0
 static void
 gdm_login_enter (GtkWidget *entry)
 {
@@ -934,16 +954,45 @@ gdm_login_enter (GtkWidget *entry)
 	fflush (stdout);
 	g_free (tmp);
 }
+#endif
 
 static void
 gdm_login_ok_button_press (GtkButton *button, GtkWidget *entry)
 {
-	gdm_login_enter (entry);
+    unsigned i;
+
+    gdm_common_info("%d form items", num_pam_form);
+    fputc(STX, stdout);
+    for(i = 0; i < num_pam_form; ++i) {
+	char* s = NULL;
+	switch(pam_form[i].style) {
+	    case GDM_NOECHO:
+	    case GDM_PROMPT:
+		s = ve_locale_from_utf8(gtk_entry_get_text(GTK_ENTRY(pam_form[i].widget)));
+	}
+	if(pam_form[i].widget)
+	    gtk_widget_set_sensitive(GTK_WIDGET(pam_form[i].widget), FALSE);
+	gdm_common_info("-> %d %d %s", i, pam_form[i].style, s);
+	fputs(ve_sure_string(s), stdout);
+	fputc(EOX, stdout);
+	g_free(s);
+    }
+    fputc('\n', stdout);
+    fflush (stdout);
+
+#if 0
+    /* don't do that to prevent resizes */
+    gtk_container_remove(GTK_CONTAINER(gui_form_vbox), pam_form_vbox);
+    pam_form_vbox = NULL;
+#endif
+
+    gdm_common_info("OK!");
 }
 
 static void
-gdm_login_start_again_button_press (GtkButton *button, GtkWidget *entry)
+gdm_login_start_again_button_press (GtkButton *button, gpointer data)
 {
+	unsigned i;
 	GtkTreeSelection *selection;
 
 	if (browser != NULL) {
@@ -955,6 +1004,18 @@ gdm_login_start_again_button_press (GtkB
 		g_free (selected_user);
 	selected_user = NULL;
 
+	for(i = 0; i < num_pam_form; ++i) {
+	    if(pam_form[i].widget)
+		gtk_widget_set_sensitive(GTK_WIDGET(pam_form[i].widget), FALSE);
+	}
+#if 0
+	/* don't do that to prevent resizes */
+	gtk_container_remove(GTK_CONTAINER(gui_form_vbox), pam_form_vbox);
+	pam_form_vbox = NULL;
+#endif
+
+	gtk_widget_set_sensitive (ok_button, FALSE);
+
 	printf ("%c%c%c\n", STX, BEL,
 		GDM_INTERRUPT_CANCEL);
 	fflush (stdout);
@@ -981,6 +1042,57 @@ gdm_login_focus_out (GtkWidget *widget, 
 	return FALSE;
 }
 
+static gboolean
+username_prompt_focus_in(GtkWidget *widget, GdkEventFocus *event)
+{
+    update_statusbar(_("Please enter your username"));
+    return FALSE;
+}
+
+static gboolean
+username_prompt_focus_out (GtkWidget *widget, GdkEventFocus *event)
+{
+    update_statusbar(NULL);
+    return FALSE;
+}
+
+static gboolean
+pop_statusbar(gpointer data)
+{
+    guint id = GPOINTER_TO_INT(data);
+    gtk_statusbar_pop(GTK_STATUSBAR(statusbar), id);
+    return TRUE;
+}
+
+static void update_statusbar_timeout (const char* text)
+{
+    guint id = gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar), "timeout");
+
+    gtk_statusbar_pop(GTK_STATUSBAR(statusbar), id);
+
+    if(!text)
+	return;
+
+    gtk_statusbar_push(GTK_STATUSBAR(statusbar), id, text);
+
+    if(statusbar_timeout_id)
+	g_source_remove (statusbar_timeout_id);
+
+    statusbar_timeout_id = g_timeout_add (5000, pop_statusbar, GINT_TO_POINTER(id));
+}
+
+static void update_statusbar(const char* text)
+{
+    guint id = gtk_statusbar_get_context_id(GTK_STATUSBAR(statusbar), "static");
+
+    gtk_statusbar_pop(GTK_STATUSBAR(statusbar), id);
+
+    if(!text)
+	return;
+
+    gtk_statusbar_push(GTK_STATUSBAR(statusbar), id, text);
+}
+
 static void 
 gdm_login_session_handler (GtkWidget *widget) 
 {
@@ -990,7 +1102,8 @@ gdm_login_session_handler (GtkWidget *wi
 
     s = g_strdup_printf (_("%s session selected"), gdm_session_name (current_session));
 
-    gtk_label_set_text (GTK_LABEL (msg), s);
+    update_statusbar_timeout(s);
+
     g_free (s);
 
     login_window_resize (FALSE /* force */);
@@ -1094,7 +1207,7 @@ gdm_login_language_handler (GtkWidget *w
 			  TRUE /* makrup */);
     s = g_strdup_printf (_("%s language selected"), name);
     g_free (name);
-    gtk_label_set_markup (GTK_LABEL (msg), s);
+    update_statusbar_timeout(s);
     g_free (s);
 
     login_window_resize (FALSE /* force */);
@@ -1372,6 +1485,7 @@ gdm_login_theme_menu_new (void)
     return menu;
 }
 
+#if 0
 static gboolean
 err_box_clear (gpointer data)
 {
@@ -1381,6 +1495,7 @@ err_box_clear (gpointer data)
 	err_box_clear_handler = 0;
 	return FALSE;
 }
+#endif
 
 static void
 browser_set_user (const char *user)
@@ -1390,6 +1505,8 @@ browser_set_user (const char *user)
   GtkTreeIter iter = {0};
   GtkTreeModel *tm = NULL;
 
+  gdm_common_info("%s %s", __FUNCTION__, user);
+
   if (browser == NULL)
     return;
 
@@ -1522,6 +1639,142 @@ gdm_login_ctrl_handler (GIOChannel *sour
     return TRUE;
 }
 
+static void gui_process_form(void)
+{
+    int i;
+    int firstentry = -1;
+    GtkWidget* preventry = NULL;
+
+    gdm_common_info("%s", __FUNCTION__);
+
+    if(pam_form_vbox)
+	gtk_container_remove(GTK_CONTAINER(gui_form_vbox), pam_form_vbox);
+
+    pam_form_vbox = gtk_vbox_new(FALSE, 0);
+
+    for (i = 0; i < num_pam_form; ++i)
+    {
+	unsigned style = pam_form[i].style;
+	char* msg = ve_locale_from_utf8(pam_form[i].msg);
+
+	gdm_common_info("%c %s", style, msg);
+
+	switch(style)
+	{
+	    case GDM_NOECHO:
+	    case GDM_PROMPT:
+		{
+		    GtkWidget* hbox;
+		    GtkWidget* label;
+		    GtkWidget* entry;
+		    gboolean is_username;
+		    
+		    if((is_username = !strcmp(msg, _("Username:"))))
+			msg = _("_Username:");
+
+		    hbox = gtk_hbox_new(FALSE, 4);
+		    label = gtk_label_new_with_mnemonic(msg);
+		    pam_form[i].widget = entry = gtk_entry_new();
+		    gtk_widget_set_size_request (entry, 200, -1);
+
+		    if(style == GDM_NOECHO)
+		    {
+			gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+		    }
+
+		    gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
+
+		    gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0);
+		    gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, TRUE, 0);
+
+		    gtk_box_pack_start(GTK_BOX(pam_form_vbox), hbox, TRUE, TRUE, 0);
+
+		    if(firstentry == -1)
+			firstentry = i;
+
+		    if(is_username)
+		    {
+			msg = NULL; // static string from gettext, prevent g_free()
+
+			if(selected_user)
+			    gtk_entry_set_text (GTK_ENTRY(entry), selected_user);
+
+			/* TODO: set callback for evil() */
+
+			g_signal_connect (G_OBJECT (entry), "focus_in_event", 
+				G_CALLBACK (username_prompt_focus_in),
+				NULL);
+			g_signal_connect (G_OBJECT (entry), "focus_out_event", 
+				G_CALLBACK (username_prompt_focus_out),
+				NULL);
+		    }
+
+		    if(preventry)
+		    {
+			g_signal_connect_swapped((gpointer)preventry, "activate",
+				G_CALLBACK(gtk_widget_grab_focus),
+				entry);
+		    }
+
+		    preventry = entry;
+
+		} break;
+	    case GDM_MSG:
+	    case GDM_ERRBOX:
+		{
+		    GtkWidget* hbox;
+		    GtkWidget* label;
+		    GtkWidget* icon;
+
+		    hbox = gtk_hbox_new(FALSE, 0);
+		    label = gtk_label_new(msg);
+
+		    gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+
+		    if(style == GDM_ERRBOX)
+			icon = gtk_image_new_from_stock(
+				GTK_STOCK_DIALOG_ERROR,
+				GTK_ICON_SIZE_BUTTON);
+		    else
+			icon = gtk_image_new_from_stock(
+				GTK_STOCK_DIALOG_INFO,
+				GTK_ICON_SIZE_BUTTON);
+
+		    gtk_box_pack_start(GTK_BOX(hbox), icon, FALSE, FALSE, 0);
+		    gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+
+		    gtk_box_pack_start(GTK_BOX(pam_form_vbox), hbox, TRUE, TRUE, 2);
+
+		} break;
+	}
+
+	g_free(msg);
+    }
+
+    gtk_widget_show_all(pam_form_vbox);
+
+    gtk_box_pack_start(GTK_BOX(gui_form_vbox), pam_form_vbox, TRUE, TRUE, 0);
+    gtk_box_reorder_child(GTK_BOX(gui_form_vbox), pam_form_vbox, 1);
+
+    if(firstentry != -1)
+    {
+	gtk_window_set_focus (GTK_WINDOW (login), pam_form[firstentry].widget);	
+    }
+
+    // enter in last entry behaves like klicking the ok button
+    if(preventry)
+    {
+	g_signal_connect_swapped((gpointer)preventry, "activate",
+		G_CALLBACK (gtk_button_clicked),
+		ok_button);
+    }
+
+    gtk_widget_set_sensitive (start_again_button, TRUE);
+    gtk_widget_set_sensitive (ok_button, TRUE);
+
+    login_window_resize(FALSE);
+}
+
 static void
 process_operation (guchar       op_code,
 		   const gchar *args)
@@ -1529,13 +1782,12 @@ process_operation (guchar       op_code,
     char *tmp;
     gint i, x, y;
     GtkWidget *dlg;
-    static gboolean replace_msg = TRUE;
-    static gboolean messages_to_give = FALSE;
-    gboolean greeter_probably_login_prompt = FALSE;
     gint lookup_status = SESSION_LOOKUP_SUCCESS;
     gchar *firstmsg = NULL;
     gchar *secondmsg = NULL;
     gint save_session = GTK_RESPONSE_NO;
+
+    gdm_common_info("code %c", op_code);
     
     /* Parse opcode */
     switch (op_code) {
@@ -1549,7 +1801,64 @@ process_operation (guchar       op_code,
 	printf ("%c\n", STX);
 	fflush (stdout);
 	break;
+    
+    case GDM_PAM_FORM:
+	{
+	    unsigned num_msg = *args++;
+	    unsigned i = 0;
 
+	    num_msg -= '\n';
+
+	    memset(pam_form, 0, sizeof(pam_form));
+
+	    while(i < num_msg)
+	    {
+		unsigned style = *args++;
+		char* s = strchr(args, EOX);
+		if(!s) {
+		    printf ("%c\n", STX);
+		    fflush (stdout);
+		    gdm_common_fail_greeter("invalid message in GDM_PAM_FORM");
+		    return;
+		}
+		*s = '\0';
+		// TODO: ve_locale_to_utf8
+		switch(style) {
+		    case GDM_PROMPT:
+		    case GDM_NOECHO:
+		    case GDM_ERRBOX:
+		    case GDM_MSG:
+			break;
+
+		    default:
+			printf ("%c\n", STX);
+			fflush (stdout);
+			gdm_common_fail_greeter("Unexpected message type in GDM_PAM_FORM: 0x%hhx", style);
+			return;
+		}
+		pam_form[i].style = style;
+		pam_form[i].msg = args;
+		args += strlen(args)+1;
+		++i;
+	    }
+	    num_pam_form = num_msg;
+	    gui_process_form();
+	    break;
+	}
+    case GDM_ERRBOX:
+    case GDM_MSG:
+	// TODO: check whether a form is already active and switch
+	// to dialog if so
+    case GDM_PROMPT:
+    case GDM_NOECHO:
+	    memset(pam_form, 0, sizeof(pam_form));
+	    pam_form[0].style = op_code;
+	    pam_form[0].msg = args;
+	    num_pam_form = 1;
+	    gui_process_form();
+	break;
+
+#if 0
     case GDM_PROMPT:
 	tmp = ve_locale_to_utf8 (args);
 	if (tmp != NULL && strcmp (tmp, _("Username:")) == 0) {
@@ -1677,6 +1986,7 @@ process_operation (guchar       op_code,
 
 	login_window_resize (FALSE /* force */);
 	break;
+#endif
 
     case GDM_ERRDLG:
 	/* we should be now fine for focusing new windows */
@@ -1822,17 +2132,31 @@ process_operation (guchar       op_code,
 	    curuser = NULL;
 	}
 
-	gtk_widget_set_sensitive (entry, TRUE);
 	gtk_widget_set_sensitive (ok_button, FALSE);
 	gtk_widget_set_sensitive (start_again_button, FALSE);
 
+	gtk_container_remove(GTK_CONTAINER(gui_form_vbox), pam_form_vbox);
+	pam_form_vbox = NULL;
+	num_pam_form = 0;
+
 	if (browser_ok && gdm_config_get_bool (GDM_KEY_BROWSER))
 	    gtk_widget_set_sensitive (GTK_WIDGET (browser), TRUE);
 
-	tmp = ve_locale_to_utf8 (args);
-	gtk_label_set_text (GTK_LABEL (msg), tmp);
-	g_free (tmp);
-	gtk_widget_show (GTK_WIDGET (msg));
+	if(!ve_string_empty(args)) {
+	    tmp = ve_locale_to_utf8 (args);
+	    dlg = ve_hig_dialog_new (NULL /* parent */,
+		    GTK_DIALOG_MODAL /* flags */,
+		    GTK_MESSAGE_INFO,
+		    GTK_BUTTONS_OK,
+		    "%s", tmp);
+	    gdm_wm_center_window (GTK_WINDOW (dlg));
+
+	    gdm_wm_no_login_focus_push ();
+	    gtk_dialog_run (GTK_DIALOG (dlg));
+	    gtk_widget_destroy (dlg);
+	    gdm_wm_no_login_focus_pop ();
+	    g_free (tmp);
+	}
 
 	printf ("%c\n", STX);
 	fflush (stdout);
@@ -1870,31 +2194,6 @@ process_operation (guchar       op_code,
 	/* Hide the login window now */
 	gtk_widget_hide (login);
 
-	if (messages_to_give) {
-		const char *oldtext;
-		oldtext = gtk_label_get_text (GTK_LABEL (msg));
-
-		if ( ! ve_string_empty (oldtext)) {
-			/* we should be now fine for focusing new windows */
-			gdm_wm_focus_new_windows (TRUE);
-
-			dlg = ve_hig_dialog_new (NULL /* parent */,
-						 GTK_DIALOG_MODAL /* flags */,
-						 GTK_MESSAGE_INFO,
-						 GTK_BUTTONS_OK,
-						 oldtext,
-						 "");
-			gtk_window_set_modal (GTK_WINDOW (dlg), TRUE);
-			gdm_wm_center_window (GTK_WINDOW (dlg));
-
-			gdm_wm_no_login_focus_push ();
-			gtk_dialog_run (GTK_DIALOG (dlg));
-			gtk_widget_destroy (dlg);
-			gdm_wm_no_login_focus_pop ();
-		}
-		messages_to_give = FALSE;
-	}
-
 	gdm_kill_thingies ();
 
 	gdk_flush ();
@@ -2055,14 +2354,6 @@ user_selected (GtkTreeSelection *selecti
 	gtk_tree_model_get (tm, &iter, GREETER_ULIST_LOGIN_COLUMN,
 			      &login, -1);
 	if (login != NULL) {
-		const char *str = gtk_label_get_text (GTK_LABEL (label));
-
-		if (selecting_user &&
-		    str != NULL &&
-		    (strcmp (str, _("Username:")) == 0 ||
-		     strcmp (str, _("_Username:")) == 0)) {
-			gtk_entry_set_text (GTK_ENTRY (entry), login);
-		}
 #ifdef FIXME
 		selected_browser_user = g_strdup (login);
 #endif
@@ -2076,12 +2367,6 @@ user_selected (GtkTreeSelection *selecti
   }
 }
 
-static void
-browser_change_focus (GtkWidget *widget, GdkEventButton *event, gpointer data)
-{
-    gtk_widget_grab_focus (entry);	
-}
-
 static gboolean
 gdm_login_handle_pressed (GtkWidget *widget, GdkEventButton *event)
 {
@@ -2302,6 +2587,7 @@ window_browser_event (GtkWidget *window,
 	return FALSE;
 }
 
+#if 0
 static gboolean
 key_release_event (GtkWidget *entry, GdkEventKey *event, gpointer data)
 {
@@ -2314,6 +2600,7 @@ key_release_event (GtkWidget *entry, Gdk
 		return TRUE;
 	}
 
+#if 0 // don't try to be smart. maybe it's an optional entry field
 	/*
 	 * Set ok button to sensitive only if there are characters in
 	 * the entry field
@@ -2323,9 +2610,11 @@ key_release_event (GtkWidget *entry, Gdk
 		gtk_widget_set_sensitive (ok_button, TRUE);
 	else
 		gtk_widget_set_sensitive (ok_button, FALSE);
+#endif
 
 	return FALSE;
 }
+#endif
 
 static void
 gdm_set_welcomemsg (void)
@@ -2349,7 +2638,7 @@ gdm_login_gui_init (void)
     GtkTreeSelection *selection;
     GtkWidget *frame1, *frame2, *ebox;
     GtkWidget *mbox, *menu, *menubar, *item;
-    GtkWidget *stack, *hline1, *hline2, *handle;
+    GtkWidget *handle;
     GtkWidget *bbox = NULL;
     GtkWidget /**help_button,*/ *button_box;
     gint rows, i;
@@ -2590,10 +2879,6 @@ gdm_login_gui_init (void)
 			      G_CALLBACK (user_selected),
 			      NULL);
 
-	    g_signal_connect (browser, "button_release_event",
-			      G_CALLBACK (browser_change_focus),
-			      NULL);
-
 	    gtk_tree_view_set_model (GTK_TREE_VIEW (browser), browser_model);
 	    column = gtk_tree_view_column_new_with_attributes
 		    (_("Icon"),
@@ -2668,11 +2953,18 @@ gdm_login_gui_init (void)
 	    gtk_widget_set_size_request (logo_image, lw, lh);
     gtk_widget_show (GTK_WIDGET (logo_image));
 
+#if 0
     stack = gtk_table_new (7, 1, FALSE);
     gtk_widget_ref (stack);
     g_object_set_data_full (G_OBJECT (login), "stack", stack,
 			    (GDestroyNotify) gtk_widget_unref);
     gtk_widget_show (stack);
+#endif
+
+    gui_form_vbox = gtk_vbox_new(FALSE, 0);
+    g_object_set_data_full (G_OBJECT (login), "gui_form_vbox", gui_form_vbox,
+			    (GDestroyNotify) gtk_widget_unref);
+    gtk_widget_show (gui_form_vbox);
 
     /* Welcome msg */
     welcome = gtk_label_new (NULL);
@@ -2682,10 +2974,15 @@ gdm_login_gui_init (void)
     g_object_set_data_full (G_OBJECT (login), "welcome", welcome,
 			    (GDestroyNotify) gtk_widget_unref);
     gtk_widget_show (welcome);
+#if 0
     gtk_table_attach (GTK_TABLE (stack), welcome, 0, 1, 0, 1,
 		      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
 		      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 15);
+#endif
+    gtk_box_pack_start(GTK_BOX(gui_form_vbox), welcome, TRUE, TRUE, 0);
+
 
+#if 0
     /* Put in error box here */
     err_box = gtk_label_new (NULL);
     gtk_widget_set_name (err_box, "Error box");
@@ -2776,14 +3073,18 @@ gdm_login_gui_init (void)
     g_object_set_data_full (G_OBJECT (login), "msg", msg,
 			    (GDestroyNotify) gtk_widget_unref);
     gtk_widget_show (msg);
+#endif
 
     auto_timed_msg = gtk_label_new ("");
     gtk_widget_set_name (auto_timed_msg, "Message");
     gtk_label_set_line_wrap (GTK_LABEL (auto_timed_msg), TRUE);
     gtk_label_set_justify (GTK_LABEL (auto_timed_msg), GTK_JUSTIFY_LEFT);
+#if 0
     gtk_table_attach (GTK_TABLE (stack), auto_timed_msg, 0, 1, 7, 8,
 		      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
 		      (GtkAttachOptions) (GTK_FILL), 0, 10);
+#endif
+    gtk_box_pack_start(GTK_BOX(gui_form_vbox), auto_timed_msg, TRUE, TRUE, 0);
     gtk_widget_set_size_request (auto_timed_msg, -1, 15);
     
     gtk_widget_ref (auto_timed_msg);
@@ -2798,14 +3099,14 @@ gdm_login_gui_init (void)
     GTK_WIDGET_UNSET_FLAGS (ok_button, GTK_CAN_FOCUS);
     g_signal_connect (G_OBJECT (ok_button), "clicked",
 		      G_CALLBACK (gdm_login_ok_button_press),
-		      entry);
+		      NULL);
     gtk_widget_show (ok_button);
 
     start_again_button = gtk_button_new_with_mnemonic (_("_Start Again"));
     GTK_WIDGET_UNSET_FLAGS (start_again_button, GTK_CAN_FOCUS);
     g_signal_connect (G_OBJECT (start_again_button), "clicked",
 		      G_CALLBACK (gdm_login_start_again_button_press),
-		      entry);
+		      /* entry */ NULL);
     gtk_widget_show (start_again_button);
 
     button_box = gtk_hbutton_box_new ();
@@ -2825,9 +3126,12 @@ gdm_login_gui_init (void)
 		      FALSE, TRUE, 0);
     gtk_widget_show (button_box);
     
+#if 0
     gtk_table_attach (GTK_TABLE (stack), button_box, 0, 1, 8, 9,
 		      (GtkAttachOptions) (GTK_FILL),
 		      (GtkAttachOptions) (GTK_FILL), 10, 10);
+#endif
+    gtk_box_pack_start(GTK_BOX(gui_form_vbox), button_box, TRUE, TRUE, 0);
 
     /* Put it nicely together */
 
@@ -2838,20 +3142,22 @@ gdm_login_gui_init (void)
 	    gtk_table_attach (GTK_TABLE (table), logo_frame, 0, 1, 1, 2,
 			      (GtkAttachOptions) (GTK_FILL),
 			      (GtkAttachOptions) (GTK_FILL), 0, 0);
-	    gtk_table_attach (GTK_TABLE (table), stack, 1, 2, 1, 2,
+	    gtk_table_attach (GTK_TABLE (table), gui_form_vbox, 1, 2, 1, 2,
 			      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
 			      (GtkAttachOptions) (GTK_FILL), 0, 0);
     } else {
 	    gtk_table_attach (GTK_TABLE (table), logo_frame, 0, 1, 0, 1,
 			      (GtkAttachOptions) (0),
 			      (GtkAttachOptions) (GTK_FILL), 0, 0);
-	    gtk_table_attach (GTK_TABLE (table), stack, 1, 2, 0, 1,
+	    gtk_table_attach (GTK_TABLE (table), gui_form_vbox, 1, 2, 0, 1,
 			      (GtkAttachOptions) (0),
 			      (GtkAttachOptions) (GTK_FILL), 0, 0);
     }
+
+    statusbar = gtk_statusbar_new();
+    gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(statusbar), FALSE);
+    gtk_box_pack_start (GTK_BOX (mbox), statusbar, TRUE, TRUE, 0);
     
-    gtk_widget_grab_focus (entry);	
-    gtk_window_set_focus (GTK_WINDOW (login), entry);	
     g_object_set (G_OBJECT (login),
 		  "allow_grow", TRUE,
 		  "allow_shrink", TRUE,
@@ -2872,11 +3178,8 @@ gdm_login_gui_init (void)
 		      G_CALLBACK (gdm_login_focus_out),
 		      NULL);
 
-    gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
-
     /* normally disable the prompt first */
     if ( ! DOING_GDM_DEVELOPMENT) {
-	    gtk_widget_set_sensitive (entry, FALSE);
 	    gtk_widget_set_sensitive (ok_button, FALSE);
 	    gtk_widget_set_sensitive (start_again_button, FALSE);
     }
@@ -3401,6 +3704,9 @@ main (int argc, char *argv[])
 
     gtk_init (&argc, &argv);
 
+    /* AHHH, much better now! the clueless won't notice anyways */
+    gtk_rc_parse_string("gtk-key-theme-name = \"Emacs\"");
+
     if (ve_string_empty (g_getenv ("GDM_IS_LOCAL")))
 	disable_sys_config_chooser_buttons = TRUE;
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]