--- gdm-2.16.0/daemon/gdm.c.org	2006-10-06 13:00:39.000000000 +0100
+++ gdm-2.16.0/daemon/gdm.c	2006-10-24 18:53:16.000000000 +0100
@@ -94,6 +94,8 @@
 				 uid_t xnest_uid,
 				 const gchar *xnest_auth_file,
 				 const gchar *xnest_cookie);
+static void custom_cmd_restart (long cmd_id);
+static void custom_cmd_no_restart (long cmd_id);
 
 /* Global vars */
 gint xdmcp_sessions = 0;	/* Number of remote sessions */
@@ -708,6 +710,86 @@
 		   "gdm_child_action", strerror (errno));
 }
 
+static void
+custom_cmd (long cmd_id)
+{	
+        gchar * key_string = g_strdup_printf(_("%s%ld="), GDM_KEY_CUSTOM_CMD_NO_RESTART_TEMPLATE, cmd_id);
+        if (gdm_get_value_bool (key_string))
+	        custom_cmd_no_restart (cmd_id);
+	else
+	        custom_cmd_restart (cmd_id);
+    
+    g_free(key_string);
+}
+
+static void
+custom_cmd_restart (long cmd_id)
+{	
+
+        gdm_info (_("Executing custom command %d with restart option..."), cmd_id);
+
+	gdm_final_cleanup ();
+	VE_IGNORE_EINTR (g_chdir ("/"));
+	
+#ifdef __linux__
+	change_to_first_and_clear (TRUE);
+#endif /* __linux */
+	
+	gchar * key_string = g_strdup_printf(_("%s%ld="), GDM_KEY_CUSTOM_CMD_TEMPLATE, cmd_id);
+	char **argv;
+	argv = ve_split (gdm_get_value_string (key_string));
+	g_free(key_string);
+	if (argv != NULL && argv[0] != NULL)
+	    VE_IGNORE_EINTR (execv (argv[0], argv));
+	
+	g_strfreev (argv);	      
+	
+	gdm_error (_("%s: Execution of custom command failed: %s"), 
+		   "gdm_child_action", strerror (errno));
+}
+
+static void
+custom_cmd_no_restart (long cmd_id)
+{	
+
+        gdm_info (_("Executing custom command %ld with no restart option ..."), cmd_id);
+
+		pid_t pid = fork ();
+	
+	if (pid < 0) {
+	        /*failed fork*/
+	        gdm_error (_("custom_cmd: forking process for custom command %d failed"), cmd_id);
+		return;
+	}
+	else if (pid == 0) {
+	      /* child */
+	      char **argv;
+	      gchar * key_string = g_strdup_printf(_("%s%ld="), GDM_KEY_CUSTOM_CMD_TEMPLATE, cmd_id);
+	      argv = ve_split (gdm_get_value_string (key_string));
+	      g_free(key_string);
+	      if (argv != NULL && argv[0] != NULL)
+		      VE_IGNORE_EINTR (execv (argv[0], argv));
+	    
+	      g_strfreev (argv);	      
+	      
+	      gdm_error (_("%s: Execution of custom command failed: %s"), 
+			 "gdm_child_action", strerror (errno));
+	    	    
+	      _exit (0);	    
+	}
+	else {
+	      /* parent */
+	      gint exitstatus = 0, status;
+	      pid_t p_stat = waitpid(1, &exitstatus, WNOHANG);
+	      if(p_stat > 0){
+		  if G_LIKELY (WIFEXITED(exitstatus)){
+		      status = WEXITSTATUS (exitstatus);
+		      gdm_debug (_("custom_cmd: child %d returned %d"), p_stat, status);
+		  }	
+		  return;
+	      }
+	}	
+}
 
 static gboolean 
 gdm_cleanup_children (void)
@@ -2383,6 +2465,20 @@
 
 			send_slave_ack (d, NULL);
 		}
