Implemented pppd pass-through
This commit is contained in:
parent
0f03769f71
commit
9c6b35783f
172
src/gsm.c
172
src/gsm.c
@ -78,6 +78,10 @@ struct _GSM
|
||||
char * wr_buf;
|
||||
size_t wr_buf_cnt;
|
||||
guint wr_source;
|
||||
GIOChannel * rd_ppp_channel;
|
||||
guint rd_ppp_source;
|
||||
GIOChannel * wr_ppp_channel;
|
||||
guint wr_ppp_source;
|
||||
|
||||
/* temporary buffers */
|
||||
char number[32];
|
||||
@ -338,8 +342,12 @@ static gboolean _on_reset(gpointer data);
|
||||
static gboolean _on_timeout(gpointer data);
|
||||
static gboolean _on_watch_can_read(GIOChannel * source, GIOCondition condition,
|
||||
gpointer data);
|
||||
static gboolean _on_watch_can_read_ppp(GIOChannel * source,
|
||||
GIOCondition condition, gpointer data);
|
||||
static gboolean _on_watch_can_write(GIOChannel * source, GIOCondition condition,
|
||||
gpointer data);
|
||||
static gboolean _on_watch_can_write_ppp(GIOChannel * source,
|
||||
GIOCondition condition, gpointer data);
|
||||
|
||||
|
||||
/* public */
|
||||
@ -378,6 +386,10 @@ GSM * gsm_new(char const * device, unsigned int baudrate, unsigned int hwflow)
|
||||
gsm->wr_buf = NULL;
|
||||
gsm->wr_buf_cnt = 0;
|
||||
gsm->wr_source = 0;
|
||||
gsm->rd_ppp_channel = NULL;
|
||||
gsm->rd_ppp_source = 0;
|
||||
gsm->wr_ppp_channel = NULL;
|
||||
gsm->wr_ppp_source = 0;
|
||||
/* error checking */
|
||||
if(gsm->device == NULL || gsm->baudrate == 0 || gsm->modem == NULL)
|
||||
{
|
||||
@ -1086,6 +1098,12 @@ int gsm_stop(GSM * gsm)
|
||||
if(gsm->source != 0)
|
||||
g_source_remove(gsm->source);
|
||||
gsm->source = 0;
|
||||
if(gsm->rd_ppp_source != 0)
|
||||
g_source_remove(gsm->rd_ppp_source);
|
||||
gsm->rd_ppp_source = 0;
|
||||
if(gsm->wr_ppp_source != 0)
|
||||
g_source_remove(gsm->wr_ppp_source);
|
||||
gsm->wr_ppp_source = 0;
|
||||
_gsm_event_send(gsm, GSM_EVENT_TYPE_SUSPEND);
|
||||
return 0;
|
||||
}
|
||||
@ -1158,9 +1176,12 @@ static int _gsm_parse(GSM * gsm)
|
||||
#endif
|
||||
while(i < gsm->rd_buf_cnt)
|
||||
{
|
||||
if(gsm->rd_buf[i++] != '\r' && gsm->rd_buf[i - 1] != '\n')
|
||||
if(gsm->rd_buf[i] != '\r' && gsm->rd_buf[i] != '\n')
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
gsm->rd_buf[i - 1] = '\0';
|
||||
}
|
||||
gsm->rd_buf[i++] = '\0';
|
||||
if(i < gsm->rd_buf_cnt && gsm->rd_buf[i] == '\n')
|
||||
i++;
|
||||
if(gsm->rd_buf[0] != '\0')
|
||||
@ -1937,14 +1958,35 @@ static int _gsm_trigger_cmut(GSM * gsm, char const * result)
|
||||
static int _gsm_trigger_connect(GSM * gsm, char const * result,
|
||||
gboolean * answered)
|
||||
{
|
||||
char * argv[] = { "/usr/sbin/pppd", "pppd", "call", "phone", NULL };
|
||||
GSpawnFlags flags = G_SPAWN_FILE_AND_ARGV_ZERO;
|
||||
int wfd;
|
||||
int rfd;
|
||||
GError * error = NULL;
|
||||
|
||||
#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, NULL);
|
||||
gsm->mode = GSM_MODE_DATA;
|
||||
if(g_spawn_async_with_pipes(NULL, argv, NULL, flags, NULL, NULL, NULL,
|
||||
&wfd, &rfd, NULL, &error)
|
||||
== FALSE)
|
||||
{
|
||||
gsm_reset(gsm, 0, NULL);
|
||||
return 1;
|
||||
}
|
||||
gsm->rd_ppp_channel = g_io_channel_unix_new(rfd);
|
||||
g_io_channel_set_encoding(gsm->rd_ppp_channel, NULL, &error);
|
||||
g_io_channel_set_buffered(gsm->rd_ppp_channel, FALSE);
|
||||
gsm->rd_ppp_source = g_io_add_watch(gsm->rd_ppp_channel, G_IO_IN,
|
||||
_on_watch_can_read_ppp, gsm);
|
||||
gsm->wr_ppp_channel = g_io_channel_unix_new(wfd);
|
||||
g_io_channel_set_encoding(gsm->wr_ppp_channel, NULL, &error);
|
||||
g_io_channel_set_buffered(gsm->wr_ppp_channel, FALSE);
|
||||
gsm->wr_ppp_source = 0;
|
||||
return gsm_event(gsm, GSM_EVENT_TYPE_GPRS_ATTACHMENT, 1);
|
||||
}
|
||||
|
||||
|
||||
@ -2240,6 +2282,7 @@ static int _gsm_trigger_no_dialtone(GSM * gsm, char const * result,
|
||||
|
||||
/* callbacks */
|
||||
/* on_reset */
|
||||
static void _reset_channel(GIOChannel * channel);
|
||||
static int _reset_do(GSM * gsm, int fd);
|
||||
static gboolean _reset_settle(gpointer data);
|
||||
|
||||
@ -2254,13 +2297,12 @@ static gboolean _on_reset(gpointer data)
|
||||
#endif
|
||||
if(gsm->source != 0)
|
||||
g_source_remove(gsm->source);
|
||||
if(gsm->channel != NULL)
|
||||
{
|
||||
/* XXX should the file descriptor also be freed? */
|
||||
g_io_channel_shutdown(gsm->channel, TRUE, &error);
|
||||
g_io_channel_unref(gsm->channel);
|
||||
gsm->channel = NULL;
|
||||
}
|
||||
_reset_channel(gsm->channel);
|
||||
gsm->channel = NULL;
|
||||
_reset_channel(gsm->rd_ppp_channel);
|
||||
gsm->rd_ppp_channel = NULL;
|
||||
_reset_channel(gsm->wr_ppp_channel);
|
||||
gsm->wr_ppp_channel = NULL;
|
||||
if((fd = open(gsm->device, O_RDWR | O_NONBLOCK)) < 0
|
||||
|| _reset_do(gsm, fd) != 0)
|
||||
{
|
||||
@ -2287,6 +2329,17 @@ static gboolean _on_reset(gpointer data)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void _reset_channel(GIOChannel * channel)
|
||||
{
|
||||
GError * error = NULL;
|
||||
|
||||
if(channel == NULL)
|
||||
return;
|
||||
/* XXX should the file descriptor also be freed? */
|
||||
g_io_channel_shutdown(channel, TRUE, &error);
|
||||
g_io_channel_unref(channel);
|
||||
}
|
||||
|
||||
static int _reset_do(GSM * gsm, int fd)
|
||||
{
|
||||
struct stat st;
|
||||
@ -2411,7 +2464,58 @@ static gboolean _on_watch_can_read(GIOChannel * source, GIOCondition condition,
|
||||
gsm->rd_source = 0;
|
||||
return FALSE;
|
||||
}
|
||||
_gsm_parse(gsm);
|
||||
switch(gsm->mode)
|
||||
{
|
||||
case GSM_MODE_INIT:
|
||||
case GSM_MODE_COMMAND:
|
||||
case GSM_MODE_PDU: /* XXX really parse? */
|
||||
_gsm_parse(gsm);
|
||||
break;
|
||||
case GSM_MODE_DATA:
|
||||
if(gsm->wr_ppp_channel == NULL
|
||||
|| gsm->wr_ppp_source != 0)
|
||||
break;
|
||||
gsm->wr_ppp_source = g_io_add_watch(gsm->wr_ppp_channel,
|
||||
G_IO_OUT, _on_watch_can_write_ppp, gsm);
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* on_watch_can_read_ppp */
|
||||
static gboolean _on_watch_can_read_ppp(GIOChannel * source,
|
||||
GIOCondition condition, gpointer data)
|
||||
{
|
||||
GSM * gsm = data;
|
||||
gsize cnt = 0;
|
||||
GError * error = NULL;
|
||||
GIOStatus status;
|
||||
char * p;
|
||||
|
||||
if(condition != G_IO_IN || source != gsm->rd_ppp_channel)
|
||||
return FALSE; /* should not happen */
|
||||
if((p = realloc(gsm->wr_buf, gsm->wr_buf_cnt + 256)) == NULL)
|
||||
return TRUE; /* XXX retries immediately (delay?) */
|
||||
gsm->wr_buf = p;
|
||||
status = g_io_channel_read_chars(source,
|
||||
&gsm->wr_buf[gsm->wr_buf_cnt], 256, &cnt, &error);
|
||||
gsm->wr_buf_cnt += cnt;
|
||||
switch(status)
|
||||
{
|
||||
case G_IO_STATUS_NORMAL:
|
||||
break;
|
||||
case G_IO_STATUS_ERROR:
|
||||
error_set("%s", error->message); /* XXX really print */
|
||||
case G_IO_STATUS_EOF:
|
||||
default:
|
||||
gsm->rd_ppp_source = 0;
|
||||
gsm_reset(gsm, 0, NULL);
|
||||
return FALSE;
|
||||
}
|
||||
if(gsm->channel != NULL && gsm->wr_source == 0)
|
||||
gsm->wr_source = g_io_add_watch(gsm->channel, G_IO_OUT,
|
||||
_on_watch_can_write, gsm);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -2481,3 +2585,45 @@ static gboolean _on_watch_can_write(GIOChannel * source, GIOCondition condition,
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* on_watch_can_write_ppp */
|
||||
static gboolean _on_watch_can_write_ppp(GIOChannel * source,
|
||||
GIOCondition condition, gpointer data)
|
||||
{
|
||||
GSM * gsm = data;
|
||||
gsize cnt = 0;
|
||||
GError * error = NULL;
|
||||
GIOStatus status;
|
||||
char * p;
|
||||
|
||||
if(condition != G_IO_OUT || source != gsm->wr_ppp_channel)
|
||||
return FALSE; /* should not happen */
|
||||
status = g_io_channel_write_chars(source, gsm->rd_buf, gsm->rd_buf_cnt,
|
||||
&cnt, &error);
|
||||
if(cnt != 0) /* some data may have been written anyway */
|
||||
{
|
||||
gsm->rd_buf_cnt -= cnt;
|
||||
memmove(gsm->rd_buf, &gsm->rd_buf[cnt], gsm->rd_buf_cnt);
|
||||
if((p = realloc(gsm->rd_buf, gsm->rd_buf_cnt)) != NULL)
|
||||
gsm->rd_buf = p; /* we can ignore errors... */
|
||||
else if(gsm->rd_buf_cnt == 0)
|
||||
gsm->rd_buf = NULL; /* ...except when it's not one */
|
||||
}
|
||||
switch(status)
|
||||
{
|
||||
case G_IO_STATUS_NORMAL:
|
||||
break;
|
||||
case G_IO_STATUS_ERROR:
|
||||
error_set("%s", error->message); /* XXX really print */
|
||||
case G_IO_STATUS_EOF:
|
||||
default:
|
||||
gsm->wr_ppp_source = 0;
|
||||
gsm_reset(gsm, 0, NULL);
|
||||
return FALSE;
|
||||
}
|
||||
if(gsm->rd_buf_cnt > 0) /* there is more data to write */
|
||||
return TRUE;
|
||||
gsm->wr_ppp_source = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -137,7 +137,7 @@ typedef enum _GSMMessageMode
|
||||
|
||||
typedef enum _GSMMode
|
||||
{
|
||||
GSM_MODE_INIT = 0, GSM_MODE_COMMAND, GSM_MODE_PDU
|
||||
GSM_MODE_INIT = 0, GSM_MODE_COMMAND, GSM_MODE_DATA, GSM_MODE_PDU
|
||||
} GSMMode;
|
||||
|
||||
typedef enum _GSMOperatorFormat
|
||||
|
@ -30,6 +30,8 @@ typedef struct _GPRS
|
||||
GtkWidget * window;
|
||||
GtkWidget * attach;
|
||||
GtkWidget * apn;
|
||||
GtkWidget * username;
|
||||
GtkWidget * password;
|
||||
} GPRS;
|
||||
|
||||
|
||||
@ -42,6 +44,8 @@ static void _gprs_settings(PhonePlugin * plugin);
|
||||
|
||||
static int _gprs_access_point(PhonePlugin * plugin);
|
||||
static int _gprs_attach(PhonePlugin * plugin);
|
||||
static int _gprs_connect(PhonePlugin * plugin);
|
||||
static int _gprs_disconnect(PhonePlugin * plugin);
|
||||
|
||||
|
||||
/* public */
|
||||
@ -109,6 +113,8 @@ static int _gprs_event_functional(PhonePlugin * plugin)
|
||||
/* gprs_settings */
|
||||
static void _on_settings_cancel(gpointer data);
|
||||
static gboolean _on_settings_closex(gpointer data);
|
||||
static void _on_settings_disconnect(gpointer data);
|
||||
static void _on_settings_connect(gpointer data);
|
||||
static void _on_settings_ok(gpointer data);
|
||||
|
||||
static void _gprs_settings(PhonePlugin * plugin)
|
||||
@ -127,20 +133,43 @@ static void _gprs_settings(PhonePlugin * plugin)
|
||||
gtk_container_set_border_width(GTK_CONTAINER(gprs->window), 4);
|
||||
gtk_window_set_default_size(GTK_WINDOW(gprs->window), 200, 300);
|
||||
#if GTK_CHECK_VERSION(2, 6, 0)
|
||||
gtk_window_set_icon_name(GTK_WINDOW(gprs->window), "network-wireless");
|
||||
gtk_window_set_icon_name(GTK_WINDOW(gprs->window), "stock_internet");
|
||||
#endif
|
||||
gtk_window_set_title(GTK_WINDOW(gprs->window), "GPRS preferences");
|
||||
g_signal_connect_swapped(G_OBJECT(gprs->window), "delete-event",
|
||||
G_CALLBACK(_on_settings_closex), plugin);
|
||||
vbox = gtk_vbox_new(FALSE, 0);
|
||||
vbox = gtk_vbox_new(FALSE, 4);
|
||||
/* attachment */
|
||||
gprs->attach = gtk_check_button_new_with_label("Always on");
|
||||
gtk_box_pack_start(GTK_BOX(vbox), gprs->attach, FALSE, TRUE, 0);
|
||||
/* access point */
|
||||
widget = gtk_label_new("Access point:");
|
||||
gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
|
||||
gprs->apn = gtk_entry_new();
|
||||
gtk_box_pack_start(GTK_BOX(vbox), gprs->apn, FALSE, TRUE, 0);
|
||||
/* credentials */
|
||||
widget = gtk_label_new("Username:");
|
||||
gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
|
||||
gprs->username = gtk_entry_new();
|
||||
gtk_box_pack_start(GTK_BOX(vbox), gprs->username, FALSE, TRUE, 0);
|
||||
widget = gtk_label_new("Password:");
|
||||
gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
|
||||
gprs->password = gtk_entry_new();
|
||||
gtk_entry_set_visibility(GTK_ENTRY(gprs->password), FALSE);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), gprs->password, FALSE, TRUE, 0);
|
||||
/* connect */
|
||||
widget = gtk_button_new_from_stock(GTK_STOCK_CONNECT);
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(
|
||||
_on_settings_connect), plugin);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
|
||||
/* disconnect */
|
||||
widget = gtk_button_new_from_stock(GTK_STOCK_DISCONNECT);
|
||||
g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK(
|
||||
_on_settings_disconnect), plugin);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0);
|
||||
/* button box */
|
||||
bbox = gtk_hbutton_box_new();
|
||||
gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END);
|
||||
@ -165,10 +194,7 @@ static void _on_settings_cancel(gpointer data)
|
||||
GPRS * gprs = plugin->priv;
|
||||
char const * p;
|
||||
|
||||
if((p = plugin->helper->config_get(plugin->helper->phone, "gprs",
|
||||
"apn")) == NULL)
|
||||
p = "";
|
||||
gtk_entry_set_text(GTK_ENTRY(gprs->apn), p);
|
||||
gtk_widget_hide(gprs->window);
|
||||
if((p = plugin->helper->config_get(plugin->helper->phone, "gprs",
|
||||
"attach")) != NULL
|
||||
&& strtoul(p, NULL, 10) != 0)
|
||||
@ -177,7 +203,18 @@ static void _on_settings_cancel(gpointer data)
|
||||
else
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gprs->attach),
|
||||
FALSE);
|
||||
gtk_widget_hide(gprs->window);
|
||||
if((p = plugin->helper->config_get(plugin->helper->phone, "gprs",
|
||||
"apn")) == NULL)
|
||||
p = "";
|
||||
gtk_entry_set_text(GTK_ENTRY(gprs->apn), p);
|
||||
if((p = plugin->helper->config_get(plugin->helper->phone, "gprs",
|
||||
"username")) == NULL)
|
||||
p = "";
|
||||
gtk_entry_set_text(GTK_ENTRY(gprs->username), p);
|
||||
if((p = plugin->helper->config_get(plugin->helper->phone, "gprs",
|
||||
"password")) == NULL)
|
||||
p = "";
|
||||
gtk_entry_set_text(GTK_ENTRY(gprs->password), p);
|
||||
}
|
||||
|
||||
static gboolean _on_settings_closex(gpointer data)
|
||||
@ -188,6 +225,20 @@ static gboolean _on_settings_closex(gpointer data)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void _on_settings_connect(gpointer data)
|
||||
{
|
||||
PhonePlugin * plugin = data;
|
||||
|
||||
_gprs_connect(plugin);
|
||||
}
|
||||
|
||||
static void _on_settings_disconnect(gpointer data)
|
||||
{
|
||||
PhonePlugin * plugin = data;
|
||||
|
||||
_gprs_disconnect(plugin);
|
||||
}
|
||||
|
||||
static void _on_settings_ok(gpointer data)
|
||||
{
|
||||
PhonePlugin * plugin = data;
|
||||
@ -195,17 +246,20 @@ static void _on_settings_ok(gpointer data)
|
||||
char const * p;
|
||||
gboolean active;
|
||||
|
||||
if((p = gtk_entry_get_text(GTK_ENTRY(gprs->apn))) != NULL
|
||||
&& strlen(p) != 0
|
||||
&& plugin->helper->config_set(plugin->helper->phone,
|
||||
"gprs", "apn", p) == 0)
|
||||
_gprs_access_point(plugin);
|
||||
active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
|
||||
gprs->attach));
|
||||
if(plugin->helper->config_set(plugin->helper->phone, "gprs", "attach",
|
||||
active ? "1" : "0") == 0)
|
||||
_gprs_attach(plugin);
|
||||
gtk_widget_hide(gprs->window);
|
||||
active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gprs->attach));
|
||||
plugin->helper->config_set(plugin->helper->phone, "gprs", "attach",
|
||||
active ? "1" : "0");
|
||||
_gprs_attach(plugin);
|
||||
p = gtk_entry_get_text(GTK_ENTRY(gprs->apn));
|
||||
plugin->helper->config_set(plugin->helper->phone, "gprs", "apn", p);
|
||||
_gprs_access_point(plugin);
|
||||
p = gtk_entry_get_text(GTK_ENTRY(gprs->username));
|
||||
plugin->helper->config_set(plugin->helper->phone, "gprs", "username",
|
||||
p);
|
||||
p = gtk_entry_get_text(GTK_ENTRY(gprs->password));
|
||||
plugin->helper->config_set(plugin->helper->phone, "gprs", "password",
|
||||
p);
|
||||
}
|
||||
|
||||
|
||||
@ -242,3 +296,21 @@ static int _gprs_attach(PhonePlugin * plugin)
|
||||
return 1;
|
||||
return plugin->helper->queue(plugin->helper->phone, "AT+CGATT?");
|
||||
}
|
||||
|
||||
|
||||
/* gprs_connect */
|
||||
static int _gprs_connect(PhonePlugin * plugin)
|
||||
{
|
||||
char const * cmd = "ATD*99***1#";
|
||||
|
||||
return plugin->helper->queue(plugin->helper->phone, cmd);
|
||||
}
|
||||
|
||||
|
||||
/* gprs_disconnect */
|
||||
static int _gprs_disconnect(PhonePlugin * plugin)
|
||||
{
|
||||
char const * cmd = "ATH"; /* XXX requires interpretation from Phone */
|
||||
|
||||
return plugin->helper->queue(plugin->helper->phone, cmd);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user