From 0a5f034d95518d1c0e08f21f1c41f08a3ccdf1ef Mon Sep 17 00:00:00 2001 From: root Date: Tue, 1 Jul 2014 13:25:36 +0000 Subject: [PATCH 1/2] Added some code for handling of renaming nodes. --- libinfinity/client/infc-browser.c | 58 ++++++++++++++++++++++ libinfinity/common/inf-browser.c | 36 ++++++++++++++ libinfinity/common/inf-browser.h | 12 +++++ libinfinity/common/inf-request-result.c | 64 +++++++++++++++++++++++++ libinfinity/common/inf-request-result.h | 11 +++++ 5 files changed, 181 insertions(+) diff --git a/libinfinity/client/infc-browser.c b/libinfinity/client/infc-browser.c index cfc40d30..f99701e2 100644 --- a/libinfinity/client/infc-browser.c +++ b/libinfinity/client/infc-browser.c @@ -3512,6 +3512,55 @@ infc_browser_handle_sync_in(InfcBrowser* browser, return result; } +static gboolean +infc_browser_handle_rename_node(InfcBrowser* browser, + InfXmlConnection* connection, + xmlNodePtr xml, + GError** error) +{ + InfcBrowserPrivate* priv; + InfcBrowserNode* node; + InfcRequest* request; + InfBrowserIter iter; + xmlChar* new_name; + + if((new_name = inf_xml_util_get_attribute_required(xml, "new_name", error)) == NULL) return FALSE; + + priv = INFC_BROWSER_PRIVATE(browser); + node = infc_browser_get_node_from_xml(browser, xml, "id", error); + if(node == NULL) + { + xmlFree(new_name); + return FALSE; + } + + request = infc_request_manager_get_request_by_xml( + priv->request_manager, + "rename-node", + xml, + NULL + ); + + if(request != NULL) + { + g_object_ref(request); + + iter.node_id = node->id; + iter.node = node; + + infc_request_manager_finish_request( + priv->request_manager, + request, + inf_request_result_make_rename_node(INF_BROWSER(browser), &iter, new_name) + ); + } + + if(request != NULL) + g_object_unref(request); + + return TRUE; +} + static gboolean infc_browser_handle_remove_node(InfcBrowser* browser, InfXmlConnection* connection, @@ -4746,6 +4795,15 @@ infc_browser_communication_object_received(InfCommunicationObject* object, &local_error ); } + else if(strcmp((const gchar*)node->name, "rename-node") == 0) + { + infc_browser_handle_rename_node( + browser, + connection, + node, + &local_error + ); + } else if(strcmp((const gchar*)node->name, "remove-node") == 0) { infc_browser_handle_remove_node( diff --git a/libinfinity/common/inf-browser.c b/libinfinity/common/inf-browser.c index 922b11f8..838d8e6a 100644 --- a/libinfinity/common/inf-browser.c +++ b/libinfinity/common/inf-browser.c @@ -864,6 +864,42 @@ inf_browser_add_subdirectory(InfBrowser* browser, return iface->add_subdirectory(browser, iter, name, acl, func, user_data); } +/** + * inf_browser_rename_node: + * @browser: A #InfBrowser. + * @iter: A #InfBrowserIter pointing to a node inside @browser. + * @func: The function to be called when the request finishes, or %NULL. + * @user_data: Additional data to pass to @func. + * + * Requests to rename the node @iter points to. + * + * The request might either finish during the call to this function, in which + * case @func will be called and %NULL being returned. If the request does not + * finish within the function call, a #InfRequest object is returned, + * where @func has been installed for the #InfRequest::finished signal, + * so that it is called as soon as the request finishes. + * + * Returns: A #InfRequest which can be used to get notified when the + * request finishes. + */ +InfRequest* +inf_browser_rename_node(InfBrowser* browser, + const InfBrowserIter* iter, + const char* new_name, + InfRequestFunc func, + gpointer user_data) +{ + InfBrowserIface* iface; + + g_return_val_if_fail(INF_IS_BROWSER(browser), NULL); + g_return_val_if_fail(iter != NULL, NULL); + + iface = INF_BROWSER_GET_IFACE(browser); + g_return_val_if_fail(iface->rename_node != NULL, NULL); + + return iface->rename_node(browser, iter, new_name, func, user_data); +} + /** * inf_browser_remove_node: * @browser: A #InfBrowser. diff --git a/libinfinity/common/inf-browser.h b/libinfinity/common/inf-browser.h index 13fa6a17..25a5e984 100644 --- a/libinfinity/common/inf-browser.h +++ b/libinfinity/common/inf-browser.h @@ -208,6 +208,11 @@ struct _InfBrowserIface { const InfAclSheetSet* acl, InfRequestFunc func, gpointer user_data); + InfRequest* (*rename_node)(InfBrowser* browser, + const InfBrowserIter* iter, + const char* new_name, + InfRequestFunc func, + gpointer user_data); InfRequest* (*remove_node)(InfBrowser* browser, const InfBrowserIter* iter, InfRequestFunc func, @@ -336,6 +341,13 @@ inf_browser_add_subdirectory(InfBrowser* browser, InfRequestFunc func, gpointer user_data); +InfRequest* +inf_browser_rename_node(InfBrowser* browser, + const InfBrowserIter* iter, + const char* new_name, + InfRequestFunc func, + gpointer user_data); + InfRequest* inf_browser_remove_node(InfBrowser* browser, const InfBrowserIter* iter, diff --git a/libinfinity/common/inf-request-result.c b/libinfinity/common/inf-request-result.c index caaace0c..41ccf0a9 100644 --- a/libinfinity/common/inf-request-result.c +++ b/libinfinity/common/inf-request-result.c @@ -208,10 +208,74 @@ inf_request_result_get_add_node(const InfRequestResult* result, if(new_node != NULL) *new_node = data->new_node; } +typedef struct _InfRequestResultRenameNode InfRequestResultRenameNode; +struct _InfRequestResultRenameNode { + InfBrowser* browser; + const InfBrowserIter* iter; + const char* new_name; +}; + +/** + * inf_request_result_make_add_node: + * @browser: A #InfBrowser. + * @iter: An iterator pointing to the node to which was renamed. + * + * Creates a new #InfRequestResult for an "rename-node" request, see + * inf_browser_rename_node(). The #InfRequestResult object is only valid + * as long as the caller maintains a reference to @browser. + * + * Returns: A new #InfRequestResult. Free with inf_request_result_free(). + */ +InfRequestResult* +inf_request_result_make_rename_node(InfBrowser* browser, + const InfBrowserIter* iter, + const char* new_name) +{ + InfRequestResultRenameNode* data; + + g_return_val_if_fail(INF_IS_BROWSER(browser), NULL); + g_return_val_if_fail(iter != NULL, NULL); + + data = g_malloc(sizeof(InfRequestResultRenameNode)); + + data->browser = browser; + data->iter = iter; + data->new_name = new_name; + + return inf_request_result_new(data, sizeof(*data)); +} + +/** + * inf_request_result_get_rename_node: + * @result: A #InfRequestResult: + * @browser: Output value of the browser that made the request, or %NULL. + * @iter: Output value for the node that has been renamed, or %NULL. + * + * Decomposes @result into its components. The object must have been created + * with inf_request_result_make_rename_node(). + */ +void +inf_request_result_get_rename_node(const InfRequestResult* result, + InfBrowser** browser, + const InfBrowserIter** iter, + const char** new_name) +{ + const InfRequestResultRenameNode* data; + + g_return_if_fail(result != NULL); + g_return_if_fail(result->len == sizeof(InfRequestResultRenameNode)); + data = (const InfRequestResultRenameNode*)result->data; + + if(browser != NULL) *browser = data->browser; + if(iter != NULL) *iter = data->iter; + if(new_name != NULL) *new_name = data->new_name; +} + typedef struct _InfRequestResultRemoveNode InfRequestResultRemoveNode; struct _InfRequestResultRemoveNode { InfBrowser* browser; const InfBrowserIter* iter; + const char* new_name; }; /** diff --git a/libinfinity/common/inf-request-result.h b/libinfinity/common/inf-request-result.h index 4bf27e1f..7d989546 100644 --- a/libinfinity/common/inf-request-result.h +++ b/libinfinity/common/inf-request-result.h @@ -58,6 +58,17 @@ inf_request_result_get_add_node(const InfRequestResult* result, const InfBrowserIter** iter, const InfBrowserIter** new_node); +InfRequestResult* +inf_request_result_make_rename_node(InfBrowser* browser, + const InfBrowserIter* iter, + const char* new_name); + +void +inf_request_result_get_rename_node(const InfRequestResult* result, + InfBrowser** browser, + const InfBrowserIter** iter, + const char** new_name); + InfRequestResult* inf_request_result_make_remove_node(InfBrowser* browser, const InfBrowserIter* iter); From 2fef75e2c469d2e7e7f352b0bec68c6d3f53353f Mon Sep 17 00:00:00 2001 From: Fluffy Date: Fri, 11 Jul 2014 21:38:40 +0000 Subject: [PATCH 2/2] Finished the rest of the rename code, except for one signal. --- libinfgtk/inf-gtk-browser-store.c | 30 +++ libinfinity/client/infc-browser.c | 84 ++++++ libinfinity/common/inf-browser.c | 53 ++++ libinfinity/common/inf-browser.h | 7 +- libinfinity/common/inf-error.c | 2 + libinfinity/common/inf-error.h | 3 + libinfinity/common/inf-file-util.c | 60 ++++- libinfinity/common/inf-file-util.h | 5 + libinfinity/common/inf-request-result.c | 8 +- libinfinity/server/infd-directory.c | 257 ++++++++++++++++++- libinfinity/server/infd-filesystem-storage.c | 83 +++++- libinfinity/server/infd-storage.c | 32 +++ libinfinity/server/infd-storage.h | 15 +- 13 files changed, 627 insertions(+), 12 deletions(-) diff --git a/libinfgtk/inf-gtk-browser-store.c b/libinfgtk/inf-gtk-browser-store.c index 645b362d..29830a5b 100644 --- a/libinfgtk/inf-gtk-browser-store.c +++ b/libinfgtk/inf-gtk-browser-store.c @@ -176,6 +176,13 @@ inf_gtk_browser_store_node_added_cb(InfBrowser* browser, InfRequest* request, gpointer user_data); +static void +inf_gtk_browser_store_node_renamed_cb(InfBrowser* browser, + InfBrowserIter* iter, + InfRequest* request, + gpointer user_data, + const gchar* new_name); + static void inf_gtk_browser_store_node_removed_cb(InfBrowser* browser, InfBrowserIter* iter, @@ -761,6 +768,16 @@ inf_gtk_browser_store_node_added_cb(InfBrowser* browser, } } +static void +inf_gtk_browser_store_node_renamed_cb(InfBrowser* browser, + InfBrowserIter* iter, + InfRequest* request, + gpointer user_data, + const gchar* new_name) +{ + /* TODO: Update the renamed node in the tree */ +} + static void inf_gtk_browser_store_node_removed_cb(InfBrowser* browser, InfBrowserIter* iter, @@ -1966,6 +1983,12 @@ inf_gtk_browser_store_browser_model_set_browser(InfGtkBrowserModel* model, model ); + inf_signal_handlers_disconnect_by_func( + G_OBJECT(item->browser), + G_CALLBACK(inf_gtk_browser_store_node_renamed_cb), + model + ); + inf_signal_handlers_disconnect_by_func( G_OBJECT(item->browser), G_CALLBACK(inf_gtk_browser_store_node_removed_cb), @@ -2026,6 +2049,13 @@ inf_gtk_browser_store_browser_model_set_browser(InfGtkBrowserModel* model, model ); + g_signal_connect_after( + G_OBJECT(item->browser), + "node-renamed", + G_CALLBACK(inf_gtk_browser_store_node_renamed_cb), + model + ); + g_signal_connect_after( G_OBJECT(item->browser), "node-removed", diff --git a/libinfinity/client/infc-browser.c b/libinfinity/client/infc-browser.c index f99701e2..68d1c3dd 100644 --- a/libinfinity/client/infc-browser.c +++ b/libinfinity/client/infc-browser.c @@ -624,6 +624,19 @@ infc_browser_session_remove_child_sessions(InfcBrowser* browser, } } +static void +infc_browser_node_rename(InfcBrowser* browser, + InfcBrowserNode* node, + InfcRequest* request, + const gchar* new_name) +{ + InfBrowserIter iter; + iter.node_id = node->id; + iter.node = node; + + inf_browser_node_renamed(INF_BROWSER(browser), &iter, INF_REQUEST(request), new_name); +} + static void infc_browser_node_register(InfcBrowser* browser, InfcBrowserNode* node, @@ -1240,6 +1253,7 @@ infc_browser_session_notify_subscription_group_cb(InfSession* session, const GParamSpec* spec, gpointer user_data) { + return; InfcBrowser* browser; InfcBrowserPrivate* priv; InfBrowserIter* iter; @@ -3520,6 +3534,8 @@ infc_browser_handle_rename_node(InfcBrowser* browser, { InfcBrowserPrivate* priv; InfcBrowserNode* node; + InfSession* session; + InfcSessionProxy* proxy; InfcRequest* request; InfBrowserIter iter; xmlChar* new_name; @@ -3534,6 +3550,15 @@ infc_browser_handle_rename_node(InfcBrowser* browser, return FALSE; } + if(node->type == INFC_BROWSER_NODE_NOTE_KNOWN && + node->shared.known.session) + { + proxy = node->shared.known.session; + g_object_get(G_OBJECT(proxy), "session", &session, NULL); + + // TODO: g_signal_emit notify::rename on session right here? + } + request = infc_request_manager_get_request_by_xml( priv->request_manager, "rename-node", @@ -3555,6 +3580,11 @@ infc_browser_handle_rename_node(InfcBrowser* browser, ); } + /* Apply new name to node */ + free(node->name); + node->name = g_strdup(new_name); + free(new_name); + if(request != NULL) g_object_unref(request); @@ -5673,6 +5703,59 @@ infc_browser_browser_add_subdirectory(InfBrowser* infbrowser, return INF_REQUEST(request); } +static InfRequest* +infc_browser_browser_rename_node(InfBrowser* infbrowser, + const InfBrowserIter* iter, + const char* new_name, + InfRequestFunc func, + gpointer user_data) +{ + InfcBrowser* browser; + InfcBrowserPrivate* priv; + InfcBrowserNode* node; + InfcRequest* request; + xmlNodePtr xml; + + g_return_val_if_fail(INFC_IS_BROWSER(infbrowser), NULL); + browser = INFC_BROWSER(infbrowser); + infc_browser_return_val_if_iter_fail(browser, iter, NULL); + + priv = INFC_BROWSER_PRIVATE(browser); + node = (InfcBrowserNode*)iter->node; + + /* The root node cannot be renamed */ + g_return_val_if_fail(node->parent != NULL, NULL); + + /* TODO: Check that there is not a rename-node request already enqueued. */ + + g_return_val_if_fail(priv->connection != NULL, NULL); + g_return_val_if_fail(priv->status == INF_BROWSER_OPEN, NULL); + + request = infc_request_manager_add_request( + priv->request_manager, + INFC_TYPE_REQUEST, + "rename-node", + G_CALLBACK(func), + user_data, + "node-id", iter->node_id, + NULL + ); + + inf_browser_begin_request(INF_BROWSER(browser), iter, INF_REQUEST(request)); + + xml = infc_browser_request_to_xml(request); + inf_xml_util_set_attribute_uint(xml, "id", node->id); + inf_xml_util_set_attribute(xml, "new_name", new_name); + + inf_communication_group_send_message( + INF_COMMUNICATION_GROUP(priv->group), + priv->connection, + xml + ); + + return INF_REQUEST(request); +} + static InfRequest* infc_browser_browser_remove_node(InfBrowser* infbrowser, const InfBrowserIter* iter, @@ -6380,6 +6463,7 @@ infc_browser_browser_init(gpointer g_iface, iface->is_subdirectory = infc_browser_browser_is_subdirectory; iface->add_note = infc_browser_browser_add_note; iface->add_subdirectory = infc_browser_browser_add_subdirectory; + iface->rename_node = infc_browser_browser_rename_node; iface->remove_node = infc_browser_browser_remove_node; iface->get_node_name = infc_browser_browser_get_node_name; iface->get_node_type = infc_browser_browser_get_node_type; diff --git a/libinfinity/common/inf-browser.c b/libinfinity/common/inf-browser.c index 838d8e6a..40869d28 100644 --- a/libinfinity/common/inf-browser.c +++ b/libinfinity/common/inf-browser.c @@ -42,6 +42,7 @@ enum { ERROR_, NODE_ADDED, + NODE_RENAMED, NODE_REMOVED, SUBSCRIBE_SESSION, UNSUBSCRIBE_SESSION, @@ -131,6 +132,29 @@ inf_browser_base_init(gpointer g_class) INF_TYPE_REQUEST ); + /** + * InfBrowser::node-renamed: + * @browser: The #InfBrowser object emitting the signal. + * @iter: An iterator pointing to the node being renamed. + * @request: The request that lead to the node being renamed, or %NULL. + * + * This signal is emitted just before a node is being renamed. + * The iterator is still valid and can be used to access the + * node which will be renamed. + */ + browser_signals[NODE_RENAMED] = g_signal_new( + "node-renamed", + INF_TYPE_BROWSER, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET(InfBrowserIface, node_renamed), + NULL, NULL, + inf_marshal_VOID__BOXED_OBJECT, + G_TYPE_NONE, + 2, + INF_TYPE_BROWSER_ITER | G_SIGNAL_TYPE_STATIC_SCOPE, + INF_TYPE_REQUEST + ); + /** * InfBrowser::node-removed: * @browser: The #InfBrowser object emitting the signal. @@ -1689,6 +1713,35 @@ inf_browser_node_added(InfBrowser* browser, ); } +/** + * inf_browser_node_renamed: + * @browser: A #InfBrowser. + * @iter: A #InfBrowserIter pointing to the node to be renamed. + * @request: The #InfRequest that was used to rename the node, or %NULL. + * + * This function emits the #InfBrowser::node-renamed signal on @browser. It + * is meant to be used by interface implementations only. + */ +void +inf_browser_node_renamed(InfBrowser* browser, + const InfBrowserIter* iter, + InfRequest* request, + const gchar* new_name) +{ + g_return_if_fail(INF_IS_BROWSER(browser)); + g_return_if_fail(iter != NULL); + g_return_if_fail(request == NULL || INF_IS_REQUEST(request)); + + g_signal_emit( + browser, + browser_signals[NODE_RENAMED], + 0, + iter, + request, + new_name + ); +} + /** * inf_browser_node_removed: * @browser: A #InfBrowser. diff --git a/libinfinity/common/inf-browser.h b/libinfinity/common/inf-browser.h index 25a5e984..c1e819e0 100644 --- a/libinfinity/common/inf-browser.h +++ b/libinfinity/common/inf-browser.h @@ -137,6 +137,11 @@ struct _InfBrowserIface { const InfBrowserIter* iter, InfRequest* request); + void (*node_renamed)(InfBrowser* browser, + const InfBrowserIter* iter, + InfRequest* request, + const gchar* new_name); + void (*node_removed)(InfBrowser* browser, const InfBrowserIter* iter, InfRequest* request); @@ -344,7 +349,7 @@ inf_browser_add_subdirectory(InfBrowser* browser, InfRequest* inf_browser_rename_node(InfBrowser* browser, const InfBrowserIter* iter, - const char* new_name, + const char* new_name, InfRequestFunc func, gpointer user_data); diff --git a/libinfinity/common/inf-error.c b/libinfinity/common/inf-error.c index 2aa02abe..840892d7 100644 --- a/libinfinity/common/inf-error.c +++ b/libinfinity/common/inf-error.c @@ -180,6 +180,8 @@ inf_directory_strerror(InfDirectoryError code) return _("Node is not a note"); case INF_DIRECTORY_ERROR_NOTE_TYPE_UNSUPPORTED: return _("The node type is not supported by the server"); + case INF_DIRECTORY_ERROR_ROOT_NODE_RENAME_ATTEMPT: + return _("The root node cannot be renamed"); case INF_DIRECTORY_ERROR_ROOT_NODE_REMOVE_ATTEMPT: return _("The root node cannot be removed"); case INF_DIRECTORY_ERROR_ALREADY_EXPLORED: diff --git a/libinfinity/common/inf-error.h b/libinfinity/common/inf-error.h index 816b1742..02d3f7b7 100644 --- a/libinfinity/common/inf-error.h +++ b/libinfinity/common/inf-error.h @@ -117,6 +117,8 @@ typedef enum _InfUserError { * a note (non-subdirectory) node, but the requested operations requires one. * @INF_DIRECTORY_ERROR_NOTE_TYPE_UNSUPPORTED: The node type is not supported * by the server. + * @INF_DIRECTORY_ERROR_ROOT_NODE_RENAME_ATTEMPT: A <rename-node> + * request attempted to rename a directory's root node, which is not allowed. * @INF_DIRECTORY_ERROR_ROOT_NODE_REMOVE_ATTEMPT: A <remove-node> * request attempted to remove a directory's root node, which is not allowed. * @INF_DIRECTORY_ERROR_ALREADY_EXPLORED: The node given in an exploration @@ -183,6 +185,7 @@ typedef enum _InfDirectoryError { INF_DIRECTORY_ERROR_NOT_A_SUBDIRECTORY, INF_DIRECTORY_ERROR_NOT_A_NOTE, INF_DIRECTORY_ERROR_NOTE_TYPE_UNSUPPORTED, + INF_DIRECTORY_ERROR_ROOT_NODE_RENAME_ATTEMPT, INF_DIRECTORY_ERROR_ROOT_NODE_REMOVE_ATTEMPT, INF_DIRECTORY_ERROR_ALREADY_EXPLORED, INF_DIRECTORY_ERROR_NOT_INITIATED, diff --git a/libinfinity/common/inf-file-util.c b/libinfinity/common/inf-file-util.c index a52a0218..ea9d27b7 100644 --- a/libinfinity/common/inf-file-util.c +++ b/libinfinity/common/inf-file-util.c @@ -212,10 +212,7 @@ inf_file_util_create_directory(const gchar* path, result = inf_file_util_create_directory(dirname, mode, error); g_free(dirname); - if(result == FALSE) - return FALSE; - - return inf_file_util_create_single_directory(path, mode, error); + return result && inf_file_util_create_single_directory(path, mode, error); } /** @@ -512,4 +509,59 @@ inf_file_util_delete(const gchar* path, return inf_file_util_delete_file(path, error); } +/** + * inf_file_util_rename: + * @old_path: Path to the object to rename. + * @new_path: Path which the object should be renamed to. + * @error: Location to store error information, if any, or %NULL. + * + * Renames the file or directory at @path. If the function fails + * %FALSE is returned and @error is set. + * + * Returns: %TRUE on success or %FALSE on error. + */ +gboolean +inf_file_util_rename(const gchar* old_path, + const gchar* new_path, + GError** error) +{ +#ifdef G_OS_WIN32 + gunichar2 *old_path16, *new_path16; + int code; + + old_path16 = g_utf8_to_utf16(old_path, -1, NULL, NULL, error); + if(!old_path16) return FALSE; + new_path16 = g_utf8_to_utf16(new_path, -1, NULL, NULL, error); + if(!new_path16) + { + g_free(old_path16); + return FALSE; + } + + if(!MoveFile(old_path16, new_path16)) + { + g_free(old_path16); + g_free(new_path16); + code = GetLastError(); + inf_file_util_set_error_from_win32(error, code); + return FALSE; + } + + g_free(old_path16); + g_free(new_path16); + return TRUE; +#else + int code; + + if(g_rename(old_path, new_path) == -1) + { + code = errno; + inf_file_util_set_error_from_errno(error, code); + return FALSE; + } + + return TRUE; +#endif +} + /* vim:set et sw=2 ts=2: */ diff --git a/libinfinity/common/inf-file-util.h b/libinfinity/common/inf-file-util.h index 154aefdf..d7bcf686 100644 --- a/libinfinity/common/inf-file-util.h +++ b/libinfinity/common/inf-file-util.h @@ -92,6 +92,11 @@ gboolean inf_file_util_delete(const gchar* path, GError** error); +gboolean +inf_file_util_rename(const gchar* old_path, + const gchar* new_path, + GError** error); + G_END_DECLS #endif /* __INF_FILE_UTIL_H__ */ diff --git a/libinfinity/common/inf-request-result.c b/libinfinity/common/inf-request-result.c index 41ccf0a9..ee25d868 100644 --- a/libinfinity/common/inf-request-result.c +++ b/libinfinity/common/inf-request-result.c @@ -212,7 +212,7 @@ typedef struct _InfRequestResultRenameNode InfRequestResultRenameNode; struct _InfRequestResultRenameNode { InfBrowser* browser; const InfBrowserIter* iter; - const char* new_name; + const gchar* new_name; }; /** @@ -229,7 +229,7 @@ struct _InfRequestResultRenameNode { InfRequestResult* inf_request_result_make_rename_node(InfBrowser* browser, const InfBrowserIter* iter, - const char* new_name) + const gchar* new_name) { InfRequestResultRenameNode* data; @@ -250,6 +250,7 @@ inf_request_result_make_rename_node(InfBrowser* browser, * @result: A #InfRequestResult: * @browser: Output value of the browser that made the request, or %NULL. * @iter: Output value for the node that has been renamed, or %NULL. + * @new_name: Output value for the name of the node that has been renamed, or %NULL. * * Decomposes @result into its components. The object must have been created * with inf_request_result_make_rename_node(). @@ -258,7 +259,7 @@ void inf_request_result_get_rename_node(const InfRequestResult* result, InfBrowser** browser, const InfBrowserIter** iter, - const char** new_name) + const gchar** new_name) { const InfRequestResultRenameNode* data; @@ -275,7 +276,6 @@ typedef struct _InfRequestResultRemoveNode InfRequestResultRemoveNode; struct _InfRequestResultRemoveNode { InfBrowser* browser; const InfBrowserIter* iter; - const char* new_name; }; /** diff --git a/libinfinity/server/infd-directory.c b/libinfinity/server/infd-directory.c index 70bd832b..5f7afb09 100644 --- a/libinfinity/server/infd-directory.c +++ b/libinfinity/server/infd-directory.c @@ -2904,6 +2904,22 @@ infd_directory_node_unregister_to_xml(InfdDirectoryNode* node) return xml; } +/* Creates XML request to tell someone about a renamed node */ +static xmlNodePtr +infd_directory_node_rename_to_xml(InfdDirectoryNode* node, const gchar* new_name) +{ + xmlNodePtr xml; + gchar id_buf[16]; + + sprintf(id_buf, "%u", node->id); + + xml = xmlNewNode(NULL, (const xmlChar*)"rename-node"); + xmlNewProp(xml, (const xmlChar*)"id", (const xmlChar*)id_buf); + xmlNewProp(xml, (const xmlChar*)"new_name", (const xmlChar*)new_name); + + return xml; +} + static gboolean infd_directory_make_seq(InfdDirectory* directory, InfXmlConnection* connection, @@ -4331,6 +4347,114 @@ infd_directory_node_add_sync_in(InfdDirectory* directory, return TRUE; } +static gboolean +infd_directory_node_rename(InfdDirectory* directory, + InfdDirectoryNode* node, + InfdRequest* request, + const gchar* seq, + const xmlChar* new_name, + GError** error) +{ + InfdDirectoryPrivate* priv; + gchar* path; + InfBrowserIter iter; + GError* local_error; + const gchar* note_type; + gchar* converted_name; + gchar* temp_name; + xmlNodePtr xml; + GSList* item; + + priv = INFD_DIRECTORY_PRIVATE(directory); + + /* Cannot rename the root node */ + /* TODO: Move the error check here so we have same error checking for + * local and remote requests. */ + g_assert(node->parent != NULL); + g_assert(request != NULL); + + local_error = NULL; + if(priv->storage != NULL) + { + infd_directory_node_get_path(node, &path, NULL); + + switch(node->type) + { + case INFD_DIRECTORY_NODE_SUBDIRECTORY: + note_type = NULL; + break; + case INFD_DIRECTORY_NODE_NOTE: + note_type = node->shared.note.plugin->note_type; + break; + case INFD_DIRECTORY_NODE_UNKNOWN: + note_type = g_quark_to_string(node->shared.unknown.type); + break; + default: + g_assert_not_reached(); + break; + } + + infd_directory_node_make_path(node->parent, new_name, &converted_name, NULL); + + infd_storage_rename_node( + priv->storage, + note_type, + path, + converted_name, + &local_error + ); + + g_free(path); + g_free(converted_name); + } + + iter.node_id = node->id; + iter.node = node; + + if(local_error != NULL) + { + inf_request_fail(INF_REQUEST(request), local_error); + g_propagate_error(error, local_error); + return FALSE; + } + else + { + /* Apply new name to the node */ + temp_name = node->name; + node->name = g_strdup(new_name); + g_free(temp_name); + + inf_request_finish( + INF_REQUEST(request), + inf_request_result_make_rename_node(INF_BROWSER(directory), &iter, new_name) + ); + + inf_browser_node_renamed( + INF_BROWSER(directory), + &iter, + INF_REQUEST(request) + ); + + xml = infd_directory_node_rename_to_xml(node, new_name); + if(seq != NULL) inf_xml_util_set_attribute(xml, "seq", seq); + + for(item = node->parent->shared.subdir.connections; + item != NULL; + item = g_slist_next(item)) + { + inf_communication_group_send_message( + INF_COMMUNICATION_GROUP(priv->group), + INF_XML_CONNECTION(item->data), + xmlCopyNode(xml, 1) + ); + } + } + + xmlFreeNode(xml); + + return TRUE; +} + static gboolean infd_directory_node_remove(InfdDirectory* directory, InfdDirectoryNode* node, @@ -4379,7 +4503,7 @@ infd_directory_node_remove(InfdDirectory* directory, path, &local_error ); - + g_free(path); } @@ -5127,6 +5251,82 @@ infd_directory_handle_add_node(InfdDirectory* directory, return node_added; } +static gboolean +infd_directory_handle_rename_node(InfdDirectory* directory, + InfXmlConnection* connection, + const xmlNodePtr xml, + GError** error) +{ + InfdDirectoryNode* node; + gchar* seq; + InfdRequest* request; + InfBrowserIter iter; + xmlChar* new_name; + gboolean result; + + InfdDirectoryNode* up; + InfAclMask perms; + + if((new_name = inf_xml_util_get_attribute_required(xml, "new_name", error)) == NULL) return FALSE; + + node = infd_directory_get_node_from_xml(directory, xml, "id", error); + if(node == NULL) + { + g_free(new_name); + return FALSE; + } + + if(node->parent == NULL) + { + g_set_error( + error, + inf_directory_error_quark(), + INF_DIRECTORY_ERROR_ROOT_NODE_RENAME_ATTEMPT, + "%s", + _("The root node cannot be renamed") + ); + + g_free(new_name); + return FALSE; + } + else + { + /* Check the remove node permission on the parent node (which means rename node permissions) */ + up = node->parent; + inf_acl_mask_set1(&perms, INF_ACL_CAN_REMOVE_NODE); + if(!infd_directory_check_auth(directory, up, connection, &perms, error) || + !infd_directory_make_seq(directory, connection, xml, &seq, error)) + { + g_free(new_name); + return FALSE; + } + + request = INFD_REQUEST( + g_object_new( + INFD_TYPE_REQUEST, + "type", "rename-node", + "node-id", node->id, + "requestor", connection, + NULL + ) + ); + + iter.node_id = node->id; + iter.node = node; + inf_browser_begin_request( + INF_BROWSER(directory), + &iter, + INF_REQUEST(request) + ); + + result = infd_directory_node_rename(directory, node, request, seq, new_name, error); + g_object_unref(request); + g_free(new_name); + + return result; + } +} + static gboolean infd_directory_handle_remove_node(InfdDirectory* directory, InfXmlConnection* connection, @@ -7374,6 +7574,15 @@ infd_directory_communication_object_received(InfCommunicationObject* object, &local_error ); } + else if(strcmp((const char*)node->name, "rename-node") == 0) + { + infd_directory_handle_rename_node( + directory, + connection, + node, + &local_error + ); + } else if(strcmp((const char*)node->name, "remove-node") == 0) { infd_directory_handle_remove_node( @@ -7945,6 +8154,51 @@ infd_directory_browser_add_subdirectory(InfBrowser* browser, return NULL; } +static InfRequest* +infd_directory_browser_rename_node(InfBrowser* browser, + const InfBrowserIter* iter, + const gchar* new_name, + InfRequestFunc func, + gpointer user_data) +{ + InfdDirectory* directory; + InfdDirectoryPrivate* priv; + InfdDirectoryNode* node; + InfdRequest* request; + + directory = INFD_DIRECTORY(browser); + priv = INFD_DIRECTORY_PRIVATE(directory); + + infd_directory_return_val_if_iter_fail(directory, iter, NULL); + + node = (InfdDirectoryNode*)iter->node; + + request = g_object_new( + INFD_TYPE_REQUEST, + "type", "remove-node", + "node-id", node->id, + "requestor", NULL, + NULL + ); + + if(func != NULL) + { + g_signal_connect_after( + G_OBJECT(request), + "finished", + G_CALLBACK(func), + user_data + ); + } + + inf_browser_begin_request(browser, iter, INF_REQUEST(request)); + + infd_directory_node_rename(directory, node, request, NULL, new_name, NULL); + + g_object_unref(request); + return NULL; +} + static InfRequest* infd_directory_browser_remove_node(InfBrowser* browser, const InfBrowserIter* iter, @@ -8805,6 +9059,7 @@ infd_directory_browser_init(gpointer g_iface, iface->is_subdirectory = infd_directory_browser_is_subdirectory; iface->add_note = infd_directory_browser_add_note; iface->add_subdirectory = infd_directory_browser_add_subdirectory; + iface->rename_node = infd_directory_browser_rename_node; iface->remove_node = infd_directory_browser_remove_node; iface->get_node_name = infd_directory_browser_get_node_name; iface->get_node_type = infd_directory_browser_get_node_type; diff --git a/libinfinity/server/infd-filesystem-storage.c b/libinfinity/server/infd-filesystem-storage.c index 9d488253..4b0b27f1 100644 --- a/libinfinity/server/infd-filesystem-storage.c +++ b/libinfinity/server/infd-filesystem-storage.c @@ -510,6 +510,85 @@ infd_filesystem_storage_storage_create_subdirectory(InfdStorage* storage, return result; } +static gboolean +infd_filesystem_storage_storage_rename_node(InfdStorage* storage, + const gchar* identifier, + const gchar* old_path, + const gchar* new_path, + GError** error) +{ + InfdFilesystemStorage *fs_storage; + InfdFilesystemStoragePrivate *priv; + gchar *old_converted_name, *new_converted_name, + *old_disk_name, *new_disk_name, + *old_full_name, *new_full_name; + gboolean result; + int save_errno; + + fs_storage = INFD_FILESYSTEM_STORAGE(storage); + priv = INFD_FILESYSTEM_STORAGE_PRIVATE(fs_storage); + + if(!infd_filesystem_storage_verify_path(new_path, error)) + return FALSE; + + old_converted_name = g_filename_from_utf8(old_path, -1, NULL, NULL, error); + if(!old_converted_name) return FALSE; + new_converted_name = g_filename_from_utf8(new_path, -1, NULL, NULL, error); + if(!new_converted_name) + { + g_free(old_converted_name); + return FALSE; + } + + if(identifier != NULL) + { + old_disk_name = g_strconcat(old_converted_name, ".", identifier, NULL); + new_disk_name = g_strconcat(new_converted_name, ".", identifier, NULL); + } + else + { + old_disk_name = old_converted_name; + new_disk_name = new_converted_name; + } + + old_full_name = g_build_filename(priv->root_directory, old_disk_name, NULL); + new_full_name = g_build_filename(priv->root_directory, new_disk_name, NULL); + if(old_disk_name != old_converted_name) g_free(old_disk_name); + if(new_disk_name != new_converted_name) g_free(new_disk_name); + + result = inf_file_util_rename(old_full_name, new_full_name, error); + g_free(old_full_name); + g_free(new_full_name); + + if(result == TRUE) + { + old_disk_name = g_strconcat(old_converted_name, ".xml.acl", NULL); + new_disk_name = g_strconcat(new_converted_name, ".xml.acl", NULL); + old_full_name = g_build_filename(priv->root_directory, old_disk_name, NULL); + new_full_name = g_build_filename(priv->root_directory, new_disk_name, NULL); + g_free(old_disk_name); + g_free(new_disk_name); + + if(g_rename(old_full_name, new_full_name) == -1) + { + save_errno = errno; + if(save_errno != ENOENT) + { + infd_filesystem_storage_system_error(save_errno, error); + result = FALSE; + } + } + + g_free(old_full_name); + g_free(new_full_name); + } + + g_free(old_converted_name); + g_free(new_converted_name); + + return result; +} + static gboolean infd_filesystem_storage_storage_remove_node(InfdStorage* storage, const gchar* identifier, @@ -798,7 +877,7 @@ infd_filesystem_storage_storage_read_acl(InfdStorage* storage, acl = g_slice_new(InfdStorageAcl); acl->account_id = g_strdup((const gchar*)account_id); xmlFree(account_id); - + if(!inf_acl_sheet_perms_from_xml(child, &acl->mask, &acl->perms, error)) { g_free(acl->account_id); @@ -983,6 +1062,8 @@ infd_filesystem_storage_storage_init(gpointer g_iface, infd_filesystem_storage_storage_read_subdirectory; iface->create_subdirectory = infd_filesystem_storage_storage_create_subdirectory; + iface->rename_node = + infd_filesystem_storage_storage_rename_node; iface->remove_node = infd_filesystem_storage_storage_remove_node; diff --git a/libinfinity/server/infd-storage.c b/libinfinity/server/infd-storage.c index c8ca830a..a9a21853 100644 --- a/libinfinity/server/infd-storage.c +++ b/libinfinity/server/infd-storage.c @@ -359,6 +359,38 @@ infd_storage_create_subdirectory(InfdStorage* storage, return iface->create_subdirectory(storage, path, error); } +/** + * infd_storage_rename_node: + * @storage: A #InfdStorage + * @identifier: The type of the node to rename, or %NULL to rename a + * subdirectory (TODO: This shouldn't be necessary). + * @path: A path pointing to an existing node. + * @error: Location to store error information. + * @new_name: The name which to rename the node to. + * + * Renames the node at path. + * + * Returns: %TRUE on success. + **/ +gboolean +infd_storage_rename_node(InfdStorage* storage, + const gchar* identifier, + const gchar* old_name, + const gchar* new_name, + GError** error) +{ + InfdStorageIface* iface; + + g_return_val_if_fail(INFD_IS_STORAGE(storage), FALSE); + g_return_val_if_fail(old_name != NULL, FALSE); + g_return_val_if_fail(new_name != NULL, FALSE); + + iface = INFD_STORAGE_GET_IFACE(storage); + g_return_val_if_fail(iface->rename_node != NULL, FALSE); + + return iface->rename_node(storage, identifier, old_name, new_name, error); +} + /** * infd_storage_remove_node: * @storage: A #InfdStorage diff --git a/libinfinity/server/infd-storage.h b/libinfinity/server/infd-storage.h index 6faf5193..32255de9 100644 --- a/libinfinity/server/infd-storage.h +++ b/libinfinity/server/infd-storage.h @@ -56,7 +56,7 @@ typedef struct _InfdStorageAcl InfdStorageAcl; struct _InfdStorageAcl { gchar* account_id; InfAclMask mask; - InfAclMask perms; + InfAclMask perms; }; struct _InfdStorageIface { @@ -76,6 +76,12 @@ struct _InfdStorageIface { const gchar* path, GError** error); + gboolean (*rename_node)(InfdStorage* storage, + const gchar* identifier, + const gchar* old_name, + const gchar* new_name, + GError** error); + /* TODO: Remove the identifier here */ gboolean (*remove_node)(InfdStorage* storage, const gchar* identifier, @@ -152,6 +158,13 @@ infd_storage_create_subdirectory(InfdStorage* storage, const gchar* path, GError** error); +gboolean +infd_storage_rename_node(InfdStorage* storage, + const gchar* identifier, + const gchar* old_name, + const gchar* new_name, + GError** error); + gboolean infd_storage_remove_node(InfdStorage* storage, const gchar* identifier,