aboutsummaryrefslogtreecommitdiff
path: root/src/conversation/gnunet-conversation-gtk_phone.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/conversation/gnunet-conversation-gtk_phone.c')
-rw-r--r--src/conversation/gnunet-conversation-gtk_phone.c1436
1 files changed, 1435 insertions, 1 deletions
diff --git a/src/conversation/gnunet-conversation-gtk_phone.c b/src/conversation/gnunet-conversation-gtk_phone.c
index d04fc84d..59a8a23d 100644
--- a/src/conversation/gnunet-conversation-gtk_phone.c
+++ b/src/conversation/gnunet-conversation-gtk_phone.c
@@ -20,9 +20,1443 @@
20 20
21/** 21/**
22 * @file src/conversation/gnunet-conversation-gtk_phone.c 22 * @file src/conversation/gnunet-conversation-gtk_phone.c
23 * @brief 23 * @brief
24 * @author yids 24 * @author yids
25 * @author hark 25 * @author hark
26 * @author Christian Grothoff
26 */ 27 */
28#include "gnunet-conversation-gtk.h"
29#include "gnunet-conversation-gtk_egos.h"
30#include "gnunet-conversation-gtk_history.h"
31#include "gnunet-conversation-gtk_log.h"
32#include "gnunet-conversation-gtk_phone.h"
27 33
28 34
35/**
36 * active calls treeview columns
37 */
38enum ActiveCallsTreeViewColumns
39{
40 AL_caller_id, //*gchar
41 AL_caller, //*
42 AL_caller_num, //gint
43 AL_type, //gint
44 AL_caller_state, //gint
45 AL_call, //*
46 AL_call_state, //gint
47 AL_call_num //gint
48};
49
50
51/**
52 * callerstate (state of incoming call)
53 */
54enum CallerState
55{
56 CT_active,
57 CT_suspended,
58 CT_ringing,
59 CT_dead,
60 CT_hangup,
61 CT_rejected,
62 CT_other
63};
64
65
66/**
67 * type of call
68 */
69enum TypeOfCall
70{
71 CALL_IN,
72 CALL_OUT
73};
74
75
76/**
77 * Possible states of the phone.
78 */
79enum PhoneState
80{
81 /**
82 * We're waiting for our own idenitty.
83 */
84 PS_LOOKUP_EGO,
85
86 /**
87 * We're listening for calls
88 */
89 PS_LISTEN,
90
91 /**
92 * We accepted an incoming phone call.
93 */
94 PS_ACCEPTED,
95
96 /**
97 * Internal error
98 */
99 PS_ERROR
100};
101
102
103/**
104 * States for current outgoing call.
105 */
106enum CallState
107{
108 /**
109 * We are looking up some other participant.
110 */
111 CS_RESOLVING,
112
113 /**
114 * We are now ringing the other participant.
115 */
116 CS_RINGING,
117
118 /**
119 * The other party accepted our call and we are now connected.
120 */
121 CS_CONNECTED,
122
123 /**
124 * The call is currently suspended (by us).
125 */
126 CS_SUSPENDED
127};
128
129
130
131/**
132 * List of incoming calls
133 */
134struct CallList
135{
136
137 /**
138 * A DLL.
139 */
140 struct CallList *prev;
141
142 /**
143 * A DLL.
144 */
145 struct CallList *next;
146
147 /**
148 * Handle to hang up or activate.
149 */
150 struct GNUNET_CONVERSATION_Caller *caller;
151
152 /**
153 * Handle to call currently selected in list
154 */
155 struct GNUNET_CONVERSATION_Caller *caller_selected;
156
157 /**
158 * String identifying the caller.
159 */
160 char *caller_id;
161
162 /**
163 * Unique number of the caller.
164 */
165 unsigned int caller_num;
166
167};
168
169
170/**
171 *
172 */
173static struct GNUNET_CONVERSATION_Caller *caller_selected;
174
175/**
176 *
177 */
178static struct GNUNET_CONVERSATION_Call *call_selected;
179
180
181/**
182 * List of active calls
183 */
184static GtkListStore *active_liststore;
185
186/**
187 * List of active calls
188 */
189static GtkTreeView *active_treeview;
190
191/**
192 * Unique number of call (outgoing)
193 */
194static unsigned int call_counter;
195
196/**
197 * Counts the number of incoming calls we have had so far.
198 */
199static unsigned int caller_num_gen;
200
201/**
202 * Phone handle
203 */
204static struct GNUNET_CONVERSATION_Phone *phone;
205
206/**
207 * Call handle (for active outgoing call).
208 */
209static struct GNUNET_CONVERSATION_Call *call;
210
211/**
212 * Caller handle (for active incoming call).
213 */
214static struct CallList *cl_active;
215
216/**
217 * Head of calls waiting to be accepted.
218 */
219static struct CallList *cl_head;
220
221/**
222 * Tail of calls waiting to be accepted.
223 */
224static struct CallList *cl_tail;
225
226/**
227 * Our speaker.
228 */
229static struct GNUNET_SPEAKER_Handle *speaker;
230
231/**
232 * Our microphone.
233 */
234static struct GNUNET_MICROPHONE_Handle *mic;
235
236/**
237 * Our phone's current state.
238 */
239static enum PhoneState phone_state;
240
241/**
242 * Our call's current state.
243 */
244static enum CallState call_state;
245
246/**
247 * Name of conversation partner (if any).
248 */
249static char *peer_name;
250
251/**
252 * GNS address for this phone.
253 */
254static char *address;
255
256static GtkWidget *b_contact;
257
258static GtkWidget *b_accept;
259
260static GtkWidget *b_hangup;
261
262static GtkWidget *b_suspend;
263
264static GtkWidget *b_resume;
265
266
267
268/**
269 * Update status based on current phone state.
270 *
271 * @param args arguments given to the command
272 */
273static void
274do_status ()
275{
276 switch (phone_state)
277 {
278 case PS_LOOKUP_EGO:
279 GCG_update_status_bar ("%s",
280 _("Phone inactive: no ego selected for the caller ID."));
281 GCG_set_status_icon ("gnunet-conversation-gtk-tray-pending");
282 break;
283 case PS_LISTEN:
284 GCG_update_status_bar ("%s",
285 _("We are listening for incoming calls"));
286 GCG_set_status_icon ("gnunet-conversation-gtk-tray-available");
287 break;
288 case PS_ACCEPTED:
289 GCG_update_status_bar (_("You are having a conversation with `%s'.\n"),
290 peer_name);
291 GCG_set_status_icon ("gnunet-conversation-call-active");
292 break;
293 case PS_ERROR:
294 GCG_update_status_bar (_("We had an internal error setting up our phone line. You can still make calls."));
295 GCG_set_status_icon ("gnunet-conversation-offline");
296 break;
297 }
298 if (NULL != call)
299 {
300 switch (call_state)
301 {
302 case CS_RESOLVING:
303 GCG_update_status_bar (_("We are trying to find the network address to call `%s'."),
304 peer_name);
305 GCG_set_status_icon ("gnunet-conversation-gtk-tray-call-pending");
306 break;
307 case CS_RINGING:
308 GCG_update_status_bar (_("We are calling `%s', his phone should be ringing."),
309 peer_name);
310 GCG_set_status_icon ("gnunet-conversation-gtk-tray-call-ringing");
311 break;
312 case CS_CONNECTED:
313 GCG_update_status_bar (_("You are having a conversation with `%s'."),
314 peer_name);
315 GCG_set_status_icon ("gnunet-conversation-gtk-tray-call-active");
316 break;
317 case CS_SUSPENDED:
318 GCG_update_status_bar (_("Conversation suspended, you can accept or initiate another call now."),
319 peer_name);
320 GCG_set_status_icon ("gnunet-conversation-gtk-tray-call-suspended");
321 break;
322 }
323 }
324 if ( ( (NULL == call) ||
325 (CS_SUSPENDED == call_state) ) &&
326 (NULL != cl_head) &&
327 ( (cl_head != cl_active) ||
328 (cl_head != cl_tail) ) )
329 GCG_set_status_icon ("gnunet-conversation-gtk-tray-call-incoming");
330}
331
332
333
334/**
335 * @brief print info for currently selected call
336 */
337static void
338print_call_info ()
339{
340 GtkTreeIter gtkiter;
341 gboolean valid;
342 gint row_count = 0;
343
344 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (active_liststore),
345 &gtkiter);
346 if (! valid)
347 GNUNET_break(0);
348
349 while (valid)
350 {
351 gchar *str_data;
352 gint int_data;
353 gpointer cl_caller;
354 gpointer cl_call;
355
356 gtk_tree_model_get (GTK_TREE_MODEL (active_liststore),
357 &gtkiter,
358 AL_caller, &cl_caller,
359 AL_caller_id, &str_data,
360 AL_caller_num, &int_data,
361 AL_call, &cl_call,
362 -1);
363 if (call_selected == cl_call)
364 {
365 GCG_log (_("info for active outgoing call:%s number: %u row: %u"),
366 str_data,
367 int_data,
368 row_count);
369 break;
370 }
371 g_free (str_data);
372 row_count++;
373 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(active_liststore), &gtkiter);
374 }
375}
376
377
378/**
379 * @brief sets caller_selected, and enables or disables the active call list buttons
380 */
381static void
382update_active_call_list_buttons()
383{
384 gchar *caller_id;
385 gpointer cl_caller;
386 gpointer cl_call;
387 gint cl_caller_state;
388 gint cl_type;
389 //gint cl_caller_type;
390 GtkTreeSelection *active_selection;
391 GtkTreeIter gcl_selected;
392 // active_liststore_selection = GCG_get_main_window_object(ml,"GNUNET_CONVERSATION_GTK_active_calls_selection");
393
394 // reset references to selected call/caller
395 //caller_selected = NULL;
396 //call_selected = NULL;
397 GCG_log("reset caller selected");
398 active_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (active_treeview));
399 if (gtk_tree_selection_get_selected (active_selection,
400 NULL,
401 &gcl_selected))
402 {
403 // get selected call
404 gtk_tree_model_get (GTK_TREE_MODEL(active_liststore), &gcl_selected,
405 AL_caller, &cl_caller, // reference to incoming call
406 AL_caller_id, &caller_id,
407 AL_caller_state, &cl_caller_state,
408 AL_type, &cl_type,
409 AL_call, &cl_call, // reference to outgoing call
410 -1);
411 // check if selected call is a incoming or outgoing call
412 switch (cl_type)
413 {
414 case CALL_IN:
415 call_selected = NULL;
416 caller_selected = cl_caller;
417 GNUNET_break (NULL != caller_selected);
418 break;
419 case CALL_OUT:
420 caller_selected = NULL;
421 call_selected = cl_call;
422 GCG_log("outgoing selected");
423 GNUNET_break (NULL != call_selected);
424 break;
425 default:
426 GNUNET_break(0);
427 break;
428 }
429 gtk_widget_show(GTK_WIDGET(GCG_get_main_window_object("GNUNET_GTK_conversation_active_call_list_buttons")));
430 GCG_log("caller state: %u phone_state: %u",
431 cl_caller_state,
432 phone_state);
433 switch (cl_caller_state)
434 {
435 /* buttons:
436 * contact
437 * accept
438 * hangup
439 * suspend
440 * resume
441 *
442 * TODO: check if there is incoming or outgoing call,
443 * disable resume and accept buttons.
444 * or suspend that other call
445 */
446 case CT_active:
447 // hangup, pause
448 //GCG_log("CT_active state: %u ",cl_caller_state);
449 gtk_widget_set_sensitive (b_contact, TRUE);
450 gtk_widget_set_sensitive (b_accept, FALSE);
451 gtk_widget_set_sensitive (b_hangup, TRUE);
452 gtk_widget_set_sensitive (b_suspend, TRUE);
453 gtk_widget_set_sensitive (b_resume, FALSE);
454 break;
455 case CT_ringing:
456 // pickup, phonebook
457 //GCG_log("CT_ring show button");
458 gtk_widget_set_sensitive (b_contact, TRUE);
459 if (phone_state == PS_LISTEN)
460 {
461 gtk_widget_set_sensitive (b_accept, TRUE);
462 }
463 else
464 {
465 gtk_widget_set_sensitive (b_accept, FALSE);
466 }
467 gtk_widget_set_sensitive (b_hangup, FALSE);
468 gtk_widget_set_sensitive (b_suspend, FALSE);
469 gtk_widget_set_sensitive (b_resume, FALSE);
470 break;
471 case CT_rejected:
472 //add to phonebook
473 //GCG_log("CT_rejected ");
474 gtk_widget_set_sensitive (b_contact, TRUE);
475 gtk_widget_set_sensitive (b_accept, FALSE);
476 gtk_widget_set_sensitive (b_hangup, FALSE);
477 gtk_widget_set_sensitive (b_suspend, FALSE);
478 gtk_widget_set_sensitive (b_resume, FALSE);
479 break;
480 case CT_suspended:
481 // resume, hangup
482 //GCG_log("CT_suspended ");
483 gtk_widget_set_sensitive (b_contact, TRUE);
484 gtk_widget_set_sensitive (b_accept, FALSE);
485 gtk_widget_set_sensitive (b_hangup, TRUE);
486 gtk_widget_set_sensitive (b_suspend, FALSE);
487 if (phone_state == PS_LISTEN)
488 {
489 GCG_log("enable resume button");
490 gtk_widget_set_sensitive (b_resume, TRUE);
491 }
492 else
493 {
494 GCG_log("do not disable resume button (for test)");
495 gtk_widget_set_sensitive (b_resume, TRUE);
496 }
497 break;
498 case CT_other:
499 //add to phonebook
500 //GCG_log("CT_rejected ");
501 gtk_widget_set_sensitive (b_contact, TRUE);
502 gtk_widget_set_sensitive (b_accept, TRUE);
503 gtk_widget_set_sensitive (b_hangup, TRUE);
504 gtk_widget_set_sensitive (b_suspend, TRUE);
505 gtk_widget_set_sensitive (b_resume, TRUE);
506 break;
507
508 default:
509 GNUNET_break(0);
510 break;
511 }
512 print_call_info();
513 }
514 else
515 {
516 GCG_log("nothing selected");
517 //gtk_widget_hide(GTK_WIDGET(GCG_get_main_window_object("GNUNET_GTK_conversation_active_call_list_buttons" )));
518 }
519}
520
521
522/**
523 * @brief executed when selecting a different item in active call list
524 */
525void
526gnunet_conversation_gtk_active_calls_treeview_selection_changed_cb ()
527{
528 update_active_call_list_buttons();
529}
530
531
532static void
533disable_list_buttons()
534{
535 gtk_widget_set_sensitive (b_contact, FALSE);
536 gtk_widget_set_sensitive (b_accept, FALSE);
537 gtk_widget_set_sensitive (b_hangup, FALSE);
538 gtk_widget_set_sensitive (b_suspend, FALSE);
539 gtk_widget_set_sensitive (b_resume, FALSE);
540}
541
542
543/**
544 * set state of outgoing call
545 */
546void
547set_outgoing_call_state (struct GNUNET_CONVERSATION_Call *call,
548 int state)
549{
550 GtkTreeIter gtkiter;
551 gint valid = 0;
552 gint cl_type;
553
554 GCG_log("set state to: %u", state);
555 valid = gtk_tree_model_get_iter_first( GTK_TREE_MODEL( active_liststore ), &gtkiter);
556
557 if (!valid)
558 GNUNET_break(0);
559 while (valid)
560 {
561 gchar *cl_caller_id;
562 gint cl_caller_num;
563 gpointer cl_call;
564
565 gtk_tree_model_get ( GTK_TREE_MODEL( active_liststore ), &gtkiter,
566 AL_call, &cl_call,
567 AL_caller_id,&cl_caller_id,
568 AL_caller_num,&cl_caller_num,
569 AL_type, &cl_type,
570 -1);
571 if (cl_type == CALL_OUT)
572 {
573 if (call == NULL) // function called by phone event handler
574 {
575 GCG_log("event handler");
576 gtk_list_store_set(active_liststore, &gtkiter,
577 AL_call_state, state,
578 -1);
579 switch (state)
580 {
581 /**
582 * We are the caller and are now ringing the other party (GNS lookup
583 * succeeded).
584 */
585 case GNUNET_CONVERSATION_EC_CALL_RINGING:
586 break;
587 /**
588 * We are the caller and are now ready to talk as the callee picked up.
589 */
590 case GNUNET_CONVERSATION_EC_CALL_PICKED_UP:
591 break;
592 /**
593 * We are the caller and failed to locate a phone record in GNS.
594 * After this invocation, the respective call handle will be
595 * automatically destroyed and the client must no longer call
596 * #GNUNET_CONVERSATION_call_stop or any other function on the
597 * call object.
598 */
599 case GNUNET_CONVERSATION_EC_CALL_GNS_FAIL:
600 gtk_list_store_remove(active_liststore,&gtkiter);
601 disable_list_buttons();
602 break;
603 /**
604 * We are the caller and the callee called
605 * #GNUNET_CONVERSATION_caller_hang_up. After this invocation, the
606 * respective call handle will be automatically destroyed and the
607 * client must no longer call #GNUNET_CONVERSATION_call_stop.
608 */
609 case GNUNET_CONVERSATION_EC_CALL_HUNG_UP:
610 gtk_list_store_remove(active_liststore,&gtkiter);
611 disable_list_buttons();
612 break;
613 /**
614 * We are the caller and the callee suspended the call. Note that
615 * both sides can independently suspend and resume calls; a call is
616 * only "working" of both sides are active.
617 */
618 case GNUNET_CONVERSATION_EC_CALL_SUSPENDED:
619 break;
620 /**
621 * We are the caller and the callee suspended the call. Note that
622 * both sides can independently suspend and resume calls; a call is
623 * only "working" of both sides are active.
624 */
625 case GNUNET_CONVERSATION_EC_CALL_RESUMED:
626 break;
627 /**
628 * We had an error handing the call, and are now restarting it
629 * (back to lookup). This happens, for example, if the peer
630 * is restarted during a call.
631 */
632 case GNUNET_CONVERSATION_EC_CALL_ERROR:
633 break;
634 default:
635 break;
636 }
637 }
638 else if (call == cl_call) // function called for specific call
639 {
640 //GCG_log (_("setting state for call:%u row: %u state: %u"),cl_caller_num,row_count,state);
641
642 switch (state)
643 {
644 case CT_hangup:
645 //GCG_log("remove line cause hangup");
646 gtk_list_store_remove(active_liststore,&gtkiter);
647 disable_list_buttons();
648 break;
649 case CT_rejected:
650 //GCG_log("remove line cause rejected");
651 gtk_list_store_remove(active_liststore,&gtkiter);
652 disable_list_buttons();
653 break;
654 default:
655 gtk_list_store_set(active_liststore, &gtkiter,
656 AL_caller_state, state,
657 -1);
658 break;
659 }//end switch
660 }//end call=cl_call
661 } //end cl_type
662 g_free (cl_caller_id);
663 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(active_liststore), &gtkiter);
664
665 }//end while
666 GCG_update_status_bar ("");
667}
668
669
670/**
671 * set call state of a incoming call
672 */
673static void
674set_incoming_call_state (struct GNUNET_CONVERSATION_Caller *caller,
675 int state)
676{
677 GtkTreeIter gtkiter;
678 gint valid = 0;
679 //FPRINTF (stderr,"set incoming call state:%u caller: ",state);
680
681// GCG_log (_("set incoming call state:%u caller: "),state);
682
683 valid = gtk_tree_model_get_iter_first( GTK_TREE_MODEL( active_liststore ), &gtkiter );
684
685 if (!valid)
686 GNUNET_break(0);
687
688 while (valid)
689 {
690 gchar *cl_caller_id;
691 gint cl_caller_num;
692 gpointer cl_caller;
693
694 gtk_tree_model_get ( GTK_TREE_MODEL( active_liststore ), &gtkiter,
695 AL_caller, &cl_caller,
696 AL_caller_id,&cl_caller_id,
697 AL_caller_num,&cl_caller_num
698 ,-1);
699
700 if (caller == cl_caller)
701 {
702 //GCG_log (_("setting state for call:%u row: %u state: %u"),cl_caller_num,row_count,state);
703
704 switch (state)
705 {
706 case CT_hangup:
707 //GCG_log("remove line cause hangup");
708 gtk_list_store_remove(active_liststore,&gtkiter);
709 disable_list_buttons();
710
711 break;
712
713 case CT_rejected:
714 //GCG_log("remove line cause rejected");
715 gtk_list_store_remove(active_liststore,&gtkiter);
716 disable_list_buttons();
717
718 break;
719 default:
720
721 gtk_list_store_set(active_liststore, &gtkiter,
722 AL_caller_state, state,
723 -1);
724 break;
725
726 }//end switch
727 }//endif
728
729 g_free (cl_caller_id);
730 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(active_liststore), &gtkiter);
731
732 }//end while
733 GCG_update_status_bar("");
734}
735
736
737/**
738 * Function called with an event emitted by a phone.
739 *
740 * @param cls closure
741 * @param code type of the event
742 * @param caller handle for the caller
743 * @param caller_id name of the caller in GNS
744 */
745static void
746phone_event_handler (void *cls,
747 enum GNUNET_CONVERSATION_PhoneEventCode code,
748 struct GNUNET_CONVERSATION_Caller *caller,
749 const char *caller_id)
750{
751 GtkTreeIter gtkiter;
752 GtkTreeIter gtkiter1;
753 gboolean valid;
754
755 switch (code)
756 {
757 case GNUNET_CONVERSATION_EC_PHONE_RING:
758 //increment call #
759 caller_num_gen++;
760
761
762 GCG_log (_("A Incoming call from `%s' with number %u\n"),
763 caller_id,
764 caller_num_gen);
765
766 //old
767 struct CallList *cl;
768
769 cl = GNUNET_new (struct CallList);
770 cl->caller = caller;
771 cl->caller_id = GNUNET_strdup (caller_id);
772 cl->caller_num = caller_num_gen;
773 GNUNET_CONTAINER_DLL_insert (cl_head, cl_tail, cl);
774 //gtk
775 gtk_list_store_append (active_liststore, &gtkiter);
776
777 gtk_list_store_set (active_liststore, &gtkiter,
778 AL_caller_id, caller_id,
779 AL_caller, caller,
780 AL_caller_num, caller_num_gen,
781 AL_caller_state, CT_ringing,
782 AL_type, CALL_IN
783 ,-1);
784
785
786 break;
787
788 case GNUNET_CONVERSATION_EC_PHONE_HUNG_UP:
789 //gtk
790
791 valid = gtk_tree_model_get_iter_first( GTK_TREE_MODEL( active_liststore ), &gtkiter1 );
792
793 if (!valid)
794 GNUNET_break(0);
795
796 while (valid)
797 {
798 //FPRINTF(stderr,"GNUNET_CONVERSATION_EC_PHONE_HUNG_UP: while valid");
799
800 gchar *str_data;
801 gint int_data;
802 gpointer cl_caller;
803
804 gtk_tree_model_get (GTK_TREE_MODEL(active_liststore), &gtkiter1,
805 AL_caller, &cl_caller,
806 AL_caller_id,&str_data,
807 AL_caller_num,&int_data,-1);
808 if (caller == cl_caller)
809 {
810
811 GCG_log (_("phone hung up:%s number: %u "), str_data,int_data);
812 set_incoming_call_state(caller,CT_rejected);
813 break ;
814 }
815 g_free (str_data);
816 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(active_liststore), &gtkiter1);
817 }
818
819
820
821 phone_state = PS_LISTEN;
822 //add to call history list
823 //history_add(CH_HANGUP, cl->caller_id);
824
825 break;
826
827 }
828 do_status();
829}
830
831
832/**
833 * Function called with an event emitted by a caller.
834 *
835 * @param cls closure with the `struct CallList` of the caller
836 * @param code type of the event issued by the caller
837 */
838static void
839caller_event_handler (void *cls,
840 enum GNUNET_CONVERSATION_CallerEventCode code)
841{
842
843 if (cls == NULL)
844 {
845 GCG_log("caller_event_handler: cls == NULL");
846 GNUNET_break(0);
847 }
848 else
849 {
850 struct CallList *cl = cls;
851
852 switch (code)
853 {
854 case GNUNET_CONVERSATION_EC_CALLER_SUSPEND:
855 //TODO: should this be cls? not cl->caller
856 set_incoming_call_state(cl->caller,CT_suspended);
857 GCG_log (_("Call from `%s' suspended by other user\n"), cl->caller_id);
858 break;
859 case GNUNET_CONVERSATION_EC_CALLER_RESUME:
860 set_incoming_call_state(cl->caller,CT_active);
861 GCG_log (_("Call from `%s' resumed by other user\n"), cl->caller_id);
862 break;
863 }
864 }
865 do_status();
866}
867
868
869
870/**
871 * Start our phone.
872 */
873static void
874start_phone ()
875{
876 struct GNUNET_GNSRECORD_Data rd;
877 struct GNUNET_IDENTITY_Ego *caller_id;
878
879 caller_id = GCG_EGOS_get_selected_ego ();
880 if (NULL == caller_id)
881 {
882 GCG_log ("%s\n",
883 _("No ego selected, phone is now down."));
884 phone_state = PS_LOOKUP_EGO;
885 do_status();
886 return;
887 }
888 phone =
889 GNUNET_CONVERSATION_phone_create (GCG_get_configuration (),
890 caller_id,
891 &phone_event_handler,
892 NULL);
893 if (NULL == phone)
894 {
895 GCG_log ("%s",
896 _("Failed to setup phone (internal error)\n"));
897 phone_state = PS_ERROR;
898 do_status();
899 return;
900 }
901 GNUNET_CONVERSATION_phone_get_record (phone,
902 &rd);
903 /* FIXME: publish record to GNS! */
904 GCG_log ("%s\n",
905 _("Phone active"));
906 phone_state = PS_LISTEN;
907 do_status();
908}
909
910
911/**
912 * Function called with an event emitted by a call.
913 *
914 * @param cls closure, NULL
915 * @param code type of the event on the call
916 */
917static void
918call_event_handler (void *cls,
919 enum GNUNET_CONVERSATION_CallEventCode code)
920{
921 //struct OutgoingCallClosure *cl = cls;
922
923 //GCG_log("call event handler code: %u num: %u", code, cl->call_num);
924
925 //if (cls == NULL){
926 set_outgoing_call_state(NULL, code);
927 //GNUNET_break(0);
928 //} else
929 //{
930 switch (code)
931 {
932 case GNUNET_CONVERSATION_EC_CALL_RINGING:
933 GNUNET_break (CS_RESOLVING == call_state);
934 GCG_log (_("Resolved address of `%s'. Now ringing other party."),
935 peer_name);
936 // set_outgoing_call_state(cls, CT_ringing);
937 call_state = CS_RINGING;
938 break;
939 case GNUNET_CONVERSATION_EC_CALL_PICKED_UP:
940 GNUNET_break (CS_RINGING == call_state);
941 GCG_log (_("Connection established to `%s'."),
942 peer_name);
943 call_state = CS_CONNECTED;
944 break;
945 case GNUNET_CONVERSATION_EC_CALL_GNS_FAIL:
946 GNUNET_break (CS_RESOLVING == call_state);
947 GCG_log (_("Failed to resolve %s in current zone."),
948 peer_name);
949 call = NULL;
950 break;
951 case GNUNET_CONVERSATION_EC_CALL_HUNG_UP:
952 GCG_log ("%s", _("Call terminated"));
953 call = NULL;
954 break;
955 case GNUNET_CONVERSATION_EC_CALL_SUSPENDED:
956 GNUNET_break (CS_CONNECTED == call_state);
957 GCG_log (_("Connection to `%s' suspended (by other user)\n"),
958 peer_name);
959 break;
960 case GNUNET_CONVERSATION_EC_CALL_RESUMED:
961 GNUNET_break (CS_CONNECTED == call_state);
962 GCG_log (_("Connection to `%s' resumed (by other user)\n"),
963 peer_name);
964 break;
965 case GNUNET_CONVERSATION_EC_CALL_ERROR:
966 GCG_log ("GNUNET_CONVERSATION_EC_CALL_ERROR %s",
967 peer_name);
968 }
969 //}
970}
971
972
973
974/**
975 * Initiating a new call
976 *
977 * @param arg arguments given to the command
978 */
979void
980GSC_do_call (const char *arg)
981{
982 GtkEntry *address_entry;
983 struct GNUNET_IDENTITY_Ego *caller_id;
984
985 address_entry = GTK_ENTRY (GCG_get_main_window_object ("GNUNET_GTK_conversation_address"));
986 gtk_entry_set_text (address_entry,
987 address);
988 caller_id = GCG_EGOS_get_selected_ego ();
989 if (NULL == caller_id)
990 {
991 // should not be possible!
992 GCG_log ("%s\n",
993 _("Caller ID unavailable, cannot initiate call."));
994 return;
995 }
996 if (NULL != call)
997 {
998 GCG_log (_("You are calling someone else already, hang up first!\n"));
999 return;
1000 }
1001 switch (phone_state)
1002 {
1003 case PS_LOOKUP_EGO:
1004 GCG_log ("%s\n",
1005 _("Caller ID unavailable, cannot initiate call."));
1006 // should not be possible!
1007 return;
1008 case PS_LISTEN:
1009 /* ok to call! */
1010 break;
1011 case PS_ACCEPTED:
1012 GCG_log (_
1013 ("You are answering call from `%s', hang up or suspend that call first!\n"),
1014 peer_name);
1015 GNUNET_break(0);
1016 return;
1017 case PS_ERROR:
1018 /* ok to call */
1019 break;
1020 }
1021 //GNUNET_free_non_null (peer_name);
1022 peer_name = GNUNET_strdup (arg);
1023 GCG_log (_("now calling: %s"), peer_name);
1024 call_state = CS_RESOLVING;
1025 GNUNET_assert (NULL == call);
1026
1027 call_counter++;
1028 call =
1029 GNUNET_CONVERSATION_call_start (GCG_get_configuration (),
1030 caller_id,
1031 arg,
1032 speaker, mic,
1033 &call_event_handler, NULL);
1034 //call = newcall;
1035
1036 // add call to active call list
1037 GtkTreeIter gtkiter;
1038
1039 gtk_list_store_append (active_liststore, &gtkiter);
1040
1041 gtk_list_store_set (active_liststore, &gtkiter,
1042 AL_caller_id, peer_name,
1043 AL_caller, NULL,
1044 AL_caller_num, NULL,
1045 AL_caller_state, CT_other,
1046 AL_type, CALL_OUT,
1047 AL_call, call,
1048 AL_call_num, call_counter,
1049 AL_call_state, CS_RESOLVING,
1050 -1
1051 );
1052
1053
1054 GCG_update_status_bar (_("We are calling `%s', his phone should be ringing."),
1055 peer_name);
1056 GCG_HISTORY_add (CH_OUTGOING,
1057 peer_name);
1058}
1059
1060
1061/**
1062 * Accepting an incoming call
1063 *
1064 * @param args arguments given to the command
1065 */
1066static void
1067do_accept (struct GNUNET_CONVERSATION_Caller *sel_caller)
1068{
1069 struct CallList *cl;
1070 //char buf[32];
1071
1072
1073 if ((NULL != call) && (CS_SUSPENDED != call_state))
1074 {
1075 GCG_log (_("You are calling someone else already, hang up first!\n"));
1076 GNUNET_break(0);
1077 return;
1078 }
1079 switch (phone_state)
1080 {
1081 case PS_LOOKUP_EGO:
1082 GNUNET_break (0);
1083 break;
1084 case PS_LISTEN:
1085 /* this is the expected state */
1086 break;
1087 case PS_ACCEPTED:
1088 GCG_log (_
1089 ("You are answering call from `%s', hang up or suspend that call first!\n"),
1090 peer_name);
1091 GNUNET_break(0);
1092 return;
1093 case PS_ERROR:
1094 GNUNET_break (0);
1095 break;
1096 }//endswitch
1097
1098 phone_state = PS_ACCEPTED;
1099 set_incoming_call_state(sel_caller,CT_active);
1100
1101 for (cl = cl_head; cl; cl = cl->next)
1102 {
1103 /* FIXME: this may not be unique enough to identify the right item!
1104 * Why not store CallList items in treeview instead of just callers?
1105 */
1106 if (cl->caller == sel_caller)
1107 break;
1108 }
1109 GNUNET_CONVERSATION_caller_pick_up (sel_caller,
1110 &caller_event_handler, cl,
1111 speaker, mic);
1112 GCG_HISTORY_add (CH_ACCEPTED, peer_name);
1113}
1114
1115
1116/**
1117 * Suspending a call
1118 *
1119 * @param args arguments given to the command
1120 */
1121static void
1122do_suspend ()
1123{
1124 /*
1125 switch (phone_state)
1126 {
1127 case PS_LOOKUP_EGO:
1128 case PS_LISTEN:
1129 case PS_ERROR:
1130 GCG_log ("%s", _(" There is no call that could be suspended right now. (PS_ERROR)"));
1131 return;
1132 case PS_ACCEPTED:
1133 // expected state, do rejection logic
1134 break;
1135 }
1136 */
1137 if (call_selected != NULL && caller_selected != NULL)
1138 {
1139 GCG_log("this shoud not be possible");
1140 GNUNET_break(0);
1141 }
1142 else
1143 {
1144 // outgoing
1145 if (NULL != call_selected)
1146 {
1147 GNUNET_CONVERSATION_call_suspend (call_selected);
1148 set_outgoing_call_state(call_selected,CT_suspended);
1149
1150 return;
1151 }
1152
1153 // incoming
1154 if (NULL != caller_selected)
1155 {
1156 GNUNET_CONVERSATION_caller_suspend (caller_selected);
1157 set_incoming_call_state(caller_selected,CT_suspended);
1158 phone_state = PS_LISTEN;
1159 return;
1160
1161 }
1162 }
1163}
1164
1165
1166/**
1167 * Resuming a call
1168 *
1169 * @param args arguments given to the command
1170 */
1171static void
1172do_resume ()
1173{
1174
1175 switch (phone_state)
1176 {
1177 case PS_LOOKUP_EGO:
1178 case PS_ERROR:
1179 GCG_log ("%s", _("There is no call that could be resumed right now.(PS_ERROR)"));
1180 return;
1181 case PS_LISTEN:
1182 break;
1183 case PS_ACCEPTED:
1184 GCG_log (_("Already talking with `%s', cannot resume a call right now."),
1185 peer_name);
1186 return;
1187 }
1188////
1189 if (call_selected != NULL && caller_selected != NULL)
1190 {
1191 GCG_log("this shoud not be possible");
1192 GNUNET_break(0);
1193 return;
1194 }
1195 else
1196 {
1197
1198 // outgoing
1199 if (NULL != call_selected)
1200 {
1201 GNUNET_CONVERSATION_call_resume (call_selected, speaker, mic);
1202 set_outgoing_call_state(call_selected,CT_active);
1203
1204 return;
1205 }
1206
1207 // incoming
1208 if (NULL != caller_selected)
1209 {
1210 GNUNET_CONVERSATION_caller_resume (caller_selected, speaker, mic);
1211 set_incoming_call_state(caller_selected,CT_active);
1212 phone_state = PS_ACCEPTED;
1213 return;
1214
1215 }
1216 GNUNET_break(0);
1217 }
1218
1219//
1220////
1221}
1222
1223
1224/**
1225 / Rejecting a call
1226 *
1227 * @param args arguments given to the command
1228 */
1229static void
1230do_reject ()
1231{
1232 if (call_selected == NULL && caller_selected == NULL)
1233 {
1234 GNUNET_break(0);
1235 }
1236 else
1237 {
1238 // if selected call is outgoing, stop it
1239 if (NULL != call_selected)
1240 {
1241 set_outgoing_call_state(call_selected,CT_hangup);
1242
1243 GNUNET_CONVERSATION_call_stop(call);
1244 //GNUNET_CONVERSATION_call_stop (call_selected);
1245
1246 call = NULL;
1247 call_selected = NULL;
1248 return;
1249 }
1250 else
1251 {
1252 // if selected call is incoming, hang it up
1253 if (NULL != caller_selected)
1254 {
1255 set_incoming_call_state(caller_selected,CT_hangup);
1256 //FPRINTF(stderr,"hangup: %u", caller_selected);
1257 GNUNET_CONVERSATION_caller_hang_up(caller_selected);
1258 //cl_active = NULL;
1259 phone_state = PS_LISTEN;
1260 caller_selected = NULL;
1261 }
1262 else
1263 {
1264 GNUNET_break(0);
1265 }
1266 }
1267 }
1268}
1269
1270
1271/**
1272 * hangup clicked
1273 */
1274void
1275GNUNET_CONVERSATION_GTK_on_hangup_clicked ()
1276{
1277
1278 do_reject ();
1279
1280 do_status ();
1281 //history_add(3,peer_name);
1282}
1283
1284/**
1285 * accept clicked
1286 */
1287void
1288GNUNET_CONVERSATION_GTK_on_accept_clicked ()
1289{
1290 if (caller_selected != NULL)
1291 {
1292 do_accept (caller_selected);
1293 } else {
1294 GNUNET_break(0);
1295 }
1296 do_status();
1297}
1298
1299
1300/**
1301 * reject clicked
1302 */
1303void
1304GNUNET_CONVERSATION_GTK_on_reject_clicked ()
1305{
1306 do_reject ();
1307 do_status();
1308}
1309
1310
1311/**
1312 * User clicked the '> contact' button to move the selected
1313 * caller's information into our address book.
1314 */
1315void
1316GNUNET_CONVERSATION_GTK_use_current_button_clicked (GtkButton *button,
1317 gpointer *user_data)
1318{
1319 // FIXME: implement, use "GSC_add_contact"
1320#if 0
1321 GtkEntry *addressEntry;
1322
1323 addressEntry = GTK_ENTRY (GCG_get_main_window_object ("GNUNET_GTK_conversation_addressAdd"));
1324 gtk_entry_set_text (addressEntry,
1325 "FIXME");
1326#endif
1327}
1328
1329
1330
1331/**
1332 * pause clicked
1333 */
1334void
1335GNUNET_CONVERSATION_GTK_on_pause_clicked ()
1336{
1337 do_suspend ();
1338 do_status();
1339}
1340
1341/**
1342 * resume clicked
1343 */
1344void
1345GNUNET_CONVERSATION_GTK_on_resume_clicked ()
1346{
1347 do_resume ();
1348 do_status();
1349}
1350
1351/**
1352 * status clicked
1353 */
1354void
1355GNUNET_CONVERSATION_GTK_on_status_clicked ()
1356{
1357 do_status ();
1358}
1359
1360
1361/**
1362 * call clicked
1363 */
1364void
1365GNUNET_CONVERSATION_GTK_on_call_clicked ()
1366{
1367 GtkEntry *address_entry;
1368
1369 address_entry = GTK_ENTRY (GCG_get_main_window_object ("GNUNET_GTK_conversation_address"));
1370
1371 GSC_do_call (gtk_entry_get_text(address_entry));
1372 //disable_button ("GNUNET_GTK_conversation_accept_button");
1373 do_status ();
1374// free(to_addr);
1375}
1376
1377
1378/**
1379 * @brief outgoing ego selector changed, (re)start the phone.
1380 *
1381 * @param widget the combo box that changed
1382 * @param user_data builder (unused)
1383 */
1384void
1385gnunet_conversation_gtk_ego_combobox_changed_cb (GtkComboBox *widget,
1386 gpointer user_data)
1387{
1388 if (NULL != phone)
1389 {
1390 GNUNET_CONVERSATION_phone_destroy (phone);
1391 phone = NULL;
1392 }
1393 start_phone();
1394}
1395
1396
1397void
1398GCG_PHONE_init ()
1399{
1400 const struct GNUNET_CONFIGURATION_Handle *cfg;
1401
1402 cfg = GCG_get_configuration ();
1403 speaker = GNUNET_SPEAKER_create_from_hardware (cfg);
1404 mic = GNUNET_MICROPHONE_create_from_hardware (cfg);
1405 /* get gui objects */
1406 b_contact = GTK_WIDGET (GCG_get_main_window_object
1407 ("GNUNET_GTK_conversation_use_current_button"));
1408 b_accept = GTK_WIDGET (GCG_get_main_window_object
1409 ("GNUNET_GTK_conversation_accept_button"));
1410 b_hangup = GTK_WIDGET (GCG_get_main_window_object
1411 ("GNUNET_GTK_conversation_hangup_button"));
1412 b_suspend = GTK_WIDGET (GCG_get_main_window_object
1413 ("GNUNET_GTK_conversation_suspend_button"));
1414 b_resume = GTK_WIDGET (GCG_get_main_window_object
1415 ("GNUNET_GTK_conversation_resume_button"));
1416
1417 active_liststore =
1418 GTK_LIST_STORE (GCG_get_main_window_object
1419 ("gnunet_conversation_gtk_active_calls_liststore"));
1420 active_treeview =
1421 GTK_TREE_VIEW (GCG_get_main_window_object
1422 ("gnunet_conversation_gtk_active_calls_treeview"));
1423}
1424
1425
1426void
1427GCG_PHONE_shutdown ()
1428{
1429//TODO: make this work
1430 //struct OperationContext *oc;
1431
1432/*
1433 GCG_advertise_shutdown_ ();
1434 while (NULL != (oc = oc_head))
1435 {
1436 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1437 _("Operation not completed due to shutdown\n"));
1438 GNUNET_IDENTITY_cancel (oc->op);
1439 GNUNET_CONTAINER_DLL_remove (oc_head,
1440 oc_tail,
1441 oc);
1442 GNUNET_free (oc);
1443 }
1444 */
1445 if (NULL != call)
1446 {
1447 GNUNET_CONVERSATION_call_stop (call);
1448 call = NULL;
1449 }
1450 if (NULL != phone)
1451 {
1452 GNUNET_CONVERSATION_phone_destroy (phone);
1453 phone = NULL;
1454 }
1455 GNUNET_SPEAKER_destroy (speaker);
1456 speaker = NULL;
1457 GNUNET_MICROPHONE_destroy (mic);
1458 mic = NULL;
1459 GNUNET_free_non_null (peer_name);
1460 peer_name = NULL;
1461 phone_state = PS_ERROR;
1462}