[svn-commits] may: branch may/smpp r411579 - in /team/may/smpp/branches/10/addons: ./ smpp/

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Mar 31 12:38:16 CDT 2014


Author: may
Date: Mon Mar 31 12:38:09 2014
New Revision: 411579

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=411579
Log:
add smpp_recode function to transcode smpp data from/to utf8
add gsm.c/.h helper files for that from android sources

Added:
    team/may/smpp/branches/10/addons/smpp/
    team/may/smpp/branches/10/addons/smpp/gsm.c   (with props)
    team/may/smpp/branches/10/addons/smpp/gsm.h   (with props)
Modified:
    team/may/smpp/branches/10/addons/Makefile
    team/may/smpp/branches/10/addons/res_smpp.c

Modified: team/may/smpp/branches/10/addons/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/may/smpp/branches/10/addons/Makefile?view=diff&rev=411579&r1=411578&r2=411579
==============================================================================
--- team/may/smpp/branches/10/addons/Makefile (original)
+++ team/may/smpp/branches/10/addons/Makefile Mon Mar 31 12:38:09 2014
@@ -25,6 +25,8 @@
 	h323/MULTIMEDIA-SYSTEM-CONTROLDec.o h323/MULTIMEDIA-SYSTEM-CONTROLEnc.o
 
 H323CFLAGS:=-Iooh323c/src -Iooh323c/src/h323
+
+GSMOBJS:=gsm.o
 
 ALL_C_MODS:=app_mysql \
             app_saycountpl \
@@ -66,11 +68,13 @@
 $(if $(filter format_mp3,$(EMBEDDED_MODS)),modules.link,format_mp3.so): mp3/common.o mp3/dct64_i386.o mp3/decode_ntom.o mp3/layer3.o mp3/tabinit.o mp3/interface.o
 
 chan_ooh323.o: _ASTCFLAGS+=$(H323CFLAGS)
-res_smpp.o: _ASTCFLAGS+=-I/usr/local/include
-res_smpp.so: LIBS+=-L/usr/local/lib -lsmpp34
+res_smpp.o: _ASTCFLAGS+=-I.
+res_smpp.so: LIBS+=-lsmpp34
 
 $(if $(filter chan_ooh323,$(EMBEDDED_MODS)),modules.link,chan_ooh323.so): _ASTCFLAGS+=$(H323CFLAGS)
 $(if $(filter chan_ooh323,$(EMBEDDED_MODS)),modules.link,chan_ooh323.so): $(addprefix ooh323c/src/,$(H323OBJS)) chan_ooh323.o ooh323cDriver.o
 $(addprefix ooh323c/src/,$(H323OBJS)) chan_ooh323.o ooh323cDriver.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,chan_ooh323)
+$(if $(filter res_smpp,$(EMBEDDED_MODS)),modules.link,res_smpp.so): $(addprefix smpp/,$(GSMOBJS)) res_smpp.o
+$(addprefix smpp/,$(GSMOBJS)) res_smpp.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_smpp)
 
 .PHONY: check_mp3

Modified: team/may/smpp/branches/10/addons/res_smpp.c
URL: http://svnview.digium.com/svn/asterisk/team/may/smpp/branches/10/addons/res_smpp.c?view=diff&rev=411579&r1=411578&r2=411579
==============================================================================
--- team/may/smpp/branches/10/addons/res_smpp.c (original)
+++ team/may/smpp/branches/10/addons/res_smpp.c Mon Mar 31 12:38:09 2014
@@ -55,12 +55,36 @@
 #include "asterisk/causes.h"
 #include "asterisk/message.h"
 
+/***	DOCUMENTATION
+	<function name="smpp_recode" language="en_US">
+		<synopsis>
+			transcode message base64 content from/to UTF-8
+		</synopsis>
+		<syntax>
+			<parameter name="direction" required="true">
+				<para>from or to UTF8</para>
+			</parameter>
+			<parameter name="smpp encdoning" required="true">
+				<para>ucs-2 or gsm8</para>
+			</parameter>
+			<parameter name="string" required="true">
+				<para>input string</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>Returns the transcoded string in base64.</para>
+		</description>
+
+	</function>
+***/
+
 
 #define	MODULE_DESCRIPTION	"SMPP messaging resource module"
 
 #include "smpp34.h"
 #include "smpp34_structs.h"
 #include "smpp34_params.h"
+#include "smpp/gsm.h"
 
 #define	TRUE	1
 #define	FALSE	0
@@ -1708,6 +1732,97 @@
 #undef FORMAT2
 }
 
