Blame baresip-1.1.0-call-history.patch

9e2a230
From 68fd6b29d34380f74ea69b32cf055639ae2b7a35 Mon Sep 17 00:00:00 2001
9e2a230
From: mbattista <m0battista@gmail.com>
9e2a230
Date: Sat, 24 Apr 2021 09:18:38 +0200
9e2a230
Subject: [PATCH] GTK caller history (#1350)
9e2a230
9e2a230
* caller history
9e2a230
9e2a230
* other icons
9e2a230
9e2a230
* rejected and []
9e2a230
9e2a230
* limit caller history
9e2a230
9e2a230
* fix ccheck
9e2a230
9e2a230
* take better icons if available
9e2a230
9e2a230
* symbolic icons suffix
9e2a230
9e2a230
* check against theme if icons exists
9e2a230
9e2a230
* symbolic for status icon
9e2a230
9e2a230
* dialog-close is not in all icons
9e2a230
9e2a230
* fixing crash when calling same person multiple times
9e2a230
9e2a230
* check against null safty
9e2a230
9e2a230
Co-authored-by: Marcel Battista <marcel.battista@etes.de>
9e2a230
---
9e2a230
 modules/gtk/gtk_mod.c | 135 ++++++++++++++++++++++++++++++++++++++++++
9e2a230
 modules/gtk/gtk_mod.h |   5 ++
9e2a230
 2 files changed, 140 insertions(+)
9e2a230
9e2a230
diff --git a/modules/gtk/gtk_mod.c b/modules/gtk/gtk_mod.c
9e2a230
index afbbc3806..55a806620 100644
9e2a230
--- a/modules/gtk/gtk_mod.c
9e2a230
+++ b/modules/gtk/gtk_mod.c
9e2a230
@@ -6,6 +6,7 @@
9e2a230
  */
9e2a230
 #include <re.h>
9e2a230
 #include <rem.h>
9e2a230
+#include <time.h>
9e2a230
 #include <baresip.h>
9e2a230
 #include <stdlib.h>
9e2a230
 #include <pthread.h>
9e2a230
@@ -43,11 +44,13 @@ struct gtk_mod {
9e2a230
 	bool run;
9e2a230
 	bool contacts_inited;
9e2a230
 	struct mqueue *mq;
9e2a230
+	int call_history_length;
9e2a230
 	GApplication *app;
9e2a230
 	GtkStatusIcon *status_icon;
9e2a230
 	GtkWidget *app_menu;
9e2a230
 	GtkWidget *contacts_menu;
9e2a230
 	GtkWidget *accounts_menu;
9e2a230
+	GtkWidget *history_menu;
9e2a230
 	GtkWidget *status_menu;
9e2a230
 	GSList *accounts_menu_group;
9e2a230
 	struct dial_dialog *dial_dialog;
9e2a230
@@ -55,6 +58,9 @@ struct gtk_mod {
9e2a230
 	GSList *incoming_call_menus;
9e2a230
 	bool clean_number;
9e2a230
 	struct ua *ua_cur;
9e2a230
+	bool icon_call_missed;
9e2a230
+	bool icon_call_outgoing;
9e2a230
+	bool icon_call_incoming;
9e2a230
 };
9e2a230
 
9e2a230
 static struct gtk_mod mod_obj;
9e2a230
@@ -150,6 +156,25 @@ static void menu_on_dial_contact(GtkMenuItem *menuItem, gpointer arg)
9e2a230
 	gtk_mod_connect(mod, uri);
9e2a230
 }
9e2a230
 
9e2a230
+static void menu_on_dial_history(GtkMenuItem *menuItem, gpointer arg)
9e2a230
+{
9e2a230
+	struct gtk_mod *mod = arg;
9e2a230
+	const char *label = gtk_menu_item_get_label(menuItem);
9e2a230
+	char *label_1;
9e2a230
+	char buf[256];
9e2a230
+	char *uri;
9e2a230
+
9e2a230
+	str_ncpy(buf, label, sizeof(buf));
9e2a230
+	label_1 = strchr(buf, '[');
9e2a230
+	if (!label_1)
9e2a230
+		return;
9e2a230
+
9e2a230
+	label_1[0] = ' ';
9e2a230
+
9e2a230
+	uri = strtok(label_1, "]");
9e2a230
+	gtk_mod_connect(mod, uri);
9e2a230
+}
9e2a230
+
9e2a230
 
9e2a230
 static void init_contacts_menu(struct gtk_mod *mod)
9e2a230
 {
9e2a230
@@ -170,6 +195,78 @@ static void init_contacts_menu(struct gtk_mod *mod)
9e2a230
 }
9e2a230
 
9e2a230
 
9e2a230
+static void add_history_menu_item(struct gtk_mod *mod, const char *uri,
9e2a230
+					int call_type, const char *info)
9e2a230
+{
9e2a230
+	GtkWidget *item, *history_item;
9e2a230
+	GtkMenuShell *history_menu = GTK_MENU_SHELL(mod->history_menu);
9e2a230
+	char buf[256];
9e2a230
+	time_t rawtime = time(NULL);
9e2a230
+	struct tm *ptm = localtime(&rawtime);
9e2a230
+	GList *list;
9e2a230
+
9e2a230
+	if (mod->call_history_length < 20) {
9e2a230
+		mod->call_history_length++;
9e2a230
+	}
9e2a230
+	else {
9e2a230
+		/* Remove old call history */
9e2a230
+		list = gtk_container_get_children(GTK_CONTAINER(history_menu));
9e2a230
+		history_item = GTK_WIDGET(list->data);
9e2a230
+		gtk_widget_destroy(history_item);
9e2a230
+
9e2a230
+	}
9e2a230
+
9e2a230
+	re_snprintf(buf, sizeof buf,
9e2a230
+			"%s [%s]\n%04d-%02d-%02d %02d:%02d:%02d",
9e2a230
+			info, uri, ptm->tm_year + 1900, ptm->tm_mon + 1,
9e2a230
+			ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
9e2a230
+
9e2a230
+	item = gtk_image_menu_item_new_with_label(buf);
9e2a230
+	switch (call_type) {
9e2a230
+		case CALL_INCOMING:
9e2a230
+			gtk_image_menu_item_set_image(
9e2a230
+				GTK_IMAGE_MENU_ITEM(item),
9e2a230
+				gtk_image_new_from_icon_name(
9e2a230
+                                        (mod->icon_call_incoming) ?
9e2a230
+					"call-incoming-symbolic" : "go-next",
9e2a230
+					GTK_ICON_SIZE_MENU));
9e2a230
+			break;
9e2a230
+		case CALL_OUTGOING:
9e2a230
+			gtk_image_menu_item_set_image(
9e2a230
+				GTK_IMAGE_MENU_ITEM(item),
9e2a230
+				gtk_image_new_from_icon_name(
9e2a230
+					(mod->icon_call_outgoing) ?
9e2a230
+					"call-outgoing-symbolic"
9e2a230
+						 : "go-previous",
9e2a230
+				GTK_ICON_SIZE_MENU));
9e2a230
+			break;
9e2a230
+		case CALL_MISSED:
9e2a230
+			gtk_image_menu_item_set_image(
9e2a230
+				GTK_IMAGE_MENU_ITEM(item),
9e2a230
+				gtk_image_new_from_icon_name(
9e2a230
+					(mod->icon_call_missed) ?
9e2a230
+					"call-missed-symbolic" : "call-stop",
9e2a230
+					GTK_ICON_SIZE_MENU));
9e2a230
+			break;
9e2a230
+		case CALL_REJECTED:
9e2a230
+			gtk_image_menu_item_set_image(
9e2a230
+				GTK_IMAGE_MENU_ITEM(item),
9e2a230
+				gtk_image_new_from_icon_name(
9e2a230
+					"window-close", GTK_ICON_SIZE_MENU));
9e2a230
+			break;
9e2a230
+		default:
9e2a230
+			gtk_image_menu_item_set_image(
9e2a230
+				GTK_IMAGE_MENU_ITEM(item),
9e2a230
+				gtk_image_new_from_icon_name(
9e2a230
+					"call-start", GTK_ICON_SIZE_MENU));
9e2a230
+			break;
9e2a230
+	}
9e2a230
+	gtk_menu_shell_append(history_menu, item);
9e2a230
+	g_signal_connect(G_OBJECT(item), "activate",
9e2a230
+		G_CALLBACK(menu_on_dial_history), mod);
9e2a230
+}
9e2a230
+
9e2a230
+
9e2a230
 static void menu_on_account_toggled(GtkCheckMenuItem *menu_item,
9e2a230
 				    struct gtk_mod *mod)
9e2a230
 {
9e2a230
@@ -207,6 +304,8 @@ static void menu_on_incoming_call_reject(GtkMenuItem *menuItem,
9e2a230
 		struct gtk_mod *mod)
9e2a230
 {
9e2a230
 	struct call *call = g_object_get_data(G_OBJECT(menuItem), "call");
9e2a230
+	add_history_menu_item(mod,call_peeruri(call), CALL_REJECTED,
9e2a230
+						call_peername(call));
9e2a230
 	denotify_incoming_call(mod, call);
9e2a230
 	mqueue_push(mod->mq, MQ_HANGUP, call);
9e2a230
 }
9e2a230
@@ -448,6 +547,8 @@ static void reject_activated(GSimpleAction *action, GVariant *parameter,
9e2a230
 
9e2a230
 	if (call) {
9e2a230
 		denotify_incoming_call(mod, call);
9e2a230
+		add_history_menu_item(mod,call_peeruri(call), CALL_REJECTED,
9e2a230
+					call_peername(call));
9e2a230
 		mqueue_push(mod->mq, MQ_HANGUP, call);
9e2a230
 	}
9e2a230
 }
9e2a230
@@ -530,6 +631,18 @@ static void ua_event_handler(struct ua *ua,
9e2a230
 		if (win)
9e2a230
 			call_window_closed(win, prm);
9e2a230
 		denotify_incoming_call(mod, call);
9e2a230
+		if (!call_is_outgoing(call)
9e2a230
+			&& call_state(call) != CALL_STATE_TERMINATED
9e2a230
+			&& call_state(call) != CALL_STATE_ESTABLISHED) {
9e2a230
+			add_history_menu_item(mod,
9e2a230
+				call_peeruri(call),
9e2a230
+				CALL_MISSED, call_peername(call));
9e2a230
+
9e2a230
+			gtk_status_icon_set_from_icon_name(
9e2a230
+				mod->status_icon,
9e2a230
+				(mod->icon_call_missed) ?
9e2a230
+					"call-missed-symbolic" : "call-stop");
9e2a230
+		}
9e2a230
 		break;
9e2a230
 
9e2a230
 	case UA_EVENT_CALL_RINGING:
9e2a230
@@ -637,6 +750,7 @@ static gboolean status_icon_on_button_press(GtkStatusIcon *status_icon,
9e2a230
 {
9e2a230
 	popup_menu(mod, gtk_status_icon_position_menu, status_icon,
9e2a230
 			event->button, event->time);
9e2a230
+	gtk_status_icon_set_from_icon_name(status_icon, "call-start");
9e2a230
 	return TRUE;
9e2a230
 }
9e2a230
 
9e2a230
@@ -719,6 +833,7 @@ static void mqueue_handler(int id, void *data, void *arg)
9e2a230
 	case MQ_CONNECT:
9e2a230
 		uri = data;
9e2a230
 		err = ua_connect(ua, &call, NULL, uri, VIDMODE_ON);
9e2a230
+		add_history_menu_item(mod, uri, CALL_OUTGOING, "");
9e2a230
 		if (err) {
9e2a230
 			gdk_threads_enter();
9e2a230
 			warning_dialog("Call failed",
9e2a230
@@ -748,6 +863,8 @@ static void mqueue_handler(int id, void *data, void *arg)
9e2a230
 	case MQ_ANSWER:
9e2a230
 		call = data;
9e2a230
 		err = ua_answer(ua, call, VIDMODE_ON);
9e2a230
+		add_history_menu_item(mod, call_peeruri(call),
9e2a230
+				CALL_INCOMING, call_peername(call));
9e2a230
 		if (err) {
9e2a230
 			gdk_threads_enter();
9e2a230
 			warning_dialog("Call failed",
9e2a230
@@ -782,6 +899,8 @@ static void *gtk_thread(void *arg)
9e2a230
 	GtkWidget *item;
9e2a230
 	GError *err = NULL;
9e2a230
 	struct le *le;
9e2a230
+	GtkIconTheme *theme;
9e2a230
+
9e2a230
 
9e2a230
 	gdk_threads_init();
9e2a230
 	gtk_init(0, NULL);
9e2a230
@@ -814,6 +933,7 @@ static void *gtk_thread(void *arg)
9e2a230
 	mod->dial_dialog = NULL;
9e2a230
 	mod->call_windows = NULL;
9e2a230
 	mod->incoming_call_menus = NULL;
9e2a230
+	mod->call_history_length = 0;
9e2a230
 
9e2a230
 	/* App menu */
9e2a230
 	mod->app_menu = gtk_menu_new();
9e2a230
@@ -872,8 +992,23 @@ static void *gtk_thread(void *arg)
9e2a230
 	gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),
9e2a230
 			mod->contacts_menu);
9e2a230
 
9e2a230
+	/* Caller history */
9e2a230
+	mod->history_menu = gtk_menu_new();
9e2a230
+	item = gtk_menu_item_new_with_mnemonic("Call _history");
9e2a230
+	gtk_menu_shell_append(app_menu, item);
9e2a230
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(item),
9e2a230
+			mod->history_menu);
9e2a230
+
9e2a230
 	gtk_menu_shell_append(app_menu, gtk_separator_menu_item_new());
9e2a230
 
9e2a230
+	theme = gtk_icon_theme_get_default();
9e2a230
+	mod->icon_call_incoming = gtk_icon_theme_has_icon(theme,
9e2a230
+						"call-incoming-symbolic");
9e2a230
+	mod->icon_call_outgoing = gtk_icon_theme_has_icon(theme,
9e2a230
+						"call-outgoing-symbolic");
9e2a230
+	mod->icon_call_missed = gtk_icon_theme_has_icon(theme,
9e2a230
+						"call-missed-symbolic");
9e2a230
+
9e2a230
 	/* About */
9e2a230
 	item = gtk_menu_item_new_with_mnemonic("A_bout");
9e2a230
 	g_signal_connect(G_OBJECT(item), "activate",
9e2a230
diff --git a/modules/gtk/gtk_mod.h b/modules/gtk/gtk_mod.h
9e2a230
index 50f6a9a98..2f3bfb4f4 100644
9e2a230
--- a/modules/gtk/gtk_mod.h
9e2a230
+++ b/modules/gtk/gtk_mod.h
9e2a230
@@ -4,6 +4,11 @@
9e2a230
  * Copyright (C) 2015 Charles E. Lehner
9e2a230
  */
9e2a230
 
9e2a230
+#define CALL_INCOMING  0
9e2a230
+#define CALL_OUTGOING  1
9e2a230
+#define CALL_MISSED    2
9e2a230
+#define CALL_REJECTED  3
9e2a230
+
9e2a230
 struct gtk_mod;
9e2a230
 struct call_window;
9e2a230
 struct dial_dialog;