+	} else if (strncmp (msg, GDM_SOP_CUSTOM_CMD " ",
+		            strlen (GDM_SOP_CUSTOM_CMD " ")) == 0) {
+		GdmDisplay *d;
+		long slave_pid;
+		long cmd_id;
+
+		if (sscanf (msg, GDM_SOP_CUSTOM_CMD " %ld %ld", &slave_pid, &cmd_id) != 2)
+			return;
+		d = gdm_display_lookup (slave_pid);
+
+		if (d != NULL) {
+		        custom_cmd (cmd_id);
+			send_slave_ack (d, NULL);
+		}		
 	} else if (strcmp (msg, GDM_SOP_FLEXI_XSERVER) == 0) {
 		handle_flexi_server (NULL, TYPE_FLEXI, gdm_get_value_string (GDM_KEY_STANDARD_XSERVER),
 				     TRUE /* handled */,
@@ -3255,7 +3351,7 @@
 			if (logout_action == GDM_LOGOUT_ACTION_REBOOT)
 				g_string_append (msg, "!");
 			sep = ";";
-		}
+		}	
 		if (sysmenu && disp->attached &&
 		    ! ve_string_empty (gdm_get_value_string (GDM_KEY_SUSPEND))) {
 			g_string_append_printf (msg, "%s%s", sep, GDM_SUP_LOGOUT_ACTION_SUSPEND);
--- gdm-2.16.0/daemon/gdmconfig.c.org	2006-10-06 12:55:52.000000000 +0100
+++ gdm-2.16.0/daemon/gdmconfig.c	2006-10-24 18:46:33.000000000 +0100
@@ -115,6 +115,11 @@
 static gchar *GdmXKeepsCrashing = NULL;
 static gchar *GdmHalt = NULL;
 static gchar *GdmReboot = NULL;
+static GdmCustomCmd *GdmCustomCommands = NULL;
+static gchar *GdmCustomCmdLabel = NULL;
+static gchar *GdmCustomCmdLRLabel = NULL;
+static gchar *GdmCustomCmdText = NULL;
+static gchar *GdmCustomCmdTooltip = NULL;
 static gchar *GdmSuspend = NULL;
 static gchar *GdmServAuthDir = NULL;
 static gchar *GdmMulticastAddr;
@@ -192,6 +197,7 @@
 static gboolean GdmSoundOnLoginSuccess = FALSE;
 static gboolean GdmSoundOnLoginFailure = FALSE;
 static gboolean GdmConsoleNotify = TRUE;
+static gboolean GdmCustomCmdNoRestart = FALSE;
 
 /* Config options used by slave */
 /* ---------------------------- */
@@ -504,6 +510,37 @@
       &GdmPreFetchProgram, &string_type);
    gdm_config_add_hash (GDM_KEY_PAM_STACK, &GdmPamStack, &string_type);
 
+   /* custom command string values */
+   GdmCustomCommands = g_new0 (GdmCustomCmd, GDM_CUSTOM_COMMAND_MAX);   
+   register int i = 0;
+   gchar *key_string = NULL; 
+   for (; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+       /* For each possible custom command */      
+       key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TEMPLATE, i); 
+       GdmCustomCommands[i].command = NULL;
+       gdm_config_add_hash (key_string, &GdmCustomCommands[i].command, &string_type);
+
+       key_string = g_strdup_printf(_("%s%d=_Custom%d"), GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i, i); 
+       GdmCustomCommands[i].command_label = NULL;
+       gdm_config_add_hash (key_string, &GdmCustomCommands[i].command_label, &string_type);
+
+       key_string = g_strdup_printf(_("%s%d=Execute _custom command %d"), GDM_KEY_CUSTOM_CMD_LR_LABEL_TEMPLATE, i, i);
+       GdmCustomCommands[i].command_lr_label = NULL;
+       gdm_config_add_hash (key_string, &GdmCustomCommands[i].command_lr_label, &string_type);
+
+       key_string = g_strdup_printf(_("%s%d=Are you sure?"), GDM_KEY_CUSTOM_CMD_TEXT_TEMPLATE, i);
+       GdmCustomCommands[i].command_text = NULL;
+       gdm_config_add_hash (key_string, &GdmCustomCommands[i].command_text, &string_type);
+        
+       key_string = g_strdup_printf(_("%s%d=Execute custom command %d"), GDM_KEY_CUSTOM_CMD_TOOLTIP_TEMPLATE, i, i);
+       GdmCustomCommands[i].command_tooltip = NULL;
+       gdm_config_add_hash (key_string, &GdmCustomCommands[i].command_tooltip, &string_type);
+
+       key_string = g_strdup_printf(_("%s%d=false"), GDM_KEY_CUSTOM_CMD_NO_RESTART_TEMPLATE, i);
+       GdmCustomCommands[i].command_no_restart = FALSE;
+       gdm_config_add_hash (key_string, &GdmCustomCommands[i].command_no_restart, &bool_type);  
+   }   
+
    /* int values */
    gdm_config_add_hash (GDM_KEY_XINERAMA_SCREEN, &GdmXineramaScreen, &int_type);
    gdm_config_add_hash (GDM_KEY_RETRY_DELAY, &GdmRetryDelay, &int_type);
