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