Patch for question callback



Hi,

Here is the patch I have been working on to add a new question callback
to gnome-vfs and libgnomeui. 
The main purpose was to make the sftp module ask the user what to do
when the authenticity of a host cant be determined. 
As you can see I currently just pass the message from sftp to the user,
this is not so nice since it is a bad message and it is not
translatable. I'm not much of an usability guy so I need some help with
the message, so anyone with such talent feel free to help out.

//Snaggen
Index: libgnomevfs/GNOME_VFS_Daemon.idl
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/GNOME_VFS_Daemon.idl,v
retrieving revision 1.6
diff -u -r1.6 GNOME_VFS_Daemon.idl
--- libgnomevfs/GNOME_VFS_Daemon.idl	22 Jan 2004 15:35:01 -0000	1.6
+++ libgnomevfs/GNOME_VFS_Daemon.idl	8 Apr 2004 11:05:39 -0000
@@ -67,6 +67,13 @@
 		
 		/* Standard module callbacks: */
 		
+		struct ModuleCallbackQuestionIn {
+			string message;
+			sequence<string> choices;
+		};
+		struct ModuleCallbackQuestionOut {
+			short answer;
+		};
 		struct ModuleCallbackAuthenticationIn {
 			string uri;
 			string realm;
Index: libgnomevfs/gnome-vfs-module-callback-marshall.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-module-callback-marshall.c,v
retrieving revision 1.4
diff -u -r1.4 gnome-vfs-module-callback-marshall.c
--- libgnomevfs/gnome-vfs-module-callback-marshall.c	10 Dec 2003 12:39:23 -0000	1.4
+++ libgnomevfs/gnome-vfs-module-callback-marshall.c	8 Apr 2004 11:05:39 -0000
@@ -603,6 +603,143 @@
 	g_free (auth_out);
 }
 