@@ -1157,6 +1194,23 @@
 
    /* All others */
    } else {
+       register int i = 0;
+       gchar * key_string = NULL;
+       for (; i < GDM_CUSTOM_COMMAND_MAX; i++) {	   
+	   /* For each possible custom command */     
+	   key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TEMPLATE, i);
+	   if(is_key (key, key_string)) {	       
+	       if (value != NULL)
+		  *setting = ve_get_first_working_command (value, FALSE);
+	       else
+		  *setting = NULL;
+
+	       break;
+	   }
+       }
+
+       g_free(key_string);
+
        if (value != NULL)
           *setting = g_strdup (value);
        else {
--- gdm-2.16.0/daemon/gdm.h.org	2006-10-06 13:45:17.000000000 +0100
+++ gdm-2.16.0/daemon/gdm.h	2006-10-24 18:45:56.000000000 +0100
@@ -127,6 +127,7 @@
 #define GDM_INTERRUPT_SELECT_USER 'U'
 #define GDM_INTERRUPT_LOGIN_SOUND 'L'
 #define GDM_INTERRUPT_THEME       'H'
+#define GDM_INTERRUPT_CUSTOM_CMD  'M'
 #define GDM_INTERRUPT_CANCEL      'X'
 
 /* List delimiter for config file lists */
@@ -234,6 +235,12 @@
 #define GDM_KEY_FAILSAFE_XSERVER "daemon/FailsafeXServer="
 #define GDM_KEY_X_KEEPS_CRASHING "daemon/XKeepsCrashing=" GDMCONFDIR "/XKeepsCrashing"
 #define GDM_KEY_REBOOT  "daemon/RebootCommand=" REBOOT_COMMAND
+#define GDM_KEY_CUSTOM_CMD_TEMPLATE "customcommand/CustomCommand"
+#define GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE "customcommand/CustomCommandLabel"
+#define GDM_KEY_CUSTOM_CMD_LR_LABEL_TEMPLATE "customcommand/CustomCommandLRLabel"
+#define GDM_KEY_CUSTOM_CMD_TEXT_TEMPLATE "customcommand/CustomCommandText"
+#define GDM_KEY_CUSTOM_CMD_TOOLTIP_TEMPLATE "customcommand/CustomCommandTooltip"
+#define GDM_KEY_CUSTOM_CMD_NO_RESTART_TEMPLATE "customcommand/CustomCommandNoRestart"
 #define GDM_KEY_ROOT_PATH "daemon/RootPath=/sbin:/usr/sbin:" GDM_USER_PATH
 #define GDM_KEY_SERV_AUTHDIR "daemon/ServAuthDir=" AUTHDIR
 #define GDM_KEY_SESSION_DESKTOP_DIR "daemon/SessionDesktopDir=/etc/X11/sessions/:" DMCONFDIR "/Sessions/:" DATADIR "/gdm/BuiltInSessions/:" DATADIR "/xsessions/"
@@ -441,6 +448,21 @@
 	GDM_LOGOUT_ACTION_LAST
 } GdmLogoutAction;
 
+#ifndef TYPEDEF_GDM_CUSTOM_CMD
+#define TYPEDEF_GDM_CUSTOM_CMD
+typedef struct _GdmCustomCmd GdmCustomCmd;
+#endif /* TYPEDEF_GDM_CUSTOM_CMD */
+struct _GdmCustomCmd {
+    gchar *command; /* command(s) to execute */
+    gchar *command_label; /* button/menu item label */
+    gchar *command_lr_label; /* radio button/list item label */
+    gchar *command_text; /* warning dialog text */
+    gchar *command_tooltip; /* tooltip string */
+    gboolean command_no_restart; /* no restart flag */
+};
+
+#define GDM_CUSTOM_COMMAND_MAX 10 /* maximum number of supported custom commands */
+
 #ifndef TYPEDEF_GDM_DISPLAY
 #define TYPEDEF_GDM_DISPLAY
 typedef struct _GdmDisplay GdmDisplay;
@@ -707,6 +729,9 @@
 #define GDM_SOP_SUSPEND_MACHINE "SUSPEND_MACHINE"  /* no arguments */
 #define GDM_SOP_CHOSEN_THEME "CHOSEN_THEME"  /* <slave pid> <theme name> */
 
+/*Execute custom cmd*/
+#define GDM_SOP_CUSTOM_CMD "CUSTOM_CMD"  /* <slave pid> <cmd id> */
+
 /* Start a new standard X flexible server */
 #define GDM_SOP_FLEXI_XSERVER "FLEXI_XSERVER" /* no arguments */
 
@@ -1192,10 +1217,10 @@
  *      200 = Too many messages
  *      999 = Unknown error
  */
-#define GDM_SUP_LOGOUT_ACTION_NONE	"NONE"
-#define GDM_SUP_LOGOUT_ACTION_HALT	"HALT"
-#define GDM_SUP_LOGOUT_ACTION_REBOOT	"REBOOT"
-#define GDM_SUP_LOGOUT_ACTION_SUSPEND	"SUSPEND"
+#define GDM_SUP_LOGOUT_ACTION_NONE	 "NONE"
+#define GDM_SUP_LOGOUT_ACTION_HALT	 "HALT"
+#define GDM_SUP_LOGOUT_ACTION_REBOOT	 "REBOOT"
+#define GDM_SUP_LOGOUT_ACTION_SUSPEND	 "SUSPEND"
 /*
  */
 #define GDM_SUP_QUERY_VT "QUERY_VT" /* None */
--- gdm-2.16.0/daemon/slave.c.org	2006-10-06 13:49:37.000000000 +0100
+++ gdm-2.16.0/daemon/slave.c	2006-10-24 14:16:38.000000000 +0100
@@ -4954,6 +4954,17 @@
 		case GDM_INTERRUPT_CANCEL:
 			do_cancel = TRUE;
 			break;
+		case GDM_INTERRUPT_CUSTOM_CMD:
+			if (d->attached &&
+			    ! ve_string_empty (&msg[2])) {
+				gchar *message = g_strdup_printf ("%s %ld %s", 
+					GDM_SOP_CUSTOM_CMD,
+					(long)getpid (), &msg[2]);
+
+				gdm_slave_send (message, TRUE);
+				g_free (message);
+			}
+			return TRUE;
 		case GDM_INTERRUPT_THEME:
 			g_free (d->theme_name);
 			d->theme_name = NULL;
