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.c1933
1 files changed, 1933 insertions, 0 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
new file mode 100644
index 00000000..2fa46ec5
--- /dev/null
+++ b/src/fs/gnunet-fs-gtk-main_window_file_publish.c
@@ -0,0 +1,1933 @@
1/*
2 This file is part of GNUnet
3 (C) 2005, 2006, 2010 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file src/main_window_file_publish.c
23 * @author Christian Grothoff
24 */
25#include "common.h"
26#include "gnunet-fs-gtk.h"
27#include "edit_publish_dialog.h"
28#include <gnunet/gnunet_util_lib.h>
29
30#define MARKER_DIR_FILE_SIZE "-"
31
32/**
33 * Builder used for the master publish dialog.
34 */
35static GtkBuilder *master_builder;
36
37
38/**
39 * Check if two GtkTreeIters refer to the same element.
40 *
41 * @param tm tree model of the iterators
42 * @param i1 first iterator
43 * @param i2 second iterator
44 * @return GNUNET_YES if they are equal
45 */
46static int
47gtk_tree_iter_equals (GtkTreeModel *tm,
48 GtkTreeIter *i1,
49 GtkTreeIter *i2)
50{
51 GtkTreePath *p1;
52 GtkTreePath *p2;
53 int ret;
54
55 p1 = gtk_tree_model_get_path (tm, i1);
56 p2 = gtk_tree_model_get_path (tm, i2);
57 ret = gtk_tree_path_compare (p1, p2);
58 gtk_tree_path_free (p1);
59 gtk_tree_path_free (p2);
60 return (0 == ret) ? GNUNET_YES : GNUNET_NO;
61}
62
63
64/**
65 * Update selectivity in the master dialog.
66 */
67static void
68update_selectivity ()
69{
70 GtkTreeView *tv;
71 GtkTreeModel *tm;
72 GtkTreeModel *ptm;
73 GtkTreeSelection *sel;
74 GtkTreeIter iter;
75 GtkTreeIter parent;
76 GtkTreeIter pred;
77 GtkWidget *up_button;
78 GtkWidget *down_button;
79 GtkWidget *left_button;
80 GtkWidget *right_button;
81 GtkWidget *delete_button;
82 GtkWidget *edit_button;
83 GtkWidget *execute_button;
84 int is_dir;
85 struct GNUNET_FS_FileInformation *fip;
86 int ns_ok;
87 gchar *namespace_id;
88
89 tm = GTK_TREE_MODEL (gtk_builder_get_object (master_builder,
90 "GNUNET_GTK_file_sharing_publishing_tree_store"));
91 tv = GTK_TREE_VIEW (gtk_builder_get_object (master_builder,
92 "GNUNET_GTK_master_publish_dialog_pseudonym_tree_view"));
93 sel = gtk_tree_view_get_selection (tv);
94 ns_ok = GNUNET_YES;
95 if (TRUE == gtk_tree_selection_get_selected (sel, &ptm, &iter))
96 {
97 gtk_tree_model_get (ptm,
98 &iter,
99 2, &namespace_id,
100 -1);
101 if (namespace_id == NULL)
102 ns_ok = GNUNET_NO;
103 else
104 g_free (namespace_id);
105 }
106 up_button = GTK_WIDGET (gtk_builder_get_object (master_builder,
107 "GNUNET_GTK_master_publish_dialog_up_button"));
108 down_button = GTK_WIDGET (gtk_builder_get_object (master_builder,
109 "GNUNET_GTK_master_publish_dialog_down_button"));
110 left_button = GTK_WIDGET (gtk_builder_get_object (master_builder,
111 "GNUNET_GTK_master_publish_dialog_left_button"));
112 right_button = GTK_WIDGET (gtk_builder_get_object (master_builder,
113 "GNUNET_GTK_master_publish_dialog_right_button"));
114 delete_button = GTK_WIDGET (gtk_builder_get_object (master_builder,
115 "GNUNET_GTK_master_publish_dialog_delete_button"));
116 edit_button = GTK_WIDGET (gtk_builder_get_object (master_builder,
117 "GNUNET_GTK_master_publish_dialog_edit_button"));
118 execute_button = GTK_WIDGET (gtk_builder_get_object (master_builder,
119 "GNUNET_GTK_master_publish_dialog_execute_button"));
120 tv = GTK_TREE_VIEW (gtk_builder_get_object (master_builder,
121 "GNUNET_GTK_master_publish_dialog_file_information_tree_view"));
122 sel = gtk_tree_view_get_selection (tv);
123 tm = gtk_tree_view_get_model (tv);
124 if ( (gtk_tree_model_get_iter_first (tm, &iter)) &&
125 (ns_ok == GNUNET_YES) )
126 gtk_widget_set_sensitive (execute_button, TRUE);
127 else
128 gtk_widget_set_sensitive (execute_button, FALSE);
129 if (TRUE != gtk_tree_selection_get_selected (sel,
130 &tm,
131 &iter))
132 {
133 gtk_widget_set_sensitive (up_button, FALSE);
134 gtk_widget_set_sensitive (down_button, FALSE);
135 gtk_widget_set_sensitive (left_button, FALSE);
136 gtk_widget_set_sensitive (right_button, FALSE);
137 gtk_widget_set_sensitive (delete_button, FALSE);
138 gtk_widget_set_sensitive (edit_button, FALSE);
139 return;
140 }
141 gtk_widget_set_sensitive (delete_button, TRUE);
142 gtk_widget_set_sensitive (edit_button, TRUE);
143
144 /* now figure out which move operations are currently legal */
145 GNUNET_assert (TRUE == gtk_tree_selection_get_selected (sel, NULL, &iter));
146 if (TRUE == gtk_tree_model_iter_next (tm, &iter))
147 {
148 gtk_widget_set_sensitive (down_button, TRUE);
149 }
150 else
151 {
152 gtk_widget_set_sensitive (down_button, FALSE);
153 }
154 GNUNET_assert (TRUE == gtk_tree_selection_get_selected (sel, NULL, &iter));
155 if (TRUE == gtk_tree_model_iter_parent (tm, &parent, &iter))
156 {
157 gtk_widget_set_sensitive (left_button, TRUE);
158 GNUNET_assert (TRUE ==
159 gtk_tree_model_iter_children (tm, &pred, &parent));
160 }
161 else
162 {
163 gtk_widget_set_sensitive (left_button, FALSE);
164 GNUNET_assert (TRUE ==
165 gtk_tree_model_get_iter_first (tm, &pred));
166 }
167 /* iterate over 'next' of pred to find out if our
168 predecessor is a directory! */
169 is_dir = GNUNET_SYSERR;
170 while (GNUNET_YES != gtk_tree_iter_equals (tm, &pred, &iter))
171 {
172 gtk_tree_model_get (tm, &pred,
173 5, &fip, -1);
174 is_dir = GNUNET_FS_file_information_is_directory (fip);
175 GNUNET_assert (TRUE == gtk_tree_model_iter_next (tm, &pred));
176 }
177 if (GNUNET_YES == is_dir)
178 {
179 gtk_widget_set_sensitive (right_button, TRUE);
180 }
181 else
182 {
183 gtk_widget_set_sensitive (right_button, FALSE);
184 }
185 if (GNUNET_SYSERR != is_dir)
186 {
187 gtk_widget_set_sensitive (up_button, TRUE);
188 }
189 else
190 {
191 gtk_widget_set_sensitive (up_button, FALSE);
192 }
193}
194
195
196/**
197 * Add a file to the tree model.
198 *
199 * @param filename file to add
200 * @param bo block options to use
201 * @param do_index should we index or insert?
202 * @param iter parent entry, or NULL for top-level addition
203 */
204static void
205add_file_at_iter (const char *filename,
206 const struct GNUNET_FS_BlockOptions *bo,
207 int do_index,
208 GtkTreeIter *iter)
209{
210 struct GNUNET_FS_FileInformation *fi;
211 GtkTreeRowReference *row_reference;
212 GtkTreePath *path;
213 uint64_t file_size;
214 const char *short_fn;
215 struct GNUNET_CONTAINER_MetaData *meta;
216 struct GNUNET_FS_Uri *ksk_uri;
217 GtkTreeStore *ts;
218 GtkTreeIter pos;
219 char *file_size_fancy;
220 const char *ss;
221 struct stat sbuf;
222
223 if (0 != STAT (filename, &sbuf))
224 return;
225 if (S_ISDIR (sbuf.st_mode))
226 {
227 file_size = 0;
228 }
229 else
230 {
231 if (GNUNET_OK !=
232 GNUNET_DISK_file_size (filename,
233 &file_size,
234 GNUNET_YES))
235 {
236 GNUNET_break (0);
237 return;
238 }
239 }
240 ts = GTK_TREE_STORE (gtk_builder_get_object (master_builder,
241 "GNUNET_GTK_file_sharing_publishing_tree_store"));
242
243 meta = GNUNET_CONTAINER_meta_data_create ();
244 GNUNET_FS_meta_data_extract_from_file (meta,
245 filename,
246 GNUNET_FS_GTK_get_le_plugins());
247 GNUNET_CONTAINER_meta_data_delete (meta,
248 EXTRACTOR_METATYPE_FILENAME,
249 NULL, 0);
250 short_fn = filename;
251 while (NULL != (ss = strstr (short_fn, DIR_SEPARATOR_STR)))
252 short_fn = 1 + ss;
253 GNUNET_CONTAINER_meta_data_insert (meta,
254 "<gnunet-gtk>",
255 EXTRACTOR_METATYPE_FILENAME,
256 EXTRACTOR_METAFORMAT_UTF8,
257 "text/plain",
258 short_fn,
259 strlen(short_fn)+1);
260 ksk_uri = GNUNET_FS_uri_ksk_create_from_meta_data (meta);
261 gtk_tree_store_insert_before (ts,
262 &pos,
263 iter,
264 NULL);
265 path = gtk_tree_model_get_path (GTK_TREE_MODEL (ts),
266 &pos);
267 row_reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (ts),
268 path);
269 gtk_tree_path_free (path);
270 fi = GNUNET_FS_file_information_create_from_file (GNUNET_FS_GTK_get_fs_handle (),
271 row_reference,
272 filename,
273 ksk_uri,
274 meta,
275 do_index,
276 bo);
277 GNUNET_CONTAINER_meta_data_destroy (meta);
278 GNUNET_FS_uri_destroy (ksk_uri);
279 if (S_ISDIR (sbuf.st_mode))
280 file_size_fancy = GNUNET_strdup (MARKER_DIR_FILE_SIZE);
281 else
282 file_size_fancy = GNUNET_STRINGS_byte_size_fancy (file_size);
283 gtk_tree_store_set (ts, &pos,
284 0, file_size_fancy,
285 1, (gboolean) do_index,
286 2, short_fn,
287 3, (guint) bo->anonymity_level,
288 4, (guint) bo->content_priority,
289 5, fi,
290 -1);
291 GNUNET_free (file_size_fancy);
292 update_selectivity ();
293}
294
295
296
297/**
298 * Add an empty directory to the tree model.
299 *
300 * @param name name for the directory
301 * @param bo block options
302 * @param iter parent entry, or NULL for top-level addition
303 * @param pos iterator to set to the location of the new element
304 */
305static void
306create_dir_at_iter (const char *name,
307 const struct GNUNET_FS_BlockOptions *bo,
308 GtkTreeIter *iter,
309 GtkTreeIter *pos)
310{
311 struct GNUNET_FS_FileInformation *fi;
312 GtkTreeRowReference *row_reference;
313 GtkTreePath *path;
314 struct GNUNET_CONTAINER_MetaData *meta;
315 GtkTreeStore *ts;
316
317 ts = GTK_TREE_STORE (gtk_builder_get_object (master_builder,
318 "GNUNET_GTK_file_sharing_publishing_tree_store"));
319 meta = GNUNET_CONTAINER_meta_data_create ();
320 GNUNET_FS_meta_data_make_directory (meta);
321 GNUNET_CONTAINER_meta_data_insert (meta,
322 "<gnunet-gtk>",
323 EXTRACTOR_METATYPE_FILENAME,
324 EXTRACTOR_METAFORMAT_UTF8,
325 "text/plain",
326 name,
327 strlen(name)+1);
328 gtk_tree_store_insert_before (ts,
329 pos,
330 iter,
331 NULL);
332 path = gtk_tree_model_get_path (GTK_TREE_MODEL (ts),
333 pos);
334 row_reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (ts),
335 path);
336 gtk_tree_path_free (path);
337 fi = GNUNET_FS_file_information_create_empty_directory (GNUNET_FS_GTK_get_fs_handle (),
338 row_reference,
339 NULL,
340 meta,
341 bo);
342 GNUNET_CONTAINER_meta_data_destroy (meta);
343 gtk_tree_store_set (ts, pos,
344 0, MARKER_DIR_FILE_SIZE,
345 1, (gboolean) GNUNET_NO,
346 2, name,
347 3, (guint) bo->anonymity_level,
348 4, (guint) bo->content_priority,
349 5, fi,
350 -1);
351 update_selectivity ();
352}
353
354
355/* ************ code for adding directories starts ************* */
356
357
358/**
359 * Data we keep when calculating the publication details for a file.
360 */
361struct PublishData
362{
363 /**
364 * Metadata for the file.
365 */
366 struct GNUNET_CONTAINER_MetaData *meta;
367
368 /**
369 * Iterator for the entry.
370 */
371 GtkTreeIter iter;
372};
373
374
375/**
376 * Entry for each unique meta data entry to track how often
377 * it occured. Contains the keyword and the counter.
378 */
379struct MetaCounter
380{
381
382 /**
383 * Keyword that was found.
384 */
385 const char *value;
386
387 /**
388 * Mimetype of the value.
389 */
390 const char *value_mimetype;
391
392 /**
393 * Type of the value.
394 */
395 enum EXTRACTOR_MetaType type;
396
397 /**
398 * Format of the value.
399 */
400 enum EXTRACTOR_MetaFormat format;
401
402 /**
403 * How many files have meta entries matching this value?
404 * (type and format do not have to match).
405 */
406 unsigned int count;
407
408};
409
410
411/**
412 * Execution context for 'add_dir'
413 */
414struct AddDirContext
415{
416 /**
417 * While scanning, 'parent' is the iter entry for the
418 * parent, or NULL for top-level.
419 */
420 GtkTreeIter *parent;
421
422 /**
423 * Tree store to manipulate.
424 */
425 GtkTreeStore *ts;
426
427 /**
428 * Map from the hash over the meta value to an 'struct MetaCounter'
429 * counter that says how often this value was
430 * encountered in the current directory.
431 */
432 struct GNUNET_CONTAINER_MultiHashMap *metacounter;
433
434 /**
435 * Map from the hash of a filename in the current directory
436 * to the 'struct PublishData*' for the file.
437 */
438 struct GNUNET_CONTAINER_MultiHashMap *metamap;
439
440 /**
441 * Metadata to exclude from using for KSK since it'll be associated
442 * with the parent as well. NULL for nothing blocked.
443 */
444 struct GNUNET_CONTAINER_MetaData *no_ksk;
445
446 /**
447 * Block options to use.
448 */
449 struct GNUNET_FS_BlockOptions bo;
450
451 /**
452 * Index or insert?
453 */
454 int do_index;
455
456 /**
457 * Number of files in the current directory.
458 */
459 unsigned int dir_entry_count;
460};
461
462
463/**
464 * Add the given meta data item to the
465 * meta data statistics tracker.
466 *
467 * @param cls closure (user-defined)
468 * @param plugin_name name of the plugin that produced this value;
469 * special values can be used (i.e. '<zlib>' for zlib being
470 * used in the main libextractor library and yielding
471 * meta data).
472 * @param type libextractor-type describing the meta data
473 * @param format basic format information about data
474 * @param data_mime_type mime-type of data (not of the original file);
475 * can be NULL (if mime-type is not known)
476 * @param data actual meta-data found
477 * @param data_len number of bytes in data
478 * @return 0 to continue extracting, 1 to abort
479 */
480static int
481add_to_meta_counter (void *cls,
482 const char *plugin_name,
483 enum EXTRACTOR_MetaType type,
484 enum EXTRACTOR_MetaFormat format,
485 const char *data_mime_type,
486 const char *data,
487 size_t data_len)
488{
489 struct GNUNET_CONTAINER_MultiHashMap *mcm = cls;
490 struct MetaCounter *cnt;
491 GNUNET_HashCode hc;
492 size_t mlen;
493 size_t dlen;
494
495 if ( (format != EXTRACTOR_METAFORMAT_UTF8) &&
496 (format != EXTRACTOR_METAFORMAT_C_STRING) )
497 return 0;
498 dlen = strlen (data) + 1;
499 GNUNET_CRYPTO_hash (data,
500 dlen - 1,
501 &hc);
502 cnt = GNUNET_CONTAINER_multihashmap_get (mcm, &hc);
503 if (cnt == NULL)
504 {
505 mlen = strlen (data_mime_type) + 1;
506 cnt = GNUNET_malloc (sizeof (struct MetaCounter) +
507 dlen + mlen);
508 cnt->count = 1;
509 cnt->value = (const char *) &cnt[1];
510 cnt->value_mimetype = &cnt->value[dlen];
511 memcpy (&cnt[1],
512 data,
513 dlen);
514 memcpy ((char*) cnt->value_mimetype,
515 data_mime_type,
516 mlen);
517 cnt->type = type;
518 cnt->format = format;
519 GNUNET_CONTAINER_multihashmap_put (mcm,
520 &hc,
521 cnt,
522 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
523
524 }
525 else
526 {
527 cnt->count++;
528 if (cnt->format == EXTRACTOR_METAFORMAT_C_STRING)
529 cnt->format = format; /* possibly improve to UTF8 */
530 if (cnt->type == EXTRACTOR_METATYPE_UNKNOWN)
531 cnt->type = type;
532 }
533 return 0;
534}
535
536
537/**
538 * Extract metadata from a file and add it to the metamap and
539 * the metacounter.
540 *
541 * @param adc context to modify
542 * @param filename name of the file to process
543 */
544static void
545extract_file (struct AddDirContext *adc,
546 const char *filename)
547{
548 struct PublishData *pd;
549 GNUNET_HashCode hc;
550 const char *short_fn;
551 const char *ss;
552
553 adc->dir_entry_count++;
554 pd = GNUNET_malloc (sizeof (struct PublishData));
555 pd->meta = GNUNET_CONTAINER_meta_data_create ();
556 GNUNET_FS_meta_data_extract_from_file (pd->meta,
557 filename,
558 GNUNET_FS_GTK_get_le_plugins());
559 GNUNET_CONTAINER_meta_data_delete (pd->meta,
560 EXTRACTOR_METATYPE_FILENAME,
561 NULL, 0);
562 short_fn = filename;
563 while (NULL != (ss = strstr (short_fn, DIR_SEPARATOR_STR)))
564 short_fn = 1 + ss;
565 GNUNET_CONTAINER_meta_data_insert (pd->meta,
566 "<gnunet-gtk>",
567 EXTRACTOR_METATYPE_FILENAME,
568 EXTRACTOR_METAFORMAT_UTF8,
569 "text/plain",
570 short_fn,
571 strlen(short_fn)+1);
572
573
574 gtk_tree_store_insert_before (adc->ts,
575 &pd->iter,
576 adc->parent,
577 NULL);
578 GNUNET_CRYPTO_hash (filename,
579 strlen (filename),
580 &hc);
581 GNUNET_CONTAINER_multihashmap_put (adc->metamap,
582 &hc,
583 pd,
584 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
585 GNUNET_CONTAINER_meta_data_iterate (pd->meta,
586 &add_to_meta_counter,
587 adc->metacounter);
588}
589
590
591/**
592 * Remove the keyword from the ksk URI.
593 *
594 * @param cls the ksk uri
595 * @param keyword the word to remove
596 * @param is_mandatory ignored
597 * @return always GNUNET_OK
598 */
599static int
600remove_keyword (void *cls,
601 const char *keyword,
602 int is_mandatory)
603{
604 struct GNUNET_FS_Uri *ksk = cls;
605
606 GNUNET_FS_uri_ksk_remove_keyword (ksk, keyword);
607 return GNUNET_OK;
608}
609
610
611/**
612 * Add the specifics of the given entry to the tree store.
613 * Derive KSK from the given meta data, but exclude meta
614 * data given in "md_no_ksk" for keyword generation.
615 *
616 * @param ts tree store to modify
617 * @param iter position in the tree store for this file
618 * @param filename file to add
619 * @param bo block options
620 * @param do_index should we index or insert?
621 * @param md_no_ksk metadata with keywords NOT to add
622 * @param meta metadata for the file
623 */
624static void
625add_entry_to_ts (GtkTreeStore *ts,
626 GtkTreeIter *iter,
627 const char *filename,
628 const struct GNUNET_FS_BlockOptions *bo,
629 int do_index,
630 struct GNUNET_CONTAINER_MetaData *md_no_ksk,
631 struct GNUNET_CONTAINER_MetaData *meta)
632{
633 char *file_size_fancy;
634 struct GNUNET_FS_FileInformation *fi;
635 GtkTreeRowReference *row_reference;
636 GtkTreePath *path;
637 uint64_t file_size;
638 struct GNUNET_FS_Uri *ksk_uri;
639 struct GNUNET_FS_Uri *kill_ksk;
640 const char *ss;
641 const char *short_fn;
642 struct stat sbuf;
643
644 if (0 != STAT (filename, &sbuf))
645 return;
646 if (S_ISDIR (sbuf.st_mode))
647 {
648 file_size = 0;
649 }
650 else
651 {
652 if (GNUNET_OK !=
653 GNUNET_DISK_file_size (filename,
654 &file_size,
655 GNUNET_YES))
656 {
657 GNUNET_break (0);
658 return;
659 }
660 }
661 ksk_uri = GNUNET_FS_uri_ksk_create_from_meta_data (meta);
662 kill_ksk = GNUNET_FS_uri_ksk_create_from_meta_data (md_no_ksk);
663 if (kill_ksk != NULL)
664 {
665 GNUNET_FS_uri_ksk_get_keywords (kill_ksk,
666 &remove_keyword,
667 ksk_uri);
668 GNUNET_FS_uri_destroy (kill_ksk);
669 }
670 path = gtk_tree_model_get_path (GTK_TREE_MODEL (ts),
671 iter);
672 row_reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (ts),
673 path);
674 gtk_tree_path_free (path);
675 if (S_ISDIR (sbuf.st_mode))
676 {
677 GNUNET_CONTAINER_meta_data_delete (meta,
678 EXTRACTOR_METATYPE_MIMETYPE,
679 NULL, 0);
680 GNUNET_FS_meta_data_make_directory (meta);
681 GNUNET_FS_uri_ksk_add_keyword (ksk_uri,
682 GNUNET_FS_DIRECTORY_MIME,
683 GNUNET_NO);
684 fi = GNUNET_FS_file_information_create_empty_directory (GNUNET_FS_GTK_get_fs_handle (),
685 row_reference,
686 ksk_uri,
687 meta,
688 bo);
689 }
690 else
691 {
692 fi = GNUNET_FS_file_information_create_from_file (GNUNET_FS_GTK_get_fs_handle (),
693 row_reference,
694 filename,
695 ksk_uri,
696 meta,
697 do_index,
698 bo);
699 }
700 GNUNET_CONTAINER_meta_data_destroy (meta);
701 GNUNET_FS_uri_destroy (ksk_uri);
702 if (S_ISDIR (sbuf.st_mode))
703 file_size_fancy = GNUNET_strdup (MARKER_DIR_FILE_SIZE);
704 else
705 file_size_fancy = GNUNET_STRINGS_byte_size_fancy (file_size);
706 short_fn = filename;
707 while (NULL != (ss = strstr (short_fn, DIR_SEPARATOR_STR)))
708 short_fn = 1 + ss;
709 gtk_tree_store_set (ts, iter,
710 0, file_size_fancy,
711 1, (gboolean) do_index,
712 2, short_fn,
713 3, (guint) bo->anonymity_level,
714 4, (guint) bo->content_priority,
715 5, fi,
716 -1);
717 GNUNET_free (file_size_fancy);
718}
719
720
721/**
722 * Function called by the directory iterator to
723 * (recursively) add all of the files in the
724 * directory to the tree.
725 *
726 * @param cls the 'struct AddDirContext*' we're in
727 * @param filename file or directory to scan
728 */
729static int
730publish_entry (void *cls,
731 const char *filename)
732{
733 struct AddDirContext *adc = cls;
734 struct PublishData *pd;
735 GNUNET_HashCode hc;
736
737 GNUNET_CRYPTO_hash (filename,
738 strlen (filename),
739 &hc);
740 pd = GNUNET_CONTAINER_multihashmap_get (adc->metamap,
741 &hc);
742 add_entry_to_ts (adc->ts,
743 &pd->iter,
744 filename,
745 &adc->bo,
746 adc->do_index,
747 adc->no_ksk,
748 pd->meta);
749 GNUNET_CONTAINER_multihashmap_remove (adc->metamap,
750 &hc,
751 pd);
752 GNUNET_free (pd);
753 return GNUNET_OK;
754}
755
756
757/**
758 * Context passed to 'migrate_and_drop'.
759 */
760struct MetaProcessContext
761{
762 /**
763 * Metadata with all the keywords we migrated to the parent.
764 */
765 struct GNUNET_CONTAINER_MetaData *md;
766
767 /**
768 * How often does a keyword have to occur to be
769 * migrated to the parent?
770 */
771 unsigned int threshold;
772};
773
774
775/**
776 * Copy "frequent" meta data entries over to the
777 * target meta data struct, free the counters.
778 *
779 */
780static int
781migrate_and_drop (void *cls,
782 const GNUNET_HashCode *key,
783 void *value)
784{
785 struct MetaProcessContext *mpc = cls;
786 struct MetaCounter *counter = value;
787
788 if (counter->count >= mpc->threshold)
789 {
790 GNUNET_CONTAINER_meta_data_insert (mpc->md,
791 "<gnunet-gtk>",
792 counter->type,
793 counter->format,
794 counter->value_mimetype,
795 counter->value,
796 strlen (counter->value)+1);
797 }
798 GNUNET_free (counter);
799 return GNUNET_YES;
800}
801
802
803/**
804 * Go over the collected meta data from all entries in the
805 * directory and push common meta data up one level (by
806 * adding it to the returned struct).
807 *
808 * @param adc collection of child meta data
809 * @return meta data to moved to parent
810 */
811static struct GNUNET_CONTAINER_MetaData *
812process_metadata (struct AddDirContext *adc)
813{
814 struct MetaProcessContext mpc;
815
816 mpc.md = GNUNET_CONTAINER_meta_data_create ();
817 mpc.threshold = (adc->dir_entry_count + 1) / 2; /* 50% */
818 GNUNET_CONTAINER_multihashmap_iterate (adc->metacounter,
819 &migrate_and_drop,
820 &mpc);
821 GNUNET_CONTAINER_multihashmap_destroy (adc->metacounter);
822 return mpc.md;
823}
824
825
826/**
827 * Function called by the directory iterator to
828 * (recursively) add all of the files in the
829 * directory to the tree.
830 *
831 * @param cls the 'struct AddDirContext*' we're in
832 * @param filename file or directory to scan
833 */
834static int
835scan_directory (void *cls,
836 const char *filename)
837
838{
839 struct AddDirContext *adc = cls;
840 struct stat sbuf;
841 GtkTreeIter *parent;
842 struct PublishData *pd;
843 GNUNET_HashCode hc;
844 struct GNUNET_CONTAINER_MultiHashMap *mhm;
845 struct GNUNET_CONTAINER_MultiHashMap *mcm;
846 unsigned int pc;
847
848 if (0 != STAT (filename, &sbuf))
849 return GNUNET_OK;
850 if (S_ISDIR (sbuf.st_mode))
851 {
852 parent = adc->parent;
853 mhm = adc->metamap;
854 mcm = adc->metacounter;
855 pc = adc->dir_entry_count;
856 adc->metamap = GNUNET_CONTAINER_multihashmap_create (1024);
857 adc->metacounter = GNUNET_CONTAINER_multihashmap_create (1024);
858 adc->dir_entry_count = 0;
859 pd = GNUNET_malloc (sizeof (struct PublishData));
860 gtk_tree_store_insert_before (adc->ts,
861 &pd->iter,
862 parent,
863 NULL);
864 adc->parent = &pd->iter;
865 GNUNET_DISK_directory_scan (filename,
866 &scan_directory,
867 adc);
868 pd->meta = process_metadata (adc);
869 adc->no_ksk = pd->meta;
870 GNUNET_DISK_directory_scan (filename,
871 &publish_entry,
872 adc);
873 GNUNET_CONTAINER_multihashmap_destroy (adc->metamap);
874 adc->metamap = mhm;
875 adc->metacounter = mcm;
876 adc->parent = parent;
877 adc->dir_entry_count = pc + 1;
878 if (adc->metamap != NULL)
879 {
880 GNUNET_CRYPTO_hash (filename,
881 strlen (filename),
882 &hc);
883 GNUNET_CONTAINER_multihashmap_put (adc->metamap,
884 &hc,
885 pd,
886 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
887 GNUNET_CONTAINER_meta_data_iterate (pd->meta,
888 &add_to_meta_counter,
889 mcm);
890 }
891 else
892 {
893 GNUNET_assert (mcm == NULL);
894 /* we're top-level */
895 add_entry_to_ts (adc->ts,
896 &pd->iter,
897 filename,
898 &adc->bo,
899 adc->do_index,
900 NULL,
901 pd->meta);
902 }
903 }
904 else
905 {
906 GNUNET_assert (adc->metamap != NULL);
907 extract_file (adc, filename);
908 }
909 return GNUNET_OK;
910}
911
912
913/**
914 * Add a directory to the tree model.
915 *
916 * @param filename directory name to add
917 * @param bo block options
918 * @param do_index should we index?
919 */
920static void
921add_dir (const char *filename,
922 const struct GNUNET_FS_BlockOptions *bo,
923 int do_index)
924{
925 struct stat sbuf;
926 struct AddDirContext scan_ctx;
927
928 if (0 != STAT (filename, &sbuf))
929 return;
930 if (! S_ISDIR (sbuf.st_mode))
931 {
932 GNUNET_break (0);
933 return;
934 }
935 memset (&scan_ctx, 0, sizeof (scan_ctx));
936 scan_ctx.bo = *bo;
937 scan_ctx.do_index = do_index;
938 scan_ctx.ts = GTK_TREE_STORE (gtk_builder_get_object (master_builder,
939 "GNUNET_GTK_file_sharing_publishing_tree_store"));
940 scan_directory (&scan_ctx, filename);
941}
942
943
944/* ************ code for adding directories ends here ************* */
945
946
947static void
948selection_changed_cb (GtkTreeSelection *ts,
949 gpointer user_data)
950{
951 update_selectivity ();
952}
953
954
955static void
956remove_old_entry (GtkTreeStore *ts,
957 GtkTreeIter *root)
958{
959 GtkTreeIter child;
960
961 while (TRUE == gtk_tree_model_iter_children (GTK_TREE_MODEL (ts),
962 &child, root))
963 remove_old_entry (ts, &child);
964 gtk_tree_store_remove (ts, root);
965}
966
967
968/**
969 * Move an entry in the tree.
970 */
971static void
972move_entry (GtkTreeModel *tm,
973 GtkTreeIter *old,
974 GtkTreeIter *newpos,
975 int dsel)
976{
977 struct GNUNET_FS_FileInformation *fip;
978 GtkTreeView *tv;
979 gint do_index;
980 gchar *short_fn;
981 guint anonymity_level;
982 guint priority;
983 char *fsf;
984 GtkTreePath *path;
985 GtkTreeSelection *sel;
986 GtkTreeIter child;
987 GtkTreeIter cnewpos;
988 GtkTreeRowReference *rr;
989 GtkTreeRowReference *rr2;
990
991 gtk_tree_model_get (tm,
992 old,
993 0, &fsf,
994 1, &do_index,
995 2, &short_fn,
996 3, &anonymity_level,
997 4, &priority,
998 5, &fip,
999 -1);
1000 gtk_tree_store_set (GTK_TREE_STORE (tm), newpos,
1001 0, fsf,
1002 1, do_index,
1003 2, short_fn,
1004 3, (guint)anonymity_level,
1005 4, (guint) priority,
1006 5, fip,
1007 -1);
1008 sel = NULL;
1009 tv = NULL;
1010 if (dsel == GNUNET_YES)
1011 {
1012 tv = GTK_TREE_VIEW (gtk_builder_get_object (master_builder,
1013 "GNUNET_GTK_master_publish_dialog_file_information_tree_view"));
1014 sel = gtk_tree_view_get_selection (tv);
1015 path = gtk_tree_model_get_path (tm, newpos);
1016 rr = gtk_tree_row_reference_new (tm, path);
1017 gtk_tree_path_free (path);
1018 }
1019 else
1020 {
1021 rr = NULL;
1022 }
1023 if (TRUE == gtk_tree_model_iter_children (tm, &child, old))
1024 {
1025 do
1026 {
1027 path = gtk_tree_model_get_path (tm, &child);
1028 rr2 = gtk_tree_row_reference_new (tm, path);
1029 gtk_tree_path_free (path);
1030 gtk_tree_store_insert_before (GTK_TREE_STORE (tm),
1031 &cnewpos, newpos, NULL);
1032 move_entry (tm, &child, &cnewpos, GNUNET_NO);
1033 path = gtk_tree_row_reference_get_path (rr2);
1034 gtk_tree_row_reference_free (rr2);
1035 GNUNET_assert (TRUE == gtk_tree_model_get_iter (tm,
1036 &child,
1037 path));
1038 gtk_tree_path_free (path);
1039 }
1040 while (TRUE == gtk_tree_model_iter_next (tm, &child));
1041 }
1042 g_free (short_fn);
1043 g_free (fsf);
1044 if (dsel == GNUNET_YES)
1045 {
1046 path = gtk_tree_row_reference_get_path (rr);
1047 gtk_tree_row_reference_free (rr);
1048 gtk_tree_view_expand_to_path (tv, path);
1049 GNUNET_assert (TRUE == gtk_tree_model_get_iter (tm,
1050 newpos,
1051 path));
1052 gtk_tree_path_free (path);
1053 gtk_tree_selection_select_iter (sel,
1054 newpos);
1055 }
1056 update_selectivity ();
1057}
1058
1059/**
1060 * User has changed the "current" identifier for the content in
1061 * the GtkTreeView. Update the model.
1062 */
1063void
1064GNUNET_GTK_master_publish_dialog_pseudonym_updates_renderer_edited_cb (GtkCellRendererText *renderer,
1065 gchar *cpath,
1066 gchar *new_text,
1067 gpointer user_data)
1068{
1069 GtkTreeIter iter;
1070 GtkTreeStore *ts;
1071
1072 ts = GTK_TREE_STORE (gtk_builder_get_object (master_builder,
1073 "GNUNET_GTK_pseudonym_tree_store"));
1074
1075 if (TRUE !=
1076 gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (ts), &iter, cpath))
1077 {
1078 GNUNET_break (0);
1079 return;
1080 }
1081 gtk_tree_store_set (ts, &iter, 5, new_text, -1);
1082 update_selectivity ();
1083}
1084
1085
1086/**
1087 * User has changed the "current" identifier for the content in
1088 * the GtkTreeView. Update the model.
1089 */
1090void
1091GNUNET_GTK_master_publish_dialog_pseudonym_identifier_renderer_edited_cb (GtkCellRendererText *renderer,
1092 gchar *cpath,
1093 gchar *new_text,
1094 gpointer user_data)
1095{
1096 GtkTreeIter iter;
1097 GtkTreeStore *ts;
1098
1099 ts = GTK_TREE_STORE (gtk_builder_get_object (master_builder,
1100 "GNUNET_GTK_pseudonym_tree_store"));
1101
1102 if (TRUE !=
1103 gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (ts), &iter, cpath))
1104 {
1105 GNUNET_break (0);
1106 return;
1107 }
1108 gtk_tree_store_set (ts, &iter, 2, new_text, -1);
1109 update_selectivity ();
1110}
1111
1112
1113void
1114GNUNET_GTK_master_publish_dialog_right_button_clicked_cb (GtkWidget * dummy,
1115 gpointer data)
1116{
1117 GtkTreeView *tv;
1118 GtkTreeModel *tm;
1119 GtkTreeSelection *sel;
1120 GtkTreeIter iter;
1121 GtkTreeIter parent;
1122 GtkTreeIter pred;
1123 GtkTreeIter prev;
1124 GtkTreeIter pos;
1125
1126 tv = GTK_TREE_VIEW (gtk_builder_get_object (master_builder,
1127 "GNUNET_GTK_master_publish_dialog_file_information_tree_view"));
1128 sel = gtk_tree_view_get_selection (tv);
1129 if (TRUE != gtk_tree_selection_get_selected (sel,
1130 &tm,
1131 &iter))
1132 {
1133 GNUNET_break (0);
1134 return;
1135 }
1136 if (TRUE == gtk_tree_model_iter_parent (tm, &parent, &iter))
1137 {
1138 GNUNET_assert (TRUE == gtk_tree_model_iter_children (tm, &pred, &parent));
1139 }
1140 else if (TRUE != gtk_tree_model_get_iter_first (tm, &pred))
1141 {
1142 GNUNET_break (0);
1143 return;
1144 }
1145 /* iterate over 'next' of pred to find out who our predecessor is! */
1146 memset (&prev, 0, sizeof (GtkTreeIter));
1147 while (GNUNET_YES != gtk_tree_iter_equals (tm, &pred, &iter))
1148 {
1149 prev = pred;
1150 GNUNET_assert (TRUE == gtk_tree_model_iter_next (tm, &pred));
1151 }
1152 gtk_tree_store_insert_before (GTK_TREE_STORE (tm),
1153 &pos, &prev, NULL);
1154 if (TRUE != gtk_tree_selection_get_selected (sel,
1155 &tm,
1156 &iter))
1157 {
1158 GNUNET_break (0);
1159 return;
1160 }
1161 move_entry (tm, &iter, &pos, GNUNET_YES);
1162 remove_old_entry (GTK_TREE_STORE (tm), &iter);
1163}
1164
1165
1166void
1167GNUNET_GTK_master_publish_dialog_left_button_clicked_cb (GtkWidget * dummy,
1168 gpointer data)
1169{
1170 GtkTreeView *tv;
1171 GtkTreeModel *tm;
1172 GtkTreeSelection *sel;
1173 GtkTreeIter iter;
1174 GtkTreeIter parent;
1175 GtkTreeIter pos;
1176
1177 tv = GTK_TREE_VIEW (gtk_builder_get_object (master_builder,
1178 "GNUNET_GTK_master_publish_dialog_file_information_tree_view"));
1179 sel = gtk_tree_view_get_selection (tv);
1180 if (TRUE != gtk_tree_selection_get_selected (sel,
1181 &tm,
1182 &iter))
1183 {
1184 GNUNET_break (0);
1185 return;
1186 }
1187 if (TRUE != gtk_tree_model_iter_parent (tm, &parent, &iter))
1188 {
1189 GNUNET_break (0);
1190 return;
1191 }
1192 gtk_tree_store_insert_after (GTK_TREE_STORE (tm),
1193 &pos, NULL, &parent);
1194 if (TRUE != gtk_tree_selection_get_selected (sel,
1195 &tm,
1196 &iter))
1197 {
1198 GNUNET_break (0);
1199 return;
1200 }
1201 move_entry (tm, &iter, &pos, GNUNET_YES);
1202 remove_old_entry (GTK_TREE_STORE (tm), &iter);
1203}
1204
1205
1206void
1207GNUNET_GTK_master_publish_dialog_up_button_clicked_cb (GtkWidget * dummy,
1208 gpointer data)
1209{
1210 GtkTreeView *tv;
1211 GtkTreeModel *tm;
1212 GtkTreeSelection *sel;
1213 GtkTreeIter iter;
1214 GtkTreeIter parent;
1215 GtkTreeIter pred;
1216 GtkTreeIter prev;
1217 GtkTreeIter *pprev;
1218 GtkTreeIter pos;
1219
1220 tv = GTK_TREE_VIEW (gtk_builder_get_object (master_builder,
1221 "GNUNET_GTK_master_publish_dialog_file_information_tree_view"));
1222 sel = gtk_tree_view_get_selection (tv);
1223 if (TRUE != gtk_tree_selection_get_selected (sel,
1224 &tm,
1225 &iter))
1226 {
1227 GNUNET_break (0);
1228 return;
1229 }
1230 if (TRUE == gtk_tree_model_iter_parent (tm, &parent, &iter))
1231 {
1232 GNUNET_assert (TRUE == gtk_tree_model_iter_children (tm, &pred, &parent));
1233 pprev = &parent;
1234 }
1235 else if (TRUE == gtk_tree_model_get_iter_first (tm, &pred))
1236 {
1237 pprev = NULL;
1238 }
1239 else
1240 {
1241 GNUNET_break (0);
1242 return;
1243 }
1244 /* iterate over 'next' of pred to find out who our predecessor is! */
1245 while (GNUNET_YES != gtk_tree_iter_equals (tm, &pred, &iter))
1246 {
1247 prev = pred;
1248 pprev = &prev;
1249 GNUNET_assert (TRUE == gtk_tree_model_iter_next (tm, &pred));
1250 }
1251 gtk_tree_store_insert_before (GTK_TREE_STORE (tm),
1252 &pos, NULL, pprev);
1253 if (TRUE != gtk_tree_selection_get_selected (sel,
1254 &tm,
1255 &iter))
1256 {
1257 GNUNET_break (0);
1258 return;
1259 }
1260 move_entry (tm, &iter, &pos, GNUNET_YES);
1261 remove_old_entry (GTK_TREE_STORE (tm), &iter);
1262}
1263
1264
1265void
1266GNUNET_GTK_master_publish_dialog_down_button_clicked_cb (GtkWidget * dummy,
1267 gpointer data)
1268{
1269 GtkTreeView *tv;
1270 GtkTreeModel *tm;
1271 GtkTreeSelection *sel;
1272 GtkTreeIter iter;
1273 GtkTreeIter next;
1274 GtkTreeIter pos;
1275
1276 tv = GTK_TREE_VIEW (gtk_builder_get_object (master_builder,
1277 "GNUNET_GTK_master_publish_dialog_file_information_tree_view"));
1278 sel = gtk_tree_view_get_selection (tv);
1279 if (TRUE != gtk_tree_selection_get_selected (sel,
1280 &tm,
1281 &iter))
1282 {
1283 GNUNET_break (0);
1284 return;
1285 }
1286 if (TRUE != gtk_tree_selection_get_selected (sel,
1287 &tm,
1288 &next))
1289 {
1290 GNUNET_break (0);
1291 return;
1292 }
1293 GNUNET_assert (TRUE == gtk_tree_model_iter_next (tm, &next));
1294 gtk_tree_store_insert_after (GTK_TREE_STORE (tm),
1295 &pos, NULL, &next);
1296 if (TRUE != gtk_tree_selection_get_selected (sel,
1297 &tm,
1298 &iter))
1299 {
1300 GNUNET_break (0);
1301 return;
1302 }
1303 move_entry (tm, &iter, &pos, GNUNET_YES);
1304 remove_old_entry (GTK_TREE_STORE (tm), &iter);
1305}
1306
1307
1308void
1309GNUNET_GTK_master_publish_dialog_new_button_clicked_cb (GtkWidget * dummy,
1310 gpointer data)
1311{
1312 GtkTreeView *tv;
1313 GtkTreeSelection *sel;
1314 GtkTreeIter iter;
1315 GtkTreeIter pos;
1316 struct GNUNET_FS_BlockOptions bo;
1317
1318 tv = GTK_TREE_VIEW (gtk_builder_get_object (master_builder,
1319 "GNUNET_GTK_master_publish_dialog_file_information_tree_view"));
1320 sel = gtk_tree_view_get_selection (tv);
1321 /* FIXME: consider opening a dialog to get
1322 * anonymity, priority and expiration prior
1323 * to calling this function (currently we
1324 * use default values for those).
1325 */
1326 bo.anonymity_level = 1;
1327 bo.content_priority = 1000;
1328 bo.expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS);
1329 bo.replication_level = 1;
1330 if (TRUE != gtk_tree_selection_get_selected (sel,
1331 NULL,
1332 &iter))
1333 {
1334 create_dir_at_iter ("unnamed/",
1335 &bo,
1336 NULL, &pos);
1337 return;
1338 }
1339 create_dir_at_iter ("unnamed/",
1340 &bo,
1341 &iter, &pos);
1342}
1343
1344
1345void
1346GNUNET_GTK_master_publish_dialog_add_button_clicked_cb (GtkWidget * dummy,
1347 gpointer data)
1348{
1349 GtkWidget *ad;
1350 GtkBuilder *builder;
1351 char *filename;
1352 struct GNUNET_FS_BlockOptions bo;
1353 int do_index;
1354 GtkSpinButton *sb;
1355
1356 builder = GNUNET_GTK_get_new_builder ("publish-file-dialog.glade");
1357 if (builder == NULL)
1358 {
1359 GNUNET_break (0);
1360 return;
1361 }
1362 ad = GTK_WIDGET (gtk_builder_get_object (builder,
1363 "GNUNET_GTK_publish_file_dialog"));
1364 GNUNET_FS_GTK_setup_expiration_year_adjustment (builder);
1365 if (GTK_RESPONSE_OK != gtk_dialog_run (GTK_DIALOG (ad)))
1366 {
1367 gtk_widget_destroy (ad);
1368 g_object_unref (G_OBJECT (builder));
1369 return;
1370 }
1371 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(ad));
1372 sb = GTK_SPIN_BUTTON (gtk_builder_get_object (builder,
1373 "GNUNET_GTK_publish_file_dialog_expiration_year_spin_button"));
1374 bo.anonymity_level = gtk_spin_button_get_value (GTK_SPIN_BUTTON (gtk_builder_get_object (builder,
1375 "GNUNET_GTK_publish_file_dialog_anonymity_spin_button")));
1376 bo.content_priority = gtk_spin_button_get_value (GTK_SPIN_BUTTON (gtk_builder_get_object (builder,
1377 "GNUNET_GTK_publish_file_dialog_priority_spin_button")));
1378 bo.expiration_time = GNUNET_FS_GTK_get_expiration_time (sb);
1379 bo.replication_level = 1; /* FIXME... */
1380 do_index = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder,
1381 "GNUNET_GTK_publish_file_dialog_do_index_checkbutton")));
1382 add_file_at_iter (filename,
1383 &bo, do_index,
1384 NULL);
1385 gtk_widget_destroy (ad);
1386 g_object_unref (G_OBJECT (builder));
1387 g_free (filename);
1388 update_selectivity ();
1389}
1390
1391
1392void
1393GNUNET_GTK_master_publish_dialog_edit_button_clicked_cb (GtkWidget * dummy,
1394 gpointer data)
1395{
1396 GtkTreeView *tv;
1397 GtkTreeModel *tm;
1398 GtkTreeSelection *sel;
1399 GtkTreeIter iter;
1400 int do_index;
1401 guint anonymity_level;
1402 guint priority;
1403 gchar *short_fn;
1404 struct GNUNET_FS_FileInformation *fip;
1405
1406 tv = GTK_TREE_VIEW (gtk_builder_get_object (master_builder,
1407 "GNUNET_GTK_master_publish_dialog_file_information_tree_view"));
1408 sel = gtk_tree_view_get_selection (tv);
1409 if (TRUE != gtk_tree_selection_get_selected (sel,
1410 &tm,
1411 &iter))
1412 {
1413 GNUNET_break (0);
1414 return;
1415 }
1416 gtk_tree_model_get (tm,
1417 &iter,
1418 1, &do_index,
1419 2, &short_fn,
1420 3, &anonymity_level,
1421 4, &priority,
1422 5, &fip,
1423 -1);
1424 GNUNET_GTK_edit_publish_dialog (&do_index,
1425 &short_fn,
1426 &anonymity_level,
1427 &priority,
1428 fip);
1429 gtk_tree_store_set (GTK_TREE_STORE (tm),
1430 &iter,
1431 1, do_index,
1432 2, short_fn,
1433 3, anonymity_level,
1434 4, priority,
1435 -1);
1436 g_free (short_fn);
1437}
1438
1439
1440/**
1441 * Free row reference stored in the file information's
1442 * client-info pointer.
1443 */
1444static int
1445free_fi_row_reference (void *cls,
1446 struct GNUNET_FS_FileInformation *fi,
1447 uint64_t length,
1448 struct GNUNET_CONTAINER_MetaData *meta,
1449 struct GNUNET_FS_Uri **uri,
1450 struct GNUNET_FS_BlockOptions *bo,
1451 int *do_index,
1452 void **client_info)
1453{
1454 GtkTreeRowReference *row = *client_info;
1455
1456 if (row == NULL)
1457 {
1458 GNUNET_break (0);
1459 return GNUNET_OK;
1460 }
1461 gtk_tree_row_reference_free (row);
1462 return GNUNET_OK;
1463}
1464
1465
1466
1467void
1468GNUNET_GTK_master_publish_dialog_delete_button_clicked_cb (GtkWidget * dummy,
1469 gpointer data)
1470{
1471 GtkTreeView *tv;
1472 GtkTreeModel *tm;
1473 GtkTreeSelection *sel;
1474 GtkTreeIter iter;
1475 struct GNUNET_FS_FileInformation *fip;
1476
1477 tv = GTK_TREE_VIEW (gtk_builder_get_object (master_builder,
1478 "GNUNET_GTK_master_publish_dialog_file_information_tree_view"));
1479 sel = gtk_tree_view_get_selection (tv);
1480 if (TRUE != gtk_tree_selection_get_selected (sel,
1481 &tm,
1482 &iter))
1483 {
1484 GNUNET_break (0);
1485 return;
1486 }
1487 gtk_tree_model_get (tm,
1488 &iter,
1489 5, &fip,
1490 -1);
1491 GNUNET_FS_file_information_destroy (fip,
1492 &free_fi_row_reference,
1493 NULL);
1494 gtk_tree_store_remove (GTK_TREE_STORE (tm),
1495 &iter);
1496 update_selectivity ();
1497}
1498
1499
1500void
1501GNUNET_GTK_master_publish_dialog_open_button_clicked_cb (GtkWidget * dummy,
1502 gpointer data)
1503{
1504 GtkWidget *ad;
1505 GtkBuilder *builder;
1506 char *filename;
1507 int do_index;
1508 GtkSpinButton *sb;
1509 struct GNUNET_FS_BlockOptions bo;
1510
1511 builder = GNUNET_GTK_get_new_builder ("publish-directory-dialog.glade");
1512 if (builder == NULL)
1513 {
1514 GNUNET_break (0);
1515 return;
1516 }
1517 GNUNET_FS_GTK_setup_expiration_year_adjustment (builder);
1518 ad = GTK_WIDGET (gtk_builder_get_object (builder,
1519 "GNUNET_GTK_publish_directory_dialog"));
1520 if (GTK_RESPONSE_OK != gtk_dialog_run (GTK_DIALOG (ad)))
1521 {
1522 gtk_widget_destroy (ad);
1523 g_object_unref (G_OBJECT (builder));
1524 return;
1525 }
1526 filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER(ad));
1527 sb = GTK_SPIN_BUTTON (gtk_builder_get_object (builder,
1528 "GNUNET_GTK_publish_directory_dialog_expiration_year_spin_button"));
1529 bo.anonymity_level = gtk_spin_button_get_value (GTK_SPIN_BUTTON (gtk_builder_get_object (builder,
1530 "GNUNET_GTK_publish_directory_dialog_anonymity_spin_button")));
1531 bo.content_priority = gtk_spin_button_get_value (GTK_SPIN_BUTTON (gtk_builder_get_object (builder,
1532 "GNUNET_GTK_publish_directory_dialog_priority_spin_button")));
1533 bo.expiration_time = GNUNET_FS_GTK_get_expiration_time (sb);
1534 do_index = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object (builder,
1535 "GNUNET_GTK_publish_directory_dialog_do_index_checkbutton")));
1536
1537 gtk_widget_destroy (ad);
1538 g_object_unref (G_OBJECT (builder));
1539 /* FIXME: open progress dialog here... */
1540 add_dir (filename, &bo, do_index);
1541 g_free (filename);
1542 update_selectivity ();
1543}
1544
1545
1546/**
1547 * Get the file information struct corresponding to the
1548 * given iter in the publish dialog tree model. Recursively
1549 * builds the file information struct from the subtree.
1550 *
1551 * @param tm model to grab fi from
1552 * @param iter position to grab fi from
1553 * @return file information from the given position (never NULL)
1554 */
1555static struct GNUNET_FS_FileInformation *
1556get_file_information (GtkTreeModel *tm,
1557 GtkTreeIter *iter)
1558{
1559 struct GNUNET_FS_FileInformation *fi;
1560 struct GNUNET_FS_FileInformation *fic;
1561 GtkTreeIter child;
1562
1563 gtk_tree_model_get (tm, iter,
1564 5, &fi,
1565 -1);
1566 gtk_tree_store_set (GTK_TREE_STORE (tm), iter,
1567 5, NULL,
1568 -1);
1569 GNUNET_assert (fi != NULL);
1570 if (gtk_tree_model_iter_children (tm, &child, iter))
1571 {
1572 GNUNET_break (GNUNET_YES ==
1573 GNUNET_FS_file_information_is_directory (fi));
1574 do
1575 {
1576 fic = get_file_information (tm, &child);
1577 GNUNET_break (GNUNET_OK ==
1578 GNUNET_FS_file_information_add (fi, fic));
1579 }
1580 while (gtk_tree_model_iter_next (tm, &child));
1581 }
1582 return fi;
1583}
1584
1585
1586/**
1587 * Closure for 'add_updateable_to_ts'.
1588 */
1589struct UpdateableContext
1590{
1591 /**
1592 * Parent of current insertion.
1593 */
1594 GtkTreeIter *parent;
1595
1596 /**
1597 * Tree store we are modifying.
1598 */
1599 GtkTreeStore *ts;
1600
1601 /**
1602 * Name of the namespace.
1603 */
1604 const char *namespace_name;
1605
1606 /**
1607 * Handle to the namespace.
1608 */
1609 struct GNUNET_FS_Namespace *ns;
1610
1611 /**
1612 * Hash codes of identifiers already added to tree store.
1613 */
1614 struct GNUNET_CONTAINER_MultiHashMap *seen;
1615
1616 /**
1617 * Did the iterator get called?
1618 */
1619 int update_called;
1620};
1621
1622
1623/**
1624 * Add updateable entries to the tree view.
1625 *
1626 * @param cls closure
1627 * @param last_id ID to add
1628 * @param last_uri associated URI
1629 * @param last_meta associate meta data
1630 * @param next_id ID for future updates
1631 */
1632static void
1633add_updateable_to_ts (void *cls,
1634 const char *last_id,
1635 const struct GNUNET_FS_Uri *last_uri,
1636 const struct GNUNET_CONTAINER_MetaData *last_meta,
1637 const char *next_id)
1638{
1639 struct UpdateableContext *uc = cls;
1640 struct UpdateableContext sc;
1641 GtkTreeIter iter;
1642 GtkTreeIter titer;
1643 char *desc;
1644 GNUNET_HashCode hc;
1645
1646 uc->update_called = GNUNET_YES;
1647 GNUNET_CRYPTO_hash (last_id,
1648 strlen (last_id),
1649 &hc);
1650 if (NULL !=
1651 GNUNET_CONTAINER_multihashmap_get (uc->seen,
1652 &hc))
1653 return;
1654 GNUNET_CONTAINER_multihashmap_put (uc->seen,
1655 &hc,
1656 "dummy",
1657 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST);
1658 desc = GNUNET_CONTAINER_meta_data_get_first_by_types (last_meta,
1659 EXTRACTOR_METATYPE_DESCRIPTION,
1660 EXTRACTOR_METATYPE_TITLE,
1661 EXTRACTOR_METATYPE_BOOK_TITLE,
1662 EXTRACTOR_METATYPE_FILENAME,
1663 EXTRACTOR_METATYPE_SUMMARY,
1664 EXTRACTOR_METATYPE_ALBUM,
1665 EXTRACTOR_METATYPE_COMMENT,
1666 EXTRACTOR_METATYPE_SUBJECT,
1667 -1);
1668 gtk_tree_store_insert_with_values (uc->ts,
1669 &iter,
1670 uc->parent,
1671 G_MAXINT,
1672 0, uc->namespace_name,
1673 1, uc->ns,
1674 2, last_id,
1675 3, GNUNET_FS_uri_dup (last_uri),
1676 4, GNUNET_CONTAINER_meta_data_duplicate (last_meta),
1677 5, "",
1678 6, desc,
1679 7, TRUE /* update editable (always) */,
1680 8, FALSE /* current not editable (only for top-level) */,
1681 -1);
1682 GNUNET_free_non_null (desc);
1683 sc.parent = &iter;
1684 sc.ts = uc->ts;
1685 sc.namespace_name = uc->namespace_name;
1686 sc.ns = uc->ns;
1687 sc.seen = uc->seen;
1688 sc.update_called = GNUNET_NO;
1689 GNUNET_FS_namespace_list_updateable (uc->ns,
1690 next_id,
1691 &add_updateable_to_ts,
1692 &sc);
1693 if ( (sc.update_called == GNUNET_NO) &&
1694 (next_id != NULL) &&
1695 (strlen (next_id) > 0) )
1696 {
1697 /* add leaf */
1698 gtk_tree_store_insert_with_values (uc->ts,
1699 &titer,
1700 &iter,
1701 G_MAXINT,
1702 0, uc->namespace_name,
1703 1, uc->ns,
1704 2, next_id,
1705 3, NULL,
1706 4, NULL,
1707 5, "",
1708 6, "",
1709 7, TRUE /* update editable (always) */,
1710 8, FALSE /* current not editable (only for top-level) */,
1711 -1);
1712 }
1713}
1714
1715
1716/**
1717 * Add all updateable entries of the current namespace to the
1718 * tree store.
1719 *
1720 * @param cls the 'GtkTreeStore' to update
1721 * @param name name of the namespace to add
1722 * @param id identity of the namespace to add
1723 */
1724static void
1725add_namespace_to_ts (void *cls,
1726 const char *name,
1727 const GNUNET_HashCode *id)
1728{
1729 GtkTreeStore *ts = cls;
1730 struct UpdateableContext uc;
1731 GtkTreeIter iter;
1732
1733 uc.parent = &iter;
1734 uc.namespace_name = name;
1735 uc.ts = ts;
1736 uc.ns = GNUNET_FS_namespace_create (GNUNET_FS_GTK_get_fs_handle (),
1737 name);
1738 uc.update_called = GNUNET_NO;
1739 gtk_tree_store_insert_with_values (ts, &iter,
1740 NULL,
1741 G_MAXINT,
1742 0, name,
1743 1, uc.ns,
1744 2, NULL /* last-id */,
1745 3, NULL /* last-uri */,
1746 4, NULL /* meta */,
1747 5, NULL /* next-ID */,
1748 6, NULL /* last-description */,
1749 7, TRUE /* update editable */,
1750 8, TRUE /* current editable */,
1751 -1);
1752 uc.seen = GNUNET_CONTAINER_multihashmap_create (128);
1753 GNUNET_FS_namespace_list_updateable (uc.ns, NULL,
1754 &add_updateable_to_ts, &uc);
1755 GNUNET_CONTAINER_multihashmap_destroy (uc.seen);
1756}
1757
1758
1759static void
1760free_pseudonym_tree_store (GtkTreeModel *tm,
1761 GtkTreeIter *iter)
1762{
1763 struct GNUNET_FS_Uri *uri;
1764 struct GNUNET_CONTAINER_MetaData *meta;
1765 struct GNUNET_FS_Namespace *ns;
1766 GtkTreeIter child;
1767
1768 gtk_tree_model_get (tm,
1769 iter,
1770 1, &ns,
1771 3, &uri,
1772 4, &meta,
1773 -1);
1774 if (uri != NULL)
1775 GNUNET_FS_uri_destroy (uri);
1776 if (meta != NULL)
1777 GNUNET_CONTAINER_meta_data_destroy (meta);
1778 if (ns != NULL)
1779 {
1780 // FIXME: delete ns?
1781 // GNUNET_FS_namespace_delete (nso, GNUNET_NO);
1782 }
1783 if (TRUE ==
1784 gtk_tree_model_iter_children (tm, &child, iter))
1785 {
1786 do
1787 {
1788 free_pseudonym_tree_store (tm,
1789 &child);
1790 }
1791 while (TRUE == gtk_tree_model_iter_next (tm,
1792 &child));
1793 }
1794}
1795
1796
1797static void
1798free_file_information_tree_store (GtkTreeModel *tm,
1799 GtkTreeIter *iter)
1800{
1801 GtkTreeIter child;
1802 struct GNUNET_FS_FileInformation *fip;
1803
1804 gtk_tree_model_get (tm,
1805 iter,
1806 5, &fip,
1807 -1);
1808 if (fip != NULL)
1809 GNUNET_FS_file_information_destroy (fip, NULL, NULL);
1810 if (TRUE ==
1811 gtk_tree_model_iter_children (tm, &child, iter))
1812 {
1813 do
1814 {
1815 free_file_information_tree_store (tm,
1816 &child);
1817 }
1818 while (TRUE == gtk_tree_model_iter_next (tm,
1819 &child));
1820 }
1821}
1822
1823
1824/**
1825 */
1826void
1827GNUNET_GTK_main_menu_file_publish_activate_cb (GtkWidget * dummy,
1828 gpointer data)
1829{
1830 GtkWidget *ad;
1831 GtkTreeStore *ts;
1832 gint ret;
1833 GtkTreeView *tv;
1834 GtkTreeSelection *sel;
1835 GtkTreeIter iter;
1836 struct GNUNET_FS_FileInformation *fi;
1837 GtkTreeModel *tm;
1838 GtkTreeModel *ptm;
1839 struct GNUNET_FS_Namespace *namespace;
1840 gchar *namespace_id;
1841 gchar *namespace_uid;
1842
1843 GNUNET_assert (master_builder == NULL);
1844 master_builder = GNUNET_GTK_get_new_builder ("publish_dialog.glade");
1845 if (master_builder == NULL)
1846 return;
1847 tv = GTK_TREE_VIEW (gtk_builder_get_object (master_builder,
1848 "GNUNET_GTK_master_publish_dialog_file_information_tree_view"));
1849 sel = gtk_tree_view_get_selection (tv);
1850 g_signal_connect(G_OBJECT(sel), "changed",
1851 G_CALLBACK(selection_changed_cb), NULL);
1852 ad = GTK_WIDGET (gtk_builder_get_object (master_builder,
1853 "GNUNET_GTK_master_publish_dialog"));
1854 ts = GTK_TREE_STORE (gtk_builder_get_object (master_builder,
1855 "GNUNET_GTK_pseudonym_tree_store"));
1856 GNUNET_FS_namespace_list (GNUNET_FS_GTK_get_fs_handle (),
1857 &add_namespace_to_ts,
1858 ts);
1859 tm = GTK_TREE_MODEL (gtk_builder_get_object (master_builder,
1860 "GNUNET_GTK_file_sharing_publishing_tree_store"));
1861 tv = GTK_TREE_VIEW (gtk_builder_get_object (master_builder,
1862 "GNUNET_GTK_master_publish_dialog_pseudonym_tree_view"));
1863 sel = gtk_tree_view_get_selection (tv);
1864 g_signal_connect(G_OBJECT(sel), "changed",
1865 G_CALLBACK(selection_changed_cb), NULL);
1866 ret = gtk_dialog_run (GTK_DIALOG (ad));
1867 if (ret == GTK_RESPONSE_OK)
1868 {
1869 if (TRUE == gtk_tree_selection_get_selected (sel, &ptm, &iter))
1870 {
1871 gtk_tree_model_get (ptm,
1872 &iter,
1873 1, &namespace,
1874 2, &namespace_id,
1875 5, &namespace_uid,
1876 -1);
1877 }
1878 else
1879 {
1880 namespace = NULL;
1881 namespace_id = NULL;
1882 namespace_uid = NULL;
1883 }
1884 if (gtk_tree_model_get_iter_first (tm, &iter))
1885 do
1886 {
1887 fi = get_file_information (tm, &iter);
1888 GNUNET_FS_publish_start (GNUNET_FS_GTK_get_fs_handle (),
1889 fi,
1890 namespace,
1891 namespace_id,
1892 namespace_uid,
1893 GNUNET_FS_PUBLISH_OPTION_NONE);
1894 }
1895 while (gtk_tree_model_iter_next (tm, &iter));
1896 if (namespace_id != NULL)
1897 g_free (namespace_id);
1898 if (namespace_uid != NULL)
1899 g_free (namespace_uid);
1900 }
1901 ptm = GTK_TREE_MODEL (gtk_builder_get_object (master_builder,
1902 "GNUNET_GTK_pseudonym_tree_store"));
1903 /* free state from 'ptm' */
1904 if (TRUE ==
1905 gtk_tree_model_get_iter_first (ptm,
1906 &iter))
1907 do
1908 {
1909 free_pseudonym_tree_store (ptm,
1910 &iter);
1911 }
1912 while (TRUE == gtk_tree_model_iter_next (ptm,
1913 &iter));
1914
1915 /* free state from 'tm' */
1916 if (TRUE ==
1917 gtk_tree_model_get_iter_first (tm,
1918 &iter))
1919 do
1920 {
1921 free_file_information_tree_store (tm,
1922 &iter);
1923 }
1924 while (TRUE == gtk_tree_model_iter_next (tm,
1925 &iter));
1926
1927 gtk_widget_destroy (ad);
1928 g_object_unref (G_OBJECT (master_builder));
1929 master_builder = NULL;
1930}
1931
1932
1933/* end of main_window_file_publish.c */