/* This file is part of GNUnet. (C) 2010-2013 Christian Grothoff (and other contributing authors) GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/conversation/gnunet-conversation-gtk.c * @brief Main function of gnunet-conversation-gtk * @author yids * @author hark */ #include "gnunet_gtk.h" #include "gtk/gtk.h" #include "gnunet-conversation-gtk.h" #include "gnunet/gnunet_gnsrecord_lib.h" #include "gnunet/gnunet_conversation_service.h" #include "gnunet/gnunet_identity_service.h" #include "gnunet/gnunet_namestore_service.h" #include "gnunet/gnunet_speaker_lib.h" #include "gnunet/gnunet_microphone_lib.h" #include "gnunet/gnunet_namestore_service.h" #include "gnunet/gnunet_gnsrecord_lib.h" #include /* * macro's */ #define UPDATE_STATUS(format, ...) update_status(g_strdup_printf (format, ## __VA_ARGS__)) //#define UPDATE_INFOBAR(format, ...) set_infobar_text(g_strdup_printf (format, ## __VA_ARGS__)) #define LOG(format, ...) log_message(g_strdup_printf (format, ## __VA_ARGS__)) /** * Get an object from the main window. * * @param name name of the object * @return NULL on error */ static GObject * get_object (const char *name) { return GNUNET_GTK_main_loop_get_object (ml, name); } /* * log a message to gtk log textbuffer * @param Message to be logged */ void log_message (const char *message) { // // log // GtkTextBuffer *logbuff; GtkTextView *log_view; GtkTextIter iter; gchar *fmsg; log_view = GTK_TEXT_VIEW(get_object ("GNUNET_GTK_conversation_log")); logbuff = GTK_TEXT_BUFFER(gtk_text_view_get_buffer (log_view)); fmsg = g_strdup_printf (" %s \n", message); gtk_text_buffer_get_start_iter (logbuff, &iter); gtk_text_buffer_insert (logbuff, &iter, fmsg, -1); g_free (fmsg); } /* * does nothing */ void update_state () { // LOG('update_state called',NULL); } /* * update status * * @param message Message to put in statusbar */ void update_status (const gchar * message) { GtkStatusbar *status_bar; guint status_bar_context; gchar *buff; status_bar = GTK_STATUSBAR(get_object ("GNUNET_GTK_conversation_statusbar")); status_bar_context = gtk_statusbar_get_context_id (status_bar, "blaat"); buff = g_strdup_printf ("%s", message); gtk_statusbar_push (GTK_STATUSBAR (status_bar), GPOINTER_TO_INT (status_bar_context), buff); g_free (buff); } /* * adds a item to the call history * * @param type type of call: 0: accepted 1: rejected 2: outgoing call * @return void */ void history_add (int type, char *contactName) { GtkTreeIter iter; time_t t; char *event; switch (type) { case CH_ACCEPTED: event = "Accepted"; break; case CH_REJECTED: event = "Rejected"; break; case CH_OUTGOING: event = "Outgoing"; break; case CH_HANGUP: event = "Hangup"; break; case CH_MISSED: event = "Missed"; break; default: event = "UNKNOWN"; break; } time (&t); gtk_list_store_append (history_liststore, &iter); gtk_list_store_set (history_liststore, &iter, 1, event, 0, ctime (&t), 2, contactName, -1); } /* * set button text * @param button_name name of button * @param label label on the button */ void set_button_text (const char *button_name, const char *label) { //GtkButton *button; GtkWidget *button; button = GTK_WIDGET(get_object (button_name)); gtk_widget_hide (button); } /* * set infobar text */ // //void //set_infobar_text (const gchar * text) //{ // GtkLabel *infolabel; // // infolabel = GTK_LABEL(get_object ("GNUNET_GTK_new_call_label")); // log_message ("setting infobar text"); // gtk_label_set_text (infolabel, text); //} // /* * disable button */ void disable_button (const char *button_name) { //GtkButton *button; GtkWidget *button; button = GTK_WIDGET(get_object (button_name)); gtk_widget_hide (button); } /* * enable button */ void enable_button (const char *button_name) { //GtkButton *button; GtkWidget *button; button = GTK_WIDGET(get_object (button_name)); gtk_widget_show (button); } /* * show infobar */ // //void //show_infobar () //{ // GtkWidget *infobar; // // infobar = GTK_WIDGET(get_object ("GNUNET_GTK_conversation_infobar")); // // gtk_widget_show (infobar); //} // /* * hide infobar */ // //void //hide_infobar () //{ // //GtkInfoBar *infobar; // GtkWidget *infobar; // // infobar = GTK_WIDGET(get_object ("GNUNET_GTK_conversation_infobar")); // // gtk_widget_hide (infobar); //} // /** * Function called with an event emitted by a phone. * * @param cls closure * @param code type of the event * @param caller handle for the caller * @param caller_id name of the caller in GNS */ static void phone_event_handler (void *cls, enum GNUNET_CONVERSATION_PhoneEventCode code, struct GNUNET_CONVERSATION_Caller *caller, const char *caller_id) { struct CallList *cl; switch (code) { case GNUNET_CONVERSATION_EC_PHONE_RING: LOG (_("A Incoming call from `%s' on line %u\n"), caller_id, caller_num_gen); //UPDATE_INFOBAR (_("Incoming call from `%s' on line %u\n"), caller_id, // caller_num_gen); //show_infobar (); // TODO: make sound cl = GNUNET_new (struct CallList); cl->caller = caller; cl->caller_id = GNUNET_strdup (caller_id); cl->caller_num = caller_num_gen++; GNUNET_CONTAINER_DLL_insert (cl_head, cl_tail, cl); //strncpy (&callerName, &caller_id, 50); //callerName[52] = '\0'; quick_message ("der is een beller", caller_id); break; case GNUNET_CONVERSATION_EC_PHONE_HUNG_UP: for (cl = cl_head; NULL != cl; cl = cl->next) if (caller == cl->caller) break; if (NULL == cl) { GNUNET_break (0); return; } LOG (_("Call from `%s' terminated\n"), cl->caller_id); GNUNET_CONTAINER_DLL_remove (cl_head, cl_tail, cl); GNUNET_free (cl->caller_id); if (cl == cl_active) { cl_active = NULL; phone_state = PS_LISTEN; } GNUNET_free (cl); gtk_widget_destroy (GTK_WIDGET(dialog)); break; } } /** * Function called with an event emitted by a caller. * * @param cls closure with the `struct CallList` of the caller * @param code type of the event issued by the caller */ static void caller_event_handler (void *cls, enum GNUNET_CONVERSATION_CallerEventCode code) { struct CallList *cl = cls; switch (code) { case GNUNET_CONVERSATION_EC_CALLER_SUSPEND: update_state (); LOG (_("Call from `%s' suspended by other user\n"), cl->caller_id); break; case GNUNET_CONVERSATION_EC_CALLER_RESUME: update_state (); LOG (_("Call from `%s' resumed by other user\n"), cl->caller_id); break; } } /** * Start our phone. */ static void start_phone () { struct GNUNET_GNSRECORD_Data rd; if (NULL == caller_id) { LOG (_("Ego `%s' no longer available, phone is now down.\n"), ego_name); phone_state = PS_LOOKUP_EGO; return; } //GNUNET_assert (NULL == phone); phone = GNUNET_CONVERSATION_phone_create (cfg, caller_id, &phone_event_handler, NULL); /* FIXME: get record and print full GNS record info later here... */ if (NULL == phone) { LOG ("%s", _("Failed to setup phone (internal error)\n")); phone_state = PS_ERROR; } else { GNUNET_CONVERSATION_phone_get_record (phone, &rd); GNUNET_free_non_null (address); address = GNUNET_GNSRECORD_value_to_string (rd.record_type, rd.data, rd.data_size); LOG (_("address: `%s' \n"), address); if (verbose) LOG (_("Phone active on line %u\n"), (unsigned int) line); phone_state = PS_LISTEN; } } /** * Function called with an event emitted by a call. * * @param cls closure, NULL * @param code type of the event on the call */ static void call_event_handler (void *cls, enum GNUNET_CONVERSATION_CallEventCode code) { switch (code) { case GNUNET_CONVERSATION_EC_CALL_RINGING: GNUNET_break (CS_RESOLVING == call_state); LOG (_("Resolved address of `%s'. Now ringing other party."), peer_name); call_state = CS_RINGING; break; case GNUNET_CONVERSATION_EC_CALL_PICKED_UP: GNUNET_break (CS_RINGING == call_state); LOG (_("Connection established to `%s'"), peer_name); call_state = CS_CONNECTED; break; case GNUNET_CONVERSATION_EC_CALL_GNS_FAIL: GNUNET_break (CS_RESOLVING == call_state); LOG (_("Failed to resolve %s in ego `%s'"), peer_name, ego_name); call = NULL; break; case GNUNET_CONVERSATION_EC_CALL_HUNG_UP: LOG ("%s", _("Call terminated")); call = NULL; break; case GNUNET_CONVERSATION_EC_CALL_SUSPENDED: GNUNET_break (CS_CONNECTED == call_state); LOG (_("Connection to `%s' suspended (by other user)\n"), peer_name); break; case GNUNET_CONVERSATION_EC_CALL_RESUMED: GNUNET_break (CS_CONNECTED == call_state); LOG (_("Connection to `%s' resumed (by other user)\n"), peer_name); break; case GNUNET_CONVERSATION_EC_CALL_ERROR: LOG ("GNUNET_CONVERSATION_EC_CALL_ERROR %s", peer_name); } } /** * Initiating a new call * * @param arg arguments given to the command */ static void do_call (const char *arg) { if (NULL == caller_id) { LOG (_("Ego `%s' not available\n"), ego_name); return; } if (NULL != call) { LOG (_("You are calling someone else already, hang up first!\n")); return; } switch (phone_state) { case PS_LOOKUP_EGO: LOG (_("Ego `%s' not available\n"), ego_name); return; case PS_LISTEN: /* ok to call! */ break; case PS_ACCEPTED: LOG (_ ("You are answering call from `%s', hang up or suspend that call first!\n"), peer_name); return; case PS_ERROR: /* ok to call */ break; } GNUNET_free_non_null (peer_name); peer_name = GNUNET_strdup (arg); LOG (_("now calling: %s"), peer_name); call_state = CS_RESOLVING; GNUNET_assert (NULL == call); call = GNUNET_CONVERSATION_call_start (cfg, caller_id, arg, speaker, mic, &call_event_handler, NULL); UPDATE_STATUS (_("We are calling `%s', his phone should be ringing."), peer_name); history_add(2,peer_name); } /** * Accepting an incoming call * * @param args arguments given to the command */ static void do_accept (const char *args) { struct CallList *cl; char buf[32]; if ((NULL != call) && (CS_SUSPENDED != call_state)) { LOG (_("You are calling someone else already, hang up first!\n")); return; } switch (phone_state) { case PS_LOOKUP_EGO: GNUNET_break (0); break; case PS_LISTEN: /* this is the expected state */ break; case PS_ACCEPTED: LOG (_ ("You are answering call from `%s', hang up or suspend that call first!\n"), peer_name); return; case PS_ERROR: GNUNET_break (0); break; } cl = cl_head; if (NULL == cl) { LOG (_("There is no incoming call to accept here!\n")); return; } if ((NULL != cl->next) || (NULL != args)) { for (cl = cl_head; NULL != cl; cl = cl->next) { GNUNET_snprintf (buf, sizeof (buf), "%u", cl->caller_num); if (0 == strcmp (buf, args)) break; } } if (NULL == cl) { LOG (_("There is no incoming call `%s' to accept right now!\n"), args); return; } cl_active = cl; GNUNET_free_non_null (peer_name); peer_name = GNUNET_strdup (cl->caller_id); phone_state = PS_ACCEPTED; GNUNET_CONVERSATION_caller_pick_up (cl->caller, &caller_event_handler, cl, speaker, mic); history_add (0, peer_name); } /** * update statusbar * * @param args arguments given to the command */ static void do_status (const char *args) { struct CallList *cl; switch (phone_state) { case PS_LOOKUP_EGO: UPDATE_STATUS (_ ("We are currently trying to locate the private key for the ego `%s'."), ego_name); break; case PS_LISTEN: UPDATE_STATUS (_ ("We are listening for incoming calls for ego `%s' on line %u."), ego_name, line); break; case PS_ACCEPTED: UPDATE_STATUS (_("You are having a conversation with `%s'.\n"), peer_name); break; case PS_ERROR: UPDATE_STATUS (_ ("We had an internal error setting up our phone line. You can still make calls.")); break; } if (NULL != call) { switch (call_state) { case CS_RESOLVING: UPDATE_STATUS (_ ("We are trying to find the network address to call `%s'."), peer_name); break; case CS_RINGING: UPDATE_STATUS (_("We are calling `%s', his phone should be ringing."), peer_name); break; case CS_CONNECTED: UPDATE_STATUS (_("You are having a conversation with `%s'."), peer_name); break; case CS_SUSPENDED: /* ok to accept incoming call right now */ break; } } if ((NULL != cl_head) && ((cl_head != cl_active) || (cl_head != cl_tail))) { for (cl = cl_head; NULL != cl; cl = cl->next) { if (cl == cl_active) continue; //UPDATE_STATUS (_("#%u: `%s'"), cl->caller_num, cl->caller_id); LOG ("%s", _("Calls waiting:")); } } } /** * Suspending a call * * @param args arguments given to the command */ static void do_suspend (const char *args) { if (NULL != call) { switch (call_state) { case CS_RESOLVING: case CS_RINGING: case CS_SUSPENDED: LOG ("%s", _("There is no call that could be suspended right now.")); return; case CS_CONNECTED: call_state = CS_SUSPENDED; GNUNET_CONVERSATION_call_suspend (call); return; } } switch (phone_state) { case PS_LOOKUP_EGO: case PS_LISTEN: case PS_ERROR: LOG ("%s", _("There is no call that could be suspended right now.")); return; case PS_ACCEPTED: /* expected state, do rejection logic */ break; } GNUNET_assert (NULL != cl_active); GNUNET_CONVERSATION_caller_suspend (cl_active->caller); cl_active = NULL; phone_state = PS_LISTEN; } /** * Resuming a call * * @param args arguments given to the command */ static void do_resume (const char *args) { struct CallList *cl; char buf[32]; if (NULL != call) { switch (call_state) { case CS_RESOLVING: case CS_RINGING: case CS_CONNECTED: LOG ("%s", _("There is no call that could be resumed right now.")); return; case CS_SUSPENDED: call_state = CS_CONNECTED; GNUNET_CONVERSATION_call_resume (call, speaker, mic); return; } } switch (phone_state) { case PS_LOOKUP_EGO: case PS_ERROR: LOG ("%s", _("There is no call that could be resumed right now.")); return; case PS_LISTEN: /* expected state, do resume logic */ break; case PS_ACCEPTED: LOG (_("Already talking with `%s', cannot resume a call right now."), peer_name); return; } GNUNET_assert (NULL == cl_active); cl = cl_head; if (NULL == cl) { LOG (_("There is no incoming call to resume here!")); return; } if ((NULL != cl->next) || (NULL != args)) { for (cl = cl_head; NULL != cl; cl = cl->next) { GNUNET_snprintf (buf, sizeof (buf), "%u", cl->caller_num); if (0 == strcmp (buf, args)) break; } } if (NULL == cl) { LOG (_("There is no incoming call `%s' to resume right now!"), args); return; } cl_active = cl; GNUNET_CONVERSATION_caller_resume (cl_active->caller, speaker, mic); phone_state = PS_ACCEPTED; } /** / Rejecting a call * * @param args arguments given to the command */ static void do_reject (const char *args) { struct CallList *cl; char buf[32]; if (NULL != call) { GNUNET_CONVERSATION_call_stop (call); call = NULL; return; } switch (phone_state) { case PS_LOOKUP_EGO: case PS_ERROR: LOG ("%s", _("There is no call that could be cancelled right now.\n")); return; case PS_LISTEN: /* look for active incoming calls to refuse */ cl = cl_head; if (NULL == cl) { LOG (_("There is no incoming call to refuse here!\n")); return; } if ((NULL != cl->next) || (NULL != args)) { for (cl = cl_head; NULL != cl; cl = cl->next) { GNUNET_snprintf (buf, sizeof (buf), "%u", cl->caller_num); if (0 == strcmp (buf, args)) break; } } if (NULL == cl) { LOG (_("There is no incoming call `%s' to refuse right now!\n"), args); return; } GNUNET_CONVERSATION_caller_hang_up (cl->caller); GNUNET_CONTAINER_DLL_remove (cl_head, cl_tail, cl); peer_name = GNUNET_strdup (cl->caller_id); GNUNET_free (cl->caller_id); GNUNET_free (cl); break; case PS_ACCEPTED: /* expected state, do rejection logic */ GNUNET_assert (NULL != cl_active); GNUNET_CONVERSATION_caller_hang_up (cl_active->caller); GNUNET_free (cl_active); // cl_active = NULL; phone_state = PS_LISTEN; break; } history_add (1, peer_name); } //////////////////////////// static void display_record (void *cls, const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key, const char *rname, unsigned int rd_len, const struct GNUNET_GNSRECORD_Data *rd) { const char *typestring; char *s, *type; unsigned int i; const char *ets; struct GNUNET_TIME_Absolute at; struct GNUNET_TIME_Relative rt; GtkTreeIter iter; if (NULL == rname) { list_it = NULL; //test_finished (); return; } if ((NULL != name) && (0 != strcmp (name, rname))) { GNUNET_NAMESTORE_zone_iterator_next (list_it); return; } //FPRINTF (stdout, // "%s:\n", // rname); for (i = 0; i < rd_len; i++) { if ((GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) && (0 != strcmp (rname, "+"))) continue; typestring = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type); s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type, rd[i].data, rd[i].data_size); if (NULL == s) { FPRINTF (stdout, _("\tCorrupt or unsupported record of type %u\n"), (unsigned int) rd[i].record_type); continue; } if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION)) { rt.rel_value_us = rd[i].expiration_time; ets = GNUNET_STRINGS_relative_time_to_string (rt, GNUNET_YES); } else { at.abs_value_us = rd[i].expiration_time; ets = GNUNET_STRINGS_absolute_time_to_string (at); } if (rd[i].record_type == 65536) { type = "PKEY"; } // if pubkey record if (rd[i].record_type == 65542) { type = "PHONE"; } // FPRINTF (stdout, "%s", rname); gtk_list_store_append (contacts_liststore, &iter); gtk_list_store_set (contacts_liststore, &iter, 1, type, 0, rname, -1); /* FPRINTF (stdout, "\t%s: %s (%s)\t%s\t%s\t%s\n", typestring, s, ets, (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)) ? "PRIVATE" : "PUBLIC", (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)) ? "SHADOW" : "", (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PENDING)) ? "PENDING" : ""); */ //gtk_widget_show(contacts_liststore); GNUNET_free (s); } // FPRINTF (stdout, "%s", "\n"); GNUNET_NAMESTORE_zone_iterator_next (list_it); } /** * Continuation called to notify client about result of the * operation. * * @param cls closure, location of the QueueEntry pointer to NULL out * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) * #GNUNET_NO if content was already there * #GNUNET_YES (or other positive value) on success * @param emsg NULL on success, otherwise an error message */ static void add_continuation (void *cls, int32_t success, const char *emsg) { struct GNUNET_NAMESTORE_QueueEntry **qe = cls; *qe = NULL; if (GNUNET_YES != success) { fprintf (stderr, _("Adding record failed: %s\n"), (GNUNET_NO == success) ? "record exists" : emsg); if (GNUNET_NO != success) ret = 1; } ret = 0; //test_finished (); } /** * Continuation called to notify client about result of the * operation. * * @param cls closure, unused * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate) * #GNUNET_NO if content was already there * #GNUNET_YES (or other positive value) on success * @param emsg NULL on success, otherwise an error message */ static void del_continuation (void *cls, int32_t success, const char *emsg) { del_qe = NULL; if (GNUNET_NO == success) { fprintf (stderr, _("Deleting record failed, record does not exist%s%s\n"), (NULL != emsg) ? ": " : "", (NULL != emsg) ? emsg : ""); } if (GNUNET_SYSERR == success) { fprintf (stderr, _("Deleting record failed%s%s\n"), (NULL != emsg) ? ": " : "", (NULL != emsg) ? emsg : ""); } // test_finished (); } /** * Function called by identity service with information about egos. * * @param cls NULL * @param ego ego handle * @param ctx unused * @param name name of the ego */ static void identity_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego, void **ctx, const char *name) { // FPRINTF (stderr, _("identity_cb name: `%s' caller_id: `%s' \n"), name, // caller_id); if (NULL == name) return; if (ego == caller_id) { if (verbose) LOG (_("Name of our ego changed to `%s'\n"), name); GNUNET_free (ego_name); ego_name = GNUNET_strdup (name); return; } if (0 != strcmp (name, ego_name)) return; if (NULL == ego) { if (verbose) LOG (_("Our ego `%s' was deleted!\n"), ego_name); caller_id = NULL; return; } caller_id = ego; GNUNET_CONFIGURATION_set_value_number (cfg, "CONVERSATION", "LINE", line); zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (caller_id); ns = GNUNET_NAMESTORE_connect (cfg); list_it = GNUNET_NAMESTORE_zone_iteration_start (ns, &zone_pkey, &display_record, NULL); start_phone (); } /** * Get our configuration. * * @return configuration handle */ const struct GNUNET_CONFIGURATION_Handle * GIG_get_configuration () { return GNUNET_GTK_main_loop_get_configuration (ml); } /** * Task run on shutdown. * * @param cls unused * @param tc scheduler context, unused */ static void shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { //TODO: make this work //struct OperationContext *oc; /* GIG_advertise_shutdown_ (); while (NULL != (oc = oc_head)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Operation not completed due to shutdown\n")); GNUNET_IDENTITY_cancel (oc->op); GNUNET_CONTAINER_DLL_remove (oc_head, oc_tail, oc); GNUNET_free (oc); } if (NULL != identity) { GNUNET_IDENTITY_disconnect (identity); identity = NULL; } */ GNUNET_GTK_tray_icon_destroy (); GNUNET_GTK_main_loop_quit (ml); ml = NULL; } /** * Callback invoked if the application is supposed to exit. * * @param object * @param user_data unused */ void GNUNET_GTK_conversation_quit_cb (GObject * object, gpointer user_data) { if (NULL != call) { GNUNET_CONVERSATION_call_stop (call); call = NULL; } if (NULL != phone) { GNUNET_CONVERSATION_phone_destroy (phone); phone = NULL; } if (NULL != id) { GNUNET_IDENTITY_disconnect (id); id = NULL; } if (NULL != ns) { GNUNET_NAMESTORE_disconnect (ns); ns = NULL; } GNUNET_SPEAKER_destroy (speaker); speaker = NULL; GNUNET_MICROPHONE_destroy (mic); mic = NULL; GNUNET_free (ego_name); ego_name = NULL; GNUNET_free_non_null (peer_name); phone_state = PS_ERROR; GNUNET_SCHEDULER_shutdown (); GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey); //return 0; } /** * Actual main function run right after GNUnet's scheduler * is initialized. Initializes up GTK and Glade. * * @param cls NULL * @param tc schedule context */ static void run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { //GtkTreeIter iter; GtkWindow *main_window; //line = 0; ml = cls; if (GNUNET_OK != GNUNET_GTK_main_loop_build_window (ml, NULL)) return; GNUNET_GTK_set_icon_search_path (); GNUNET_GTK_setup_nls (); /* setup main window */ main_window = GTK_WINDOW (get_object ("GNUNET_GTK_conversation_window")); main_window = GTK_WIDGET(GNUNET_GTK_plug_me ("GNUNET_CONVERSATION_GTK_PLUG", GTK_WIDGET(main_window))); gtk_window_set_default_size (main_window, 300, 700); contacts_liststore = GTK_LIST_STORE (get_object ("gnunet_conversation_gtk_contacts_liststore")); contacts_treeview = GTK_TREE_VIEW (get_object ("gnunet_conversation_gtk_treeview")); contacts_treestore = GTK_TREE_STORE (get_object ("gnunet_conversation_gtk_contacts_treestore")); contacts_treemodel = GTK_TREE_MODEL (contacts_treestore); history_liststore = GTK_LIST_STORE (get_object ("gnunet_conversation_gtk_history_liststore")); history_treeview = GTK_TREE_VIEW (get_object ("gnunet_conversation_gtk_history_treeview")); history_treestore = GTK_TREE_STORE (get_object ("gnunet_conversation_gtk_history_treestore")); history_treemodel = GTK_TREE_MODEL (history_treestore); //gtk_tree_view_set_activate_on_single_click(contacts_treeview, TRUE); GNUNET_assert (NULL != contacts_liststore); // gtk_window_maximize (GTK_WINDOW (main_window)); if (NULL == getenv ("GNUNET_CONVERSATION_GTK_PLUG")) GNUNET_GTK_tray_icon_create (ml, GTK_WINDOW (main_window), "gnunet-gtk" /* FIXME: different icon? */ , "gnunet-conversation-gtk"); /* make GUI visible */ if (!tray_only) { gtk_widget_show (GTK_WIDGET(main_window)); gtk_window_present (GTK_WINDOW (main_window)); } /* get gui objects */ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task, NULL); cfg = GIG_get_configuration (); //cfg = GNUNET_CONFIGURATION_dup (c); speaker = GNUNET_SPEAKER_create_from_hardware (GIG_get_configuration()); mic = GNUNET_MICROPHONE_create_from_hardware (GIG_get_configuration()); if (NULL == ego_name) { ego_name = "phone-ego"; LOG (_("No ego given, using default: %s "), ego_name); } id = GNUNET_IDENTITY_connect (cfg, &identity_cb, NULL); // zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (caller_id); } /** * Main function of gnunet-conversation-gtk. * * @param argc number of arguments * @param argv arguments * @return 0 on success */ int main (int argc, char *const *argv) { static struct GNUNET_GETOPT_CommandLineOption options[] = { {'p', "phone", "LINE", gettext_noop ("sets the LINE to use for the phone"), 1, &GNUNET_GETOPT_set_uint, &line}, {'e', "ego", "ego", gettext_noop ("select ego to use"), 1, &GNUNET_GETOPT_set_string, &ego_name}, {'t', "tray", NULL, gettext_noop ("start in tray mode"), 0, &GNUNET_GETOPT_set_one, &tray_only}, GNUNET_GETOPT_OPTION_END }; if (GNUNET_OK != GNUNET_GTK_main_loop_start ("gnunet-conversation-gtk", "GTK GUI for conversation", argc, argv, options, "gnunet_conversation_gtk_main_window.glade", &run)) return 1; return 0; // FPRINTF (stderr, "line %i", line); } /* gui stuff start */ /* * Accept call window * TODO: rename this * * @param message message in the dialogbox * @param caller_id */ void quick_message (gchar * message, const char *caller_id) { GtkWidget *caller_name, *notification, *content_area; GtkWidget *dialog; GtkWindow *main_window; main_window = GTK_WINDOW(get_object("GNUNET_GTK_conversation_window")); // Create the widgets dialog = gtk_dialog_new_with_buttons ("Incoming call!", main_window, GTK_DIALOG_DESTROY_WITH_PARENT, _("Accept call"), GTK_RESPONSE_ACCEPT, _("Reject call"), GTK_RESPONSE_REJECT, _("Decide later"), GTK_RESPONSE_CANCEL, NULL); content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); notification = gtk_label_new ("Incoming call from:"); caller_name = gtk_label_new (caller_id); // Add the labels, and show everything we've added to the dialog gtk_container_add (GTK_CONTAINER (content_area), notification); gtk_container_add (GTK_CONTAINER (content_area), caller_name); gtk_widget_show_all (GTK_WIDGET(dialog)); switch(gtk_dialog_run(GTK_DIALOG(dialog))){ case GTK_RESPONSE_ACCEPT : do_status(""); gtk_widget_destroy(GTK_WIDGET(dialog)); do_accept("0"); break; case GTK_RESPONSE_REJECT : do_reject("0"); do_status(""); gtk_widget_destroy(GTK_WIDGET(dialog)); break; case GTK_RESPONSE_CANCEL : do_status(""); gtk_widget_destroy(GTK_WIDGET(dialog)); break; } } /** * call clicked */ void GNUNET_CONVERSATION_GTK_on_call_clicked () { // char *to_addr = malloc((MAX_TO_ADDR+1)*sizeof(char)); char *to_addr; GtkEntry *address_entry; address_entry = GTK_ENTRY (get_object ("GNUNET_GTK_conversation_address")); to_addr = gtk_entry_get_text (address_entry); // strncpy(to_addr, gtk_entry_get_text (address_entry), MAX_TO_ADDR); // to_addr[strlen(to_addr)+1] = '\0'; // FPRINTF (stderr, _("calling: %s \n"), to_addr ); do_call (to_addr); disable_button ("GNUNET_GTK_conversation_accept_button"); do_status (""); // free(to_addr); } /** * clicked */ void GNUNET_CONVERSATION_GTK_on_hangup_clicked () { //update_status()disable_button("GNUNET_CONVERSATION_GTK_call_button"); enable_button ("GNUNET_GTK_conversation_call_button"); //FPRINTF (stderr, "hangup clicked \n"); do_reject (NULL); do_status (""); //history_add(3,peer_name); } /** * clicked */ void GNUNET_CONVERSATION_GTK_on_accept_clicked () { FPRINTF (stderr, "accept clicked \n"); do_accept (0); // hide_infobar (); } /** * clicked */ void GNUNET_CONVERSATION_GTK_on_reject_clicked () { LOG ("reject clicked \n"); do_reject ("0"); } /** * clicked */ void GNUNET_CONVERSATION_GTK_on_pause_clicked () { // GtkEntry *entry; do_suspend("0"); //FPRINTF (stderr, "pause clicked \n"); //do_pause(""); // entry = GTK_ENTRY((get_object ("GNUNET_GTK_conversation_address"))); //FPRINTF (stderr, gtk_entry_get_text (entry)); // gtk_entry_set_text (entry, "testtextje"); // show_infobar (); } /** * clicked */ void GNUNET_CONVERSATION_GTK_on_resume_clicked () { //FPRINTF (stderr, "reject clicked \n"); do_resume (""); } /** * clicked */ void GNUNET_CONVERSATION_GTK_on_status_clicked () { // do_accept("0"); do_status (" "); //quick_message('hee blaaat you have a call from blaat'); } /* * add a new contact * @param name * @param address */ void add_contact(const gchar *name, const gchar *address) { // memmove(&address+1,&address+51,1); GtkTreeIter iter; struct GNUNET_GNSRECORD_Data rd; struct GNUNET_GNSRECORD_Data *rde; static void *data; static size_t data_size; struct GNUNET_CRYPTO_EcdsaPublicKey pkey; GNUNET_CRYPTO_ecdsa_public_key_from_string (address, strlen (address), &pkey); rde=&rd; zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (caller_id); rd.data = &pkey; rd.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey); rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY; rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; // always set to relative for testing purposes rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE; rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us; FPRINTF (stderr, "adding\n"); FPRINTF (stderr, "name: %s\n", name); FPRINTF (stderr, "address: %s\n", address); if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value (65536, address, &data, &data_size)) { FPRINTF (stderr, "invalid address\n"); } else { add_qe = GNUNET_NAMESTORE_records_store (ns, &zone_pkey, name, 1, rde, &add_continuation, &add_qe); gtk_list_store_append (contacts_liststore, &iter); gtk_list_store_set (contacts_liststore, &iter, 1, "PKEY", 0, name, -1); } } /* * executed when clicked on add contact * @param button * @param user_data */ void GNUNET_CONVERSATION_GTK_on_add_clicked (GtkButton * button, gpointer * user_data) { // gint response_id; //unused: *anotherArea, *labelName, *labelAddres *caller_name GtkLabel *notification; // GtkHBox *content_area; GtkContainer *content_area; GtkButton *currentCheckButton; GtkEntry *nameEntry, *addressEntry; GtkDialog *dialog; GtkWindow *main_window; currentCheckButton = GTK_BUTTON(gtk_button_new_with_label ("use currently incoming addres")); nameEntry = GTK_ENTRY(gtk_entry_new ()); gtk_entry_set_text (nameEntry, "Name of contact"); addressEntry = GTK_ENTRY(gtk_entry_new ()); gtk_entry_set_text (addressEntry, "Address of contact"); main_window = GTK_WINDOW(get_object ("GNUNET_GTK_conversation_window")); dialog = GTK_DIALOG(gtk_dialog_new_with_buttons ("Adding contact", main_window, GTK_DIALOG_DESTROY_WITH_PARENT, _("Add contact"), GTK_RESPONSE_ACCEPT, _("Cancel"), GTK_RESPONSE_CANCEL, NULL)); gtk_dialog_add_action_widget (dialog, GTK_WIDGET(currentCheckButton), GTK_RESPONSE_OK); // FPRINTF (stderr, "response id : %u", response_id); // g_signal_connect (GTK_BUTTON (currentCheckButton), "clicked", // G_CALLBACK (use_current_incoming_address), NULL); gtk_dialog_add_action_widget (dialog, GTK_WIDGET(nameEntry), 2); gtk_dialog_add_action_widget (dialog, GTK_WIDGET(addressEntry), 3); content_area = GTK_CONTAINER(gtk_dialog_get_content_area (GTK_DIALOG (dialog))); notification = GTK_LABEL(gtk_label_new ("Adding contact")); // caller_name = gtk_label_new (caller_id); // Add the labels, and show everything we've added to the dialog gtk_container_add (GTK_CONTAINER (content_area), GTK_WIDGET(notification)); // gtk_container_add (GTK_CONTAINER (content_area), caller_name); gtk_widget_show_all (GTK_WIDGET(dialog)); switch (gtk_dialog_run (dialog)) { case GTK_RESPONSE_ACCEPT: do_status (""); add_contact (gtk_entry_get_text (nameEntry), gtk_entry_get_text (addressEntry)); gtk_widget_destroy (GTK_WIDGET(dialog)); break; case GTK_RESPONSE_CANCEL: FPRINTF (stderr, "cancel clicked"); do_status (""); gtk_widget_destroy (GTK_WIDGET(dialog)); break; case GTK_RESPONSE_OK: //use_current_incoming_address(); gtk_entry_set_text (GTK_ENTRY(addressEntry), callerName); add_contact (gtk_entry_get_text (nameEntry), callerName); // add_contact(gtk_entry_get_text(nameEntry),memmove(&callerName,&callerName+52,1)); gtk_widget_destroy (GTK_WIDGET(dialog)); // memmove(&address+1,&address+51,1); break; } } void GNUNET_CONVERSATION_GTK_on_remove_clicked (GtkButton * button, gpointer * user_data) { GtkTreeSelection *selection; GtkTreeModel *model; GtkTreeIter iter; GtkDialog *confirm; GtkWindow *main_window; GtkLabel *notification; GtkHBox *content_area; selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(contacts_treeview)); if (gtk_tree_selection_get_selected(selection, &model, &iter)) { gtk_tree_model_get (model, &iter, 0, &name, -1); FPRINTF(stderr, "selected %s \n", name); main_window = GTK_WINDOW(get_object ("GNUNET_GTK_conversation_window")); confirm = GTK_DIALOG(gtk_dialog_new_with_buttons ("Removing contact", main_window, GTK_DIALOG_DESTROY_WITH_PARENT, _("Yes"), GTK_RESPONSE_ACCEPT, _("No"), GTK_RESPONSE_CANCEL, NULL)); content_area = GTK_CONTAINER(gtk_dialog_get_content_area (GTK_DIALOG (confirm))); notification = GTK_LABEL(gtk_label_new ("Do you really want to remove this contact?")); gtk_container_add (GTK_CONTAINER (content_area), GTK_WIDGET(notification)); gtk_widget_show_all (GTK_WIDGET(confirm)); switch (gtk_dialog_run(confirm)) { case GTK_RESPONSE_ACCEPT: zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (caller_id); del_qe = GNUNET_NAMESTORE_records_store (ns, &zone_pkey, name, 0, NULL, &del_continuation, NULL); gtk_list_store_remove(contacts_liststore, &iter); gtk_widget_destroy (GTK_WIDGET(confirm)); break; case GTK_RESPONSE_CANCEL: FPRINTF(stderr, "not removing \n"); gtk_widget_destroy (GTK_WIDGET(confirm)); break; } } } /* * row activated * @return void */ void GNUNET_CONVERSATION_GTK_row_activated () { gchar *callAddress; gchar *type; FPRINTF (stderr, "row activated \n"); GtkTreeSelection *selection; GtkTreeIter iterA; selection = gtk_tree_view_get_selection (contacts_treeview); gtk_tree_selection_get_selected (selection, &contacts_treemodel, &iterA); gtk_tree_model_get (contacts_treemodel, &iterA, 0, &name, 1, &type, -1); g_print ("ego name %s\n", ego_name); g_print ("selected row is: %s\n", name); g_print ("selected rowtype is: %s\n", type); g_print ("type @row active%s", type); if (strcmp (type, "PKEY") == 0) { GNUNET_asprintf (&callAddress, "call\.%s\.gnu", name); } if (strcmp (type, "PHONE") == 0) { GNUNET_asprintf (&callAddress, "%s\.gnu", name); } // else { GNUNET_asprintf(&callAddress, "%s", peer_id);} g_print ("ego name %s\n", callAddress); GtkEntry *address_entry; address_entry = GTK_ENTRY ((get_object ("GNUNET_GTK_conversation_address"))); gtk_entry_set_text (address_entry, callAddress); do_call (callAddress); } /* end of gnunet-conversation-gtk.c */ void GNUNET_contact_test() { history_add(0,"test"); history_add(1,"test"); history_add(2,"test"); history_add(3,"test"); history_add(4,"test"); }