+static CORBA_any *
+question_marshal_in (gconstpointer in, gsize in_size)
+{
+	CORBA_any *retval;
+	GNOME_VFS_ModuleCallbackQuestionIn *ret_in;
+	const GnomeVFSModuleCallbackQuestionIn *question_in;
+	int cnt;
+
+	if (in_size != sizeof (GnomeVFSModuleCallbackQuestionIn)) {
+		return NULL;
+	}
+	question_in = in;
+
+	retval = CORBA_any_alloc ();
+	retval->_type = TC_GNOME_VFS_ModuleCallbackQuestionIn;
+	retval->_value = GNOME_VFS_ModuleCallbackQuestionIn__alloc ();
+	ret_in = retval->_value;
+
+	/* Set the values in ret_in, like ret_in->stuff=question_in->stuff */
+	ret_in->message = corba_string_or_null_dup(question_in->message);
+	if (question_in->choices) {
+		
+		/* Just count the number of elements and allocate the memory */
+		for (cnt=0; question_in->choices[cnt] != NULL; cnt++);
+		ret_in->choices._maximum = cnt; 
+		ret_in->choices._length = cnt;
+		ret_in->choices._buffer = CORBA_sequence_CORBA_string_allocbuf (cnt);
+		//FIXME
+		//CORBA_sequence_set_release (ret_in->choices, TRUE);
+		
+		/* Insert the strings into the sequence */
+		for (cnt=0; question_in->choices[cnt] != NULL; cnt++) {
+			ret_in->choices._buffer[cnt] = corba_string_or_null_dup (question_in->choices[cnt]);
+		}
+	}
+	return retval;
+}
+
+static gboolean
+question_demarshal_in (const CORBA_any *any_in,
+			gpointer *in, gsize *in_size,
+			gpointer *out, gsize *out_size)
+{
+	GNOME_VFS_ModuleCallbackQuestionIn *corba_in;
+	GnomeVFSModuleCallbackQuestionIn *question_in;
+	GnomeVFSModuleCallbackQuestionOut *question_out;
+	int cnt;
+
+	if (!CORBA_TypeCode_equal (any_in->_type, TC_GNOME_VFS_ModuleCallbackQuestionIn, NULL)) {
+		return FALSE;
+	}
+	
+	question_in = *in = g_new0 (GnomeVFSModuleCallbackQuestionIn, 1);
+	*in_size = sizeof (GnomeVFSModuleCallbackQuestionIn);
+	question_out = *out = g_new0 (GnomeVFSModuleCallbackQuestionOut, 1);
+	*out_size = sizeof (GnomeVFSModuleCallbackQuestionOut);
+
+	corba_in = (GNOME_VFS_ModuleCallbackQuestionIn *)any_in->_value;
+
+	if (corba_in) {
+		question_in->message = decode_corba_string_or_null (corba_in->message, FALSE);	
+		question_in->choices = g_new(char *, corba_in->choices._length+1);
+		for(cnt=0; cnt<corba_in->choices._length; cnt++){
+			question_in->choices[cnt] = g_strdup(corba_in->choices._buffer[cnt]);
+		}
+		question_in->choices[corba_in->choices._length] = NULL;
+		
+		question_out->answer = -1; /* Set a default value */
+
+		return TRUE;
+	}
+	return FALSE;
+}
+
+static CORBA_any *
+question_marshal_out (gconstpointer out, gsize out_size)
+{
+	CORBA_any *retval;
+	GNOME_VFS_ModuleCallbackQuestionOut *ret_out;
+	const GnomeVFSModuleCallbackQuestionOut *question_out;
+
+	if (out_size != sizeof (GnomeVFSModuleCallbackQuestionOut)) {
+		return NULL;
+	}
+	question_out = out;
+
+	retval = CORBA_any_alloc();
+	retval->_type = TC_GNOME_VFS_ModuleCallbackQuestionOut;
+	retval->_value = GNOME_VFS_ModuleCallbackQuestionOut__alloc ();
+	ret_out = retval->_value;
+
+	g_message("Anser is:%d\n", question_out->answer);
+	ret_out->answer = question_out->answer;
+
+	return retval;
+}
+
+static gboolean
+question_demarshal_out (CORBA_any *any_out, gpointer out, gsize out_size)
+{
+	GNOME_VFS_ModuleCallbackQuestionOut *corba_out;
+	GnomeVFSModuleCallbackQuestionOut *question_out;
+
+	if (!CORBA_TypeCode_equal (any_out->_type, TC_GNOME_VFS_ModuleCallbackQuestionOut, NULL) ||
+	    out_size != sizeof (GnomeVFSModuleCallbackQuestionOut)) {
+		return FALSE;
+	}
+	question_out = out;
+
+	corba_out = (GNOME_VFS_ModuleCallbackQuestionOut *)any_out->_value;
+
+	question_out->answer = corba_out->answer,TRUE;
+
+	return TRUE;
+}
+
+static void
+question_free_in (gpointer in)
+{
+	GnomeVFSModuleCallbackQuestionIn *question_in;
+
+	question_in = in;
+
+	g_free (question_in->message);
+	g_strfreev (question_in->choices);
+	g_free (question_in);
+}
+
+static void
+question_free_out (gpointer out)
+{
+	GnomeVFSModuleCallbackQuestionOut *question_out;
+
+	question_out = out;
+	g_free (question_out);
+}
+
 struct ModuleCallbackMarshaller {
 	char *name;
 	CORBA_any *(*marshal_in)(gconstpointer in, gsize in_size);
@@ -654,6 +791,14 @@
 	  save_auth_free_in,
 	  save_auth_free_out
 	},
+	{ GNOME_VFS_MODULE_CALLBACK_QUESTION,
+	  question_marshal_in,
+	  question_demarshal_in,
+	  question_marshal_out,
+	  question_demarshal_out,
+	  question_free_in,
+	  question_free_out
+	},
 };
 
 
Index: libgnomevfs/gnome-vfs-standard-callbacks.h
===================================================================
RCS file: /cvs/gnome/gnome-vfs/libgnomevfs/gnome-vfs-standard-callbacks.h,v
retrieving revision 1.10
diff -u -r1.10 gnome-vfs-standard-callbacks.h
--- libgnomevfs/gnome-vfs-standard-callbacks.h	8 Jan 2004 19:46:37 -0000	1.10
+++ libgnomevfs/gnome-vfs-standard-callbacks.h	8 Apr 2004 11:05:39 -0000
@@ -83,6 +83,15 @@
  */
 #define GNOME_VFS_MODULE_CALLBACK_HTTP_PROXY_AUTHENTICATION "http:proxy-authentication"
 
