[PATCH] MO routing: smsbox-route with keywords

Stipe Tolj <[email protected]>
Newsgroups gmane.comp.mobile.kannel.devel
Organization tolj.org system architecture
Message-ID <[email protected]>
Hi list,

please find attached a patch against current CVS HEAD to add support for
keyword/alias based smsbox instance MO routing.

This patch was provided by a user. Unfortunately I can't recall which one it
was, so please feel free to "recall me" on this, so the appropriate people get
their credits in the ChangeLog. :)

What it allows is using this for bearerbox's MO routing towards a connected
smsbox instance:

  group = smsbox-route
  ...
  keyword = <keyword>
  aliases = "<alias1>;<alias2>;...;<aliasN>"
  smsbox-id = foobar

which will ensure (in combination if used with the other 2 directives, 'smsc-id'
and 'shortcode') that any MO with the associated keywords are routed to the
'smsbox-id' identified smsbox instance.

Please review and vote for commit to CVS.

Stipe

-- 
-------------------------------------------------------------------
Kölner Landstrasse 419
40589 DÃŒsseldorf, NRW, Germany

tolj.org system architecture      Kannel Software Foundation (KSF)
http://www.tolj.org/              http://www.kannel.org/

mailto:st_{at}_tolj.org           mailto:stolj_{at}_kannel.org
-------------------------------------------------------------------
smsbox-route-keyword.diff (text/plain, 16 KB)
### Eclipse Workspace Patch 1.0
#P gateway-cvs-head
Index: doc/userguide/userguide.xml
===================================================================
RCS file: /home/cvs/gateway/doc/userguide/userguide.xml,v
retrieving revision 1.342
diff -u -r1.342 userguide.xml
--- doc/userguide/userguide.xml	7 Nov 2008 08:46:08 -0000	1.342
+++ doc/userguide/userguide.xml	18 Nov 2008 21:47:16 -0000
@@ -5596,6 +5596,32 @@
 		  the connections in the smsc-id are matched against the shortcode list.
      </entry></row>
 
+	 <row><entry><literal>keyword</literal></entry>
+     <entry>word</entry>
+     <entry valign="bottom">
+        If set, specifies which keyword for inbound messages should
+		  be routed to this smsbox instance. Value contains a single keyword.
+		  This rule may be used to pull keyword specific message streams 
+		  to an smsbox instance. If used in combination
+		  with config directive smsc-id and/or shortcode, then only messages 
+		  originating from the connections in the smsc-id and/or with shortcode
+		  destination address are matched against this keyword. If you need to
+		  apply the same rule for several keywords, then the 
+		  <literal>aliases</literal> directive can be used.
+     </entry></row>
+
+	 <row><entry><literal>aliases</literal></entry>
+     <entry>word-list</entry>
+     <entry valign="bottom">
+        If set, specifies which keyword for inbound messages should
+		  be routed to this smsbox instance. List contains keywords seperated.
+		  by semicolon (";"). This rule may be used to pull keyword 
+		  specific message streams to an smsbox instance. If used in combination
+		  with config directive smsc-id and/or shortcode, then only messages 
+		  originating from the connections in the smsc-id and/or with shortcode
+		  destination address are matched against these keyword aliases.
+     </entry></row>
+
   </tbody>
   </tgroup>
  </table>
Index: gwlib/cfg.def
===================================================================
RCS file: /home/cvs/gateway/gwlib/cfg.def,v
retrieving revision 1.134
diff -u -r1.134 cfg.def
--- gwlib/cfg.def	26 Jul 2008 09:21:17 -0000	1.134
+++ gwlib/cfg.def	18 Nov 2008 21:47:19 -0000
@@ -287,6 +287,8 @@
     OCTSTR(smsbox-id)
     OCTSTR(smsc-id)
     OCTSTR(shortcode)
+    OCTSTR(keyword)
+    OCTSTR(aliases)
 )
 
 
Index: gw/bb_boxc.c
===================================================================
RCS file: /home/cvs/gateway/gw/bb_boxc.c,v
retrieving revision 1.91
diff -u -r1.91 bb_boxc.c
--- gw/bb_boxc.c	9 Jan 2008 20:06:58 -0000	1.91
+++ gw/bb_boxc.c	18 Nov 2008 21:47:18 -0000
@@ -64,6 +64,7 @@
  * Alexander Malysh (various fixes)
  */
 
+#include <ctype.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -111,6 +112,8 @@
 static Dict *smsbox_by_smsc;
 static Dict *smsbox_by_receiver;
 static Dict *smsbox_by_smsc_receiver;
+static Dict *smsbox_by_keyword_smsc_receiver;
+static Dict *smsbox_by_keyword_smsc;
 
 static long	smsbox_port;
 static int smsbox_port_ssl;