--- gdm-2.16.0/gui/gdmlogin.c.org	2006-10-06 13:51:56.000000000 +0100
+++ gdm-2.16.0/gui/gdmlogin.c	2006-10-24 14:49:48.000000000 +0100
@@ -669,6 +669,21 @@
 	}
 }
 
+static void
+gdm_custom_cmd_handler (GtkWidget *widget, gint *cmd_id)
+{	
+	if (cmd_id) {
+	    gchar * key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TEXT_TEMPLATE, *cmd_id);
+	    if (gdm_wm_warn_dialog (
+		gdm_config_get_string (key_string) , "", GTK_STOCK_OK, NULL, TRUE) == GTK_RESPONSE_YES) {
+		    
+		    printf ("%c%c%c%d\n", STX, BEL, GDM_INTERRUPT_CUSTOM_CMD, *cmd_id);
+		    fflush (stdout);
+	    }
+
+	    g_free(key_string);		
+	}
+}
 
 static void
 gdm_login_halt_handler (void)
@@ -2379,6 +2394,25 @@
 		got_anything = TRUE;
 	}
 	
+	register int i = 0;
+	gchar * key_string = NULL;
+	for (; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TEMPLATE, i);
+		if (gdm_working_command_exists (gdm_config_get_string (key_string))) {
+			gint * cmd_index = g_new0(gint, 1);
+			*cmd_index = i;
+			key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_LR_LABEL_TEMPLATE, i);
+			item = gtk_menu_item_new_with_mnemonic (gdm_config_get_string (key_string));
+			gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
+			g_signal_connect (G_OBJECT (item), "activate",
+					  G_CALLBACK (gdm_custom_cmd_handler), 
+					  cmd_index);
+			gtk_widget_show (GTK_WIDGET (item));
+			got_anything = TRUE;			
+		}
+	}
+	g_free(key_string);	
+
 	if (gdm_working_command_exists (gdm_config_get_string (GDM_KEY_HALT))) {
 		item = gtk_menu_item_new_with_mnemonic (_("Shut _Down"));
 		gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
@@ -2976,6 +3010,27 @@
 	gdm_config_get_string (GDM_KEY_USE_24_CLOCK);
 	gdm_config_get_string (GDM_KEY_WELCOME);
 
+	/* String keys for custom commands */
+	register int i = 0;
+	gchar * key_string = NULL;	
+	for (; i < GDM_CUSTOM_COMMAND_MAX; i++) {		
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TEMPLATE, i);
+		gdm_config_get_string (key_string);
+
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i);
+		gdm_config_get_string (key_string);
+		
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_LR_LABEL_TEMPLATE, i);
+		gdm_config_get_string (key_string);
+		
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TEXT_TEMPLATE, i);
+		gdm_config_get_string (key_string);
+        
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TOOLTIP_TEMPLATE, i);
+		gdm_config_get_string (key_string);
+	}     
+	g_free(key_string);
+
 	gdm_config_get_int    (GDM_KEY_BACKGROUND_TYPE);
 	gdm_config_get_int    (GDM_KEY_BACKGROUND_PROGRAM_INITIAL_DELAY);
 	gdm_config_get_int    (GDM_KEY_BACKGROUND_PROGRAM_RESTART_DELAY);
@@ -3113,6 +3168,45 @@
 		back_prog_launch_after_timeout ();
 	}
 
+	/* Keys for custom commands */
+	register int i = 0;
+	gboolean custom_changed = FALSE;
+	gchar *key_string = NULL;
+	for (; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TEMPLATE, i);
+		if(gdm_config_reload_string (key_string))
+			custom_changed = TRUE;
+		
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i);
+		if(gdm_config_reload_string (key_string))
+			custom_changed = TRUE;
+		
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_LR_LABEL_TEMPLATE, i);
+		if(gdm_config_reload_string (key_string))
+			custom_changed = TRUE;
+		
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TEXT_TEMPLATE, i);
+		if(gdm_config_reload_string (key_string))
+			custom_changed = TRUE;
+        
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TOOLTIP_TEMPLATE, i);
+		if(gdm_config_reload_string (key_string))
+			custom_changed = TRUE;
+	}     
+	g_free(key_string);			
+
+	if(custom_changed){
+		/* Set busy cursor */
+		gdm_common_setup_cursor (GDK_WATCH);
+
+		gdm_wm_save_wm_order ();
+		gdm_kill_thingies ();
+		gdmcomm_comm_bulk_stop ();
+
+		_exit (DISPLAY_RESTARTGREETER);
+		return TRUE;		
+	}
+
 	gdm_config_reload_string (GDM_KEY_SOUND_PROGRAM);
 	gdm_config_reload_bool   (GDM_KEY_SOUND_ON_LOGIN);
 	gdm_config_reload_string (GDM_KEY_SOUND_ON_LOGIN_FILE);
--- gdm-2.16.0/gui/greeter/greeter.c.org	2006-10-06 13:58:59.000000000 +0100
+++ gdm-2.16.0/gui/greeter/greeter.c	2006-10-24 14:37:46.000000000 +0100
@@ -70,6 +70,8 @@
 static gboolean ignore_buttons = FALSE;
 gboolean GdmHaltFound          = FALSE;
 gboolean GdmRebootFound        = FALSE;
