diff options
author | Christian Grothoff <christian@grothoff.org> | 2012-01-15 12:13:05 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2012-01-15 12:13:05 +0000 |
commit | 9dd6006e8de2c3231ba96318f3a12e1b1edfbb13 (patch) | |
tree | 02a7f6097ac6bfe8ba3d5b4dc86d77709035bdb5 | |
parent | 958d4aba0584eeb7557c0cafc7de229204556a08 (diff) | |
download | gnunet-gtk-9dd6006e8de2c3231ba96318f3a12e1b1edfbb13.tar.gz gnunet-gtk-9dd6006e8de2c3231ba96318f3a12e1b1edfbb13.zip |
-LRN: use progress dialog and dirmetascanner
-rw-r--r-- | contrib/Makefile.am | 1 | ||||
-rw-r--r-- | src/fs/gnunet-fs-gtk-main_window_file_publish.c | 1208 |
2 files changed, 471 insertions, 738 deletions
diff --git a/contrib/Makefile.am b/contrib/Makefile.am index e509e31f..4b6f8b4a 100644 --- a/contrib/Makefile.am +++ b/contrib/Makefile.am | |||
@@ -27,6 +27,7 @@ pkgdata_DATA = \ | |||
27 | gnunet_fs_gtk_publish_tab.glade \ | 27 | gnunet_fs_gtk_publish_tab.glade \ |
28 | gnunet_fs_gtk_search_tab.glade \ | 28 | gnunet_fs_gtk_search_tab.glade \ |
29 | gnunet_fs_gtk_select_pseudonym_dialog.glade \ | 29 | gnunet_fs_gtk_select_pseudonym_dialog.glade \ |
30 | gnunet_fs_gtk_progress_dialog.glade \ | ||
30 | gnunet_gtk_status_bar_menu.glade \ | 31 | gnunet_gtk_status_bar_menu.glade \ |
31 | gnunet_peerinfo_gtk_about_window.glade \ | 32 | gnunet_peerinfo_gtk_about_window.glade \ |
32 | gnunet_peerinfo_gtk_main_window.glade \ | 33 | gnunet_peerinfo_gtk_main_window.glade \ |
diff --git a/src/fs/gnunet-fs-gtk-main_window_file_publish.c b/src/fs/gnunet-fs-gtk-main_window_file_publish.c index 3cafc71e..502ddddc 100644 --- a/src/fs/gnunet-fs-gtk-main_window_file_publish.c +++ b/src/fs/gnunet-fs-gtk-main_window_file_publish.c | |||
@@ -30,6 +30,8 @@ | |||
30 | 30 | ||
31 | #define MARKER_DIR_FILE_SIZE "-" | 31 | #define MARKER_DIR_FILE_SIZE "-" |
32 | 32 | ||
33 | struct AddDirClientContext; | ||
34 | |||
33 | struct MainPublishingDialogContext | 35 | struct MainPublishingDialogContext |
34 | { | 36 | { |
35 | GtkBuilder *builder; | 37 | GtkBuilder *builder; |
@@ -44,6 +46,7 @@ struct MainPublishingDialogContext | |||
44 | GtkWidget *delete_button; | 46 | GtkWidget *delete_button; |
45 | GtkWidget *edit_button; | 47 | GtkWidget *edit_button; |
46 | GtkWidget *execute_button; | 48 | GtkWidget *execute_button; |
49 | GtkWidget *cancel_button; | ||
47 | GtkTreeView *file_info_treeview; | 50 | GtkTreeView *file_info_treeview; |
48 | GtkTreeSelection *file_info_selection; | 51 | GtkTreeSelection *file_info_selection; |
49 | GtkTreeModel *file_info_treemodel; | 52 | GtkTreeModel *file_info_treemodel; |
@@ -51,8 +54,53 @@ struct MainPublishingDialogContext | |||
51 | 54 | ||
52 | gulong open_directory_handler_id; | 55 | gulong open_directory_handler_id; |
53 | GtkBuilder *open_directory_builder; | 56 | GtkBuilder *open_directory_builder; |
54 | GtkBuilder *open_file_builder; | 57 | |
55 | gulong open_file_handler_id; | 58 | gulong open_file_handler_id; |
59 | GtkBuilder *open_file_builder; | ||
60 | |||
61 | /* To keep multiple scanners running */ | ||
62 | struct AddDirClientContext *adddir_head; | ||
63 | struct AddDirClientContext *adddir_tail; | ||
64 | }; | ||
65 | |||
66 | /* One of these is kept for every directory being opened */ | ||
67 | struct AddDirClientContext | ||
68 | { | ||
69 | struct AddDirClientContext *prev; | ||
70 | struct AddDirClientContext *next; | ||
71 | |||
72 | /** | ||
73 | * GNUNET_YES if the user asked to cancel the processing. | ||
74 | * If so, wrap up as fast as possible and close the progress dialog. | ||
75 | */ | ||
76 | int cancelling; | ||
77 | |||
78 | /** | ||
79 | * GNUNET_YES if there was something during the scan that might | ||
80 | * need user's attention. Prevents the dialog from closing, unless | ||
81 | * the process was cancelled. | ||
82 | */ | ||
83 | int keep; | ||
84 | |||
85 | struct ProcessMetadataContext *pmc; | ||
86 | |||
87 | struct MainPublishingDialogContext *ctx; | ||
88 | struct GNUNET_FS_DirScanner *ds; | ||
89 | |||
90 | struct ShareTreeItem *directory_scan_result; | ||
91 | struct ShareTreeItem *directory_scan_intermediary_result; | ||
92 | |||
93 | struct GNUNET_FS_BlockOptions directory_scan_bo; | ||
94 | int directory_scan_do_index; | ||
95 | |||
96 | GtkBuilder *progress_dialog_builder; | ||
97 | GtkWidget *progress_dialog; | ||
98 | GtkProgressBar *progress_dialog_bar; | ||
99 | GtkButton *progress_dialog_ok; | ||
100 | GtkButton *progress_dialog_cancel; | ||
101 | GtkTextView *progress_dialog_textview; | ||
102 | GtkTextBuffer *progress_dialog_textbuffer; | ||
103 | GtkTextMark *progress_dialog_textmark; | ||
56 | }; | 104 | }; |
57 | 105 | ||
58 | void | 106 | void |
@@ -87,6 +135,7 @@ gtk_tree_iter_equals (GtkTreeModel * tm, GtkTreeIter * i1, GtkTreeIter * i2) | |||
87 | return (0 == ret) ? GNUNET_YES : GNUNET_NO; | 135 | return (0 == ret) ? GNUNET_YES : GNUNET_NO; |
88 | } | 136 | } |
89 | 137 | ||
138 | /* Fill out the main publishing dialog context structure */ | ||
90 | static void | 139 | static void |
91 | init_ctx (struct MainPublishingDialogContext *ctx) | 140 | init_ctx (struct MainPublishingDialogContext *ctx) |
92 | { | 141 | { |
@@ -107,6 +156,8 @@ init_ctx (struct MainPublishingDialogContext *ctx) | |||
107 | (ctx->builder, "GNUNET_GTK_master_publish_dialog_edit_button")); | 156 | (ctx->builder, "GNUNET_GTK_master_publish_dialog_edit_button")); |
108 | ctx->execute_button = GTK_WIDGET (gtk_builder_get_object | 157 | ctx->execute_button = GTK_WIDGET (gtk_builder_get_object |
109 | (ctx->builder, "GNUNET_GTK_master_publish_dialog_execute_button")); | 158 | (ctx->builder, "GNUNET_GTK_master_publish_dialog_execute_button")); |
159 | ctx->cancel_button = GTK_WIDGET (gtk_builder_get_object | ||
160 | (ctx->builder , "GNUNET_GTK_master_publish_dialog_cancel_button")); | ||
110 | ctx->file_info_treeview = GTK_TREE_VIEW (gtk_builder_get_object | 161 | ctx->file_info_treeview = GTK_TREE_VIEW (gtk_builder_get_object |
111 | (ctx->builder, "GNUNET_GTK_master_publish_dialog_file_information_tree_view")); | 162 | (ctx->builder, "GNUNET_GTK_master_publish_dialog_file_information_tree_view")); |
112 | 163 | ||
@@ -148,10 +199,18 @@ update_selectivity (struct MainPublishingDialogContext *ctx) | |||
148 | else | 199 | else |
149 | g_free (namespace_id); | 200 | g_free (namespace_id); |
150 | } | 201 | } |
151 | if ((gtk_tree_model_get_iter_first (ctx->file_info_treemodel, &iter)) && (ns_ok == GNUNET_YES)) | 202 | /* Don't let the user close the dialog until all scanners are finished and |
203 | * their windows are closed | ||
204 | */ | ||
205 | if ((gtk_tree_model_get_iter_first (ctx->file_info_treemodel, &iter)) | ||
206 | && (ns_ok == GNUNET_YES) && ctx->adddir_head == NULL) | ||
152 | gtk_widget_set_sensitive (ctx->execute_button, TRUE); | 207 | gtk_widget_set_sensitive (ctx->execute_button, TRUE); |
153 | else | 208 | else |
154 | gtk_widget_set_sensitive (ctx->execute_button, FALSE); | 209 | gtk_widget_set_sensitive (ctx->execute_button, FALSE); |
210 | if (ctx->adddir_head == NULL) | ||
211 | gtk_widget_set_sensitive (ctx->cancel_button, TRUE); | ||
212 | else | ||
213 | gtk_widget_set_sensitive (ctx->cancel_button, FALSE); | ||
155 | if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter)) | 214 | if (TRUE != gtk_tree_selection_get_selected (ctx->file_info_selection, NULL, &iter)) |
156 | { | 215 | { |
157 | gtk_widget_set_sensitive (ctx->up_button, FALSE); | 216 | gtk_widget_set_sensitive (ctx->up_button, FALSE); |
@@ -239,6 +298,10 @@ add_file_at_iter (struct MainPublishingDialogContext *ctx, const char *filename, | |||
239 | const char *ss; | 298 | const char *ss; |
240 | struct stat sbuf; | 299 | struct stat sbuf; |
241 | 300 | ||
301 | /* TODO: make directory scanner capable of scanning single files and use | ||
302 | * it instead | ||
303 | */ | ||
304 | |||
242 | if (0 != STAT (filename, &sbuf)) | 305 | if (0 != STAT (filename, &sbuf)) |
243 | return; | 306 | return; |
244 | if (S_ISDIR (sbuf.st_mode)) | 307 | if (S_ISDIR (sbuf.st_mode)) |
@@ -332,735 +395,12 @@ create_dir_at_iter (struct MainPublishingDialogContext *ctx, const char *name, | |||
332 | update_selectivity (ctx); | 395 | update_selectivity (ctx); |
333 | } | 396 | } |
334 | 397 | ||
335 | |||
336 | /* ************ code for adding directories starts ************* */ | ||
337 | |||
338 | |||
339 | /** | ||
340 | * Data we keep when calculating the publication details for a file. | ||
341 | */ | ||
342 | struct PublishData | ||
343 | { | ||
344 | /** | ||
345 | * Metadata for the file. | ||
346 | */ | ||
347 | struct GNUNET_CONTAINER_MetaData *meta; | ||
348 | |||
349 | /** | ||
350 | * Keywords for the file (derived from metadata). | ||
351 | */ | ||
352 | struct GNUNET_FS_Uri *ksk_uri; | ||
353 | |||
354 | /** | ||
355 | * Iterator for the entry. | ||
356 | */ | ||
357 | GtkTreeIter iter; | ||
358 | }; | ||
359 | |||
360 | |||
361 | /** | ||
362 | * Entry for each unique keyword to track how often | ||
363 | * it occured. Contains the keyword and the counter. | ||
364 | */ | ||
365 | struct KeywordCounter | ||
366 | { | ||
367 | |||
368 | /** | ||
369 | * Keyword that was found. | ||
370 | */ | ||
371 | const char *value; | ||
372 | |||
373 | /** | ||
374 | * How many files have meta entries matching this value? | ||
375 | * (type and format do not have to match). | ||
376 | */ | ||
377 | unsigned int count; | ||
378 | |||
379 | }; | ||
380 | |||
381 | |||
382 | /** | ||
383 | * Execution context for 'add_dir' | ||
384 | */ | ||
385 | struct AddDirContext | ||
386 | { | ||
387 | /** | ||
388 | * While scanning, 'parent' is the iter entry for the | ||
389 | * parent, or NULL for top-level. | ||
390 | */ | ||
391 | GtkTreeIter *parent; | ||
392 | |||
393 | /** | ||
394 | * Pointer to the context of the parent directory, or NULL | ||
395 | * for top-level. | ||
396 | */ | ||
397 | struct AddDirContext *parent_ctx; | ||
398 | |||
399 | /** | ||
400 | * Directory iterator of the parent directory, or NULL | ||
401 | * for top-level. | ||
402 | */ | ||
403 | struct GNUNET_DISK_DirectoryIterator *parent_iter; | ||
404 | |||
405 | /** | ||
406 | * Filename parent directory was processing (filename of THIS directory) | ||
407 | * when it started child directory iterator. NULL for top-level. | ||
408 | */ | ||
409 | char *parent_filename; | ||
410 | |||
411 | /** | ||
412 | * Publication data for this directory. | ||
413 | */ | ||
414 | struct PublishData *pd; | ||
415 | |||
416 | /** | ||
417 | * Master publication dialog context (used to access treestore) | ||
418 | */ | ||
419 | struct MainPublishingDialogContext *ctx; | ||
420 | |||
421 | /** | ||
422 | * Map from the hash over the keyword to an 'struct KeywordCounter' | ||
423 | * counter that says how often this keyword was | ||
424 | * encountered in the current directory. | ||
425 | */ | ||
426 | struct GNUNET_CONTAINER_MultiHashMap *keywordcounter; | ||
427 | |||
428 | /** | ||
429 | * Map from the hash of a filename in the current directory | ||
430 | * to the 'struct PublishData*' for the file. | ||
431 | */ | ||
432 | struct GNUNET_CONTAINER_MultiHashMap *metamap; | ||
433 | |||
434 | /** | ||
435 | * Keywords to exclude from using for KSK since they'll be associated | ||
436 | * with the parent as well. NULL for nothing blocked. | ||
437 | */ | ||
438 | struct GNUNET_FS_Uri *exclude_ksk; | ||
439 | |||
440 | /** | ||
441 | * Block options to use. | ||
442 | */ | ||
443 | struct GNUNET_FS_BlockOptions bo; | ||
444 | |||
445 | /** | ||
446 | * Index or insert? | ||
447 | */ | ||
448 | int do_index; | ||
449 | |||
450 | /** | ||
451 | * Number of files in the current directory. | ||
452 | */ | ||
453 | unsigned int dir_entry_count; | ||
454 | }; | ||
455 | |||
456 | |||
457 | /** | ||
458 | * Add the given keyword to the | ||
459 | * keyword statistics tracker. | ||
460 | * | ||
461 | * @param cls closure (user-defined) | ||
462 | * @param keyword the keyword to count | ||
463 | * @param is_mandatory ignored | ||
464 | * @return always GNUNET_OK | ||
465 | */ | ||
466 | static int | ||
467 | add_to_keyword_counter (void *cls, const char *keyword, int is_mandatory) | ||
468 | { | ||
469 | struct GNUNET_CONTAINER_MultiHashMap *mcm = cls; | ||
470 | struct KeywordCounter *cnt; | ||
471 | GNUNET_HashCode hc; | ||
472 | size_t klen; | ||
473 | |||
474 | klen = strlen (keyword) + 1; | ||
475 | GNUNET_CRYPTO_hash (keyword, klen - 1, &hc); | ||
476 | cnt = GNUNET_CONTAINER_multihashmap_get (mcm, &hc); | ||
477 | if (cnt == NULL) | ||
478 | { | ||
479 | cnt = GNUNET_malloc (sizeof (struct KeywordCounter) + klen); | ||
480 | cnt->count = 1; | ||
481 | cnt->value = (const char *) &cnt[1]; | ||
482 | memcpy (&cnt[1], keyword, klen); | ||
483 | GNUNET_CONTAINER_multihashmap_put (mcm, &hc, cnt, | ||
484 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
485 | } | ||
486 | else | ||
487 | { | ||
488 | cnt->count++; | ||
489 | } | ||
490 | return GNUNET_OK; | ||
491 | } | ||
492 | |||
493 | |||
494 | /** | ||
495 | * Extract metadata from a file and add it to the metamap and | ||
496 | * the keywordcounter. | ||
497 | * | ||
498 | * @param adc context to modify | ||
499 | * @param filename name of the file to process | ||
500 | */ | ||
501 | static void | ||
502 | extract_file (struct AddDirContext *adc, const char *filename) | ||
503 | { | ||
504 | struct PublishData *pd; | ||
505 | GNUNET_HashCode hc; | ||
506 | const char *short_fn; | ||
507 | const char *ss; | ||
508 | |||
509 | adc->dir_entry_count++; | ||
510 | pd = GNUNET_malloc (sizeof (struct PublishData)); | ||
511 | pd->meta = GNUNET_CONTAINER_meta_data_create (); | ||
512 | GNUNET_FS_meta_data_extract_from_file (pd->meta, filename, | ||
513 | GNUNET_FS_GTK_get_le_plugins ()); | ||
514 | GNUNET_CONTAINER_meta_data_delete (pd->meta, EXTRACTOR_METATYPE_FILENAME, | ||
515 | NULL, 0); | ||
516 | short_fn = filename; | ||
517 | while (NULL != (ss = strstr (short_fn, DIR_SEPARATOR_STR))) | ||
518 | short_fn = 1 + ss; | ||
519 | GNUNET_CONTAINER_meta_data_insert (pd->meta, "<gnunet-gtk>", | ||
520 | EXTRACTOR_METATYPE_FILENAME, | ||
521 | EXTRACTOR_METAFORMAT_UTF8, "text/plain", | ||
522 | short_fn, strlen (short_fn) + 1); | ||
523 | |||
524 | gtk_tree_store_insert_before (GTK_TREE_STORE (adc->ctx->file_info_treemodel), &pd->iter, adc->parent, NULL); | ||
525 | |||
526 | GNUNET_CRYPTO_hash (filename, strlen (filename), &hc); | ||
527 | GNUNET_CONTAINER_multihashmap_put (adc->metamap, &hc, pd, | ||
528 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
529 | /* FIXME: what if this put fails? I think it actually can... Why unique only? */ | ||
530 | pd->ksk_uri = GNUNET_FS_uri_ksk_create_from_meta_data (pd->meta); | ||
531 | GNUNET_FS_uri_ksk_get_keywords (pd->ksk_uri, &add_to_keyword_counter, adc->keywordcounter); | ||
532 | } | ||
533 | |||
534 | |||
535 | /** | ||
536 | * Remove the keyword from the ksk URI. | ||
537 | * | ||
538 | * @param cls the ksk uri | ||
539 | * @param keyword the word to remove | ||
540 | * @param is_mandatory ignored | ||
541 | * @return always GNUNET_OK | ||
542 | */ | ||
543 | static int | ||
544 | remove_keyword (void *cls, const char *keyword, int is_mandatory) | ||
545 | { | ||
546 | struct GNUNET_FS_Uri *ksk = cls; | ||
547 | |||
548 | GNUNET_FS_uri_ksk_remove_keyword (ksk, keyword); | ||
549 | return GNUNET_OK; | ||
550 | } | ||
551 | |||
552 | |||
553 | /** | ||
554 | * Add the specifics of the given entry to the tree store. | ||
555 | * Use keywords from ksk_uri, but exclude the ones given in | ||
556 | * "md_no_ksk". | ||
557 | * | ||
558 | * @param ts tree store to modify | ||
559 | * @param iter position in the tree store for this file | ||
560 | * @param filename file to add | ||
561 | * @param bo block options | ||
562 | * @param do_index should we index or insert? | ||
563 | * @param ksk_uri keywords to use. Will be destroyed at the end. | ||
564 | * @param exclude_ksk keywords NOT to use. Won't be modified. | ||
565 | * @param meta metadata for the file. Will be destroyed at the end. | ||
566 | */ | ||
567 | static void | ||
568 | add_entry_to_ts (GtkTreeStore * ts, GtkTreeIter * iter, const char *filename, | ||
569 | const struct GNUNET_FS_BlockOptions *bo, int do_index, | ||
570 | struct GNUNET_FS_Uri *ksk_uri, struct GNUNET_FS_Uri *exclude_ksk, | ||
571 | struct GNUNET_CONTAINER_MetaData *meta) | ||
572 | { | ||
573 | char *file_size_fancy; | ||
574 | struct GNUNET_FS_FileInformation *fi; | ||
575 | GtkTreeRowReference *row_reference; | ||
576 | GtkTreePath *path; | ||
577 | uint64_t file_size; | ||
578 | const char *ss; | ||
579 | const char *short_fn; | ||
580 | struct stat sbuf; | ||
581 | |||
582 | if (0 != STAT (filename, &sbuf)) | ||
583 | return; | ||
584 | if (S_ISDIR (sbuf.st_mode)) | ||
585 | { | ||
586 | file_size = 0; | ||
587 | } | ||
588 | else | ||
589 | { | ||
590 | if (GNUNET_OK != GNUNET_DISK_file_size (filename, &file_size, GNUNET_YES)) | ||
591 | { | ||
592 | GNUNET_break (0); | ||
593 | return; | ||
594 | } | ||
595 | } | ||
596 | if (exclude_ksk != NULL) | ||
597 | { | ||
598 | GNUNET_FS_uri_ksk_get_keywords (exclude_ksk, &remove_keyword, ksk_uri); | ||
599 | } | ||
600 | path = gtk_tree_model_get_path (GTK_TREE_MODEL (ts), iter); | ||
601 | row_reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (ts), path); | ||
602 | gtk_tree_path_free (path); | ||
603 | if (S_ISDIR (sbuf.st_mode)) | ||
604 | { | ||
605 | GNUNET_CONTAINER_meta_data_delete (meta, EXTRACTOR_METATYPE_MIMETYPE, NULL, | ||
606 | 0); | ||
607 | GNUNET_FS_meta_data_make_directory (meta); | ||
608 | GNUNET_FS_uri_ksk_add_keyword (ksk_uri, GNUNET_FS_DIRECTORY_MIME, | ||
609 | GNUNET_NO); | ||
610 | fi = GNUNET_FS_file_information_create_empty_directory | ||
611 | (GNUNET_FS_GTK_get_fs_handle (), row_reference, ksk_uri, meta, bo, filename); | ||
612 | } | ||
613 | else | ||
614 | { | ||
615 | fi = GNUNET_FS_file_information_create_from_file | ||
616 | (GNUNET_FS_GTK_get_fs_handle (), row_reference, filename, ksk_uri, meta, | ||
617 | do_index, bo); | ||
618 | } | ||
619 | GNUNET_CONTAINER_meta_data_destroy (meta); | ||
620 | GNUNET_FS_uri_destroy (ksk_uri); | ||
621 | if (S_ISDIR (sbuf.st_mode)) | ||
622 | file_size_fancy = GNUNET_strdup (MARKER_DIR_FILE_SIZE); | ||
623 | else | ||
624 | file_size_fancy = GNUNET_STRINGS_byte_size_fancy (file_size); | ||
625 | short_fn = filename; | ||
626 | while (NULL != (ss = strstr (short_fn, DIR_SEPARATOR_STR))) | ||
627 | short_fn = 1 + ss; | ||
628 | gtk_tree_store_set (ts, iter, 0, file_size_fancy, 1, (gboolean) do_index, 2, | ||
629 | short_fn, 3, (guint) bo->anonymity_level, 4, | ||
630 | (guint) bo->content_priority, 5, fi, | ||
631 | 6, (guint64) bo->expiration_time.abs_value, | ||
632 | 7, (guint) bo->replication_level, -1); | ||
633 | GNUNET_free (file_size_fancy); | ||
634 | } | ||
635 | |||
636 | |||
637 | #if DEAD_CODE | ||
638 | /** | ||
639 | * Function called by the directory iterator to | ||
640 | * (recursively) add all of the files in the | ||
641 | * directory to the tree. | ||
642 | * | ||
643 | * @param cls the 'struct AddDirContext*' we're in | ||
644 | * @param filename file or directory to scan | ||
645 | */ | ||
646 | static int | ||
647 | publish_entry (void *cls, const char *filename) | ||
648 | { | ||
649 | struct AddDirContext *adc = cls; | ||
650 | struct PublishData *pd; | ||
651 | GNUNET_HashCode hc; | ||
652 | |||
653 | GNUNET_CRYPTO_hash (filename, strlen (filename), &hc); | ||
654 | pd = GNUNET_CONTAINER_multihashmap_get (adc->metamap, &hc); | ||
655 | add_entry_to_ts (GTK_TREE_STORE (adc->ctx->file_info_treemodel), &pd->iter, filename, &adc->bo, adc->do_index, | ||
656 | pd->ksk_uri, adc->exclude_ksk, pd->meta); | ||
657 | GNUNET_CONTAINER_multihashmap_remove (adc->metamap, &hc, pd); | ||
658 | GNUNET_free (pd); | ||
659 | return GNUNET_OK; | ||
660 | } | ||
661 | #endif | ||
662 | |||
663 | |||
664 | /** | ||
665 | * Context passed to 'migrate_and_drop'. | ||
666 | */ | ||
667 | struct KeywordProcessContext | ||
668 | { | ||
669 | /** | ||
670 | * All the keywords we migrated to the parent. | ||
671 | */ | ||
672 | struct GNUNET_FS_Uri *ksk; | ||
673 | |||
674 | /** | ||
675 | * How often does a keyword have to occur to be | ||
676 | * migrated to the parent? | ||
677 | */ | ||
678 | unsigned int threshold; | ||
679 | }; | ||
680 | |||
681 | |||
682 | /** | ||
683 | * Copy "frequent" keywords over to the | ||
684 | * target ksk uri, free the counters. | ||
685 | * | ||
686 | */ | ||
687 | static int | ||
688 | migrate_and_drop (void *cls, const GNUNET_HashCode * key, void *value) | ||
689 | { | ||
690 | struct KeywordProcessContext *kpc = cls; | ||
691 | struct KeywordCounter *counter = value; | ||
692 | |||
693 | if (counter->count >= kpc->threshold && counter->count > 1) | ||
694 | { | ||
695 | GNUNET_FS_uri_ksk_add_keyword (kpc->ksk, counter->value, GNUNET_NO); | ||
696 | } | ||
697 | GNUNET_free (counter); | ||
698 | return GNUNET_YES; | ||
699 | } | ||
700 | |||
701 | |||
702 | /** | ||
703 | * Go over the collected keywords from all entries in the | ||
704 | * directory and push common keywords up one level (by | ||
705 | * adding it to the returned struct). | ||
706 | * | ||
707 | * @param adc collection of child meta data | ||
708 | * @return meta data to moved to parent | ||
709 | */ | ||
710 | static struct GNUNET_FS_Uri * | ||
711 | process_keywords (struct AddDirContext *adc) | ||
712 | { | ||
713 | struct KeywordProcessContext kpc; | ||
714 | struct GNUNET_CONTAINER_MetaData *tmp; | ||
715 | |||
716 | tmp = GNUNET_CONTAINER_meta_data_create (); | ||
717 | |||
718 | /* Surprisingly, it's impossible to create a ksk with 0 keywords directly. | ||
719 | * But we can create one from an empty metadata set | ||
720 | */ | ||
721 | kpc.ksk = GNUNET_FS_uri_ksk_create_from_meta_data (tmp); | ||
722 | GNUNET_CONTAINER_meta_data_destroy (tmp); | ||
723 | kpc.threshold = (adc->dir_entry_count + 1) / 2; /* 50% */ | ||
724 | GNUNET_CONTAINER_multihashmap_iterate (adc->keywordcounter, &migrate_and_drop, | ||
725 | &kpc); | ||
726 | GNUNET_CONTAINER_multihashmap_destroy (adc->keywordcounter); | ||
727 | return kpc.ksk; | ||
728 | } | ||
729 | |||
730 | |||
731 | #if DEAD_CODE | ||
732 | /** | ||
733 | * Function called by the directory iterator to | ||
734 | * (recursively) add all of the files in the | ||
735 | * directory to the tree. | ||
736 | * | ||
737 | * @param cls the 'struct AddDirContext*' we're in | ||
738 | * @param filename file or directory to scan | ||
739 | */ | ||
740 | static int | ||
741 | scan_directory (void *cls, const char *filename) | ||
742 | { | ||
743 | struct AddDirContext *adc = cls; | ||
744 | struct stat sbuf; | ||
745 | GtkTreeIter *parent; | ||
746 | struct PublishData *pd; | ||
747 | GNUNET_HashCode hc; | ||
748 | struct GNUNET_CONTAINER_MultiHashMap *mhm; | ||
749 | struct GNUNET_CONTAINER_MultiHashMap *kcm; | ||
750 | unsigned int pc; | ||
751 | const char *ss; | ||
752 | const char *short_fn; | ||
753 | const char *user; | ||
754 | |||
755 | if (0 != STAT (filename, &sbuf)) | ||
756 | return GNUNET_OK; | ||
757 | if (S_ISDIR (sbuf.st_mode)) | ||
758 | { | ||
759 | parent = adc->parent; | ||
760 | mhm = adc->metamap; | ||
761 | kcm = adc->keywordcounter; | ||
762 | pc = adc->dir_entry_count; | ||
763 | adc->metamap = GNUNET_CONTAINER_multihashmap_create (1024); | ||
764 | adc->keywordcounter = GNUNET_CONTAINER_multihashmap_create (1024); | ||
765 | adc->dir_entry_count = 0; | ||
766 | pd = GNUNET_malloc (sizeof (struct PublishData)); | ||
767 | gtk_tree_store_insert_before (GTK_TREE_STORE (adc->ctx->file_info_treemodel), &pd->iter, parent, NULL); | ||
768 | adc->parent = &pd->iter; | ||
769 | GNUNET_DISK_directory_scan (filename, &scan_directory, adc); | ||
770 | pd->ksk_uri = process_keywords (adc); | ||
771 | pd->meta = GNUNET_CONTAINER_meta_data_create (); | ||
772 | adc->exclude_ksk = GNUNET_FS_uri_dup (pd->ksk_uri); | ||
773 | GNUNET_DISK_directory_scan (filename, &publish_entry, adc); | ||
774 | GNUNET_CONTAINER_multihashmap_destroy (adc->metamap); | ||
775 | adc->metamap = mhm; | ||
776 | adc->keywordcounter = kcm; | ||
777 | adc->parent = parent; | ||
778 | adc->dir_entry_count = pc + 1; | ||
779 | short_fn = filename; | ||
780 | while ( (NULL != (ss = strstr (short_fn, DIR_SEPARATOR_STR))) && | ||
781 | (ss[1] != '\0') ) | ||
782 | short_fn = 1 + ss; | ||
783 | user = getenv ("USER"); | ||
784 | if ( (user == NULL) || | ||
785 | (0 != strncasecmp (user, | ||
786 | short_fn, | ||
787 | strlen(user))) ) | ||
788 | { | ||
789 | /* only use filename if it doesn't match $USER */ | ||
790 | GNUNET_CONTAINER_meta_data_insert (pd->meta, "<gnunet-gtk>", | ||
791 | EXTRACTOR_METATYPE_FILENAME, | ||
792 | EXTRACTOR_METAFORMAT_UTF8, | ||
793 | "text/plain", short_fn, | ||
794 | strlen (short_fn) + 1); | ||
795 | GNUNET_CONTAINER_meta_data_insert (pd->meta, "<gnunet-gtk>", | ||
796 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, | ||
797 | EXTRACTOR_METAFORMAT_UTF8, | ||
798 | "text/plain", short_fn, | ||
799 | strlen (short_fn) + 1); | ||
800 | } | ||
801 | if (adc->metamap != NULL) | ||
802 | { | ||
803 | GNUNET_CRYPTO_hash (filename, strlen (filename), &hc); | ||
804 | GNUNET_CONTAINER_multihashmap_put (adc->metamap, &hc, pd, | ||
805 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
806 | /* FIXME: what if this put fails? I think it actually can... Why unique only? */ | ||
807 | GNUNET_FS_uri_ksk_get_keywords (pd->ksk_uri, &add_to_keyword_counter, kcm); | ||
808 | } | ||
809 | else | ||
810 | { | ||
811 | GNUNET_assert (kcm == NULL); | ||
812 | add_entry_to_ts (GTK_TREE_STORE (adc->ctx->file_info_treemodel), &pd->iter, filename, &adc->bo, adc->do_index, | ||
813 | pd->ksk_uri, NULL, pd->meta); | ||
814 | } | ||
815 | GNUNET_FS_uri_destroy (adc->exclude_ksk); | ||
816 | } | ||
817 | else | ||
818 | { | ||
819 | GNUNET_assert (adc->metamap != NULL); | ||
820 | extract_file (adc, filename); | ||
821 | } | ||
822 | return GNUNET_OK; | ||
823 | } | ||
824 | #endif | ||
825 | |||
826 | |||
827 | static void | ||
828 | add_dir_callback (void *cls, struct GNUNET_DISK_DirectoryIterator * di, | ||
829 | const char *filename, const char *dirname); | ||
830 | |||
831 | |||
832 | static void | ||
833 | child_dir_finished_publishing (struct AddDirContext *adc) | ||
834 | { | ||
835 | const char *ss; | ||
836 | const char *short_fn; | ||
837 | const char *user; | ||
838 | GNUNET_HashCode hc; | ||
839 | |||
840 | GNUNET_CONTAINER_multihashmap_destroy (adc->metamap); | ||
841 | if (adc->parent_ctx) | ||
842 | adc->parent_ctx->dir_entry_count += 1; | ||
843 | short_fn = adc->parent_filename; | ||
844 | while ( (NULL != (ss = strstr (short_fn, DIR_SEPARATOR_STR))) && | ||
845 | (ss[1] != '\0') ) | ||
846 | short_fn = 1 + ss; | ||
847 | user = getenv ("USER"); | ||
848 | if ((user == NULL) || (0 != strncasecmp (user, short_fn, strlen(user)))) | ||
849 | { | ||
850 | /* only use filename if it doesn't match $USER */ | ||
851 | GNUNET_CONTAINER_meta_data_insert (adc->pd->meta, "<gnunet-gtk>", | ||
852 | EXTRACTOR_METATYPE_FILENAME, | ||
853 | EXTRACTOR_METAFORMAT_UTF8, | ||
854 | "text/plain", short_fn, | ||
855 | strlen (short_fn) + 1); | ||
856 | GNUNET_CONTAINER_meta_data_insert (adc->pd->meta, "<gnunet-gtk>", | ||
857 | EXTRACTOR_METATYPE_GNUNET_ORIGINAL_FILENAME, | ||
858 | EXTRACTOR_METAFORMAT_UTF8, | ||
859 | "text/plain", short_fn, | ||
860 | strlen (short_fn) + 1); | ||
861 | } | ||
862 | if (adc->parent_ctx != NULL) | ||
863 | { | ||
864 | if (adc->parent_ctx->metamap != NULL) | ||
865 | { | ||
866 | GNUNET_CRYPTO_hash (adc->parent_filename, strlen (adc->parent_filename), &hc); | ||
867 | GNUNET_CONTAINER_multihashmap_put (adc->parent_ctx->metamap, &hc, adc->pd, | ||
868 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | ||
869 | /* FIXME: what if this put fails? I think it actually can... Why unique only? */ | ||
870 | GNUNET_FS_uri_ksk_get_keywords (adc->pd->ksk_uri, &add_to_keyword_counter, adc->parent_ctx->keywordcounter); | ||
871 | } | ||
872 | else | ||
873 | { | ||
874 | GNUNET_assert (adc->parent_ctx->keywordcounter == NULL); | ||
875 | add_entry_to_ts (GTK_TREE_STORE (adc->ctx->file_info_treemodel), | ||
876 | &adc->pd->iter, adc->parent_filename, &adc->bo, adc->do_index, | ||
877 | adc->pd->ksk_uri, NULL, adc->pd->meta); | ||
878 | } | ||
879 | } | ||
880 | GNUNET_FS_uri_destroy (adc->exclude_ksk); | ||
881 | if (adc->parent_ctx != NULL) | ||
882 | add_dir_callback (adc->parent_ctx, adc->parent_iter, | ||
883 | adc->parent_filename, NULL); | ||
884 | GNUNET_free_non_null (adc->parent_filename); | ||
885 | GNUNET_free (adc); | ||
886 | } | ||
887 | |||
888 | static void | ||
889 | publish_dir_callback (void *cls, struct GNUNET_DISK_DirectoryIterator *di, | ||
890 | const char *filename, const char *dirname) | ||
891 | { | ||
892 | struct AddDirContext *adc = cls; | ||
893 | struct PublishData *pd; | ||
894 | GNUNET_HashCode hc; | ||
895 | struct stat sbuf; | ||
896 | |||
897 | GNUNET_CRYPTO_hash (filename, strlen (filename), &hc); | ||
898 | pd = GNUNET_CONTAINER_multihashmap_get (adc->metamap, &hc); | ||
899 | /* stat() is needed here to match the stat() call add_dir_callback() does */ | ||
900 | if ((pd != NULL) && (0 == STAT (filename, &sbuf))) | ||
901 | { | ||
902 | add_entry_to_ts (GTK_TREE_STORE (adc->ctx->file_info_treemodel), | ||
903 | &pd->iter, filename, &adc->bo, adc->do_index, | ||
904 | pd->ksk_uri, adc->exclude_ksk, pd->meta); | ||
905 | } | ||
906 | if (pd != NULL) | ||
907 | { | ||
908 | GNUNET_CONTAINER_multihashmap_remove (adc->metamap, &hc, pd); | ||
909 | GNUNET_free (pd); | ||
910 | } | ||
911 | if (GNUNET_DISK_directory_iterator_next (di, GNUNET_NO) != GNUNET_YES) | ||
912 | { | ||
913 | child_dir_finished_publishing (adc); | ||
914 | } | ||
915 | } | ||
916 | |||
917 | static void | ||
918 | child_dir_finished_scanning (struct AddDirContext *adc) | ||
919 | { | ||
920 | adc->pd->ksk_uri = process_keywords (adc); | ||
921 | adc->pd->meta = GNUNET_CONTAINER_meta_data_create (); | ||
922 | adc->exclude_ksk = GNUNET_FS_uri_dup (adc->pd->ksk_uri); | ||
923 | if (GNUNET_YES != GNUNET_DISK_directory_iterator_start (GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
924 | adc->parent_filename, &publish_dir_callback, adc)) | ||
925 | child_dir_finished_publishing (adc); | ||
926 | } | ||
927 | |||
928 | /** | ||
929 | * Function called by directory iterator. | ||
930 | * | ||
931 | * @param cls closure | ||
932 | * @param di argument to pass to "GNUNET_DISK_directory_iterator_next" to | ||
933 | * get called on the next entry (or finish cleanly); | ||
934 | * NULL on error (will be the last call in that case) | ||
935 | * @param filename complete filename (absolute path) | ||
936 | * @param dirname directory name (absolute path) | ||
937 | */ | ||
938 | static void | ||
939 | add_dir_callback (void *cls, struct GNUNET_DISK_DirectoryIterator * di, | ||
940 | const char *filename, const char *dirname) | ||
941 | { | ||
942 | struct AddDirContext *adc = cls, *child_adc; | ||
943 | struct stat sbuf; | ||
944 | int will_continue; | ||
945 | |||
946 | /* dirname == NULL is a special case when add_dir_callback() is called by | ||
947 | * the child directory iterator callback. | ||
948 | */ | ||
949 | if (dirname == NULL) | ||
950 | { | ||
951 | if (di == NULL) | ||
952 | { | ||
953 | /* This is the top-level entry, hook the treemodel back */ | ||
954 | gtk_tree_view_set_model (adc->ctx->file_info_treeview, adc->ctx->file_info_treemodel); | ||
955 | return; | ||
956 | } | ||
957 | else | ||
958 | will_continue = GNUNET_DISK_directory_iterator_next (di, GNUNET_NO); | ||
959 | } | ||
960 | else if (0 != STAT (filename, &sbuf)) | ||
961 | { | ||
962 | GNUNET_assert (di != NULL); | ||
963 | will_continue = GNUNET_DISK_directory_iterator_next (di, GNUNET_NO); | ||
964 | } | ||
965 | else | ||
966 | { | ||
967 | if (!S_ISDIR (sbuf.st_mode)) | ||
968 | { | ||
969 | GNUNET_assert (adc->metamap != NULL); | ||
970 | extract_file (adc, filename); | ||
971 | will_continue = GNUNET_DISK_directory_iterator_next (di, GNUNET_NO); | ||
972 | } | ||
973 | else | ||
974 | { | ||
975 | child_adc = GNUNET_malloc (sizeof (struct AddDirContext)); | ||
976 | will_continue = GNUNET_DISK_directory_iterator_start (GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
977 | filename, &add_dir_callback, child_adc); | ||
978 | if (will_continue != GNUNET_YES) | ||
979 | { | ||
980 | /* Ignore empty directories for now */ | ||
981 | GNUNET_free (child_adc); | ||
982 | will_continue = GNUNET_DISK_directory_iterator_next (di, GNUNET_NO); | ||
983 | } | ||
984 | else | ||
985 | { | ||
986 | child_adc->metamap = GNUNET_CONTAINER_multihashmap_create (1024); | ||
987 | child_adc->keywordcounter = GNUNET_CONTAINER_multihashmap_create (1024); | ||
988 | child_adc->dir_entry_count = 0; | ||
989 | child_adc->parent_ctx = adc; | ||
990 | child_adc->parent_iter = di; | ||
991 | child_adc->bo = adc->bo; | ||
992 | child_adc->do_index = adc->do_index; | ||
993 | child_adc->ctx = adc->ctx; | ||
994 | child_adc->pd = GNUNET_malloc (sizeof (struct PublishData)); | ||
995 | child_adc->parent_filename = GNUNET_strdup (filename); | ||
996 | gtk_tree_store_insert_before (GTK_TREE_STORE (adc->ctx->file_info_treemodel), | ||
997 | &child_adc->pd->iter, adc->parent, NULL); | ||
998 | child_adc->parent = &child_adc->pd->iter; | ||
999 | /* Don't advance directory iterator here, child iterator will call | ||
1000 | * us with dirname == NULL for that later. | ||
1001 | */ | ||
1002 | } | ||
1003 | } | ||
1004 | } | ||
1005 | if (will_continue != GNUNET_YES) | ||
1006 | { | ||
1007 | child_dir_finished_scanning (adc); | ||
1008 | } | ||
1009 | return; | ||
1010 | } | ||
1011 | |||
1012 | |||
1013 | /** | ||
1014 | * Add a directory to the tree model. | ||
1015 | * | ||
1016 | * @param filename directory name to add | ||
1017 | * @param bo block options | ||
1018 | * @param do_index should we index? | ||
1019 | */ | ||
1020 | static void | ||
1021 | add_dir (struct MainPublishingDialogContext *ctx, const char *filename, | ||
1022 | const struct GNUNET_FS_BlockOptions *bo, int do_index) | ||
1023 | { | ||
1024 | struct stat sbuf; | ||
1025 | struct AddDirContext *scan_ctx; | ||
1026 | char *filename_expanded; | ||
1027 | |||
1028 | if (0 != STAT (filename, &sbuf)) | ||
1029 | return; | ||
1030 | if (!S_ISDIR (sbuf.st_mode)) | ||
1031 | { | ||
1032 | GNUNET_break (0); | ||
1033 | return; | ||
1034 | } | ||
1035 | filename_expanded = GNUNET_STRINGS_filename_expand (filename); | ||
1036 | if (filename_expanded == NULL) | ||
1037 | return; | ||
1038 | scan_ctx = GNUNET_malloc (sizeof (struct AddDirContext)); | ||
1039 | scan_ctx->bo = *bo; | ||
1040 | scan_ctx->do_index = do_index; | ||
1041 | scan_ctx->ctx = ctx; | ||
1042 | |||
1043 | /* Disconnect treestore from the treeview to prevent GTK from trying | ||
1044 | * to update it on the fly. | ||
1045 | */ | ||
1046 | gtk_tree_view_set_model (ctx->file_info_treeview, NULL); | ||
1047 | |||
1048 | /* just make sure that dirname is not NULL, it's not really used */ | ||
1049 | add_dir_callback (scan_ctx, NULL, filename_expanded, filename_expanded); | ||
1050 | GNUNET_free (filename_expanded); | ||
1051 | } | ||
1052 | |||
1053 | |||
1054 | /* ************ code for adding directories ends here ************* */ | ||
1055 | |||
1056 | |||
1057 | static void | 398 | static void |
1058 | selection_changed_cb (GtkTreeSelection * ts, struct MainPublishingDialogContext *ctx) | 399 | selection_changed_cb (GtkTreeSelection * ts, struct MainPublishingDialogContext *ctx) |
1059 | { | 400 | { |
1060 | update_selectivity (ctx); | 401 | update_selectivity (ctx); |
1061 | } | 402 | } |
1062 | 403 | ||
1063 | |||
1064 | static void | 404 | static void |
1065 | remove_old_entry (GtkTreeStore * ts, GtkTreeIter * root) | 405 | remove_old_entry (GtkTreeStore * ts, GtkTreeIter * root) |
1066 | { | 406 | { |
@@ -1348,6 +688,7 @@ GNUNET_GTK_master_publish_dialog_new_button_clicked_cb (GtkWidget * dummy, | |||
1348 | * anonymity, priority and expiration prior | 688 | * anonymity, priority and expiration prior |
1349 | * to calling this function (currently we | 689 | * to calling this function (currently we |
1350 | * use default values for those). | 690 | * use default values for those). |
691 | * Or getting these values from the configuration. | ||
1351 | */ | 692 | */ |
1352 | bo.anonymity_level = 1; | 693 | bo.anonymity_level = 1; |
1353 | bo.content_priority = 1000; | 694 | bo.content_priority = 1000; |
@@ -1377,6 +718,17 @@ GNUNET_GTK_master_publish_dialog_add_button_clicked_cb (GtkWidget * dummy, | |||
1377 | ad = GTK_WIDGET (gtk_builder_get_object | 718 | ad = GTK_WIDGET (gtk_builder_get_object |
1378 | (ctx->open_file_builder, "GNUNET_GTK_publish_file_dialog")); | 719 | (ctx->open_file_builder, "GNUNET_GTK_publish_file_dialog")); |
1379 | 720 | ||
721 | /* FIXME: Use some kind of adjustable defaults instead of 1000, 0 and TRUE */ | ||
722 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object ( | ||
723 | ctx->open_file_builder, | ||
724 | "GNUNET_GTK_publish_file_dialog_priority_spin_button")), 1000); | ||
725 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object ( | ||
726 | ctx->open_file_builder, | ||
727 | "GNUNET_GTK_publish_file_dialog_replication_spin_button")), 0); | ||
728 | gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object ( | ||
729 | ctx->open_file_builder, | ||
730 | "GNUNET_GTK_publish_file_dialog_do_index_checkbutton")), TRUE); | ||
731 | |||
1380 | ctx->open_file_handler_id = g_signal_connect (G_OBJECT (ad), "response", G_CALLBACK (GNUNET_GTK_publish_file_dialog_response_cb), ctx); | 732 | ctx->open_file_handler_id = g_signal_connect (G_OBJECT (ad), "response", G_CALLBACK (GNUNET_GTK_publish_file_dialog_response_cb), ctx); |
1381 | 733 | ||
1382 | anon_treemodel = GTK_TREE_MODEL (gtk_builder_get_object (ctx->main_window_builder, | 734 | anon_treemodel = GTK_TREE_MODEL (gtk_builder_get_object (ctx->main_window_builder, |
@@ -1518,6 +870,337 @@ GNUNET_GTK_master_publish_dialog_delete_button_clicked_cb (GtkWidget * dummy, | |||
1518 | update_selectivity (ctx); | 870 | update_selectivity (ctx); |
1519 | } | 871 | } |
1520 | 872 | ||
873 | static void | ||
874 | insert_progress_dialog_text (struct AddDirClientContext *adcc, | ||
875 | char *text) | ||
876 | { | ||
877 | GtkTextIter iter; | ||
878 | |||
879 | gtk_text_buffer_get_iter_at_mark (adcc->progress_dialog_textbuffer, | ||
880 | &iter, adcc->progress_dialog_textmark); | ||
881 | gtk_text_buffer_insert (adcc->progress_dialog_textbuffer, | ||
882 | &iter, text, -1); | ||
883 | gtk_text_view_scroll_to_mark (adcc->progress_dialog_textview, | ||
884 | adcc->progress_dialog_textmark, | ||
885 | 0.0, FALSE, 1.0, 1.0); | ||
886 | |||
887 | } | ||
888 | |||
889 | /** | ||
890 | * Does the same freeing and destorying "add_item" does, | ||
891 | * without doing anything else | ||
892 | */ | ||
893 | void | ||
894 | discard_item (struct ShareTreeItem *item) | ||
895 | { | ||
896 | GNUNET_CONTAINER_meta_data_destroy (item->meta); | ||
897 | GNUNET_FS_uri_destroy (item->ksk_uri); | ||
898 | GNUNET_free (item->short_filename); | ||
899 | GNUNET_free (item->filename); | ||
900 | } | ||
901 | |||
902 | void | ||
903 | add_item (struct AddDirClientContext *adcc, GtkTreeStore *ts, | ||
904 | struct ShareTreeItem *item, GtkTreeIter *parent, GtkTreeIter *sibling, | ||
905 | GtkTreeIter *item_iter) | ||
906 | { | ||
907 | char *file_size_fancy; | ||
908 | struct GNUNET_FS_FileInformation *fi; | ||
909 | GtkTreeRowReference *row_reference; | ||
910 | GtkTreePath *path; | ||
911 | |||
912 | gtk_tree_store_insert_after (ts, item_iter, parent, sibling); | ||
913 | |||
914 | path = gtk_tree_model_get_path (GTK_TREE_MODEL (ts), item_iter); | ||
915 | row_reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (ts), path); | ||
916 | gtk_tree_path_free (path); | ||
917 | |||
918 | if (item->is_directory) | ||
919 | { | ||
920 | GNUNET_CONTAINER_meta_data_delete (item->meta, | ||
921 | EXTRACTOR_METATYPE_MIMETYPE, NULL, 0); | ||
922 | GNUNET_FS_meta_data_make_directory (item->meta); | ||
923 | GNUNET_FS_uri_ksk_add_keyword (item->ksk_uri, GNUNET_FS_DIRECTORY_MIME, | ||
924 | GNUNET_NO); | ||
925 | fi = GNUNET_FS_file_information_create_empty_directory ( | ||
926 | GNUNET_FS_GTK_get_fs_handle (), row_reference, item->ksk_uri, | ||
927 | item->meta, &adcc->directory_scan_bo, item->filename); | ||
928 | } | ||
929 | else | ||
930 | { | ||
931 | fi = GNUNET_FS_file_information_create_from_file ( | ||
932 | GNUNET_FS_GTK_get_fs_handle (), row_reference, item->filename, | ||
933 | item->ksk_uri, item->meta, adcc->directory_scan_do_index, | ||
934 | &adcc->directory_scan_bo); | ||
935 | } | ||
936 | GNUNET_CONTAINER_meta_data_destroy (item->meta); | ||
937 | GNUNET_FS_uri_destroy (item->ksk_uri); | ||
938 | if (item->is_directory) | ||
939 | file_size_fancy = GNUNET_strdup (MARKER_DIR_FILE_SIZE); | ||
940 | else | ||
941 | file_size_fancy = GNUNET_STRINGS_byte_size_fancy (item->file_size); | ||
942 | gtk_tree_store_set (ts, item_iter, 0, file_size_fancy, | ||
943 | 1, (gboolean) adcc->directory_scan_do_index, | ||
944 | 2, item->short_filename, | ||
945 | 3, (guint) adcc->directory_scan_bo.anonymity_level, | ||
946 | 4, (guint) adcc->directory_scan_bo.content_priority, | ||
947 | 5, fi, | ||
948 | 6, (guint64) adcc->directory_scan_bo.expiration_time.abs_value, | ||
949 | 7, (guint) adcc->directory_scan_bo.replication_level, -1); | ||
950 | GNUNET_free (file_size_fancy); | ||
951 | GNUNET_free (item->short_filename); | ||
952 | GNUNET_free (item->filename); | ||
953 | } | ||
954 | |||
955 | /* Used to avoid recursion */ | ||
956 | struct AddShareItemsStack | ||
957 | { | ||
958 | struct AddShareItemsStack *parent; | ||
959 | GtkTreeIter last_added; | ||
960 | }; | ||
961 | |||
962 | /** | ||
963 | * Traverse the share tree and add it to the tree store | ||
964 | * Set "discard" to GNUNET_YES to force the tree to be destroyed | ||
965 | * without processing (it is destroyed either way). | ||
966 | */ | ||
967 | void | ||
968 | add_share_items_to_treestore (struct AddDirClientContext *adcc, | ||
969 | struct ShareTreeItem *toplevel, int discard) | ||
970 | { | ||
971 | struct MainPublishingDialogContext *ctx = adcc->ctx; | ||
972 | GtkTreeStore *ts = GTK_TREE_STORE (ctx->file_info_treemodel); | ||
973 | GtkTreeIter *parent_iter; | ||
974 | GtkTreeIter *sibling_iter; | ||
975 | struct ShareTreeItem *item, *next; | ||
976 | struct AddShareItemsStack *stack; | ||
977 | |||
978 | if (!discard) | ||
979 | { | ||
980 | stack = GNUNET_malloc (sizeof (struct AddShareItemsStack)); | ||
981 | parent_iter = NULL; | ||
982 | sibling_iter = NULL; | ||
983 | } | ||
984 | for (item = toplevel; item != NULL; item = next) | ||
985 | { | ||
986 | if (!discard) | ||
987 | { | ||
988 | add_item (adcc, ts, item, parent_iter, sibling_iter, &stack->last_added); | ||
989 | sibling_iter = &stack->last_added; | ||
990 | } | ||
991 | else | ||
992 | discard_item (item); | ||
993 | if (item->is_directory) | ||
994 | { | ||
995 | if (item->children_head != NULL) | ||
996 | { | ||
997 | if (!discard) | ||
998 | { | ||
999 | struct AddShareItemsStack *child = GNUNET_malloc (sizeof (struct AddShareItemsStack)); | ||
1000 | child->parent = stack; | ||
1001 | sibling_iter = NULL; | ||
1002 | parent_iter = &stack->last_added; | ||
1003 | stack = child; | ||
1004 | } | ||
1005 | next = item->children_head; | ||
1006 | continue; | ||
1007 | } | ||
1008 | } | ||
1009 | while ((next = item->next) == NULL) | ||
1010 | { | ||
1011 | if (item->parent != NULL) | ||
1012 | { | ||
1013 | next = item->parent; | ||
1014 | if (!discard) | ||
1015 | { | ||
1016 | struct AddShareItemsStack *child; | ||
1017 | sibling_iter = &stack->parent->last_added; | ||
1018 | parent_iter = stack->parent->parent != NULL ? &stack->parent->parent->last_added : NULL; | ||
1019 | child = stack; | ||
1020 | stack = stack->parent; | ||
1021 | GNUNET_free (child); | ||
1022 | } | ||
1023 | GNUNET_free (item); | ||
1024 | item = next; | ||
1025 | } | ||
1026 | else | ||
1027 | break; | ||
1028 | } | ||
1029 | GNUNET_free (item); | ||
1030 | } | ||
1031 | if (!discard) | ||
1032 | GNUNET_free (stack); | ||
1033 | } | ||
1034 | |||
1035 | static void | ||
1036 | close_scan (struct AddDirClientContext *adcc) | ||
1037 | { | ||
1038 | gtk_widget_destroy (adcc->progress_dialog); | ||
1039 | g_object_unref (G_OBJECT (adcc->progress_dialog_builder)); | ||
1040 | GNUNET_CONTAINER_DLL_remove (adcc->ctx->adddir_head, | ||
1041 | adcc->ctx->adddir_tail, adcc); | ||
1042 | update_selectivity (adcc->ctx); | ||
1043 | GNUNET_free (adcc); | ||
1044 | } | ||
1045 | |||
1046 | static void | ||
1047 | complete_scan (struct AddDirClientContext *adcc) | ||
1048 | { | ||
1049 | /* Pressing OK shouldn't work until we have the results */ | ||
1050 | if (adcc->directory_scan_result != NULL) | ||
1051 | { | ||
1052 | add_share_items_to_treestore (adcc, adcc->directory_scan_result, | ||
1053 | adcc->cancelling ? GNUNET_YES : GNUNET_NO); | ||
1054 | adcc->directory_scan_result = NULL; | ||
1055 | update_selectivity (adcc->ctx); | ||
1056 | close_scan (adcc); | ||
1057 | } | ||
1058 | } | ||
1059 | |||
1060 | static int | ||
1061 | cancel_scan (struct AddDirClientContext *adcc) | ||
1062 | { | ||
1063 | int result = GNUNET_YES; | ||
1064 | /* User wants to cancel */ | ||
1065 | adcc->cancelling = GNUNET_YES; | ||
1066 | if (adcc->ds != NULL) | ||
1067 | { | ||
1068 | /* Still scanning - signal the scanner to finish */ | ||
1069 | GNUNET_FS_directory_scan_finish (adcc->ds, GNUNET_NO); | ||
1070 | result = GNUNET_NO; | ||
1071 | } | ||
1072 | if (adcc->directory_scan_result != NULL) | ||
1073 | { | ||
1074 | /* Not scanning anymore - discard the results of the scan and close */ | ||
1075 | add_share_items_to_treestore (adcc, adcc->directory_scan_result, GNUNET_YES); | ||
1076 | adcc->directory_scan_result = NULL; | ||
1077 | close_scan (adcc); | ||
1078 | result = GNUNET_YES; | ||
1079 | } | ||
1080 | return result; | ||
1081 | } | ||
1082 | |||
1083 | void | ||
1084 | GNUNET_FS_GTK_progress_dialog_ok_button_clicked_cb (GtkButton *button, | ||
1085 | struct AddDirClientContext *adcc) | ||
1086 | { | ||
1087 | complete_scan (adcc); | ||
1088 | } | ||
1089 | |||
1090 | void | ||
1091 | GNUNET_FS_GTK_progress_dialog_cancel_button_clicked_cb (GtkButton *button, | ||
1092 | struct AddDirClientContext *adcc) | ||
1093 | { | ||
1094 | cancel_scan (adcc); | ||
1095 | } | ||
1096 | |||
1097 | gboolean | ||
1098 | GNUNET_FS_GTK_progress_dialog_delete_event_cb (GtkWidget *widget, | ||
1099 | GdkEvent * event, struct AddDirClientContext *adcc) | ||
1100 | { | ||
1101 | /* Don't allow GTK to kill the window, until the scan is finished */ | ||
1102 | return cancel_scan (adcc) == GNUNET_NO; | ||
1103 | } | ||
1104 | |||
1105 | static void | ||
1106 | directory_trim_complete (void *cls, | ||
1107 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1108 | { | ||
1109 | struct AddDirClientContext *adcc = cls; | ||
1110 | adcc->directory_scan_result = adcc->directory_scan_intermediary_result; | ||
1111 | if (adcc->cancelling) | ||
1112 | { | ||
1113 | cancel_scan (adcc); | ||
1114 | } | ||
1115 | else | ||
1116 | { | ||
1117 | gtk_widget_set_sensitive (GTK_WIDGET (adcc->progress_dialog_ok), TRUE); | ||
1118 | gtk_widget_set_visible (GTK_WIDGET (adcc->progress_dialog_bar), FALSE); | ||
1119 | if (!adcc->keep) | ||
1120 | complete_scan (adcc); | ||
1121 | } | ||
1122 | } | ||
1123 | |||
1124 | static int | ||
1125 | directory_scan_cb (void *cls, struct GNUNET_FS_DirScanner *ds, | ||
1126 | const char *filename, char is_directory, | ||
1127 | enum GNUNET_DirScannerProgressUpdateReason reason) | ||
1128 | { | ||
1129 | struct AddDirClientContext *adcc = cls; | ||
1130 | char *s; | ||
1131 | gtk_progress_bar_pulse (adcc->progress_dialog_bar); | ||
1132 | switch (reason) | ||
1133 | { | ||
1134 | case GNUNET_DIR_SCANNER_NEW_FILE: | ||
1135 | if (filename != NULL) | ||
1136 | { | ||
1137 | if (is_directory) | ||
1138 | GNUNET_asprintf (&s, _("Scanning directory `%s'.\n"), filename); | ||
1139 | else | ||
1140 | GNUNET_asprintf (&s, _("Scanning file `%s'.\n"), filename); | ||
1141 | insert_progress_dialog_text (adcc, s); | ||
1142 | GNUNET_free (s); | ||
1143 | } | ||
1144 | break; | ||
1145 | case GNUNET_DIR_SCANNER_DOES_NOT_EXIST: | ||
1146 | if (filename != NULL) | ||
1147 | { | ||
1148 | GNUNET_asprintf (&s, | ||
1149 | _("Failed to scan `%s', because it does not exist.\n"), | ||
1150 | filename); | ||
1151 | adcc->keep = 1; | ||
1152 | insert_progress_dialog_text (adcc, s); | ||
1153 | GNUNET_free (s); | ||
1154 | } | ||
1155 | break; | ||
1156 | case GNUNET_DIR_SCANNER_ASKED_TO_STOP: | ||
1157 | if (filename != NULL) | ||
1158 | { | ||
1159 | GNUNET_asprintf (&s, | ||
1160 | _("Scanner was about to scan `%s', but is now stopping.\n"), | ||
1161 | filename); | ||
1162 | insert_progress_dialog_text (adcc, s); | ||
1163 | GNUNET_free (s); | ||
1164 | } | ||
1165 | else | ||
1166 | insert_progress_dialog_text (adcc, _("Scanner is stopping.\n")); | ||
1167 | break; | ||
1168 | case GNUNET_DIR_SCANNER_SHUTDOWN: | ||
1169 | insert_progress_dialog_text (adcc, _("Client is shutting down.\n")); | ||
1170 | break; | ||
1171 | case GNUNET_DIR_SCANNER_FINISHED: | ||
1172 | insert_progress_dialog_text (adcc, _("Scanner has finished.\n")); | ||
1173 | break; | ||
1174 | case GNUNET_DIR_SCANNER_PROTOCOL_ERROR: | ||
1175 | insert_progress_dialog_text (adcc, | ||
1176 | _("There was a failure communicating with the scanner.\n")); | ||
1177 | adcc->keep = 1; | ||
1178 | break; | ||
1179 | default: | ||
1180 | GNUNET_asprintf (&s,_("Got unknown scanner update with filename `%s'.\n"), | ||
1181 | filename); | ||
1182 | insert_progress_dialog_text (adcc, s); | ||
1183 | GNUNET_free (s); | ||
1184 | adcc->keep = 1; | ||
1185 | break; | ||
1186 | } | ||
1187 | if ((filename == NULL && GNUNET_DIR_SCANNER_FINISHED) | ||
1188 | || reason == GNUNET_DIR_SCANNER_PROTOCOL_ERROR | ||
1189 | || reason == GNUNET_DIR_SCANNER_SHUTDOWN) | ||
1190 | { | ||
1191 | /* Any of this causes us to try to clean up the scanner */ | ||
1192 | adcc->directory_scan_intermediary_result = GNUNET_FS_directory_scan_cleanup (ds); | ||
1193 | adcc->pmc = GNUNET_FS_trim_share_tree (adcc->directory_scan_intermediary_result, | ||
1194 | &directory_trim_complete, adcc); | ||
1195 | |||
1196 | adcc->ds = NULL; | ||
1197 | /* FIXME: change the tree processor to be able to free untrimmed trees | ||
1198 | * right here instead of waiting for trimming to complete, if we need to | ||
1199 | * cancel everything. | ||
1200 | */ | ||
1201 | } | ||
1202 | return 0; | ||
1203 | } | ||
1521 | 1204 | ||
1522 | void | 1205 | void |
1523 | GNUNET_GTK_publish_directory_dialog_response_cb (GtkDialog * dialog, | 1206 | GNUNET_GTK_publish_directory_dialog_response_cb (GtkDialog * dialog, |
@@ -1529,6 +1212,8 @@ GNUNET_GTK_publish_directory_dialog_response_cb (GtkDialog * dialog, | |||
1529 | GtkSpinButton *sb; | 1212 | GtkSpinButton *sb; |
1530 | struct GNUNET_FS_BlockOptions bo; | 1213 | struct GNUNET_FS_BlockOptions bo; |
1531 | GtkWidget *ad; | 1214 | GtkWidget *ad; |
1215 | GtkTextIter iter; | ||
1216 | struct AddDirClientContext *adcc; | ||
1532 | 1217 | ||
1533 | if (g_signal_handler_is_connected (G_OBJECT (dialog), ctx->open_directory_handler_id)) | 1218 | if (g_signal_handler_is_connected (G_OBJECT (dialog), ctx->open_directory_handler_id)) |
1534 | g_signal_handler_disconnect (G_OBJECT (dialog), ctx->open_directory_handler_id); | 1219 | g_signal_handler_disconnect (G_OBJECT (dialog), ctx->open_directory_handler_id); |
@@ -1563,8 +1248,45 @@ GNUNET_GTK_publish_directory_dialog_response_cb (GtkDialog * dialog, | |||
1563 | (ctx->open_directory_builder, | 1248 | (ctx->open_directory_builder, |
1564 | "GNUNET_GTK_publish_directory_dialog_do_index_checkbutton"))); | 1249 | "GNUNET_GTK_publish_directory_dialog_do_index_checkbutton"))); |
1565 | 1250 | ||
1566 | /* FIXME: open progress dialog here... */ | 1251 | adcc = GNUNET_malloc (sizeof (struct AddDirClientContext)); |
1567 | add_dir (ctx, filename, &bo, do_index); | 1252 | adcc->ctx = ctx; |
1253 | GNUNET_CONTAINER_DLL_insert_tail (ctx->adddir_head, ctx->adddir_tail, adcc); | ||
1254 | adcc->ds = GNUNET_FS_directory_scan_start (filename, | ||
1255 | GNUNET_NO, NULL, directory_scan_cb, adcc); | ||
1256 | adcc->directory_scan_bo = bo; | ||
1257 | adcc->directory_scan_do_index = do_index; | ||
1258 | |||
1259 | adcc->progress_dialog_builder = GNUNET_GTK_get_new_builder ( | ||
1260 | "gnunet_fs_gtk_progress_dialog.glade", adcc); | ||
1261 | adcc->progress_dialog = GTK_WIDGET (gtk_builder_get_object ( | ||
1262 | adcc->progress_dialog_builder, | ||
1263 | "GNUNET_FS_GTK_progress_dialog")); | ||
1264 | adcc->progress_dialog_bar = GTK_PROGRESS_BAR (gtk_builder_get_object ( | ||
1265 | adcc->progress_dialog_builder, | ||
1266 | "GNUNET_FS_GTK_progress_dialog_progressbar")); | ||
1267 | adcc->progress_dialog_ok = GTK_BUTTON (gtk_builder_get_object ( | ||
1268 | adcc->progress_dialog_builder, | ||
1269 | "GNUNET_FS_GTK_progress_dialog_ok_button")); | ||
1270 | adcc->progress_dialog_cancel = GTK_BUTTON (gtk_builder_get_object ( | ||
1271 | adcc->progress_dialog_builder, | ||
1272 | "GNUNET_FS_GTK_progress_dialog_cancel_button")); | ||
1273 | adcc->progress_dialog_textview = GTK_TEXT_VIEW ( | ||
1274 | gtk_builder_get_object (adcc->progress_dialog_builder, | ||
1275 | "GNUNET_FS_GTK_progress_dialog_textview")); | ||
1276 | adcc->progress_dialog_textbuffer = GTK_TEXT_BUFFER ( | ||
1277 | gtk_builder_get_object (adcc->progress_dialog_builder, | ||
1278 | "GNUNET_FS_GTK_progress_dialog_textbuffer")); | ||
1279 | gtk_widget_set_sensitive (GTK_WIDGET (adcc->progress_dialog_ok), FALSE); | ||
1280 | |||
1281 | gtk_text_buffer_get_end_iter (adcc->progress_dialog_textbuffer, | ||
1282 | &iter); | ||
1283 | adcc->progress_dialog_textmark = gtk_text_buffer_create_mark ( | ||
1284 | adcc->progress_dialog_textbuffer, "scroll", | ||
1285 | &iter, FALSE); | ||
1286 | |||
1287 | gtk_window_set_transient_for (GTK_WINDOW (adcc->progress_dialog), adcc->ctx->master_pubdialog); | ||
1288 | gtk_window_present (GTK_WINDOW (adcc->progress_dialog)); | ||
1289 | |||
1568 | g_free (filename); | 1290 | g_free (filename); |
1569 | update_selectivity (ctx); | 1291 | update_selectivity (ctx); |
1570 | } | 1292 | } |
@@ -1584,6 +1306,18 @@ GNUNET_GTK_master_publish_dialog_open_button_clicked_cb (GtkWidget * dummy, | |||
1584 | 1306 | ||
1585 | ctx->open_directory_builder = GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_publish_directory_dialog.glade", ctx); | 1307 | ctx->open_directory_builder = GNUNET_GTK_get_new_builder ("gnunet_fs_gtk_publish_directory_dialog.glade", ctx); |
1586 | GNUNET_FS_GTK_setup_expiration_year_adjustment (ctx->open_directory_builder); | 1308 | GNUNET_FS_GTK_setup_expiration_year_adjustment (ctx->open_directory_builder); |
1309 | |||
1310 | /* FIXME: Use some kind of adjustable defaults instead of 1000, 0 and TRUE */ | ||
1311 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object ( | ||
1312 | ctx->open_directory_builder, | ||
1313 | "GNUNET_GTK_publish_directory_dialog_priority_spin_button")), 1000); | ||
1314 | gtk_spin_button_set_value (GTK_SPIN_BUTTON (gtk_builder_get_object ( | ||
1315 | ctx->open_directory_builder, | ||
1316 | "GNUNET_GTK_publish_directory_dialog_replication_spin_button")), 0); | ||
1317 | gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object ( | ||
1318 | ctx->open_directory_builder, | ||
1319 | "GNUNET_GTK_publish_directory_dialog_do_index_checkbutton")), TRUE); | ||
1320 | |||
1587 | ad = GTK_WIDGET (gtk_builder_get_object | 1321 | ad = GTK_WIDGET (gtk_builder_get_object |
1588 | (ctx->open_directory_builder, "GNUNET_GTK_publish_directory_dialog")); | 1322 | (ctx->open_directory_builder, "GNUNET_GTK_publish_directory_dialog")); |
1589 | 1323 | ||
@@ -1839,15 +1573,7 @@ free_file_information_tree_store (GtkTreeModel * tm, GtkTreeIter * iter) | |||
1839 | } | 1573 | } |
1840 | } | 1574 | } |
1841 | 1575 | ||
1842 | 1576 | static int | |
1843 | void | ||
1844 | GNUNET_GTK_master_publish_dialog_realize_cb (GtkWidget * widget, | ||
1845 | struct MainPublishingDialogContext *ctx) | ||
1846 | { | ||
1847 | } | ||
1848 | |||
1849 | |||
1850 | static void | ||
1851 | hide_master_publish_dialog (struct MainPublishingDialogContext *ctx, gint ret) | 1577 | hide_master_publish_dialog (struct MainPublishingDialogContext *ctx, gint ret) |
1852 | { | 1578 | { |
1853 | GtkTreeIter iter; | 1579 | GtkTreeIter iter; |
@@ -1856,6 +1582,10 @@ hide_master_publish_dialog (struct MainPublishingDialogContext *ctx, gint ret) | |||
1856 | gchar *namespace_uid; | 1582 | gchar *namespace_uid; |
1857 | struct GNUNET_FS_FileInformation *fi; | 1583 | struct GNUNET_FS_FileInformation *fi; |
1858 | 1584 | ||
1585 | /* Don't close until all scanners are finished */ | ||
1586 | if (ctx->adddir_head != NULL) | ||
1587 | return GNUNET_NO; | ||
1588 | |||
1859 | if (ret == GTK_RESPONSE_OK) | 1589 | if (ret == GTK_RESPONSE_OK) |
1860 | { | 1590 | { |
1861 | if (TRUE == gtk_tree_selection_get_selected (ctx->pseudonym_selection, NULL, &iter)) | 1591 | if (TRUE == gtk_tree_selection_get_selected (ctx->pseudonym_selection, NULL, &iter)) |
@@ -1903,6 +1633,7 @@ hide_master_publish_dialog (struct MainPublishingDialogContext *ctx, gint ret) | |||
1903 | gtk_widget_destroy (GTK_WIDGET (ctx->master_pubdialog)); | 1633 | gtk_widget_destroy (GTK_WIDGET (ctx->master_pubdialog)); |
1904 | g_object_unref (G_OBJECT (ctx->builder)); | 1634 | g_object_unref (G_OBJECT (ctx->builder)); |
1905 | GNUNET_free (ctx); | 1635 | GNUNET_free (ctx); |
1636 | return GNUNET_YES; | ||
1906 | } | 1637 | } |
1907 | 1638 | ||
1908 | 1639 | ||
@@ -1927,8 +1658,9 @@ GNUNET_GTK_master_publish_dialog_delete_event_cb (GtkWidget * widget, | |||
1927 | GdkEvent * event, | 1658 | GdkEvent * event, |
1928 | struct MainPublishingDialogContext *ctx) | 1659 | struct MainPublishingDialogContext *ctx) |
1929 | { | 1660 | { |
1930 | hide_master_publish_dialog (ctx, GTK_RESPONSE_CANCEL); | 1661 | if (GNUNET_NO == hide_master_publish_dialog (ctx, GTK_RESPONSE_CANCEL)) |
1931 | return TRUE; | 1662 | return TRUE; |
1663 | return FALSE; | ||
1932 | } | 1664 | } |
1933 | 1665 | ||
1934 | 1666 | ||