Index: gwlib/cfg.def
===================================================================
--- gwlib/cfg.def	(revision 4833)
+++ gwlib/cfg.def	(working copy)
@@ -293,6 +293,13 @@
 )
 
 
+MULTI_GROUP(smsbox-route-between,
+    OCTSTR(smsbox-id1)
+    OCTSTR(smsbox-id2)
+    OCTSTR(shortcode)
+)
+
+
 MULTI_GROUP(smsc,
     OCTSTR(smsc)
     OCTSTR(smsc-id)
Index: gw/bb_boxc.c
===================================================================
--- gw/bb_boxc.c	(revision 4833)
+++ gw/bb_boxc.c	(working copy)
@@ -111,6 +111,8 @@
 static Dict *smsbox_by_smsc;
 static Dict *smsbox_by_receiver;
 static Dict *smsbox_by_smsc_receiver;
+static Dict *smsbox2_by_boxc;
+static Dict *smsbox2_by_boxc_receiver;
 
 static long	smsbox_port;
 static int smsbox_port_ssl;
@@ -273,7 +275,34 @@
     msg_destroy(mack);
 }
 
+static int route_to_smsbox(Msg *msg)
+{
+    Octstr *id, *os;
+    List *boxlist;
+    Boxc *conn;
 
+    os = octstr_format("%s:%s",
+         octstr_get_cstr(msg->sms.receiver),
+         octstr_get_cstr(msg->sms.boxc_id));
+    id = dict_get(smsbox2_by_boxc_receiver, os);
+    octstr_destroy(os);
+
+    if (!id) {
+	id = dict_get(smsbox2_by_boxc, msg->sms.boxc_id);
+    }
+
+    if (id) {
+	boxlist = dict_get(smsbox_by_id, id);
+	if (NULL != boxlist && gwlist_len(boxlist) > 0) {
+	    conn = gwlist_get(boxlist, 0);
+	    gwlist_produce(conn->incoming, msg);
+	    return 1;
+	}
+    }
+
+    return 0;
+}
+
 static void boxc_receiver(void *arg)
 {
     Boxc *conn = arg;
@@ -306,14 +335,16 @@
         if (msg_type(msg) == sms && conn->is_wap == 0) {
             debug("bb.boxc", 0, "boxc_receiver: sms received");
 
-            /* deliver message to queue */
-            deliver_sms_to_queue(msg, conn);
+	    if (!route_to_smsbox(msg)) {
+            	/* deliver message to queue */
+            	deliver_sms_to_queue(msg, conn);
 
-            if (conn->routable == 0) {
-                conn->routable = 1;
-                /* wakeup the dequeue thread */
-                gwthread_wakeup(sms_dequeue_thread);
-            }
+                if (conn->routable == 0) {
+                    conn->routable = 1;
+                    /* wakeup the dequeue thread */
+                    gwthread_wakeup(sms_dequeue_thread);
+                }
+	    }
         } else if (msg_type(msg) == wdp_datagram && conn->is_wap) {
             debug("bb.boxc", 0, "boxc_receiver: got wdp from wapbox");
 
@@ -1044,6 +1075,10 @@
     smsbox_by_receiver = NULL;
     dict_destroy(smsbox_by_smsc_receiver);
     smsbox_by_smsc_receiver = NULL;
+    dict_destroy(smsbox2_by_boxc);
+    smsbox2_by_boxc = NULL;
+    dict_destroy(smsbox2_by_boxc_receiver);
+    smsbox2_by_boxc_receiver = NULL;
 
     gwlist_remove_producer(flow_threads);
 }
@@ -1196,6 +1231,96 @@
 }
 
 
