implement rename

Tue, 26 Nov 2024 11:38:10 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Tue, 26 Nov 2024 11:38:10 +0100
changeset 89
2fbb3cac05a5
parent 88
e27526429d85
child 90
f501f0efc9a8

implement rename

application/application.c file | annotate | diff | comparison | revisions
application/application.h file | annotate | diff | comparison | revisions
application/davcontroller.c file | annotate | diff | comparison | revisions
application/davcontroller.h file | annotate | diff | comparison | revisions
application/window.c file | annotate | diff | comparison | revisions
--- a/application/application.c	Tue Nov 26 10:40:45 2024 +0100
+++ b/application/application.c	Tue Nov 26 11:38:10 2024 +0100
@@ -315,6 +315,16 @@
     }
 }
 
+void action_rename(UiEvent *event, void *data) {
+    DavBrowser *browser = event->document;
+    UiListSelection sel = ui_list_getselection(browser->resources);
+    if (sel.count == 1) {
+        davbrowser_rename(event->obj, browser, sel);
+    } else if(sel.count > 1) {
+        fprintf(stderr, "Renaming multiple resources is not implemented yet\n");
+    }
+}
+
 static void newfiledialog_result(UiEvent *event, void *data) {
     DavBrowser *browser = event->document;
     char *path = event->eventdata;
--- a/application/application.h	Tue Nov 26 10:40:45 2024 +0100
+++ b/application/application.h	Tue Nov 26 11:38:10 2024 +0100
@@ -186,6 +186,8 @@
 
 void action_selectall(UiEvent *event, void *data);
 
+void action_rename(UiEvent *event, void *data);
+
 void action_newfile(UiEvent *event, void *data);
 
 void action_mkcol(UiEvent *event, void *data);
--- a/application/davcontroller.c	Tue Nov 26 10:40:45 2024 +0100
+++ b/application/davcontroller.c	Tue Nov 26 11:38:10 2024 +0100
@@ -517,6 +517,26 @@
     char *result_contenttype;
 } DavPathOpResult;
 