+
+static int smpp_recode(struct ast_channel *chan, const char *cmd, char *arguments, char *buf, size_t len)
+{
+	AST_DECLARE_APP_ARGS(args,
+		AST_APP_ARG(direction);
+		AST_APP_ARG(smpp_charset);
+		AST_APP_ARG(text);
+	);
+
+	int incount = 0, outcount = 0;
+	char *parse;
+	char *text = NULL;
+	unsigned char *tmpin, *tmp;
+	char esm_class[1024] = "";
+	int offset = 0;
+
+	
+
+
+	if (ast_strlen_zero(arguments)) {
+		ast_log(LOG_WARNING, "Syntax: SMPP_RECODE(<from/to>,<CHARSET>,<text>) - missing arguments!\n");
+		return -1;
+	}
+
+	parse = ast_strdupa(arguments);
+	AST_STANDARD_APP_ARGS(args, parse);
+	if (args.argc < 3) {
+		ast_log(LOG_WARNING, "Syntax: SMPP_RECODE(<from/to>,<CHARSET>,<text>) - missing arguments!\n");
+		return -1;
+	}
+
+	text = args.text;
+	if (!(tmpin = ast_alloca(strlen(text)))) {
+		ast_log(LOG_ERROR, "can't allocate buffer memory\n");
+		return -1;
+	}
+	if (!(tmp = ast_alloca(strlen(text)*2))) {
+		ast_log(LOG_ERROR, "can't allocate buffer memory\n");
+		return -1;
+	}
+        incount = ast_base64decode(tmpin, text, sizeof(tmpin)-1);
+
+//	check UDH header on message data
+
+	if (ast_func_read(chan, "MESSAGE_DATA(esm_class)", esm_class, sizeof(esm_class)) != -1) {
+		if (atoi(esm_class) & 0x40) {
+			offset = tmpin[0] + 1;
+			if (offset >= incount) {
+				offset = 0; // the case of incorrect message
+			} else {
+				incount -= offset;
+			}
+		}
+	}
+
+	if (!strcasecmp(args.direction, "from")) {
+		if (!strcasecmp(args.smpp_charset, "ucs2")) {
+			outcount = ucs2_to_utf8(tmpin + offset, incount, tmp);
+			ast_base64encode(buf, (void *)tmp, outcount, len);
+			goto doneok;
+		}
+		if (!strcasecmp(args.smpp_charset, "gsm8")) {
+			outcount = utf8_from_gsm8(tmpin + offset, incount, tmp);
+			ast_base64encode(buf, (void *)tmp, outcount, len);
+			goto doneok;
+		}
+	}
+	if (!strcasecmp(args.direction, "to")) {
+		if (!strcasecmp(args.smpp_charset, "ucs2")) {
+			outcount = utf8_to_ucs2(tmpin + offset, incount, tmp) * 2;	// 2 bytes on UCS2 char
+			ast_base64encode(buf, (void *)tmp, outcount, len);
+			goto doneok;
+		}
+		if (!strcasecmp(args.smpp_charset, "gsm8")) {
+			outcount = utf8_to_gsm8(tmpin + offset, incount, tmp);
+			ast_base64encode(buf, (void *)tmp, outcount, len);
+			goto doneok;
+		}
+	}
+
+	ast_log(LOG_WARNING, "Wrong direction: %s\n", args.direction);
+	return -1;
+
+doneok:
+
+	ast_free(tmp);
+	ast_free(tmpin);
+	return 0;
+}
+
+
 static const struct ast_msg_tech smpp_msg_tech = {
 	.name = "smpp",
 	.msg_send = smpp_msg_send,
@@ -1719,9 +1834,18 @@
 	AST_CLI_DEFINE(handle_cli_smpp_show_peers,	     "Show SMPP peers"),
 };
 
