From a652d31e11f9d8edee277620ba338714c4a47315 Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Fri, 30 Nov 2001 16:56:28 +0000 Subject: [PATCH] r947: Added new SOAP methods Copy, Move, Link, Mount and FileType (Stephen Watson). --- ROX-Filer/Help/Changes | 4 + ROX-Filer/src/action.c | 63 ++++-- ROX-Filer/src/action.h | 8 +- ROX-Filer/src/dnd.c | 12 +- ROX-Filer/src/global.h | 3 + ROX-Filer/src/main.c | 32 +-- ROX-Filer/src/menu.c | 6 +- ROX-Filer/src/pinboard.c | 2 +- ROX-Filer/src/remote.c | 524 ++++++++++++++++++++++++++++++++++------------ ROX-Filer/src/run.c | 2 +- ROX-Filer/src/support.c | 44 +++- ROX-Filer/src/support.h | 4 +- ROX-Filer/src/usericons.c | 2 +- 13 files changed, 505 insertions(+), 201 deletions(-) diff --git a/ROX-Filer/Help/Changes b/ROX-Filer/Help/Changes index 0dd78b14..2db14f78 100644 --- a/ROX-Filer/Help/Changes +++ b/ROX-Filer/Help/Changes @@ -2,6 +2,10 @@ A RISC OS-like filer for X by Thomas Leonard +30-Nov-2001 +~~~~~~~~~~~ +Added new SOAP methods Copy, Move, Link, Mount and FileType (Stephen Watson). + 29-Nov-2001 ~~~~~~~~~~~ Moved 'Select All', 'Clear Selection' and 'Select If...' to a new 'Select' diff --git a/ROX-Filer/src/action.c b/ROX-Filer/src/action.c index ae618a91..57e92508 100644 --- a/ROX-Filer/src/action.c +++ b/ROX-Filer/src/action.c @@ -805,7 +805,9 @@ static void destroy_action_window(GtkWidget *widget, gpointer data) * * If autoq then automatically selects 'Quiet'. */ -static GUIside *start_action(gpointer data, ActionChild *func, gboolean autoq) +static GUIside *start_action_with_options(gpointer data, ActionChild *func, + gboolean autoq, + int force, int brief, int recurse) { int filedes[4]; /* 0 and 2 are for reading */ GUIside *gui_side; @@ -827,9 +829,9 @@ static GUIside *start_action(gpointer data, ActionChild *func, gboolean autoq) return NULL; } - o_force = option_get_int("action_force"); - o_brief = option_get_int("action_brief"); - o_recurse = option_get_int("action_recurse"); + o_force = force; + o_brief = brief; + o_recurse = recurse; child = fork(); switch (child) @@ -935,6 +937,14 @@ static GUIside *start_action(gpointer data, ActionChild *func, gboolean autoq) return gui_side; } +static GUIside *start_action(gpointer data, ActionChild *func, gboolean autoq) +{ + return start_action_with_options(data, func, autoq, + option_get_int("action_force"), + option_get_int("action_brief"), + option_get_int("action_recurse")); +} + /* ACTIONS ON ONE ITEM */ /* These may call themselves recursively, or ask questions, etc. @@ -1536,17 +1546,10 @@ static gboolean do_move(char *path, char *dest) static gboolean do_link(char *path, char *dest) { char *dest_path; - char *leaf; check_flags(); - leaf = strrchr(path, '/'); - if (!leaf) - leaf = path; /* Error? */ - else - leaf++; - - dest_path = make_path(dest, leaf)->str; + dest_path = make_dest_path(path, dest); if (quiet) { @@ -1962,15 +1965,18 @@ void action_usage(FilerWindow *filer_window) /* Mount/unmount listed items (paths). * Free the list after this function returns. * If open_dir is TRUE and the dir is successfully mounted, open it. + * quiet can be -1 for default. */ -void action_mount(GList *paths, gboolean open_dir) +void action_mount(GList *paths, gboolean open_dir, int quiet) { #ifdef DO_MOUNT_POINTS GUIside *gui_side; + if (quiet == -1) + quiet = option_get_int("action_mount"); + mount_open_dir = open_dir; - gui_side = start_action(paths, mount_cb, - option_get_int("action_mount")); + gui_side = start_action(paths, mount_cb, quiet); if (!gui_side) return; @@ -2094,15 +2100,20 @@ void action_chmod(FilerWindow *filer_window) gtk_widget_show_all(gui_side->window); } -/* If leaf is NULL then the copy has the same name as the original */ -void action_copy(GList *paths, char *dest, char *leaf) +/* If leaf is NULL then the copy has the same name as the original. + * quiet can be -1 for default. + */ +void action_copy(GList *paths, char *dest, char *leaf, int quiet) { GUIside *gui_side; + if (quiet == -1) + quiet = option_get_int("action_copy"); + action_dest = dest; action_leaf = leaf; action_do_func = do_copy; - gui_side = start_action(paths, list_cb, option_get_int("action_copy")); + gui_side = start_action(paths, list_cb, quiet); if (!gui_side) return; @@ -2111,15 +2122,20 @@ void action_copy(GList *paths, char *dest, char *leaf) gtk_widget_show_all(gui_side->window); } -/* If leaf is NULL then the file is not renamed */ -void action_move(GList *paths, char *dest, char *leaf) +/* If leaf is NULL then the file is not renamed. + * quiet can be -1 for default. + */ +void action_move(GList *paths, char *dest, char *leaf, int quiet) { GUIside *gui_side; + if (quiet == -1) + quiet = option_get_int("action_move"); + action_dest = dest; action_leaf = leaf; action_do_func = do_move; - gui_side = start_action(paths, list_cb, option_get_int("action_move")); + gui_side = start_action(paths, list_cb, quiet); if (!gui_side) return; @@ -2128,11 +2144,14 @@ void action_move(GList *paths, char *dest, char *leaf) gtk_widget_show_all(gui_side->window); } -void action_link(GList *paths, char *dest) +/* If leaf is NULL then the link will have the same name */ +/* XXX: No quiet option here? */ +void action_link(GList *paths, char *dest, char *leaf) { GUIside *gui_side; action_dest = dest; + action_leaf = leaf; action_do_func = do_link; gui_side = start_action(paths, list_cb, option_get_int("action_link")); if (!gui_side) diff --git a/ROX-Filer/src/action.h b/ROX-Filer/src/action.h index 238e0d80..86d32663 100644 --- a/ROX-Filer/src/action.h +++ b/ROX-Filer/src/action.h @@ -13,13 +13,13 @@ void action_init(void); void action_usage(FilerWindow *filer_window); -void action_mount(GList *paths, gboolean open_dir); +void action_mount(GList *paths, gboolean open_dir, int quiet); void action_delete(FilerWindow *filer_window); void action_chmod(FilerWindow *filer_window); void action_find(FilerWindow *filer_window); -void action_move(GList *paths, char *dest, char *leaf); -void action_copy(GList *paths, char *dest, char *leaf); -void action_link(GList *paths, char *dest); +void action_move(GList *paths, char *dest, char *leaf, int quiet); +void action_copy(GList *paths, char *dest, char *leaf, int quiet); +void action_link(GList *paths, char *dest, char *leaf); void show_condition_help(gpointer data); void set_find_string_colour(GtkWidget *widget, guchar *string); diff --git a/ROX-Filer/src/dnd.c b/ROX-Filer/src/dnd.c index 9fafa03a..dc0bd459 100644 --- a/ROX-Filer/src/dnd.c +++ b/ROX-Filer/src/dnd.c @@ -1041,11 +1041,11 @@ static void got_uri_list(GtkWidget *widget, else if (context->action == GDK_ACTION_ASK) prompt_action(local_paths, dest_path); else if (context->action == GDK_ACTION_MOVE) - action_move(local_paths, dest_path, NULL); + action_move(local_paths, dest_path, NULL, -1); else if (context->action == GDK_ACTION_COPY) - action_copy(local_paths, dest_path, NULL); + action_copy(local_paths, dest_path, NULL, -1); else if (context->action == GDK_ACTION_LINK) - action_link(local_paths, dest_path); + action_link(local_paths, dest_path, NULL); else error = _("Unknown action requested"); @@ -1075,11 +1075,11 @@ static void got_uri_list(GtkWidget *widget, static void menuitem_response(gpointer data, guint action, GtkWidget *widget) { if (action == MENU_MOVE) - action_move(prompt_local_paths, prompt_dest_path, NULL); + action_move(prompt_local_paths, prompt_dest_path, NULL, -1); else if (action == MENU_COPY) - action_copy(prompt_local_paths, prompt_dest_path, NULL); + action_copy(prompt_local_paths, prompt_dest_path, NULL, -1); else if (action == MENU_LINK) - action_link(prompt_local_paths, prompt_dest_path); + action_link(prompt_local_paths, prompt_dest_path, NULL); else if (action == MENU_SET_ICON) { if (g_list_length(prompt_local_paths) == 1) diff --git a/ROX-Filer/src/global.h b/ROX-Filer/src/global.h index ac340d98..f488419b 100644 --- a/ROX-Filer/src/global.h +++ b/ROX-Filer/src/global.h @@ -17,6 +17,9 @@ #define SOAP_ENV_NS "http://www.w3.org/2001/06/soap-envelope" +/* For debugging... */ +#define SHOW(var) (g_print("[ " #var " = '%s' ]\n", var)) + /* We typedef various pointers here to avoid creating unnecessary * dependencies on the other header files. */ diff --git a/ROX-Filer/src/main.c b/ROX-Filer/src/main.c index 1a93c3c2..4f131e43 100644 --- a/ROX-Filer/src/main.c +++ b/ROX-Filer/src/main.c @@ -163,7 +163,6 @@ static gboolean child_died_flag = FALSE; /* Static prototypes */ static void show_features(void); -static xmlDocPtr soap_new(xmlNodePtr *ret_body); static void soap_add(xmlNodePtr body, xmlChar *function, xmlChar *arg1_name, xmlChar *arg1_value, @@ -187,7 +186,7 @@ int main(int argc, char **argv) guchar *tmp, *dir, *slash; gchar *client_id = NULL; gboolean show_user = FALSE; - xmlDocPtr rpc, soap_rpc = NULL; + xmlDocPtr rpc, soap_rpc = NULL, reply; xmlNodePtr body; home_dir = g_get_home_dir(); @@ -461,8 +460,13 @@ int main(int argc, char **argv) session_init(client_id); g_free(client_id); - run_soap(rpc); + reply = run_soap(rpc); xmlFreeDoc(rpc); + if (reply) + { + save_xml_file(reply, "-"); + xmlFreeDoc(reply); + } if (number_of_windows > 0) gtk_main(); @@ -501,28 +505,6 @@ static void show_features(void) ); } -/* Create a new SOAP message and return the document and the (empty) - * body node. - */ -static xmlDocPtr soap_new(xmlNodePtr *ret_body) -{ - xmlDocPtr doc; - xmlNodePtr root; - xmlNs *env_ns; - - doc = xmlNewDoc("1.0"); - root = xmlNewDocNode(doc, NULL, "Envelope", NULL); - xmlDocSetRootElement(doc, root); - - env_ns = xmlNewNs(root, SOAP_ENV_NS, "env"); - xmlSetNs(root, env_ns); - - *ret_body = xmlNewTextChild(root, env_ns, "Body", NULL); - xmlNewNs(*ret_body, ROX_NS, "rox"); - - return doc; -} - static void soap_add(xmlNodePtr body, xmlChar *function, xmlChar *arg1_name, xmlChar *arg1_value, diff --git a/ROX-Filer/src/menu.c b/ROX-Filer/src/menu.c index b2a85e87..ba680497 100644 --- a/ROX-Filer/src/menu.c +++ b/ROX-Filer/src/menu.c @@ -64,7 +64,7 @@ typedef enum menu_icon_style { MIS_DEFAULT } MenuIconStyle; -typedef void (*ActionFn)(GList *paths, char *dest_dir, char *leaf); +typedef void (*ActionFn)(GList *paths, char *dest_dir, char *leaf, int quiet); typedef void MenuCallback(GtkWidget *widget, gpointer data); GtkAccelGroup *filer_keys; @@ -1070,7 +1070,7 @@ static gboolean action_with_leaf(ActionFn action, guchar *current, guchar *new) } local_paths = g_list_append(NULL, current); - action(local_paths, new_dir, leaf); + action(local_paths, new_dir, leaf, -1); g_list_free(local_paths); g_free(new_dir); @@ -1498,7 +1498,7 @@ static gboolean new_file_type_cb(guchar *initial, guchar *path) leaf = g_basename(path); paths = g_list_append(NULL, templ); - action_copy(paths, dest, leaf); + action_copy(paths, dest, leaf, -1); g_list_free(paths); g_free(dest); diff --git a/ROX-Filer/src/pinboard.c b/ROX-Filer/src/pinboard.c index 0e1ff1ce..c389a009 100644 --- a/ROX-Filer/src/pinboard.c +++ b/ROX-Filer/src/pinboard.c @@ -194,7 +194,7 @@ void pinboard_activate(guchar *name) guchar *path, *slash; /* Treat an empty name the same as NULL */ - if (!*name) + if (name && !*name) name = NULL; if (old_board) diff --git a/ROX-Filer/src/remote.c b/ROX-Filer/src/remote.c index f6e70700..102a21f6 100644 --- a/ROX-Filer/src/remote.c +++ b/ROX-Filer/src/remote.c @@ -27,6 +27,8 @@ #include "config.h" +#include + #include #include #include @@ -44,10 +46,21 @@ #include "filer.h" #include "pinboard.h" #include "panel.h" +#include "action.h" +#include "type.h" static GdkAtom filer_atom; /* _ROX_FILER_VERSION_HOST */ static GdkAtom xsoap; /* _XSOAP */ +typedef struct _SOAP_call SOAP_call; +typedef xmlNodePtr (*SOAP_func)(GList *args); + +struct _SOAP_call { + SOAP_func func; + gchar **required_args; + gchar **optional_args; +}; + static GHashTable *rpc_calls = NULL; /* MethodName -> Function */ /* Static prototypes */ @@ -57,13 +70,20 @@ static void soap_send(GtkWidget *from, GdkAtom prop, GdkWindow *dest); static gboolean client_event(GtkWidget *window, GdkEventClient *event, gpointer data); -static xmlNodePtr rpc_OpenDir(xmlNodePtr method); -static xmlNodePtr rpc_CloseDir(xmlNodePtr method); -static xmlNodePtr rpc_Examine(xmlNodePtr method); -static xmlNodePtr rpc_Show(xmlNodePtr method); -static xmlNodePtr rpc_Pinboard(xmlNodePtr method); -static xmlNodePtr rpc_Panel(xmlNodePtr method); -static xmlNodePtr rpc_Run(xmlNodePtr method); +static void soap_register(char *name, SOAP_func func, char *req, char *opt); +static xmlNodePtr soap_invoke(xmlNode *method); +static xmlNodePtr rpc_OpenDir(GList *args); +static xmlNodePtr rpc_CloseDir(GList *args); +static xmlNodePtr rpc_Examine(GList *args); +static xmlNodePtr rpc_Show(GList *args); +static xmlNodePtr rpc_Pinboard(GList *args); +static xmlNodePtr rpc_Panel(GList *args); +static xmlNodePtr rpc_Run(GList *args); +static xmlNodePtr rpc_Copy(GList *args); +static xmlNodePtr rpc_Move(GList *args); +static xmlNodePtr rpc_Link(GList *args); +static xmlNodePtr rpc_FileType(GList *args); +static xmlNodePtr rpc_Mount(GList *args); /**************************************************************** * EXTERNAL INTERFACE * @@ -85,13 +105,21 @@ gboolean remote_init(xmlDocPtr rpc, gboolean new_copy) rpc_calls = g_hash_table_new(g_str_hash, g_str_equal); - g_hash_table_insert(rpc_calls, "Run", rpc_Run); - g_hash_table_insert(rpc_calls, "OpenDir", rpc_OpenDir); - g_hash_table_insert(rpc_calls, "Pinboard", rpc_Pinboard); - g_hash_table_insert(rpc_calls, "Panel", rpc_Panel); - g_hash_table_insert(rpc_calls, "CloseDir", rpc_CloseDir); - g_hash_table_insert(rpc_calls, "Examine", rpc_Examine); - g_hash_table_insert(rpc_calls, "Show", rpc_Show); + soap_register("Run", rpc_Run, "Filename", NULL); + soap_register("OpenDir", rpc_OpenDir, "Filename", NULL); + soap_register("CloseDir", rpc_CloseDir, "Filename", NULL); + soap_register("Examine", rpc_Examine, "Filename", NULL); + soap_register("Show", rpc_Show, "Directory,Leafname", NULL); + + soap_register("Pinboard", rpc_Pinboard, NULL, "Name"); + soap_register("Panel", rpc_Panel, "Side", "Name"); + + soap_register("FileType", rpc_FileType, "Filename", NULL); + + soap_register("Copy", rpc_Copy, "From,To", "Leafname,Quiet"); + soap_register("Move", rpc_Move, "From,To", "Leafname,Quiet"); + soap_register("Link", rpc_Link, "From,To", "Leafname,Quiet"); + soap_register("Mount", rpc_Mount, "MountPoints", "OpenDir,Quiet"); /* Look for a property on the root window giving the IPC window * of an already-running copy of this version of the filer, running @@ -161,7 +189,8 @@ gboolean remote_init(xmlDocPtr rpc, gboolean new_copy) */ xmlDocPtr run_soap(xmlDocPtr soap) { - xmlNodePtr body, node; + xmlNodePtr body, node, rep_body, reply; + xmlDocPtr rep_doc = NULL; g_return_val_if_fail(soap != NULL, NULL); @@ -180,8 +209,6 @@ xmlDocPtr run_soap(xmlDocPtr soap) for (node = body->xmlChildrenNode; node; node = node->next) { - xmlNodePtr (*fn)(xmlNodePtr method); - if (node->type != XML_ELEMENT_NODE) continue; @@ -193,11 +220,14 @@ xmlDocPtr run_soap(xmlDocPtr soap) continue; } - fn = g_hash_table_lookup(rpc_calls, node->name); - if (fn) - fn(node); - else - g_warning("Unknown method '%s'", node->name); + reply = soap_invoke(node); + + if (reply) + { + if (!rep_doc) + rep_doc = soap_new(&rep_body); + xmlAddChild(rep_body, reply); + } } goto out; @@ -208,7 +238,7 @@ bad_soap: out: number_of_windows--; - return NULL; + return rep_doc; } @@ -216,6 +246,24 @@ out: * INTERNAL FUNCTIONS * ****************************************************************/ +/* Register this function to handle SOAP calls to method 'name'. + * 'req' and 'opt' are comma separated lists of argument names, in the order + * that they are to be delivered to the function. + * NULL will be passed for an opt argument if not given. + * Otherwise, the parameter is the xmlNode from the call. + */ +static void soap_register(char *name, SOAP_func func, char *req, char *opt) +{ + SOAP_call *call; + + call = g_new(SOAP_call, 1); + call->func = func; + call->required_args = req ? g_strsplit(req, ",", 0) : NULL; + call->optional_args = opt ? g_strsplit(opt, ",", 0) : NULL; + + g_hash_table_insert(rpc_calls, g_strdup(name), call); +} + /* Get the remote IPC window of the already-running filer if there * is one. */ @@ -262,32 +310,19 @@ static gboolean get_ipc_property(GdkWindow *window, Window *r_xid) return retval; } -static gboolean client_event(GtkWidget *window, - GdkEventClient *event, - gpointer user_data) +static char *read_property(GdkWindow *window, GdkAtom prop, gint *out_length) { gint grab_len = 4096; gint length; guchar *data; - GdkWindow *src_window; - GdkAtom prop; - - if (event->message_type != xsoap) - return FALSE; - - src_window = gdk_window_foreign_new(event->data.l[0]); - g_return_val_if_fail(src_window != NULL, FALSE); - prop = gdk_x11_xatom_to_atom(event->data.l[1]); while (1) { - xmlDocPtr doc; - - if (!(gdk_property_get(src_window, prop, + if (!(gdk_property_get(window, prop, gdk_x11_xatom_to_atom(XA_STRING), 0, grab_len, - TRUE, NULL, NULL, + FALSE, NULL, NULL, &length, &data) && data)) - return TRUE; /* Error? */ + return NULL; /* Error? */ if (length >= grab_len) { @@ -299,170 +334,322 @@ static gboolean client_event(GtkWidget *window, data = g_realloc(data, length + 1); data[length] = '\0'; /* libxml seems to need this */ - - doc = xmlParseMemory(g_strndup(data, length), length); - g_free(data); + *out_length = length; - run_soap(doc); - if (number_of_windows == 0) - gtk_main_quit(); + return data; + } +} - xmlFreeDoc(doc); +static gboolean client_event(GtkWidget *window, + GdkEventClient *event, + gpointer user_data) +{ + GdkWindow *src_window; + GdkAtom prop; + xmlDocPtr reply; + guchar *data; + gint length; + xmlDocPtr doc; + if (event->message_type != xsoap) + return FALSE; + + src_window = gdk_window_foreign_new(event->data.l[0]); + g_return_val_if_fail(src_window != NULL, FALSE); + prop = gdk_x11_xatom_to_atom(event->data.l[1]); + + data = read_property(src_window, prop, &length); + if (!data) return TRUE; + + doc = xmlParseMemory(g_strndup(data, length), length); + g_free(data); + + reply = run_soap(doc); + if (number_of_windows == 0) + gtk_main_quit(); + + xmlFreeDoc(doc); + + if (reply) + { + /* Send reply back... */ + xmlChar *mem; + int size; + + xmlDocDumpMemory(reply, &mem, &size); + g_return_val_if_fail(size > 0, TRUE); + + gdk_property_change(src_window, prop, + gdk_x11_xatom_to_atom(XA_STRING), 8, + GDK_PROP_MODE_REPLACE, mem, size); + g_free(mem); } + else + gdk_property_delete(src_window, prop); - return FALSE; + return TRUE; } -/* The RPC handlers all work in the same way -- they get passed the - * method node in the RPC call and they return the result node, or - * NULL if there isn't a result. - */ +/* Some handy functions for processing SOAP RPC arguments... */ -static xmlNodePtr rpc_OpenDir(xmlNodePtr method) +/* Returns TRUE, FALSE, or -1 (if argument is unspecified) */ +static int bool_value(xmlNode *arg) { - xmlNodePtr path_node; - char *path; - - path_node = get_subnode(method, ROX_NS, "Filename"); + int answer; + char *optval; - g_return_val_if_fail(path_node != NULL, NULL); + if (!arg) + return -1; - path = xmlNodeGetContent(path_node); + optval = xmlNodeGetContent(arg); + answer = text_to_boolean(optval, -1); /* XXX: Report error? */ + g_free(optval); - filer_opendir(path, NULL); + return answer; +} - g_free(path); +/* Returns the text of this arg as a string, or NULL if the (optional) + * argument wasn't supplied. Returns "" if the arg is empty. + * g_free() the result. + */ +static char *string_value(xmlNode *arg) +{ + char *retval; + + if (!arg) + return NULL; - return NULL; + retval = xmlNodeGetContent(arg); + + return retval ? retval : g_strdup(""); } -static xmlNodePtr rpc_Run(xmlNodePtr method) +/* Return a list of strings, one for each child node of arg. + * g_list_free the list, and g_free each string. + */ +static GList *list_value(xmlNode *arg) { - xmlNodePtr path_node; - char *path; - - path_node = get_subnode(method, ROX_NS, "Filename"); + GList *list = NULL; + xmlNode *node; + + for (node = arg->xmlChildrenNode; node; node = node->next) + { + if (node->type != XML_ELEMENT_NODE) + continue; - g_return_val_if_fail(path_node != NULL, NULL); + list = g_list_append(list, string_value(node)); + } - path = xmlNodeGetContent(path_node); + return list; +} - run_by_path(path); +#define ARG(n) ((xmlNode *) g_list_nth(args, n)->data) +/* The RPC handlers all work in the same way -- they get passed a list of + * xmlNode arguments from the RPC call and they return the result node, or + * NULL if there isn't a result. + */ + +static xmlNodePtr rpc_OpenDir(GList *args) +{ + char *path; + + path = string_value(ARG(0)); + filer_opendir(path, NULL); g_free(path); - + return NULL; } -static xmlNodePtr rpc_CloseDir(xmlNodePtr method) +static xmlNodePtr rpc_Run(GList *args) { - xmlNodePtr path_node; char *path; - - path_node = get_subnode(method, ROX_NS, "Filename"); - g_return_val_if_fail(path_node != NULL, NULL); + path = string_value(ARG(0)); + run_by_path(path); + g_free(path); + + return NULL; +} - path = xmlNodeGetContent(path_node); +static xmlNodePtr rpc_CloseDir(GList *args) +{ + char *path; + path = string_value(ARG(0)); filer_close_recursive(path); - g_free(path); - + return NULL; } -static xmlNodePtr rpc_Examine(xmlNodePtr method) +static xmlNodePtr rpc_Examine(GList *args) { - xmlNodePtr path_node; char *path; - - path_node = get_subnode(method, ROX_NS, "Filename"); - - g_return_val_if_fail(path_node != NULL, NULL); - - path = xmlNodeGetContent(path_node); + path = string_value(ARG(0)); examine(path); - g_free(path); - + return NULL; } -static xmlNodePtr rpc_Show(xmlNodePtr method) +static xmlNodePtr rpc_Show(GList *args) { - xmlNodePtr node; char *dir, *leaf; - node = get_subnode(method, ROX_NS, "Directory"); - g_return_val_if_fail(node != NULL, NULL); - dir = xmlNodeGetContent(node); - - node = get_subnode(method, ROX_NS, "Leafname"); - g_return_val_if_fail(node != NULL, NULL); - leaf = xmlNodeGetContent(node); + dir = string_value(ARG(0)); + leaf = string_value(ARG(1)); /* XXX: Seems silly to join them only to split again later... */ open_to_show(make_path(dir, leaf)->str); g_free(dir); g_free(leaf); - + return NULL; } -static xmlNodePtr rpc_Pinboard(xmlNodePtr method) +static xmlNodePtr rpc_Pinboard(GList *args) { - xmlNodePtr node; - char *value = NULL; - - node = get_subnode(method, ROX_NS, "Name"); + char *name = NULL; - if (node) - value = xmlNodeGetContent(node); + name = string_value(ARG(0)); + pinboard_activate(name); + g_free(name); - pinboard_activate(value); + return NULL; +} + +/* args = Side, [Name] */ +static xmlNodePtr rpc_Panel(GList *args) +{ + char *name, *side; + + side = string_value(ARG(0)); + name = string_value(ARG(1)); + + if (strcmp(side, "Top") == 0) + panel_new(name, PANEL_TOP); + else if (strcmp(side, "Bottom") == 0) + panel_new(name, PANEL_BOTTOM); + else if (strcmp(side, "Left") == 0) + panel_new(name, PANEL_LEFT); + else if (strcmp(side, "Right") == 0) + panel_new(name, PANEL_RIGHT); + else + g_warning("Unknown panel side '%s'", side); + + g_free(side); + g_free(name); + + return NULL; +} + +static xmlNodePtr rpc_Copy(GList *args) +{ + GList *from; + char *to; + char *leaf; + int quiet; + + from = list_value(ARG(0)); + to = string_value(ARG(1)); + leaf = string_value(ARG(2)); + quiet = bool_value(ARG(3)); + + if (from) + action_copy(from, to, leaf, quiet); + + g_list_foreach(from, (GFunc) g_free, NULL); + g_list_free(from); + g_free(to); + g_free(leaf); + + return NULL; +} + +static xmlNodePtr rpc_Move(GList *args) +{ + GList *from; + char *to; + char *leaf; + int quiet; + + from = list_value(ARG(0)); + to = string_value(ARG(1)); + leaf = string_value(ARG(2)); + quiet = bool_value(ARG(3)); + + if (from) + action_move(from, to, leaf, quiet); + + g_list_foreach(from, (GFunc) g_free, NULL); + g_list_free(from); + g_free(to); + g_free(leaf); + + return NULL; +} + +static xmlNodePtr rpc_Link(GList *args) +{ + GList *from; + char *to; + char *leaf; + + from = list_value(ARG(0)); + to = string_value(ARG(1)); + leaf = string_value(ARG(2)); + + if (from) + action_link(from, to, leaf); + + g_list_foreach(from, (GFunc) g_free, NULL); + g_list_free(from); + g_free(to); + g_free(leaf); - g_free(value); - return NULL; } -static xmlNodePtr rpc_Panel(xmlNodePtr method) +static xmlNodePtr rpc_FileType(GList *args) { - xmlNodePtr name, side; - char *value = NULL, *side_name = NULL; + MIME_type *type; + char *path, *tname; + xmlNodePtr reply; + + path = string_value(ARG(0)); + type = type_get_type(path); + g_free(path); - name = get_subnode(method, ROX_NS, "Name"); - side = get_subnode(method, ROX_NS, "Side"); + reply = xmlNewNode(ARG(0)->ns, "FileTypeReply"); + tname = g_strconcat(type->media_type, "/", type->subtype, NULL); + xmlNewChild(reply, reply->ns, "MIMEType", tname); + g_free(tname); - if (!side) - { - g_warning("Panel requires a Side"); - return NULL; - } + return reply; +} - if (name) - value = xmlNodeGetContent(name); - side_name = xmlNodeGetContent(side); - - if (strcmp(side_name, "Top") == 0) - panel_new(value, PANEL_TOP); - else if (strcmp(side_name, "Bottom") == 0) - panel_new(value, PANEL_BOTTOM); - else if (strcmp(side_name, "Left") == 0) - panel_new(value, PANEL_LEFT); - else if (strcmp(side_name, "Right") == 0) - panel_new(value, PANEL_RIGHT); - else - g_warning("Unknown panel side '%s'", side_name); +static xmlNodePtr rpc_Mount(GList *args) +{ + GList *paths; + int open_dir, quiet; + + paths = list_value(ARG(0)); + open_dir = bool_value(ARG(1)); + quiet = bool_value(ARG(2)); - g_free(value); - g_free(side_name); + if (open_dir == -1) + open_dir = TRUE; + if (paths) + action_mount(paths, open_dir, quiet); + + g_list_foreach(paths, (GFunc) g_free, NULL); + g_list_free(paths); + return NULL; } @@ -473,7 +660,16 @@ static void soap_done(GtkWidget *widget, GdkEventProperty *event, gpointer data) if (prop != event->atom) return; - /* TODO: If we got a reply, display it here */ + /* If we got a reply, display it here */ + if (event->state == GDK_PROPERTY_NEW_VALUE) + { + gint length; + + data = read_property(event->window, event->atom, &length); + + if (data) + puts(data); + } gtk_main_quit(); } @@ -508,3 +704,59 @@ static void soap_send(GtkWidget *from, GdkAtom prop, GdkWindow *dest) gtk_main(); } + +/* Lookup this method in rpc_calls and invoke it. + * Returns the SOAP reply or fault, or NULL if this method + * doesn't return anything. + */ +static xmlNodePtr soap_invoke(xmlNode *method) +{ + GList *args = NULL; + SOAP_call *call; + gchar **arg; + xmlNodePtr retval = NULL; + + call = g_hash_table_lookup(rpc_calls, method->name); + if (!call) + { + g_warning("Unknown method '%s'", method->name); + return NULL; + } + + if (call->required_args) + { + for (arg = call->required_args; *arg; arg++) + { + xmlNode *node; + + node = get_subnode(method, ROX_NS, *arg); + if (!node) + { + g_warning("Missing required argument '%s' " + "in call to method '%s'", *arg, + method->name); + goto out; + } + + args = g_list_append(args, node); + } + } + + if (call->optional_args) + { + for (arg = call->optional_args; *arg; arg++) + { + xmlNode *node; + + node = get_subnode(method, ROX_NS, *arg); + + args = g_list_append(args, node); + } + } + + retval = call->func(args); +out: + g_list_free(args); + + return retval; +} diff --git a/ROX-Filer/src/run.c b/ROX-Filer/src/run.c index 175826d7..33eb44f5 100644 --- a/ROX-Filer/src/run.c +++ b/ROX-Filer/src/run.c @@ -217,7 +217,7 @@ gboolean run_diritem(guchar *full_path, GList *paths; paths = g_list_prepend(NULL, full_path); - action_mount(paths, filer_window == NULL); + action_mount(paths, filer_window == NULL, -1); g_list_free(paths); if (item->flags & ITEM_FLAG_MOUNTED || !filer_window) diff --git a/ROX-Filer/src/support.c b/ROX-Filer/src/support.c index 190498ed..04b86754 100644 --- a/ROX-Filer/src/support.c +++ b/ROX-Filer/src/support.c @@ -809,7 +809,7 @@ void add_default_styles(void) /* Return the (first) child of this node with the given name. * NULL if not found. */ -xmlNode *get_subnode(xmlNode *node, char *namespaceURI, char *name) +xmlNode *get_subnode(xmlNode *node, const char *namespaceURI, const char *name) { for (node = node->xmlChildrenNode; node; node = node->next) { @@ -833,6 +833,26 @@ xmlNode *get_subnode(xmlNode *node, char *namespaceURI, char *name) return NULL; } +/* + * Interperet text as a boolean value. Return defvalue if we don't + * recognise it + */ +int text_to_boolean(const char *text, int defvalue) +{ + if(g_strcasecmp(text, "true")==0) + return TRUE; + else if(g_strcasecmp(text, "false")==0) + return FALSE; + else if(g_strcasecmp(text, "yes")==0) + return TRUE; + else if(g_strcasecmp(text, "no")==0) + return FALSE; + else if(isdigit(text[0])) + return !!atoi(text); + + return defvalue; +} + void set_to_null(gpointer *data) { *data = NULL; @@ -860,6 +880,28 @@ int save_xml_file(xmlDocPtr doc, gchar *filename) return 0; } +/* Create a new SOAP message and return the document and the (empty) + * body node. + */ +xmlDocPtr soap_new(xmlNodePtr *ret_body) +{ + xmlDocPtr doc; + xmlNodePtr root; + xmlNs *env_ns; + + doc = xmlNewDoc("1.0"); + root = xmlNewDocNode(doc, NULL, "Envelope", NULL); + xmlDocSetRootElement(doc, root); + + env_ns = xmlNewNs(root, SOAP_ENV_NS, "env"); + xmlSetNs(root, env_ns); + + *ret_body = xmlNewTextChild(root, env_ns, "Body", NULL); + xmlNewNs(*ret_body, ROX_NS, "rox"); + + return doc; +} + /* Return the pathname that this symlink points to. * NULL on error (not a symlink, path too long) and errno set. * g_free() the result. diff --git a/ROX-Filer/src/support.h b/ROX-Filer/src/support.h index 199f1a44..526ec432 100644 --- a/ROX-Filer/src/support.h +++ b/ROX-Filer/src/support.h @@ -37,9 +37,11 @@ gboolean in_list(guchar *item, guchar *list); GPtrArray *split_path(guchar *path); guchar *get_relative_path(guchar *from, guchar *to); void add_default_styles(void); -xmlNode *get_subnode(xmlNode *node, char *namespaceURI, char *name); +xmlNode *get_subnode(xmlNode *node, const char *namespaceURI, const char *name); +int text_to_boolean(const char *text, int defvalue); void set_to_null(gpointer *data); int save_xml_file(xmlDocPtr doc, gchar *filename); char *readlink_dup(char *path); +xmlDocPtr soap_new(xmlNodePtr *ret_body); #endif /* _SUPPORT_H */ diff --git a/ROX-Filer/src/usericons.c b/ROX-Filer/src/usericons.c index 94c73230..fb0254cc 100644 --- a/ROX-Filer/src/usericons.c +++ b/ROX-Filer/src/usericons.c @@ -592,7 +592,7 @@ static gboolean set_icon_for_type(const MIME_type *type, gchar *iconpath, dir = g_dirname(target); paths = g_list_append(NULL, iconpath); - action_copy(paths, dir, leaf); + action_copy(paths, dir, leaf, -1); g_free(leaf); g_free(dir); -- 2.11.4.GIT