Fwd: [PATCH] CMTI support for AT2

Stipe Tolj <[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Organization Wapme Systems AG
Message-ID <[email protected]>
Hi list,

this is a pending patch from "Rene Kluwen" <[email protected]>. 

It's a bit older, so don't blame me if it does not apply cleanly ;)

Can somebody who uses AT2 module a lot check this and vote for
commitment please?! Oded, how about you?!

Stipe

[email protected]
-------------------------------------------------------------------
Wapme Systems AG

Vogelsanger Weg 80
40470 Düsseldorf

Tel: +49-211-74845-0
Fax: +49-211-74845-299

E-Mail: [email protected]
Internet: http://www.wapme-systems.de
-------------------------------------------------------------------
wapme.net - wherever you are
cmti_cdsi.patch (text/plain, 12 KB)
Index: gw/smsc/smsc_at2.c
===================================================================
RCS file: /home/cvs/gateway/gw/smsc/smsc_at2.c,v
retrieving revision 1.12
diff -u -r1.12 smsc_at2.c
--- gw/smsc/smsc_at2.c	25 Nov 2002 16:29:27 -0000	1.12
+++ gw/smsc/smsc_at2.c	9 Dec 2002 17:00:18 -0000
@@ -458,14 +458,7 @@
 
     if (privdata->sms_memory_poll_interval && privdata->modem->message_storage) {
         /* set message storage location for "SIM buffering" using the CPMS command */
-        Octstr *temp;
-        temp = octstr_create("AT+CPMS=");
-        octstr_append_char(temp, 34);
-        octstr_append(temp, privdata->modem->message_storage);
-        octstr_append_char(temp, 34);
-        ret = at2_send_modem_command(privdata, octstr_get_cstr(temp), 0, 0);
-        octstr_destroy(temp);
-        if (ret != 0)
+        if (at2_set_message_storage(privdata, privdata->modem->message_storage) != 0)
             return -1;
     }
 
@@ -535,6 +528,16 @@
                 ret = 1;
                 goto end;
             }
+	    if (octstr_search(line, octstr_imm("+CMTI:"), 0) != -1 || 
+	        octstr_search(line, octstr_imm("+CDSI:"), 0) != -1) {
+		/*
+		   we received an incoming message indication
+		   put it in the pending_incoming_messages queue for later retrieval
+		*/
+		debug("bb.smsc.at2", 0, "AT2[%s]: +CMTI incoming SMS indication: %s", octstr_get_cstr(privdata->name), octstr_get_cstr(line));
+		list_append(privdata->pending_incoming_messages, (void *)octstr_create(octstr_get_cstr(line)));
+                continue;
+	    }
             if (octstr_search(line, octstr_imm("+CMT:"), 0) != -1 ||
 		octstr_search(line, octstr_imm("+CDS:"), 0) != -1 ||
                 ((octstr_search(line, octstr_imm("+CMGR:"), 0) != -1) && (cmgr_flag = 1)) ) {
@@ -609,11 +612,132 @@
     return ret;
 }
 