+static struct ast_custom_function acf_smpprecode = {
+	.name = "SMPP_RECODE",
+	.read = smpp_recode,
+};
+
 static int load_module(void)
 {
 	if (ast_msg_tech_register(&smpp_msg_tech)) {
+		return AST_MODULE_LOAD_FAILURE;
+	}
+
+	if (ast_custom_function_register(&acf_smpprecode)) {
 		return AST_MODULE_LOAD_FAILURE;
 	}
 
@@ -1755,6 +1879,7 @@
 
 	ast_msg_tech_unregister(&smpp_msg_tech);
 	ast_cli_unregister_multiple(cli_smpp, sizeof(cli_smpp) / sizeof(struct ast_cli_entry));
+	ast_custom_function_unregister(&acf_smpprecode);
 	stop_monitor_threads();
 	destroy_smscs();
 

Added: team/may/smpp/branches/10/addons/smpp/gsm.c
URL: http://svnview.digium.com/svn/asterisk/team/may/smpp/branches/10/addons/smpp/gsm.c?view=auto&rev=411579
==============================================================================
--- team/may/smpp/branches/10/addons/smpp/gsm.c (added)
+++ team/may/smpp/branches/10/addons/smpp/gsm.c Mon Mar 31 12:38:09 2014
@@ -1,0 +1,1220 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+*/
+#include "gsm.h"
+#include <stdlib.h>
+#include <string.h>
+
+/** UTILITIES
+ **/
+byte_t
+gsm_int_to_bcdi( int  value )
+{
+    return (byte_t)((value / 10) | ((value % 10) << 4));
+}
+
+int
+gsm_int_from_bcdi( byte_t  val )
+{
+    int  ret = 0;
+
+    if ((val & 0xf0) <= 0x90)
+        ret = (val >> 4);
+
+    if ((val & 0x0f) <= 0x90)
+        ret |= (val % 0xf)*10;
+
+    return ret;
+}
+
+#if 0
+static int
+gsm_bcdi_to_ascii( cbytes_t  bcd, int  bcdlen, bytes_t  dst )
+{
+    static byte_t  bcdichars[14] = "0123456789*#,N";
+
+    int  result = 0;
+    int  shift  = 0;
+
+    while (bcdlen > 0) {
+        int  c = (bcd[0] >> shift) & 0xf;
+
+        if (c == 0xf && bcdlen == 1)
+            break;
+
+        if (c < 14) {
+            if (dst) dst[result] = bcdichars[c];
+            result += 1;
+        }
+        bcdlen --;
+        shift += 4;
+        if (shift == 8) {
+            bcd++;
+            shift = 0;
+        }
+    }
+    return result;
+}
+#endif
+
+#if 0
+static int
+gsm_bcdi_from_ascii( cbytes_t  ascii, int  asciilen, bytes_t  dst )
+{
+    cbytes_t  end    = ascii + asciilen;
+    int       result = 0;
+    int       phase  = 0x01;
+
+    while (ascii < end) {
+        int  c = *ascii++;
+
+        if (c == '*')
+            c = 11;
+        else if (c == '#')
+            c = 12;
+        else if (c == ',')
+            c = 13;
+        else if (c == 'N')
+            c = 14;
+        else {
+            c -= '0';
+            if ((unsigned)c >= 10)
+                break;
+        }
+        phase = (phase << 4) | c;
+        if (phase & 0x100) {
+            if (dst) dst[result] = (byte_t) phase;
+            result += 1;
+            phase   = 0x01;
+        }
+    }
+    if (phase != 0x01) {
+        if (dst) dst[result] = (byte_t)( phase | 0xf0 );
+        result += 1;
+    }
+    return  result;
+}
+#endif
+
+int
+gsm_hexchar_to_int( char  c )
+{
+    if ((unsigned)(c - '0') < 10)
+        return c - '0';
+    if ((unsigned)(c - 'a') < 6)
+        return 10 + (c - 'a');
+    if ((unsigned)(c - 'A') < 6)
+        return 10 + (c - 'A');
+    return -1;
+}
+
+int
+gsm_hexchar_to_int0( char  c )
+{
+    int  ret = gsm_hexchar_to_int(c);
+
+    return (ret < 0) ? 0 : ret;
+}
+
+int
+gsm_hex2_to_byte( const char*  hex )
+{
+    int  hi = gsm_hexchar_to_int(hex[0]);
+    int  lo = gsm_hexchar_to_int(hex[1]);
+
+    if (hi < 0 || lo < 0)
+        return -1;
+
+    return ( (hi << 4) | lo );
+}
+
+int
+gsm_hex4_to_short( const char*  hex )
+{
+    int  hi = gsm_hex2_to_byte(hex);
+    int  lo = gsm_hex2_to_byte(hex+2);
+
+    if (hi < 0 || lo < 0)
+        return -1;
+
+    return ((hi << 8) | lo);
+}
+
+int
+gsm_hex2_to_byte0( const char*  hex )
+{
+    int  hi = gsm_hexchar_to_int0(hex[0]);
+    int  lo = gsm_hexchar_to_int0(hex[1]);
+
+    return (byte_t)( (hi << 4) | lo );
+}
+
+void
+gsm_hex_from_byte( char*  hex, int val )
+{
+    static const char  hexdigits[] = "0123456789abcdef";
+
+    hex[0] = hexdigits[(val >> 4) & 15];
+    hex[1] = hexdigits[val & 15];
+}
+
+void
+gsm_hex_from_short( char*  hex, int  val )
+{
+    gsm_hex_from_byte( hex,   (val >> 8) );
+    gsm_hex_from_byte( hex+2, val );
+}
+
+
+
+/** HEX
+ **/
+void
+gsm_hex_to_bytes0( cbytes_t  hex, int  hexlen, bytes_t  dst )
+{
+    int  nn;
+
+    for (nn = 0; nn < hexlen/2; nn++ ) {
+        dst[nn] = (byte_t) gsm_hex2_to_byte0( (const char*)hex+2*nn );
+    }
+    if (hexlen & 1) {
+        dst[nn] = gsm_hexchar_to_int0( hex[2*nn] ) << 4;
+    }
+}
+
+int
+gsm_hex_to_bytes( cbytes_t  hex, int  hexlen, bytes_t  dst )
+{
+    int  nn;
+
+    if (hexlen & 1)  /* must be even */
+        return -1;
+
+    for (nn = 0; nn < hexlen/2; nn++ ) {
+        int  c = gsm_hex2_to_byte( (const char*)hex+2*nn );
+        if (c < 0) return -1;
+        dst[nn] = (byte_t) c;
+    }
+    return hexlen/2;
+}
+
+void
+gsm_hex_from_bytes( char*  hex, cbytes_t  src, int  srclen )
+{
+    int  nn;
+
+    for (nn = 0; nn < srclen; nn++) {
+        gsm_hex_from_byte( hex + 2*nn, src[nn] );
+    }
+}
+
+/** ROPES
+ **/
+
+void
+gsm_rope_init( GsmRope  rope )
+{
+    rope->data  = NULL;
+    rope->pos   = 0;
+    rope->max   = 0;
+    rope->error = 0;
+}
+
+void
+gsm_rope_init_alloc( GsmRope  rope, int  count )
+{
+    rope->data  = rope->data0;
+    rope->pos   = 0;
+    rope->max   = sizeof(rope->data0);
+    rope->error = 0;
+
+    if (count > 0) {
+        rope->data = calloc( count, 1 );
+        rope->max  = count;
+
+        if (rope->data == NULL) {
+            rope->error = 1;
+            rope->max   = 0;
+        }
+    }
+}
+
+int
+gsm_rope_done( GsmRope  rope )
+{
+    int  result = rope->error;
+
+    if (rope->data && rope->data != rope->data0)
+        free(rope->data);
+
+    rope->data  = NULL;
+    rope->pos   = 0;
+    rope->max   = 0;
+    rope->error = 0;
+
+    return result;
+}
+
+
+bytes_t
+gsm_rope_done_acquire( GsmRope  rope, int  *psize )
+{
+    bytes_t  result = rope->data;
+
+    *psize = rope->pos;
+    if (result == rope->data0) {
+        result = malloc(  rope->pos );
+        if (result != NULL)
+            memcpy( result, rope->data, rope->pos );
+    }
+    return result;
+}
+
+
+int
+gsm_rope_ensure( GsmRope  rope, int  new_count )
+{
+    if (rope->data != NULL) {
+        int       old_max  = rope->max;
+        bytes_t   old_data = rope->data == rope->data0 ? NULL : rope->data;
+        int       new_max  = old_max;
+        bytes_t   new_data;
+
+        while (new_max < new_count) {
+            new_max += (new_max >> 1) + 4;
+        }
+        new_data = realloc( old_data, new_max );
+        if (new_data == NULL) {
+            rope->error = 1;
+            return -1;
+        }
+        rope->data = new_data;
+        rope->max  = new_max;
+    } else {
+        rope->max = new_count;
+    }
+    return 0;
+}
+
+static int
+gsm_rope_can_grow( GsmRope  rope, int  count )
+{
+    if (!rope->data || rope->error)
+        return 0;
+
+    if (rope->pos + count > rope->max)
+    {
+        if (rope->data == NULL)
+            rope->max = rope->pos + count;
+
+        else if (rope->error ||
+                 gsm_rope_ensure( rope, rope->pos + count ) < 0)
+            return 0;
+    }
+    return 1;
+}
+
+void
+gsm_rope_add_c( GsmRope  rope,  char  c )
+{
+    if (gsm_rope_can_grow(rope, 1)) {
+        rope->data[ rope->pos ] = (byte_t) c;
+    }
+    rope->pos += 1;
+}
+
+void
+gsm_rope_add( GsmRope  rope, const void*  buf, int  buflen )
+{
+    if (gsm_rope_can_grow(rope, buflen)) {
+        memcpy( rope->data + rope->pos, (const char*)buf, buflen );
+    }
+    rope->pos += buflen;
+}
+
+void*
+gsm_rope_reserve( GsmRope  rope, int  count )
+{
+    void*  result = NULL;
+
+    if (gsm_rope_can_grow(rope, count))
+    {
+        if (rope->data != NULL)
+            result = rope->data + rope->pos;
+    }
+    rope->pos += count;
+
+    return result;
+}
+
+/* skip a given number of Unicode characters in a utf-8 byte string */
+cbytes_t
+utf8_skip( cbytes_t   utf8,
+           cbytes_t   utf8end,
+           int        count)
+{
+    cbytes_t  p   = utf8;
+    cbytes_t  end = utf8end;
+
+    for ( ; count > 0; count-- ) {
+        int  c;
+
+        if (p >= end)
+            break;
+
+        c = *p++;
+        if (c > 128) {
+            while (p < end && (p[0] & 0xc0) == 0x80)
+                p++;
+        }
+    }
+    return  p;
+}
+
+
+static __inline__ int
+utf8_next( cbytes_t  *pp, cbytes_t  end )
+{
+    cbytes_t  p      = *pp;
+    int       result = -1;
+
+    if (p < end) {
+        int  c= *p++;
+        if (c >= 128) {
+            if ((c & 0xe0) == 0xc0)
+                c &= 0x1f;
+            else if ((c & 0xf0) == 0xe0)
+                c &= 0x0f;
+            else
+                c &= 0x07;
+
+            while (p < end && (p[0] & 0xc0) == 0x80) {
+                c = (c << 6) | (p[0] & 0x3f);
+                p ++;
+            }
+        }
+        result = c;
+        *pp    = p;
+    }
+    return result;
+}
+
+
+__inline__ int
+utf8_write( bytes_t  utf8, int  offset, int  v )
+{
+    int  result;
+
+    if (v < 128) {
+        result = 1;
+        if (utf8)
+            utf8[offset] = (byte_t) v;
+    } else if (v < 0x800) {
+        result = 2;
+        if (utf8) {
+            utf8[offset+0] = (byte_t)( 0xc0 | (v >> 6) );
+            utf8[offset+1] = (byte_t)( 0x80 | (v & 0x3f) );
+        }
+    } else if (v < 0x10000) {
+        result = 3;
+        if (utf8) {
+            utf8[offset+0] = (byte_t)( 0xe0 |  (v >> 12) );
+            utf8[offset+1] = (byte_t)( 0x80 | ((v >> 6) & 0x3f) );
+            utf8[offset+2] = (byte_t)( 0x80 |  (v & 0x3f) );
+        }
+    } else {
+        result = 4;
+        if (utf8) {
+            utf8[offset+0] = (byte_t)( 0xf0 | ((v >> 18) & 0x7) );
+            utf8[offset+1] = (byte_t)( 0x80 | ((v >> 12) & 0x3f) );
+            utf8[offset+2] = (byte_t)( 0x80 | ((v >> 6) & 0x3f) );
+            utf8[offset+3] = (byte_t)( 0x80 |  (v & 0x3f) );
+        }
+    }
+    return  result;
+}
+
+static __inline__ int
+ucs2_write( bytes_t  ucs2, int  offset, int  v )
+{
+    if (ucs2) {
+        ucs2[offset+0] = (byte_t) (v >> 8);
+        ucs2[offset+1] = (byte_t) (v);
+    }
+    return 2;
+}
+
+int
+utf8_check( cbytes_t   p, int  utf8len )
+{
+    cbytes_t  end    = p + utf8len;
+    int       result = 0;
+
+    if (p) {
+        while (p < end) {
+            int  c = *p++;
+            if (c >= 128) {
+                int  len;
+                if ((c & 0xe0) == 0xc0) {
+                    len = 1;
+                }
+                else if ((c & 0xf0) == 0xe0) {
+                    len = 2;
+                }
+                else if ((c & 0xf8) == 0xf0) {
+                    len = 3;
+                }
+                else
+                    goto Exit;  /* malformed utf-8 */
+
+                if (p+len > end) /* string too short */
+                    goto Exit;
+
+                for ( ; len > 0; len--, p++ ) {
+                    if ((p[0] & 0xc0) != 0x80)
+                        goto Exit;
+                }
+            }
+        }
+        result = 1;
+    }
+Exit:
+    return result;
+}
+
+/** UCS2 to UTF8
+ **/
+
+/* convert a UCS2 string into a UTF8 byte string, assumes 'buf' is correctly sized */
+int
+ucs2_to_utf8( cbytes_t  ucs2,
+              int       ucs2len,
+              bytes_t   buf )
+{
+    int  nn;
+    int  result = 0;
+
+    for (nn = 0; nn < ucs2len; ucs2 += 2, nn++) {
+        int  c= (ucs2[0] << 8) | ucs2[1];
+        result += utf8_write(buf, result, c);
+    }
+    return result;
+}
+
+/* count the number of UCS2 chars contained in a utf8 byte string */
+int
+utf8_to_ucs2( cbytes_t  utf8,
+              int       utf8len,
+              bytes_t   ucs2 )
+{
+    cbytes_t  p      = utf8;
+    cbytes_t  end    = p + utf8len;
+    int       result = 0;
+
+    while (p < end) {
+        int  c = utf8_next(&p, end);
+
+        if (c < 0)
+            break;
+
+        result += ucs2_write(ucs2, result, c);
+    }
+    return result/2;
+}
+
+
+
+/** GSM ALPHABET
+ **/
+
+#define  GSM_7BITS_ESCAPE   0x1b
+#define  GSM_7BITS_UNKNOWN  0
+
+static const unsigned short   gsm7bits_to_unicode[128] = {
+  '@', 0xa3,  '$', 0xa5, 0xe8, 0xe9, 0xf9, 0xec, 0xf2, 0xc7, '\n', 0xd8, 0xf8, '\r', 0xc5, 0xe5,
+0x394,  '_',0x3a6,0x393,0x39b,0x3a9,0x3a0,0x3a8,0x3a3,0x398,0x39e,    0, 0xc6, 0xe6, 0xdf, 0xc9,
+  ' ',  '!',  '"',  '#', 0xa4,  '%',  '&', '\'',  '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',
+  '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  ':',  ';',  '<',  '=',  '>',  '?',
+ 0xa1,  'A',  'B',  'C',  'D',  'E',  'F',  'G',  'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
+  'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  'X',  'Y',  'Z', 0xc4, 0xd6,0x147, 0xdc, 0xa7,
+ 0xbf,  'a',  'b',  'c',  'd',  'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l',  'm',  'n',  'o',
+  'p',  'q',  'r',  's',  't',  'u',  'v',  'w',  'x',  'y',  'z', 0xe4, 0xf6, 0xf1, 0xfc, 0xe0,
+};
+
+static const unsigned short  gsm7bits_extend_to_unicode[128] = {
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\f',   0,   0,   0,   0,   0,
+    0,   0,   0,   0, '^',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0, '{', '}',   0,   0,   0,   0,   0,'\\',
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, '[', '~', ']',   0,
+  '|',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,0x20ac, 0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
+};
+
+
+static int
+unichar_to_gsm7( int  unicode )
+{
+    int  nn;
+    for (nn = 0; nn < 128; nn++) {
+        if (gsm7bits_to_unicode[nn] == unicode) {
+            return nn;
+        }
+    }
+    return -1;
+}
+
+static int
+unichar_to_gsm7_extend( int  unichar )
+{
+    int  nn;
+    for (nn = 0; nn < 128; nn++) {
+        if (gsm7bits_extend_to_unicode[nn] == unichar) {
+            return nn;
+        }
+    }
+    return -1;
+}
+
+
+/* return the number of septets needed to encode a unicode charcode */
+static int
+unichar_to_gsm7_count( int  unicode )
+{
+    int  nn;
+
+    nn = unichar_to_gsm7(unicode);
+    if (nn >= 0)
+        return 1;
+
+    nn = unichar_to_gsm7_extend(unicode);
+    if (nn >= 0)
+        return 2;
+
+    return 0;
+}
+
+
+cbytes_t
+utf8_skip_gsm7( cbytes_t  utf8, cbytes_t  utf8end, int  gsm7len )
+{
+    cbytes_t  p   = utf8;
+    cbytes_t  end = utf8end;
+
+    while (gsm7len >0) {
+        cbytes_t  q = p;
+        int       c = utf8_next( &q, end );
+        int       len;
+
+        if (c < 0)
+            break;
+
+        len = unichar_to_gsm7_count( c );
+        if (len == 0)  /* unknown chars are replaced by spaces */
+            len = 1;
+
+        if (len > gsm7len)
+            break;
+
+        gsm7len -= len;
+        p        = q;
+    }
+    return  p;
+}
+
+
+int
+utf8_check_gsm7( cbytes_t  utf8,
+                 int       utf8len )
+{
+    cbytes_t  utf8end = utf8 + utf8len;
+
+    while (utf8 < utf8end) {
+        int  c = utf8_next( &utf8, utf8end );
+        if (unichar_to_gsm7_count(c) == 0)
+            return 0;
+    }
+    return 1;
+}
+
+
+int
+utf8_from_gsm7( cbytes_t  src,
+                int       septet_offset,
+                int       septet_count,
+                bytes_t   utf8 )
+{
+    int  shift   = (septet_offset & 7);
+    int  escaped = 0;
+    int  result  = 0;
+
+    src += (septet_offset >> 3);
+    for ( ; septet_count > 0; septet_count-- )
+    {
+        int  c = (src[0] >> shift) & 0x7f;
+        int  v;
+
+        if (shift > 1) {
+            c = ((src[1] << (8-shift)) | c) & 0x7f;
+        }
+
+        if (escaped) {
+            v = gsm7bits_extend_to_unicode[c];
+        } else if (c == GSM_7BITS_ESCAPE) {
+            escaped = 1;
+            goto NextSeptet;
+        } else {
+            v = gsm7bits_to_unicode[c];
+        }
+
+        result += utf8_write( utf8, result, v );
+
+    NextSeptet:
+        shift += 7;
+        if (shift >= 8) {
+            shift -= 8;
+            src   += 1;
+        }
+    }
+    return  result;
+}
+
+
+int
+utf8_from_gsm8( cbytes_t  src, int  count, bytes_t  utf8 )
+{
+    int  result  = 0;
+    int  escaped = 0;
+
+
+    for ( ; count > 0; count-- )
+    {
+        int  c = *src++;
+
+        if (c == 0xff)
+            break;
+
+        if (c == GSM_7BITS_ESCAPE) {
+            if (escaped) { /* two escape characters => one space */
+                c = 0x20;
+                escaped = 0;
+            } else {
+                escaped = 1;
+                continue;
+            }
+        }
+        else
+        {
+            if (c >= 0x80) {
+                c       = 0x20;
+                escaped = 0;
+            } else if (escaped) {
+                c = gsm7bits_extend_to_unicode[c];
+            } else
+                c = gsm7bits_to_unicode[c];
+        }
+
+        result += utf8_write( utf8, result, c );
+    }
+    return  result;
+}
+
+/* convert a GSM 7-bit message into a unicode character array
+ * the 'dst' array must contain at least 160 chars. the function
+ * returns the number of characters decoded
+ *
+ * assumes the 'dst' array has at least septet_count items, returns the
+ * number of unichars really written
+ */
+int
+ucs2_from_gsm7( bytes_t   ucs2,
+                cbytes_t  src,
+                int       septet_offset,
+                int       septet_count )
+{
+    const unsigned char*  p     = src + (septet_offset >> 3);
+    int                   shift = (septet_offset & 7);
+    int                   escaped = 0;
+    int                   result  = 0;
+
+    for ( ; septet_count > 0; septet_count-- )
+    {
+        unsigned  val  = (p[0] >> shift) & 0x7f;
+
+        if (shift > 1)
+            val = (val | (p[1] << (8-shift))) & 0x7f;
+
+        if (escaped) {
+            int  c = gsm7bits_to_unicode[val];
+
+            result += ucs2_write(ucs2, result, c);
+            escaped = 0;
+        }
+        else if (val == GSM_7BITS_ESCAPE) {
+            escaped = 1;
+        }
+        else {
+            val = gsm7bits_extend_to_unicode[val];
+            if (val == 0)
+                val = 0x20;
+
+            result += ucs2_write( ucs2, result, val );
+        }
+    }
+    return result/2;
+}
+
+
+/* count the number of septets required to write a utf8 string */
+static int
+utf8_to_gsm7_count( cbytes_t  utf8, int  utf8len )
+{
+    cbytes_t  utf8end = utf8 + utf8len;
+    int       result  = 0;
+
+    while ( utf8 < utf8end ) {
+        int  len;
+        int  c = utf8_next( &utf8, utf8end );
+
+        if (c < 0)
+            break;
+
+        len = unichar_to_gsm7_count(c);
+        if (len == 0)    /* replace non-representables with space */
+            len = 1;
+
+        result += len;
+    }
+    return result;
+}
+
+typedef struct {
+    bytes_t   dst;
+    unsigned  pad;
+    int       bits;
+    int       offset;
+} BWriterRec, *BWriter;
+
+static void
+bwriter_init( BWriter  writer, bytes_t  dst, int  start )
+{
+    int  shift = start & 7;
+
+    writer->dst    = dst + (start >> 3);
+    writer->pad    = 0;
+    writer->bits   = shift;
+    writer->offset = start;
+
+    if (shift > 0) {
+        writer->pad  = writer->dst[0] & ~(0xFF << shift);
+    }
+}
+
+static void
+bwriter_add7( BWriter  writer, unsigned  value )
+{
+    writer->pad  |= (unsigned)(value << writer->bits);
+    writer->bits += 7;
+    if (writer->bits >= 8) {
+        writer->dst[0] = (byte_t)writer->pad;
+        writer->bits  -= 8;
+        writer->pad  >>= 8;
+        writer->dst   += 1;
+    }
+    writer->offset += 7;
+}
+
+static int
+bwriter_done( BWriter  writer )
+{
+    if (writer->bits > 0) {
+        writer->dst[0] = (byte_t)writer->pad;
+        writer->pad    = 0;
+        writer->bits   = 0;
+        writer->dst   += 1;
+    }
+    return writer->offset;
+}
+
+/* convert a utf8 string to a gsm7 byte string - return the number of septets written */
+int
+utf8_to_gsm7( cbytes_t  utf8, int  utf8len, bytes_t  dst, int offset )
+{
+    const unsigned char*  utf8end = utf8 + utf8len;
+    BWriterRec            writer[1];
+
+    if (dst == NULL)
+        return utf8_to_gsm7_count(utf8, utf8len);
+
+    bwriter_init( writer, dst, offset );
+    while ( utf8 < utf8end ) {
+        int  c = utf8_next( &utf8, utf8end );
+        int  nn;
+
+        if (c < 0)
+            break;
+
+        nn = unichar_to_gsm7(c);
+        if (nn >= 0) {
+            bwriter_add7( writer, nn );
+            continue;
+        }
+
+        nn = unichar_to_gsm7_extend(c);
+        if (nn >= 0) {
+            bwriter_add7( writer, GSM_7BITS_ESCAPE );
+            bwriter_add7( writer, nn );
+            continue;
+        }
+
+        /* unknown => replaced by space */
+        bwriter_add7( writer, 0x20 );
+    }
+    return  bwriter_done( writer );
+}
+
+
+int
+utf8_to_gsm8( cbytes_t  utf8, int  utf8len, bytes_t  dst )
+{
+    const unsigned char*  utf8end = utf8 + utf8len;
+    int                   result  = 0;
+
+    while ( utf8 < utf8end ) {
+        int  c = utf8_next( &utf8, utf8end );
+        int  nn;
+
+        if (c < 0)
+            break;
+
+        nn = unichar_to_gsm7(c);
+        if (nn >= 0) {
+            if (dst)
+                dst[result] = (byte_t)nn;
+            result += 1;
+            continue;
+        }
+
+        nn = unichar_to_gsm7_extend(c);
+        if (nn >= 0) {
+            if (dst) {
+                dst[result+0] = (byte_t) GSM_7BITS_ESCAPE;
+                dst[result+1] = (byte_t) nn;
+            }
+            result += 2;
+            continue;
+        }
+
+        /* unknown => space */
+        if (dst)
+            dst[result] = 0x20;
+        result += 1;
+    }
+    return  result;
+}
+
+
+int
+ucs2_to_gsm7( cbytes_t  ucs2, int  ucs2len, bytes_t  dst, int offset )
+{
+    const unsigned char*  ucs2end = ucs2 + ucs2len*2;
+    BWriterRec            writer[1];
+
+    bwriter_init( writer, dst, offset );
+    while ( ucs2 < ucs2end ) {
+        int  c = *ucs2++;
+        int  nn;
+
+        for (nn = 0; nn < 128; nn++) {
+            if ( gsm7bits_to_unicode[nn] == c ) {
+                bwriter_add7( writer, nn );
+                goto NextUnicode;
+            }
+        }
+        for (nn = 0; nn < 128; nn++) {
+            if ( gsm7bits_extend_to_unicode[nn] == c ) {
+                bwriter_add7( writer, GSM_7BITS_ESCAPE );
+                bwriter_add7( writer, nn );
+                goto NextUnicode;
+            }
+        }
+
+        /* unknown */
+        bwriter_add7( writer, 0x20 );
+
+    NextUnicode:
+        ;
+    }
+    return  bwriter_done( writer );
+}
+
+
+int
+ucs2_to_gsm8( cbytes_t  ucs2, int  ucs2len, bytes_t  dst )
+{
+    const unsigned char*  ucs2end = ucs2 + ucs2len*2;
+    bytes_t               dst0    = dst;
+
+    while ( ucs2 < ucs2end ) {
+        int  c = *ucs2++;
+        int  nn;
+
+        for (nn = 0; nn < 128; nn++) {
+            if ( gsm7bits_to_unicode[nn] == c ) {
+                *dst++ = (byte_t)nn;
+                goto NextUnicode;
+            }
+        }
+        for (nn = 0; nn < 128; nn++) {
+            if ( gsm7bits_extend_to_unicode[nn] == c ) {
+                dst[0] = (byte_t) GSM_7BITS_ESCAPE;
+                dst[1] = (byte_t) nn;
+                dst   += 2;
+                goto NextUnicode;
+            }
+        }
+
+        /* unknown */
+        *dst++ = 0x20;
+
+    NextUnicode:
+        ;
+    }
+    return (dst - dst0);
+}
+
+int
+gsm_bcdnum_to_ascii( cbytes_t  bcd, int  count, bytes_t  dst )
+{
+    int  result = 0;
+    int  shift  = 0;
+
+    while (count > 0) {
+        int  c = (bcd[0] >> shift) & 0xf;
+
+        if (c == 15 && count == 1)  /* ignore trailing 0xf */
+            break;
+
+        if (c >= 14)
+            c = 0;
+
+        if (dst) dst[result] = "0123456789*#,N"[c];
+        result += 1;
+
+        shift += 4;
+        if (shift == 8) {
+            shift = 0;
+            bcd += 1;
+        }
+    }
+    return  result;
+}
+
+
+int
+gsm_bcdnum_from_ascii( cbytes_t  ascii, int  asciilen, bytes_t  dst )
+{
+    cbytes_t  end = ascii + asciilen;
+    int  result   = 0;
+    int  phase = 0x01;
+
+    while (ascii < end) {
+        int  c = *ascii++;
+
+        if (c == '*')
+            c = 10;
+        else if (c == '#')
+            c = 11;
+        else if (c == ',')
+            c = 12;
+        else if (c == 'N')
+            c = 13;
+        else {
+            c -= '0';
+            if ((unsigned)c >= 10U)
+                return -1;
+        }
+        phase   = (phase << 4) | c;
+        result += 1;
+        if (phase & 0x100) {
+            if (dst) dst[result/2] = (byte_t) phase;
+            phase   = 0x01;
+        }
+    }
+
+    if (result & 1) {
+        if (dst) dst[result/2] = (byte_t)(phase | 0xf0);
+    }
+    return result;
+}
+
+/** ADN: Abbreviated Dialing Number
+ **/
+
+#define  ADN_FOOTER_SIZE     14
+#define  ADN_OFFSET_NUMBER_LENGTH   0
+#define  ADN_OFFSET_TON_NPI         1
+#define  ADN_OFFSET_NUMBER_START    2
+#define  ADN_OFFSET_NUMBER_END      11
+#define  ADN_OFFSET_CAPABILITY_ID   12
+#define  ADN_OFFSET_EXTENSION_ID    13
+
+/* see 10.5.1 of 3GPP 51.011 */
+static int
+sim_adn_alpha_to_utf8( cbytes_t  alpha, cbytes_t  end, bytes_t  dst )
+{
+    int  result = 0;
+
+    /* ignore trailing 0xff */
+    while (alpha < end && end[-1] == 0xff)
+        end--;
+
+    if (alpha >= end)
+        return 0;
+
+    if (alpha[0] == 0x80) { /* UCS/2 source encoding */
+        alpha += 1;
+        result = ucs2_to_utf8( alpha, (end-alpha)/2, dst );
+    }
+    else
+    {
+        int  is_ucs2 = 0;
+        int  len = 0, base = 0;
+
+        if (alpha+3 <= end && alpha[0] == 0x81) {
+            is_ucs2 = 1;
+            len     = alpha[1];
+            base    = alpha[2] << 7;
+            alpha  += 3;
+            if (len > end-alpha)
+                len = end-alpha;
+        } else if (alpha+4 <= end && alpha[0] == 0x82) {
+            is_ucs2 = 1;
+            len     = alpha[1];
+            base    = (alpha[2] << 8) | alpha[3];
+            alpha  += 4;
+            if (len > end-alpha)
+                len = end-alpha;
+        }
+
+        if (is_ucs2) {
+            end = alpha + len;
+            while (alpha < end) {
+                int  c = alpha[0];
+                if (c >= 0x80) {
+                    result += utf8_write(dst, result, base + (c & 0x7f));
+                    alpha  += 1;
+                } else {
+                    /* GSM character set */
+                    int   count;
+                    for (count = 0; alpha+count < end && alpha[count] < 128; count++)
+                        ;
+                    result += utf8_from_gsm8(alpha, count, (dst ? dst+result : NULL));
+                    alpha  += count;
+                }
+            }
+        }
+        else {
+            result = utf8_from_gsm8(alpha, end-alpha, dst);
+        }
+    }
+    return result;
+}
+
+#if 0
+static int
+sim_adn_alpha_from_utf8( cbytes_t  utf8, int  utf8len, bytes_t  dst )
+{
+    int   result = 0;
+
+    if (utf8_check_gsm7(utf8, utf8len)) {
+        /* GSM 7-bit compatible, encode directly as 8-bit string */
+        result = utf8_to_gsm8(utf8, utf8len, dst);
+    } else {
+        /* otherwise, simply try UCS-2 encoding, nothing more serious at the moment */
+        if (dst) {
+            dst[0] = 0x80;
+        }
+        result = 1 + utf8_to_ucs2(utf8, utf8len, dst ? (dst+1) : NULL)*2;
+    }
+    return  result;
+}
+#endif
+
+int
+sim_adn_record_from_bytes( SimAdnRecord  rec, cbytes_t  data, int  len )
+{
+    cbytes_t  end    = data + len;
+    cbytes_t  footer = end - ADN_FOOTER_SIZE;
+    int       num_len;
+
+    rec->adn.alpha[0]  = 0;
+    rec->adn.number[0] = 0;
+    rec->ext_record    = 0xff;
+
+    if (len < ADN_FOOTER_SIZE)
+        return -1;
+
+    /* alpha is optional */
+    if (len > ADN_FOOTER_SIZE) {
+        cbytes_t  dataend = data + len - ADN_FOOTER_SIZE;
+        int       count   = sim_adn_alpha_to_utf8(data, dataend, NULL);
+
+        if (count > sizeof(rec->adn.alpha)-1)  /* too long */
+            return -1;
+
+        sim_adn_alpha_to_utf8(data, dataend, rec->adn.alpha);
+        rec->adn.alpha[count] = 0;
+    }
+
+    num_len = footer[ADN_OFFSET_NUMBER_LENGTH];
+    if (num_len > 11)
+        return -1;
+
+    /* decode TON and number to ASCII, NOTE: this is lossy !! */
+    {
+        int      ton    = footer[ADN_OFFSET_TON_NPI];
+        bytes_t  number = (bytes_t) rec->adn.number;
+        int      len    = sizeof(rec->adn.number)-1;
+        int      count;
+
+        if (ton != 0x81 && ton != 0x91)
+            return -1;
+
+        if (ton == 0x91) {
+            *number++ = '+';
+            len      -= 1;
+        }
+
+        count = gsm_bcdnum_to_ascii( footer + ADN_OFFSET_NUMBER_START,
+                                     num_len*2, number );
+        number[count] = 0;
+    }
+    return 0;
+}
+
+int
+sim_adn_record_to_bytes( SimAdnRecord  rec, bytes_t   data, int  datalen )
+{
+    bytes_t   end    = data + datalen;
+    bytes_t   footer = end - ADN_FOOTER_SIZE;
+    int       ton    = 0x81;
+    cbytes_t  number = (cbytes_t) rec->adn.number;
+
+    if (number[0] == '+') {
+        ton     = 0x91;
+        number += 1;
+    }
+    footer[0] = (strlen((const char*)number)+1)/2 + 1;
+    /* XXXX: TODO */
+    return 0;
+}

Propchange: team/may/smpp/branches/10/addons/smpp/gsm.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/may/smpp/branches/10/addons/smpp/gsm.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/may/smpp/branches/10/addons/smpp/gsm.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: team/may/smpp/branches/10/addons/smpp/gsm.h
URL: http://svnview.digium.com/svn/asterisk/team/may/smpp/branches/10/addons/smpp/gsm.h?view=auto&rev=411579
==============================================================================
--- team/may/smpp/branches/10/addons/smpp/gsm.h (added)
+++ team/may/smpp/branches/10/addons/smpp/gsm.h Mon Mar 31 12:38:09 2014
@@ -1,0 +1,198 @@
+/* Copyright (C) 2007-2008 The Android Open Source Project
+**
+** This software is licensed under the terms of the GNU General Public
+** License version 2, as published by the Free Software Foundation, and
+** may be copied, distributed, and modified under those terms.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU General Public License for more details.
+*/
+#ifndef _android_gsm_h
+#define _android_gsm_h
+
+/** USEFUL TYPES
+ **/
+
+typedef unsigned char  byte_t;
+typedef byte_t*        bytes_t;
+typedef const byte_t*  cbytes_t;
+
+/** BCD
+ **/
+
+/* convert a 8-bit value into the corresponding nibble-bcd byte */
+extern byte_t   gsm_int_to_bcdi( int  value );
+
+/* convert a nibble-bcd byte into an int, invalid nibbles are silently converted to 0 */
+extern int      gsm_int_from_bcdi( byte_t  value );
+
+/** HEX
+ **/
+
+/* try to convert a hex string into a byte string, assumes 'dst' is properly sized, and hexlen is even.
+ * returns the number of bytes on exit, or -1 in case of badly formatted data */
+extern int      gsm_hex_to_bytes  ( cbytes_t  hex, int  hexlen, bytes_t  dst );
+
+/* convert a hex string into a byte string, assumes 'dst' is properly sized, and hexlen is even.
+ * no checks are performed */
+extern void     gsm_hex_to_bytes0 ( cbytes_t  hex, int  hexlen, bytes_t  dst );
+
+/* convert a byte string into a hex string, assumes 'hex' is properly sized */
+extern void     gsm_hex_from_bytes( char*  hex, cbytes_t  src, int  srclen );
+
+/* convert a hexchar to an int, returns -1 on error */
+extern int      gsm_hexchar_to_int( char  c );
+
+/* convert a hexchar to an int, returns 0 on error */
+extern int      gsm_hexchar_to_int0( char  c );
+
+/* convert a 2-char hex value into an int, returns -1 on error */
+extern int      gsm_hex2_to_byte( const char*  hex );
+
+/* convert a 2-char hex value into an int, returns 0 on error */
+extern int      gsm_hex2_to_byte0( const char*  hex );
+
+/* convert a 4-char hex value into an int, returns -1 on error */
+extern int      gsm_hex4_to_short( const char*  hex );
+
+/* convert a 4-char hex value into an int, returns 0 on error */
+extern int      gsm_hex4_to_short0( const char*  hex );
+
+/* write a byte to a 2-byte hex string */
+extern void     gsm_hex_from_byte( char*  hex, int  val );
+
+extern void     gsm_hex_from_short( char*  hex, int  val );
+
+/** UTF-8 and GSM Alphabet
+ **/
+
+/* check that a given utf8 string is well-formed, returns 1 on success, 0 otherwise */
+extern int      utf8_check( cbytes_t  utf8, int  utf8len );
+
+/* check that all characters in a given utf8 string can be encoded into the GSM alphabet.
+   returns 1 if TRUE, 0 otherwise */
+extern int      utf8_check_gsm7( cbytes_t  utf8, int  utf8len );
+

[... 134 lines stripped ...]



More information about the svn-commits mailing list