summaryrefslogtreecommitdiff
path: root/gatchat/gatchat.c
diff options
context:
space:
mode:
authorDenis Kenzior <denkenz@gmail.com>2010-08-12 10:05:01 -0500
committerDenis Kenzior <denkenz@gmail.com>2010-08-12 16:06:27 -0500
commit2356ebf9ef8796226aa17092366b62af0f00b73a (patch)
treede5902d39e9d010ee4c19c8f4f9495c21c1c9d4e /gatchat/gatchat.c
parent3b34dd44f19d067592242466111dff38e660486e (diff)
downloadofono-2356ebf9ef8796226aa17092366b62af0f00b73a.tar.gz
gatchat: Make GAtChat a facade for struct at_chat
Each GAtChat object is now simply a representation of a set of outstanding commands and registered unsolicited notification handlers. This makes it easy to cancel entire groups, e.g. by canceling the GAtChat object itself rather than forcing the user into tracking all relevant g_at_chat_register and g_at_chat_send ids.
Diffstat (limited to 'gatchat/gatchat.c')
-rw-r--r--gatchat/gatchat.c629
1 files changed, 401 insertions, 228 deletions
diff --git a/gatchat/gatchat.c b/gatchat/gatchat.c
index f192a907..31ec81e5 100644
--- a/gatchat/gatchat.c
+++ b/gatchat/gatchat.c
@@ -38,7 +38,8 @@
/* #define WRITE_SCHEDULER_DEBUG 1 */
-static void chat_wakeup_writer(GAtChat *chat);
+struct at_chat;
+static void chat_wakeup_writer(struct at_chat *chat);
static const char *none_prefix[] = { NULL };
@@ -47,6 +48,7 @@ struct at_command {
char **prefixes;
gboolean expect_pdu;
guint id;
+ guint gid;
GAtResultFunc callback;
GAtNotifyFunc listing;
gpointer user_data;
@@ -55,6 +57,7 @@ struct at_command {
struct at_notify_node {
guint id;
+ guint gid;
GAtNotifyFunc callback;
gpointer user_data;
GDestroyNotify notify;
@@ -65,10 +68,11 @@ struct at_notify {
gboolean pdu;
};
-struct _GAtChat {
+struct at_chat {
gint ref_count; /* Ref count */
guint next_cmd_id; /* Next command id */
guint next_notify_id; /* Next notify id */
+ guint next_gid; /* Next group id */
GAtIO *io; /* AT IO */
GQueue *command_queue; /* Command queue */
guint cmd_bytes_written; /* bytes written from cmd */
@@ -92,6 +96,12 @@ struct _GAtChat {
GSList *terminator_list; /* Non-standard terminator */
};
+struct _GAtChat {
+ gint ref_count;
+ struct at_chat *parent;
+ guint group;
+};
+
struct terminator_info {
char *terminator;
int len;
@@ -144,7 +154,7 @@ static gint at_command_compare_by_id(gconstpointer a, gconstpointer b)
return 0;
}
-static struct at_command *at_command_create(const char *cmd,
+static struct at_command *at_command_create(guint gid, const char *cmd,
const char **prefix_list,
gboolean expect_pdu,
GAtNotifyFunc listing,
@@ -199,6 +209,7 @@ static struct at_command *at_command_create(const char *cmd,
c->cmd[len] = '\0';
+ c->gid = gid;
c->expect_pdu = expect_pdu;
c->prefixes = prefixes;
c->callback = func;
@@ -227,7 +238,7 @@ static void free_terminator(struct terminator_info *info)
info = NULL;
}
-static void chat_cleanup(GAtChat *chat)
+static void chat_cleanup(struct at_chat *chat)
{
struct at_command *c;
@@ -280,7 +291,7 @@ static void chat_cleanup(GAtChat *chat)
static void io_disconnect(gpointer user_data)
{
- GAtChat *chat = user_data;
+ struct at_chat *chat = user_data;
chat_cleanup(chat);
g_at_io_unref(chat->io);
@@ -298,7 +309,7 @@ static void at_notify_call_callback(gpointer data, gpointer user_data)
node->callback(result, node->user_data);
}
-static gboolean g_at_chat_match_notify(GAtChat *chat, char *line)
+static gboolean at_chat_match_notify(struct at_chat *chat, char *line)
{
GHashTableIter iter;
struct at_notify *notify;
@@ -341,7 +352,7 @@ static gboolean g_at_chat_match_notify(GAtChat *chat, char *line)
return ret;
}
-static void g_at_chat_finish_command(GAtChat *p, gboolean ok, char *final)
+static void at_chat_finish_command(struct at_chat *p, gboolean ok, char *final)
{
struct at_command *cmd = g_queue_pop_head(p->command_queue);
GSList *response_lines;
@@ -389,7 +400,7 @@ static struct terminator_info terminator_table[] = {
{ "+EXT ERROR:", 11, FALSE }
};
-void g_at_chat_add_terminator(GAtChat *chat, char *terminator,
+static void at_chat_add_terminator(struct at_chat *chat, char *terminator,
int len, gboolean success)
{
struct terminator_info *info = g_new0(struct terminator_info, 1);
@@ -410,7 +421,7 @@ static gboolean check_terminator(struct terminator_info *info, char *line)
return FALSE;
}
-static gboolean g_at_chat_handle_command_response(GAtChat *p,
+static gboolean at_chat_handle_command_response(struct at_chat *p,
struct at_command *cmd,
char *line)
{
@@ -422,7 +433,7 @@ static gboolean g_at_chat_handle_command_response(GAtChat *p,
for (i = 0; i < size; i++) {
struct terminator_info *info = &terminator_table[i];
if (check_terminator(info, line)) {
- g_at_chat_finish_command(p, info->success, line);
+ at_chat_finish_command(p, info->success, line);
return TRUE;
}
}
@@ -430,7 +441,7 @@ static gboolean g_at_chat_handle_command_response(GAtChat *p,
for (l = p->terminator_list; l; l = l->next) {
struct terminator_info *info = l->data;
if (check_terminator(info, line)) {
- g_at_chat_finish_command(p, info->success, line);
+ at_chat_finish_command(p, info->success, line);
return TRUE;
}
}
@@ -475,7 +486,7 @@ out:
return TRUE;
}
-static void have_line(GAtChat *p, char *str)
+static void have_line(struct at_chat *p, char *str)
{
/* We're not going to copy terminal <CR><LF> */
struct at_command *cmd;
@@ -501,11 +512,11 @@ static void have_line(GAtChat *p, char *str)
* final response from the modem, so we check this as well.
*/
if ((c == '\r' || c == 26) &&
- g_at_chat_handle_command_response(p, cmd, str))
+ at_chat_handle_command_response(p, cmd, str))
return;
}
- if (g_at_chat_match_notify(p, str) == TRUE)
+ if (at_chat_match_notify(p, str) == TRUE)
return;
done:
@@ -513,7 +524,7 @@ done:
g_free(str);
}
-static void have_notify_pdu(GAtChat *p, char *pdu, GAtResult *result)
+static void have_notify_pdu(struct at_chat *p, char *pdu, GAtResult *result)
{
GHashTableIter iter;
struct at_notify *notify;
@@ -536,7 +547,7 @@ static void have_notify_pdu(GAtChat *p, char *pdu, GAtResult *result)
}
}
-static void have_pdu(GAtChat *p, char *pdu)
+static void have_pdu(struct at_chat *p, char *pdu)
{
struct at_command *cmd;
GAtResult result;
@@ -576,7 +587,7 @@ error:
g_free(pdu);
}
-static char *extract_line(GAtChat *p, struct ring_buffer *rbuf)
+static char *extract_line(struct at_chat *p, struct ring_buffer *rbuf)
{
unsigned int wrap = ring_buffer_len_no_wrap(rbuf);
unsigned int pos = 0;
@@ -618,7 +629,7 @@ static char *extract_line(GAtChat *p, struct ring_buffer *rbuf)
static void new_bytes(struct ring_buffer *rbuf, gpointer user_data)
{
- GAtChat *p = user_data;
+ struct at_chat *p = user_data;
unsigned int len = ring_buffer_len(rbuf);
unsigned int wrap = ring_buffer_len_no_wrap(rbuf);
unsigned char *buf = ring_buffer_read_ptr(rbuf, p->read_so_far);
@@ -675,7 +686,7 @@ static void new_bytes(struct ring_buffer *rbuf, gpointer user_data)
static void wakeup_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
- GAtChat *chat = user_data;
+ struct at_chat *chat = user_data;
if (ok == FALSE)
return;
@@ -689,7 +700,7 @@ static void wakeup_cb(gboolean ok, GAtResult *result, gpointer user_data)
static gboolean wakeup_no_response(gpointer user_data)
{
- GAtChat *chat = user_data;
+ struct at_chat *chat = user_data;
struct at_command *cmd = g_queue_peek_head(chat->command_queue);
if (chat->debugf)
@@ -698,8 +709,8 @@ static gboolean wakeup_no_response(gpointer user_data)
if (cmd == NULL)
return FALSE;
- g_at_chat_finish_command(chat, FALSE, NULL);
- cmd = at_command_create(chat->wakeup, none_prefix, FALSE,
+ at_chat_finish_command(chat, FALSE, NULL);
+ cmd = at_command_create(0, chat->wakeup, none_prefix, FALSE,
NULL, wakeup_cb, chat, NULL, TRUE);
if (!cmd) {
@@ -714,7 +725,7 @@ static gboolean wakeup_no_response(gpointer user_data)
static gboolean can_write_data(gpointer data)
{
- GAtChat *chat = data;
+ struct at_chat *chat = data;
struct at_command *cmd;
gsize bytes_written;
gsize towrite;
@@ -751,7 +762,7 @@ static gboolean can_write_data(gpointer data)
}
if (chat->cmd_bytes_written == 0 && wakeup_first == TRUE) {
- cmd = at_command_create(chat->wakeup, none_prefix, FALSE,
+ cmd = at_command_create(0, chat->wakeup, none_prefix, FALSE,
NULL, wakeup_cb, chat, NULL, TRUE);
if (!cmd)
@@ -796,121 +807,23 @@ static gboolean can_write_data(gpointer data)
return FALSE;
}
-static void chat_wakeup_writer(GAtChat *chat)
+static void chat_wakeup_writer(struct at_chat *chat)
{
g_at_io_set_write_handler(chat->io, can_write_data, chat);
}
-static GAtChat *create_chat(GIOChannel *channel, GIOFlags flags,
- GAtSyntax *syntax)
+static void at_chat_suspend(struct at_chat *chat)
{
- GAtChat *chat;
-
- if (!channel)
- return NULL;
-
- if (!syntax)
- return NULL;
-
- chat = g_try_new0(GAtChat, 1);
- if (!chat)
- return chat;
-
- chat->ref_count = 1;
- chat->next_cmd_id = 1;
- chat->next_notify_id = 1;
- chat->debugf = NULL;
-
- if (flags & G_IO_FLAG_NONBLOCK)
- chat->io = g_at_io_new(channel);
- else
- chat->io = g_at_io_new_blocking(channel);
-
- if (!chat->io)
- goto error;
-
- g_at_io_set_disconnect_function(chat->io, io_disconnect, chat);
-
- chat->command_queue = g_queue_new();
-
- if (!chat->command_queue)
- goto error;
-
- chat->notify_list = g_hash_table_new_full(g_str_hash, g_str_equal,
- g_free, at_notify_destroy);
-
- g_at_io_set_read_handler(chat->io, new_bytes, chat);
-
- chat->syntax = g_at_syntax_ref(syntax);
-
- return chat;
-
-error:
- g_at_io_unref(chat->io);
-
- if (chat->command_queue)
- g_queue_free(chat->command_queue);
-
- if (chat->notify_list)
- g_hash_table_destroy(chat->notify_list);
-
- g_free(chat);
- return NULL;
-}
-
-GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax)
-{
- return create_chat(channel, G_IO_FLAG_NONBLOCK, syntax);
-}
-
-GAtChat *g_at_chat_new_blocking(GIOChannel *channel, GAtSyntax *syntax)
-{
- return create_chat(channel, 0, syntax);
-}
-
-GIOChannel *g_at_chat_get_channel(GAtChat *chat)
-{
- if (chat == NULL || chat->io == NULL)
- return NULL;
-
- return g_at_io_get_channel(chat->io);
-}
-
-GAtIO *g_at_chat_get_io(GAtChat *chat)
-{
- if (chat == NULL)
- return NULL;
-
- return chat->io;
-}
-
-GAtChat *g_at_chat_ref(GAtChat *chat)
-{
- if (chat == NULL)
- return NULL;
-
- g_atomic_int_inc(&chat->ref_count);
-
- return chat;
-}
-
-void g_at_chat_suspend(GAtChat *chat)
-{
- if (chat == NULL)
- return;
-
chat->suspended = TRUE;
g_at_io_set_write_handler(chat->io, NULL, NULL);
g_at_io_set_read_handler(chat->io, NULL, NULL);
g_at_io_set_debug(chat->io, NULL, NULL);
+
}
-void g_at_chat_resume(GAtChat *chat)
+static void at_chat_resume(struct at_chat *chat)
{
- if (chat == NULL)
- return;
-
chat->suspended = FALSE;
if (g_at_io_get_channel(chat->io) == NULL) {
@@ -927,20 +840,17 @@ void g_at_chat_resume(GAtChat *chat)
chat_wakeup_writer(chat);
}
-void g_at_chat_unref(GAtChat *chat)
+static void at_chat_unref(struct at_chat *chat)
{
gboolean is_zero;
- if (chat == NULL)
- return;
-
is_zero = g_atomic_int_dec_and_test(&chat->ref_count);
if (is_zero == FALSE)
return;
if (chat->io) {
- g_at_chat_suspend(chat);
+ at_chat_suspend(chat);
g_at_io_unref(chat->io);
chat->io = NULL;
chat_cleanup(chat);
@@ -952,23 +862,18 @@ void g_at_chat_unref(GAtChat *chat)
g_free(chat);
}
-gboolean g_at_chat_set_disconnect_function(GAtChat *chat,
+static gboolean at_chat_set_disconnect_function(struct at_chat *chat,
GAtDisconnectFunc disconnect, gpointer user_data)
{
- if (chat == NULL)
- return FALSE;
-
chat->user_disconnect = disconnect;
chat->user_disconnect_data = user_data;
return TRUE;
}
-gboolean g_at_chat_set_debug(GAtChat *chat,
+static gboolean at_chat_set_debug(struct at_chat *chat,
GAtDebugFunc func, gpointer user_data)
{
- if (chat == NULL)
- return FALSE;
chat->debugf = func;
chat->debug_data = user_data;
@@ -979,18 +884,36 @@ gboolean g_at_chat_set_debug(GAtChat *chat,
return TRUE;
}
-static guint send_common(GAtChat *chat, const char *cmd,
- const char **prefix_list,
- gboolean expect_pdu,
- GAtNotifyFunc listing, GAtResultFunc func,
- gpointer user_data, GDestroyNotify notify)
+static gboolean at_chat_set_wakeup_command(struct at_chat *chat,
+ const char *cmd,
+ unsigned int timeout,
+ unsigned int msec)
+{
+ if (chat->wakeup)
+ g_free(chat->wakeup);
+
+ chat->wakeup = g_strdup(cmd);
+ chat->inactivity_time = (gdouble)msec / 1000;
+ chat->wakeup_timeout = timeout;
+
+ return TRUE;
+}
+
+static guint at_chat_send_common(struct at_chat *chat, guint gid,
+ const char *cmd,
+ const char **prefix_list,
+ gboolean expect_pdu,
+ GAtNotifyFunc listing,
+ GAtResultFunc func,
+ gpointer user_data,
+ GDestroyNotify notify)
{
struct at_command *c;
if (chat == NULL || chat->command_queue == NULL)
return 0;
- c = at_command_create(cmd, prefix_list, expect_pdu, listing, func,
+ c = at_command_create(gid, cmd, prefix_list, expect_pdu, listing, func,
user_data, notify, FALSE);
if (!c)
@@ -1006,47 +929,37 @@ static guint send_common(GAtChat *chat, const char *cmd,
return c->id;
}
-guint g_at_chat_send(GAtChat *chat, const char *cmd,
- const char **prefix_list, GAtResultFunc func,
- gpointer user_data, GDestroyNotify notify)
+static struct at_notify *at_notify_create(struct at_chat *chat,
+ const char *prefix,
+ gboolean pdu)
{
- return send_common(chat, cmd, prefix_list, FALSE, NULL, func,
- user_data, notify);
-}
+ struct at_notify *notify;
+ char *key;
-guint g_at_chat_send_listing(GAtChat *chat, const char *cmd,
- const char **prefix_list,
- GAtNotifyFunc listing, GAtResultFunc func,
- gpointer user_data, GDestroyNotify notify)
-{
- if (listing == NULL)
- return 0;
+ key = g_strdup(prefix);
- return send_common(chat, cmd, prefix_list, FALSE, listing, func,
- user_data, notify);
-}
+ if (!key)
+ return 0;
-guint g_at_chat_send_pdu_listing(GAtChat *chat, const char *cmd,
- const char **prefix_list,
- GAtNotifyFunc listing, GAtResultFunc func,
- gpointer user_data, GDestroyNotify notify)
-{
- if (listing == NULL)
+ notify = g_try_new0(struct at_notify, 1);
+ if (!notify) {
+ g_free(key);
return 0;
+ }
+
+ notify->pdu = pdu;
- return send_common(chat, cmd, prefix_list, TRUE, listing, func,
- user_data, notify);
+ g_hash_table_insert(chat->notify_list, key, notify);
+
+ return notify;
}
-gboolean g_at_chat_cancel(GAtChat *chat, guint id)
+static gboolean at_chat_cancel(struct at_chat *chat, guint group, guint id)
{
GList *l;
+ struct at_command *c;
- if (chat == NULL || chat->command_queue == NULL)
- return FALSE;
-
- /* We use id 0 for wakeup commands */
- if (id == 0)
+ if (chat->command_queue == NULL)
return FALSE;
l = g_queue_find_custom(chat->command_queue, GUINT_TO_POINTER(id),
@@ -1055,33 +968,36 @@ gboolean g_at_chat_cancel(GAtChat *chat, guint id)
if (!l)
return FALSE;
+ c = l->data;
+
+ if (c->gid != group)
+ return FALSE;
+
if (l == g_queue_peek_head(chat->command_queue) &&
chat->cmd_bytes_written > 0) {
- struct at_command *c = l->data;
-
/* We can't actually remove it since it is most likely
* already in progress, just null out the callback
* so it won't be called
*/
c->callback = NULL;
} else {
- at_command_destroy(l->data);
- g_queue_remove(chat->command_queue, l->data);
+ at_command_destroy(c);
+ g_queue_remove(chat->command_queue, c);
}
return TRUE;
}
-gboolean g_at_chat_cancel_all(GAtChat *chat)
+static gboolean at_chat_cancel_group(struct at_chat *chat, guint group)
{
int n = 0;
struct at_command *c;
- if (chat == NULL || chat->command_queue == NULL)
+ if (chat->command_queue == NULL)
return FALSE;
while ((c = g_queue_peek_nth(chat->command_queue, n)) != NULL) {
- if (c->id == 0) {
+ if (c->id == 0 || c->gid != group) {
n += 1;
continue;
}
@@ -1099,39 +1015,15 @@ gboolean g_at_chat_cancel_all(GAtChat *chat)
return TRUE;
}
-static struct at_notify *at_notify_create(GAtChat *chat, const char *prefix,
- gboolean pdu)
-{
- struct at_notify *notify;
- char *key;
-
- key = g_strdup(prefix);
-
- if (!key)
- return 0;
-
- notify = g_try_new0(struct at_notify, 1);
- if (!notify) {
- g_free(key);
- return 0;
- }
-
- notify->pdu = pdu;
-
- g_hash_table_insert(chat->notify_list, key, notify);
-
- return notify;
-}
-
-guint g_at_chat_register(GAtChat *chat, const char *prefix,
- GAtNotifyFunc func, gboolean expect_pdu,
- gpointer user_data,
+static guint at_chat_register(struct at_chat *chat, guint group,
+ const char *prefix, GAtNotifyFunc func,
+ gboolean expect_pdu, gpointer user_data,
GDestroyNotify destroy_notify)
{
struct at_notify *notify;
struct at_notify_node *node;
- if (chat == NULL || chat->notify_list == NULL)
+ if (chat->notify_list == NULL)
return 0;
if (func == NULL)
@@ -1153,6 +1045,7 @@ guint g_at_chat_register(GAtChat *chat, const char *prefix,
return 0;
node->id = chat->next_notify_id++;
+ node->gid = group;
node->callback = func;
node->user_data = user_data;
node->notify = destroy_notify;
@@ -1162,14 +1055,15 @@ guint g_at_chat_register(GAtChat *chat, const char *prefix,
return node->id;
}
-gboolean g_at_chat_unregister(GAtChat *chat, guint id)
+static gboolean at_chat_unregister(struct at_chat *chat, guint group, guint id)
{
GHashTableIter iter;
struct at_notify *notify;
+ struct at_notify_node *node;
gpointer key, value;
GSList *l;
- if (chat == NULL || chat->notify_list == NULL)
+ if (chat->notify_list == NULL)
return FALSE;
g_hash_table_iter_init(&iter, chat->notify_list);
@@ -1183,8 +1077,13 @@ gboolean g_at_chat_unregister(GAtChat *chat, guint id)
if (!l)
continue;
- at_notify_node_destroy(l->data, NULL);
- notify->nodes = g_slist_remove(notify->nodes, l->data);
+ node = l->data;
+
+ if (node->gid != group)
+ continue;
+
+ at_notify_node_destroy(node, NULL);
+ notify->nodes = g_slist_remove(notify->nodes, node);
if (notify->nodes == NULL)
g_hash_table_iter_remove(&iter);
@@ -1192,17 +1091,20 @@ gboolean g_at_chat_unregister(GAtChat *chat, guint id)
return TRUE;
}
- return TRUE;
+ return FALSE;
}
-gboolean g_at_chat_unregister_all(GAtChat *chat)
+static gboolean at_chat_unregister_group(struct at_chat *chat, guint group)
{
GHashTableIter iter;
struct at_notify *notify;
+ struct at_notify_node *node;
gpointer key, value;
- GSList *l;
+ GSList *p;
+ GSList *c;
+ GSList *t;
- if (chat == NULL || chat->notify_list == NULL)
+ if (chat->notify_list == NULL)
return FALSE;
g_hash_table_iter_init(&iter, chat->notify_list);
@@ -1210,29 +1112,300 @@ gboolean g_at_chat_unregister_all(GAtChat *chat)
while (g_hash_table_iter_next(&iter, &key, &value)) {
notify = value;
- for (l = notify->nodes; l; l = l->next)
- at_notify_node_destroy(l->data, NULL);
+ p = NULL;
+ c = notify->nodes;
+
+ while (c) {
+ node = c->data;
+
+ if (node->gid != group) {
+ p = c;
+ c = c->next;
+ continue;
+ }
+
+ if (p)
+ p->next = c->next;
+ else
+ notify->nodes = c->next;
+
+ at_notify_node_destroy(node, NULL);
- g_slist_free(notify->nodes);
- notify->nodes = NULL;
- g_hash_table_iter_remove(&iter);
+ t = c;
+ c = c->next;
+ g_slist_free_1(t);
+ }
+
+ if (notify->nodes == NULL)
+ g_hash_table_iter_remove(&iter);
}
return TRUE;
}
+static struct at_chat *create_chat(GIOChannel *channel, GIOFlags flags,
+ GAtSyntax *syntax)
+{
+ struct at_chat *chat;
+
+ if (!channel)
+ return NULL;
+
+ if (!syntax)
+ return NULL;
+
+ chat = g_try_new0(struct at_chat, 1);
+ if (!chat)
+ return chat;
+
+ chat->ref_count = 1;
+ chat->next_cmd_id = 1;
+ chat->next_notify_id = 1;
+ chat->debugf = NULL;
+
+ if (flags & G_IO_FLAG_NONBLOCK)
+ chat->io = g_at_io_new(channel);
+ else
+ chat->io = g_at_io_new_blocking(channel);
+
+ if (!chat->io)
+ goto error;
+
+ g_at_io_set_disconnect_function(chat->io, io_disconnect, chat);
+
+ chat->command_queue = g_queue_new();
+
+ if (!chat->command_queue)
+ goto error;
+
+ chat->notify_list = g_hash_table_new_full(g_str_hash, g_str_equal,
+ g_free, at_notify_destroy);
+
+ g_at_io_set_read_handler(chat->io, new_bytes, chat);
+
+ chat->syntax = g_at_syntax_ref(syntax);
+
+ return chat;
+
+error:
+ g_at_io_unref(chat->io);
+
+ if (chat->command_queue)
+ g_queue_free(chat->command_queue);
+
+ if (chat->notify_list)
+ g_hash_table_destroy(chat->notify_list);
+
+ g_free(chat);
+ return NULL;
+}
+
+static GAtChat *g_at_chat_new_common(GIOChannel *channel, GIOFlags flags,
+ GAtSyntax *syntax)
+{
+ GAtChat *chat;
+
+ chat = g_try_new0(GAtChat, 1);
+ if (chat == NULL)
+ return NULL;
+
+ chat->parent = create_chat(channel, flags, syntax);
+ if (chat->parent == NULL) {
+ g_free(chat);
+ return NULL;
+ }
+
+ chat->group = chat->parent->next_gid++;
+ chat->ref_count = 1;
+
+ return chat;
+}
+
+GAtChat *g_at_chat_new(GIOChannel *channel, GAtSyntax *syntax)
+{
+ return g_at_chat_new_common(channel, G_IO_FLAG_NONBLOCK, syntax);
+}
+
+GAtChat *g_at_chat_new_blocking(GIOChannel *channel, GAtSyntax *syntax)
+{
+ return g_at_chat_new_common(channel, 0, syntax);
+}
+
+GIOChannel *g_at_chat_get_channel(GAtChat *chat)
+{
+ if (chat == NULL || chat->parent->io == NULL)
+ return NULL;
+
+ return g_at_io_get_channel(chat->parent->io);
+}
+
+GAtIO *g_at_chat_get_io(GAtChat *chat)
+{
+ if (chat == NULL)
+ return NULL;
+
+ return chat->parent->io;
+}
+
+GAtChat *g_at_chat_ref(GAtChat *chat)
+{
+ if (chat == NULL)
+ return NULL;
+
+ g_atomic_int_inc(&chat->ref_count);
+
+ return chat;
+}
+
+void g_at_chat_suspend(GAtChat *chat)
+{
+ if (chat == NULL)
+ return;
+
+ at_chat_suspend(chat->parent);
+}
+
+void g_at_chat_resume(GAtChat *chat)
+{
+ if (chat == NULL)
+ return;
+
+ at_chat_resume(chat->parent);
+}
+
+void g_at_chat_unref(GAtChat *chat)
+{
+ gboolean is_zero;
+
+ if (chat == NULL)
+ return;
+
+ is_zero = g_atomic_int_dec_and_test(&chat->ref_count);
+
+ if (is_zero == FALSE)
+ return;
+
+ at_chat_cancel_group(chat->parent, chat->group);
+ at_chat_unregister_group(chat->parent, chat->group);
+ at_chat_unref(chat->parent);
+
+ g_free(chat);
+}
+
+gboolean g_at_chat_set_disconnect_function(GAtChat *chat,
+ GAtDisconnectFunc disconnect, gpointer user_data)
+{
+ if (chat == NULL || chat->group != 0)
+ return FALSE;
+
+ return at_chat_set_disconnect_function(chat->parent, disconnect,
+ user_data);
+}
+
+gboolean g_at_chat_set_debug(GAtChat *chat,
+ GAtDebugFunc func, gpointer user_data)
+{
+
+ if (chat == NULL || chat->group != 0)
+ return FALSE;
+
+ return at_chat_set_debug(chat->parent, func, user_data);
+}
+
+void g_at_chat_add_terminator(GAtChat *chat, char *terminator,
+ int len, gboolean success)
+{
+ if (chat == NULL || chat->group != 0)
+ return;
+
+ at_chat_add_terminator(chat->parent, terminator, len, success);
+}
+
gboolean g_at_chat_set_wakeup_command(GAtChat *chat, const char *cmd,
unsigned int timeout, unsigned int msec)
{
+ if (chat == NULL || chat->group != 0)
+ return FALSE;
+
+ return at_chat_set_wakeup_command(chat->parent, cmd, timeout, msec);
+}
+
+guint g_at_chat_send(GAtChat *chat, const char *cmd,
+ const char **prefix_list, GAtResultFunc func,
+ gpointer user_data, GDestroyNotify notify)
+{
+ return at_chat_send_common(chat->parent, chat->group,
+ cmd, prefix_list, FALSE, NULL,
+ func, user_data, notify);
+}
+
+guint g_at_chat_send_listing(GAtChat *chat, const char *cmd,
+ const char **prefix_list,
+ GAtNotifyFunc listing, GAtResultFunc func,
+ gpointer user_data, GDestroyNotify notify)
+{
+ if (listing == NULL)
+ return 0;
+
+ return at_chat_send_common(chat->parent, chat->group,
+ cmd, prefix_list, FALSE,
+ listing, func, user_data, notify);
+}
+
+guint g_at_chat_send_pdu_listing(GAtChat *chat, const char *cmd,
+ const char **prefix_list,
+ GAtNotifyFunc listing, GAtResultFunc func,
+ gpointer user_data, GDestroyNotify notify)
+{
+ if (listing == NULL)
+ return 0;
+
+ return at_chat_send_common(chat->parent, chat->group,
+ cmd, prefix_list, TRUE,
+ listing, func, user_data, notify);
+}
+
+gboolean g_at_chat_cancel(GAtChat *chat, guint id)
+{
+ /* We use id 0 for wakeup commands */
+ if (chat == NULL || id == 0)
+ return FALSE;
+
+ return at_chat_cancel(chat->parent, chat->group, id);
+}
+
+gboolean g_at_chat_cancel_all(GAtChat *chat)
+{
if (chat == NULL)
return FALSE;
- if (chat->wakeup)
- g_free(chat->wakeup);
+ return at_chat_cancel_group(chat->parent, chat->group);
+}
- chat->wakeup = g_strdup(cmd);
- chat->inactivity_time = (gdouble)msec / 1000;
- chat->wakeup_timeout = timeout;
+guint g_at_chat_register(GAtChat *chat, const char *prefix,
+ GAtNotifyFunc func, gboolean expect_pdu,
+ gpointer user_data,
+ GDestroyNotify destroy_notify)
+{
+ if (chat == NULL)
+ return 0;
- return TRUE;
+ return at_chat_register(chat->parent, chat->group, prefix,
+ func, expect_pdu, user_data, destroy_notify);
+}
+
+gboolean g_at_chat_unregister(GAtChat *chat, guint id)
+{
+ if (chat == NULL)
+ return FALSE;
+
+ return at_chat_unregister(chat->parent, chat->group, id);
+}
+
+gboolean g_at_chat_unregister_all(GAtChat *chat)
+{
+ if (chat == NULL)
+ return FALSE;
+
+ return at_chat_unregister_group(chat->parent, chat->group);
}