---
 gatchat/gatserver.c |  103 +++++++++++++++++++++++++++-----------------------
 1 files changed, 56 insertions(+), 47 deletions(-)

diff --git a/gatchat/gatserver.c b/gatchat/gatserver.c
index c75fbf5..07999a8 100644
--- a/gatchat/gatserver.c
+++ b/gatchat/gatserver.c
@@ -112,6 +112,8 @@ struct _GAtServer {
        guint max_read_attempts;                /* Max reads per select */
        enum ParserState parser_state;
        gboolean destroyed;                     /* Re-entrancy guard */
+       char *read_line;                        /* Current read line */
+       unsigned int read_pos;                  /* Current read offset */
 };
 
 static void g_at_server_wakeup_writer(GAtServer *server);
@@ -215,7 +217,7 @@ static void at_command_notify(GAtServer *server, char 
*command,
        g_slist_free(result.lines);
 }
 
-static unsigned int parse_extended_command(GAtServer *server, char *buf)
+static void parse_extended_command(GAtServer *server, char *buf)
 {
        const char *valid_extended_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                                                "0123456789!%-./:_";
@@ -230,7 +232,7 @@ static unsigned int parse_extended_command(GAtServer 
*server, char *buf)
        prefix_len = strcspn(buf, separators);
 
        if (prefix_len > 17 || prefix_len < 2)
-               return 0;
+               goto error;
 
        /* Convert to upper case, we will always use upper case naming */
        for (i = 0; i < prefix_len; i++)
@@ -239,17 +241,17 @@ static unsigned int parse_extended_command(GAtServer 
*server, char *buf)
        prefix[prefix_len] = '\0';
 
        if (strspn(prefix + 1, valid_extended_chars) != (prefix_len - 1))
-               return 0;
+               goto error;
 
        /*
         * V.250 Section 5.4.1: "The first character following "+" shall be
         * an alphabetic character in the range "A" through "Z".
         */
        if (prefix[1] <= 'A' || prefix[1] >= 'Z')
-               return 0;
+               goto error;
 
        if (buf[i] != '\0' && buf[i] != ';' && buf[i] != '?' && buf[i] != '=')
-               return 0;
+               goto error;
 
        type = G_AT_SERVER_REQUEST_TYPE_COMMAND_ONLY;
 
@@ -265,16 +267,16 @@ static unsigned int parse_extended_command(GAtServer 
*server, char *buf)
 
                if (buf[i] == '?') {
                        if (seen_question || seen_equals)
-                               return 0;
+                               goto error;
 
                        if (buf[i + 1] != '\0' && buf[i + 1] != ';')
-                               return 0;
+                               goto error;
 
                        seen_question = TRUE;
                        type = G_AT_SERVER_REQUEST_TYPE_QUERY;
                } else if (buf[i] == '=') {
                        if (seen_equals || seen_question)
-                               return 0;
+                               goto error;
 
                        seen_equals = TRUE;
 
@@ -291,10 +293,15 @@ next:
        /* We can scratch in this buffer, so mark ';' as null */
        buf[i] = '\0';
 
+       /* Also consume the terminating null */
+       server->read_pos += i + 1;
+
        at_command_notify(server, buf, prefix, type);
 
-       /* Also consume the terminating null */
-       return i + 1;
+       return;
+
+error:
+       g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
 }
 
 static int get_basic_prefix_size(const char *buf)
@@ -336,16 +343,20 @@ static int get_basic_prefix_size(const char *buf)
        return 0;
 }
 
-static unsigned int parse_basic_command(GAtServer *server, char *buf)
+static void parse_basic_command(GAtServer *server, char *buf)
 {
        gboolean seen_equals = FALSE;
        char prefix[4], tmp;
-       unsigned int i, prefix_size;
+       unsigned int i, prefix_size, end;
        GAtServerRequestType type;
 
        prefix_size = get_basic_prefix_size(buf);
        if (prefix_size == 0)
-               return 0;
+               goto error;
+
+       /* Handle S-parameter with 100+ */
+       if (prefix_size > 3)
+               goto error;
 
        i = prefix_size;
        prefix[0] = g_ascii_toupper(buf[0]);
@@ -390,33 +401,39 @@ static unsigned int parse_basic_command(GAtServer 
*server, char *buf)
        }
 
 done:
-       if (prefix_size <= 3) {
-               memcpy(prefix + 1, buf + 1, prefix_size - 1);
-               prefix[prefix_size] = '\0';
-
-               tmp = buf[i];
-               buf[i] = '\0';
-               at_command_notify(server, buf, prefix, type);
-               buf[i] = tmp;
-       } else /* Handle S-parameter with 100+ */
-               g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
+       end = i;
 
        /* Commands like ATA, ATZ cause the remainder line
         * to be ignored.
         */
        if (prefix[0] == 'A' || prefix[0] == 'Z')
-               return strlen(buf);
+               i = strlen(buf);
 
        /* Consume the seperator ';' */
        if (buf[i] == ';')
                i += 1;
 
-       return i;
+       /* Update read offset before notify the callback */
+       server->read_pos += i;
+
+       memcpy(prefix + 1, buf + 1, prefix_size - 1);
+       prefix[prefix_size] = '\0';
+
+       tmp = buf[end];
+       buf[end] = '\0';
+       at_command_notify(server, buf, prefix, type);
+       buf[end] = tmp;
+
+       return;
+
+error:
+       g_at_server_send_final(server, G_AT_SERVER_RESULT_ERROR);
 }
 
-static void server_parse_line(GAtServer *server, char *line)
+static void server_parse_line(GAtServer *server)
 {
-       unsigned int pos = 0;
+       char *line = server->read_line;
+       unsigned int pos = server->read_pos;
        unsigned int len = strlen(line);
 
        if (len == 0) {
@@ -424,22 +441,10 @@ static void server_parse_line(GAtServer *server, char 
*line)
                return;
        }
 
-       while (pos < len) {
-               unsigned int consumed;
-
-               if (is_extended_command_prefix(line[pos]))
-                       consumed = parse_extended_command(server, line + pos);
-               else
-                       consumed = parse_basic_command(server, line + pos);
-
-               if (consumed == 0) {
-                       g_at_server_send_final(server,
-                                               G_AT_SERVER_RESULT_ERROR);
-                       break;
-               }
-
-               pos += consumed;
-       }
+       if (is_extended_command_prefix(line[pos]))
+               parse_extended_command(server, line + pos);
+       else
+               parse_basic_command(server, line + pos);
 }
 
 static enum ParserResult server_feed(GAtServer *server,
@@ -621,11 +626,13 @@ static void new_bytes(GAtServer *p)
 
                case PARSER_RESULT_COMMAND:
                {
-                       char *line = extract_line(p);
+                       g_free(p->read_line);
 
-                       if (line) {
-                               server_parse_line(p, line);
-                               g_free(line);
+                       p->read_line = extract_line(p);
+                       if (p->read_line) {
+                               p->read_pos = 0;
+
+                               server_parse_line(p);
                        } else
                                g_at_server_send_final(p,
                                                G_AT_SERVER_RESULT_ERROR);
@@ -795,6 +802,8 @@ static void g_at_server_cleanup(GAtServer *server)
        g_hash_table_destroy(server->command_list);
        server->command_list = NULL;
 
+       g_free(server->read_line);
+
        server->channel = NULL;
 }
 
-- 
1.6.6.1

_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono

Reply via email to