--- gw/opensmppbox.c	2012-02-08 11:55:45.000000000 +0100
+++ /Users/aarno/opensmppbox/gw/opensmppbox.c	2012-02-16 11:42:32.000000000 +0100
@@ -76,7 +76,6 @@
 
 #include "gw/smsc/smpp_pdu.h"
 #include "gw/sms.h"
-#include "gw/dlr.h"
 #include "gw/heartbeat.h"
 #include "gw/meta_data.h"
 
@@ -84,6 +83,9 @@
 #undef GW_VERSION
 #include "../sb-config.h"
 
+#include "box-dlr.h"
+#include "gw/dlr.h"
+
 #ifdef HAVE_PAM_SECURITY
 #include <security/pam_appl.h>
 #elif defined HAVE_PAM_PAM
@@ -118,17 +120,24 @@
 
 static Octstr *smppbox_id;
 static Octstr *our_system_id;
-static Octstr *route_to_smsc;
+static Octstr *route_to_smsc = NULL;
 static time_t smpp_timeout;
 
 static int systemidisboxcid;
 static int enablepam;
 static Octstr *pamacl;
+static int usesmppboxid;
 
+static Dict *client_by_smsc;
+static Dict *client_by_receiver;
+static Dict *client_by_smsc_receiver;
 
 #define TIMEOUT_SECONDS 300
 
-typedef enum { SMPP_LOGIN_NOTLOGGEDIN, SMPP_LOGIN_TRANSMITTER, SMPP_LOGIN_RECEIVER, SMPP_LOGIN_TRANSCEIVER } smpp_login;
+typedef enum { SMPP_LOGIN_NOTLOGGEDIN, SMPP_LOGIN_TRANSMITTER, SMPP_LOGIN_RECEIVER, 
+              SMPP_LOGIN_TRANSCEIVER } smpp_login;
+
+enum {USE_UUID = 0, USE_SMPP_ID = 1};
 
 typedef struct _boxc {
     Connection	*smpp_connection;
@@ -149,8 +158,9 @@
     Dict	*sent;
     Semaphore	*pending;
     volatile sig_atomic_t alive;
-    Octstr	*boxc_id; /* identifies the connected opensmppbox instance */
-    Octstr	*sms_service;
+    Octstr	*boxc_id; /* identifies connected client */
+    Octstr      *our_id; /* Idenfies us to our bearerbox */    
+    Octstr	*sms_service; //
     Octstr	*route_to_smsc;
     Dict	*msg_acks;
     Dict	*deliver_acks;
@@ -173,11 +183,105 @@
 
 } Boxc;
 
+typedef struct _bbboxc {
+    Connection *bearerbox_connection;
+    volatile sig_atomic_t alive;
+    Dict       *msg_acks;
+    Dict       *deliver_acks;
+    int        mo_recode;
+} BBBoxc;
+
+static BBBoxc *bbbox;
+
+
+static void msg_list_destroy(List *l)
+{
+        long i, len;
+        Msg *item;
+
+        i = 0;
+        len = gwlist_len(l);
+        while (i < len) {
+               item = gwlist_get(l, i);
+               msg_destroy(item); item = NULL;            
+               ++i;
+        }
+}
+
+static void msg_list_destroy_item(void *item)
+{
+        msg_list_destroy(item);
+}
+
+static void box_dump_salient(Boxc *boxc)
+{
+        if (!boxc) {
+                debug("opensmppbox", 0, "client pointer points to NULL");
+                return;
+        }
+
+        debug("opensmppbox", 0, "client dump starts");
+        if (boxc->client_ip)   
+                debug("opensmppbox", 0, "client ip address was <%s>", octstr_get_cstr(boxc->client_ip));
+        if (boxc->our_id)
+                debug("opensmppbox", 0, "our id to bearerbox was <%s>", octstr_get_cstr(boxc->our_id));
+        if (boxc->boxc_id)
+                debug("opensmppbox", 0, "client id (username) was <%s>", octstr_get_cstr(boxc->boxc_id));
+        debug("opensmppbox", 0, "client dump ends");
+}
+
+static void box_list_dump_salient(List *boxes)
+{ 
+        long i, len;
+        Boxc *box;
+  
+        i = 0;
+        len = gwlist_len(boxes);
+        while (i < len) {
+                box = gwlist_get(boxes, i);
+                box_dump_salient(box);
+                ++i;
+        }
+}
+
+void box_id_dict_dump(Dict *box_id_by_msg_id)
+{
+        long i, count;
+        List *ids;
+        Octstr *key;
+        Octstr *box_id;
+
+        gwlib_assert_init();
+
+        debug("opensmppbox", 0, "Dumping box_id dict:");
+        if (!box_id_by_msg_id) {
+                debug("opensmppbox", 0, "box id dict point NULL");
+                return;
+        }
+
+        ids = dict_keys(box_id_by_msg_id);
+        count = dict_key_count(box_id_by_msg_id);
+        for (i = 0; i < count; ++i) {
+                key = gwlist_get(ids, i);
+                box_id = dict_get(box_id_by_msg_id, key);
+                debug("opensmppbox", 0, "Msg id %ld was: ", i);
+                octstr_dump(key, 0);
+                debug("opensmppbox", 0, "Box id %ld was: ", i);
+                octstr_dump(box_id, 0);
+        }
+        debug("opensmppbox", 0, "End of dump.");
+}
+
 void smpp_pdu_destroy_item(void *pdu)
 {
 	smpp_pdu_destroy(pdu);
 }
 
+static void shutdown_connection(Connection *conn)
+{
+        conn_destroy(conn);
+}
+
 /*
  * Use PAM (Pluggable Authentication Module) to check sendsms authentication.
  */
@@ -309,16 +414,18 @@
 valid_login:
 	for (box = 0; box < gwlist_len(all_boxes); box++) {
 		thisbox = (Boxc *)gwlist_get(all_boxes, box);
-		if (octstr_compare(system_type, thisbox->boxc_id) == 0 && (thisbox->login_type == SMPP_LOGIN_TRANSCEIVER || (thisbox->login_type == login_type))) {
-			debug("bb.sms.smpp", 0, "opensmppbox[%s]: Multiple login: disconnect.",
-				octstr_get_cstr(thisbox->boxc_id));
+	     if (system_type && thisbox && thisbox->boxc_id && octstr_compare(system_type, thisbox->boxc_id) == 0 && 
+                     (thisbox->login_type == SMPP_LOGIN_TRANSCEIVER || (thisbox->login_type == login_type))) {
+		debug("opensmppbox", 0, "opensmppbox[%s]: Multiple login: disconnect", octstr_get_cstr(thisbox->boxc_id));
 			thisbox->alive = 0;
 #ifdef HAVE_SHUTDOWN_CONNECTION
+                if (!use_smppboxid)
 			shutdown_connection(thisbox->bearerbox_connection);
 			shutdown_connection(thisbox->smpp_connection);
 #endif
 		}
 	}
+         
 	return 1;
 }
 
@@ -342,6 +449,12 @@
     } while(0)
 #endif
 