+gboolean *GdmCustomCmdsFound   = NULL;
+gboolean GdmAnyCustomCmdsFound = FALSE;
 gboolean GdmSuspendFound       = FALSE;
 gboolean GdmConfiguratorFound  = FALSE;
 
@@ -774,6 +776,28 @@
 	gdm_config_get_bool   (GDM_KEY_DEFAULT_WELCOME);
 	gdm_config_get_bool   (GDM_KEY_DEFAULT_REMOTE_WELCOME);
 
+	/* Keys for custom commands */
+	register int i = 0;
+	gchar * key_string = NULL;	
+	for (; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TEMPLATE, i);
+		gdm_config_get_string (key_string);
+
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i);
+		gdm_config_get_string (key_string);
+		
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_LR_LABEL_TEMPLATE, i);
+		gdm_config_get_string (key_string);
+		
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TEXT_TEMPLATE, i);
+		gdm_config_get_string (key_string);
+        
+		key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TOOLTIP_TEMPLATE, i);
+		gdm_config_get_string (key_string);
+	}     
+
+	g_free(key_string);
+
 	/* Keys not to include in reread_config */
 	gdm_config_get_string (GDM_KEY_SESSION_DESKTOP_DIR);
 	gdm_config_get_string (GDM_KEY_PID_FILE);
@@ -843,6 +867,43 @@
 		_exit (DISPLAY_RESTARTGREETER);
 	}
 
+	register int i = 0;
+	gboolean custom_changed = FALSE;
+	gchar *key_string = NULL;
+	for (; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+  	    key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TEMPLATE, i);
+	    if (gdm_config_reload_string (key_string))
+		custom_changed = TRUE;
+	    
+	    key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i);
+	    if (gdm_config_reload_string (key_string))
+		custom_changed = TRUE;
+	    
+	    key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_LR_LABEL_TEMPLATE, i);
+	    if (gdm_config_reload_string (key_string))
+		custom_changed = TRUE;
+	    
+	    key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TEXT_TEMPLATE, i);
+	    if (gdm_config_reload_string (key_string))
+		custom_changed = TRUE;
+	    
+	    key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TOOLTIP_TEMPLATE, i);
+	    if (gdm_config_reload_string (key_string))
+		custom_changed = TRUE;
+	}     
+	
+	g_free(key_string);			
+
+	if(custom_changed){
+	    /* Set busy cursor */
+	    gdm_common_setup_cursor (GDK_WATCH);
+	    
+	    gdm_wm_save_wm_order ();
+	    gdmcomm_comm_bulk_stop ();
+	    
+	    _exit (DISPLAY_RESTARTGREETER);
+	}
+
 	gdm_config_reload_string (GDM_KEY_SOUND_PROGRAM);
 	gdm_config_reload_bool   (GDM_KEY_SOUND_ON_LOGIN);
 	gdm_config_reload_string (GDM_KEY_SOUND_ON_LOGIN_FILE);
@@ -1146,12 +1207,23 @@
   * is displayed it doesn't show as 0.  Also determine if the Halt,
   * Reboot, Suspend and Configurator commands work.
   */
-  gdm_timed_delay      = gdm_config_get_int (GDM_KEY_TIMED_LOGIN_DELAY);
-  GdmHaltFound         = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_HALT));
-  GdmRebootFound       = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_REBOOT));
-  GdmSuspendFound      = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_SUSPEND));
-  GdmConfiguratorFound = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_CONFIGURATOR));
-
+  gdm_timed_delay         = gdm_config_get_int (GDM_KEY_TIMED_LOGIN_DELAY);
+  GdmHaltFound            = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_HALT));
+  GdmRebootFound          = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_REBOOT));
+  GdmSuspendFound         = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_SUSPEND));
+  GdmConfiguratorFound    = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_CONFIGURATOR));
+
+  GdmCustomCmdsFound = g_new0 (gboolean, GDM_CUSTOM_COMMAND_MAX);
+  register int i = 0;
+  gchar * key_string = NULL;	
+  for (; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+      /*  For each possible custom command */      
+      key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TEMPLATE, i);
+      GdmCustomCmdsFound[i] = gdm_working_command_exists (gdm_config_get_string (key_string));
+      if (GdmCustomCmdsFound[i])
+	  GdmAnyCustomCmdsFound = TRUE;
+  }
+  g_free(key_string);
 
   if (g_getenv ("GDM_THEME") != NULL)
      gdm_graphical_theme = g_strdup (g_getenv ("GDM_THEME"));
--- gdm-2.16.0/gui/greeter/greeter_parser.c.org	2006-10-06 14:09:53.000000000 +0100
+++ gdm-2.16.0/gui/greeter/greeter_parser.c	2006-10-24 14:45:47.000000000 +0100
@@ -34,6 +34,7 @@
 #include "greeter_configuration.h"
 #include "greeter_parser.h"
 #include "greeter_events.h"
+#include "gdm.h"
 
 /* FIXME: hack */
 extern GreeterItemInfo *welcome_string_info;
