1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "settings.h"
30
31 #include <cx/list.h>
32 #include <cx/array_list.h>
33 #include <cx/printf.h>
34 #include <libidav/utils.h>
35
36
37
38 #define SETTINGS_STATE_REPOLIST_SELECTED 1
39 #define SETTINGS_STATE_REPO_ENCRYPTION 20
40 #define SETTINGS_STATE_CREDENTIALS_SELECTED 30
41 #define SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED 31
42 #define SETTINGS_STATE_KEYS_SELECTED 40
43
44 #define SETTINGS_STATE_DISABLED 9999
45
46
47 static void repolist_activate(UiEvent *event,
void *userdata) {
48 UiListSelection *selection = event->eventdata;
49 SettingsWindow *settings = event->window;
50 settings_edit_repository(settings, selection->rows[
0]);
51 }
52
53 static void repolist_selection(UiEvent *event,
void *userdata) {
54 UiListSelection *selection = event->eventdata;
55 SettingsWindow *settings = event->window;
56 if(selection->count >
0) {
57 ui_set_group(event->obj->ctx,
SETTINGS_STATE_REPOLIST_SELECTED);
58 settings->selected_repo = selection->rows[
0];
59 }
else {
60 ui_unset_group(event->obj->ctx,
SETTINGS_STATE_REPOLIST_SELECTED);
61 }
62 }
63
64 static void repolist_edit(UiEvent *event,
void *userdata) {
65 SettingsWindow *settings = event->window;
66 if(settings->selected_repo >=
0) {
67 settings_edit_repository(settings, settings->selected_repo);
68 }
69 }
70
71 static void repolist_add(UiEvent *event,
void *userdata) {
72 SettingsWindow *settings = event->window;
73 settings->repo_new =
TRUE;
74 settings->selected_repo = -
1;
75 settings_clear_repository(settings);
76
77 ui_set(settings->repo_tabview,
1);
78 }
79
80 static void repolist_remove(UiEvent *event,
void *userdata) {
81 SettingsWindow *settings = event->window;
82 DavCfgRepository *repo = ui_list_get(settings->repos, settings->selected_repo);
83 if(!repo) {
84 fprintf(stderr,
"Error: cannot get repository at index %d\n", settings->selected_repo);
85 return;
86 }
87 dav_repository_remove_and_free(settings->config, repo);
88 settings_update_repolist(settings);
89 settings->selected_repo = -
1;
90 ui_unset_group(event->obj->ctx,
SETTINGS_STATE_REPOLIST_SELECTED);
91 }
92
93 static void editrepo_go_back(UiEvent *event,
void *userdata) {
94 SettingsWindow *settings = event->window;
95 settings_store_repository(settings);
96 ui_set(settings->repo_tabview,
0);
97 }
98
99 static void credentials_add(UiEvent *event,
void *userdata) {
100 SettingsWindow *settings = event->window;
101 if(settings_credentials_save(settings)) {
102 return;
103 }
104 if(settings->credentials_list_needs_update) {
105 settings->credentials_ignore_selectionevent =
TRUE;
106 ui_list_update(settings->credentials_users);
107 settings_reload_repo_credentials(settings);
108 settings->credentials_ignore_selectionevent =
FALSE;
109 settings->credentials_list_needs_update =
FALSE;
110 }
111 settings_credentials_clear(settings);
112 settings->credentials_new =
TRUE;
113 PwdStore *pwd = settings->pwdstore;
114 if(!pwd->isdecrypted) {
115 settings_credentials_decrypt(settings);
116 return;
117 }
118 settings_credentials_select(settings,
NULL);
119 }
120
121 static void addcred_onclick(UiEvent *event,
void *userdata) {
122 SettingsNewCredentialsDialog *wdata = event->window;
123 if(event->intval ==
4) {
124 char *id = ui_get(wdata->id);
125 char *user = ui_get(wdata->user);
126 char *password = ui_get(wdata->password);
127 int addlocation = ui_get(wdata->addlocation);
128
129 if(strlen(id) ==
0) {
130 ui_set(wdata->message,
"Missing identifier!");
131 return;
132 }
133 if(strlen(user) ==
0) {
134 ui_set(wdata->message,
"Missing user!");
135 return;
136 }
137 if(strlen(password) ==
0) {
138 ui_set(wdata->message,
"Missing password!");
139 return;
140 }
141
142 if(pwdstore_has_id(wdata->settings->pwdstore, id)) {
143 ui_set(wdata->message,
"Identifier already in use!");
144 return;
145 }
146
147 CxList *locations =
NULL;
148 if(addlocation) {
149 locations = cxLinkedListCreateSimple(
CX_STORE_POINTERS);
150 cxListAdd(locations, strdup(wdata->url));
151 }
152 pwdstore_put(wdata->settings->pwdstore, id, user, password);
153 pwdstore_put_index(wdata->settings->pwdstore, strdup(id), locations);
154
155 settings_reload_credentials(wdata->settings);
156 settings_reload_repo_credentials(wdata->settings);
157
158 CxList *list = wdata->settings->repo_credentials->data;
159 ssize_t index = cxListFind(list, id);
160 if(index >=
0) {
161 ui_list_setselection(wdata->settings->repo_credentials, index);
162 }
163 }
164
165 ui_close(event->obj);
166 }
167
168
169
170 static void credentials_new(UiEvent *event,
void *userdata) {
171 SettingsWindow *settings = event->window;
172
173 UiObject *dialog = ui_dialog_window(event->obj,
174 .modal =
UI_ON,
175 .title =
"New Credentials",
176 .show_closebutton =
UI_OFF,
177 .lbutton1 =
"Cancel",
178 .rbutton4 =
"Add",
179 .onclick = addcred_onclick);
180
181 SettingsNewCredentialsDialog *wdata = ui_malloc(dialog->ctx,
sizeof(SettingsNewCredentialsDialog));
182 wdata->settings = settings;
183 wdata->id = ui_string_new(dialog->ctx,
NULL);
184 wdata->user = ui_string_new(dialog->ctx,
NULL);
185 wdata->password = ui_string_new(dialog->ctx,
NULL);
186 wdata->addlocation = ui_int_new(dialog->ctx,
NULL);
187 wdata->message = ui_string_new(dialog->ctx,
NULL);
188 dialog->window = wdata;
189
190 char *url = ui_get(settings->repo_url);
191 if(strlen(url) >
0) {
192 wdata->url = ui_strdup(dialog->ctx, url);
193 }
else {
194 wdata->url =
NULL;
195 }
196
197 ui_grid(dialog, .margin =
16, .columnspacing =
40, .rowspacing =
10) {
198 ui_llabel(dialog, .label =
"Identifier");
199 ui_textfield(dialog, .value = wdata->id, .hexpand =
TRUE);
200 ui_newline(dialog);
201
202 ui_llabel(dialog, .label =
"User");
203 ui_textfield(dialog, .value = wdata->user, .hexpand =
TRUE);
204 ui_newline(dialog);
205
206 ui_llabel(dialog, .label =
"Password");
207 ui_passwordfield(dialog, .value = wdata->password, .hexpand =
TRUE);
208 ui_newline(dialog);
209
210 if(wdata->url) {
211 cxmutstr msg = cx_asprintf(
"Add URL %s to Credential Locations", url);
212 ui_checkbox(dialog, .label = msg.ptr, .value = wdata->addlocation, .colspan =
2);
213 ui_newline(dialog);
214 free(msg.ptr);
215 }
216
217 ui_llabel(dialog, .value = wdata->message, .colspan =
2);
218 }
219
220 ui_show(dialog);
221 }
222
223 static void credentials_remove(UiEvent *event,
void *userdata) {
224 SettingsWindow *settings = event->window;
225 if(settings->credentials_selected_id) {
226 pwdstore_remove_entry(settings->pwdstore, settings->credentials_selected_id);
227 ui_list_remove(settings->credentials_users, settings->credentials_selected_index);
228 ui_list_update(settings->credentials_users);
229 settings_reload_repo_credentials(settings);
230 }
231 }
232
233 static void credentials_onselect(UiEvent *event,
void *userdata) {
234 SettingsWindow *settings = event->window;
235 if(settings->credentials_ignore_selectionevent) {
236 return;
237 }
238 UiListSelection *sel = event->eventdata;
239 if(settings_credentials_save(settings)) {
240 return;
241 }
242 if(sel->count >
0) {
243 const char *id = ui_list_get(settings->credentials_users, sel->rows[
0]);
244 settings->credentials_selected_index = sel->rows[
0];
245 settings_credentials_select(settings, id);
246 if(settings->credentials_list_needs_update) {
247 settings->credentials_ignore_selectionevent =
TRUE;
248 ui_list_update(settings->credentials_users);
249 settings_reload_repo_credentials(settings);
250 ui_list_setselection(settings->credentials_users, sel->rows[
0]);
251 settings->credentials_ignore_selectionevent =
FALSE;
252 settings->credentials_list_needs_update =
FALSE;
253 }
254 }
else {
255 settings_credentials_clear(settings);
256 }
257 }
258
259 static void c_add_location(UiEvent *event,
void *userdata) {
260 SettingsWindow *settings = event->window;
261 if(event->intval ==
1) {
262 ui_list_append(settings->credentials_locations, ui_strdup(event->obj->ctx, event->eventdata));
263 ui_list_update(settings->credentials_locations);
264 }
265 }
266
267 static void credentials_location_add(UiEvent *event,
void *userdata) {
268 SettingsWindow *settings = event->window;
269 ui_dialog(event->obj,
270 .title =
"Add Location",
271 .content =
"New Location URL",
272 .input =
TRUE,
273 .result = c_add_location,
274 .button1_label =
"Add Location",
275 .closebutton_label =
"Cancel");
276 }
277
278 static void c_edit_location(UiEvent *event,
void *userdata) {
279 SettingsWindow *settings = event->window;
280 if(event->intval ==
1) {
281 CxList *list = settings->credentials_locations->data;
282 ssize_t i = cxListFind(list, userdata);
283 if(i >=
0) {
284 cxListRemove(list, i);
285 cxListInsert(list, i, ui_strdup(event->obj->ctx, event->eventdata));
286 ui_list_update(settings->credentials_locations);
287 }
288 }
289 }
290
291 static void credentials_location_edit(UiEvent *event,
void *userdata) {
292 SettingsWindow *settings = event->window;
293 char *location = ui_list_get(settings->credentials_locations, settings->credentials_location_selected_index);
294 if(!location) {
295 return;
296 }
297 ui_dialog(event->obj,
298 .title =
"Edit Location",
299 .content =
"Location URL",
300 .input_value = location,
301 .input =
TRUE,
302 .result = c_edit_location,
303 .resultdata = location,
304 .button1_label =
"Edit Location",
305 .closebutton_label =
"Cancel");
306 }
307
308 static void credentials_location_remove(UiEvent *event,
void *userdata) {
309 SettingsWindow *settings = event->window;
310 if(settings->credentials_location_selected_index >=
0) {
311 CxList *list = settings->credentials_locations->data;
312 cxListRemove(list, settings->credentials_location_selected_index);
313 ui_list_update(settings->credentials_locations);
314 }
315 }
316
317 static void credentials_location_up(UiEvent *event,
void *userdata) {
318 SettingsWindow *settings = event->window;
319 int index = settings->credentials_location_selected_index;
320 if(index >=
1) {
321 CxList *list = settings->credentials_locations->data;
322 cxListSwap(list, index, index-
1);
323 ui_list_update(settings->credentials_locations);
324 ui_list_setselection(settings->credentials_locations, index-
1);
325 }
326 }
327
328 static void credentials_location_down(UiEvent *event,
void *userdata) {
329 SettingsWindow *settings = event->window;
330 int index = settings->credentials_location_selected_index;
331 if(index >=
0 && index +
1 < ui_list_count(settings->credentials_locations)) {
332 CxList *list = settings->credentials_locations->data;
333 cxListSwap(list, index, index+
1);
334 ui_list_update(settings->credentials_locations);
335 ui_list_setselection(settings->credentials_locations, index+
1);
336 }
337 }
338
339 static void credentials_location_onselect(UiEvent *event,
void *userdata) {
340 SettingsWindow *settings = event->window;
341 UiListSelection *sel = event->eventdata;
342 if(sel->count >
0) {
343 settings->credentials_location_selected_index = sel->rows[
0];
344 ui_set_group(event->obj->ctx,
SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED);
345 }
else {
346 settings->credentials_location_selected_index = -
1;
347 ui_unset_group(event->obj->ctx,
SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED);
348 }
349 }
350
351 static void credentials_setmasterpw(UiEvent *event,
void *userdata) {
352 if(event->intval ==
1) {
353 SettingsWindow *settings = event->window;
354 char *pw = event->eventdata;
355 size_t pwlen = strlen(pw);
356 if(pwlen >
0) {
357 pwdstore_setpassword(settings->pwdstore, event->eventdata);
358 memset(pw,
0, pwlen);
359 if(!pwdstore_decrypt(settings->pwdstore)) {
360 settings_credentials_select(settings,
NULL);
361 }
else {
362 ui_dialog(event->obj, .title =
"Error", .content =
"Cannot decrypt Secret Store", .closebutton_label =
"OK");
363 }
364 }
365 }
366 }
367
368 void settings_credentials_decrypt(SettingsWindow *settings) {
369 ui_dialog(settings->obj,
370 .title =
"Secret Store",
371 .content =
"Master password",
372 .password =
TRUE,
373 .result = credentials_setmasterpw,
374 .button1_label =
"Decrypt Secret Store",
375 .closebutton_label =
"Cancel");
376 }
377
378
379
380
381 #define ADDKEY_DIALOG_STATE_NO_IMPORT 10
382
383 static void addkey_onclick(UiEvent *event,
void *userdata) {
384 SettingsNewKeyDialog *wdata = event->window;
385 if(event->intval ==
4) {
386 ui_set(wdata->message,
"");
387
388
389 char *name = ui_get(wdata->name);
390 if(strlen(name) ==
0) {
391 ui_set(wdata->message,
"A name must be specified!");
392 return;
393 }
394 char *file = ui_get(wdata->file);
395 if(strlen(file) ==
0) {
396 ui_set(wdata->message,
"A file path must be specified!");
397 return;
398 }
399 UiListSelection sel = ui_list_getselection(wdata->type);
400 if(sel.count ==
0) {
401 ui_set(wdata->message,
"No type selected!");
402 return;
403 }
404 DavCfgKeyType type = sel.rows[
0];
405
406
407 char *path =
NULL;
408 char *cfg_path =
NULL;
409 if(file[
0] ==
'/') {
410 path = file;
411 }
else {
412 cfg_path = config_file_path(file);
413 path = cfg_path;
414 }
415 FILE *f = fopen(path,
"w");
416 if(!f) {
417 cxmutstr msg = cx_asprintf(
"Error: cannot write file ''%s'': %s", path, strerror(errno));
418 ui_set(wdata->message, msg.ptr);
419 free(msg.ptr);
420 free(cfg_path);
421 return;
422 }
423 free(cfg_path);
424
425 unsigned char key[
32];
426 dav_rand_bytes(key,
32);
427
428 size_t len;
429 switch(type) {
430 default:
431 case DAV_KEY_TYPE_AES256: len =
32;
break;
432 case DAV_KEY_TYPE_AES128: len =
16;
break;
433 }
434 size_t w = fwrite(key,
1, len, f);
435 fclose(f);
436
437 if(w != len) {
438 cxmutstr msg = cx_asprintf(
"Could not write key data: %s", strerror(errno));
439 ui_set(wdata->message, msg.ptr);
440 free(msg.ptr);
441 return;
442 }
443
444
445 DavCfgKey *newkey = dav_key_new(wdata->settings->config);
446 const CxAllocator *a = wdata->settings->config->mp->allocator;
447 newkey->name.value = cx_strdup_a(a, cx_str(name));
448 newkey->file.value = cx_strdup_a(a, cx_str(file));
449 newkey->type = type;
450
451 dav_config_add_key(wdata->settings->config, newkey);
452 settings_reload_repo_keys(wdata->settings);
453 settings_reload_keys(wdata->settings);
454
455 if(wdata->add_to_repo && (wdata->settings->selected_repo >=
0 || wdata->settings->repo_new)) {
456 CxList *repo_keys = wdata->settings->repo_keys->data;
457 ssize_t index = cxListFind(repo_keys, name);
458 if(index >=
0) {
459 ui_list_setselection(wdata->settings->repo_keys, index);
460 }
461 }
462 }
463
464 ui_close(event->obj);
465 }
466
467 static void addkey_name_changed(UiEvent *event,
void *userdata) {
468 SettingsNewKeyDialog *wdata = event->window;
469 char *name = ui_get(wdata->name);
470 cxmutstr file = cx_asprintf(
"keys/%s", name);
471 ui_set(wdata->file, file.ptr);
472 free(file.ptr);
473 }
474
475 static void keys_add(UiEvent *event,
void *userdata) {
476 SettingsWindow *settings = event->window;
477
478 UiObject *dialog = ui_dialog_window(event->obj,
479 .modal =
UI_ON,
480 .title =
"Add Key",
481 .show_closebutton =
UI_OFF,
482 .lbutton1 =
"Cancel",
483 .rbutton4 =
"Add",
484 .default_button =
4,
485 .onclick = addkey_onclick);
486 SettingsNewKeyDialog *wdata = ui_malloc(dialog->ctx,
sizeof(SettingsNewKeyDialog));
487 wdata->settings = settings;
488 wdata->name = ui_string_new(dialog->ctx,
NULL);
489 wdata->file = ui_string_new(dialog->ctx,
NULL);
490 wdata->import_path = ui_string_new(dialog->ctx,
NULL);
491 wdata->message = ui_string_new(dialog->ctx,
NULL);
492 wdata->secretstore = ui_int_new(dialog->ctx,
NULL);
493 wdata->type = ui_list_new(dialog->ctx,
NULL);
494 wdata->add_to_repo = userdata ?
TRUE :
FALSE;
495 dialog->window = wdata;
496
497 ui_list_append(wdata->type,
"AES256");
498 ui_list_append(wdata->type,
"AES128");
499
500 ui_grid(dialog, .margin =
16, .columnspacing =
40, .rowspacing =
10) {
501
502
503
504
505
506
507
508
509
510 ui_llabel(dialog, .label =
"Name");
511 ui_textfield(dialog, .value = wdata->name, .onchange = addkey_name_changed, .hexpand =
TRUE);
512 ui_newline(dialog);
513
514 ui_llabel(dialog, .label =
"File");
515 ui_textfield(dialog, .value = wdata->file);
516 ui_newline(dialog);
517
518 ui_llabel(dialog, .label =
"Type");
519 ui_combobox(dialog, .list = wdata->type, .groups =
UI_GROUPS(
ADDKEY_DIALOG_STATE_NO_IMPORT));
520 ui_newline(dialog);
521
522 ui_llabel(dialog, .value = wdata->message, .colspan =
2);
523 }
524
525 ui_set_group(dialog->ctx,
ADDKEY_DIALOG_STATE_NO_IMPORT);
526 ui_list_setselection(wdata->type,
0);
527
528 ui_show(dialog);
529 }
530
531 static void keys_remove(UiEvent *event,
void *userdata) {
532 SettingsWindow *settings = event->window;
533 DavCfgKey *key = ui_list_get(settings->keys_list, settings->keys_selected_index);
534 if(key) {
535 dav_key_remove_and_free(settings->config, key);
536 ui_list_remove(settings->keys_list, settings->keys_selected_index);
537 ui_list_update(settings->keys_list);
538 settings_reload_repo_keys(settings);
539 }
540 }
541
542 static void keys_onselect(UiEvent *event,
void *userdata) {
543 SettingsWindow *settings = event->window;
544 UiListSelection *sel = event->eventdata;
545 if(sel->count >
0) {
546 settings->keys_selected_index = sel->rows[
0];
547 DavCfgKey *key = ui_list_get(settings->keys_list, sel->rows[
0]);
548 if(key) {
549 settings_edit_key(settings, key);
550 ui_set_group(event->obj->ctx,
SETTINGS_STATE_KEYS_SELECTED);
551 }
552 }
else {
553 settings->keys_selected_index = -
1;
554 settings_clear_key(settings);
555 ui_unset_group(event->obj->ctx,
SETTINGS_STATE_KEYS_SELECTED);
556 }
557 }
558
559 static void list_str_destructor(
void *data,
void *ptr) {
560 UiContext *ctx = data;
561 char *s = ptr;
562 ui_free(ctx, ptr);
563 }
564
565 static void secretstore_newmasterpw(UiEvent *event,
void *userdata) {
566 SettingsWindow *settings = event->window;
567 if(event->intval ==
1) {
568 pwdstore_setpassword(settings->pwdstore, event->eventdata);
569 set_pwdstore(settings->pwdstore);
570 pwdstore_save(settings->pwdstore);
571 settings->pwdstore =
NULL;
572 }
573 ui_close(event->obj);
574 }
575
576 void settings_ok(UiEvent *event,
void *userdata) {
577 SettingsWindow *settings = event->window;
578
579 settings_store_repository(settings);
580 settings_credentials_save(settings);
581
582 set_config(settings->config);
583 if(store_config()) {
584 ui_dialog(event->obj, .title =
"Error", .content =
"Cannot store settings", .closebutton_label =
"OK");
585 }
586 application_update_repolist(get_application()); settings->config =
NULL;
587 if(settings->credentials_modified) {
588 if(settings->pwdstore->key) {
589 set_pwdstore(settings->pwdstore);
590 pwdstore_save(settings->pwdstore);
591 }
else {
592 ui_dialog(event->obj,
593 .title =
"Secret Store",
594 .content =
"Master password",
595 .password =
TRUE,
596 .result = secretstore_newmasterpw,
597 .button1_label =
"Create Secret Store",
598 .closebutton_label =
"Cancel",
599 .result = secretstore_newmasterpw);
600 return;
601 }
602 settings->pwdstore =
NULL;
603 }
604 ui_close(event->obj);
605 }
606
607 void settings_close(UiEvent *event,
void *userdata) {
608 SettingsWindow *settings = event->window;
609 if(settings->config) {
610 dav_config_free(settings->config);
611 }
612 if(settings->pwdstore) {
613 pwdstore_free(settings->pwdstore);
614 }
615 }
616
617 void settings_cancel(UiEvent *event,
void *userdata) {
618 ui_close(event->obj);
619 }
620
621 void settings_window_open() {
622 DavConfig *config = load_config_file();
623 if(!config) {
624 return;
625 }
626 PwdStore *pwdstore = get_pwdstore();
627 pwdstore = pwdstore ? pwdstore_clone(pwdstore) : pwdstore_new();
628
629 UiObject *obj = ui_simple_window(
"Settings",
NULL);
630 ui_context_closefunc(obj->ctx, settings_close,
NULL);
631 SettingsWindow *wdata = ui_malloc(obj->ctx,
sizeof(SettingsWindow));
632 memset(wdata,
0,
sizeof(SettingsWindow));
633 wdata->config = config;
634 wdata->pwdstore = pwdstore;
635 obj->window = wdata;
636 wdata->obj = obj;
637 settings_init(obj, wdata);
638
639 ui_tabview(obj, .tabview =
UI_TABVIEW_NAVIGATION_TOP) {
640 ui_tab(obj,
"General") {
641 ui_grid(obj, .margin =
10) {
642 ui_label(obj, .label =
"TODO");
643 }
644 }
645
646 ui_tab(obj,
"Repositories") {
647
648 ui_tabview(obj, .value = wdata->repo_tabview, .tabview =
UI_TABVIEW_INVISIBLE) {
649 ui_tab(obj,
"list") {
650 ui_grid(obj, .margin =
16, .columnspacing =
10, .rowspacing =
10) {
651 ui_hbox(obj, .spacing =
4) {
652 ui_button(obj, .label =
"Add", .onclick = repolist_add);
653 ui_button(obj, .label =
"Edit", .onclick = repolist_edit, .groups =
UI_GROUPS(
SETTINGS_STATE_REPOLIST_SELECTED));
654 ui_button(obj, .label =
"Remove", .onclick = repolist_remove, .groups =
UI_GROUPS(
SETTINGS_STATE_REPOLIST_SELECTED));
655 }
656 ui_newline(obj);
657
658 UiModel* model = ui_model(obj->ctx,
UI_STRING,
"Name",
UI_STRING,
"URL",
UI_STRING,
"User",
UI_STRING,
"Encrypted", -
1);
659 model->getvalue = (ui_getvaluefunc) settings_repolist_getvalue;
660 ui_table(obj,
661 .model = model,
662 .list = wdata->repos,
663 .multiselection =
FALSE,
664 .onactivate = repolist_activate,
665 .onselection = repolist_selection,
666 .vexpand =
TRUE, .hexpand =
TRUE, .colspan =
3);
667 }
668 }
669
670 ui_tab(obj,
"repo") {
671 ui_vbox(obj, .margin =
16, .spacing =
10) {
672 ui_hbox(obj, .fill =
UI_OFF, .spacing =
4) {
673 ui_button(obj, .icon =
UI_ICON_GO_BACK, .onclick = editrepo_go_back);
674 ui_label(obj, .label =
"Repository List");
675 }
676
677 ui_scrolledwindow(obj, .hexpand =
TRUE, .vexpand =
TRUE, .subcontainer =
UI_CONTAINER_NO_SUB) {
678 ui_grid(obj, .margin =
10, .columnspacing =
10, .rowspacing =
10) {
679 ui_llabel(obj, .label =
"Name");
680 ui_textfield(obj, .value = wdata->repo_name, .width =
15);
681 ui_newline(obj);
682 ui_llabel(obj, .label =
"URL");
683 ui_textfield(obj, .value = wdata->repo_url, .hexpand =
TRUE);
684 ui_newline(obj);
685
686 ui_llabel(obj, .label =
"Credentials", .style =
UI_LABEL_STYLE_TITLE, .colspan =
2);
687 ui_newline(obj);
688 ui_hbox(obj, .spacing =
4, .colspan =
2) {
689 ui_combobox(obj, .list = wdata->repo_credentials);
690 ui_button(obj, .label =
"New Credentials", .onclick = credentials_new);
691 }
692 ui_newline(obj);
693 ui_expander(obj, .spacing =
10, .colspan =
2, .label =
"Unencrypted User/Password", .margin =
10) {
694 ui_llabel(obj, .label =
"Store the credentials unencrypted in the repository and not in the secret store", .style =
UI_LABEL_STYLE_DIM);
695 ui_grid(obj, .rowspacing =
10, .columnspacing =
10, .fill =
UI_OFF) {
696 ui_llabel(obj, .label =
"User");
697 ui_textfield(obj, .value = wdata->repo_user, .width =
15);
698 ui_newline(obj);
699
700 ui_llabel(obj, .label =
"Password");
701 ui_passwordfield(obj, .value = wdata->repo_password, .width =
15);
702 }
703 }
704 ui_newline(obj);
705
706 ui_llabel(obj, .label =
"Encryption", .style =
UI_LABEL_STYLE_TITLE, .colspan =
2);
707 ui_newline(obj);
708
709 ui_checkbox(obj, .label =
"Enable client-side encryption", .value = wdata->repo_encryption, .colspan =
2, .enable_group =
SETTINGS_STATE_REPO_ENCRYPTION);
710 ui_newline(obj);
711 ui_llabel(obj, .label =
"Default key");
712 ui_hbox(obj, .spacing =
4) {
713 ui_combobox(obj, .list = wdata->repo_keys, .groups =
UI_GROUPS(
SETTINGS_STATE_REPO_ENCRYPTION));
714 ui_button(obj, .label =
"Generate Key", .onclick = keys_add, .onclickdata =
"repo", .groups =
UI_GROUPS(
SETTINGS_STATE_REPO_ENCRYPTION));
715 }
716 ui_newline(obj);
717
718 ui_llabel(obj, .label =
"TLS", .style =
UI_LABEL_STYLE_TITLE, .colspan =
2);
719 ui_newline(obj);
720
721 ui_llabel(obj, .label =
"Cert Path");
722 ui_hbox0(obj) {
723 ui_textfield(obj, .value = wdata->repo_cacert, .width =
15);
724 }
725 ui_newline(obj);
726
727 ui_llabel(obj, .label =
"TLS Version");
728 ui_hbox0(obj) {
729 ui_combobox(obj, .list = wdata->repo_tls_versions);
730 }
731 ui_newline(obj);
732 ui_checkbox(obj, .label =
"Disable TLS verification", .value = wdata->repo_disable_verification, .colspan =
2);
733 }
734 }
735 }
736 }
737 }
738
739
740 }
741
742 ui_tab(obj,
"Sync Directories") {
743 ui_grid(obj, .margin =
10) {
744 ui_label(obj, .label =
"TODO");
745 }
746 }
747
748 ui_tab(obj,
"Credentials") {
749 ui_hbox(obj, .margin =
16, .spacing =
30) {
750 ui_vbox(obj, .fill =
UI_OFF, .spacing =
4) {
751 ui_hbox(obj, .fill =
UI_OFF, .spacing =
4) {
752 ui_button(obj, .label =
"Add", .onclick = credentials_add);
753 ui_button(obj, .label =
"Remove", .onclick = credentials_remove, .groups =
UI_GROUPS(
SETTINGS_STATE_CREDENTIALS_SELECTED));
754 }
755 ui_listview(obj, .list = wdata->credentials_users, .fill =
UI_ON, .onselection = credentials_onselect);
756 }
757
758 ui_grid(obj, .columnspacing =
30, .rowspacing =
10) {
759 ui_llabel(obj, .label =
"Identifier");
760 ui_textfield(obj, .value = wdata->credentials_id, .hexpand =
TRUE, .groups =
UI_GROUPS(
SETTINGS_STATE_CREDENTIALS_SELECTED));
761 ui_newline(obj);
762
763 ui_llabel(obj, .label =
"User");
764 ui_textfield(obj, .value = wdata->credentials_user, .hexpand =
TRUE, .groups =
UI_GROUPS(
SETTINGS_STATE_CREDENTIALS_SELECTED));
765 ui_newline(obj);
766
767 ui_llabel(obj, .label =
"Password");
768 ui_passwordfield(obj, .value = wdata->credentials_password, .hexpand =
TRUE, .groups =
UI_GROUPS(
SETTINGS_STATE_CREDENTIALS_SELECTED));
769 ui_newline(obj);
770
771
772 ui_label(obj, .label =
" ");
773 ui_newline(obj);
774
775 ui_llabel(obj, .style =
UI_LABEL_STYLE_TITLE, .label =
"Locations", .colspan =
2);
776 ui_newline(obj);
777 ui_llabel(obj, .style =
UI_LABEL_STYLE_DIM, .label =
"List of URLs for which these credentials should be used (optional)", .colspan =
2);
778 ui_newline(obj);
779
780 ui_hbox(obj, .colspan =
2, .vexpand =
TRUE, .hexpand =
TRUE, .spacing =
10) {
781 #ifndef UI_WINUI
782 ui_callback credentials_activate_callback = credentials_location_edit;
783 #else
784 ui_callback credentials_activate_callback =
NULL;
785 #endif
786 ui_listview(obj, .list = wdata->credentials_locations, .onactivate = credentials_activate_callback, .onselection = credentials_location_onselect, .colspan =
2, .fill =
UI_ON, .groups =
UI_GROUPS(
SETTINGS_STATE_CREDENTIALS_SELECTED));
787 ui_vbox(obj, .fill =
UI_OFF, .spacing =
4) {
788 ui_button(obj, .label =
"Add", .onclick = credentials_location_add, .groups =
UI_GROUPS(
SETTINGS_STATE_CREDENTIALS_SELECTED));
789 ui_button(obj, .label =
"Edit", .onclick = credentials_location_edit, .groups =
UI_GROUPS(
SETTINGS_STATE_CREDENTIALS_SELECTED,
SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED));
790 ui_button(obj, .label =
"Remove", .onclick = credentials_location_remove, .groups =
UI_GROUPS(
SETTINGS_STATE_CREDENTIALS_SELECTED,
SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED));
791 ui_button(obj, .label =
"Move Up", .onclick = credentials_location_up, .groups =
UI_GROUPS(
SETTINGS_STATE_CREDENTIALS_SELECTED,
SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED));
792 ui_button(obj, .label =
"Move Down", .onclick = credentials_location_down, .groups =
UI_GROUPS(
SETTINGS_STATE_CREDENTIALS_SELECTED,
SETTINGS_STATE_CREDENTIALS_LOCATION_SELECTED));
793 }
794 }
795 }
796 }
797 }
798
799 ui_tab(obj,
"Keys") {
800 ui_hbox(obj, .margin =
16, .spacing =
30) {
801 ui_vbox(obj, .fill =
UI_OFF, .spacing =
4) {
802 ui_hbox(obj, .fill =
UI_OFF, .spacing =
4) {
803 ui_button(obj, .label =
"Add", .onclick = keys_add);
804 ui_button(obj, .label =
"Remove", .onclick = keys_remove, .groups =
UI_GROUPS(
SETTINGS_STATE_KEYS_SELECTED));
805 }
806 ui_listview(obj, .list = wdata->keys_list, .fill =
UI_ON, .onselection = keys_onselect, .getvalue = keylist_getvalue);
807 }
808
809 ui_grid(obj, .columnspacing =
30, .rowspacing =
10) {
810 ui_llabel(obj, .label =
"Identifier");
811 ui_textfield(obj, .value = wdata->key_name, .groups =
UI_GROUPS(
SETTINGS_STATE_KEYS_SELECTED));
812 ui_newline(obj);
813 ui_llabel(obj, .label =
"Type");
814 ui_textfield(obj, .value = wdata->key_type, .groups =
UI_GROUPS(
SETTINGS_STATE_DISABLED));
815 ui_newline(obj);
816 ui_llabel(obj, .label =
"File");
817 ui_textfield(obj, .value = wdata->key_file, .groups =
UI_GROUPS(
SETTINGS_STATE_KEYS_SELECTED));
818 }
819 }
820 }
821
822
823
824
825
826
827
828
829 }
830
831 ui_hbox(obj, .fill =
UI_OFF, .margin =
10) {
832 ui_button(obj, .label =
"Cancel", .onclick = settings_cancel);
833 ui_label(obj, .fill =
UI_ON);
834 ui_button(obj, .label =
"Save", .onclick = settings_ok);
835 }
836
837
838 ui_show(obj);
839 }
840
841 void settings_init(UiObject *obj, SettingsWindow *settings) {
842 settings->repos = ui_list_new(obj->ctx,
NULL);
843 settings->repo_tabview = ui_int_new(obj->ctx,
NULL);
844
845 settings->repo_name = ui_string_new(obj->ctx,
NULL);
846 settings->repo_url = ui_string_new(obj->ctx,
NULL);
847 settings->repo_user = ui_string_new(obj->ctx,
NULL);
848 settings->repo_password = ui_string_new(obj->ctx,
NULL);
849 settings->repo_cacert = ui_string_new(obj->ctx,
NULL);
850 settings->repo_credentials = ui_list_new(obj->ctx,
NULL);
851 settings->repo_keys = ui_list_new(obj->ctx,
NULL);
852 settings->repo_tls_versions = ui_list_new(obj->ctx,
NULL);
853 settings->repo_encryption = ui_int_new(obj->ctx,
NULL);
854 settings->repo_disable_verification = ui_int_new(obj->ctx,
NULL);
855 CxList *repo_keys = settings->repo_keys->data;
856 repo_keys->collection.cmpfunc = (cx_compare_func)strcmp;
857
858 ui_list_append(settings->repo_tls_versions,
"Default");
859 ui_list_append(settings->repo_tls_versions,
"TLSv1.3");
860 ui_list_append(settings->repo_tls_versions,
"TLSv1.2");
861 ui_list_append(settings->repo_tls_versions,
"TLSv1.1");
862 ui_list_append(settings->repo_tls_versions,
"TLSv1.0");
863
864 settings->credentials_selected_index = -
1;
865 settings->credentials_users = ui_list_new(obj->ctx,
NULL);
866 settings->credentials_locations = ui_list_new(obj->ctx,
NULL);
867 settings->credentials_id = ui_string_new(obj->ctx,
NULL);
868 settings->credentials_user = ui_string_new(obj->ctx,
NULL);
869 settings->credentials_password = ui_string_new(obj->ctx,
NULL);
870 CxList *credentials_users = settings->credentials_users->data;
871 CxList *credentials_locations = settings->credentials_locations->data;
872 credentials_users->collection.advanced_destructor = list_str_destructor;
873 credentials_users->collection.destructor_data = settings->obj->ctx;
874 credentials_users->collection.cmpfunc = (cx_compare_func)strcmp;
875 credentials_locations->collection.advanced_destructor = list_str_destructor;
876 credentials_locations->collection.destructor_data = settings->obj->ctx;
877 credentials_locations->collection.cmpfunc = (cx_compare_func)strcmp;
878
879 settings->keys_list = ui_list_new(obj->ctx,
NULL);
880 settings->key_name = ui_string_new(obj->ctx,
NULL);
881 settings->key_type = ui_string_new(obj->ctx,
NULL);
882 settings->key_file = ui_string_new(obj->ctx,
NULL);
883 settings->keys_selected_index = -
1;
884
885
886 settings_update_repolist(settings);
887 settings_reload_repo_keys(settings);
888 settings_reload_credentials(settings);
889 settings_reload_repo_credentials(settings);
890 settings_reload_keys(settings);
891
892 settings->selected_repo = -
1;
893 }
894
895 #define SETTINGS_SET_STRING(str, setting)
if(setting.value.ptr) ui_set(str, setting.value.ptr);
896
897
898
899 void settings_edit_repository(SettingsWindow *settings,
int repo_index) {
900 DavCfgRepository *repo = ui_list_get(settings->repos, repo_index);
901 if(!repo) {
902 fprintf(stderr,
"Error: cannot get repository at index %d\n", repo_index);
903 return;
904 }
905 settings->selected_repo = repo_index;
906
907
908 SETTINGS_SET_STRING(settings->repo_name, repo->name);
909 SETTINGS_SET_STRING(settings->repo_url, repo->url);
910 SETTINGS_SET_STRING(settings->repo_cacert, repo->cert);
911 SETTINGS_SET_STRING(settings->repo_user, repo->user);
912
913 if(repo->password.value.ptr) {
914 char *decoded_pw = util_base64decode(repo->password.value.ptr);
915 ui_set(settings->repo_password, decoded_pw);
916 size_t decoded_pw_len = strlen(decoded_pw);
917 memset(decoded_pw,
0, decoded_pw_len);
918 free(decoded_pw);
919 }
920
921
922 CxList *cred = settings->repo_credentials->data;
923 cred->collection.cmpfunc = (cx_compare_func)strcmp;
924 ssize_t cred_index = repo->stored_user.value.ptr ? cxListFind(cred, repo->stored_user.value.ptr) :
0;
925 if(cred_index >
0) {
926 ui_list_setselection(settings->repo_credentials, cred_index);
927 }
else {
928 ui_list_setselection(settings->repo_credentials,
0);
929 }
930
931
932 ui_set(settings->repo_encryption, repo->full_encryption.value);
933 CxList *keys = settings->repo_keys->data;
934 keys->collection.cmpfunc = (cx_compare_func)strcmp;
935 ssize_t key_index = repo->default_key.value.ptr ? cxListFind(keys, repo->default_key.value.ptr) :
0;
936 if(key_index >
0) {
937 ui_list_setselection(settings->repo_keys, key_index);
938 }
else {
939 ui_list_setselection(settings->repo_keys,
0);
940 }
941
942
943 CxList *tlsVersions = settings->repo_tls_versions->data;
944 tlsVersions->collection.cmpfunc = (cx_compare_func)strcmp;
945 const char *tls_str = dav_tlsversion2str(repo->ssl_version.value);
946 if(!tls_str) tls_str =
"";
947 ssize_t tlsv_index = cxListFind(tlsVersions, tls_str);
948 if(tlsv_index >
0) {
949 ui_list_setselection(settings->repo_tls_versions, tlsv_index);
950 }
else {
951 ui_list_setselection(settings->repo_tls_versions,
0);
952 }
953
954 if(!repo->verification.value) {
955 ui_set(settings->repo_disable_verification,
TRUE);
956 }
957
958
959
960 ui_set(settings->repo_tabview,
1);
961 }
962
963
964
965
966
967 static void cfg_string_set_value_or_remove(DavConfig *config, CfgString *str, xmlNode *parent, cxstring new_value,
const char *nodename) {
968 if(new_value.length ==
0) {
969 new_value.ptr =
NULL;
970 }
971 dav_cfg_string_set_value(config, str, parent, new_value, nodename);
972 if(!new_value.ptr) {
973 dav_cfg_string_remove(str);
974 }
975 }
976
977
978
979
980 static cxstring default_list_get_value(UiList *list) {
981 cxstring ret = {
NULL,
0 };
982 UiListSelection sel = ui_list_getselection(list);
983 if(sel.count >
0) {
984 int index = sel.rows[
0];
985 if(index >
0) {
986 ret = cx_str(ui_list_get(list, index));
987 }
988 free(sel.rows);
989 }
990 return ret;
991 }
992
993 void settings_store_repository(SettingsWindow *settings) {
994 DavConfig *config = settings->config;
995 DavCfgRepository *repo;
996 if(settings->repo_new) {
997 settings->repo_new =
FALSE;
998 char *name = ui_get(settings->repo_name);
999 if(strlen(name) ==
0) {
1000 return;
1001 }
1002 repo = dav_repository_new(config);
1003 dav_config_add_repository(config, repo);
1004 }
else if(settings->selected_repo >=
0) {
1005 repo = ui_list_get(settings->repos, settings->selected_repo);
1006 if(!repo) {
1007 fprintf(stderr,
"Error: cannot get repository at index %d\n", settings->selected_repo);
1008 return;
1009 }
1010 }
else {
1011 return;
1012 }
1013
1014
1015 dav_cfg_string_set_value(config, &repo->name, repo->node, cx_str(ui_get(settings->repo_name)),
"name");
1016 dav_cfg_string_set_value(config, &repo->url, repo->node, cx_str(ui_get(settings->repo_url)),
"url");
1017
1018 cfg_string_set_value_or_remove(config, &repo->user, repo->node, cx_str(ui_get(settings->repo_user)),
"user");
1019
1020 cfg_string_set_value_or_remove(config, &repo->cert, repo->node, cx_str(ui_get(settings->repo_cacert)),
"cert");
1021
1022
1023
1024 char *pw = ui_get(settings->repo_password);
1025 size_t pwlen = strlen(pw);
1026 if(pwlen >
0) {
1027 char *pwenc = util_base64encode(pw, pwlen);
1028 memset(pw,
0, pwlen);
1029 dav_cfg_string_set_value(config, &repo->password, repo->node, cx_str(pwenc),
"password");
1030 free(pwenc);
1031 }
else {
1032
1033 cfg_string_set_value_or_remove(config, &repo->password, repo->node, cx_strn(
NULL,
0),
"password");
1034 }
1035
1036
1037
1038 cxstring stored_user = default_list_get_value(settings->repo_credentials);
1039 cfg_string_set_value_or_remove(config, &repo->stored_user, repo->node, stored_user,
"stored-user");
1040
1041
1042 int encryption = ui_get(settings->repo_encryption);
1043 if(encryption || repo->full_encryption.node) {
1044 dav_cfg_bool_set_value(config, &repo->full_encryption, repo->node, encryption,
"full-encryption");
1045 }
1046
1047
1048 cxstring key = default_list_get_value(settings->repo_keys);
1049 cfg_string_set_value_or_remove(config, &repo->default_key, repo->node, key,
"default-key");
1050
1051
1052
1053 int disable_verification = ui_get(settings->repo_disable_verification);
1054 if(disable_verification) {
1055 dav_cfg_bool_set_value(config, &repo->verification, repo->node, !disable_verification,
"verification");
1056 }
else {
1057 dav_cfg_bool_remove(&repo->verification);
1058 }
1059
1060
1061 cxstring tlsversion_str = default_list_get_value(settings->repo_tls_versions);
1062 int tlsversion = dav_str2ssl_version(tlsversion_str.ptr);
1063 if(tlsversion >=
0) {
1064 dav_cfg_int_set_value(config, &repo->ssl_version, repo->node, tlsversion,
"ssl-version");
1065 }
else {
1066 dav_cfg_int_remove(&repo->ssl_version);
1067 }
1068
1069 settings_update_repolist(settings);
1070 settings->selected_repo = -
1;
1071 }
1072
1073 void settings_clear_repository(SettingsWindow *settings) {
1074 ui_set(settings->repo_name,
"");
1075 ui_set(settings->repo_url,
"");
1076 ui_set(settings->repo_user,
"");
1077 ui_set(settings->repo_password,
"");
1078 ui_set(settings->repo_cacert,
"");
1079 ui_list_setselection(settings->repo_credentials,
0);
1080 ui_list_setselection(settings->repo_keys,
0);
1081 ui_list_setselection(settings->repo_tls_versions,
0);
1082 ui_set(settings->repo_encryption,
0);
1083 ui_set(settings->repo_disable_verification,
0);
1084 }
1085
1086 void settings_update_repolist(SettingsWindow *settings) {
1087 DavConfig *config = settings->config;
1088
1089 ui_list_clear(settings->repos);
1090
1091 for (DavCfgRepository *repo = config->repositories; repo; repo = repo->next) {
1092 ui_list_append(settings->repos, repo);
1093 }
1094
1095 if(settings->repos->update) {
1096 ui_list_update(settings->repos);
1097 }
1098 }
1099
1100 void* settings_repolist_getvalue(DavCfgRepository *repo,
int col) {
1101 switch(col) {
1102 case 0: {
1103 return repo->name.value.ptr;
1104 }
1105 case 1: {
1106 return repo->url.value.ptr;
1107 }
1108 case 2: {
1109 return repo->user.value.ptr ? repo->user.value.ptr : repo->stored_user.value.ptr;
1110 }
1111 case 3: {
1112 return repo->full_encryption.value ?
"yes" :
"no";
1113 }
1114 }
1115 return NULL;
1116 }
1117
1118 void settings_reload_repo_keys(SettingsWindow *settings) {
1119 DavConfig *config = settings->config;
1120 DavCfgKey *key = config->keys;
1121 ui_list_clear(settings->repo_keys);
1122 ui_list_append(settings->repo_keys,
"-");
1123 while(key) {
1124 if(key->name.value.ptr) {
1125 ui_list_append(settings->repo_keys, key->name.value.ptr);
1126 }
1127 key = key->next;
1128 }
1129 ui_list_update(settings->repo_keys);
1130 }
1131
1132 void settings_reload_keys(SettingsWindow *settings) {
1133 DavConfig *config = settings->config;
1134 DavCfgKey *key = config->keys;
1135 ui_list_clear(settings->keys_list);
1136 while(key) {
1137 if(key->name.value.ptr) {
1138 ui_list_append(settings->keys_list, key);
1139 }
1140 key = key->next;
1141 }
1142 ui_list_update(settings->keys_list);
1143 }
1144
1145 const char* dav_tlsversion2str(
int value) {
1146 if(value == CURL_SSLVERSION_TLSv1) {
1147 return "TLSv1";
1148 }
else if(value == CURL_SSLVERSION_SSLv2) {
1149 return "SSLv2";
1150 }
else if(value == CURL_SSLVERSION_SSLv3) {
1151 return "SSLv3";
1152 }
1153 #if LIBCURL_VERSION_MAJOR *
1000 +
LIBCURL_VERSION_MINOR >=
7034
1154 else if(value == CURL_SSLVERSION_TLSv1_0) {
1155 return "TLSv1.0";
1156 }
else if(value == CURL_SSLVERSION_TLSv1_1) {
1157 return "TLSv1.1";
1158 }
else if(value == CURL_SSLVERSION_TLSv1_2) {
1159 return "TLSv1.2";
1160 }
1161 #endif
1162 #if LIBCURL_VERSION_MAJOR *
1000 +
LIBCURL_VERSION_MINOR >=
7052
1163 else if(value == CURL_SSLVERSION_TLSv1_3) {
1164 return "TLSv1.3";
1165 }
1166 #endif
1167 return NULL;
1168 }
1169
1170
1171
1172
1173 void settings_reload_credentials(SettingsWindow *settings) {
1174 PwdStore *pwd = settings->pwdstore;
1175
1176 ui_list_clear(settings->credentials_users);
1177
1178 CxIterator i = cxListIterator(pwd->noloc);
1179 cx_foreach(PwdIndexEntry*, entry, i) {
1180 char *id = ui_strdup(settings->obj->ctx, entry->id);
1181 ui_list_append(settings->credentials_users, id);
1182 }
1183 i = cxListIterator(pwd->locations);
1184 cx_foreach(PwdIndexEntry*, entry, i) {
1185 char *id = ui_strdup(settings->obj->ctx, entry->id);
1186 ui_list_append(settings->credentials_users, id);
1187 }
1188
1189 ui_list_update(settings->credentials_users);
1190 }
1191
1192 void settings_reload_repo_credentials(SettingsWindow *settings) {
1193 PwdStore *pwd = settings->pwdstore;
1194
1195 ui_list_clear(settings->repo_credentials);
1196
1197
1198 ui_list_append(settings->repo_credentials,
"-");
1199
1200 CxIterator i = cxListIterator(pwd->noloc);
1201 cx_foreach(PwdIndexEntry*, entry, i) {
1202 char *id = ui_strdup(settings->obj->ctx, entry->id);
1203 ui_list_append(settings->repo_credentials, id);
1204 }
1205 i = cxListIterator(pwd->locations);
1206 cx_foreach(PwdIndexEntry*, entry, i) {
1207 char *id = ui_strdup(settings->obj->ctx, entry->id);
1208 ui_list_append(settings->repo_credentials, id);
1209 }
1210
1211 ui_list_update(settings->repo_credentials);
1212 }
1213
1214
1215 void settings_credentials_select(SettingsWindow *settings,
const char *id) {
1216 if(!id && !settings->credentials_selected_id && !settings->credentials_new) {
1217 fprintf(stderr,
"Error: no credentials id selected\n");
1218 return;
1219 }
1220
1221 PwdStore *pwd = settings->pwdstore;
1222
1223 if(id) {
1224 ui_free(settings->obj->ctx, settings->credentials_selected_id);
1225 settings->credentials_selected_id = ui_strdup(settings->obj->ctx, id);
1226 }
1227
1228 if(!pwd->isdecrypted) {
1229 settings_credentials_decrypt(settings);
1230 return;
1231 }
1232
1233 if(settings->credentials_new) {
1234 ui_free(settings->obj->ctx, settings->credentials_selected_id);
1235 settings->credentials_selected_id =
NULL;
1236 settings->credentials_selected_index = ui_list_count(settings->credentials_users);
1237 ui_list_append(settings->credentials_users, ui_strdup(settings->obj->ctx,
"new"));
1238 settings->credentials_ignore_selectionevent =
TRUE;
1239 ui_list_update(settings->credentials_users);
1240 ui_list_setselection(settings->credentials_users, settings->credentials_selected_index);
1241 settings->credentials_ignore_selectionevent =
FALSE;
1242
1243 ui_set(settings->credentials_id,
"new");
1244 ui_set(settings->credentials_user,
"");
1245 ui_set(settings->credentials_password,
"");
1246 ui_list_clear(settings->credentials_locations);
1247 ui_list_update(settings->credentials_locations);
1248 }
else {
1249 PwdEntry *entry = cxMapGet(pwd->ids, settings->credentials_selected_id);
1250 PwdIndexEntry *index = cxMapGet(pwd->index, settings->credentials_selected_id);
1251 if(!entry) {
1252 fprintf(stderr,
"Error: cannot get pwd entry %s\n", settings->credentials_selected_id);
1253 return;
1254 }
1255 if(!index) {
1256 fprintf(stderr,
"Error: missing PwdIndexEntry. PwdStore may be broken.\n");
1257 return;
1258 }
1259
1260 ui_set(settings->credentials_id, entry->id);
1261 ui_set(settings->credentials_user, entry->user);
1262 ui_set(settings->credentials_password, entry->password);
1263
1264 ui_list_clear(settings->credentials_locations);
1265 if(index->locations) {
1266 CxIterator i = cxListIterator(index->locations);
1267 cx_foreach(
char *, loc, i) {
1268 ui_list_append(settings->credentials_locations, ui_strdup(settings->obj->ctx, loc));
1269 }
1270 }
1271 }
1272
1273 ui_list_update(settings->credentials_locations);
1274
1275 ui_set_group(settings->obj->ctx,
SETTINGS_STATE_CREDENTIALS_SELECTED);
1276 }
1277
1278 void settings_credentials_clear(SettingsWindow *settings) {
1279 ui_free(settings->obj->ctx, settings->credentials_selected_id);
1280 settings->credentials_selected_id =
NULL;
1281 settings->credentials_new =
FALSE;
1282
1283 ui_set(settings->credentials_id,
"");
1284 ui_set(settings->credentials_user,
"");
1285 ui_set(settings->credentials_password,
"");
1286 ui_list_clear(settings->credentials_locations);
1287 ui_list_update(settings->credentials_locations);
1288
1289 ui_unset_group(settings->obj->ctx,
SETTINGS_STATE_CREDENTIALS_SELECTED);
1290 }
1291
1292 int settings_credentials_save(SettingsWindow *settings) {
1293 if(settings->credentials_selected_index == -
1) {
1294 return 0;
1295 }
1296
1297
1298
1299
1300 char *newid = ui_get(settings->credentials_id);
1301 if(strlen(newid) ==
0) {
1302 return 0;
1303 }
1304
1305 ssize_t index = cxListFind(settings->credentials_users->data, newid);
1306 if(index >=
0 && index != settings->credentials_selected_index) {
1307 cxmutstr s = cx_asprintf(
"Identifier %s already in use", newid);
1308 ui_dialog(settings->obj, .title =
"Error", .content = s.ptr, .closebutton_label =
"OK");
1309 free(s.ptr);
1310 return 1;
1311 }
1312
1313 char *user = ui_get(settings->credentials_user);
1314 char *password = ui_get(settings->credentials_password);
1315 CxList *ui_locations = settings->credentials_locations->data;
1316 size_t numlocations = cxListSize(ui_locations);
1317 CxList *locations =
NULL;
1318 if(numlocations >
0) {
1319 locations = cxArrayListCreateSimple(
CX_STORE_POINTERS, numlocations);
1320 CxIterator i = cxListIterator(ui_locations);
1321 cx_foreach(
char*, loc, i) {
1322 cxListAdd(locations, strdup(loc));
1323 }
1324 }
1325
1326
1327 settings->credentials_list_needs_update = settings->credentials_new || strcmp(newid, settings->credentials_selected_id);
1328 if(settings->credentials_new || strcmp(newid, settings->credentials_selected_id ? settings->credentials_selected_id :
"")) {
1329 settings->credentials_list_needs_update =
TRUE;
1330 cxListRemove(settings->credentials_users->data, settings->credentials_selected_index);
1331 cxListInsert(settings->credentials_users->data, settings->credentials_selected_index, ui_strdup(settings->obj->ctx, newid));
1332 }
1333
1334
1335 if(settings->credentials_selected_id) {
1336 pwdstore_remove_entry(settings->pwdstore, settings->credentials_selected_id);
1337 }
1338
1339 pwdstore_put(settings->pwdstore, newid, user, password);
1340 pwdstore_put_index(settings->pwdstore, strdup(newid), locations);
1341 settings->credentials_modified =
TRUE;
1342 settings->credentials_new =
FALSE;
1343
1344 return 0;
1345 }
1346
1347 void *keylist_getvalue(
void *data,
int col) {
1348 DavCfgKey *key = data;
1349 return key->name.value.ptr;
1350 }
1351
1352 void settings_edit_key(SettingsWindow *settings, DavCfgKey *key) {
1353 if(key->name.value.ptr) {
1354 ui_set(settings->key_name, key->name.value.ptr);
1355 }
1356 const char *key_type;
1357 switch(key->type) {
1358 default: key_type =
"";
break;
1359 case DAV_KEY_TYPE_AES256: {
1360 key_type =
"AES256";
1361 break;
1362 }
1363 case DAV_KEY_TYPE_AES128: {
1364 key_type =
"AES128";
1365 break;
1366 }
1367 case DAV_KEY_TYPE_UNKNOWN: {
1368 key_type =
"unknown";
1369 break;
1370 }
1371 }
1372 ui_set(settings->key_type, key_type);
1373
1374 if(key->file.value.ptr) {
1375 ui_set(settings->key_file, key->file.value.ptr);
1376 }
1377 }
1378
1379 void settings_clear_key(SettingsWindow *settings) {
1380 ui_set(settings->key_name,
"");
1381 ui_set(settings->key_type,
"");
1382 ui_set(settings->key_file,
"");
1383 }
1384
1385