+typedef struct DavRenameOp {
+    UiObject *ui;
+    DavBrowser *browser;
+    
+    // clone of the browser's DavSession
+    DavSession *sn;
+    char *path;
+    char *newname;
+    int result;
+    char *errormsg;
+    
+    // browser->resources index
+    size_t index;
+    
+    // browser->current ptr when the PathOp started
+    // used in combination with collection_ctn to check if the browser list changed
+    DavResource *collection;
+    int64_t collection_ctn;
+} DavRenameOp;
+
 static int uithr_pathop_delete_error(void *data) {
     DavPathOpResult *result = data;
 
@@ -693,6 +713,149 @@
 
 
 
+
+static int jobthr_rename(void *data) {
+    DavRenameOp *op = data;
+    
+    DavResource *res = dav_get(op->sn, op->path, NULL);
+    if(!res) {
+        fprintf(stderr, "Error: Cannot get resource %s\n", op->path);
+        op->result = 1;
+        return 0;
+    }
+    
+    char *cryptoname = dav_get_string_property_ns(res, DAV_NS, "crypto-name");
+    char *cryptokey = dav_get_string_property_ns(res, DAV_NS, "crypto-key");
+    if(cryptoname && cryptokey) {
+        // encrypted resource, the name is stored in the crypto-name property
+        // these properties are only loaded if encryption is enabled for
+        // this session
+        DavKey *key = dav_context_get_key(op->sn->context, cryptokey);
+        if(!key) {
+            cxmutstr error = cx_asprintf_a(op->sn->mp->allocator, "Cannot rename resource: crypto key %s not found.", cryptokey);
+            op->errormsg = error.ptr;
+            op->result = 1;
+            return 0;
+        }
+        
+        // check if a resource with this name already exists
+        char *parent = util_parent_path(res->path);
+        char *newpath = util_concat_path(parent, op->newname);
+        DavResource *testres = dav_resource_new(op->sn, newpath);
+        if(dav_exists(testres)) {
+            cxmutstr error = cx_asprintf_a(op->sn->mp->allocator, "A resource with the name %s already exists.", op->newname);
+            op->errormsg = error.ptr;
+            op->result = 1;
+        } else {
+            char *crname = aes_encrypt(op->newname, strlen(op->newname), key);
+            dav_set_string_property_ns(res, DAV_NS, "crypto-name", crname);
+            free(crname);
+            if(dav_store(res)) {
+                op->result = 1;
+            }
+        }
+        free(parent);
+        free(newpath);
+    } else {
+        // rename the resource by changing the url mapping with MOVE  
+        char *parent = util_parent_path(res->href);
+        char *new_href = util_concat_path(parent, op->newname);
+        char *dest = util_get_url(op->sn, new_href);
+        free(parent);
+        free(new_href);
+        if(dav_moveto(res, dest, false)) {
+            op->result = 1;
+        }
+        free(dest);
+    }
+    
+    if(op->result && !op->errormsg) {
+        cxmutstr error = cx_asprintf_a(op->sn->mp->allocator, "Error: %d", op->sn->error);
+        op->errormsg = error.ptr;
+    }
+    
+    return 0;
+}
+
+static void uithr_rename_finished(UiEvent *event, void *data) {
+    DavRenameOp *op = data;
+    
+    if(!op->result) {
+        // update name in the browser list
+        if (op->browser->current == op->collection && op->browser->res_counter == op->collection_ctn) {
+            DavResource *res = ui_list_get(op->browser->resources, op->index);
+            
+            char *parent = util_parent_path(res->path);
+            char *newpath = util_concat_path(parent, op->newname);
+            dav_session_free(res->session, res->path);
+            dav_session_free(res->session, res->name);
+            res->path = dav_session_strdup(res->session, newpath);
+            res->name = dav_session_strdup(res->session, op->newname);
+            op->browser->resources->update(op->browser->resources, 0);
+            free(parent);
+            free(newpath);
+        }
+    } else {
+        // error
+        ui_dialog(op->ui, .title = "Error", .content = op->errormsg, .closebutton_label = "OK");
+    }
+    dav_session_destroy(op->sn);
+}
+
+static void action_resource_rename(UiEvent *event, void *data) {
+    DavRenameOp *op = data;
+    if(event->intval == 1) {
+        char *newname = event->eventdata;
+        if(!newname || strlen(newname) == 0) {
+            ui_dialog(op->ui, .title = "Error", .content = "No name specified", .closebutton_label = "OK");
+            dav_session_destroy(op->sn);
+            return;
+        }
+        
+        char *s = strchr(newname, '/');
+        if(s) {
+            ui_dialog(op->ui, .title = "Error", .content = "Character '/' is not allowed", .closebutton_label = "OK");
+            dav_session_destroy(op->sn);
+            return;
+        }
+        
+        op->newname = dav_session_strdup(op->sn, newname);
+        
+        ui_job(op->ui, jobthr_rename, op, uithr_rename_finished, op);
+        return;
+    }
+    dav_session_destroy(op->sn);
+}
+
+void davbrowser_rename(UiObject *ui, DavBrowser *browser, UiListSelection selection) {
+    DavSession *sn = dav_session_clone(browser->sn);
+    
+    DavResource *res = ui_list_get(browser->resources, selection.rows[0]);
+    
+    DavRenameOp *rename = dav_session_malloc(sn, sizeof(DavRenameOp));
+    memset(rename, 0, sizeof(DavRenameOp));
+    rename->browser = browser;
+    rename->ui = ui;
+    rename->sn = sn;
+    rename->path = dav_session_strdup(sn, res->path);
+    rename->index = selection.rows[0];
+    
+    rename->collection = browser->current;
+    rename->collection_ctn = browser->res_counter;
+    
+    ui_dialog(ui,
+            .title = "Rename",
+            .content = res->name,
+            .input = TRUE,
+            .input_value = res->name,
+            .result = action_resource_rename,
+            .resultdata = rename,
+            .button1_label = "Rename",
+            .closebutton_label = "Cancel");
+}
+
+
+
 DavResourceViewer* dav_resourceviewer_create(DavSession *sn, const char *path, DavResourceViewType type) {
     DavResourceViewer *doc = ui_document_new(sizeof(DavResourceViewer));
     UiContext *ctx = ui_document_context(doc);
--- a/application/davcontroller.h	Tue Nov 26 10:40:45 2024 +0100
+++ b/application/davcontroller.h	Tue Nov 26 11:38:10 2024 +0100
@@ -85,6 +85,8 @@
 void davbrowser_mkcol(UiObject *ui, DavBrowser *browser, const char *name);
 void davbrowser_newfile(UiObject *ui, DavBrowser *browser, const char *name);
 
+void davbrowser_rename(UiObject *ui, DavBrowser *browser, UiListSelection selection);
+
 
 DavResourceViewer* dav_resourceviewer_create(DavSession *sn, const char *path, DavResourceViewType type);
 
--- a/application/window.c	Tue Nov 26 10:40:45 2024 +0100
+++ b/application/window.c	Tue Nov 26 11:38:10 2024 +0100
@@ -60,7 +60,7 @@
         ui_menuitem(.label = "Delete", .onclick = action_delete, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
         ui_menuitem(.label = "Select All", .onclick = action_selectall, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION));
         ui_menuseparator();
-        ui_menuitem(.label = "Rename", .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION, APP_STATE_BROWSER_SELECTION));
+        ui_menuitem(.label = "Rename", .onclick = action_rename, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION, APP_STATE_BROWSER_SELECTION));
         ui_menuseparator();
         ui_menuitem("Open Properties", .onclick = action_open_properties, .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION, APP_STATE_BROWSER_SELECTION));
         ui_menuitem("Open as Text File", .onclick = action_open_properties, .onclickdata = "text/plain", .groups = UI_GROUPS(APP_STATE_BROWSER_SESSION, APP_STATE_BROWSER_SELECTION));

mercurial