+/*
+ * Populates the corresponding smsbox_by_foobar dictionary hash tables
+ */
+static void init_smsbox_between_routes(Cfg *cfg)
+{
+    CfgGroup *grp;
+    List *list, *items;
+    Octstr *boxc_id1, *boxc_id2, *shortcuts, *subitem;
+    int i, j;
+
+    boxc_id1 = boxc_id2 = shortcuts = NULL;
+
+    list = cfg_get_multi_group(cfg, octstr_imm("smsbox-route-between"));
+
+    /* loop multi-group "smsbox-route" */
+    while (list && (grp = gwlist_extract_first(list)) != NULL) {
+
+        if ((boxc_id1 = cfg_get(grp, octstr_imm("smsbox-id1"))) == NULL) {
+            grp_dump(grp);
+            panic(0,"'smsbox-route-between' group without valid 'smsbox-id1' directive!");
+        }
+
+        if ((boxc_id2 = cfg_get(grp, octstr_imm("smsbox-id2"))) == NULL) {
+            grp_dump(grp);
+            panic(0,"'smsbox-route-between' group without valid 'smsbox-id2' directive!");
+        }
+
+        shortcuts = cfg_get(grp, octstr_imm("shortcode"));
+
+        /* consider now the 2 possibilities: */
+        if (!shortcuts) {
+            /* smsbox-id2 only, so all MO traffic */
+                debug("bb.boxc",0,"Adding smsbox between routing to id <%s> for box <%s>",
+                      octstr_get_cstr(boxc_id1), octstr_get_cstr(boxc_id2));
+
+                if (!dict_put_once(smsbox2_by_boxc, boxc_id1, octstr_duplicate(boxc_id2)))
+                    panic(0, "Routing for smsbox-id <%s> already exists!",
+                          octstr_get_cstr(boxc_id2));
+
+                debug("bb.boxc",0,"Adding smsbox between routing to id <%s> for box <%s>",
+                      octstr_get_cstr(boxc_id2), octstr_get_cstr(boxc_id1));
+                if (!dict_put_once(smsbox2_by_boxc, boxc_id2, octstr_duplicate(boxc_id1)))
+                    panic(0, "Routing for smsbox-id <%s> already exists!",
+                          octstr_get_cstr(boxc_id1));
+        }
+        else {
+            /* both, so only specified MOs from specified smscs */
+            items = octstr_split(shortcuts, octstr_imm(";"));
+            for (i = 0; i < gwlist_len(items); i++) {
+                Octstr *item = gwlist_get(items, i);
+                octstr_strip_blanks(item);
+
+                debug("bb.boxc",0,"Adding smsbox routing between to id <%s> "
+                      "for receiver no <%s> and box <%s>",
+                  octstr_get_cstr(boxc_id1), octstr_get_cstr(item),
+                  octstr_get_cstr(boxc_id2));
+
+		subitem = octstr_duplicate(boxc_id2);
+                /* construct the dict key '<shortcode>:<boxc-id>' */
+                octstr_insert(subitem, item, 0);
+                octstr_insert_char(subitem, octstr_len(item), ':');
+                if (!dict_put_once(smsbox2_by_boxc_receiver, subitem, octstr_duplicate(boxc_id1)))
+                    panic(0, "Routing for receiver:box <%s> already exists!",
+                          octstr_get_cstr(subitem));
+		octstr_destroy(subitem);
+
+                debug("bb.boxc",0,"Adding smsbox routing between to id <%s> "
+                      "for receiver no <%s> and box <%s>",
+                  octstr_get_cstr(boxc_id2), octstr_get_cstr(item),
+                  octstr_get_cstr(boxc_id1));
+                /* construct the dict key '<shortcode>:<boxc-id>' */
+		subitem = octstr_duplicate(boxc_id1);
+                octstr_insert(subitem, item, 0);
+                octstr_insert_char(subitem, octstr_len(item), ':');
+                if (!dict_put_once(smsbox2_by_boxc_receiver, subitem, octstr_duplicate(boxc_id2)))
+                    panic(0, "Routing for receiver:box <%s> already exists!",
+                          octstr_get_cstr(subitem));
+		octstr_destroy(subitem);
+            }
+            gwlist_destroy(items, octstr_destroy_item);
+            octstr_destroy(shortcuts);
+        }
+        octstr_destroy(boxc_id1);
+        octstr_destroy(boxc_id2);
+    }
+
+    gwlist_destroy(list, NULL);
+}
+
+
 /*-------------------------------------------------------------
  * public functions
  *
@@ -1238,8 +1363,12 @@
     smsbox_by_receiver = dict_create(50, (void(*)(void *)) octstr_destroy);
     smsbox_by_smsc_receiver = dict_create(50, (void(*)(void *)) octstr_destroy);
 
+    smsbox2_by_boxc = dict_create(10, (void(*)(void *)) octstr_destroy);
+    smsbox2_by_boxc_receiver = dict_create(50, (void(*)(void *)) octstr_destroy);
+
     /* load the defined smsbox routing rules */
     init_smsbox_routes(cfg);
+    init_smsbox_between_routes(cfg);
 
     gwlist_add_producer(outgoing_sms);
     gwlist_add_producer(smsbox_list);
