Detecting when phone calls terminate
This commit is contained in:
parent
2666b2fa59
commit
7568bb814e
@ -87,6 +87,15 @@ void on_phone_call_answer(gpointer data)
|
||||
}
|
||||
|
||||
|
||||
/* on_phone_call_close */
|
||||
void on_phone_call_close(gpointer data)
|
||||
{
|
||||
Phone * phone = data;
|
||||
|
||||
phone_show_call(phone, FALSE);
|
||||
}
|
||||
|
||||
|
||||
/* on_phone_call_hangup */
|
||||
void on_phone_call_hangup(gpointer data)
|
||||
{
|
||||
|
@ -28,6 +28,7 @@ GdkFilterReturn on_phone_filter(GdkXEvent * xevent, GdkEvent * event,
|
||||
|
||||
/* calls */
|
||||
void on_phone_call_answer(gpointer data);
|
||||
void on_phone_call_close(gpointer data);
|
||||
void on_phone_call_hangup(gpointer data);
|
||||
void on_phone_call_reject(gpointer data);
|
||||
|
||||
|
108
src/gsm.c
108
src/gsm.c
@ -79,9 +79,6 @@ struct _GSM
|
||||
|
||||
|
||||
/* variables */
|
||||
/* ANSWERS */
|
||||
static char const * _gsm_errors[] = { "ERROR", "NO CARRIER", NULL };
|
||||
|
||||
/* CME ERROR */
|
||||
static struct
|
||||
{
|
||||
@ -162,6 +159,8 @@ static void _gsm_queue_pop(GSM * gsm);
|
||||
static int _gsm_queue_push(GSM * gsm);
|
||||
|
||||
/* triggers */
|
||||
static int _gsm_trigger_busy(GSM * gsm, char const * result,
|
||||
gboolean * answered);
|
||||
static int _gsm_trigger_cfun(GSM * gsm, char const * result);
|
||||
static int _gsm_trigger_cgmm(GSM * gsm, char const * result);
|
||||
static int _gsm_trigger_cme_error(GSM * gsm, char const * result,
|
||||
@ -169,12 +168,20 @@ static int _gsm_trigger_cme_error(GSM * gsm, char const * result,
|
||||
static int _gsm_trigger_cms_error(GSM * gsm, char const * result);
|
||||
static int _gsm_trigger_cmgl(GSM * gsm, char const * result);
|
||||
static int _gsm_trigger_cmgs(GSM * gsm, char const * result);
|
||||
static int _gsm_trigger_connect(GSM * gsm, char const * result,
|
||||
gboolean * answered);
|
||||
static int _gsm_trigger_cops(GSM * gsm, char const * result);
|
||||
static int _gsm_trigger_cpbr(GSM * gsm, char const * result);
|
||||
static int _gsm_trigger_cpin(GSM * gsm, char const * result);
|
||||
static int _gsm_trigger_creg(GSM * gsm, char const * result);
|
||||
static int _gsm_trigger_cring(GSM * gsm, char const * result);
|
||||
static int _gsm_trigger_csq(GSM * gsm, char const * result);
|
||||
static int _gsm_trigger_no_answer(GSM * gsm, char const * result,
|
||||
gboolean * answered);
|
||||
static int _gsm_trigger_no_carrier(GSM * gsm, char const * result,
|
||||
gboolean * answered);
|
||||
static int _gsm_trigger_no_dialtone(GSM * gsm, char const * result,
|
||||
gboolean * answered);
|
||||
|
||||
/* triggers */
|
||||
static GSMTrigger _gsm_triggers[] =
|
||||
@ -182,18 +189,23 @@ static GSMTrigger _gsm_triggers[] =
|
||||
#define GSM_TRIGGER(trigger, callback) \
|
||||
{ trigger, sizeof(trigger) - 1, \
|
||||
(GSMTriggerCallback)_gsm_trigger_ ## callback }
|
||||
GSM_TRIGGER("BUSY", busy),
|
||||
GSM_TRIGGER("+CFUN: ", cfun),
|
||||
GSM_TRIGGER("+CGMM: ", cgmm),
|
||||
GSM_TRIGGER("+CME ERROR: ", cme_error),
|
||||
GSM_TRIGGER("+CMS ERROR: ", cms_error),
|
||||
GSM_TRIGGER("+CMGL: ", cmgl),
|
||||
GSM_TRIGGER("+CMGS: ", cmgs),
|
||||
GSM_TRIGGER("CONNECT", connect),
|
||||
GSM_TRIGGER("+COPS: ", cops),
|
||||
GSM_TRIGGER("+CPBR: ", cpbr),
|
||||
GSM_TRIGGER("+CPIN: ", cpin),
|
||||
GSM_TRIGGER("+CREG: ", creg),
|
||||
GSM_TRIGGER("+CRING: ", cring),
|
||||
GSM_TRIGGER("+CSQ: ", csq),
|
||||
GSM_TRIGGER("NO ANSWER", no_answer),
|
||||
GSM_TRIGGER("NO CARRIER", no_carrier),
|
||||
GSM_TRIGGER("NO DIALTONE", no_dialtone),
|
||||
{ NULL, 0, NULL }
|
||||
};
|
||||
|
||||
@ -845,23 +857,21 @@ static int _gsm_parse_line(GSM * gsm, char const * line, gboolean * answered)
|
||||
callback(gsm);
|
||||
return 0;
|
||||
}
|
||||
for(i = 0; _gsm_errors[i] != NULL; i++)
|
||||
{
|
||||
if(strcmp(_gsm_errors[i], line) != 0)
|
||||
continue;
|
||||
if(answered != NULL)
|
||||
*answered = TRUE;
|
||||
if(gsmc != NULL)
|
||||
error = gsm_command_get_error(gsmc);
|
||||
gsm_event(gsm, GSM_EVENT_TYPE_ERROR, error, line);
|
||||
return 0;
|
||||
}
|
||||
for(i = 0; _gsm_triggers[i].trigger != NULL; i++)
|
||||
if(strncmp(line, _gsm_triggers[i].trigger,
|
||||
_gsm_triggers[i].trigger_cnt) == 0)
|
||||
return _gsm_triggers[i].callback(gsm,
|
||||
&line[_gsm_triggers[i].trigger_cnt],
|
||||
answered);
|
||||
if(strcmp(line, "ERROR") == 0)
|
||||
{
|
||||
if(answered != NULL)
|
||||
*answered = TRUE;
|
||||
if(gsmc != NULL)
|
||||
error = gsm_command_get_error(gsmc);
|
||||
gsm_event(gsm, GSM_EVENT_TYPE_ERROR, error, _("Unknown error"));
|
||||
return 0;
|
||||
}
|
||||
/* XXX look for a potential trigger */
|
||||
if(gsmc != NULL && (cmd = gsm_command_get_command(gsmc)) != NULL
|
||||
&& strncmp(cmd, "AT+", 3) == 0 && isupper((c = cmd[3])))
|
||||
@ -966,6 +976,19 @@ static int _gsm_queue_push(GSM * gsm)
|
||||
|
||||
|
||||
/* triggers */
|
||||
/* gsm_trigger_busy */
|
||||
static int _gsm_trigger_busy(GSM * gsm, char const * result,
|
||||
gboolean * answered)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, result);
|
||||
#endif
|
||||
if(answered != NULL)
|
||||
*answered = TRUE;
|
||||
return gsm_event(gsm, GSM_EVENT_TYPE_ERROR, GSM_ERROR_BUSY, "BUSY");
|
||||
}
|
||||
|
||||
|
||||
/* gsm_trigger_cfun */
|
||||
static int _gsm_trigger_cfun(GSM * gsm, char const * result)
|
||||
{
|
||||
@ -1081,6 +1104,21 @@ static int _gsm_trigger_cmgs(GSM * gsm, char const * result)
|
||||
}
|
||||
|
||||
|
||||
/* gsm_trigger_connect */
|
||||
static int _gsm_trigger_connect(GSM * gsm, char const * result,
|
||||
gboolean * answered)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, result);
|
||||
#endif
|
||||
if(answered != NULL)
|
||||
*answered = TRUE;
|
||||
/* FIXME implement pass-through */
|
||||
/* FIXME reset is probably not enough (send "+++"?) */
|
||||
return gsm_reset(gsm, gsm->retry);
|
||||
}
|
||||
|
||||
|
||||
/* gsm_trigger_cops */
|
||||
static int _gsm_trigger_cops(GSM * gsm, char const * result)
|
||||
{
|
||||
@ -1234,6 +1272,48 @@ static int _gsm_trigger_csq(GSM * gsm, char const * result)
|
||||
}
|
||||
|
||||
|
||||
/* gsm_trigger_no_answer */
|
||||
static int _gsm_trigger_no_answer(GSM * gsm, char const * result,
|
||||
gboolean * answered)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, result);
|
||||
#endif
|
||||
if(answered != NULL)
|
||||
*answered = TRUE;
|
||||
return gsm_event(gsm, GSM_EVENT_TYPE_ERROR, GSM_ERROR_NO_ANSWER,
|
||||
"NO ANSWER");
|
||||
}
|
||||
|
||||
|
||||
/* gsm_trigger_no_carrier */
|
||||
static int _gsm_trigger_no_carrier(GSM * gsm, char const * result,
|
||||
gboolean * answered)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, result);
|
||||
#endif
|
||||
if(answered != NULL)
|
||||
*answered = TRUE;
|
||||
return gsm_event(gsm, GSM_EVENT_TYPE_ERROR, GSM_ERROR_NO_CARRIER,
|
||||
"NO CARRIER");
|
||||
}
|
||||
|
||||
|
||||
/* gsm_trigger_no_dialtone */
|
||||
static int _gsm_trigger_no_dialtone(GSM * gsm, char const * result,
|
||||
gboolean * answered)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, result);
|
||||
#endif
|
||||
if(answered != NULL)
|
||||
*answered = TRUE;
|
||||
return gsm_event(gsm, GSM_EVENT_TYPE_ERROR, GSM_ERROR_NO_DIALTONE,
|
||||
"NO DIALTONE");
|
||||
}
|
||||
|
||||
|
||||
/* callbacks */
|
||||
/* on_reset */
|
||||
static int _reset_do(GSM * gsm, int fd);
|
||||
|
@ -55,6 +55,7 @@ typedef enum _GSMError
|
||||
{
|
||||
GSM_ERROR_UNKNOWN = 0,
|
||||
GSM_ERROR_ANSWER_FAILED,
|
||||
GSM_ERROR_BUSY,
|
||||
GSM_ERROR_CALL_FAILED,
|
||||
GSM_ERROR_CONTACT_FETCH_FAILED,
|
||||
GSM_ERROR_CONTACT_LIST_FAILED,
|
||||
@ -63,6 +64,9 @@ typedef enum _GSMError
|
||||
GSM_ERROR_MESSAGE_FETCH_FAILED,
|
||||
GSM_ERROR_MESSAGE_LIST_FAILED,
|
||||
GSM_ERROR_MESSAGE_SEND_FAILED,
|
||||
GSM_ERROR_NO_ANSWER,
|
||||
GSM_ERROR_NO_CARRIER,
|
||||
GSM_ERROR_NO_DIALTONE,
|
||||
GSM_ERROR_OPERATOR_MODE_FAILED,
|
||||
GSM_ERROR_SIGNAL_LEVEL_FAILED,
|
||||
GSM_ERROR_RESET_FAILED,
|
||||
|
56
src/phone.c
56
src/phone.c
@ -77,8 +77,10 @@ struct _Phone
|
||||
GtkWidget * ca_hangup;
|
||||
GtkWidget * ca_image;
|
||||
GtkWidget * ca_reject;
|
||||
GtkWidget * ca_close;
|
||||
GtkWidget * ca_volume;
|
||||
GtkWidget * ca_speaker;
|
||||
GtkWidget * ca_mute;
|
||||
|
||||
/* code */
|
||||
PhoneCode en_code;
|
||||
@ -505,25 +507,35 @@ void phone_show_call(Phone * phone, gboolean show, ...)
|
||||
vbox = gtk_vbox_new(FALSE, 4);
|
||||
gtk_container_set_border_width(GTK_CONTAINER(vbox), 4);
|
||||
/* buttons */
|
||||
/* answer */
|
||||
phone->ca_answer = _phone_create_button("call-start",
|
||||
_("Answer"));
|
||||
g_signal_connect_swapped(G_OBJECT(phone->ca_answer), "clicked",
|
||||
G_CALLBACK(on_phone_call_answer), phone);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), phone->ca_answer, FALSE, TRUE,
|
||||
0);
|
||||
/* hangup */
|
||||
phone->ca_hangup = _phone_create_button("call-stop",
|
||||
_("Hangup"));
|
||||
g_signal_connect_swapped(G_OBJECT(phone->ca_hangup), "clicked",
|
||||
G_CALLBACK(on_phone_call_hangup), phone);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), phone->ca_hangup, FALSE, TRUE,
|
||||
0);
|
||||
/* reject */
|
||||
phone->ca_reject = _phone_create_button("call-stop",
|
||||
_("Reject"));
|
||||
g_signal_connect_swapped(G_OBJECT(phone->ca_reject), "clicked",
|
||||
G_CALLBACK(on_phone_call_reject), phone);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), phone->ca_reject, FALSE, TRUE,
|
||||
0);
|
||||
/* close */
|
||||
phone->ca_close = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
|
||||
g_signal_connect_swapped(G_OBJECT(phone->ca_close), "clicked",
|
||||
G_CALLBACK(on_phone_call_close), phone);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), phone->ca_close, FALSE, TRUE,
|
||||
0);
|
||||
hbox = gtk_hbox_new(FALSE, 0);
|
||||
/* volume bar */
|
||||
phone->ca_image = gtk_image_new_from_icon_name(
|
||||
"audio-volume-muted", GTK_ICON_SIZE_BUTTON);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), phone->ca_image, FALSE, TRUE,
|
||||
@ -532,18 +544,26 @@ void phone_show_call(Phone * phone, gboolean show, ...)
|
||||
gtk_box_pack_start(GTK_BOX(hbox), phone->ca_volume, TRUE, TRUE,
|
||||
0);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
|
||||
/* speaker mode */
|
||||
phone->ca_speaker = gtk_toggle_button_new_with_label(
|
||||
_("Loudspeaker"));
|
||||
gtk_button_set_image(GTK_BUTTON(phone->ca_speaker),
|
||||
gtk_image_new_from_icon_name("stock_volume",
|
||||
gtk_image_new_from_icon_name("stock_volume-max",
|
||||
GTK_ICON_SIZE_BUTTON));
|
||||
gtk_box_pack_start(GTK_BOX(vbox), phone->ca_speaker, FALSE,
|
||||
TRUE, 0);
|
||||
/* mute microphone */
|
||||
phone->ca_mute = gtk_toggle_button_new_with_label(
|
||||
_("Mute microphone"));
|
||||
gtk_button_set_image(GTK_BUTTON(phone->ca_mute),
|
||||
gtk_image_new_from_icon_name(
|
||||
"audio-input-microphone",
|
||||
GTK_ICON_SIZE_BUTTON));
|
||||
gtk_box_pack_start(GTK_BOX(vbox), phone->ca_mute, FALSE,
|
||||
TRUE, 0);
|
||||
gtk_container_add(GTK_CONTAINER(phone->ca_window), vbox);
|
||||
}
|
||||
phone_show_dialer(phone, FALSE);
|
||||
gtk_window_set_transient_for(GTK_WINDOW(phone->ca_window), GTK_WINDOW(
|
||||
phone->di_window));
|
||||
gtk_widget_show_all(phone->ca_window);
|
||||
switch(call)
|
||||
{
|
||||
@ -552,17 +572,27 @@ void phone_show_call(Phone * phone, gboolean show, ...)
|
||||
_("In conversation"));
|
||||
gtk_widget_hide(phone->ca_answer);
|
||||
gtk_widget_hide(phone->ca_reject);
|
||||
gtk_widget_hide(phone->ca_close);
|
||||
break;
|
||||
case PHONE_CALL_INCOMING:
|
||||
gtk_window_set_title(GTK_WINDOW(phone->ca_window),
|
||||
_("Incoming call"));
|
||||
gtk_widget_hide(phone->ca_hangup);
|
||||
gtk_widget_hide(phone->ca_close);
|
||||
break;
|
||||
case PHONE_CALL_OUTGOING:
|
||||
gtk_window_set_title(GTK_WINDOW(phone->ca_window),
|
||||
_("Outgoing call"));
|
||||
gtk_widget_hide(phone->ca_answer);
|
||||
gtk_widget_hide(phone->ca_reject);
|
||||
gtk_widget_hide(phone->ca_close);
|
||||
break;
|
||||
case PHONE_CALL_TERMINATED:
|
||||
gtk_window_set_title(GTK_WINDOW(phone->ca_window),
|
||||
_("Call finished"));
|
||||
gtk_widget_hide(phone->ca_answer);
|
||||
gtk_widget_hide(phone->ca_hangup);
|
||||
gtk_widget_hide(phone->ca_reject);
|
||||
break;
|
||||
}
|
||||
gtk_window_present(GTK_WINDOW(phone->ca_window));
|
||||
@ -1413,13 +1443,13 @@ static int _gsm_event_error(Phone * phone, GSMEvent * event)
|
||||
{
|
||||
switch(event->error.error)
|
||||
{
|
||||
case GSM_ERROR_SIM_PIN_REQUIRED:
|
||||
phone_code_clear(phone);
|
||||
phone_show_code(phone, TRUE, PHONE_CODE_SIM_PIN);
|
||||
case GSM_ERROR_BUSY:
|
||||
case GSM_ERROR_NO_ANSWER:
|
||||
case GSM_ERROR_NO_DIALTONE:
|
||||
_phone_error(phone->ca_window, event->error.message);
|
||||
break;
|
||||
case GSM_ERROR_SIM_PIN_WRONG:
|
||||
phone_code_clear(phone);
|
||||
_phone_error(phone->en_window, _("Wrong SIM PIN code"));
|
||||
case GSM_ERROR_NO_CARRIER:
|
||||
phone_show_call(phone, TRUE, PHONE_CALL_TERMINATED);
|
||||
break;
|
||||
case GSM_ERROR_CONTACT_FETCH_FAILED:
|
||||
case GSM_ERROR_MESSAGE_FETCH_FAILED:
|
||||
@ -1440,6 +1470,14 @@ static int _gsm_event_error(Phone * phone, GSMEvent * event)
|
||||
_phone_error(phone->wr_window,
|
||||
_("Could not send message"));
|
||||
break;
|
||||
case GSM_ERROR_SIM_PIN_REQUIRED:
|
||||
phone_code_clear(phone);
|
||||
phone_show_code(phone, TRUE, PHONE_CODE_SIM_PIN);
|
||||
break;
|
||||
case GSM_ERROR_SIM_PIN_WRONG:
|
||||
phone_code_clear(phone);
|
||||
_phone_error(phone->en_window, _("Wrong SIM PIN code"));
|
||||
break;
|
||||
default:
|
||||
phone_error(phone, event->error.message, 0);
|
||||
break;
|
||||
|
@ -29,7 +29,8 @@ typedef enum _PhoneCall
|
||||
{
|
||||
PHONE_CALL_ESTABLISHED = 0,
|
||||
PHONE_CALL_INCOMING,
|
||||
PHONE_CALL_OUTGOING
|
||||
PHONE_CALL_OUTGOING,
|
||||
PHONE_CALL_TERMINATED
|
||||
} PhoneCall;
|
||||
|
||||
typedef enum _PhoneCode
|
||||
|
Loading…
Reference in New Issue
Block a user