+static void dump_pdu_debug(char *msg, Octstr *id, SMPP_PDU *pdu)
+{
+        debug("opensmppbox", 0, "SMPP[%s]: %s", \
+              octstr_get_cstr(id), msg);          \
+        smpp_pdu_dump(pdu);
+}
 
 /*
  * Converting SMPP timestamp to minutes relative 
@@ -396,7 +509,7 @@
         localdiff = difftime(gw_mktime(&local), gw_mktime(&tm));
         valutc += localdiff;
 
-        debug("sms.smpp",0, "diff between utc and localtime (%d)", localdiff);
+        debug("opensmppbox",0, "diff between utc and localtime (%d)", localdiff);
         diff = diff*15*60;
         switch(relation) {
             case '+':
@@ -421,10 +534,10 @@
         return -1;
     }
     tm = gw_gmtime(valutc);
-    debug("sms.smpp",0,"Requested UTC timestamp: %02d-%02d-%02d %02d:%02d:%02d",
+    debug("opensmppbox",0,"Requested UTC timestamp: %02d-%02d-%02d %02d:%02d:%02d",
             tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
 
-    debug("sms.smpp", 0, "requested timestamp in min. (%ld)", (valutc - utc)/60);
+    debug("opensmppbox", 0, "requested timestamp in min. (%ld)", (valutc - utc)/60);
 
     return ceil ( difftime (valutc, utc) / 60 );
 }
@@ -440,7 +553,7 @@
 
 /* send to bearerbox */
 
-static int send_msg(Connection *conn, Boxc *boxconn, Msg *pmsg)
+static int send_msg(Connection *conn, Msg *pmsg)
 {
 	/* Caution: implicit msg_destroy */
 	write_to_bearerbox_real(conn, pmsg);
@@ -456,7 +569,7 @@
 
 	for (pos = 0; pos < gwlist_len(all_boxes); pos++) {
 		box = (Boxc *)gwlist_get(all_boxes, pos);
-		send_msg(box->bearerbox_connection, box, msg);
+		send_msg(box->bearerbox_connection, msg);
 	}
 }
 */
@@ -474,40 +587,43 @@
  * Do this even while no opensmppbox-id is given to unlock the sender thread in
  * bearerbox.
  */
-static void identify_to_bearerbox(Boxc *conn)
+static void identify_to_bearerbox(Connection *conn, Octstr *our_id)
 {
     Msg *msg;
 
     msg = msg_create(admin);
     msg->admin.command = cmd_identify;
-    msg->admin.boxc_id = octstr_duplicate(conn->boxc_id);
-    send_msg(conn->bearerbox_connection, conn, msg);
+    msg->admin.boxc_id = octstr_duplicate(our_id);
+    send_msg(conn, msg);
 }
 
 /* read from bearerbox */
 
