aboutsummaryrefslogtreecommitdiff
path: root/src/fs/gnunet-fs-gtk-main_window_file_publish.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs/gnunet-fs-gtk-main_window_file_publish.c')
-rw-r--r--src/fs/gnunet-fs-gtk-main_window_file_publish.c1208
1 files changed, 470 insertions, 738 deletions
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
33struct AddDirClientContext;
34
33struct MainPublishingDialogContext 35struct 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 */
67struct 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
58void 106void
@@ -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 */
90static void 139static void
91init_ctx (struct MainPublishingDialogContext *ctx) 140init_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 */
342struct 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 */
365struct 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 */
385struct 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 */
466static int
467add_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 */
501static void
502extract_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 */
543static int
544remove_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 */
567static void
568add_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 */
646static int
647publish_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 */
667struct 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 */
687static int
688migrate_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 */
710static struct GNUNET_FS_Uri *
711process_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 */
740static int
741scan_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
827static void
828add_dir_callback (void *cls, struct GNUNET_DISK_DirectoryIterator * di,
829 const char *filename, const char *dirname);
830
831
832static void
833child_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
888static void
889publish_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
917static void
918child_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 */
938static void
939add_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 */
1020static void
1021add_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
1057static void 398static void
1058selection_changed_cb (GtkTreeSelection * ts, struct MainPublishingDialogContext *ctx) 399selection_changed_cb (GtkTreeSelection * ts, struct MainPublishingDialogContext *ctx)
1059{ 400{
1060 update_selectivity (ctx); 401 update_selectivity (ctx);
1061} 402}
1062 403
1063
1064static void 404static void
1065remove_old_entry (GtkTreeStore * ts, GtkTreeIter * root) 405remove_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
873static void
874insert_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 */
893void
894discard_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
902void
903add_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 */
956struct 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 */
967void
968add_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
1035static void
1036close_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
1046static void
1047complete_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
1060static int
1061cancel_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
1083void
1084GNUNET_FS_GTK_progress_dialog_ok_button_clicked_cb (GtkButton *button,
1085 struct AddDirClientContext *adcc)
1086{
1087 complete_scan (adcc);
1088}
1089
1090void
1091GNUNET_FS_GTK_progress_dialog_cancel_button_clicked_cb (GtkButton *button,
1092 struct AddDirClientContext *adcc)
1093{
1094 cancel_scan (adcc);
1095}
1096
1097gboolean
1098GNUNET_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
1105static void
1106directory_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
1124static int
1125directory_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
1522void 1205void
1523GNUNET_GTK_publish_directory_dialog_response_cb (GtkDialog * dialog, 1206GNUNET_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 1576static int
1843void
1844GNUNET_GTK_master_publish_dialog_realize_cb (GtkWidget * widget,
1845 struct MainPublishingDialogContext *ctx)
1846{
1847}
1848
1849
1850static void
1851hide_master_publish_dialog (struct MainPublishingDialogContext *ctx, gint ret) 1577hide_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