@@ -354,7 +355,7 @@
         {
 	  g_free (*translated_text);
 	  *translated_text = g_strdup (_("_Restart"));
-	}
+	}  
       else if (g_ascii_strcasecmp ((char *) prop, "chooser") == 0)
         {
 	  g_free (*translated_text);
@@ -411,12 +412,32 @@
         }
       else
         {
-          g_set_error (error,
-		       GREETER_PARSER_ERROR,
-		       GREETER_PARSER_ERROR_BAD_SPEC,
-		       "Bad stock label type");
-	  xmlFree (prop);
-	  return FALSE;
+	  gboolean is_error = TRUE;
+	  register int i = 0;
+	    for (; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+		gchar * key_string = NULL;
+		key_string = g_strdup_printf(_("custom_cmd%d"), i);
+		if (g_ascii_strcasecmp ((char *) prop, key_string) == 0) {
+		    g_free (*translated_text);
+		    g_free(key_string);
+		    key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i);
+		    *translated_text = g_strdup(gdm_config_get_string (key_string));
+		    g_free(key_string);
+		    is_error = FALSE;
+		    break;
+		}
+		g_free(key_string);
+	    }
+	    
+	    if (is_error)
+	      {
+		g_set_error (error,
+		     GREETER_PARSER_ERROR,
+		     GREETER_PARSER_ERROR_BAD_SPEC,
+		     "Bad stock label type");
+		xmlFree (prop);
+		return FALSE;
+	      }
 	}
 
       /* This is the very very very best "translation" */
--- gdm-2.16.0/gui/greeter/greeter_item.c.org	2006-10-06 14:08:18.000000000 +0100
+++ gdm-2.16.0/gui/greeter/greeter_item.c	2006-10-24 14:41:41.000000000 +0100
@@ -35,6 +35,8 @@
 
 extern gboolean GdmHaltFound;
 extern gboolean GdmRebootFound;
+extern gboolean GdmCustomCmdFound;
+extern gboolean *GdmCustomCmdsFound;
 extern gboolean GdmSuspendFound;
 extern gboolean GdmConfiguratorFound;
 
@@ -209,6 +211,19 @@
        strcmp (info->show_type, "suspend") == 0))
 	  return FALSE;
 
+  register int i = 0;
+  gchar * key_string = NULL;	
+  for (; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+      key_string = g_strdup_printf(_("custom_cmd%d"), i);
+      if (( ! sysmenu || ! GdmCustomCmdsFound[i]) &&
+      (info->show_type != NULL &&
+       strcmp (info->show_type, key_string) == 0)) {
+	      g_free(key_string);
+	      return FALSE;
+	  }
+  }
+  g_free(key_string);
+
   if (( ! gdm_config_get_bool (GDM_KEY_TIMED_LOGIN_ENABLE) ||
           ve_string_empty (gdm_config_get_string (GDM_KEY_TIMED_LOGIN))) &&
       (info->show_type != NULL &&
--- gdm-2.16.0/gui/greeter/greeter_system.c.org	2006-10-06 14:11:49.000000000 +0100
+++ gdm-2.16.0/gui/greeter/greeter_system.c	2006-10-24 14:56:34.000000000 +0100
@@ -39,6 +39,8 @@
 GtkWidget *dialog;
 extern gboolean GdmHaltFound;
 extern gboolean GdmRebootFound;
+extern gboolean * GdmCustomCmdsFound;
+extern gboolean GdmAnyCustomCmdsFound;
 extern gboolean GdmSuspendFound;
 extern gboolean GdmConfiguratorFound;
 
@@ -79,6 +81,20 @@
 }
 
 static void
+query_greeter_custom_cmd_handler (GtkWidget *widget, gint *cmd_id)
+{
+        if (cmd_id) {
+	        gchar * key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TEXT_TEMPLATE, *cmd_id);
+		if (gdm_wm_warn_dialog (gdm_config_get_string (key_string) , "", 
+					GTK_STOCK_OK, NULL, TRUE) == GTK_RESPONSE_YES) {
+		        printf ("%c%c%c%d\n", STX, BEL, GDM_INTERRUPT_CUSTOM_CMD, *cmd_id);
+			fflush (stdout);
+		}
+		g_free(key_string);		
+	}
+}
+
+static void
 query_greeter_halt_handler (void)
 {
 	if (gdm_wm_warn_dialog (_("Are you sure you want to Shut Down the computer?"), "",
@@ -107,6 +123,12 @@
 	_exit (DISPLAY_REBOOT);
 }
 
+static void
+greeter_custom_cmd_handler (gint cmd_id)
+{
+	printf ("%c%c%c%d\n", STX, BEL, GDM_INTERRUPT_CUSTOM_CMD, cmd_id);
+	fflush (stdout);
+}
 
 static void
 greeter_halt_handler (void)
@@ -174,7 +196,7 @@
 				  NULL);
 	}
 
-	if (GdmRebootFound || GdmHaltFound || GdmSuspendFound) {
+	if (GdmRebootFound || GdmHaltFound || GdmSuspendFound || GdmAnyCustomCmdsFound) {
 		sep = gtk_separator_menu_item_new ();
 		gtk_menu_shell_append (GTK_MENU_SHELL (menu), sep);
 		gtk_widget_show (sep);
@@ -189,6 +211,25 @@
 				  NULL);
 	}
 
