aboutsummaryrefslogtreecommitdiff
path: root/src/fs_event_handler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fs_event_handler.c')
-rw-r--r--src/fs_event_handler.c2027
1 files changed, 0 insertions, 2027 deletions
diff --git a/src/fs_event_handler.c b/src/fs_event_handler.c
deleted file mode 100644
index b044c86d..00000000
--- a/src/fs_event_handler.c
+++ /dev/null
@@ -1,2027 +0,0 @@
1/*
2 This file is part of GNUnet.
3 (C) 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/fs_event_handler.c
23 * @brief Main event handler for file-sharing
24 * @author Christian Grothoff
25 */
26#include "common.h"
27#include "download.h"
28#include "fs_event_handler.h"
29#include <string.h>
30
31static struct SearchTab *search_tab_head;
32
33static struct SearchTab *search_tab_tail;
34
35struct PublishTab
36{
37 /**
38 * This is a doubly-linked list.
39 */
40 struct PublishTab *next;
41
42 /**
43 * This is a doubly-linked list.
44 */
45 struct PublishTab *prev;
46
47 GtkWidget *frame;
48
49 GtkBuilder *builder;
50
51 /**
52 * Associated (top-level) FS publish operation.
53 */
54 struct GNUNET_FS_PublishContext *pc;
55
56 GtkTreeStore *ts;
57};
58
59
60struct PublishEntry
61{
62 /**
63 * Associated FS publish operation.
64 */
65 struct GNUNET_FS_PublishContext *pc;
66
67 /**
68 * Tab storing this entry.
69 */
70 struct PublishTab *tab;
71
72 /**
73 * Where in the tab is this entry?
74 */
75 GtkTreeRowReference *rr;
76
77 /**
78 * URI of the file (set after completion).
79 */
80 struct GNUNET_FS_Uri *uri;
81
82 int is_top;
83};
84
85
86struct SearchResult
87{
88 /**
89 * Where in the tab is this result?
90 */
91 GtkTreeRowReference *rr;
92
93 /**
94 * Tab storing this result.
95 */
96 struct SearchTab *tab;
97
98 /**
99 * Search result for top-level results and
100 * namespace-update results.
101 */
102 struct GNUNET_FS_SearchResult *result;
103
104 /**
105 * Associated download, or NULL for none.
106 */
107 struct DownloadEntry *download;
108};
109
110
111
112static struct PublishTab *publish_tab_head;
113
114static struct PublishTab *publish_tab_tail;
115
116
117static struct DownloadEntry *
118change_download_colour (struct DownloadEntry *de,
119 const char *colour)
120{
121 GtkTreeIter iter;
122 GtkTreePath *path;
123
124 path = gtk_tree_row_reference_get_path (de->rr);
125 if (TRUE != gtk_tree_model_get_iter (GTK_TREE_MODEL (de->ts),
126 &iter, path))
127 {
128 GNUNET_break (0);
129 gtk_tree_path_free (path);
130 return de;
131 }
132 gtk_tree_path_free (path);
133 gtk_tree_store_set (de->ts, &iter,
134 8, colour,
135 -1);
136 return de;
137}
138
139
140static struct PublishEntry *
141change_publish_colour (struct PublishEntry *pe,
142 const char *colour)
143{
144 GtkTreeIter iter;
145 GtkTreePath *path;
146
147 if (pe == NULL)
148 {
149 GNUNET_break (0);
150 return NULL;
151 }
152 path = gtk_tree_row_reference_get_path (pe->rr);
153 if (TRUE != gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts),
154 &iter, path))
155 {
156 GNUNET_break (0);
157 gtk_tree_path_free (path);
158 return pe;
159 }
160 gtk_tree_path_free (path);
161 gtk_tree_store_set (pe->tab->ts, &iter,
162 2, colour,
163 -1);
164 return pe;
165}
166
167
168static void
169stop_download (struct DownloadEntry *de,
170 int is_suspend)
171{
172 change_download_colour (de, "white");
173 gtk_tree_row_reference_free (de->rr);
174 if (is_suspend == GNUNET_NO)
175 GNUNET_FS_download_stop (de->dc, GNUNET_YES);
176 GNUNET_FS_uri_destroy (de->uri);
177 GNUNET_CONTAINER_meta_data_destroy (de->meta);
178 GNUNET_free (de);
179}
180
181
182
183struct AddDirectoryEntryContext
184{
185
186 struct DownloadEntry *de;
187
188 /**
189 * Row reference of parent (the directory).
190 */
191 GtkTreeRowReference *prr;
192
193 int check_duplicates;
194
195};
196
197
198/**
199 * Function used to process entries in a directory.
200 *
201 * @param cls closure, our 'struct AddDirectoryEntryContext*'
202 * @param filename name of the file in the directory
203 * @param uri URI of the file
204 * @param metadata metadata for the file; metadata for
205 * the directory if everything else is NULL/zero
206 * @param length length of the available data for the file
207 * (of type size_t since data must certainly fit
208 * into memory; if files are larger than size_t
209 * permits, then they will certainly not be
210 * embedded with the directory itself).
211 * @param data data available for the file (length bytes)
212 */
213static void
214add_directory_entry (void *cls,
215 const char *filename,
216 const struct GNUNET_FS_Uri *uri,
217 const struct GNUNET_CONTAINER_MetaData *meta,
218 size_t length,
219 const void *data)
220{
221 struct AddDirectoryEntryContext *ade = cls;
222 GtkTreeIter iter;
223 GtkTreeIter piter;
224 GtkTreePath *path;
225 GtkTreeModel *tm;
226 struct GNUNET_FS_Uri *xuri;
227
228 if (uri == NULL)
229 {
230 /* directory meta data itself */
231 /* FIXME: consider merging it in... */
232 return;
233 }
234 if (ade->check_duplicates == GNUNET_YES)
235 {
236 path = gtk_tree_row_reference_get_path (ade->prr);
237 tm = gtk_tree_row_reference_get_model (ade->prr);
238 if (TRUE != gtk_tree_model_get_iter (tm,
239 &piter, path))
240 {
241 GNUNET_break (0);
242 gtk_tree_path_free (path);
243 return;
244 }
245 gtk_tree_path_free (path);
246 if (TRUE == gtk_tree_model_iter_children (tm,
247 &iter,
248 &piter))
249 {
250 do
251 {
252 gtk_tree_model_get (tm,
253 &iter,
254 1, &xuri,
255 -1);
256 if (GNUNET_YES ==
257 GNUNET_FS_uri_test_equal (xuri, uri))
258 return; /* already present */
259 }
260 while (TRUE == gtk_tree_model_iter_next (tm, &iter));
261 }
262 }
263 GNUNET_GTK_add_search_result (ade->de->tab,
264 &iter,
265 ade->prr,
266 uri,
267 meta,
268 NULL,
269 0);
270}
271
272
273static struct DownloadEntry *
274mark_download_progress (struct DownloadEntry *de,
275 uint64_t size,
276 uint64_t completed,
277 const void *block_data,
278 uint64_t offset,
279 uint64_t block_size,
280 unsigned int depth)
281{
282 struct AddDirectoryEntryContext ade;
283 GtkTreeIter iter;
284 GtkTreePath *path;
285
286 path = gtk_tree_row_reference_get_path (de->rr);
287 if (TRUE != gtk_tree_model_get_iter (GTK_TREE_MODEL (de->ts),
288 &iter, path))
289 {
290 GNUNET_break (0);
291 gtk_tree_path_free (path);
292 return de;
293 }
294 gtk_tree_path_free (path);
295 gtk_tree_store_set (de->ts, &iter,
296 4, (guint) ((size > 0) ? (100 * completed / size) : 100) /* progress */,
297 -1);
298 if ( (depth == 0) &&
299 (block_size > 0) &&
300 (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (de->meta)) )
301 {
302 ade.de = de;
303 ade.prr = de->rr;
304 ade.check_duplicates = GNUNET_NO;
305 if (GNUNET_SYSERR ==
306 GNUNET_FS_directory_list_contents ((size_t) block_size,
307 block_data,
308 offset,
309 &add_directory_entry,
310 &ade))
311 {
312 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
313 _("Metadata wrongly claims that this is a GNUnet directory!\n"));
314 }
315 }
316 return de;
317}
318
319
320static struct DownloadEntry *
321mark_download_error (struct DownloadEntry *de,
322 const char *emsg)
323{
324 GtkTreeIter iter;
325 GtkTreePath *path;
326
327 de = change_download_colour (de,
328 "red");
329 de->is_done = GNUNET_YES;
330 path = gtk_tree_row_reference_get_path (de->rr);
331 if (TRUE != gtk_tree_model_get_iter (GTK_TREE_MODEL (de->tab->ts),
332 &iter, path))
333 {
334 GNUNET_break (0);
335 gtk_tree_path_free (path);
336 return de;
337 }
338 gtk_tree_path_free (path);
339 gtk_tree_store_set (de->tab->ts, &iter,
340 4, 0,
341 7, emsg,
342 -1);
343 return de;
344}
345
346
347static struct DownloadEntry *
348mark_download_completed (struct DownloadEntry *de,
349 uint64_t size,
350 const char *filename)
351{
352 struct AddDirectoryEntryContext ade;
353
354 de->is_done = GNUNET_YES;
355 (void) mark_download_progress (de, size, size, NULL, 0, 0, 0);
356 if ( (GNUNET_YES == GNUNET_FS_meta_data_test_for_directory (de->meta)) &&
357 (filename != NULL) )
358 {
359 ade.de = de;
360 ade.prr = de->rr;
361 ade.check_duplicates = GNUNET_NO;
362 GNUNET_GTK_mmap_and_scan (filename,
363 &add_directory_entry,
364 &ade);
365 }
366 (void) change_download_colour (de, "green");
367 return de;
368}
369
370
371static struct PublishEntry *
372mark_publish_progress (struct PublishEntry *pe,
373 uint64_t size,
374 uint64_t completed)
375{
376 GtkTreeIter iter;
377 GtkTreePath *path;
378
379 path = gtk_tree_row_reference_get_path (pe->rr);
380 if (TRUE != gtk_tree_model_get_iter (GTK_TREE_MODEL (pe->tab->ts),
381 &iter, path))
382 {
383 GNUNET_break (0);
384 gtk_tree_path_free (path);
385 return pe;
386 }
387 gtk_tree_path_free (path);
388 gtk_tree_store_set (pe->tab->ts, &iter,
389 3, (guint) ((size > 0) ? (100 * completed / size) : 100) /* progress */,
390 -1);
391 return pe;
392}
393
394
395/**
396 * Move (aka copy) all of the children of 'src_iter' from the 'src_model'
397 * to become children of 'dst_iter' in the 'dst_model'.
398 *
399 * The models are both 'GNUNET_GTK_file_sharing_result_tree_store' models.
400 *
401 * Note that we also need to update the 'struct SearchResult'
402 * and (if it exists) the respective 'struct DownloadEntry'
403 * to refer to the new model.
404 */
405static void
406move_children (GtkTreeModel *src_model,
407 GtkTreeIter *src_iter,
408 GtkTreeModel *dst_model,
409 GtkTreeIter *dst_iter)
410{
411 GtkTreeIter src_child;
412 GtkTreeIter dst_child;
413 GtkTreePath *path;
414 struct GNUNET_CONTAINER_MetaData *meta;
415 struct GNUNET_FS_Uri *uri;
416 guint64 filesize;
417 GdkPixbuf *preview;
418 guint percent_progress;
419 guint percent_availability;
420 gchar *filename;
421 gchar *uri_as_string;
422 gchar *status_colour;
423 struct SearchResult *search_result;
424 gchar *mimetype;
425 guint applicability_rank;
426 guint availability_certainty;
427 gint availability_rank;
428
429 if (TRUE == gtk_tree_model_iter_children (src_model,
430 &src_child,
431 src_iter))
432 {
433 do
434 {
435 gtk_tree_model_get (src_model,
436 &src_child,
437 0, &meta,
438 1, &uri,
439 2, &filesize,
440 3, &preview,
441 4, &percent_progress,
442 5, &percent_availability,
443 6, &filename,
444 7, &uri_as_string,
445 8, &status_colour,
446 9, &search_result,
447 10, &mimetype,
448 11, &applicability_rank,
449 12, &availability_certainty,
450 13, &availability_rank,
451 -1);
452 gtk_tree_store_insert_with_values (GTK_TREE_STORE (dst_model),
453 &dst_child,
454 dst_iter,
455 G_MAXINT,
456 0, meta,
457 1, uri,
458 2, filesize,
459 3, preview,
460 4, percent_progress,
461 5, percent_availability,
462 6, filename,
463 7, uri_as_string,
464 8, status_colour,
465 9, search_result,
466 10, mimetype,
467 11, applicability_rank,
468 12, availability_certainty,
469 13, availability_rank,
470 -1);
471 g_free (filename);
472 g_free (uri_as_string);
473 g_free (status_colour);
474 g_free (mimetype);
475 if (preview != NULL)
476 g_object_unref (preview);
477 gtk_tree_row_reference_free (search_result->rr);
478 path = gtk_tree_model_get_path (dst_model,
479 &dst_child);
480 search_result->rr = gtk_tree_row_reference_new (dst_model,
481 path);
482 gtk_tree_path_free (path);
483 if (search_result->download != NULL)
484 {
485 search_result->download->ts = GTK_TREE_STORE (dst_model);
486 gtk_tree_row_reference_free (search_result->download->rr);
487 search_result->download->rr = gtk_tree_row_reference_copy (search_result->rr);
488 }
489 move_children (src_model,
490 &src_child,
491 dst_model,
492 &dst_child);
493 }
494 while (TRUE == gtk_tree_model_iter_next (src_model,
495 &src_child));
496 }
497}
498
499
500/**
501 * Delete the entire given subtree from the model.
502 * Does not free anything inside of the respective
503 * model's fields (since they have been moved).
504 */
505static void
506delete_stale_subtree (GtkTreeModel *model,
507 GtkTreeIter *iter)
508{
509 GtkTreeIter child;
510
511 while (TRUE == gtk_tree_model_iter_children (model,
512 &child,
513 iter))
514 delete_stale_subtree (model, &child);
515 gtk_tree_store_remove (GTK_TREE_STORE (model),
516 iter);
517}
518
519
520/**
521 * Handle the case where an active download lost its
522 * search parent by moving it to the URI tab.
523 */
524static struct DownloadEntry *
525download_lost_parent (struct DownloadEntry *de,
526 uint64_t size,
527 uint64_t completed,
528 int is_active)
529{
530 GtkTreeIter iter;
531 GtkTreePath *path;
532 struct SearchTab *tab;
533 GtkTreeRowReference *rr_old;
534 GtkTreeModel *tm_old;
535 GtkTreeIter iter_old;
536
537 rr_old = de->rr;
538 de->sr = NULL;
539 tab = GNUNET_GTK_add_to_uri_tab (&iter,
540 NULL,
541 de->meta,
542 de->uri);
543 de->ts = tab->ts;
544 path = gtk_tree_model_get_path (GTK_TREE_MODEL (de->ts),
545 &iter);
546 de->rr = gtk_tree_row_reference_new (GTK_TREE_MODEL (de->ts),
547 path);
548 gtk_tree_path_free (path);
549 mark_download_progress (de, size, completed,
550 NULL, 0, 0, 0);
551 tm_old = gtk_tree_row_reference_get_model (rr_old);
552 path = gtk_tree_row_reference_get_path (rr_old);
553 gtk_tree_row_reference_free (rr_old);
554 gtk_tree_model_get_iter (tm_old,
555 &iter_old,
556 path);
557 gtk_tree_path_free (path);
558 move_children (tm_old,
559 &iter_old,
560 GTK_TREE_MODEL (de->ts),
561 &iter);
562 delete_stale_subtree (tm_old,
563 &iter_old);
564 if (size > completed)
565 {
566 if (is_active)
567 change_download_colour (de, "yellow");
568 else
569 change_download_colour (de, "blue");
570 }
571 else
572 {
573 change_download_colour (de, "green");
574 }
575 return de;
576}
577
578
579/**
580 * Setup a new download entry.
581 *
582 * @param de existing download entry for the download, or NULL
583 * @param pde parent download entry, or NULL
584 * @param sr search result, or NULL
585 * @param dc download context (for stopping)
586 * @param uri the URI
587 * @param meta metadata
588 * @param size total size
589 * @param completed current progress
590 */
591static struct DownloadEntry *
592setup_download (struct DownloadEntry *de,
593 struct DownloadEntry *pde,
594 struct SearchResult *sr,
595 struct GNUNET_FS_DownloadContext *dc,
596 const struct GNUNET_FS_Uri *uri,
597 const struct GNUNET_CONTAINER_MetaData *meta,
598 uint64_t size,
599 uint64_t completed)
600{
601 GtkTreeIter iter;
602 GtkTreePath *path;
603
604 if (de == NULL)
605 {
606 de = GNUNET_malloc (sizeof (struct DownloadEntry));
607 GNUNET_assert (sr->download == NULL);
608 sr->download = de;
609 de->sr = sr;
610 de->dc = dc;
611 de->uri = GNUNET_FS_uri_dup (uri);
612 }
613 de->pde = pde;
614 if ( (meta != NULL) &&
615 (de->meta == NULL) )
616 de->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
617 if (sr != NULL)
618 {
619 de->rr = gtk_tree_row_reference_copy (sr->rr);
620 de->ts = sr->tab->ts;
621 de->tab = sr->tab;
622 }
623 else if (de->rr == NULL)
624 {
625 de->tab = GNUNET_GTK_add_to_uri_tab (&iter,
626 NULL,
627 meta,
628 uri);
629 de->ts = de->tab->ts;
630 path = gtk_tree_model_get_path (GTK_TREE_MODEL (de->ts),
631 &iter);
632 de->rr = gtk_tree_row_reference_new (GTK_TREE_MODEL (de->ts),
633 path);
634 gtk_tree_path_free (path);
635 }
636 path = gtk_tree_row_reference_get_path (de->rr);
637 if (TRUE != gtk_tree_model_get_iter (GTK_TREE_MODEL (de->ts),
638 &iter, path))
639 {
640 GNUNET_break (0);
641 gtk_tree_path_free (path);
642 return de;
643 }
644 gtk_tree_path_free (path);
645 gtk_tree_store_set (de->ts, &iter,
646 4, (guint) ((size > 0) ? (100 * completed / size) : 100) /* progress */,
647 8, "blue" /* status colour: pending */,
648 -1);
649 return de;
650}
651
652
653/**
654 * Tell FS to start a download. Begins by opening the
655 * "save as" window.
656 */
657static void
658start_download (GtkTreeView *tree_view,
659 GtkTreePath *path,
660 GtkTreeViewColumn *column,
661 gpointer user_data)
662{
663 struct SearchTab *tab = user_data;
664 GtkTreeModel *tm;
665 GtkTreeIter iter;
666 struct GNUNET_FS_Uri *uri;
667 struct GNUNET_CONTAINER_MetaData *meta;
668 struct SearchResult *sr;
669 gchar *mime;
670 struct DownloadContext *dlc;
671
672 GNUNET_assert (tab != NULL);
673 tm = gtk_tree_view_get_model (tree_view);
674 if (TRUE != gtk_tree_model_get_iter (tm, &iter, path))
675 {
676 GNUNET_break (0);
677 return;
678 }
679 gtk_tree_model_get (tm, &iter,
680 0, &meta,
681 1, &uri,
682 9, &sr,
683 10, &mime,
684 -1);
685 dlc = GNUNET_malloc (sizeof (struct DownloadContext));
686 dlc->uri = GNUNET_FS_uri_dup (uri);
687 dlc->mime = (NULL != mime) ? GNUNET_strdup (mime) : NULL;
688 dlc->filename = GNUNET_FS_meta_data_suggest_filename (meta);
689 dlc->meta = GNUNET_CONTAINER_meta_data_duplicate (meta);
690 dlc->rr = gtk_tree_row_reference_new (tm, path);
691 dlc->sr = sr->result;
692 dlc->anonymity = -1;
693 GNUNET_GTK_open_download_as_dialog (dlc);
694 g_free (mime);
695}
696
697
698
699/**
700 * Row reference for the current search context menu.
701 */
702static GtkTreeRowReference *current_context_row_reference;
703
704/**
705 * Search tab used for the current search context menu.
706 */
707static struct SearchTab *current_context_search_tab;
708
709/**
710 * Download was selected in the current search context menu.
711 */
712static void
713start_download_ctx_menu (gpointer user_data,
714 guint unused,
715 GtkWidget *widget)
716{
717 GtkTreePath *path;
718 GtkTreeView *tv;
719
720 if (current_context_row_reference == NULL)
721 {
722 GNUNET_break (0);
723 return;
724 }
725 path = gtk_tree_row_reference_get_path (current_context_row_reference);
726 gtk_tree_row_reference_free (current_context_row_reference);
727 current_context_row_reference = NULL;
728 tv = GTK_TREE_VIEW (gtk_builder_get_object (current_context_search_tab->builder,
729 "_search_result_frame"));
730 start_download (tv, path, NULL, current_context_search_tab);
731 gtk_tree_path_free (path);
732 current_context_search_tab = NULL;
733}
734
735
736/**
737 * Download was selected in the current search context menu.
738 */
739static void
740abort_download_ctx_menu (gpointer user_data,
741 guint unused,
742 GtkWidget *widget)
743{
744 struct DownloadEntry *de = user_data;
745
746 GNUNET_assert (de->dc != NULL);
747 GNUNET_FS_download_stop (de->dc,
748 GNUNET_YES);
749 current_context_search_tab = NULL;
750}
751
752
753/**
754 * Copy current URI to clipboard.
755 */
756static void
757copy_uri_to_clipboard_ctx_menu (gpointer user_data,
758 guint unused,
759 GtkWidget *widget)
760{
761 GtkTreePath *path;
762 GtkTreeView *tv;
763 GtkTreeModel *tm;
764 GtkTreeIter iter;
765 struct GNUNET_FS_Uri *uri;
766 char *uris;
767 GtkClipboard *cb;
768
769 if (current_context_row_reference == NULL)
770 {
771 GNUNET_break (0);
772 return;
773 }
774 path = gtk_tree_row_reference_get_path (current_context_row_reference);
775 gtk_tree_row_reference_free (current_context_row_reference);
776 current_context_row_reference = NULL;
777 tv = GTK_TREE_VIEW (gtk_builder_get_object (current_context_search_tab->builder,
778 "_search_result_frame"));
779 tm = gtk_tree_view_get_model (tv);
780 if (TRUE != gtk_tree_model_get_iter (tm, &iter, path))
781 {
782 GNUNET_break (0);
783 gtk_tree_path_free (path);
784 return;
785 }
786 gtk_tree_model_get (tm, &iter,
787 1, &uri, -1);
788 gtk_tree_path_free (path);
789 current_context_search_tab = NULL;
790 if (uri == NULL)
791 {
792 GNUNET_break (0);
793 return;
794 }
795 uris = GNUNET_FS_uri_to_string (uri);
796 cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
797 gtk_clipboard_set_text (cb,
798 uris,
799 -1);
800 gtk_clipboard_store (cb);
801 GNUNET_free (uris);
802}
803
804
805/**
806 * We got a right-click on the search result list. Display the context
807 * menu.
808 */
809static int
810search_list_on_menu(GtkWidget *widget,
811 GdkEvent *event,
812 gpointer user_data)
813{
814 GdkEventButton *event_button;
815 struct SearchTab *tab = user_data;
816 GtkTreeView *tv;
817 GtkMenu *menu;
818 GtkWidget *child;
819 GtkTreePath *path;
820 GtkTreeModel *tm;
821 GtkTreeIter iter;
822 struct SearchResult *sr;
823
824 tv = GTK_TREE_VIEW (widget);
825 if (event->type == GDK_BUTTON_PRESS)
826 {
827 event_button = (GdkEventButton *) event;
828 if (event_button->button == 3)
829 {
830 current_context_search_tab = tab;
831 if (current_context_row_reference != NULL)
832 {
833 gtk_tree_row_reference_free (current_context_row_reference);
834 current_context_row_reference = NULL;
835 }
836 path = NULL;
837 if (FALSE == gtk_tree_view_get_path_at_pos (tv,
838 event_button->x,
839 event_button->y,
840 &path, NULL, NULL, NULL))
841 {
842 /* nothing selected */
843 current_context_search_tab = NULL;
844 return FALSE;
845 }
846 tm = gtk_tree_view_get_model (tv);
847 gtk_tree_model_get_iter (tm, &iter, path);
848 gtk_tree_model_get (tm, &iter,
849 9, &sr,
850 -1);
851 current_context_row_reference = gtk_tree_row_reference_new (tm,
852 path);
853 gtk_tree_path_free (path);
854
855 /*
856 FIXME: have additional options, depending on status:
857 - view full meta data (in new window)
858 - copy URI to clipboard
859 - start recursive download
860 - abort active download (!)
861 => need to know download status before creating menu!
862 */
863 menu = GTK_MENU (gtk_menu_new ());
864 if (sr->download == NULL)
865 {
866 child = gtk_menu_item_new_with_label (_("_Download"));
867 g_signal_connect (child,
868 "activate",
869 G_CALLBACK (start_download_ctx_menu),
870 NULL);
871 gtk_label_set_use_underline (GTK_LABEL
872 (gtk_bin_get_child (GTK_BIN (child))),
873 TRUE);
874 gtk_widget_show (child);
875 }
876 else
877 {
878 child = gtk_menu_item_new_with_label (_("_Abort download"));
879 g_signal_connect (child,
880 "activate",
881 G_CALLBACK (abort_download_ctx_menu),
882 sr->download);
883 gtk_label_set_use_underline (GTK_LABEL
884 (gtk_bin_get_child (GTK_BIN (child))),
885 TRUE);
886 gtk_widget_show (child);
887
888 }
889
890 child = gtk_menu_item_new_with_label (_("_Copy URI to Clipboard"));
891 g_signal_connect (child,
892 "activate",
893 G_CALLBACK (copy_uri_to_clipboard_ctx_menu),
894 NULL);
895 gtk_label_set_use_underline (GTK_LABEL
896 (gtk_bin_get_child (GTK_BIN (child))),
897 TRUE);
898 gtk_widget_show (child);
899
900
901
902 gtk_menu_shell_append (GTK_MENU_SHELL (menu), child);
903 gtk_menu_popup (menu, NULL, NULL, NULL, NULL,
904 event_button->button,
905 event_button->time);
906 }
907 }
908 return FALSE;
909}
910
911
912/**
913 * Selected row has changed, update preview and metadata
914 * areas.
915 */
916static void
917update_meta_data_views (GtkTreeView *tv,
918 gpointer user_data)
919{
920 struct SearchTab *tab = user_data;
921 GtkImage *image;
922 GtkListStore *ms;
923 GtkTreeSelection *sel;
924 GtkTreeModel *model;
925 GtkTreeIter iter;
926 struct GNUNET_CONTAINER_MetaData *meta;
927 GdkPixbuf *pixbuf;
928
929 GNUNET_assert (tab->query_txt != NULL);
930 image = GTK_IMAGE (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_preview_image"));
931 ms = GTK_LIST_STORE (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_meta_data_list_store"));
932
933 sel = gtk_tree_view_get_selection (tv);
934 gtk_list_store_clear (ms);
935 if (TRUE != gtk_tree_selection_get_selected (sel,
936 &model,
937 &iter))
938 {
939 gtk_image_clear (image);
940 return;
941 }
942 meta = NULL;
943 pixbuf = NULL;
944 gtk_tree_model_get (model,
945 &iter,
946 0, &meta,
947 3, &pixbuf,
948 -1);
949 if (pixbuf != NULL)
950 {
951 gtk_image_set_from_pixbuf (image, pixbuf);
952 g_object_unref (G_OBJECT (pixbuf));
953 }
954 if (meta != NULL)
955 {
956 GNUNET_CONTAINER_meta_data_iterate (meta,
957 &GNUNET_GTK_add_meta_data_to_list_store,
958 ms);
959 }
960}
961
962
963/**
964 * Update the label for a search
965 */
966static void
967update_search_label (struct SearchTab *tab)
968{
969 char *name;
970
971 while (tab->parent != NULL)
972 tab = tab->parent->tab;
973 if (tab->num_results > 0)
974 GNUNET_asprintf (&name,
975 "%.*s%s (%u)",
976 20,
977 tab->query_txt,
978 strlen (tab->query_txt) > 20 ? "..." : "",
979 tab->num_results);
980 else
981 GNUNET_asprintf (&name,
982 "%.*s%s",
983 20,
984 tab->query_txt,
985 strlen (tab->query_txt) > 20 ? "..." : "");
986 gtk_label_set_text (tab->label, name);
987 GNUNET_free (name);
988}
989
990
991/**
992 * Close a search tab and free associated state.
993 */
994static void
995close_search_tab (struct SearchTab *tab)
996{
997 GtkNotebook *notebook;
998 int index;
999 int i;
1000
1001 if (tab->parent != NULL)
1002 {
1003 /* not a top-level search, do not close tab here! */
1004 GNUNET_free (tab);
1005 return;
1006 }
1007
1008 notebook = GTK_NOTEBOOK (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_notebook"));
1009 index = -1;
1010 for (i = gtk_notebook_get_n_pages (notebook) - 1; i >= 0; i--)
1011 if (tab->frame == gtk_notebook_get_nth_page (notebook, i))
1012 index = i;
1013 gtk_notebook_remove_page (notebook, index);
1014 g_object_unref (tab->builder);
1015 GNUNET_free (tab->query_txt);
1016 GNUNET_CONTAINER_DLL_remove (search_tab_head,
1017 search_tab_tail,
1018 tab);
1019 GNUNET_free (tab);
1020}
1021
1022
1023/**
1024 * Close a publish tab and free associated state.
1025 */
1026static struct PublishEntry *
1027handle_publish_completed (struct PublishEntry *ent,
1028 const struct GNUNET_FS_Uri *uri)
1029{
1030 ent->uri = GNUNET_FS_uri_dup (uri);
1031 return change_publish_colour (ent,
1032 "green");
1033}
1034
1035
1036
1037/**
1038 * Handle error.
1039 */
1040static struct PublishEntry *
1041handle_publish_error (struct PublishEntry *ent,
1042 const char *emsg)
1043{
1044 GNUNET_break (0);
1045 return change_publish_colour (ent,
1046 "red");
1047}
1048
1049
1050/**
1051 * Close a publish tab and free associated state.
1052 */
1053static void
1054close_publish_tab (struct PublishEntry *ent)
1055{
1056 struct PublishTab *tab;
1057 GtkNotebook *notebook;
1058 int index;
1059 int i;
1060
1061 if (ent == NULL)
1062 {
1063 GNUNET_break (0);
1064 return;
1065 }
1066 gtk_tree_row_reference_free (ent->rr);
1067 if (GNUNET_YES != ent->is_top)
1068 {
1069 GNUNET_free (ent);
1070 return;
1071 }
1072 tab = ent->tab;
1073 if (ent->uri != NULL)
1074 GNUNET_FS_uri_destroy (ent->uri);
1075 GNUNET_free (ent);
1076 notebook = GTK_NOTEBOOK (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_notebook"));
1077 index = -1;
1078 for (i = gtk_notebook_get_n_pages (notebook) - 1; i >= 0; i--)
1079 if (tab->frame == gtk_notebook_get_nth_page (notebook, i))
1080 index = i;
1081 gtk_notebook_remove_page (notebook, index);
1082 g_object_unref (tab->builder);
1083 GNUNET_CONTAINER_DLL_remove (publish_tab_head,
1084 publish_tab_tail,
1085 tab);
1086 GNUNET_free (tab);
1087}
1088
1089
1090/**
1091 * Tell FS to stop a search.
1092 */
1093static void
1094stop_search (GtkButton *button,
1095 gpointer user_data)
1096{
1097 struct SearchTab *tab = user_data;
1098 if (tab->sc != NULL)
1099 {
1100 GNUNET_FS_search_stop (tab->sc);
1101 tab->sc = NULL;
1102 }
1103}
1104
1105
1106/**
1107 * Stop completed downloads (or those that failed). Should
1108 * iterate over the underlying tree store and stop all
1109 * completed entries. Furthermore, if the resulting tree
1110 * store is empty and has no search associated with it,
1111 * the tab should be closed.
1112 */
1113static void
1114clear_downloads (GtkButton *button,
1115 gpointer user_data)
1116{
1117 struct SearchTab *tab = user_data;
1118 struct SearchResult *sr;
1119 GtkTreeModel *tm;
1120 GtkTreeIter iter;
1121
1122 tm = GTK_TREE_MODEL (tab->ts);
1123 if (TRUE != gtk_tree_model_get_iter_first (tm, &iter))
1124 return;
1125 do
1126 {
1127 gtk_tree_model_get (tm, &iter,
1128 9, &sr,
1129 -1);
1130 if ( (sr->download != NULL) &&
1131 (sr->download->is_done == GNUNET_YES) )
1132 GNUNET_FS_download_stop (sr->download->dc,
1133 GNUNET_YES);
1134 }
1135 while (TRUE == gtk_tree_model_iter_next (tm, &iter));
1136}
1137
1138
1139
1140/**
1141 * Tell FS to pause a search.
1142 */
1143static void
1144pause_search (GtkButton *button,
1145 gpointer user_data)
1146{
1147 struct SearchTab *tab = user_data;
1148 if (tab->sc != NULL)
1149 {
1150 GNUNET_FS_search_pause (tab->sc);
1151 gtk_widget_show (tab->play_button);
1152 gtk_widget_hide (tab->pause_button);
1153 }
1154}
1155
1156
1157/**
1158 * Tell FS to resume a search.
1159 */
1160static void
1161continue_search (GtkButton *button,
1162 gpointer user_data)
1163{
1164 struct SearchTab *tab = user_data;
1165 if (tab->sc != NULL)
1166 {
1167 GNUNET_FS_search_continue (tab->sc);
1168 gtk_widget_show (tab->pause_button);
1169 gtk_widget_hide (tab->play_button);
1170 }
1171}
1172
1173
1174/**
1175 * Setup a new search tab.
1176 *
1177 * @param sc context with FS for the search
1178 * @param query the query
1179 * @param anonymity anonymity level
1180 */
1181static struct SearchTab *
1182setup_search (struct GNUNET_FS_SearchContext *sc,
1183 const struct GNUNET_FS_Uri *query)
1184{
1185 struct SearchTab *tab;
1186 GtkTreeView *tv;
1187 GtkNotebook *notebook;
1188 GtkWindow *sf;
1189 gint pages;
1190
1191 tab = GNUNET_malloc (sizeof (struct SearchTab));
1192 GNUNET_CONTAINER_DLL_insert (search_tab_head,
1193 search_tab_tail,
1194 tab);
1195 tab->sc = sc;
1196 if (query == NULL)
1197 {
1198 tab->query_txt = GNUNET_strdup ("*");
1199 }
1200 else
1201 {
1202 if (GNUNET_FS_uri_test_ksk (query))
1203 tab->query_txt = GNUNET_FS_uri_ksk_to_string_fancy (query);
1204 else
1205 tab->query_txt = GNUNET_FS_uri_to_string (query);
1206 }
1207 tab->builder = GNUNET_GTK_get_new_builder ("search_tab.glade");
1208 tab->ts = GTK_TREE_STORE (gtk_builder_get_object (tab->builder,
1209 "GNUNET_GTK_file_sharing_result_tree_store"));
1210 /* load frame */
1211 sf = GTK_WINDOW (gtk_builder_get_object (tab->builder,
1212 "_search_result_frame_window"));
1213 tab->frame = gtk_bin_get_child (GTK_BIN (sf));
1214 gtk_widget_ref (tab->frame);
1215 gtk_container_remove (GTK_CONTAINER (sf), tab->frame);
1216 gtk_widget_destroy (GTK_WIDGET (sf));
1217
1218 /* load tab_label */
1219 sf = GTK_WINDOW (gtk_builder_get_object (tab->builder,
1220 "_search_result_label_window"));
1221 tab->tab_label = gtk_bin_get_child (GTK_BIN (sf));
1222 gtk_widget_ref (tab->tab_label);
1223 gtk_container_remove (GTK_CONTAINER (sf), tab->tab_label);
1224 gtk_widget_destroy (GTK_WIDGET (sf));
1225
1226 /* get refs to widgets */
1227 tab->label = GTK_LABEL (gtk_builder_get_object (tab->builder,
1228 "_search_result_label_window_label"));
1229
1230 tab->close_button = GTK_WIDGET (gtk_builder_get_object (tab->builder,
1231 "_search_result_label_close_button"));
1232 g_signal_connect(G_OBJECT(tab->close_button), "clicked",
1233 G_CALLBACK(stop_search), tab);
1234 tab->clear_button = GTK_WIDGET (gtk_builder_get_object (tab->builder,
1235 "_search_result_label_clear_button"));
1236 g_signal_connect(G_OBJECT(tab->clear_button), "clicked",
1237 G_CALLBACK(clear_downloads), tab);
1238 tab->play_button = GTK_WIDGET (gtk_builder_get_object (tab->builder,
1239 "_search_result_label_play_button"));
1240 g_signal_connect(G_OBJECT(tab->play_button), "clicked",
1241 G_CALLBACK(continue_search), tab);
1242 tab->pause_button = GTK_WIDGET (gtk_builder_get_object (tab->builder,
1243 "_search_result_label_pause_button"));
1244 g_signal_connect(G_OBJECT(tab->pause_button), "clicked",
1245 G_CALLBACK(pause_search), tab);
1246 /* patch text */
1247 update_search_label (tab);
1248
1249 /* add signal handlers */
1250 tv = GTK_TREE_VIEW (gtk_builder_get_object (tab->builder,
1251 "_search_result_frame"));
1252 g_signal_connect(G_OBJECT(tv), "row-activated",
1253 G_CALLBACK(start_download), tab);
1254 g_signal_connect(G_OBJECT(tv), "cursor-changed",
1255 G_CALLBACK(update_meta_data_views), tab);
1256 g_signal_connect (G_OBJECT(tv),
1257 "button_press_event",
1258 G_CALLBACK(search_list_on_menu),
1259 tab);
1260
1261
1262 /* make visible */
1263 notebook = GTK_NOTEBOOK (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_notebook"));
1264 pages = gtk_notebook_get_n_pages (notebook);
1265 gtk_notebook_insert_page (notebook,
1266 tab->frame,
1267 tab->tab_label,
1268 pages - 1);
1269 gtk_notebook_set_current_page (notebook,
1270 pages - 1);
1271 gtk_widget_show (GTK_WIDGET (notebook));
1272 return tab;
1273}
1274
1275
1276/**
1277 * Setup an inner search.
1278 *
1279 * @param sc context with FS for the search
1280 * @param parent parent search tab
1281 * @param anonymity anonymity level
1282 */
1283static struct SearchTab *
1284setup_inner_search (struct GNUNET_FS_SearchContext *sc,
1285 struct SearchResult *parent)
1286{
1287 struct SearchTab *ret;
1288
1289 ret = GNUNET_malloc (sizeof (struct SearchTab));
1290 ret->parent = parent;
1291 ret->sc = sc;
1292 ret->query_txt = parent->tab->query_txt;
1293 ret->builder = parent->tab->builder;
1294 ret->frame = parent->tab->frame;
1295 ret->tab_label = parent->tab->tab_label;
1296 ret->close_button = parent->tab->close_button;
1297 ret->clear_button = parent->tab->clear_button;
1298 ret->play_button = parent->tab->play_button;
1299 ret->label = parent->tab->label;
1300
1301 return ret;
1302}
1303
1304
1305
1306/**
1307 * Add a search result to the given search tab.
1308 *
1309 * @param tab search tab to extend
1310 * @param iter set to position where search result is added
1311 * @param parent_rr reference to parent entry in search tab
1312 * @param uri uri to add
1313 * @param meta metadata of the entry
1314 * @param result associated FS search result (can be NULL)
1315 * @param applicability_rank how relevant is the result
1316 * @return entry for the search result
1317 */
1318struct SearchResult *
1319GNUNET_GTK_add_search_result (struct SearchTab *tab,
1320 GtkTreeIter *iter,
1321 GtkTreeRowReference *parent_rr,
1322 const struct GNUNET_FS_Uri *uri,
1323 const struct GNUNET_CONTAINER_MetaData *meta,
1324 struct GNUNET_FS_SearchResult *result,
1325 uint32_t applicability_rank)
1326{
1327 struct SearchResult *sr;
1328 GtkTreePath *tp;
1329 const char *status_colour;
1330 char *desc;
1331 char *mime;
1332 char *uris;
1333 GdkPixbuf *pixbuf;
1334 GtkTreeIter *pitr;
1335 GtkTreeIter pmem;
1336 GtkTreePath *path;
1337 GtkTreeModel *tm;
1338 GtkTreeStore *ts;
1339 uint64_t fsize;
1340
1341 if ( (uri != NULL) &&
1342 (!GNUNET_FS_uri_test_loc (uri)) &&
1343 (!GNUNET_FS_uri_test_chk (uri)) )
1344 {
1345 fsize = 0;
1346 mime = GNUNET_strdup ("GNUnet namespace");
1347 status_colour = "lightgreen";
1348 }
1349 else if (uri != NULL)
1350 {
1351 fsize = GNUNET_FS_uri_chk_get_file_size (uri);
1352 mime = GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
1353 EXTRACTOR_METATYPE_MIMETYPE,
1354 EXTRACTOR_METATYPE_FORMAT,
1355 -1);
1356 status_colour = "white";
1357 }
1358 else
1359 {
1360 fsize = 0;
1361 status_colour = "gray";
1362 mime = NULL;
1363 }
1364 desc = GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
1365 EXTRACTOR_METATYPE_PACKAGE_NAME,
1366 EXTRACTOR_METATYPE_TITLE,
1367 EXTRACTOR_METATYPE_BOOK_TITLE,
1368 EXTRACTOR_METATYPE_FILENAME,
1369 EXTRACTOR_METATYPE_DESCRIPTION,
1370 EXTRACTOR_METATYPE_SUMMARY,
1371 EXTRACTOR_METATYPE_ALBUM,
1372 EXTRACTOR_METATYPE_COMMENT,
1373 EXTRACTOR_METATYPE_SUBJECT,
1374 EXTRACTOR_METATYPE_KEYWORDS,
1375 -1);
1376 if (desc == NULL)
1377 desc = GNUNET_strdup (_("no description supplied"));
1378 if (uri == NULL)
1379 uris = GNUNET_strdup (_("no URI"));
1380 else
1381 uris = GNUNET_FS_uri_to_string (uri);
1382
1383 pixbuf = GNUNET_GTK_get_thumbnail_from_meta_data (meta);
1384 sr = GNUNET_malloc (sizeof (struct SearchResult));
1385 sr->result = result;
1386 sr->tab = tab;
1387 if (parent_rr != NULL)
1388 {
1389 /* get piter from parent */
1390 path = gtk_tree_row_reference_get_path (parent_rr);
1391 tm = gtk_tree_row_reference_get_model (parent_rr);
1392 if (TRUE != gtk_tree_model_get_iter (GTK_TREE_MODEL (tm),
1393 &pmem, path))
1394 {
1395 GNUNET_break (0);
1396 gtk_tree_path_free (path);
1397 /* desperate measure: make top-level entry */
1398 pitr = NULL;
1399 }
1400 else
1401 {
1402 pitr = &pmem;
1403 }
1404 ts = GTK_TREE_STORE (tm);
1405 }
1406 else
1407 {
1408 /* top-level result */
1409 pitr = NULL;
1410 ts = tab->ts;
1411 }
1412 gtk_tree_store_insert_with_values (ts,
1413 iter,
1414 pitr,
1415 G_MAXINT,
1416 0, GNUNET_CONTAINER_meta_data_duplicate (meta),
1417 1, (uri == NULL) ? NULL : GNUNET_FS_uri_dup (uri),
1418 2, (uri == NULL) ? 0 : fsize,
1419 3, pixbuf /* preview */,
1420 4, 0 /* percent progress */,
1421 5, 0 /* percent availability */,
1422 6, desc /* filename/description */,
1423 7, uris,
1424 8, status_colour,
1425 9, sr,
1426 10, mime,
1427 11, applicability_rank,
1428 12, 0 /* avail-cert */,
1429 13, 0 /* avail-rank */,
1430 -1);
1431 if (tab != NULL)
1432 {
1433 while (tab->parent != NULL)
1434 tab = tab->parent->tab;
1435 tab->num_results++;
1436 }
1437 if (pixbuf != NULL)
1438 g_object_unref (pixbuf);
1439 GNUNET_free (uris);
1440 GNUNET_free (desc);
1441 GNUNET_free_non_null (mime);
1442 tp = gtk_tree_model_get_path (GTK_TREE_MODEL (ts),
1443 iter);
1444 sr->rr = gtk_tree_row_reference_new (GTK_TREE_MODEL (ts),
1445 tp);
1446 gtk_tree_path_free (tp);
1447 return sr;
1448}
1449
1450
1451static struct SearchResult *
1452process_search_result (void *cls,
1453 struct SearchResult *parent,
1454 const struct GNUNET_FS_Uri *uri,
1455 const struct GNUNET_CONTAINER_MetaData *meta,
1456 struct GNUNET_FS_SearchResult *result,
1457 uint32_t applicability_rank)
1458{
1459 struct SearchTab *tab = cls;
1460 struct SearchResult *sr;
1461 GtkTreeIter iter;
1462
1463 sr = GNUNET_GTK_add_search_result (tab, &iter,
1464 (parent != NULL) ? parent->rr : NULL,
1465 uri,
1466 meta, result, applicability_rank);
1467 update_search_label (tab);
1468 return sr;
1469}
1470
1471
1472/**
1473 * Setup a new top-level entry in the URI tab. If necessary, create
1474 * the URI tab first.
1475 *
1476 * @param iter set to the new entry
1477 * @param srp set to search result
1478 * @param meta metadata for the new entry
1479 * @param uri URI for the new entry
1480 * @return NULL on error, otherwise tree store matching iter
1481 */
1482struct SearchTab *
1483GNUNET_GTK_add_to_uri_tab (GtkTreeIter *iter,
1484 struct SearchResult **srp,
1485 const struct GNUNET_CONTAINER_MetaData *meta,
1486 const struct GNUNET_FS_Uri *uri)
1487{
1488 struct SearchTab *utab;
1489 struct SearchResult *sr;
1490 GtkNotebook *notebook;
1491 gint page;
1492
1493 utab = search_tab_head;
1494 while (utab != NULL)
1495 {
1496 if (utab->sc == NULL)
1497 break;
1498 utab = utab->next;
1499 }
1500 if (utab == NULL)
1501 {
1502 utab = setup_search (NULL, NULL);
1503 gtk_widget_set_visible (utab->close_button,
1504 FALSE);
1505 gtk_widget_set_visible (utab->pause_button,
1506 FALSE);
1507 }
1508 else
1509 {
1510 /* make 'utab' the current page */
1511 notebook = GTK_NOTEBOOK (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_notebook"));
1512 for (page=0;page<gtk_notebook_get_n_pages (notebook);page++)
1513 if (utab->frame ==
1514 gtk_notebook_get_nth_page (notebook,
1515 page))
1516 {
1517 gtk_notebook_set_current_page (notebook,
1518 page);
1519 break;
1520 }
1521 }
1522 sr = GNUNET_GTK_add_search_result (utab, iter,
1523 NULL, uri, meta,
1524 NULL, 0);
1525
1526 if (NULL != srp)
1527 *srp = sr;
1528 return utab;
1529}
1530
1531
1532static struct SearchTab *
1533handle_search_error (struct SearchTab *sr,
1534 const char *emsg)
1535{
1536 /* FIXME: implement error handler */
1537 GNUNET_break (0);
1538 return sr;
1539}
1540
1541
1542static struct SearchResult *
1543update_search_result (struct SearchResult *sr,
1544 const struct GNUNET_CONTAINER_MetaData *meta,
1545 int32_t availability_rank,
1546 uint32_t availability_certainty,
1547 uint32_t applicability_rank)
1548{
1549 GtkTreeIter iter;
1550 struct GNUNET_CONTAINER_MetaData *ometa;
1551 GtkTreeView *tv;
1552 GtkTreePath *tp;
1553 GtkTreeStore *ts;
1554 GtkTreeModel *tm;
1555 char *desc;
1556 char *mime;
1557 GdkPixbuf *pixbuf;
1558 guint percent_avail;
1559 GtkNotebook *notebook;
1560 gint page;
1561
1562 if (sr == NULL)
1563 return NULL;
1564 desc = GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
1565 EXTRACTOR_METATYPE_PACKAGE_NAME,
1566 EXTRACTOR_METATYPE_TITLE,
1567 EXTRACTOR_METATYPE_BOOK_TITLE,
1568 EXTRACTOR_METATYPE_FILENAME,
1569 EXTRACTOR_METATYPE_DESCRIPTION,
1570 EXTRACTOR_METATYPE_SUMMARY,
1571 EXTRACTOR_METATYPE_ALBUM,
1572 EXTRACTOR_METATYPE_COMMENT,
1573 EXTRACTOR_METATYPE_SUBJECT,
1574 EXTRACTOR_METATYPE_KEYWORDS,
1575 -1);
1576 if (desc == NULL)
1577 desc = GNUNET_strdup (_("no description supplied"));
1578 mime = GNUNET_CONTAINER_meta_data_get_first_by_types (meta,
1579 EXTRACTOR_METATYPE_MIMETYPE,
1580 EXTRACTOR_METATYPE_FORMAT,
1581 -1);
1582 pixbuf = GNUNET_GTK_get_thumbnail_from_meta_data (meta);
1583 tp = gtk_tree_row_reference_get_path (sr->rr);
1584 tm = gtk_tree_row_reference_get_model (sr->rr);
1585 ts = GTK_TREE_STORE (tm);
1586 gtk_tree_model_get_iter (tm, &iter, tp);
1587 gtk_tree_path_free (tp);
1588 gtk_tree_model_get (tm,
1589 &iter,
1590 0, &ometa,
1591 -1);
1592 if (meta != NULL)
1593 GNUNET_CONTAINER_meta_data_destroy (ometa);
1594 if (availability_certainty > 0)
1595 percent_avail = (availability_certainty + availability_rank) * 50 / availability_certainty;
1596 else
1597 percent_avail = 0;
1598 gtk_tree_store_set (ts,
1599 &iter,
1600 0, GNUNET_CONTAINER_meta_data_duplicate (meta),
1601 3, pixbuf /* preview */,
1602 5, (guint) percent_avail /* percent availability */,
1603 6, desc /* filename/description */,
1604 10, mime,
1605 11, (guint) applicability_rank,
1606 12, (guint) availability_certainty,
1607 13, (gint) availability_rank,
1608 -1);
1609 if (pixbuf != NULL)
1610 g_object_unref (pixbuf);
1611 GNUNET_free (desc);
1612 GNUNET_free_non_null (mime);
1613
1614 notebook = GTK_NOTEBOOK (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_notebook"));
1615 page = gtk_notebook_get_current_page (notebook);
1616 if (gtk_notebook_get_nth_page (notebook,
1617 page) == sr->tab->frame)
1618 {
1619 tv = GTK_TREE_VIEW (gtk_builder_get_object (sr->tab->builder,
1620 "_search_result_frame"));
1621
1622 update_meta_data_views (tv,
1623 sr->tab);
1624 }
1625 return sr;
1626}
1627
1628
1629static void
1630free_search_result (struct SearchResult *sr)
1631{
1632 GtkTreePath *tp;
1633 GtkTreeModel *tm;
1634 GtkTreeIter iter;
1635 struct GNUNET_FS_Uri *uri;
1636 struct GNUNET_CONTAINER_MetaData *meta;
1637
1638 if (sr == NULL)
1639 {
1640 GNUNET_break (0);
1641 return;
1642 }
1643 tp = gtk_tree_row_reference_get_path (sr->rr);
1644 tm = gtk_tree_row_reference_get_model (sr->rr);
1645 gtk_tree_model_get_iter (tm, &iter, tp);
1646 gtk_tree_path_free (tp);
1647 gtk_tree_model_get (tm,
1648 &iter,
1649 0, &meta,
1650 1, &uri,
1651 -1);
1652 if (uri != NULL)
1653 GNUNET_FS_uri_destroy (uri);
1654 if (meta != NULL)
1655 GNUNET_CONTAINER_meta_data_destroy (meta);
1656 gtk_tree_row_reference_free (sr->rr);
1657 gtk_tree_store_remove (GTK_TREE_STORE (tm),
1658 &iter);
1659 GNUNET_free (sr);
1660}
1661
1662
1663/**
1664 * Tell FS to stop publishing.
1665 */
1666static void
1667stop_publishing (GtkButton *button,
1668 gpointer user_data)
1669{
1670 struct PublishTab *tab = user_data;
1671 struct GNUNET_FS_PublishContext *pc;
1672
1673 if (NULL != (pc = tab->pc))
1674 {
1675 tab->pc = NULL;
1676 GNUNET_FS_publish_stop (pc);
1677 }
1678}
1679
1680
1681static struct PublishEntry *
1682setup_publish (struct GNUNET_FS_PublishContext *pc,
1683 const char *fn,
1684 uint64_t fsize,
1685 struct PublishEntry *parent)
1686{
1687 struct PublishTab *tab;
1688 struct PublishEntry *ent;
1689 GtkTreeIter *pitrptr;
1690 GtkTreeIter iter;
1691 GtkTreeIter piter;
1692 GtkTreePath *path;
1693 GtkWindow *df;
1694 GtkWidget *tab_label;
1695 GtkLabel *fn_label;
1696 GtkWidget *close_button;
1697 GtkNotebook *notebook;
1698 gint pages;
1699 char *size_fancy;
1700
1701 if (NULL == parent)
1702 {
1703 /* create new tab */
1704 tab = GNUNET_malloc (sizeof (struct PublishTab));
1705 tab->pc = pc;
1706 GNUNET_CONTAINER_DLL_insert (publish_tab_head,
1707 publish_tab_tail,
1708 tab);
1709 tab->builder = GNUNET_GTK_get_new_builder ("publish_tab.glade");
1710 df = GTK_WINDOW (gtk_builder_get_object (tab->builder,
1711 "_publish_frame_window"));
1712 tab->frame = gtk_bin_get_child (GTK_BIN (df));
1713 gtk_widget_ref (tab->frame);
1714 gtk_container_remove (GTK_CONTAINER (df), tab->frame);
1715 gtk_widget_destroy (GTK_WIDGET (df));
1716
1717 /* load tab_label */
1718 df = GTK_WINDOW (gtk_builder_get_object (tab->builder,
1719 "_publish_label_window"));
1720 tab_label = gtk_bin_get_child (GTK_BIN (df));
1721 gtk_widget_ref (tab_label);
1722 gtk_container_remove (GTK_CONTAINER (df), tab_label);
1723 gtk_widget_destroy (GTK_WIDGET (df));
1724
1725 /* get refs to widgets */
1726 fn_label = GTK_LABEL (gtk_builder_get_object (tab->builder,
1727 "_publish_label_window_label"));
1728 gtk_label_set_text (fn_label, fn);
1729 close_button = GTK_WIDGET (gtk_builder_get_object (tab->builder,
1730 "_publish_label_close_button"));
1731 g_signal_connect(G_OBJECT(close_button), "clicked",
1732 G_CALLBACK(stop_publishing), tab);
1733 /* make visible */
1734 notebook = GTK_NOTEBOOK (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_notebook"));
1735 pages = gtk_notebook_get_n_pages (notebook);
1736 gtk_notebook_insert_page (notebook,
1737 tab->frame,
1738 tab_label,
1739 pages - 1);
1740 gtk_widget_show (GTK_WIDGET (notebook));
1741 tab->ts = GTK_TREE_STORE (gtk_builder_get_object (tab->builder,
1742 "_publish_frame_tree_store"));
1743 pitrptr = NULL;
1744 }
1745 else
1746 {
1747 /* create new iter from parent */
1748 tab = parent->tab;
1749 path = gtk_tree_row_reference_get_path (parent->rr);
1750 if (TRUE != gtk_tree_model_get_iter (GTK_TREE_MODEL (tab->ts),
1751 &piter, path))
1752 {
1753 GNUNET_break (0);
1754 return NULL;
1755 }
1756 pitrptr = &piter;
1757 }
1758 size_fancy = GNUNET_STRINGS_byte_size_fancy (fsize);
1759 gtk_tree_store_insert_with_values (tab->ts,
1760 &iter,
1761 pitrptr,
1762 G_MAXINT,
1763 0, fn,
1764 1, size_fancy,
1765 2, "white",
1766 3, (guint) 0 /* progress */,
1767 -1);
1768 GNUNET_free (size_fancy);
1769 ent = GNUNET_malloc (sizeof (struct PublishEntry));
1770 ent->is_top = (parent == NULL) ? GNUNET_YES : GNUNET_NO;
1771 ent->tab = tab;
1772 path = gtk_tree_model_get_path (GTK_TREE_MODEL (tab->ts), &iter);
1773 ent->rr = gtk_tree_row_reference_new (GTK_TREE_MODEL (tab->ts),
1774 path);
1775 gtk_tree_path_free (path);
1776 ent->pc = pc;
1777 return ent;
1778}
1779
1780
1781/**
1782 * Notification of FS to a client about the progress of an
1783 * operation. Callbacks of this type will be used for uploads,
1784 * downloads and searches. Some of the arguments depend a bit
1785 * in their meaning on the context in which the callback is used.
1786 *
1787 * @param cls closure
1788 * @param info details about the event, specifying the event type
1789 * and various bits about the event
1790 * @return client-context (for the next progress call
1791 * for this operation; should be set to NULL for
1792 * SUSPEND and STOPPED events). The value returned
1793 * will be passed to future callbacks in the respective
1794 * field in the GNUNET_FS_ProgressInfo struct.
1795 */
1796void*
1797GNUNET_GTK_fs_event_handler (void *cls,
1798 const struct GNUNET_FS_ProgressInfo *info)
1799{
1800 void *ret;
1801
1802 switch (info->status)
1803 {
1804 case GNUNET_FS_STATUS_PUBLISH_START:
1805 return setup_publish (info->value.publish.pc,
1806 info->value.publish.filename,
1807 info->value.publish.size,
1808 info->value.publish.pctx);
1809 case GNUNET_FS_STATUS_PUBLISH_RESUME:
1810 ret = setup_publish (info->value.publish.pc,
1811 info->value.publish.filename,
1812 info->value.publish.size,
1813 info->value.publish.pctx);
1814 if (ret == NULL)
1815 return ret;
1816 if (info->value.publish.specifics.resume.message != NULL)
1817 {
1818 ret = handle_publish_error (ret,
1819 info->value.publish.specifics.resume.message);
1820 }
1821 else if (info->value.publish.specifics.resume.chk_uri != NULL)
1822 {
1823 ret = handle_publish_completed (ret,
1824 info->value.publish.specifics.resume.chk_uri);
1825 }
1826 return ret;
1827 case GNUNET_FS_STATUS_PUBLISH_SUSPEND:
1828 close_publish_tab (info->value.publish.cctx);
1829 return NULL;
1830 case GNUNET_FS_STATUS_PUBLISH_PROGRESS:
1831 return mark_publish_progress (info->value.publish.cctx,
1832 info->value.publish.size,
1833 info->value.publish.completed);
1834 case GNUNET_FS_STATUS_PUBLISH_ERROR:
1835 return handle_publish_error (info->value.publish.cctx,
1836 info->value.publish.specifics.error.message);
1837 case GNUNET_FS_STATUS_PUBLISH_COMPLETED:
1838 return handle_publish_completed (info->value.publish.cctx,
1839 info->value.publish.specifics.completed.chk_uri);
1840 case GNUNET_FS_STATUS_PUBLISH_STOPPED:
1841 close_publish_tab (info->value.publish.cctx);
1842 return NULL;
1843 case GNUNET_FS_STATUS_DOWNLOAD_START:
1844 return setup_download (info->value.download.cctx,
1845 info->value.download.pctx,
1846 info->value.download.sctx,
1847 info->value.download.dc,
1848 info->value.download.uri,
1849 info->value.download.specifics.start.meta,
1850 info->value.download.size,
1851 info->value.download.completed);
1852 case GNUNET_FS_STATUS_DOWNLOAD_RESUME:
1853 ret = setup_download (info->value.download.cctx,
1854 info->value.download.pctx,
1855 info->value.download.sctx,
1856 info->value.download.dc,
1857 info->value.download.uri,
1858 info->value.download.specifics.resume.meta,
1859 info->value.download.size,
1860 info->value.download.completed);
1861 if (info->value.download.specifics.resume.message != NULL)
1862 {
1863 ret = mark_download_error (ret,
1864 info->value.download.specifics.resume.message);
1865 }
1866 return ret;
1867 case GNUNET_FS_STATUS_DOWNLOAD_SUSPEND:
1868 stop_download (info->value.download.cctx, GNUNET_YES);
1869 return NULL;
1870 case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
1871 return mark_download_progress (info->value.download.cctx,
1872 info->value.download.size,
1873 info->value.download.completed,
1874 info->value.download.specifics.progress.data,
1875 info->value.download.specifics.progress.offset,
1876 info->value.download.specifics.progress.data_len,
1877 info->value.download.specifics.progress.depth);
1878 case GNUNET_FS_STATUS_DOWNLOAD_ERROR:
1879 return mark_download_error (info->value.download.cctx,
1880 info->value.download.specifics.error.message);
1881 case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED:
1882 return mark_download_completed (info->value.download.cctx,
1883 info->value.download.size,
1884 info->value.download.filename);
1885 case GNUNET_FS_STATUS_DOWNLOAD_STOPPED:
1886 stop_download (info->value.download.cctx, GNUNET_NO);
1887 return NULL;
1888 case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE:
1889 return change_download_colour (info->value.download.cctx,
1890 "yellow");
1891 case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE:
1892 return change_download_colour (info->value.download.cctx,
1893 "blue");
1894 case GNUNET_FS_STATUS_DOWNLOAD_LOST_PARENT:
1895 return download_lost_parent (info->value.download.cctx,
1896 info->value.download.size,
1897 info->value.download.completed,
1898 info->value.download.is_active);
1899 case GNUNET_FS_STATUS_SEARCH_START:
1900 if (info->value.search.pctx != NULL)
1901 return setup_inner_search (info->value.search.sc,
1902 info->value.search.pctx);
1903 return setup_search (info->value.search.sc,
1904 info->value.search.query);
1905 case GNUNET_FS_STATUS_SEARCH_RESUME:
1906 ret = setup_search (info->value.search.sc,
1907 info->value.search.query);
1908 if (info->value.search.specifics.resume.message)
1909 ret = handle_search_error (ret,
1910 info->value.search.specifics.resume.message);
1911 return ret;
1912 case GNUNET_FS_STATUS_SEARCH_RESUME_RESULT:
1913 ret = process_search_result (info->value.search.cctx,
1914 info->value.search.pctx,
1915 info->value.search.specifics.resume_result.uri,
1916 info->value.search.specifics.resume_result.meta,
1917 info->value.search.specifics.resume_result.result,
1918 info->value.search.specifics.resume_result.applicability_rank);
1919 return update_search_result (ret,
1920 info->value.search.specifics.resume_result.meta,
1921 info->value.search.specifics.resume_result.applicability_rank,
1922 info->value.search.specifics.resume_result.availability_certainty,
1923 info->value.search.specifics.resume_result.availability_rank);
1924 case GNUNET_FS_STATUS_SEARCH_SUSPEND:
1925 close_search_tab (info->value.search.cctx);
1926 return NULL;
1927 case GNUNET_FS_STATUS_SEARCH_RESULT:
1928 return process_search_result (info->value.search.cctx,
1929 info->value.search.pctx,
1930 info->value.search.specifics.result.uri,
1931 info->value.search.specifics.result.meta,
1932 info->value.search.specifics.result.result,
1933 info->value.search.specifics.result.applicability_rank);
1934 case GNUNET_FS_STATUS_SEARCH_RESULT_NAMESPACE:
1935 GNUNET_break (0);
1936 break;
1937 case GNUNET_FS_STATUS_SEARCH_UPDATE:
1938 return update_search_result (info->value.search.specifics.update.cctx,
1939 info->value.search.specifics.update.meta,
1940 info->value.search.specifics.update.applicability_rank,
1941 info->value.search.specifics.update.availability_certainty,
1942 info->value.search.specifics.update.availability_rank);
1943 case GNUNET_FS_STATUS_SEARCH_ERROR:
1944 return handle_search_error (info->value.search.cctx,
1945 info->value.search.specifics.error.message);
1946 case GNUNET_FS_STATUS_SEARCH_PAUSED:
1947 return info->value.search.cctx;
1948 case GNUNET_FS_STATUS_SEARCH_CONTINUED:
1949 return info->value.search.cctx;
1950 case GNUNET_FS_STATUS_SEARCH_RESULT_STOPPED:
1951 free_search_result (info->value.search.specifics.result_suspend.cctx);
1952 return NULL;
1953 case GNUNET_FS_STATUS_SEARCH_RESULT_SUSPEND:
1954 free_search_result (info->value.search.specifics.result_suspend.cctx);
1955 return NULL;
1956 case GNUNET_FS_STATUS_SEARCH_STOPPED:
1957 close_search_tab (info->value.search.cctx);
1958 return NULL;
1959 case GNUNET_FS_STATUS_UNINDEX_START:
1960 GNUNET_break (0);
1961 break;
1962 case GNUNET_FS_STATUS_UNINDEX_RESUME:
1963 GNUNET_break (0);
1964 break;
1965 case GNUNET_FS_STATUS_UNINDEX_SUSPEND:
1966 GNUNET_break (0);
1967 break;
1968 case GNUNET_FS_STATUS_UNINDEX_PROGRESS:
1969 GNUNET_break (0);
1970 break;
1971 case GNUNET_FS_STATUS_UNINDEX_ERROR:
1972 GNUNET_break (0);
1973 break;
1974 case GNUNET_FS_STATUS_UNINDEX_COMPLETED:
1975 GNUNET_break (0);
1976 break;
1977 case GNUNET_FS_STATUS_UNINDEX_STOPPED:
1978 GNUNET_break (0);
1979 break;
1980 default:
1981 GNUNET_break (0);
1982 break;
1983 }
1984 return NULL;
1985}
1986
1987
1988/**
1989 * Page switched in main notebook, update thumbnail and
1990 * metadata views.
1991 */
1992void
1993GNUNET_GTK_main_window_notebook_switch_page_cb (GtkWidget * dummy,
1994 gpointer data)
1995{
1996 GtkNotebook *notebook;
1997 gint page;
1998 GtkWidget *w;
1999 struct SearchTab *tab;
2000 GtkImage *image;
2001 GtkListStore *ms;
2002 GtkTreeView *tv;
2003
2004 notebook = GTK_NOTEBOOK (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_notebook"));
2005 page = gtk_notebook_get_current_page (notebook);
2006 w = gtk_notebook_get_nth_page (notebook, page);
2007 tab = search_tab_head;
2008 while (tab != NULL)
2009 {
2010 if (tab->frame == w)
2011 {
2012 tv = GTK_TREE_VIEW (gtk_builder_get_object (tab->builder,
2013 "_search_result_frame"));
2014 update_meta_data_views (tv, tab);
2015 return;
2016 }
2017 tab = tab->next;
2018 }
2019 image = GTK_IMAGE (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_main_window_preview_image"));
2020 gtk_image_clear (image);
2021 ms = GTK_LIST_STORE (GNUNET_GTK_get_main_window_object ("GNUNET_GTK_meta_data_list_store"));
2022 gtk_list_store_clear (ms);
2023}
2024
2025
2026
2027/* end of fs_event_handler.c */