+/*
+ * hook name: "ask-question"
+ * In arg: GnomeVFSModuleCallbackQuestionIn *
+ * Out arg: GnomeVFSModuleCallbackQuestionOut *
+ * 
+ * Called when access to a URI requires the user to make a choise
+ */
+#define GNOME_VFS_MODULE_CALLBACK_QUESTION "ask-question"
+
 typedef struct {
 	char *uri;		/* Full URI of operation */
 	char *protocol;         /* The protocol of the request */
@@ -300,6 +309,31 @@
 	void *reserved2;
 } GnomeVFSModuleCallbackStatusMessageOut;
 
+typedef struct {
+	char *message;		/* A message explaining the question to the user or 
+				 * NULL if there is no message */
+	char **choices;		/* The list of choices the user have to choose from,
+						   the list must be NULL terminated.
+						   The choices will be displayes so that choises[0]
+						   will be to the left and choises[n] will be to the 
+						   right.
+						   The last choice in the list should be affirmative
+						   to comply with the button ordering in gnome */
+
+	/* Reserved "padding" to avoid future breaks in ABI compatibility */
+	void *reserved1;
+	void *reserved2;
+} GnomeVFSModuleCallbackQuestionIn;
+
+typedef struct {
+	int answer; /* The index of the choice in the choices list sent in 
+				   to the callback */
+
+	/* Reserved "padding" to avoid future breaks in ABI compatibility */
+	void *reserved1;
+	void *reserved2;
+} GnomeVFSModuleCallbackQuestionOut;
+
 G_END_DECLS
 
 #endif /* GNOME_VFS_STANDARD_CALLBACKS_H */
Index: libgnomeui/gnome-authentication-manager.c
===================================================================
RCS file: /cvs/gnome/libgnomeui/libgnomeui/gnome-authentication-manager.c,v
retrieving revision 1.7
diff -u -r1.7 gnome-authentication-manager.c
--- libgnomeui/gnome-authentication-manager.c	24 Mar 2004 10:40:55 -0000	1.7
+++ libgnomeui/gnome-authentication-manager.c	8 Apr 2004 11:09:59 -0000
@@ -703,6 +703,145 @@
 	DEBUG_MSG (("-%s\n", G_GNUC_FUNCTION));
 }
 