+	if (GdmAnyCustomCmdsFound) {
+	        register int i = 0;
+		for (; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+		        if (GdmCustomCmdsFound[i]){
+			         gint * cmd_index = g_new0(gint, 1);
+				 *cmd_index = i;
+				 gchar * key_string = NULL;
+				 key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i);
+				 w = gtk_menu_item_new_with_mnemonic (gdm_config_get_string(key_string));
+				 gtk_menu_shell_append (GTK_MENU_SHELL (menu), w);
+				 gtk_widget_show (GTK_WIDGET (w));
+				 g_signal_connect (G_OBJECT (w), "activate",
+						   G_CALLBACK (query_greeter_custom_cmd_handler),
+						   cmd_index);
+				 g_free(key_string);
+			}
+		}
+	}
+
 	if (GdmHaltFound) {
 		w = gtk_menu_item_new_with_mnemonic (_("Shut _Down"));
 		gtk_menu_shell_append (GTK_MENU_SHELL (menu), w);
@@ -232,10 +273,11 @@
   GtkWidget *halt_radio = NULL;
   GtkWidget *suspend_radio = NULL;
   GtkWidget *restart_radio = NULL;
+  GtkWidget **custom_cmds_radio = NULL;
   GtkWidget *config_radio = NULL;
   GtkWidget *chooser_radio = NULL;
   gchar *s;
-  int ret;
+  int ret, i;
   GSList *radio_group = NULL;
   static GtkTooltips *tooltips = NULL;
 
@@ -316,6 +358,33 @@
 	  gtk_widget_show (restart_radio);
   }
 
+  if (GdmAnyCustomCmdsFound) {
+	  custom_cmds_radio = g_new0 (GtkWidget*, GDM_CUSTOM_COMMAND_MAX); 
+	  for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+	          custom_cmds_radio[i] = NULL;
+		  if (GdmCustomCmdsFound[i]){
+		          gchar * key_string = NULL;
+			  key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_LR_LABEL_TEMPLATE, i);
+			  radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (group_radio));
+			  custom_cmds_radio[i] = gtk_radio_button_new_with_mnemonic (radio_group,
+										     gdm_config_get_string(key_string));
+			  group_radio = custom_cmds_radio[i];
+			  g_free(key_string);
+			  key_string = g_strdup_printf(_("%s%d="), GDM_KEY_CUSTOM_CMD_TOOLTIP_TEMPLATE, i);
+			  gtk_tooltips_set_tip (tooltips, GTK_WIDGET (custom_cmds_radio[i]),
+						gdm_config_get_string(key_string),
+						NULL);
+			  g_signal_connect (G_OBJECT(custom_cmds_radio[i]), "button_press_event",
+					    G_CALLBACK(radio_button_press_event), NULL);
+			  gtk_box_pack_start (GTK_BOX (vbox),
+					      custom_cmds_radio[i],
+					      FALSE, FALSE, 4);
+			  gtk_widget_show (custom_cmds_radio[i]);
+			  g_free(key_string);
+		  }
+	  }
+  }
+
   if (GdmSuspendFound) {
 	  if (group_radio != NULL)
 		  radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (group_radio));
@@ -405,6 +474,11 @@
     greeter_config_handler ();
   else if (chooser_radio != NULL && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (chooser_radio)))
     greeter_chooser_handler ();
+  else
+    for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+	if (custom_cmds_radio[i] != NULL &&  gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (custom_cmds_radio[i])))
+	    greeter_custom_cmd_handler (i);
+    }  
 
   gtk_widget_destroy (dialog);
 }
@@ -415,7 +489,7 @@
 {
   greeter_item_register_action_callback ("reboot_button",
 					 (ActionFunc)query_greeter_restart_handler,
-					 NULL);
+					 NULL);  
   greeter_item_register_action_callback ("halt_button",
 					 (ActionFunc)query_greeter_halt_handler,
 					 NULL);
@@ -431,4 +505,15 @@
   greeter_item_register_action_callback ("chooser_button",
 					 (ActionFunc)greeter_chooser_handler,
 					 NULL);
+
+  register int i = 0;
+  for (; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+      gint * cmd_index = g_new0(gint, 1);
+      *cmd_index = i;
+      gchar * key_string = g_strdup_printf(_("custom_cmd_button%d"), i);
+      greeter_item_register_action_callback (key_string,
+					     (ActionFunc)query_greeter_custom_cmd_handler,
+					     cmd_index);
+      g_free(key_string);
+  }
 }
--- gdm-2.16.0/gui/greeter/greeter_configuration.h.org	2006-10-06 13:57:50.000000000 +0100
+++ gdm-2.16.0/gui/greeter/greeter_configuration.h	2006-10-24 14:30:26.000000000 +0100
@@ -29,10 +29,17 @@
 extern gboolean GdmChooserButton;
 extern gchar *GdmHalt;
 extern gchar *GdmReboot;
