diff --git a/src/callbacks.c b/src/callbacks.c index fe1f66d..d6dbb45 100644 --- a/src/callbacks.c +++ b/src/callbacks.c @@ -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) { diff --git a/src/callbacks.h b/src/callbacks.h index 87b05f4..29e2cee 100644 --- a/src/callbacks.h +++ b/src/callbacks.h @@ -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); diff --git a/src/gsm.c b/src/gsm.c index 7a6c59d..2c88764 100644 --- a/src/gsm.c +++ b/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); diff --git a/src/gsm.h b/src/gsm.h index c581e09..4ec6da6 100644 --- a/src/gsm.h +++ b/src/gsm.h @@ -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, diff --git a/src/phone.c b/src/phone.c index 0ab3631..2a6f8fd 100644 --- a/src/phone.c +++ b/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; diff --git a/src/phone.h b/src/phone.h index c0d0699..a75e803 100644 --- a/src/phone.h +++ b/src/phone.h @@ -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