@@ -983,6 +986,10 @@
     smsbox_by_receiver = NULL;
     dict_destroy(smsbox_by_smsc_receiver);
     smsbox_by_smsc_receiver = NULL;
+    dict_destroy(smsbox_by_keyword_smsc_receiver);
+    smsbox_by_keyword_smsc_receiver = NULL;
+    dict_destroy(smsbox_by_keyword_smsc);
+    smsbox_by_keyword_smsc = NULL;
     
     gwlist_remove_producer(flow_threads);
 }
@@ -997,7 +1004,7 @@
     port = (int) *((long*)arg);
     
     fd = make_server_socket(port, NULL);
-    	/* XXX add interface_name if required */
+    /* XXX add interface_name if required */
 
     if (fd < 0) {
 	    panic(0, "Could not open wapbox port %d", port);
@@ -1009,16 +1016,13 @@
 
     gwlist_remove_producer(outgoing_wdp);
 
-
-    /* wait for all connections to die and then remove list
-     */
-    
-    while(gwlist_wait_until_nonempty(wapbox_list) == 1)
+    /* wait for all connections to die and then remove list */
+    while (gwlist_wait_until_nonempty(wapbox_list) == 1)
         gwthread_sleep(1.0);
 
     /* wait for wdp_to_wapboxes to exit */
-    while(gwlist_consume(wapbox_list)!=NULL)
-	;
+    while (gwlist_consume(wapbox_list) != NULL)
+        ;
     
     /* close listen socket */
     close(fd);   
@@ -1037,8 +1041,8 @@
 {
     CfgGroup *grp;
     List *list, *items;
-    Octstr *boxc_id, *smsc_ids, *shortcuts;
-    int i, j;
+    Octstr *boxc_id, *smsc_ids, *shortcuts, *keyword, *aliases;
+    int i, j, k;
 
     boxc_id = smsc_ids = shortcuts = NULL;
 
@@ -1063,9 +1067,15 @@
          */
         smsc_ids = cfg_get(grp, octstr_imm("smsc-id"));
         shortcuts = cfg_get(grp, octstr_imm("shortcode"));
+        keyword = cfg_get(grp, octstr_imm("keyword"));
+        aliases = cfg_get(grp, octstr_imm("aliases"));
+        if (keyword != NULL) {
+            octstr_convert_range(keyword, 0, octstr_len(keyword), tolower);
+            octstr_strip_blanks(keyword);
+        }
 
         /* consider now the 3 possibilities: */
-        if (smsc_ids && !shortcuts) {
+        if (smsc_ids && !shortcuts && !keyword) {
             /* smsc-id only, so all MO traffic */
             items = octstr_split(smsc_ids, octstr_imm(";"));
             for (i = 0; i < gwlist_len(items); i++) {
@@ -1082,7 +1092,7 @@
             gwlist_destroy(items, octstr_destroy_item);
             octstr_destroy(smsc_ids);
         }
-        else if (!smsc_ids && shortcuts) {
+        else if (!smsc_ids && shortcuts && !keyword) {
             /* shortcode only, so these MOs from all smscs */
             items = octstr_split(shortcuts, octstr_imm(";"));
             for (i = 0; i < gwlist_len(items); i++) {
@@ -1099,7 +1109,7 @@
             gwlist_destroy(items, octstr_destroy_item);
             octstr_destroy(shortcuts);
         }
-        else if (smsc_ids && shortcuts) {
+        else if (smsc_ids && shortcuts && !keyword) {
             /* both, so only specified MOs from specified smscs */
             items = octstr_split(shortcuts, octstr_imm(";"));
             for (i = 0; i < gwlist_len(items); i++) {
@@ -1128,6 +1138,126 @@
             gwlist_destroy(items, octstr_destroy_item);
             octstr_destroy(shortcuts);
         }
+        else if (smsc_ids && shortcuts && keyword && !aliases) {
+            /* all, so only specified MOs from specified smscs and with specified keyword */
+            items = octstr_split(shortcuts, octstr_imm(";"));
+            for (i = 0; i < gwlist_len(items); i++) {
+                List *subitems;
+                Octstr *item = gwlist_get(items, i);
+                octstr_strip_blanks(item);
+                subitems = octstr_split(smsc_ids, octstr_imm(";")); 
+                for (j = 0; j < gwlist_len(subitems); j++) {
+                    Octstr *subitem = gwlist_get(subitems, j);
+                    octstr_strip_blanks(subitem);
+                    
+                    debug("bb.boxc",0,"Adding smsbox routing to id <%s> "
+                          "for receiver no <%s> and smsc id <%s> and keyword <%s>",
+                          octstr_get_cstr(boxc_id), octstr_get_cstr(item),
+                          octstr_get_cstr(subitem), octstr_get_cstr(keyword));
+            
+                    /* construct the dict key '<keyword>:<shortcode>:<smsc-id>' */
+                    octstr_insert(subitem, item, 0);
+                    octstr_insert_char(subitem, octstr_len(item), ':');
+                    octstr_insert(subitem, keyword, 0);
+                    octstr_insert_char(subitem, octstr_len(keyword), ':');
+                    if (!dict_put_once(smsbox_by_keyword_smsc_receiver, subitem, octstr_duplicate(boxc_id)))
+                        panic(0, "Routing for keyword:receiver:smsc <%s> already exists!",
+                              octstr_get_cstr(subitem));
+                }
+                gwlist_destroy(subitems, octstr_destroy_item);
+            }
+            gwlist_destroy(items, octstr_destroy_item);
+            octstr_destroy(shortcuts);        		
+      	}
+      	else if (smsc_ids && shortcuts && keyword && aliases) {
+      	    /* lets add keyword to aliases list so it would be easier to parse it */
+            octstr_insert(aliases, keyword, 0);
+            octstr_insert_char(aliases, octstr_len(keyword), ';');      		
+            
+            /* all, so only specified MOs from specified smscs and with 
+             * specified keyword and/or alias */
+            items = octstr_split(shortcuts, octstr_imm(";"));
+            for (i = 0; i < gwlist_len(items); i++) {
+                List *subitems;
+                Octstr *item = gwlist_get(items, i);
+                octstr_strip_blanks(item);
+                subitems = octstr_split(smsc_ids, octstr_imm(";")); 
+                for (j = 0; j < gwlist_len(subitems); j++) {
+                    Octstr *subitem = gwlist_get(subitems, j);
+                    octstr_strip_blanks(subitem);
+                    
+                    List *subsubitems;
+                    subsubitems = octstr_split(aliases, octstr_imm(";")); 
+                    
+                    for (k = 0; k < gwlist_len(subsubitems); k++) {
+                        Octstr *subsubitem = gwlist_get(subsubitems, k);    
+                        octstr_strip_blanks(subsubitem);
+                        octstr_convert_range(subsubitem, 0, octstr_len(subsubitem), tolower);
+                                     
+                        debug("bb.boxc",0,"Adding smsbox routing to id <%s> "
+                              "for receiver no <%s> and smsc id <%s> and keyword/alias <%s>",
+                              octstr_get_cstr(boxc_id), octstr_get_cstr(item),
+                              octstr_get_cstr(subitem), octstr_get_cstr(subsubitem));
+                             
+                        /* construct the dict key '<keyword>:<shortcode>:<smsc-id>' */
+                        Octstr *dictitem = octstr_duplicate(subitem);
+                        octstr_insert(dictitem, item, 0);
+                        octstr_insert_char(dictitem, octstr_len(item), ':');
+                        octstr_insert(dictitem, subsubitem, 0);
+                        octstr_insert_char(dictitem, octstr_len(subsubitem), ':');                    
+                                                                 
+                        debug("bb.boxc",0,"Adding smsbox routing <%s> ",
+                              octstr_get_cstr(dictitem));
+                                     
+                        if (!dict_put_once(smsbox_by_keyword_smsc_receiver, dictitem, 
+                                           octstr_duplicate(boxc_id)))
+                            panic(0, "Routing for keyword:receiver:smsc <%s> already exists!",
+                                  octstr_get_cstr(dictitem));                           
+                    }                                        
+                    gwlist_destroy(subsubitems, octstr_destroy_item);
+                }
+                gwlist_destroy(subitems, octstr_destroy_item);
+            }
+            gwlist_destroy(items, octstr_destroy_item);
+            octstr_destroy(shortcuts);        		
+      	}
+      	else if (smsc_ids && !shortcuts && keyword && aliases) {
+      	    /* lets add keyword to aliases list so it would be easier to parse it */
+            octstr_insert(aliases, keyword, 0);
+            octstr_insert_char(aliases, octstr_len(keyword), ';');      		
+            
+            /* both, so only specified MOs from specified smscs */
+            items = octstr_split(aliases, octstr_imm(";"));
+            for (i = 0; i < gwlist_len(items); i++) {
+                List *subitems;
+                Octstr *item = gwlist_get(items, i);
+                octstr_strip_blanks(item);
+                subitems = octstr_split(smsc_ids, octstr_imm(";")); 
+                for (j = 0; j < gwlist_len(subitems); j++) {
+                    Octstr *subitem = gwlist_get(subitems, j);
+                    octstr_strip_blanks(subitem);
+                    
+                    debug("bb.boxc",0,"Adding smsbox routing to id <%s> "
+                          "for smsc-id <%s> and smsc id <%s>",
+                          octstr_get_cstr(boxc_id), octstr_get_cstr(item),
+                          octstr_get_cstr(subitem));
+            
+                    /* construct the dict key '<keyword>:<smsc-id>' */
+                    octstr_insert(subitem, item, 0);
+                    octstr_insert_char(subitem, octstr_len(item), ':');
+
+                    debug("bb.boxc", 0, "Routing for keyword:smsc <%s> already exists!",
+                    octstr_get_cstr(subitem));
+                    
+                    if (!dict_put_once(smsbox_by_keyword_smsc, subitem, octstr_duplicate(boxc_id)))
+                        panic(0, "Routing for receiver:smsc <%s> already exists!",
+                              octstr_get_cstr(subitem));
+                }
+                gwlist_destroy(subitems, octstr_destroy_item);
+            }
+            gwlist_destroy(items, octstr_destroy_item);
+            octstr_destroy(shortcuts);
+      	}
         octstr_destroy(boxc_id);
     }
 
@@ -1176,6 +1306,8 @@
     smsbox_by_smsc = dict_create(30, (void(*)(void *)) octstr_destroy);
     smsbox_by_receiver = dict_create(50, (void(*)(void *)) octstr_destroy);
     smsbox_by_smsc_receiver = dict_create(50, (void(*)(void *)) octstr_destroy);
+    smsbox_by_keyword_smsc_receiver = dict_create(50, (void(*)(void *)) octstr_destroy);
+    smsbox_by_keyword_smsc = dict_create(50, (void(*)(void *)) octstr_destroy);
 
     /* load the defined smsbox routing rules */
     init_smsbox_routes(cfg);
@@ -1415,9 +1547,12 @@
 int route_incoming_to_boxc(Msg *msg)
 {
     Boxc *bc = NULL, *best = NULL;
-    Octstr *s, *r, *rs;
+    Octstr *s, *r, *rs, *krs;
     long len, b, i;
     int full_found = 0;
+    List *word_list;
+    int num_words;
+    Octstr *keyword;
 
     s = r = NULL;
     gw_assert(msg_type(msg) == sms);
@@ -1458,6 +1593,38 @@
          * Where the shortcode route has a higher priority then the smsc-id rule.
          * Highest priority has the combined <shortcode>:<smsc-id> route.
          */
+        
+        if (msg->sms.msgdata && octstr_len(msg->sms.msgdata)) {
+            word_list = octstr_split_words(msg->sms.msgdata);
+            num_words = gwlist_len(word_list);
+            word_list = octstr_split_words(msg->sms.msgdata);
+            num_words = gwlist_len(word_list);
+        } else {
+            word_list = gwlist_create();
+            num_words = 0;
+        }
+       
+        if (num_words >= 1) {
+            keyword = octstr_duplicate(gwlist_get(word_list, 0));
+            Octstr *kos = octstr_format("%s:%s:%s", 
+                                   octstr_get_cstr(keyword),
+                                   octstr_get_cstr(msg->sms.receiver),
+                                   octstr_get_cstr(msg->sms.smsc_id));          
+            krs = (kos ? dict_get(smsbox_by_keyword_smsc_receiver, kos) : NULL);
+            octstr_destroy(kos);
+            if (!krs) {
+                Octstr *ks = octstr_format("%s:%s", 
+                                   octstr_get_cstr(keyword),
+                                   octstr_get_cstr(msg->sms.smsc_id));                          
+                krs = (ks ? dict_get(smsbox_by_keyword_smsc, ks) : NULL);
+                octstr_destroy(ks);
+            }
+        } else {
+            krs = NULL;
+        }
+                
+        gwlist_destroy(word_list, octstr_destroy_item);
+        
         Octstr *os = octstr_format("%s:%s", 
                                    octstr_get_cstr(msg->sms.receiver),
                                    octstr_get_cstr(msg->sms.smsc_id));
@@ -1465,8 +1632,10 @@
         r = (msg->sms.receiver ? dict_get(smsbox_by_receiver, msg->sms.receiver) : NULL);
         rs = (os ? dict_get(smsbox_by_smsc_receiver, os) : NULL);
         octstr_destroy(os); 
-        bc = rs ? dict_get(smsbox_by_id, rs) : 
-            (r ? dict_get(smsbox_by_id, r) : (s ? dict_get(smsbox_by_id, s) : NULL));
+        bc = krs ? dict_get(smsbox_by_id, krs) : (
+                rs ? dict_get(smsbox_by_id, rs) :
+                    (r ? dict_get(smsbox_by_id, r) : (s ? dict_get(smsbox_by_id, s) : NULL))
+             );
     }
 
     /* check if we found our routing */
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.