+typedef struct {
+	const GnomeVFSModuleCallbackQuestionIn	*in_args;
+	GnomeVFSModuleCallbackQuestionOut		*out_args;
+
+	GnomeVFSModuleCallbackResponse response;
+	gpointer response_data;
+} QuestionCallbackInfo;
+
+static void
+question_dialog_button_clicked (GtkDialog *dialog, 
+				      gint button_number, 
+				      QuestionCallbackInfo *info)
+{
+	info->out_args->answer = button_number;
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+
+static void
+question_dialog_destroyed (GtkDialog *dialog, QuestionCallbackInfo *info)
+{
+	info->response (info->response_data);
+	g_free (info);
+}
+
+static void
+question_dialog_closed (GtkDialog *dialog, QuestionCallbackInfo *info)
+{
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+static GtkWidget *create_question_dialog(char *msg, char **choices) 
+{
+	GtkWidget *dialog;
+	int cnt;
+	
+	dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, msg);
+	if (choices) {
+		for (cnt=0; choices[cnt] != NULL; cnt++) {
+			/* Maybe we should define some gnome-vfs stockbuttons and 
+			 * then replace them here with gtk-stockbuttons */
+			gtk_dialog_add_button(GTK_DIALOG(dialog), choices[cnt], cnt);			
+		}
+	}
+	return (dialog);
+}
+
+static gint /* GtkFunction */
+present_question_dialog_nonblocking (QuestionCallbackInfo *info)
+{
+	GtkWidget *dialog;
+	GtkWidget *toplevel, *current_grab;
+
+	g_return_val_if_fail (info != NULL, 0);
+
+	dialog = create_question_dialog (info->in_args->message,info->in_args->choices);
+	
+	toplevel = NULL;
+	current_grab = gtk_grab_get_current ();
+	if (current_grab) {
+		toplevel = gtk_widget_get_toplevel (current_grab);
+	}
+	if (toplevel && GTK_WIDGET_TOPLEVEL (toplevel)) {
+		/* There is a modal window, so we need to be modal too in order to
+		 * get input. We set the other modal dialog as parent, which
+		 * hopefully gives us better window management.
+		 */
+		gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+		gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (toplevel));
+	}
+
+	g_signal_connect (GTK_OBJECT(dialog), "response", 
+			  G_CALLBACK (question_dialog_button_clicked), info);
+	g_signal_connect (dialog, "close", 
+			  G_CALLBACK (question_dialog_closed), info);
+	g_signal_connect (dialog, "destroy", 
+			  G_CALLBACK (question_dialog_destroyed), info);
+	
+	gtk_widget_show (GTK_WIDGET (dialog));
+	return 0;
+}
+
+
+static void /* GnomeVFSAsyncModuleCallback */
+vfs_async_question_callback (gconstpointer in, size_t in_size, 
+					gpointer out, size_t out_size, 
+					gpointer user_data,
+					GnomeVFSModuleCallbackResponse response,
+					gpointer response_data)
+{
+	GnomeVFSModuleCallbackQuestionIn *in_real;
+	GnomeVFSModuleCallbackQuestionOut *out_real;
+	GtkWidget *dialog;
+	QuestionCallbackInfo *info;
+	
+	g_return_if_fail (sizeof (GnomeVFSModuleCallbackQuestionIn) == in_size
+		&& sizeof (GnomeVFSModuleCallbackQuestionOut) == out_size);
+
+	g_return_if_fail (in != NULL);
+	g_return_if_fail (out != NULL);
+
+	in_real = (GnomeVFSModuleCallbackQuestionIn *)in;
+	out_real = (GnomeVFSModuleCallbackQuestionOut *)out;
+
+	info = g_new (QuestionCallbackInfo, 1);
+	
+	info->in_args = in_real;
+	info->out_args = out_real;
+	info->response = response;
+	info->response_data = response_data;
+
+	present_question_dialog_nonblocking(info);
+}
+
+static void /* GnomeVFSModuleCallback */
+vfs_question_callback (gconstpointer in, size_t in_size, 
+				  gpointer out, size_t out_size, 
+				  gpointer user_data)
+{
+	GnomeVFSModuleCallbackQuestionIn *in_real;
+	GnomeVFSModuleCallbackQuestionOut *out_real;
+	guint32 item;
+	GtkWidget *dialog;
+	
+	g_return_if_fail (sizeof (GnomeVFSModuleCallbackQuestionIn) == in_size
+		&& sizeof (GnomeVFSModuleCallbackQuestionOut) == out_size);
+
+	g_return_if_fail (in != NULL);
+	g_return_if_fail (out != NULL);
+
+	in_real = (GnomeVFSModuleCallbackQuestionIn *)in;
+	out_real = (GnomeVFSModuleCallbackQuestionOut *)out;
+
+	dialog = create_question_dialog (in_real->message,in_real->choices);
+	out_real->answer = gtk_dialog_run (GTK_DIALOG(dialog));
+
+	gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
 void
 gnome_authentication_manager_init (void)
 {
@@ -731,6 +870,10 @@
 						     vfs_async_save_authentication_callback, 
 						     GINT_TO_POINTER (0),
 						     NULL);
+	gnome_vfs_async_module_callback_set_default (GNOME_VFS_MODULE_CALLBACK_QUESTION,
+						     vfs_async_question_callback, 
+						     GINT_TO_POINTER (0),
+						     NULL);
 
 	/* These are in case someone makes a synchronous http call for
 	 * some reason. 
@@ -757,6 +900,10 @@
 					       vfs_save_authentication_callback, 
 					       GINT_TO_POINTER (0),
 					       NULL);
+	gnome_vfs_module_callback_set_default (GNOME_VFS_MODULE_CALLBACK_QUESTION,
+					       vfs_question_callback, 
+					       GINT_TO_POINTER (0),
+					       NULL);
 
 }
 
@@ -784,6 +931,10 @@
 					      vfs_async_save_authentication_callback, 
 					      GINT_TO_POINTER (0),
 					      NULL);
+	gnome_vfs_async_module_callback_push (GNOME_VFS_MODULE_CALLBACK_QUESTION,
+					      vfs_async_question_callback, 
+					      GINT_TO_POINTER (0),
+					      NULL);
 }
 
 void
@@ -794,6 +945,7 @@
 	gnome_vfs_async_module_callback_pop (GNOME_VFS_MODULE_CALLBACK_FILL_AUTHENTICATION);
 	gnome_vfs_async_module_callback_pop (GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION);
 	gnome_vfs_async_module_callback_pop (GNOME_VFS_MODULE_CALLBACK_SAVE_AUTHENTICATION);
+	gnome_vfs_async_module_callback_pop (GNOME_VFS_MODULE_CALLBACK_QUESTION);
 }
 
 void
@@ -821,6 +973,10 @@
 					vfs_save_authentication_callback, 
 					GINT_TO_POINTER (0),
 					NULL);
+	gnome_vfs_module_callback_push (GNOME_VFS_MODULE_CALLBACK_QUESTION,
+					vfs_question_callback, 
+					GINT_TO_POINTER (0),
+					NULL);
 }
 
 void
@@ -831,5 +987,6 @@
 	gnome_vfs_module_callback_pop (GNOME_VFS_MODULE_CALLBACK_FILL_AUTHENTICATION);
 	gnome_vfs_module_callback_pop (GNOME_VFS_MODULE_CALLBACK_FULL_AUTHENTICATION);
 	gnome_vfs_module_callback_pop (GNOME_VFS_MODULE_CALLBACK_SAVE_AUTHENTICATION);
+	gnome_vfs_module_callback_pop (GNOME_VFS_MODULE_CALLBACK_QUESTION);
 }
 
Index: sftp-method.c
===================================================================
RCS file: /cvs/gnome/gnome-vfs/modules/sftp-method.c,v
retrieving revision 1.5
diff -u -r1.5 sftp-method.c
--- sftp-method.c	8 Mar 2004 18:53:47 -0000	1.5
+++ sftp-method.c	8 Apr 2004 11:07:57 -0000
@@ -944,7 +944,10 @@
 	GError         *error = NULL;
 
 	gchar          *args[20]; /* Enough for now, extend if you add more args */
-
+	gboolean invoked; 		  
+	GnomeVFSModuleCallbackQuestionIn in_args; 
+	GnomeVFSModuleCallbackQuestionOut out_args;
+	
 	DEBUG (gchar *tmp);
 
 	/* Fill in the first few args */
@@ -1083,11 +1086,41 @@
 				}
 				done_auth = TRUE;
 			} else if (g_str_has_prefix (buffer, "The authenticity of host")) {
-				/* FIXME: This should do a callback asking the user if the host id is ok */
-				/* For now we just fail */
-				res = GNOME_VFS_ERROR_ACCESS_DENIED;
-				goto bail;
-                        }
+				//FIXME: Don't use message. Create a better translatable 
+				//		 message to present to the user.
+				in_args.message = buffer;
+				in_args.choices = g_new(char *, 3);
+				//FIXME: Add stuff to translate the strings.
+				in_args.choices[0] = "Cancel";
+				in_args.choices[1] = "Accept New Host Key";
+				in_args.choices[2] = NULL;
+				
+				invoked = gnome_vfs_module_callback_invoke
+					(GNOME_VFS_MODULE_CALLBACK_QUESTION,
+					 &in_args, sizeof (in_args),
+					 &out_args, sizeof (out_args));
+				
+				if (invoked) {
+					if (out_args.answer == 1) {
+						g_io_channel_write_chars (tty_channel, "yes\n", -1, &len, NULL);
+					} else if (out_args.answer == 0) {
+						g_io_channel_write_chars (tty_channel, "no\n", -1, &len, NULL);
+					} else {
+						g_io_channel_write_chars (tty_channel, "no\n", -1, &len, NULL);
+						res = GNOME_VFS_ERROR_GENERIC;
+						goto bail;
+					}
+					g_io_channel_flush (tty_channel, NULL);
+					buffer[0]='\0';
+				} else {
+					g_io_channel_write_chars (tty_channel, "no\n", -1, &len, NULL);
+					g_io_channel_flush (tty_channel, NULL);
+					buffer[0]='\0';
+					res = GNOME_VFS_ERROR_ACCESS_DENIED;
+					goto bail;
+				}
+			}
+			
 		}
 	}
 


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