+extern gchar *GdmCustomCmdText;
+extern gchar *GdmCustomCmdLabel;
+extern gchar *GdmCustomCmdLRLabel;
+extern gchar *GdmCustomCmdTooltip;
 extern gchar *GdmSuspend;
 extern gchar *GdmConfigurator;
 extern gboolean GdmHaltFound;
 extern gboolean GdmRebootFound;
+extern gboolean GdmCustomCmdFound;
+extern gboolean *GdmCustomCmdsFound;
+extern gboolean GdmAnyCustomCmdsFound;
 extern gboolean GdmSuspendFound;
 extern gboolean GdmConfiguratorFound;
 extern gchar *GdmSessionDir;
--- gdm-2.16.0/AUTHORS.org	2006-10-06 14:33:18.000000000 +0100
+++ gdm-2.16.0/AUTHORS	2006-10-06 14:33:39.000000000 +0100
@@ -76,6 +76,7 @@
 	Lee Mallabone <lee0@callnetuk.com>
 	Leena Gunda <leena.gunda@wipro.com>
 	Luis Villa <louie@ximian.com>
+	Lukasz Zalewski <lukas@dcs.qmul.ac.uk>
 	Mark McLoughlin <mark@skynet.ie>
 	Mathieu Lacage <mathieu@eazel.com>
 	Matt Forrest <mforrest@scs.ryerson.ca>
--- gdm-2.16.0/ChangeLog.org	2006-10-06 14:33:53.000000000 +0100
+++ gdm-2.16.0/ChangeLog	2006-10-10 14:55:31.000000000 +0100
@@ -0,0 +1,32 @@
+2006-09-05  Lukasz Zalewski  <lukas@dcs.qmul.ac.uk>
+
+        * Release 2.16.0:
+	* daemon/gdmconfig.c: Added variables & functions used to read/store 
+	  CustomCommand related values
+	* daemon/gdm.c (custom_cmd): New function that handles 
+	  execution of CustomCommand if NoRestart is set to false
+	* daemon/gdm.c (custom_cmd_no_restart): New function that handles 
+	  execution of CustomCommand if NoRestart option is set to true
+	* daemon/gdm. [ch]: Updated macros and several functions to accomodate 
+	  new CustomCommand functionality
+	* daemon/slave.c: Added Custom command interrupt handler to handle 
+	  the CustomCommand when gdm/system restart is not required
+	* gui/gdmlogin.c (gdm_custom_cmd_handler): New function that handles 
+	  execution of CustomCommand
+	* gui/gdmlogin.c: Added variables and updated several functions to accomodate 
+	  new CustomCommand functionality
+	* gui/greeter/greeter_configuration.h: Added variables used to 
+	  store CustomCommand related values
+	* gui/greeter/greeter.c: Added variables that use/store 
+	  CustomCommand related values
+	* gui/greeter/greeter.dtd: Added custom_cmd_button as 
+	  one of the internal id for stock buttons
+	* gui/greeter/greeter_item.c: Added visibility check for custom_cmd related widgets
+	* gui/greeter/greeter_parser.c: Added code for parsing custom_cmd stock items
+	* gui/greeter/greeter_system.c (greeter_custom_cmd_handler): New function that 
+	  handles execution of CustomCommand
+	* gui/greeter/greeter_system.c (query_greeter_custom_cmd_handler): New function that 
+	  handles execution of CustomCommand (with warn message query beforehand)
+	* gui/greeter/greeter_system.c: Updated macros and several functions to accomodate 
+	  new CustomCommand functionality
+	
--- gdm-2.16.0/config/gdm.conf.in.org	2006-10-06 17:38:02.000000000 +0100
+++ gdm-2.16.0/config/gdm.conf.in	2006-10-10 16:09:45.000000000 +0100
@@ -202,6 +202,33 @@
 # kills it.  10 seconds should be long enough for X, but Xgl may need 20 or 25. 
 GdmXserverTimeout=10
 
+# Custom command path, you can add different commands separated by 
+# by a semicolon.  GDM will use the first one it can find. Examples:
+# /sbin/bootwindoze;/usr/bin/bootwindoze, or
+# /sbin/runupdate;/usr/local/sbin/runupdate
+#CustomCommand=
+# NOTE: All of the CustomCommand options below are not valid without CustomCommand option
+# Custom command dialog message that will appear on all warning dialogs.
+# This will vary depending on what you want to do. Examples:
+# Are you sure you want to restart system into Windoze?, or
+# Are you sure you want do do this?
+#CustomCommandText=
+# Custom command label that will appear as stock label on buttons/menu items. Examples:
+# _Windoze, or
+# _Update Me
+#CustomCommandLabel=
+# Custom command label that will appear as stock label on radio buttons/list items. Examples:
+# Restart into _Windoze, or
+# Perform system _Update
+#CustomCommandLRLabel=
+# Custom command tooltip. Examples
+# Restarts the computer into Windoze
+# Updates the computer software to the most recent version(s)
+#CustomCommandTooltip=
+# Custom command gdm/system restart option. Setting it to true will not restart gdm after
+# command execution.
+#CustomCommandNoRestart=
+
 [security]
 # Allow root to login.  It makes sense to turn this off for kiosk use, when
 # you want to minimize the possibility of break in.