-static Msg *read_from_box(Connection *conn, Boxc *boxconn)
+/* ret is -1, when connection was broke, 0 when we had a message and 1 when we had a timeout*/
+static Msg *read_from_box(Connection *conn, int alive, int *ret)
 {
     Octstr *pack;
-    Msg *msg;
+    Msg *msg = NULL;
 
     pack = NULL;
-    while (boxconn->alive) {
-	switch (read_from_bearerbox_real(conn, &msg, 1.0)) {
+    while (alive) {
+	switch (read_from_bearerbox_real(conn, &msg, 0.1)) {
 	case -1:
 	    /* connection to bearerbox lost */
+           *ret = -1; 
 	    return NULL;
-	    break;
 	case  0:
 	    /* all is well */
+	    *ret = 0;
 	    return msg;
-	    break;
 	case  1:
 	    /* timeout */
-	    break;
+            *ret = 1;
+	    return NULL;
 	}
     }
 
+    *ret = -1;
     return msg;
 }
 
@@ -626,7 +742,7 @@
 /* generate 8 character ID, taken from msgid */
 static Octstr *generate_smppid(Msg *msg)
 {
-	char uuidbuf[100];
+	char uuidbuf[UUID_STR_LEN + 1];
 	Octstr *result;
 
 	// gw_assert(msg->type == sms); // we segfault on this
@@ -673,7 +789,7 @@
     if (*pdu == NULL) {
         error(0, "opensmppbox[%s]: PDU unpacking failed.",
               octstr_get_cstr(box->boxc_id));
-        debug("bb.sms.smpp", 0, "opensmppbox[%s]: Failed PDU omitted.",
+        debug("opensmppbox", 0, "opensmppbox[%s]: Failed PDU omitted.",
               octstr_get_cstr(box->boxc_id));
         /* octstr_dump(os, 0); */
         octstr_destroy(os);
@@ -684,6 +800,59 @@
     return 1;
 }
 
+static int msg_is_report_mo(Msg *msg)
+{
+    return msg->sms.sms_type == report_mo;
+}
+
+ /* To route to the original client, we restore the original
+  * box id (i.e., essentially the username). 
+  * For report mo, we get id of the original message following way:
+  *     a) in case of HTTP SMSC drl-url up to semicolon 
+  *     b) otherwise (AT & SMPP tested), the whole dlr_url
+  */
+static void restore_box_id(Msg *msg)
+{ 
+      if (msg_is_report_mo(msg)) {
+              Msg *dlr = NULL;
+              Octstr *boxid = NULL;
+              Octstr *msgid = NULL;
+              long semicolon = -1;
+
+              if (msg->sms.dlr_url)
+                  semicolon = octstr_search(msg->sms.dlr_url, octstr_imm(";"), 0);
+              
+              if (semicolon > -1) 
+                      msgid = octstr_copy(msg->sms.dlr_url, 0, semicolon);
+              else
+                      msgid = octstr_duplicate(msg->sms.dlr_url);
+              
+              if (msgid) {
+                      dlr = dlr_find_by_id(msgid, USE_SMPP_ID);
+
+                      if (dlr && dlr->sms.boxc_id) {
+                              boxid = octstr_duplicate(dlr->sms.boxc_id);
+                   
+                              if (boxid) {
+                                       octstr_destroy(msg->sms.boxc_id);
+                                       msg->sms.boxc_id = octstr_duplicate(boxid);
+                              }
+
+                              octstr_destroy(boxid); boxid = NULL;
+                              msg_destroy(dlr); dlr = NULL;
+                     }
+                     octstr_destroy(msgid);
+              }
+       }
+       /* MOs are routed separately, using smsc_id */
+}
+
+static void change_box_id(Msg *msg)
+{
+        octstr_destroy(msg->sms.boxc_id);
+        msg->sms.boxc_id = octstr_duplicate(smppbox_id);
+}
+
 static List *msg_to_pdu(Boxc *box, Msg *msg)
 {
     SMPP_PDU *pdu, *pdu2;
@@ -702,8 +871,7 @@
     Octstr *header, *footer, *suffix, *split_chars;
     Msg *msg2;
     
-    pdu = smpp_pdu_create(deliver_sm,
-    	    	    	  counter_increase(box->smpp_pdu_counter));
+    pdu = smpp_pdu_create(deliver_sm, counter_increase(box->smpp_pdu_counter));
 
     pdu->u.deliver_sm.source_addr = octstr_duplicate(msg->sms.sender);
     pdu->u.deliver_sm.destination_addr = octstr_duplicate(msg->sms.receiver);
@@ -717,7 +885,7 @@
     if(box->source_addr_ton > -1 && box->source_addr_npi > -1) {
         pdu->u.deliver_sm.source_addr_ton = box->source_addr_ton;
         pdu->u.deliver_sm.source_addr_npi = box->source_addr_npi;
-        debug("bb.sms.smpp", 0, "SMPP[%s]: Manually forced source addr ton = %ld, source add npi = %ld",
+        debug("opensmppbox", 0, "SMPP[%s]: Manually forced source addr ton = %ld, source add npi = %ld",
               octstr_get_cstr(box->boxc_id), box->source_addr_ton,
               box->source_addr_npi);
     } else {
@@ -749,7 +917,7 @@
     if (box->dest_addr_ton > -1 && box->dest_addr_npi > -1) {
         pdu->u.deliver_sm.dest_addr_ton = box->dest_addr_ton;
         pdu->u.deliver_sm.dest_addr_npi = box->dest_addr_npi;
-        debug("bb.sms.smpp", 0, "SMPP[%s]: Manually forced dest addr ton = %ld, dest add npi = %ld",
+        debug("opensmppbox", 0, "SMPP[%s]: Manually forced dest addr ton = %ld, dest add npi = %ld",
               octstr_get_cstr(box->boxc_id), box->dest_addr_ton,
               box->dest_addr_npi);
     } else {
@@ -770,7 +938,9 @@
     if (octstr_len(pdu->u.deliver_sm.destination_addr) > 20 ||
         octstr_len(pdu->u.deliver_sm.source_addr) > 20) {
         smpp_pdu_destroy(pdu);
-        gwlist_destroy(pdulist, NULL);
+
+        gwlist_destroy(pdulist, smpp_pdu_destroy_item);
+        warning(0, "opensmppbox: msg_to_pdu: address too long, not acceptable");
         return NULL;
     }
 
@@ -807,7 +977,7 @@
             ESM_CLASS_SUBMIT_RPI;
 
     /* Is this a delivery report? */
-    if (msg->sms.sms_type == report_mo) {
+    if (msg_is_report_mo(msg)) {
 	pdu->u.deliver_sm.esm_class |= ESM_CLASS_DELIVER_SMSC_DELIVER_ACK;
 	dlrtype = msg->sms.dlr_mask;
 	parts = octstr_split(msg->sms.dlr_url, octstr_imm(";"));
@@ -816,9 +987,10 @@
 	if (dlr == NULL) {
 		/* we could not find a corresponding dlr; nothing to send */
 		smpp_pdu_destroy(pdu);
-		gwlist_destroy(pdulist, NULL);
+		gwlist_destroy(pdulist, smpp_pdu_destroy_item);
 		octstr_destroy(msgid);
 		gwlist_destroy(parts, octstr_destroy_item);
+                warning(0, "opensmppbox: msg_to_pdu: no msg corresponding dlr, ignoring");
 		return NULL;
 	}
 	dlvrd = octstr_imm("000");
@@ -901,7 +1073,7 @@
 			if (box->version > 0x33) {
 				pdu2->u.deliver_sm.receipted_message_id = octstr_duplicate(msgid2);
 				pdu2->u.deliver_sm.message_state = dlr_state;
-				dict_destroy(pdu2->u.deliver_sm.tlv);
+                                dict_destroy(pdu->u.deliver_sm.tlv);
 				pdu2->u.deliver_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp");
 			}
 			pdu2->u.deliver_sm.short_message = octstr_format("id:%S sub:001 dlvrd:%S submit date:%s done date:%s stat:%S err:%s text:%12s", msgid2, dlvrd, submit_date_c_str, done_date_c_str, dlr_status, err, text);
@@ -1028,7 +1200,7 @@
         parts = NULL;
     }
 
-    debug("SMPP", 0, "message length %ld, sending %ld message%s",
+    debug("opensmppbox", 0, "message length %ld, sending %ld message%s",
         octstr_len(msg->sms.msgdata), msg_count, msg_count == 1 ? "" : "s");
 
     if (parts) {
@@ -1067,7 +1239,7 @@
     }
     else {
         if (box->version > 0x33) {
-	    dict_destroy(pdu->u.deliver_sm.tlv);
+            dict_destroy(pdu->u.deliver_sm.tlv); pdu->u.deliver_sm.tlv = NULL;
             pdu->u.deliver_sm.tlv = meta_data_get_values(msg->sms.meta_data, "smpp");
         }
 
@@ -1162,7 +1333,7 @@
     if (pdu->u.submit_sm.esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR) {
         int udhl;
         udhl = octstr_get_char(msg->sms.msgdata, 0) + 1;
-        debug("bb.sms.smpp",0,"SMPP[%s]: UDH length read as %d", 
+        debug("opensmppbox",0,"SMPP[%s]: UDH length read as %d", 
               octstr_get_cstr(box->boxc_id), udhl);
         if (udhl > octstr_len(msg->sms.msgdata)) {
             error(0, "SMPP[%s]: Mallformed UDH length indicator 0x%03x while message length "
@@ -1348,7 +1518,7 @@
     if (pdu->u.data_sm.esm_class & ESM_CLASS_SUBMIT_UDH_INDICATOR) {
         int udhl;
         udhl = octstr_get_char(msg->sms.msgdata, 0) + 1;
-        debug("bb.sms.smpp",0,"SMPP[%s]: UDH length read as %d", 
+        debug("opensmppbox",0,"SMPP[%s]: UDH length read as %d", 
               octstr_get_cstr(box->boxc_id), udhl);
         if (udhl > octstr_len(msg->sms.msgdata)) {
             error(0, "SMPP[%s]: Mallformed UDH length indicator 0x%03x while message length "
@@ -1494,12 +1664,18 @@
 
 static void handle_pdu(Connection *conn, Boxc *box, SMPP_PDU *pdu) {
 	SMPP_PDU *resp = NULL;
-	Msg *msg, *msg2, *mack;
+	Msg *msg = NULL, *msg2 = NULL, *mack = NULL;
 	long reason;
-	Octstr *msgid = NULL, *hold_service, *system_type;
+	Octstr *msgid = NULL, *hold_service = NULL, *system_type = NULL;
 	int msg_to_send = 1;
 	List *parts_list = NULL;
 	char id[UUID_STR_LEN + 1];
+        Connection *bearerbox_connection;
+
+        if (usesmppboxid)
+                bearerbox_connection = bbbox->bearerbox_connection;
+        else
+                bearerbox_connection = box->bearerbox_connection;
 
 	dump_pdu("Got PDU:", box->boxc_id, pdu);
 	switch (pdu->type) {
@@ -1516,6 +1692,7 @@
 		break;
 	}
 	switch (pdu->type) {
+        /* We set a substitute box id here, if smppbox id is used*/
 	case bind_transmitter:
 		system_type = pdu->u.bind_transmitter.system_type ? pdu->u.bind_transmitter.system_type : octstr_imm("");
 		if (check_login(box, pdu->u.bind_transmitter.system_id, pdu->u.bind_transmitter.password, system_type, SMPP_LOGIN_TRANSMITTER)) {
@@ -1524,11 +1701,12 @@
 			box->login_type = SMPP_LOGIN_TRANSMITTER;
 			box->boxc_id = systemidisboxcid ? octstr_duplicate(pdu->u.bind_transmitter.system_id) : octstr_duplicate(system_type);
 			box->sms_service = octstr_duplicate(pdu->u.bind_transmitter.system_id);
-			identify_to_bearerbox(box);
+			if (!usesmppboxid)
+                                identify_to_bearerbox(box->bearerbox_connection, box->boxc_id);
 			resp = smpp_pdu_create(bind_transmitter_resp, pdu->u.bind_transmitter.sequence_number);
 			resp->u.bind_transmitter_resp.system_id = octstr_duplicate(our_system_id);
-		}
-		else {
+                        debug("opensmppbox", 0, "Client connected with id %s", octstr_get_cstr(box->boxc_id));	
+                } else {
 			resp = smpp_pdu_create(bind_transmitter_resp, pdu->u.bind_transmitter_resp.sequence_number);
 			resp->u.bind_transmitter.command_status = 0x0d; /* invalid login */
 		}
@@ -1541,9 +1719,11 @@
 			box->login_type = SMPP_LOGIN_RECEIVER;
 			box->boxc_id = systemidisboxcid ? octstr_duplicate(pdu->u.bind_transmitter.system_id) : octstr_duplicate(system_type);
 			box->sms_service = octstr_duplicate(pdu->u.bind_receiver.system_id);
-			identify_to_bearerbox(box);
+			if (!usesmppboxid)
+                                identify_to_bearerbox(box->bearerbox_connection, box->boxc_id);
 			resp = smpp_pdu_create(bind_receiver_resp, pdu->u.bind_receiver.sequence_number);
 			resp->u.bind_receiver_resp.system_id = octstr_duplicate(our_system_id);
+                        debug("opensmppbox", 0, "Client connected with id %s", octstr_get_cstr(box->boxc_id));
 		}
 		else {
 			resp = smpp_pdu_create(bind_receiver_resp, pdu->u.bind_receiver.sequence_number);
@@ -1558,9 +1738,11 @@
 			box->login_type = SMPP_LOGIN_TRANSCEIVER;
 			box->boxc_id = systemidisboxcid ? octstr_duplicate(pdu->u.bind_transmitter.system_id) : octstr_duplicate(system_type);
 			box->sms_service = octstr_duplicate(pdu->u.bind_transceiver.system_id);
-			identify_to_bearerbox(box);
+			if (!usesmppboxid)
+                                identify_to_bearerbox(box->bearerbox_connection, box->boxc_id);
 			resp = smpp_pdu_create(bind_transceiver_resp, pdu->u.bind_transceiver.sequence_number);
 			resp->u.bind_transceiver_resp.system_id = octstr_duplicate(our_system_id);
+                        debug("opensmppbox", 0, "Client connected with id %s", octstr_get_cstr(box->boxc_id));
 		}
 		else {
 			resp = smpp_pdu_create(bind_transceiver_resp, pdu->u.bind_transceiver.sequence_number);
@@ -1587,7 +1769,6 @@
 			check_multipart(box, msg, &msg_to_send, &msg2, &parts_list);
 			msg->sms.smsc_id = box->route_to_smsc ? octstr_duplicate(box->route_to_smsc) : NULL;
 			msg->sms.boxc_id = octstr_duplicate(box->boxc_id);
-			msg_dump(msg, 0);
 			resp = smpp_pdu_create(data_sm_resp, pdu->u.data_sm.sequence_number);
 			msgid = generate_smppid(msg);
 			msg->sms.dlr_url = octstr_duplicate(msgid);
@@ -1596,20 +1777,29 @@
 				if (DLR_IS_ENABLED(msg2->sms.dlr_mask)) {
 					hold_service = msg2->sms.service;
 					msg2->sms.service = octstr_format("%ld", msg2->sms.time);
+					octstr_destroy(msgid);
 					msgid = generate_smppid(msg2);
 					if (parts_list) {
 						msg2->sms.dlr_url = concat_msgids(msgid, parts_list);
 					}
-					dlr_add(box->boxc_id, msgid, msg2);
+					msg_add(box->boxc_id, msgid, msg2);
+					if (usesmppboxid)
+                                                change_box_id(msg2);
 					octstr_destroy(msgid);
 					octstr_destroy(msg2->sms.service);
 					msg2->sms.service = hold_service;
 				}
 				uuid_unparse(msg2->sms.id, id);
 				msgid = octstr_create(id);
+                                if (!usesmppboxid)
 				dict_put(box->msg_acks, msgid, resp);
+                                else
+                                        dict_put(bbbox->msg_acks, msgid, resp);
 				resp = NULL;
-				send_msg(box->bearerbox_connection, box, msg2);
+                                if (usesmppboxid) {
+                                        send_msg(bearerbox_connection, msg2);
+                                } else
+                                        send_msg(box->bearerbox_connection, msg2);
 				if (parts_list) {
 					/* destroy values */
 					gwlist_destroy(parts_list, msg_destroy_item);
@@ -1628,21 +1818,28 @@
 			check_multipart(box, msg, &msg_to_send, &msg2, &parts_list);
 			msg->sms.smsc_id = box->route_to_smsc ? octstr_duplicate(box->route_to_smsc) : NULL;
 			msg->sms.boxc_id = octstr_duplicate(box->boxc_id);
-			msg_dump(msg, 0);
 			resp = smpp_pdu_create(submit_sm_resp, pdu->u.submit_sm.sequence_number);
 			msgid = generate_smppid(msg);
 			msg->sms.dlr_url = octstr_duplicate(msgid);
-			resp->u.submit_sm_resp.message_id = msgid;
+			resp->u.submit_sm_resp.message_id = octstr_duplicate(msgid);
+			/* Note that we add msg to dlr tzble in all cases. 
+                         * In case of report_mo, need is obvious. In case 
+                         * of mo, it is needed to route resps. Report mo must be stored before
+                         * we change box id.*/
+                        if (usesmppboxid)
+                                 msg_add(msg->sms.boxc_id, msgid, msg);
 			if (msg_to_send) {
 				if (DLR_IS_ENABLED(msg2->sms.dlr_mask)) {
 					hold_service = msg2->sms.service;
 					msg2->sms.service = octstr_format("%ld", msg2->sms.time);
+					octstr_destroy(msgid);
 					msgid = generate_smppid(msg2);
 					if (parts_list) {
 						msg2->sms.dlr_url = concat_msgids(msgid, parts_list);
 					}
-					dlr_add(box->boxc_id, msgid, msg2);
-					octstr_destroy(msgid);
+                                        //dlr_add(box->boxc_id, msgid, msg2);
+                                        if (usesmppboxid)
+                                                change_box_id(msg2);
 					octstr_destroy(msg2->sms.service);
 					msg2->sms.service = hold_service;
 				}
@@ -1646,19 +1843,32 @@
 					octstr_destroy(msg2->sms.service);
 					msg2->sms.service = hold_service;
 				}
+
 				uuid_unparse(msg2->sms.id, id);
+                                octstr_destroy(msgid);
 				msgid = octstr_create(id);
+                                
+                                if (!usesmppboxid) {
 				dict_put(box->msg_acks, msgid, resp);
-				octstr_destroy(msgid);
+				} else {
+                                        dict_put(bbbox->msg_acks, msgid, resp);
+                                }
 				resp = NULL;
-				send_msg(box->bearerbox_connection, box, msg2);
+
+                                if (usesmppboxid) {
+                                        send_msg(bearerbox_connection, msg2);
+                                } else
+                                        send_msg(box->bearerbox_connection, msg2);
 				if (parts_list) {
 					/* destroy values */
 					gwlist_destroy(parts_list, msg_destroy_item);
 				}
+                                octstr_destroy(msgid); msgid = NULL;
 			}
 		}
 		break;
+        /* Note that deliver_sm_resp message_id filed is set to NULL. Instead, the sequwnce number
+         * is used for identification. */
 	case deliver_sm_resp:
 		msgid = octstr_format("%ld", pdu->u.deliver_sm_resp.sequence_number);
 		mack = dict_get(box->deliver_acks, msgid);
@@ -1668,10 +1878,15 @@
 			if (pdu->u.deliver_sm_resp.command_status != 0) {
 				msg->ack.nack = ack_failed;
 			}
-			send_msg(box->bearerbox_connection, box, msg);
-			dict_put(box->deliver_acks, msgid, NULL);
+                        if (usesmppboxid) {
+                                send_msg(bearerbox_connection, msg);
+                        } else {
+                                send_msg(box->bearerbox_connection, msg);
+                        }
+                        dict_put(box->deliver_acks, msgid, NULL); /* would destroy the message */
 		}
-		octstr_destroy(msgid);
+	
+                octstr_destroy(msgid); msgid = NULL;
 		break;
 	case unbind_resp:
 		box->logged_in = 0;
@@ -1688,12 +1903,13 @@
 		resp->u.generic_nack.command_status = SMPP_ESME_RINVCMDID;
 		break;
 	}
+/* An intentional fall-through*/
 error:
 	smpp_pdu_destroy(pdu);
 	if (resp != NULL) {
 		send_pdu(conn, box->boxc_id, resp);
-		smpp_pdu_destroy(resp);
 	}
+        smpp_pdu_destroy(resp);
 }
 
 /*
@@ -1712,11 +1928,18 @@
     boxc->is_wap = 0;
     boxc->load = 0;
     boxc->smpp_connection = conn_wrap_fd(fd, ssl);
+    boxc->bearerbox_connection = NULL;
     boxc->id = counter_increase(boxid);
     boxc->client_ip = octstr_duplicate(ip);
     boxc->alive = 1;
     boxc->connect_time = time(NULL);
+    /* If smmpbox id is not used, box id would be set when doing SMPP bind */
+    if (usesmppboxid)
+        boxc->our_id = octstr_duplicate(smppbox_id);
+    else
+        boxc->our_id = NULL;
     boxc->boxc_id = NULL;
+    boxc->sms_service = NULL;
     boxc->routable = 0;
     boxc->smpp_pdu_counter = counter_create();
     boxc->alt_charset = NULL; /* todo: get from config */
@@ -1754,6 +1977,8 @@
 	    conn_destroy(boxc->bearerbox_connection);
     if (boxc->boxc_id)
 	    octstr_destroy(boxc->boxc_id);
+    if (boxc->our_id)
+            octstr_destroy(boxc->our_id);
     if (boxc->alt_charset)
 	    octstr_destroy(boxc->alt_charset);
     counter_destroy(boxc->smpp_pdu_counter);
@@ -1762,11 +1987,45 @@
     }
     if (boxc->client_ip)
 	    octstr_destroy(boxc->client_ip);
+    if (boxc->sms_service)
+            octstr_destroy(boxc->sms_service);
+    
     dict_destroy(boxc->msg_acks);
     dict_destroy(boxc->deliver_acks);
     gw_free(boxc);
 }
 
+static void boxc_destroy_item(void *item)
+{
+    boxc_destroy(item);
+}
+
+static BBBoxc *bbboxc_create(void)
+{
+    BBBoxc *boxc;
+
+    boxc = gw_malloc(sizeof(BBBoxc));
+    boxc->bearerbox_connection = connect_to_bearerbox_real(bearerbox_host, bearerbox_port, bearerbox_port_ssl, NULL);
+    boxc->alive = 1;
+    boxc->mo_recode = 0;
+    boxc->msg_acks = dict_create(1024, smpp_pdu_destroy_item);
+
+    return boxc;
+}
+
+static void bbboxc_destroy(BBBoxc *boxc)
+{
+    if (boxc == NULL)
+        return;
+
+    if (boxc->bearerbox_connection)
+        conn_destroy(boxc->bearerbox_connection);
+
+    dict_destroy(boxc->msg_acks);
+
+    gw_free(boxc);
+}
+
 /* ------------------------------------------------------------------
  * SMPP thingies
  * ------------------------------------------------------------------
@@ -1816,7 +2075,9 @@
     SMPP_PDU *pdu;
     long len;
 
+    error(0, "opensmppbox: smpp_to_bearerbox: thread starts");
     box->last_pdu_received = time(NULL);
+
     while (smppbox_status == SMPP_RUNNING && box->alive) {
 		len = 0;
 		switch (read_pdu(box, conn, &len, &pdu)) {
@@ -1838,16 +2099,126 @@
 		}
     }
 #ifdef HAVE_SHUTDOWN_CONNECTION
+    if (!usesmppboxid)
     shutdown_connection(box->bearerbox_connection);
 #endif
+    error(0, "opensmppbox: smpp_to_bearerbox: thread terminates");
+}
+
+/*
+ * Check do we have a specific route to pass this msg to client-id?
+ */
+static Octstr *find_configured_box_id(Msg *msg)
+{
+        Octstr *boxc_id = NULL;
+        Octstr *r, *s, *rs;
+        /*
+         * Check if we have a "client-route" for this msg.
+         * 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.receiver == NULL)
+             return boxc_id;
+
+         if (msg->sms.smsc_id == NULL)
+             return boxc_id;
+
+         Octstr *os = octstr_format("%s:%s", octstr_get_cstr(msg->sms.receiver),
+                                    octstr_get_cstr(msg->sms.smsc_id));
+         s = (msg->sms.smsc_id ? dict_get(client_by_smsc, msg->sms.smsc_id) : NULL);
+         r = (msg->sms.receiver ? dict_get(client_by_receiver, msg->sms.receiver) : NULL);
+         rs = (os ? dict_get(client_by_smsc_receiver, os) : NULL);
+         octstr_destroy(os);
+         if (rs)
+                 boxc_id = rs;
+         else if (r)
+                 boxc_id = r;
+         else if (s)
+                 boxc_id = s;
+
+         return boxc_id;
+}
+
+static Boxc *find_box_by_id(Octstr *boxc_id)
+{
+        Boxc *thisbox;
+        long retry = 0;
+        long i = 0;
+        long cnt = gwlist_len(all_boxes);
+        while (i < cnt) {
+                thisbox = gwlist_get(all_boxes, i);
+                if (!thisbox ||  !(thisbox->boxc_id)) {
+                        ++i;
+                        continue;
+                }
+
+                /* Reject connection that is just sending*/
+                if (thisbox->login_type == SMPP_LOGIN_TRANSMITTER){
+                         ++i;
+                         continue;
+                }
+
+                /* If the client was not logged in, wait some time*/
+                if (thisbox->login_type == SMPP_LOGIN_NOTLOGGEDIN && retry < 30){
+                        ++retry;
+                        if (retry < 30)
+                                gwthread_sleep(0.1);
+                        else
+                                ++i;
+                        continue;
+                }
+
+                if (boxc_id && octstr_compare(thisbox->boxc_id, boxc_id) == 0) {
+                            return thisbox;
+                }
+                ++i;
+        }
+
+        return NULL;
 }
 
-/* if this login was made as a transmitter, then find the corresponding receiver connection */
-static Boxc *find_receiver_box(Boxc *box)
+/*
+ * This function is used to route msg acks. Ack's msg id maps ack to original
+ * message. The box id of the original message is used for routing.
+ */
+static Boxc *find_receiver_box_by_msg_id(Octstr *msgid, Msg *msg)
+{
+        Msg *sack = NULL;
+        Octstr *boxid = NULL;
+        Boxc *thisbox = NULL;
+
+        sack = dlr_find_by_id(msgid, USE_UUID);
+        if (sack)
+                boxid = sack->sms.boxc_id;
+        else
+                return NULL;
+
+        if (boxid)
+                thisbox = find_box_by_id(boxid);
+        else {
+                msg_destroy(sack); sack = NULL; 
+                return NULL;
+        }
+
+        msg_destroy(sack); sack = NULL;
+        return thisbox; 
+}
+
+/* if this login was made as a transmitter or receiver, then find the corresponding 
+ * receiver connection */
+static Boxc *find_receiver_box(Boxc *box, Msg *msg)
 {
 	Boxc *thisbox;
 	int cnt;
+        Octstr *boxc_id = NULL;
+        int report_mo = 0;
+        int retry = 0;
 
+        if (usesmppboxid && octstr_len(msg->sms.boxc_id) > 0) {
+                boxc_id = msg->sms.boxc_id;
+        }
+
+        if (!usesmppboxid) {
 	if (box->login_type == SMPP_LOGIN_RECEIVER || box->login_type == SMPP_LOGIN_TRANSCEIVER) {
 		return box;
 	}
@@ -1858,37 +2229,101 @@
 		}
 	}
 	return box;
+        }
+
+        else {
+                /* If we had no clients, wait a little, bearerbox may resend when they  be connecting*/
+                report_mo = 1;
+                while (gwlist_len(all_boxes) == 0 && retry < 3) {
+                        gwthread_sleep(1);
+                        ++retry;
+                }
+
+                if (gwlist_len(all_boxes) == 0 && retry == 3)
+                        return NULL;
+
+                if (msg->sms.sms_type == mo) {
+                        report_mo = 0;
+                        boxc_id = find_configured_box_id(msg);
+                }
+
+               /*
+                * Mos will be routed simply by they boxc-id, defined by smsbox-route. 
+                * If there is none, a random box is picked.
+                */
+                thisbox = find_box_by_id(boxc_id);
+
+                /* If no box was found and we have MO, pick a random box. In case
+                 * of DLR, this is an error. */
+                if (!thisbox && !report_mo) {
+                        thisbox = gwlist_get(all_boxes, gw_rand() % gwlist_len(all_boxes));
+                        return thisbox;
+                }
+
+                return thisbox;
+        }
 }
 
 static void bearerbox_to_smpp(void *arg)
 {
-    Msg *msg, *mack;
-    Boxc *box = arg;
-    SMPP_PDU *pdu;
-    List *pdulist;
+    Msg *msg = NULL, *mack = NULL;
+    Boxc *box = NULL;
+    BBBoxc *bbbox = NULL;
+    SMPP_PDU *pdu = NULL;;
+    List *pdulist = NULL;
     int dreport, errcode;
-    Boxc *receiver_box;
+    Boxc *receiver_box = NULL;
     char id[UUID_STR_LEN + 1];
-    Octstr *msgid;
+    Octstr *msgid = NULL;
+    int ret;
 
-    while (smppbox_status == SMPP_RUNNING && box->alive) {
+    error(0, "opensmppbox: bearerbox_to_smpp: thread starts");
 
-	msg = read_from_box(box->bearerbox_connection, box);
-        if (msg == NULL) {
-	    if ((!box->alive) || conn_eof(box->bearerbox_connection)) {
+    if (!usesmppboxid) {
+        box = arg;
+    } else {
+        bbbox = arg;
+    }
+
+    while (smppbox_status == SMPP_RUNNING && (usesmppboxid ? bbbox->alive : box->alive)) {
+
+        if (usesmppboxid)
+            msg = read_from_box(bbbox->bearerbox_connection, smppbox_status == SMPP_RUNNING && bbbox->alive, &ret);
+        else
+            msg = read_from_box(box->bearerbox_connection, smppbox_status == SMPP_RUNNING && box->alive, &ret);
+        
+        /* Connection was broken */
+        if (ret == -1) {
             	/* tell opensmppbox to die */
 	    	/* the client closes the connection, after that die in receiver */
+	    if (usesmppboxid)  
+                if (conn_eof(bbbox->bearerbox_connection))
+            	    bbbox->alive = 0;
+	    else 
+                if (conn_eof(box->bearerbox_connection))
 	    	box->alive = 0;
+	    continue;
 	    }
+
+        /* timeout*/
+        if (ret == 1) {
 	    continue;
         }
+            
+        /* have a message, hopefully a good one */
 	if (msg_type(msg) == admin) {
 	    if (msg->admin.command == cmd_shutdown) {
 		info(0, "Bearerbox told us to die");
+                if (usesmppboxid)
+		    bbbox->alive = 0;
+                else
 		box->alive = 0;
 	    } else if (msg->admin.command == cmd_restart) {
 		info(0, "Bearerbox told us to restart");
 		restart = 1;
+                if (usesmppboxid)
+		    bbbox->alive = 0;
+                else
 		box->alive = 0;
 	    }
 	}
@@ -1901,7 +2336,11 @@
 	if (msg_type(msg) == ack) {
 	    uuid_unparse(msg->ack.id, id);
 	    msgid = octstr_create(id);
+            if (!usesmppboxid)
 	    pdu = dict_get(box->msg_acks, msgid);
+            else
+                pdu = dict_get(bbbox->msg_acks, msgid);
+                      
 	    errcode = SMPP_ESME_RMSGQFUL; /* in case we get ack_failed_tmp */
 	    if (pdu) {
 		switch (msg->ack.nack) {
@@ -1933,26 +2372,39 @@
 			debug("opensmppbox", 0, "Unknown ack.nack type: %ld.", msg->ack.nack);
 			break;
 		}
+                if (!usesmppboxid) {
 		send_pdu(box->smpp_connection, box->boxc_id, pdu);
 		dict_put(box->msg_acks, msgid, NULL); /* also destroys item */
+                } else {
+                    Boxc *receiver_box = find_receiver_box_by_msg_id(msgid, msg);
+                    if (receiver_box) {
+                        send_pdu(receiver_box->smpp_connection, receiver_box->boxc_id, pdu);
+                        dict_put(receiver_box->msg_acks, msgid, NULL);
+                    } 
+                    //dlr_remove_by_id(msg);
+                }
 	    }
 	    else {
 		debug("opensmppbox", 0, "Ack to unknown message: %s.", id);
 	    }
 	    octstr_destroy(msgid);
 	}
-        if (!box->alive) {
+        if (usesmppboxid ? !bbbox->alive : !box->alive) {
 		msg_destroy(msg);
 		break;
 	}
 	if (msg_type(msg) == sms) {
 		info(0, "We received an SMS message.");
-		if (msg->sms.sms_type == report_mo)
+            msg_dump(msg, 0);
+            uuid_unparse(msg->sms.id, id);
+            msgid = octstr_create(id);
+	    if (msg_is_report_mo(msg)) {
 			dreport = 1;
-		else
+	    } else {
 			dreport = 0;
+            }
 		/* Recode to iso-8859-1 the MO message if possible */
-		if (box->mo_recode && msg->sms.coding == DC_UCS2) {
+	    if ((usesmppboxid ? bbbox->mo_recode : box->mo_recode) && msg->sms.coding == DC_UCS2) {
 			int converted = 0;
 			Octstr *text;
 
@@ -2006,43 +2458,58 @@
 			mack->ack.nack = ack_failed;
 			mack->ack.time = msg->sms.time;
 			uuid_copy(mack->ack.id, msg->sms.id);
-			send_msg(box->bearerbox_connection, box, mack);
+               if (usesmppboxid) {
+                   send_msg(bbbox->bearerbox_connection, mack);
+               } else
+                   send_msg(box->bearerbox_connection, mack);
 
 			msg_destroy(msg);
 			continue;
 		}
-		/* create ack message to be sent afterwards */
+	   /* create ack message to be sent afterwards, or immediately, in case of error*/
 		mack = msg_create(ack);
 		mack->ack.nack = ack_success;
 		mack->ack.time = msg->sms.time;
 		uuid_copy(mack->ack.id, msg->sms.id);
 
-		msgid = NULL;
-		receiver_box = find_receiver_box(box);
+	  if (usesmppboxid) {
+               restore_box_id(msg);
+               receiver_box = find_receiver_box(NULL, msg);
+           } else
+               receiver_box = find_receiver_box(box, msg);
+           if (receiver_box != NULL)
 		pdulist = msg_to_pdu(receiver_box, msg);
 		if (pdulist != NULL) {
 			while ((pdu = gwlist_extract_first(pdulist)) != NULL) {
-				if (NULL == msgid) {
-					/* Put ack in dict. We will send it as soon as we received a deliver_sm_resp */
+	           octstr_destroy(msgid);
+		   /* Put ack in dict. We will send it as soon as we received a deliver_sm_resp.
+                    * Note that sequence number is used for identification. */
 					msgid = octstr_format("%ld", pdu->u.deliver_sm.sequence_number);
 					dict_put(receiver_box->deliver_acks, msgid, mack);
-				}
-				send_pdu(receiver_box->smpp_connection, box->boxc_id, pdu);
+                   
+		   send_pdu(receiver_box->smpp_connection, receiver_box->boxc_id, pdu);
 				smpp_pdu_destroy(pdu);
 			}
-			if (msgid)
-				octstr_destroy(msgid);
-			gwlist_destroy(pdulist, NULL);
+	      gwlist_destroy(pdulist, smpp_pdu_destroy_item);
 		}
 		else {
 			/* Send NACK to bearerbox, otherwise message remains in store file. */
 			warning(0, "msg_to_pdu failed, sending negative ack");
 			mack->ack.nack = ack_failed;
-			send_msg(box->bearerbox_connection, box, mack);
+              if (usesmppboxid) {
+	          send_msg(bbbox->bearerbox_connection, mack);
+              } else
+                  send_msg(box->bearerbox_connection, mack);
+	  }
+          if (msgid) {
+              octstr_destroy(msgid); msgid = NULL;
 		}		
 	}
         msg_destroy(msg);
     }
+
+    error(0, "opensmppbox: bearerbox_to_smpp: thread terminates");
+    smppbox_status = SMPP_SHUTDOWN;
 }
 
 static void run_smppbox(void *arg)
@@ -2057,7 +2524,8 @@
 	    panic(0, "Socket accept failed");
 	    return;
     }
-    newconn->boxc_id = octstr_duplicate(smppbox_id);
+    
+    if (!usesmppboxid) {
     newconn->bearerbox_connection = connect_to_bearerbox_real(bearerbox_host, bearerbox_port, bearerbox_port_ssl, NULL /* bb_our_host */);
 	/* XXX add our_host if required */
     if (newconn->bearerbox_connection == NULL) {
@@ -2065,6 +2533,7 @@
 	    boxc_destroy(newconn);
 	    return;
     }
+    }
 
     gwlist_append(all_boxes, newconn);
 
@@ -2083,7 +2552,10 @@
     		boxc_destroy(newconn);
 	    return;
     }
+    if (!usesmppboxid)
     bearerbox_to_smpp(newconn);
+    
+
     gwthread_join(sender);
     gwlist_delete_equal(all_boxes, newconn);
     boxc_destroy(newconn);
@@ -2163,10 +2635,11 @@
 
     switch (signum) {
         case SIGINT:
-
+        case SIGTERM:
        	    if (smppbox_status == SMPP_RUNNING) {
                 error(0, "SIGINT received, aborting program...");
 		smppbox_status = SMPP_SHUTDOWN;
+                gwthread_wakeup_all();
             }
             break;
 
@@ -2198,6 +2671,7 @@
     sigaction(SIGQUIT, &act, NULL);
     sigaction(SIGHUP, &act, NULL);
     sigaction(SIGPIPE, &act, NULL);
+    sigaction(SIGTERM, &act, NULL);
 }
 
 
@@ -2210,6 +2684,110 @@
 {
 }
 
+/*
+ * Populates the corresponding client_by_foobar dictionary hash tables
+ */
+static void init_client_routes(Cfg *cfg)
+{
+    CfgGroup *grp;
+    List *list, *items;
+    Octstr *client_id, *smsc_ids, *shortcuts;
+    int i, j;
+
+    client_id = smsc_ids = shortcuts = NULL;
+    list = items = NULL;
+
+    list = cfg_get_multi_group(cfg, octstr_imm("client-route"));
+
+    /* loop multi-group "client-route" */
+    while (list && (grp = gwlist_extract_first(list)) != NULL) {
+        if ((client_id = cfg_get(grp, octstr_imm("client-id"))) == NULL) {
+            grp_dump(grp);
+            panic(0,"'client-route' group without valid 'client-id' directive!");
+        }
+
+        /*
+         * If smsc-id is given, then any message comming from the specified
+         * smsc-id in the list will be routed to this client.
+         * If shortcode is given, then any message with receiver number
+         * matching those will be routed to this client.
+         * If both are given, then only receiver within shortcode originating
+         * from smsc-id list will be routed to this cleint. So if both are 
+         * present then this is a logical AND operation.
+         */
+        smsc_ids = cfg_get(grp, octstr_imm("smsc-id"));
+        shortcuts = cfg_get(grp, octstr_imm("shortcode"));
+
+        /* consider now the 3 possibilities: */
+        if (smsc_ids && !shortcuts) {
+            /* smsc-id only, so all MO traffic */
+            items = octstr_split(smsc_ids, octstr_imm(";"));
+            for (i = 0; i < gwlist_len(items); i++) {
+                Octstr *item = gwlist_get(items, i);
+                octstr_strip_blanks(item);
+
+                debug("opensmppbox",0,"Adding client routing to id <%s> for smsc id <%s>",
+                      octstr_get_cstr(client_id), octstr_get_cstr(item));
+
+                if (!dict_put_once(client_by_smsc, item, octstr_duplicate(client_id)))
+                    panic(0, "Routing for smsc-id <%s> already exists!",
+                          octstr_get_cstr(item));
+            }
+            gwlist_destroy(items, octstr_destroy_item);
+            octstr_destroy(smsc_ids);   
+        }
+        else if (!smsc_ids && shortcuts) {
+            /* shortcode only, so these MOs from all 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("opensmppbox",0,"Adding client routing to id <%s> for receiver no <%s>",
+                      octstr_get_cstr(client_id), octstr_get_cstr(item));
+
+                if (!dict_put_once(client_by_receiver, item, octstr_duplicate(client_id)))
+                    panic(0, "Routing for receiver no <%s> already exists!",
+                          octstr_get_cstr(item));
+            }
+            gwlist_destroy(items, octstr_destroy_item);
+            octstr_destroy(shortcuts);
+        }
+        else if (smsc_ids && shortcuts) {
+            /* both, so only specified MOs from specified smscs */
+            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("opensmppbox",0,"Adding client routing to id <%s> "
+                          "for receiver no <%s> and smsc id <%s>",
+                          octstr_get_cstr(client_id), octstr_get_cstr(item),
+                          octstr_get_cstr(subitem));
+
+                    /* construct the dict key '<shortcode>:<smsc-id>' */
+                    octstr_insert(subitem, item, 0);
+                    octstr_insert_char(subitem, octstr_len(item), ':');
+                    if (!dict_put_once(client_by_smsc_receiver, subitem, octstr_duplicate(client_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(client_id);
+    }
+
+    gwlist_destroy(list, NULL);
+}
+
 static void init_smppbox(Cfg *cfg)
 {
 	CfgGroup *grp;
@@ -2225,9 +2803,7 @@
 	lvl = 0;
 	systemidisboxcid = 0; /* default backward compatible */
 	enablepam = 0; /* also default false */
-
-	/* init dlr storage */
-	dlr_init(cfg);
+        usesmppboxid = 0; /* Ditto */
 
 	/* initialize low level PDUs */
 	if (smpp_pdu_init(cfg) == -1)
@@ -2298,6 +2873,7 @@
 
 	cfg_get_bool(&systemidisboxcid, grp, octstr_imm("use-systemid-as-smsboxid"));
 	cfg_get_bool(&enablepam, grp, octstr_imm("enable-pam"));
+	cfg_get_bool(&usesmppboxid, grp, octstr_imm("use-smppboxid"));
 	pamacl = cfg_get(grp, octstr_imm("pam-acl"));
 	if (NULL == pamacl) {
 		pamacl = octstr_create("kannel");
@@ -2318,6 +2894,17 @@
         boxid = counter_create();
 	gw_smpp_enter(cfg);
 
+        /* the client routing specific inits */
+        client_by_smsc = dict_create(30, (void(*)(void *)) octstr_destroy);
+        client_by_receiver = dict_create(50, (void(*)(void *)) octstr_destroy);
+        client_by_smsc_receiver = dict_create(50, (void(*)(void *)) octstr_destroy);
+        
+        init_client_routes(cfg);
+
+        /* DLR storage - both ours and Kannel's */
+        dlr_init(cfg);
+        box_dlr_init(cfg);
+
 	smppbox_status = SMPP_RUNNING;
 }
 
@@ -2381,6 +2968,18 @@
     return 0;
 }
 
+static void smppbox_shutdown(void)
+{
+    octstr_destroy(our_system_id); our_system_id = NULL;
+    octstr_destroy(pamacl); pamacl = NULL;
+    octstr_destroy(smpp_logins); smpp_logins = NULL;
+    octstr_destroy(bearerbox_host); bearerbox_host = NULL;
+    octstr_destroy(smppbox_id); smppbox_id = NULL;   
+
+    box_dlr_shutdown();
+    smpp_pdu_shutdown();
+}
+
 int main(int argc, char **argv)
 {
 	int cf_index;
@@ -2388,7 +2987,7 @@
 
 	gwlib_init();
 	all_boxes = gwlist_create();
-	list_dict = dict_create(1, NULL);
+	list_dict = dict_create(32, msg_list_destroy_item);
 
 	cf_index = get_and_set_debugs(argc, argv, check_args);
 	setup_signal_handlers();
@@ -2414,20 +3013,40 @@
 	octstr_destroy(version);
 
 	init_smppbox(cfg);
-
+        if (usesmppboxid) {
+                bbbox = bbboxc_create();
+	        identify_to_bearerbox(bbbox->bearerbox_connection, smppbox_id);
+                gwthread_create(bearerbox_to_smpp, bbbox);
+        }
 	smppboxc_run((void *)smppbox_port);
 
 	/* shutdown dlr storage */
 	heartbeat_stop(ALL_HEARTBEATS);
+        if (usesmppboxid) {
+                gwthread_join_every(bearerbox_to_smpp);
+                bbboxc_destroy(bbbox);
+        }
+
 	dlr_shutdown();
+        smppbox_shutdown();
 	counter_destroy(catenated_sms_counter);
 	counter_destroy(boxid);
 
+        dict_destroy(list_dict); list_dict = NULL;;
+        dict_destroy(client_by_smsc);
+        client_by_smsc = NULL;
+        dict_destroy(client_by_receiver);
+        client_by_receiver = NULL;
+        dict_destroy(client_by_smsc_receiver);
+        client_by_smsc_receiver = NULL;
+
+        cfg_destroy(cfg);
+
 	if (restart_smppbox) {
 		gwthread_sleep(1.0);
 	}
 
-	gwlist_destroy(all_boxes, NULL);
+	gwlist_destroy(all_boxes, boxc_destroy_item);
 	gw_smpp_leave();
 	gwlib_shutdown();
 
