# HG changeset patch # User Olaf Wintermann # Date 1730125258 -3600 # Node ID 48f43130b4a25a72d78e568a4c14a8c67465eb18 # Parent 98d0e2516f4e87cae7d51d38b370ca1114dce728 implement UI for credentials settings diff -r 98d0e2516f4e -r 48f43130b4a2 application/config.c --- a/application/config.c Mon Oct 28 07:37:45 2024 +0100 +++ b/application/config.c Mon Oct 28 15:20:58 2024 +0100 @@ -265,6 +265,13 @@ return pstore; } +void set_pwdstore(PwdStore *newstore) { + if(pstore) { + // TODO: free + } + pstore = newstore; +} + int pwdstore_save(PwdStore *pwdstore) { if(check_config_dir()) { return 1; diff -r 98d0e2516f4e -r 48f43130b4a2 application/config.h --- a/application/config.h Mon Oct 28 07:37:45 2024 +0100 +++ b/application/config.h Mon Oct 28 15:20:58 2024 +0100 @@ -62,6 +62,7 @@ cxmutstr load_key_file(const char *filename); PwdStore* get_pwdstore(void); +void set_pwdstore(PwdStore *newstore); int pwdstore_save(PwdStore *pwdstore); diff -r 98d0e2516f4e -r 48f43130b4a2 application/settings.c --- a/application/settings.c Mon Oct 28 07:37:45 2024 +0100 +++ b/application/settings.c Mon Oct 28 15:20:58 2024 +0100 @@ -29,12 +29,16 @@ #include "settings.h" #include +#include +#include #include + #define SETTINGS_STATE_REPOLIST_SELECTED 1 - #define SETTINGS_STATE_REPO_ENCRYPTION 20 +#define SETTINGS_STATE_CREDENTIALS_SELECTED 30 +#define SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED 31 static void repolist_activate(UiEvent *event, void *userdata) { @@ -89,17 +93,204 @@ ui_set(settings->repo_tabview, 0); } +static void credentials_add(UiEvent *event, void *userdata) { + SettingsWindow *settings = event->window; + if(settings_credentials_save(settings)) { + return; + } + if(settings->credentials_list_needs_update) { + settings->credentials_ignore_selectionevent = TRUE; + ui_list_update(settings->credentials_users); + settings_reload_repo_credentials(settings); + settings->credentials_ignore_selectionevent = FALSE; + settings->credentials_list_needs_update = FALSE; + } + settings_credentials_clear(settings); + settings->credentials_new = TRUE; + PwdStore *pwd = settings->pwdstore; + if(!pwd->isdecrypted) { + settings_credentials_decrypt(settings); + return; + } + settings_credentials_select(settings, NULL); +} + +static void credentials_remove(UiEvent *event, void *userdata) { + SettingsWindow *settings = event->window; + if(settings->credentials_selected_id) { + pwdstore_remove_entry(settings->pwdstore, settings->credentials_selected_id); + ui_list_remove(settings->credentials_users, settings->credentials_selected_index); + ui_list_update(settings->credentials_users); + settings_reload_repo_credentials(settings); + } +} + +static void credentials_onselect(UiEvent *event, void *userdata) { + SettingsWindow *settings = event->window; + if(settings->credentials_ignore_selectionevent) { + return; + } + UiListSelection *sel = event->eventdata; + if(settings_credentials_save(settings)) { + return; + } + if(sel->count > 0) { + const char *id = ui_list_get(settings->credentials_users, sel->rows[0]); + settings->credentials_selected_index = sel->rows[0]; + settings_credentials_select(settings, id); + if(settings->credentials_list_needs_update) { + settings->credentials_ignore_selectionevent = TRUE; + ui_list_update(settings->credentials_users); + settings_reload_repo_credentials(settings); + ui_list_setselection(settings->credentials_users, sel->rows[0]); + settings->credentials_ignore_selectionevent = FALSE; + settings->credentials_list_needs_update = FALSE; + } + } else { + settings_credentials_clear(settings); + } +} + +static void c_add_location(UiEvent *event, void *userdata) { + SettingsWindow *settings = event->window; + if(event->intval == 1) { + ui_list_append(settings->credentials_locations, ui_strdup(event->obj->ctx, event->eventdata)); + ui_list_update(settings->credentials_locations); + } +} + +static void credentials_location_add(UiEvent *event, void *userdata) { + SettingsWindow *settings = event->window; + ui_dialog(event->obj, + .title = "Add Location", + .content = "New Location URL", + .input = TRUE, + .result = c_add_location, + .button1_label = "Add Location", + .closebutton_label = "Cancel"); +} + +static void c_edit_location(UiEvent *event, void *userdata) { + SettingsWindow *settings = event->window; + if(event->intval == 1) { + CxList *list = settings->credentials_locations->data; + ssize_t i = cxListFind(list, userdata); + if(i >= 0) { + cxListRemove(list, i); + cxListInsert(list, i, ui_strdup(event->obj->ctx, event->eventdata)); + ui_list_update(settings->credentials_locations); + } + } +} + +static void credentials_location_edit(UiEvent *event, void *userdata) { + SettingsWindow *settings = event->window; + char *location = ui_list_get(settings->credentials_locations, settings->credentials_location_selected_index); + ui_dialog(event->obj, + .title = "Edit Location", + .content = "Location URL", + .input_value = location, + .input = TRUE, + .result = c_edit_location, + .resultdata = location, + .button1_label = "Edit Location", + .closebutton_label = "Cancel"); +} + +static void credentials_location_remove(UiEvent *event, void *userdata) { + SettingsWindow *settings = event->window; + if(settings->credentials_location_selected_index >= 0) { + CxList *list = settings->credentials_locations->data; + cxListRemove(list, settings->credentials_location_selected_index); + ui_list_update(settings->credentials_locations); + } +} + +static void credentials_location_up(UiEvent *event, void *userdata) { + SettingsWindow *settings = event->window; + int index = settings->credentials_location_selected_index; + if(index >= 1) { + CxList *list = settings->credentials_locations->data; + cxListSwap(list, index, index-1); + ui_list_update(settings->credentials_locations); + ui_list_setselection(settings->credentials_locations, index-1); + } +} + +static void credentials_location_down(UiEvent *event, void *userdata) { + SettingsWindow *settings = event->window; + int index = settings->credentials_location_selected_index; + if(index >= 0 && index + 1 < ui_list_count(settings->credentials_locations)) { + CxList *list = settings->credentials_locations->data; + cxListSwap(list, index, index+1); + ui_list_update(settings->credentials_locations); + ui_list_setselection(settings->credentials_locations, index+1); + } +} + +static void credentials_location_onselect(UiEvent *event, void *userdata) { + SettingsWindow *settings = event->window; + UiListSelection *sel = event->eventdata; + if(sel->count > 0) { + settings->credentials_location_selected_index = sel->rows[0]; + ui_set_group(event->obj->ctx, SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED); + } else { + settings->credentials_location_selected_index = -1; + ui_unset_group(event->obj->ctx, SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED); + } +} + +static void credentials_setmasterpw(UiEvent *event, void *userdata) { + if(event->intval == 1) { + SettingsWindow *settings = event->window; + char *pw = event->eventdata; + size_t pwlen = strlen(pw); + if(pwlen > 0) { + pwdstore_setpassword(settings->pwdstore, event->eventdata); + memset(pw, 0, pwlen); + if(!pwdstore_decrypt(settings->pwdstore)) { + settings_credentials_select(settings, NULL); + } else { + ui_dialog(event->obj, .title = "Error", .content = "Cannot decrypt Secret Store", .closebutton_label = "OK"); + } + } + } +} + +void settings_credentials_decrypt(SettingsWindow *settings) { + ui_dialog(settings->obj, + .title = "Secret Store", + .content = "Master password", + .password = TRUE, + .result = credentials_setmasterpw, + .button1_label = "Decrypt Secret Store", + .closebutton_label = "Cancel"); +} + +static void list_str_destructor(void *data, void *ptr) { + UiContext *ctx = data; + char *s = ptr; + ui_free(ctx, ptr); +} + void settings_ok(UiEvent *event, void *userdata) { SettingsWindow *settings = event->window; settings->config_saved = TRUE; // save any changed settings settings_store_repository(settings); + settings_credentials_save(settings); set_config(settings->config); // TODO: free old config if(store_config()) { ui_dialog(event->obj, .title = "Error", .content = "Cannot store settings", .closebutton_label = "OK"); } + settings->config = NULL; + if(settings->credentials_modified) { + set_pwdstore(settings->pwdstore); + pwdstore_save(settings->pwdstore); + settings->pwdstore = NULL; + } application_update_repolist(get_application()); ui_close(event->obj); } @@ -112,7 +303,12 @@ // don't free anything return; } - dav_config_free(settings->config); + if(settings->config) { + dav_config_free(settings->config); + } + if(settings->pwdstore) { + pwdstore_free(settings->pwdstore); + } } void settings_cancel(UiEvent *event, void *userdata) { @@ -125,12 +321,17 @@ if(!config) { return; } + PwdStore *pwdstore = get_pwdstore(); + pwdstore = !pwdstore ? pwdstore_new() : pwdstore_clone(pwdstore); UiObject *obj = ui_simple_window("Settings", NULL); ui_context_closefunc(obj->ctx, settings_close, NULL); SettingsWindow *wdata = ui_malloc(obj->ctx, sizeof(SettingsWindow)); + memset(wdata, 0, sizeof(SettingsWindow)); wdata->config = config; + wdata->pwdstore = pwdstore; obj->window = wdata; + wdata->obj = obj; settings_init(obj, wdata); ui_tabview(obj) { @@ -247,8 +448,47 @@ } ui_tab(obj, "Credentials") { - ui_grid(obj, .margin = 10) { - ui_label(obj, .label = "TODO"); + ui_hbox(obj, .margin = 10, .spacing = 10) { + ui_vbox(obj, .fill = UI_OFF) { + ui_listview(obj, .list = wdata->credentials_users, .fill = UI_ON, .onselection = credentials_onselect); + ui_hbox(obj, .fill = UI_OFF, .spacing = 4) { + ui_button(obj, .label = "Add", .onclick = credentials_add); + ui_button(obj, .label = "Remove", .onclick = credentials_remove, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED)); + } + } + + ui_grid(obj, .columnspacing = 30, .rowspacing = 10) { + ui_llabel(obj, .label = "Identifier"); + ui_textfield(obj, .value = wdata->credentials_id, .hexpand = TRUE, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED)); + ui_newline(obj); + + ui_llabel(obj, .label = "User"); + ui_textfield(obj, .value = wdata->credentials_user, .hexpand = TRUE, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED)); + ui_newline(obj); + + ui_llabel(obj, .label = "Password"); + ui_passwordfield(obj, .value = wdata->credentials_password, .hexpand = TRUE, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED)); + ui_newline(obj); + + ui_label(obj, .label = " "); + ui_newline(obj); + + ui_llabel(obj, .style = UI_LABEL_STYLE_TITLE, .label = "Locations", .colspan = 2); + ui_newline(obj); + ui_llabel(obj, .style = UI_LABEL_STYLE_DIM, .label = "List of URLs for which these credentials should be used (optional)", .colspan = 2); + ui_newline(obj); + + ui_hbox(obj, .colspan = 2, .vexpand = TRUE, .hexpand = TRUE, .spacing = 10) { + ui_listview(obj, .list = wdata->credentials_locations, .onactivate = credentials_location_edit, .onselection = credentials_location_onselect, .colspan = 2, .fill = UI_ON, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED)); + ui_vbox(obj, .fill = UI_OFF, .spacing = 4) { + ui_button(obj, .label = "Add", .onclick = credentials_location_add, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED)); + ui_button(obj, .label = "Edit", .onclick = credentials_location_edit, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED, SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED)); + ui_button(obj, .label = "Remove", .onclick = credentials_location_remove, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED, SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED)); + ui_button(obj, .label = "Move Up", .onclick = credentials_location_up, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED, SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED)); + ui_button(obj, .label = "Move Down", .onclick = credentials_location_down, .groups = UI_GROUPS(SETTINGS_STATE_CREDENTIALS_SELECTED, SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED)); + } + } + } } } @@ -264,7 +504,7 @@ } } } - + ui_hbox(obj, .fill = UI_OFF, .margin = 10) { ui_button(obj, .label = "Cancel", .onclick = settings_cancel); ui_label(obj, .fill = UI_ON); @@ -289,23 +529,41 @@ settings->repo_tls_versions = ui_list_new(obj->ctx, NULL); settings->repo_encryption = ui_int_new(obj->ctx, NULL); settings->repo_disable_verification = ui_int_new(obj->ctx, NULL); - + ui_list_append(settings->repo_tls_versions, "Default"); ui_list_append(settings->repo_tls_versions, "TLSv1.3"); ui_list_append(settings->repo_tls_versions, "TLSv1.2"); ui_list_append(settings->repo_tls_versions, "TLSv1.1"); ui_list_append(settings->repo_tls_versions, "TLSv1.0"); + settings->credentials_selected_index = -1; + settings->credentials_users = ui_list_new(obj->ctx, NULL); + settings->credentials_locations = ui_list_new(obj->ctx, NULL); + settings->credentials_id = ui_string_new(obj->ctx, NULL); + settings->credentials_user = ui_string_new(obj->ctx, NULL); + settings->credentials_password = ui_string_new(obj->ctx, NULL); + CxList *credentials_users = settings->credentials_users->data; + CxList *credentials_locations = settings->credentials_locations->data; + credentials_users->collection.advanced_destructor = list_str_destructor; + credentials_users->collection.destructor_data = settings->obj->ctx; + credentials_users->collection.cmpfunc = (cx_compare_func)strcmp; + credentials_locations->collection.advanced_destructor = list_str_destructor; + credentials_locations->collection.destructor_data = settings->obj->ctx; + credentials_locations->collection.cmpfunc = (cx_compare_func)strcmp; + // load some list values, that can be reused settings_update_repolist(settings); settings_reload_keys(settings); settings_reload_credentials(settings); + void settings_reload_repo_credentials(SettingsWindow *settings); settings->selected_repo = -1; } #define SETTINGS_SET_STRING(str, setting) if(setting.value.ptr) ui_set(str, setting.value.ptr); +/* ----------------------------- Repository ----------------------------- */ + void settings_edit_repository(SettingsWindow *settings, int repo_index) { DavCfgRepository *repo = ui_list_get(settings->repos, repo_index); if(!repo) { @@ -566,27 +824,179 @@ return NULL; } + +/* ----------------------------- Credentials ----------------------------- */ + void settings_reload_credentials(SettingsWindow *settings) { - PwdStore *pwd = get_pwdstore(); - if(!pwd) { - return; + PwdStore *pwd = settings->pwdstore; + + ui_list_clear(settings->credentials_users); + + CxIterator i = cxListIterator(pwd->noloc); + cx_foreach(PwdIndexEntry*, entry, i) { + char *id = ui_strdup(settings->obj->ctx, entry->id); + ui_list_append(settings->credentials_users, id); + } + i = cxListIterator(pwd->locations); + cx_foreach(PwdIndexEntry*, entry, i) { + char *id = ui_strdup(settings->obj->ctx, entry->id); + ui_list_append(settings->credentials_users, id); } + ui_list_update(settings->credentials_users); +} + +void settings_reload_repo_credentials(SettingsWindow *settings) { + PwdStore *pwd = settings->pwdstore; + ui_list_clear(settings->repo_credentials); + + // repo_credentials needs an entry for selecting no credentials ui_list_append(settings->repo_credentials, "-"); CxIterator i = cxListIterator(pwd->noloc); cx_foreach(PwdIndexEntry*, entry, i) { - ui_list_append(settings->repo_credentials, entry->id); + char *id = ui_strdup(settings->obj->ctx, entry->id); + ui_list_append(settings->repo_credentials, id); } i = cxListIterator(pwd->locations); cx_foreach(PwdIndexEntry*, entry, i) { - ui_list_append(settings->repo_credentials, entry->id); + char *id = ui_strdup(settings->obj->ctx, entry->id); + ui_list_append(settings->repo_credentials, id); } - if(settings->repo_credentials->update) { - ui_list_update(settings->repo_credentials); - } + ui_list_update(settings->repo_credentials); } +void settings_credentials_select(SettingsWindow *settings, const char *id) { + if(!id && !settings->credentials_selected_id && !settings->credentials_new) { + fprintf(stderr, "Error: no credentials id selected\n"); + return; + } + + PwdStore *pwd = settings->pwdstore; + + if(id) { + ui_free(settings->obj->ctx, settings->credentials_selected_id); + settings->credentials_selected_id = ui_strdup(settings->obj->ctx, id); + } + + if(!pwd->isdecrypted) { + settings_credentials_decrypt(settings); + return; + } + + if(settings->credentials_new) { + ui_free(settings->obj->ctx, settings->credentials_selected_id); + settings->credentials_selected_id = NULL; + settings->credentials_selected_index = ui_list_count(settings->credentials_users); + ui_list_append(settings->credentials_users, ui_strdup(settings->obj->ctx, "new")); + settings->credentials_ignore_selectionevent = TRUE; + ui_list_update(settings->credentials_users); + ui_list_setselection(settings->credentials_users, settings->credentials_selected_index); + settings->credentials_ignore_selectionevent = FALSE; + + ui_set(settings->credentials_id, "new"); + ui_set(settings->credentials_user, ""); + ui_set(settings->credentials_password, ""); + ui_list_clear(settings->credentials_locations); + ui_list_update(settings->credentials_locations); + } else { + PwdEntry *entry = cxMapGet(pwd->ids, settings->credentials_selected_id); + PwdIndexEntry *index = cxMapGet(pwd->index, settings->credentials_selected_id); + if(!entry) { + fprintf(stderr, "Error: cannot get pwd entry %s\n", settings->credentials_selected_id); + return; + } + if(!index) { + fprintf(stderr, "Error: missing PwdIndexEntry. PwdStore may be broken.\n"); + return; + } + + ui_set(settings->credentials_id, entry->id); + ui_set(settings->credentials_user, entry->user); + ui_set(settings->credentials_password, entry->password); + + ui_list_clear(settings->credentials_locations); + if(index->locations) { + CxIterator i = cxListIterator(index->locations); + cx_foreach(char *, loc, i) { + ui_list_append(settings->credentials_locations, ui_strdup(settings->obj->ctx, loc)); + } + } + } + + ui_list_update(settings->credentials_locations); + + ui_set_group(settings->obj->ctx, SETTINGS_STATE_CREDENTIALS_SELECTED); +} + +void settings_credentials_clear(SettingsWindow *settings) { + ui_free(settings->obj->ctx, settings->credentials_selected_id); + settings->credentials_selected_id = NULL; + settings->credentials_new = FALSE; + + ui_set(settings->credentials_id, ""); + ui_set(settings->credentials_user, ""); + ui_set(settings->credentials_password, ""); + ui_list_clear(settings->credentials_locations); + ui_list_update(settings->credentials_locations); + + ui_unset_group(settings->obj->ctx, SETTINGS_STATE_CREDENTIALS_SELECTED); +} + +int settings_credentials_save(SettingsWindow *settings) { + if(settings->credentials_selected_index == -1) { + return 0; + } + + // check if the credentials list contains an element with the same id + // if an index is found, it must match the selected index, otherwise + // we have a duplicate identifier + char *newid = ui_get(settings->credentials_id); + if(strlen(newid) == 0) { + return 0; // TODO: check if other fields are set + } + + ssize_t index = cxListFind(settings->credentials_users->data, newid); + if(index >=0 && index != settings->credentials_selected_index) { + cxmutstr s = cx_asprintf("Identifier %s already in use", newid); + ui_dialog(settings->obj, .title = "Error", .content = s.ptr, .closebutton_label = "OK"); + free(s.ptr); + return 1; + } + + char *user = ui_get(settings->credentials_user); + char *password = ui_get(settings->credentials_password); + CxList *ui_locations = settings->credentials_locations->data; + size_t numlocations = cxListSize(ui_locations); + CxList *locations = NULL; + if(numlocations > 0) { + locations = cxArrayListCreateSimple(CX_STORE_POINTERS, numlocations); + CxIterator i = cxListIterator(ui_locations); + cx_foreach(char*, loc, i) { + cxListAdd(locations, strdup(loc)); + } + } + + // if the user id changed, mark the list as changed to update it later + settings->credentials_list_needs_update = settings->credentials_new || strcmp(newid, settings->credentials_selected_id); + if(settings->credentials_new || strcmp(newid, settings->credentials_selected_id ? settings->credentials_selected_id : "")) { + settings->credentials_list_needs_update = TRUE; + cxListRemove(settings->credentials_users->data, settings->credentials_selected_index); + cxListInsert(settings->credentials_users->data, settings->credentials_selected_index, ui_strdup(settings->obj->ctx, newid)); + } + + // if the pwdstore already contains this id, remove it first + if(settings->credentials_selected_id) { + pwdstore_remove_entry(settings->pwdstore, settings->credentials_selected_id); + } + + pwdstore_put(settings->pwdstore, newid, user, password); + pwdstore_put_index(settings->pwdstore, strdup(newid), locations); + settings->credentials_modified = TRUE; + settings->credentials_new = FALSE; + + return 0; +} diff -r 98d0e2516f4e -r 48f43130b4a2 application/settings.h --- a/application/settings.h Mon Oct 28 07:37:45 2024 +0100 +++ b/application/settings.h Mon Oct 28 15:20:58 2024 +0100 @@ -38,29 +38,79 @@ typedef struct SettingsWindow { + UiObject *obj; + DavConfig *config; + PwdStore *pwdstore; DavBool config_saved; UiList *repos; + /* + * 0: repo list page + * 1: edit repo page + */ UiInteger *repo_tabview; DavBool repo_new; UiString *repo_name; UiString *repo_url; + /* + * value: char* credential id + * + * '-' entry + list of all credentials + * This list contains the same credential pointers as credentials_users + * and therefore doesn't need a destructor. + * Both lists are updated at the same time + */ UiList *repo_credentials; UiString *repo_user; UiString *repo_password; + /* + * checkbox value + */ UiInteger *repo_encryption; UiList *repo_keys; + /* + * value: char* tls version name + * + * static list of TLS version strings + */ UiList *repo_tls_versions; UiString *repo_cacert; UiInteger *repo_disable_verification; + DavBool credentials_new; + DavBool credentials_modified; + DavBool credentials_list_needs_update; + DavBool credentials_ignore_selectionevent; + char *credentials_selected_id; + int credentials_selected_index; + int credentials_location_selected_index; + /* + * value: char* credentials id + * + * List of pwdstore locations and noloc credentials + * The value is a copy (allocated by the UiContext) + */ + UiList *credentials_users; + UiString *credentials_id; + UiString *credentials_user; + UiString *credentials_password; + /* + * value: char* url + * + * List of credential locations (PwdIndexEntry locations) + * The value is a copy (allocated by the UiContext) + */ + UiList *credentials_locations; + int selected_repo; } SettingsWindow; void settings_window_open(); +void settings_credentials_decrypt(SettingsWindow *settings); + void settings_ok(UiEvent *event, void *userdata); void settings_cancel(UiEvent *event, void *userdata); @@ -93,8 +143,23 @@ const char* dav_tlsversion2str(int value); void settings_reload_credentials(SettingsWindow *settings); +void settings_reload_repo_credentials(SettingsWindow *settings); +/* + * select credentials with the specified id and fill the credentials form + * + * if the id is specified, settings->credentials_id will be adjusted + * id no id is specified, credentials with the id settings->credentials_id + * are selected + */ +void settings_credentials_select(SettingsWindow *settings, const char *id); +/* + * clear the credentials form + */ +void settings_credentials_clear(SettingsWindow *settings); + +int settings_credentials_save(SettingsWindow *settings); #ifdef __cplusplus diff -r 98d0e2516f4e -r 48f43130b4a2 libidav/pwdstore.c --- a/libidav/pwdstore.c Mon Oct 28 07:37:45 2024 +0100 +++ b/libidav/pwdstore.c Mon Oct 28 15:20:58 2024 +0100 @@ -109,6 +109,61 @@ return p; } +PwdStore* pwdstore_clone(PwdStore *p) { + CxBuffer *newbuffer = calloc(1, sizeof(CxBuffer)); + *newbuffer = *p->content; + newbuffer->space = malloc(p->content->capacity); + memcpy(newbuffer->space, p->content->space, p->content->capacity); + + DavKey *key = NULL; + if(p->key) { + key = malloc(sizeof(DavKey)); + key->data = malloc(p->key->length); + memcpy(key->data, p->key->data, p->key->length); + key->length = p->key->length; + key->type = p->key->type; + key->name = NULL; + } + + PwdStore *newp = calloc(1, sizeof(PwdStore)); + newp->ids = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); + newp->locations = cxLinkedListCreateSimple(CX_STORE_POINTERS); + newp->noloc = cxLinkedListCreateSimple(CX_STORE_POINTERS); + newp->index = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 16); + newp->content = newbuffer; + newp->key = key; + newp->unlock_cmd = p->unlock_cmd ? strdup(p->unlock_cmd) : NULL; + newp->lock_cmd = p->lock_cmd ? strdup(p->lock_cmd) : NULL; + newp->encoffset = p->encoffset; + newp->isdecrypted = p->isdecrypted; + + CxIterator i = cxMapIterator(p->ids); + cx_foreach(CxMapEntry *, e, i) { + PwdEntry *entry = e->value; + PwdEntry *new_entry = malloc(sizeof(PwdEntry)); + new_entry->id = strdup(entry->id); + new_entry->user = entry->user ? strdup(entry->user) : NULL; + new_entry->password = entry->password ? strdup(entry->password) : NULL; + cxMapPut(newp->ids, *e->key, new_entry); + } + + i = cxMapIterator(p->index); + cx_foreach(CxMapEntry *, e, i) { + PwdIndexEntry *entry = e->value; + CxList *locations = NULL; + if(entry->locations) { + locations = cxLinkedListCreateSimple(CX_STORE_POINTERS); + CxIterator li = cxListIterator(entry->locations); + cx_foreach(char *, location, li) { + cxListAdd(locations, strdup(location)); + } + } + pwdstore_put_index(newp, entry->id, locations); + } + + return newp; +} + static int readval(CxBuffer *in, char **val, int allowzero) { // value = length string // length = uint32 @@ -172,6 +227,9 @@ if(ret) { pwdstore_put_index(p, id, locations); + if(cxListSize(locations) == 0) { + cxListDestroy(locations); + } } else { if(id) free(id); cxListDestroy(locations); @@ -235,7 +293,9 @@ PwdEntry *e = cxMapRemoveAndGet(s->ids, key); if(i) { - cxListDestroy(i->locations); + if(i->locations) { + cxListDestroy(i->locations); + } free(i->id); free(i); } @@ -306,6 +366,8 @@ cxBufferFree(content); + p->isdecrypted = 1; + return 0; } @@ -377,13 +439,12 @@ } PwdIndexEntry *newentry = malloc(sizeof(PwdIndexEntry)); newentry->id = id; - if(cxListSize(locations) > 0) { + if(locations && cxListSize(locations) > 0) { newentry->locations = locations; cxListAdd(p->locations, newentry); } else { newentry->locations = NULL; cxListAdd(p->noloc, newentry); - cxListDestroy(locations); } cxMapPut(p->index, cx_hash_key_str(id), newentry); } @@ -397,13 +458,15 @@ cxBufferWrite(&netidlen, 1, sizeof(uint32_t), out); cxBufferWrite(e->id, 1, idlen, out); - CxIterator i = cxListIterator(e->locations); - cx_foreach(char *, location, i) { - uint32_t locationlen = strlen(location); - uint32_t netlocationlen = htonl(locationlen); - - cxBufferWrite(&netlocationlen, 1, sizeof(uint32_t), out); - cxBufferWrite(location, 1, locationlen, out); + if(e->locations) { + CxIterator i = cxListIterator(e->locations); + cx_foreach(char *, location, i) { + uint32_t locationlen = strlen(location); + uint32_t netlocationlen = htonl(locationlen); + + cxBufferWrite(&netlocationlen, 1, sizeof(uint32_t), out); + cxBufferWrite(location, 1, locationlen, out); + } } uint32_t terminate = 0; diff -r 98d0e2516f4e -r 48f43130b4a2 libidav/pwdstore.h --- a/libidav/pwdstore.h Mon Oct 28 07:37:45 2024 +0100 +++ b/libidav/pwdstore.h Mon Oct 28 15:20:58 2024 +0100 @@ -166,6 +166,8 @@ PwdStore* pwdstore_new(void); +PwdStore* pwdstore_clone(PwdStore *p); + /* * decrypts the password store with the previously set password */ diff -r 98d0e2516f4e -r 48f43130b4a2 ui/common/types.c --- a/ui/common/types.c Mon Oct 28 07:37:45 2024 +0100 +++ b/ui/common/types.c Mon Oct 28 15:20:58 2024 +0100 @@ -159,7 +159,9 @@ } UIEXPORT void ui_list_update(UiList *list) { - list->update(list, 0); + if(list->update) { + list->update(list, 0); + } } void ui_list_addobsv(UiList *list, ui_callback f, void *data) { diff -r 98d0e2516f4e -r 48f43130b4a2 ui/gtk/list.c --- a/ui/gtk/list.c Mon Oct 28 07:37:45 2024 +0100 +++ b/ui/gtk/list.c Mon Oct 28 15:20:58 2024 +0100 @@ -202,22 +202,39 @@ // bind var list->update = ui_listview_update; list->getselection = ui_listview_getselection; + list->setselection = ui_listview_setselection; list->obj = listview; // add callback + UiTreeEventData *event = malloc(sizeof(UiTreeEventData)); + event->obj = obj; + event->activate = args.onactivate; + event->activatedata = args.onactivatedata; + event->selection = args.onselection; + event->selectiondata = args.onselectiondata; + g_signal_connect( + view, + "destroy", + G_CALLBACK(ui_destroy_userdata), + event); + if(args.onactivate) { - UiTreeEventData *event = ui_malloc(obj->ctx, sizeof(UiTreeEventData)); - event->obj = obj; - event->activatedata = args.onactivatedata; - event->activate = args.onactivate; - event->selection = NULL; - g_signal_connect( view, "row-activated", G_CALLBACK(ui_listview_activate_event), event); } + if(args.onselection) { + GtkTreeSelection *selection = gtk_tree_view_get_selection( + GTK_TREE_VIEW(view)); + g_signal_connect( + selection, + "changed", + G_CALLBACK(ui_listview_selection_event), + event); + } + // add widget to the current container GtkWidget *scroll_area = SCROLLEDWINDOW_NEW(); @@ -492,6 +509,14 @@ return selection; } +void ui_listview_setselection(UiList *list, UiListSelection selection) { + UiListView *view = list->obj; + GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(view->widget)); + GtkTreePath *path = gtk_tree_path_new_from_indicesv(selection.rows, selection.count); + gtk_tree_selection_select_path(sel, path); + //g_object_unref(path); +} + void ui_listview_destroy(GtkWidget *w, UiListView *v) { gtk_tree_view_set_model(GTK_TREE_VIEW(w), NULL); ui_destroy_boundvar(v->obj->ctx, v->var); diff -r 98d0e2516f4e -r 48f43130b4a2 ui/gtk/window.c --- a/ui/gtk/window.c Mon Oct 28 07:37:45 2024 +0100 +++ b/ui/gtk/window.c Mon Oct 28 15:20:58 2024 +0100 @@ -239,8 +239,14 @@ } GtkWidget *entry = NULL; - if(args.input) { + if(args.input || args.password) { entry = gtk_entry_new(); + if(args.password) { + gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); + } + if(args.input_value) { + ENTRY_SET_TEXT(entry, args.input_value); + } adw_alert_dialog_set_extra_child(ADW_ALERT_DIALOG(dialog), entry); event->customdata = entry; } @@ -313,8 +319,14 @@ } GtkWidget *textfield = NULL; - if(args.input) { + if(args.input || args.password) { textfield = gtk_entry_new(); + if(args.password) { + gtk_entry_set_visibility(GTK_ENTRY(textfield), FALSE); + } + if(args.input_value) { + ENTRY_SET_TEXT(textfield, args.input_value); + } BOX_ADD(content_area, textfield); } diff -r 98d0e2516f4e -r 48f43130b4a2 ui/ui/window.h --- a/ui/ui/window.h Mon Oct 28 07:37:45 2024 +0100 +++ b/ui/ui/window.h Mon Oct 28 15:20:58 2024 +0100 @@ -45,7 +45,9 @@ const char *button1_label; const char *button2_label; const char *closebutton_label; + const char *input_value; UiBool input; + UiBool password; ui_callback result; void *resultdata; } UiDialogArgs;