Hi,
I'd still like to get this included in Kannel, it alters the behaviour
of the (old) at2 module to handle inbound SMS's better.
It probably needs rejigging to make it work with the new smsc_at stuff,
but I think it's very worthwhile and has been working here successfully
for about 6 months !!!
Maybe it could be turned into a configurable option.
Steve
--
NetTek Ltd Phone/Fax +44-(0)20 7483 2455
SMS steve-pager (at) gbnet.net [body] gpg 1024D/468952DB 2001-09-19
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"