-
-void at2_read_sms_memory(PrivAT2data* privdata)
+int at2_read_delete_message(PrivAT2data* privdata, int message_number)
 {
     char cmd[20];
+    int message_count = 0;
+
+    sprintf(cmd, "AT+CMGR=%d", message_number);
+    /* read one message from memory */
+    at2_write_line(privdata, cmd);
+    if (at2_wait_modem_command(privdata, 0, 0, &message_count) != 0) {
+	debug("bb.smsc.at2", 0, "AT2[%s]: failed to get message %d.", 
+	    octstr_get_cstr(privdata->name), message_number);
+        return 0; /* failed to read the message - skip to next message */
+    }
+
+    /* no need to delete if no message collected */
+    if (!message_count) { 
+	debug("bb.smsc.at2", 0, "AT2[%s]: not deleted.", 
+	    octstr_get_cstr(privdata->name));
+        return 0;
+    }
+
+    sprintf(cmd, "AT+CMGD=%d", message_number); /* delete the message we just read */
+    /* 
+    * 3 seconds (default timeout of send_modem_command()) is not enough with some
+    * modems if the message is large, so we'll give it 7 seconds 
+    */
+    if (at2_send_modem_command(privdata, cmd, 7, 0) != 0) {  
+	/* 
+	* failed to delete the message, we'll just ignore it for now, 
+	* this is bad, since if the message really didn't get deleted
+	* we'll see it next time around. 
+	*/                
+        error(2, "AT2[%s]: failed to delete message %d.",
+	    octstr_get_cstr(privdata->name), message_number);
+    }
 
+    return 1;
+}
+
+/*
+ * This function loops through the pending_incoming_messages queue for CMTI
+ * notifications.
+ * Every notification is parsed and the messages are read (and deleted)
+ * accordingly.
+*/
+void at2_read_pending_incoming_messages(PrivAT2data* privdata)
+{
+    Octstr *current_storage = NULL;
+
+    if (privdata->modem->message_storage) {
+	    current_storage = octstr_duplicate(privdata->modem->message_storage);
+    }
+    while (list_len(privdata->pending_incoming_messages) > 0) {
+        int pos;
+        long location;
+        Octstr *cmti_storage = NULL, *line = NULL;
+        
+        line = list_extract_first(privdata->pending_incoming_messages);
+	/* message memory starts after the first quote in the string */
+        if ((pos = octstr_search_char(line, '"', 0)) != -1) {
+            /* grab memory storage name */
+            int next_quote = octstr_search_char(line, '"', ++pos);
+            if (next_quote == -1) { /* no second qoute - this line must be broken somehow */
+                O_DESTROY(line);
+                continue;
+	    }
+
+            /* store notification storage location for reference */
+            cmti_storage = octstr_copy(line, pos, next_quote - pos);
+        } else
+            /* reset pos for the next lookup which would start from the beginning if no memory
+             * location was found */
+            pos = 0; 
+
+        /* if no message storage is set in configuration - set now */
+        if (!privdata->modem->message_storage && cmti_storage) { 
+            info(2, "AT2[%s]: CMTI received, but no message-storage is set in confiuration."
+                "setting now to <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(cmti_storage));
+            privdata->modem->message_storage = octstr_duplicate(cmti_storage);
+            current_storage = octstr_duplicate(cmti_storage);
+            at2_set_message_storage(privdata, cmti_storage);
+	}
+
+        /* find the message id from the line, which should appear after the first comma */
+        if ((pos = octstr_search_char(line, ',', pos)) == -1) { /* this CMTI notification is probably broken */
+            error(2, "AT2[%s]: failed to find memory location in CMTI notification",
+                octstr_get_cstr(privdata->name));
+		O_DESTROY(line);
+		octstr_destroy(cmti_storage);
+            continue;
+        }
+
+        if ((pos = octstr_parse_long(&location, line, ++pos, 10)) == -1) {
+            /* there was an error parsing the message id. next! */
+            error(2, "AT2[%s]: error parsing memory location in CMTI notification",
+                octstr_get_cstr(privdata->name));
+		O_DESTROY(line);
+		octstr_destroy(cmti_storage);
+            continue;
+        }
+
+        /* check if we need to change storage location before issuing the read command */
+        if (!current_storage || (octstr_compare(current_storage, cmti_storage) != 0)) {
+	    octstr_destroy(current_storage);
+	    current_storage = octstr_duplicate(cmti_storage);
+            at2_set_message_storage(privdata, cmti_storage);
+	}
+        
+        if (!at2_read_delete_message(privdata, location)) {
+            error(1,"AT2[%s]: CMTI notification received, but no message found in memory!",
+                octstr_get_cstr(privdata->name));
+        }
+
+        
+        octstr_destroy(line);
+        octstr_destroy(cmti_storage);
+    }
+    /* set prefered message storage back to what configured */
+    if (current_storage && privdata->modem->message_storage && (octstr_compare(privdata->modem->message_storage, current_storage) != 0))
+	at2_set_message_storage(privdata, privdata->modem->message_storage);
+
+    octstr_destroy(current_storage);
+}
+
+void at2_read_sms_memory(PrivAT2data* privdata)
+{
     /* get memory status */
     if (at2_check_sms_memory(privdata) == -1) {
         debug("bb.smsc.at2", 0, "AT2[%s]: memory check error", octstr_get_cstr(privdata->name));
@@ -656,40 +780,15 @@
          * loop till end of memory or collected enouch messages
          */
         for (i = 1; i <= privdata->sms_memory_capacity &&
-             message_count < privdata->sms_memory_usage; ++i) { 
-            int old_message_count = message_count;
-            sprintf(cmd, "AT+CMGR=%d", i);
-            /* read one message from memory */
-            at2_write_line(privdata, cmd);
-            if (at2_wait_modem_command(privdata, 0, 0, &message_count) != 0) {
-                debug("bb.smsc.at2", 0, "AT2[%s]: failed to get message %d.", 
-                      octstr_get_cstr(privdata->name), i);
-                continue; /* failed to read the message - skip to next message */
-            }
-
-            /* no need to delete if no message collected */
-            if (old_message_count == message_count) { 
-                debug("bb.smsc.at2", 0, "AT2[%s]: not deleted.", 
-                      octstr_get_cstr(privdata->name));
-                continue;
-            }
-
-            sprintf(cmd, "AT+CMGD=%d", i); /* delete the message we just read */
-            /* 
-             * 3 seconds is not enough with some modems if the message is large,
-             * so we'll give it 7 seconds 
-             */
-            if (at2_send_modem_command(privdata, cmd, 7, 0) != 0) {  
-                /* 
-                 * failed to delete the message, we'll just ignore it for now, 
-                 * this is bad, since if the message really didn't get deleted
-                 * we'll see it next time around. 
-                 */                
-                debug("bb.smsc.at2", 0, "AT2[%s]: failed to delete message %d.", 
-                      octstr_get_cstr(privdata->name), i);
-                continue; 
+            message_count < privdata->sms_memory_usage; ++i) { 
 
-            }
+	    /* if (meanwhile) there are pending CMTI notifications, process these first
+	     * to not let CMTI and sim buffering sit in each others way */
+	    while (list_len(privdata->pending_incoming_messages) > 0) {
+		    at2_read_pending_incoming_messages(privdata);
+	    }
+	    /* read the message and delete it */
+            message_count += at2_read_delete_message(privdata, i);
         }
     }
     /*
@@ -918,6 +1017,10 @@
         } else
             at2_wait_modem_command(privdata, 1, 0, NULL);
 
+	while (list_len(privdata->pending_incoming_messages) > 0) {
+		at2_read_pending_incoming_messages(privdata);
+	}
+
         if (privdata->keepalive &&
             idle_timeout + privdata->keepalive < time(NULL)) {
             if (at2_send_modem_command(privdata, 
@@ -950,6 +1053,7 @@
     octstr_destroy(privdata->name);
     octstr_destroy(privdata->configfile);
     list_destroy(privdata->outgoing_queue, NULL);
+    list_destroy(privdata->pending_incoming_messages, octstr_destroy_item);
     gw_free(conn->data);
     conn->data = NULL;
     conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
@@ -1036,6 +1140,7 @@
 
     privdata = gw_malloc(sizeof(PrivAT2data));
     privdata->outgoing_queue = list_create();
+    privdata->pending_incoming_messages = list_create();
 
     privdata->configfile = cfg_get_configfile(cfg);
 
@@ -2284,4 +2389,20 @@
 
     O_DESTROY(temp);
     return out;	
+}
+
+int at2_set_message_storage(PrivAT2data* privdata, Octstr* memory_name)
+{
+    Octstr *temp;
+    int ret;
+
+    if (!memory_name || !privdata)
+        return -1;
+
+    temp = octstr_format("AT+CPMS=\"%S\"", memory_name);
+    ret = at2_send_modem_command(privdata, octstr_get_cstr(temp), 0, 0);
+    octstr_destroy(temp);
+    if (ret != 0)
+            return -1;
+    return 0;
 }
Index: gw/smsc/smsc_at2.h
===================================================================
RCS file: /home/cvs/gateway/gw/smsc/smsc_at2.h,v
retrieving revision 1.3
diff -u -r1.3 smsc_at2.h
--- gw/smsc/smsc_at2.h	25 Nov 2002 16:29:27 -0000	1.3
+++ gw/smsc/smsc_at2.h	9 Dec 2002 17:00:19 -0000
@@ -82,6 +82,7 @@
     int	sms_memory_poll_interval;
     int	sms_memory_capacity;
     int	sms_memory_usage;
+    List *pending_incoming_messages;
 } PrivAT2data;
 
 
@@ -282,6 +283,13 @@
 void at2_destroy_modem(ModemDef *modem);
 
 /*
+ * Check the pending_incoming_messages queue for CMTI notifications.
+ * Every notification is parsed and the messages are read (and deleted)
+ * accordingly.
+*/
+void at2_read_pending_incoming_messages(PrivAT2data* privdata);
+
+/*
  * Checks whether any messages are buffered in message storage and extract them.
  */
 void at2_read_sms_memory(PrivAT2data *privdata);
@@ -290,6 +298,18 @@
  * Memory capacity and usage check
  */
 int at2_check_sms_memory(PrivAT2data* privdata);
+
+/*
+ * Set the memory storage location of the modem by sending a +CPMS command
+ */
+int at2_set_message_storage(PrivAT2data* privdata, Octstr* memory_name);
+
+/*
+ * Reads a message from selected memory location and deletes it afterwards.
+ * returns 0 on failure and 1 on success
+ */
+int at2_read_delete_message(PrivAT2data* privdata, int message_number);
+
 
 /*
  * This silly thing here will just translate a "swapped nibble"
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.