Browse code

smsops: New module for handling 3GPP SMS over IP

Carsten Bock authored on 26/05/2015 20:22:49
Showing 8 changed files
... ...
@@ -15,7 +15,7 @@ mod_list_basic=async auth benchmark blst cfg_rpc cfgutils corex counters \
15 15
 				   nat_traversal nathelper path pike pv ratelimit rr rtimer \
16 16
 				   rtpproxy sanity sdpops siputils sl statistics textops \
17 17
 				   textopsx tm tmx topoh xlog rtpengine stun sipt tcpops \
18
-				   auth_xkeys
18
+				   auth_xkeys smsops
19 19
 
20 20
 # - extra used modules, with no extra dependency
21 21
 mod_list_extra=avp auth_diameter call_control dmq domainpolicy msrp pdb \
22 22
new file mode 100644
... ...
@@ -0,0 +1,18 @@
1
+#
2
+# smsops module makefile
3
+#
4
+# 
5
+# WARNING: do not run this directly, it should be run by the master Makefile
6
+
7
+include ../../Makefile.defs
8
+auto_gen=
9
+NAME=smsops.so
10
+LIBS=
11
+
12
+DEFS+=-DKAMAILIO_MOD_INTERFACE
13
+
14
+SERLIBPATH=../../lib
15
+SER_LIBS+=$(SERLIBPATH)/kmi/kmi
16
+SER_LIBS+=$(SERLIBPATH)/kcore/kcore
17
+SER_LIBS+=$(SERLIBPATH)/srutils/srutils
18
+include ../../Makefile.modules
0 19
new file mode 100644
... ...
@@ -0,0 +1,4 @@
1
+docs = smsops.xml
2
+
3
+docbook_dir = ../../../docbook
4
+include $(docbook_dir)/Makefile.module
0 5
new file mode 100644
... ...
@@ -0,0 +1,43 @@
1
+<?xml version="1.0" encoding='ISO-8859-1'?>
2
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
3
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
4
+
5
+<!-- Include general documentation entities -->
6
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
7
+%docentities;
8
+
9
+]>
10
+
11
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
12
+    <bookinfo>
13
+	<title>SMS-OPS Module</title>
14
+	<productname class="trade">&kamailioname;</productname>
15
+	<authorgroup>
16
+	    <author>
17
+		<firstname>Carsten</firstname>
18
+		<surname>Bock</surname>
19
+		<affiliation><orgname>ng-voice GmbH</orgname></affiliation>
20
+		<email>carsten@ng-voice.com</email>
21
+		<address>
22
+		<otheraddr>
23
+		<ulink url="http://www.ng-voice.com">http://www.ng-voice.com</ulink>
24
+		</otheraddr>
25
+		</address>
26
+	    </author>
27
+	    <editor>
28
+		<firstname>Carsten</firstname>
29
+		<surname>Bock</surname>
30
+		<email>carsten@ng-voice.com</email>
31
+	    </editor>
32
+	</authorgroup>
33
+	<copyright>
34
+	    <year>2015</year>
35
+	    <holder>Carsten Bock, ng-voice GmbH</holder>
36
+	</copyright>
37
+    </bookinfo>
38
+    <toc></toc>
39
+    
40
+    <xi:include href="smsops_admin.xml"/>
41
+    
42
+    
43
+</book>
0 44
new file mode 100644
... ...
@@ -0,0 +1,53 @@
1
+<?xml version="1.0" encoding='ISO-8859-1'?>
2
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
3
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
4
+
5
+<!-- Include general documentation entities -->
6
+<!ENTITY % docentities SYSTEM "../../../docbook/entities.xml">
7
+%docentities;
8
+
9
+]>
10
+<!-- Module User's Guide -->
11
+
12
+<chapter>
13
+	
14
+	<title>&adminguide;</title>
15
+	
16
+	<section>
17
+	<title>Overview</title>
18
+	<para>
19
+		This module collects the Transformations for 3GPP-SMS-V2.
20
+	</para>
21
+	</section>
22
+	<section>
23
+	<title>Dependencies</title>
24
+	<section>
25
+		<title>&kamailio; Modules</title>
26
+		<para>
27
+		The following modules must be loaded before this module:
28
+			<itemizedlist>
29
+			<listitem>
30
+			<para>
31
+				<emphasis>No dependencies on other &kamailio; modules</emphasis>.
32
+			</para>
33
+			</listitem>
34
+			</itemizedlist>
35
+		</para>
36
+	</section>
37
+	<section>
38
+		<title>External Libraries or Applications</title>
39
+		<para>
40
+		The following libraries or applications must be installed before running
41
+		&kamailio; with this module loaded:
42
+			<itemizedlist>
43
+			<listitem>
44
+			<para>
45
+				<emphasis>None</emphasis>.
46
+			</para>
47
+			</listitem>
48
+			</itemizedlist>
49
+		</para>
50
+	</section>
51
+	</section>
52
+</chapter>
53
+
0 54
new file mode 100644
... ...
@@ -0,0 +1,63 @@
1
+/**
2
+ * Copyright (C) 2015 Carsten Bock, ng-voice GmbH
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * Kamailio is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version
10
+ *
11
+ * Kamailio is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License 
17
+ * along with this program; if not, write to the Free Software 
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
+ */
20
+
21
+#include <stdio.h>
22
+#include <string.h>
23
+#include <stdlib.h>
24
+
25
+#include "../../sr_module.h"
26
+#include "../../pvar.h"
27
+#include "../../mod_fix.h"
28
+
29
+#include "smsops_impl.h"
30
+
31
+MODULE_VERSION
32
+
33
+static pv_export_t mod_pvs[] = {
34
+	{ {"smsack", sizeof("smsack")-1}, PVT_OTHER, pv_sms_ack, 0, 0, 0, 0, 0 },
35
+	{ {"rpdata", sizeof("rpdata")-1}, PVT_OTHER, pv_get_sms, pv_set_sms, pv_parse_rpdata_name, 0, 0, 0 },
36
+	{ {"tpdu", sizeof("tpdu")-1}, PVT_OTHER, pv_get_sms, pv_set_sms, pv_parse_tpdu_name, 0, 0, 0 },
37
+	{ {"smsbody", sizeof("smsbody")-1}, PVT_OTHER, pv_sms_body, 0, 0, 0, 0, 0 },
38
+	{ {0, 0}, 0, 0, 0, 0, 0, 0, 0 }
39
+};
40
+
41
+static cmd_export_t cmds[]={
42
+	{"smsdump",   (cmd_function)smsdump, 0, 0, 0, REQUEST_ROUTE},
43
+	{"isRPDATA",  (cmd_function)isRPDATA, 0, 0, 0, REQUEST_ROUTE},
44
+	{0,0,0,0,0,0}
45
+};
46
+
47
+/** module exports */
48
+struct module_exports exports= {
49
+	"smsops",
50
+	DEFAULT_DLFLAGS, /* dlopen flags */
51
+	cmds,
52
+	0,
53
+	0,          /* exported statistics */
54
+	0,    /* exported MI functions */
55
+	mod_pvs,    /* exported pseudo-variables */
56
+	0,          /* extra processes */
57
+	0,   /* module initialization function */
58
+	0,
59
+	0,
60
+	0           /* per-child init function */
61
+};
62
+
63
+
0 64
new file mode 100644
... ...
@@ -0,0 +1,904 @@
1
+/*
2
+ * Copyright (C) 2015 Carsten Bock, ng-voice GmbH
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * Kamailio is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version
10
+ *
11
+ * Kamailio is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License 
17
+ * along with this program; if not, write to the Free Software 
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
+ *
20
+ */
21
+
22
+/*! \file
23
+ * \brief Support for transformations
24
+ */
25
+
26
+#include <stdio.h>
27
+#include <string.h>
28
+#include <stdlib.h>
29
+#include <time.h>
30
+#include <sys/types.h>
31
+#include <unistd.h>
32
+
33
+#include "../../dprint.h"
34
+#include "../../mem/mem.h"
35
+#include "../../ut.h" 
36
+#include "../../trim.h" 
37
+#include "../../pvapi.h"
38
+#include "../../dset.h"
39
+#include "../../basex.h"
40
+
41
+#include "../../lib/kcore/strcommon.h"
42
+#include "../../parser/parse_content.h" 
43
+
44
+
45
+#include "smsops_impl.h"
46
+
47
+// Types of RP-DATA
48
+typedef enum _rp_message_type {
49
+	RP_DATA_MS_TO_NETWORK = 0x00,
50
+	RP_DATA_NETWORK_TO_MS = 0x01,
51
+	RP_ACK_MS_TO_NETWORK  = 0x02,
52
+	RP_ACK_NETWORK_TO_MS  = 0x03,
53
+} rp_message_type_t;
54
+
55
+enum SMS_DATA { 
56
+	SMS_ALL,
57
+	SMS_RPDATA_TYPE,
58
+	SMS_RPDATA_REFERENCE,
59
+	SMS_RPDATA_ORIGINATOR,
60
+	SMS_RPDATA_DESTINATION,
61
+	SMS_TPDU_TYPE,
62
+	SMS_TPDU_FLAGS,
63
+	SMS_TPDU_CODING,
64
+	SMS_TPDU_PAYLOAD,
65
+	SMS_TPDU_PROTOCOL,
66
+	SMS_TPDU_VALIDITY,
67
+	SMS_TPDU_REFERENCE,
68
+	SMS_TPDU_ORIGINATING_ADDRESS,
69
+	SMS_TPDU_DESTINATION,
70
+};
71
+
72
+// Types of the PDU-Message
73
+typedef enum _pdu_message_type {
74
+	DELIVER = 0x00,
75
+	SUBMIT = 0x01,
76
+	COMMAND = 0x02,
77
+	ANY = 0x03,
78
+} pdu_message_type_t;
79
+
80
+#define TP_RD 0x4;
81
+#define TP_VPF 0x16;
82
+#define TP_SRR 0x32;
83
+#define TP_UDHI 0x64;
84
+#define TP_RP 0x128;
85
+
86
+// PDU (GSM 03.40) of the SMS
87
+typedef struct _sms_pdu {
88
+	pdu_message_type_t msg_type;
89
+	unsigned char reference;
90
+	unsigned char flags;
91
+	unsigned char pid;
92
+	unsigned char coding;
93
+	unsigned char validity;
94
+	str originating_address;
95
+	str destination;
96
+	str payload;
97
+} sms_pdu_t;
98
+
99
+// RP-Data of the message
100
+typedef struct _sms_rp_data {
101
+	rp_message_type_t msg_type;
102
+	unsigned char reference;
103
+	str originator;
104
+	str destination;
105
+	int pdu_len;
106
+	sms_pdu_t pdu;	
107
+} sms_rp_data_t;
108
+
109
+// Pointer to current parsed rp_data/tpdu
110
+static sms_rp_data_t * rp_data = NULL;
111
+// Pointer to rp_data/tpdu used for sending
112
+static sms_rp_data_t * rp_send_data = NULL;
113
+
114
+// ID of current message
115
+static unsigned int current_msg_id = 0;
116
+
117
+/*******************************************************************
118
+ * Helper Functions
119
+ *******************************************************************/
120
+
121
+// Frees internal pointers within the SMS-PDU-Type:
122
+void freeRP_DATA(sms_rp_data_t * rpdata) {
123
+	if (rpdata) {
124
+		if (rpdata->originator.s) pkg_free(rpdata->originator.s);
125
+		if (rpdata->destination.s) pkg_free(rpdata->destination.s);
126
+		if (rpdata->pdu.originating_address.s) pkg_free(rpdata->pdu.originating_address.s);
127
+		if (rpdata->pdu.destination.s) pkg_free(rpdata->pdu.destination.s);
128
+		if (rpdata->pdu.payload.s) pkg_free(rpdata->pdu.payload.s);
129
+	}
130
+}
131
+
132
+#define BITMASK_7BITS 0x7F
133
+#define BITMASK_8BITS 0xFF
134
+#define BITMASK_HIGH_4BITS 0xF0
135
+#define BITMASK_LOW_4BITS 0x0F
136
+
137
+// Encode SMS-Message by merging 7 bit ASCII characters into 8 bit octets.
138
+static int ascii_to_gsm(str sms, char * output_buffer, int buffer_size) {
139
+	// Check if output buffer is big enough.
140
+	if ((sms.len * 7 + 7) / 8 > buffer_size)
141
+		return -1;
142
+
143
+	int output_buffer_length = 0;
144
+	int carry_on_bits = 1;
145
+	int i = 0;
146
+
147
+	for (; i < sms.len; ++i) {
148
+		output_buffer[output_buffer_length++] =
149
+			((sms.s[i] & BITMASK_7BITS) >> (carry_on_bits - 1)) |
150
+			((sms.s[i + 1] & BITMASK_7BITS) << (8 - carry_on_bits));
151
+		carry_on_bits++;
152
+		if (carry_on_bits == 8) {
153
+			carry_on_bits = 1;
154
+			++i;
155
+		}
156
+	}
157
+
158
+	if (i <= sms.len)
159
+		output_buffer[output_buffer_length++] =	(sms.s[i] & BITMASK_7BITS) >> (carry_on_bits - 1);
160
+
161
+	return output_buffer_length;
162
+}
163
+
164
+// Decode 7bit encoded message by splitting 8 bit encoded buffer into 7 bit ASCII characters.
165
+int gsm_to_ascii(char* buffer, int buffer_length, str sms) {
166
+        int output_text_length = 0;
167
+        if (buffer_length > 0)
168
+                sms.s[output_text_length++] = BITMASK_7BITS & buffer[0];
169
+
170
+        int carry_on_bits = 1;
171
+        int i = 1;
172
+        for (; i < buffer_length; ++i) {
173
+                sms.s[output_text_length++] = BITMASK_7BITS & ((buffer[i] << carry_on_bits) | (buffer[i - 1] >> (8 - carry_on_bits)));
174
+
175
+                if (output_text_length == sms.len) break;
176
+
177
+                carry_on_bits++;
178
+
179
+                if (carry_on_bits == 8) {
180
+                        carry_on_bits = 1;
181
+                        sms.s[output_text_length++] = buffer[i] & BITMASK_7BITS;
182
+                        if (output_text_length == sms.len) break;
183
+                }
184
+
185
+        }
186
+        if (output_text_length < sms.len)  // Add last remainder.
187
+                sms.s[output_text_length++] = buffer[i - 1] >> (8 - carry_on_bits);
188
+
189
+        return output_text_length;
190
+}
191
+
192
+// Decode UCS2 message by splitting the buffer into utf8 characters
193
+int ucs2_to_utf8 (int ucs2, char * utf8) {
194
+    if (ucs2 < 0x80) {
195
+        utf8[0] = ucs2;
196
+	utf8[1] = 0;
197
+        return 1;
198
+    }
199
+    if (ucs2 >= 0x80  && ucs2 < 0x800) {
200
+        utf8[0] = (ucs2 >> 6)   | 0xC0;
201
+        utf8[1] = (ucs2 & 0x3F) | 0x80;
202
+        return 2;
203
+    }
204
+    if (ucs2 >= 0x800 && ucs2 < 0xFFFF) {
205
+	if (ucs2 >= 0xD800 && ucs2 <= 0xDFFF) return -1;
206
+        utf8[0] = ((ucs2 >> 12)       ) | 0xE0;
207
+        utf8[1] = ((ucs2 >> 6 ) & 0x3F) | 0x80;
208
+        utf8[2] = ((ucs2      ) & 0x3F) | 0x80;
209
+        return 3;
210
+    }
211
+    if (ucs2 >= 0x10000 && ucs2 < 0x10FFFF) {
212
+	utf8[0] = 0xF0 | (ucs2 >> 18);
213
+	utf8[1] = 0x80 | ((ucs2 >> 12) & 0x3F);
214
+	utf8[2] = 0x80 | ((ucs2 >> 6) & 0x3F);
215
+	utf8[3] = 0x80 | ((ucs2 & 0x3F));
216
+        return 4;
217
+    }
218
+    return -1;
219
+}
220
+
221
+// Decode UTF8 to UCS2
222
+int utf8_to_ucs2 (const unsigned char * input, const unsigned char ** end_ptr) {
223
+    *end_ptr = input;
224
+    if (input[0] == 0)
225
+        return -1;
226
+    if (input[0] < 0x80) {
227
+        * end_ptr = input + 1;
228
+        return input[0];
229
+    }
230
+    if ((input[0] & 0xE0) == 0xE0) {
231
+        if (input[1] == 0 || input[2] == 0) return -1;
232
+        *end_ptr = input + 3;
233
+        return (input[0] & 0x0F) << 12 | (input[1] & 0x3F) << 6  | (input[2] & 0x3F);
234
+    }
235
+    if ((input[0] & 0xC0) == 0xC0) {
236
+        if (input[1] == 0) return -1;
237
+        * end_ptr = input + 2;
238
+        return (input[0] & 0x1F) << 6 | (input[1] & 0x3F);
239
+    }
240
+    return -1;
241
+}
242
+
243
+// Encode a digit based phone number for SMS based format.
244
+static int EncodePhoneNumber(str phone, char * output_buffer, int buffer_size) {
245
+	int output_buffer_length = 0;
246
+	// Check if the output buffer is big enough.
247
+	if ((phone.len + 1) / 2 > buffer_size)
248
+		return -1;
249
+
250
+	int i = 0;
251
+	for (; i < phone.len; ++i) {
252
+		if (phone.s[i] < '0' && phone.s[i] > '9')
253
+			return -1;
254
+		if (i % 2 == 0) {
255
+			output_buffer[output_buffer_length++] =	BITMASK_HIGH_4BITS | (phone.s[i] - '0');
256
+		} else {
257
+			output_buffer[output_buffer_length - 1] = (output_buffer[output_buffer_length - 1] & BITMASK_LOW_4BITS) | ((phone.s[i] - '0') << 4); 
258
+		}
259
+	}
260
+
261
+	return output_buffer_length;
262
+}
263
+
264
+// Decode a digit based phone number for SMS based format.
265
+static int DecodePhoneNumber(char* buffer, int len, str phone) {
266
+	int i = 0;
267
+	for (; i < len; ++i) {
268
+		if (i % 2 == 0)
269
+			phone.s[i] = (buffer[i / 2] & BITMASK_LOW_4BITS) + '0';
270
+	        else
271
+			phone.s[i] = ((buffer[i / 2] & BITMASK_HIGH_4BITS) >> 4) + '0';
272
+	}
273
+	return i;
274
+}
275
+
276
+// Generate a 7 Byte Long Time
277
+static void EncodeTime(char * buffer) {
278
+	time_t ts;
279
+	struct tm * now;
280
+	int i = 0;
281
+
282
+	time(&ts);
283
+	/* Get GMT time */
284
+	now = gmtime(&ts);
285
+
286
+	i = now->tm_year % 100;
287
+	buffer[0] = (unsigned char)((((i % 10) << 4) | (i / 10)) & 0xff);
288
+	i = now->tm_mon + 1;
289
+	buffer[1] = (unsigned char)((((i % 10) << 4) | (i / 10)) & 0xff);
290
+	i = now->tm_mday;
291
+	buffer[2] = (unsigned char)((((i % 10) << 4) | (i / 10)) & 0xff);
292
+	i = now->tm_hour;
293
+	buffer[3] = (unsigned char)((((i % 10) << 4) | (i / 10)) & 0xff);
294
+	i = now->tm_min;
295
+	buffer[4] = (unsigned char)((((i % 10) << 4) | (i / 10)) & 0xff);
296
+	i = now->tm_sec;
297
+	buffer[5] = (unsigned char)((((i % 10) << 4) | (i / 10)) & 0xff);
298
+	buffer[6] = 0; // Timezone, we use no time offset.
299
+}
300
+
301
+// Decode SMS-Body into the given structure:
302
+int decode_3gpp_sms(struct sip_msg *msg) {
303
+	str body;
304
+	int len, j, p = 0;
305
+	// Parse only the body again, if the mesage differs from the last call:
306
+	if (msg->id != current_msg_id) {
307
+		// Extract Message-body and length: taken from RTPEngine's code
308
+		body.s = get_body(msg);
309
+		if (body.s == 0) {
310
+			LM_ERR("failed to get the message body\n");
311
+			return -1;
312
+		}
313
+
314
+		/*
315
+		 * Better use the content-len value - no need of any explicit
316
+		 * parcing as get_body() parsed all headers and Conten-Length
317
+		 * body header is automaticaly parsed when found.
318
+		 */
319
+		if (msg->content_length==0) {
320
+			LM_ERR("failed to get the content length in message\n");
321
+			return -1;
322
+		}
323
+
324
+		body.len = get_content_length(msg);
325
+		if (body.len==0) {
326
+			LM_ERR("message body has length zero\n");
327
+			return -1;
328
+		}
329
+
330
+		if (body.len + body.s > msg->buf + msg->len) {
331
+			LM_ERR("content-length exceeds packet-length by %d\n",
332
+					(int)((body.len + body.s) - (msg->buf + msg->len)));
333
+			return -1;
334
+		}
335
+
336
+		// Get structure for RP-DATA:
337
+		if (!rp_data) {
338
+			rp_data = (sms_rp_data_t*)pkg_malloc(sizeof(struct _sms_rp_data));
339
+			if (!rp_data) {
340
+				LM_ERR("Error allocating %lu bytes!\n", sizeof(struct _sms_rp_data));
341
+				return -1;
342
+			}
343
+		} else {
344
+			freeRP_DATA(rp_data);
345
+		}
346
+
347
+		// Initialize structure:
348
+		memset(rp_data, 0, sizeof(struct _sms_rp_data));
349
+
350
+		////////////////////////////////////////////////
351
+		// RP-Data
352
+		////////////////////////////////////////////////
353
+		rp_data->msg_type = (unsigned char)body.s[p++];
354
+		rp_data->reference = (unsigned char)body.s[p++];
355
+		if ((rp_data->msg_type == RP_DATA_MS_TO_NETWORK) || (rp_data->msg_type == RP_DATA_NETWORK_TO_MS)) {
356
+			len = body.s[p++];
357
+			if (len > 0) {
358
+				p++; // Type of Number, we assume E164, thus ignored
359
+				len--; // Deduct the type of number from the len
360
+				rp_data->originator.s = pkg_malloc(len * 2);
361
+				rp_data->originator.len = DecodePhoneNumber(&body.s[p], len * 2, rp_data->originator);
362
+				p += len;
363
+			}
364
+			len = body.s[p++];
365
+			if (len > 0) {
366
+				p++; // Type of Number, we assume E164, thus ignored
367
+				len--; // Deduct the type of number from the len
368
+				rp_data->destination.s = pkg_malloc(len * 2);
369
+				rp_data->destination.len = DecodePhoneNumber(&body.s[p], len * 2, rp_data->destination);
370
+				p += len;
371
+			}
372
+
373
+			////////////////////////////////////////////////
374
+			// TPDU
375
+			////////////////////////////////////////////////
376
+			rp_data->pdu_len = body.s[p++];
377
+			if (rp_data->pdu_len > 0) {
378
+				rp_data->pdu.flags = (unsigned char)body.s[p++];
379
+				rp_data->pdu.msg_type = (unsigned char)rp_data->pdu.flags & 0x03;
380
+				rp_data->pdu.reference = (unsigned char)body.s[p++];
381
+				// TP-DA
382
+				rp_data->pdu.destination.len = body.s[p++];
383
+				if (rp_data->pdu.destination.len > 0) {
384
+					p++; // Type of Number, we assume E164, thus ignored
385
+					rp_data->pdu.destination.s = pkg_malloc(rp_data->pdu.destination.len);
386
+					DecodePhoneNumber(&body.s[p], rp_data->pdu.destination.len, rp_data->pdu.destination);
387
+					if (rp_data->pdu.destination.len % 2 == 0) {
388
+						p += rp_data->pdu.destination.len/2;	
389
+					} else {
390
+						p += (rp_data->pdu.destination.len/2)+1;	
391
+					}
392
+					
393
+				}
394
+				rp_data->pdu.pid = (unsigned char)body.s[p++];
395
+				rp_data->pdu.coding = (unsigned char)body.s[p++];
396
+				rp_data->pdu.validity = (unsigned char)body.s[p++];
397
+				len = body.s[p++];
398
+				if (len > 0) {
399
+					// Coding: 7 Bit
400
+					if (rp_data->pdu.coding == 0x00) {
401
+						// We don't care about the extra used bytes here.
402
+						rp_data->pdu.payload.s = pkg_malloc(len);
403
+						rp_data->pdu.payload.len = gsm_to_ascii(&body.s[p], len, rp_data->pdu.payload);
404
+					} else {
405
+						// Length is worst-case 2 * len (UCS2 is 2 Bytes, UTF8 is worst-case 4 Bytes)
406
+						rp_data->pdu.payload.s = pkg_malloc(len*4);
407
+						rp_data->pdu.payload.len = 0;
408
+						while (len > 0) {
409
+							j = (body.s[p] << 8) + body.s[p + 1];
410
+							p += 2;
411
+							rp_data->pdu.payload.len += ucs2_to_utf8(j, &rp_data->pdu.payload.s[rp_data->pdu.payload.len]);
412
+							len -= 2;
413
+						}
414
+					}
415
+				}
416
+			}				
417
+		}
418
+	}
419
+
420
+	return 1;	
421
+}
422
+
423
+int dumpRPData(sms_rp_data_t * rpdata, int level) {
424
+	if (rpdata) {
425
+		LOG(level, "SMS-Message\n");
426
+		LOG(level, "------------------------\n");
427
+		LOG(level, "RP-Data\n");
428
+		LOG(level, "  Type:                       %x\n", rpdata->msg_type);
429
+		LOG(level, "  Reference:                  %x (%i)\n", rpdata->reference, rpdata->reference);
430
+		LOG(level, "  Originator:                 %.*s (%i)\n", rpdata->originator.len, rpdata->originator.s, rpdata->originator.len);
431
+		LOG(level, "  Destination:                %.*s (%i)\n", rpdata->destination.len, rpdata->destination.s, rpdata->destination.len);
432
+		LOG(level, "T-PDU\n");
433
+		LOG(level, "  Type:                       %x\n", rpdata->pdu.msg_type);
434
+		LOG(level, "  Flags:                      %x (%i)\n", rpdata->pdu.flags, rpdata->pdu.flags);
435
+		LOG(level, "  Reference:                  %x (%i)\n", rpdata->pdu.reference, rpdata->pdu.reference);
436
+
437
+		LOG(level, "  Originating-Address:        %.*s (%i)\n", rpdata->pdu.originating_address.len, rpdata->pdu.originating_address.s, rpdata->pdu.originating_address.len);
438
+		LOG(level, "  Destination:                %.*s (%i)\n", rpdata->pdu.destination.len, rpdata->pdu.destination.s, rpdata->pdu.destination.len);
439
+
440
+		LOG(level, "  Protocol:                   %x (%i)\n", rpdata->pdu.pid, rpdata->pdu.pid);
441
+		LOG(level, "  Coding:                     %x (%i)\n", rpdata->pdu.coding, rpdata->pdu.coding);
442
+		LOG(level, "  Validity:                   %x (%i)\n", rpdata->pdu.validity, rpdata->pdu.validity);
443
+
444
+		LOG(level, "  Payload:                    %.*s (%i)\n", rpdata->pdu.payload.len, rpdata->pdu.payload.s, rpdata->pdu.payload.len);
445
+	}
446
+	return 1;
447
+}
448
+
449
+/*******************************************************************
450
+ * Implementation
451
+ *******************************************************************/
452
+
453
+/*
454
+ * Creates the body for SMS-ACK from the current message
455
+ */
456
+int pv_sms_ack(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
457
+	str rp_data_ack = {0, 0};
458
+
459
+	// Decode the 3GPP-SMS:
460
+	if (decode_3gpp_sms(msg) != 1) {
461
+		LM_ERR("Error getting/decoding RP-Data from request!\n");
462
+		return -1;
463
+	}
464
+
465
+	// RP-Type (1) + RP-Ref (1) + RP-User-Data (Element-ID (1) + Length (9 => Msg-Type (1) + Parameter (1) + Service-Centre-Time (7)) = 13;
466
+	rp_data_ack.len = 13;
467
+	rp_data_ack.s = (char*)pkg_malloc(rp_data_ack.len);
468
+	if (!rp_data_ack.s) {
469
+		LM_ERR("Error allocating %d bytes!\n", rp_data_ack.len);
470
+		return -1;
471
+	}
472
+
473
+	// Encode the data (RP-Data)
474
+	// Always ACK NETWORK to MS
475
+	rp_data_ack.s[0] = RP_ACK_NETWORK_TO_MS;
476
+	// Take the reference from request:
477
+	rp_data_ack.s[1] = rp_data->reference;
478
+	// RP-Data-Element-ID
479
+	rp_data_ack.s[2] = 0x41;
480
+	// Length
481
+	rp_data_ack.s[3] = 9;
482
+	// PDU
483
+	// SMS-SUBMIT-Report
484
+	rp_data_ack.s[4] = SUBMIT;
485
+	// Parameters (none)
486
+	rp_data_ack.s[5] = 0x0;
487
+
488
+	EncodeTime(&rp_data_ack.s[6]);
489
+
490
+	return pv_get_strval(msg, param, res, &rp_data_ack);
491
+}
492
+
493
+
494
+/*
495
+ * Creates the body for SMS-ACK from the current message
496
+ */
497
+int pv_sms_body(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
498
+	dumpRPData(rp_send_data, L_DBG);
499
+
500
+	str sms_body = {0, 0};
501
+	int buffer_size = 1024, lenpos = 0, i = 0;
502
+
503
+	// We assume a maximum size of 1024 Bytes, to be verified.
504
+	sms_body.s = (char*)pkg_malloc(buffer_size);
505
+	if (!sms_body.s) {
506
+		LM_ERR("Error allocating %i bytes!\n", buffer_size);
507
+		return -1;
508
+	}
509
+
510
+	// Encode the data (RP-Data)
511
+	sms_body.s[sms_body.len++] = rp_send_data->msg_type;
512
+	sms_body.s[sms_body.len++] = rp_send_data->reference;
513
+	lenpos = sms_body.len;
514
+	sms_body.s[sms_body.len++] = 0x00;
515
+	if (rp_send_data->originator.len > 0) {
516
+		sms_body.s[sms_body.len++] = 0x91; // Type of number: ISDN/Telephony Numbering (E164), no extension
517
+		i = EncodePhoneNumber(rp_send_data->originator, &sms_body.s[sms_body.len], buffer_size - sms_body.len);
518
+		sms_body.s[lenpos] = i + 1;
519
+		sms_body.len += i;
520
+	}
521
+	lenpos = sms_body.len;
522
+	sms_body.s[sms_body.len++] = 0x00;
523
+	if (rp_send_data->destination.len > 0) {
524
+		sms_body.s[sms_body.len++] = 0x91; // Type of number: ISDN/Telephony Numbering (E164), no extension
525
+		i = EncodePhoneNumber(rp_send_data->destination, &sms_body.s[sms_body.len], buffer_size - sms_body.len);
526
+		sms_body.s[lenpos] = i + 1;
527
+		sms_body.len += i;
528
+	}
529
+	// Store the position of the length for later usage:
530
+	lenpos = sms_body.len;
531
+	sms_body.s[sms_body.len++] = 0x00;
532
+	
533
+	///////////////////////////////////////////////////
534
+	// T-PDU
535
+	///////////////////////////////////////////////////
536
+	sms_body.s[sms_body.len++] = rp_send_data->pdu.msg_type | rp_send_data->pdu.flags | 0x4; // We've always got no more messages to send.
537
+	// Originating Address:
538
+	sms_body.s[sms_body.len++] = rp_send_data->pdu.originating_address.len;
539
+	sms_body.s[sms_body.len++] = 0x91; // Type of number: ISDN/Telephony Numbering (E164), no extension
540
+	sms_body.len += EncodePhoneNumber(rp_send_data->pdu.originating_address, &sms_body.s[sms_body.len], buffer_size - sms_body.len);
541
+	// Protocol ID
542
+	sms_body.s[sms_body.len++] = rp_send_data->pdu.pid;
543
+	// Encoding (0 => default 7 Bit)
544
+	sms_body.s[sms_body.len++] = rp_send_data->pdu.coding;
545
+	// Service-Center-Timestamp (always 7 octets)
546
+	EncodeTime(&sms_body.s[sms_body.len]);
547
+	sms_body.len += 7;
548
+	sms_body.s[sms_body.len++] = rp_send_data->pdu.payload.len;
549
+	i = ascii_to_gsm(rp_send_data->pdu.payload, &sms_body.s[sms_body.len], buffer_size - sms_body.len);
550
+	sms_body.len += i - 1;
551
+
552
+	// Update the len of the PDU
553
+	sms_body.s[lenpos] = (unsigned char)(sms_body.len - lenpos - 1);
554
+	
555
+	return pv_get_strval(msg, param, res, &sms_body);
556
+}
557
+
558
+int pv_get_sms(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) {
559
+	if (param==NULL) return -1;
560
+
561
+	// Decode the 3GPP-SMS:
562
+	if (decode_3gpp_sms(msg) != 1) {
563
+		LM_ERR("Error getting/decoding RP-Data from request!\n");
564
+		return -1;
565
+	}
566
+
567
+	switch(param->pvn.u.isname.name.n) {
568
+		case SMS_RPDATA_TYPE:
569
+			return pv_get_sintval(msg, param, res, (int)rp_data->msg_type);
570
+		case SMS_RPDATA_REFERENCE:
571
+			return pv_get_sintval(msg, param, res, (int)rp_data->reference);
572
+		case SMS_RPDATA_ORIGINATOR:
573
+			return pv_get_strval(msg, param, res, &rp_data->originator);
574
+		case SMS_RPDATA_DESTINATION:
575
+			return pv_get_strval(msg, param, res, &rp_data->destination);
576
+		case SMS_TPDU_TYPE:
577
+			return  pv_get_sintval(msg, param, res, (int)rp_data->pdu.msg_type);
578
+		case SMS_TPDU_FLAGS:
579
+			return  pv_get_sintval(msg, param, res, (int)rp_data->pdu.flags);
580
+		case SMS_TPDU_CODING:
581
+			return  pv_get_sintval(msg, param, res, (int)rp_data->pdu.coding);
582
+		case SMS_TPDU_PROTOCOL:
583
+			return  pv_get_sintval(msg, param, res, (int)rp_data->pdu.pid);
584
+		case SMS_TPDU_VALIDITY:
585
+			return  pv_get_sintval(msg, param, res, (int)rp_data->pdu.validity);
586
+		case SMS_TPDU_REFERENCE:
587
+			return  pv_get_sintval(msg, param, res, (int)rp_data->pdu.reference);
588
+		case SMS_TPDU_PAYLOAD:
589
+			return pv_get_strval(msg, param, res, &rp_data->pdu.payload);
590
+		case SMS_TPDU_DESTINATION:
591
+			return pv_get_strval(msg, param, res, &rp_data->pdu.destination);
592
+		case SMS_TPDU_ORIGINATING_ADDRESS:
593
+			return pv_get_strval(msg, param, res, &rp_data->pdu.originating_address);
594
+	}
595
+	return 0;
596
+}
597
+
598
+int pv_set_sms(struct sip_msg* msg, pv_param_t *param, int op, pv_value_t *val) {
599
+	if (param==NULL)
600
+		return -1;
601
+	
602
+	if (!rp_send_data) {
603
+		rp_send_data = (sms_rp_data_t*)pkg_malloc(sizeof(struct _sms_rp_data));
604
+		if (!rp_send_data) {
605
+			LM_ERR("Error allocating %lu bytes!\n", sizeof(struct _sms_rp_data));
606
+			return -1;
607
+		}
608
+		// Initialize structure:
609
+		memset(rp_send_data, 0, sizeof(struct _sms_rp_data));
610
+	}
611
+
612
+	switch(param->pvn.u.isname.name.n) {
613
+		case SMS_ALL:
614
+			freeRP_DATA(rp_send_data);
615
+			// Initialize structure:
616
+			memset(rp_send_data, 0, sizeof(struct _sms_rp_data));
617
+			break;
618
+		case SMS_RPDATA_TYPE:
619
+			if (val == NULL) {
620
+				rp_send_data->msg_type = 0;
621
+				return 0;
622
+			}
623
+			if (!(val->flags & PV_VAL_INT)) {
624
+				LM_ERR("Invalid value type\n");
625
+				return -1;
626
+			}
627
+			rp_send_data->msg_type = (unsigned char)val->ri;
628
+			break;
629
+		case SMS_RPDATA_REFERENCE:
630
+			if (val == NULL) {
631
+				rp_send_data->reference = 0;
632
+				return 0;
633
+			}
634
+			if (!(val->flags & PV_VAL_INT)) {
635
+				LM_ERR("Invalid value type\n");
636
+				return -1;
637
+			}
638
+			rp_send_data->reference = (unsigned char)val->ri;
639
+			break;
640
+		case SMS_RPDATA_ORIGINATOR:
641
+			if (rp_send_data->originator.s) {
642
+				pkg_free(rp_send_data->originator.s);
643
+				rp_send_data->originator.s = 0;
644
+				rp_send_data->originator.len = 0;
645
+			}
646
+			if (val == NULL)
647
+				return 0;
648
+			if (!(val->flags&PV_VAL_STR)) {
649
+				LM_ERR("Invalid type\n");
650
+				return -1;
651
+			}
652
+			rp_send_data->originator.s = pkg_malloc(val->rs.len);
653
+			rp_send_data->originator.len = val->rs.len;
654
+			memcpy(rp_send_data->originator.s, val->rs.s, val->rs.len);
655
+			break;
656
+		case SMS_RPDATA_DESTINATION:
657
+			if (rp_send_data->destination.s) {
658
+				pkg_free(rp_send_data->destination.s);
659
+				rp_send_data->destination.s = 0;
660
+				rp_send_data->destination.len = 0;
661
+			}
662
+			if (val == NULL)
663
+				return 0;
664
+			if (!(val->flags&PV_VAL_STR)) {
665
+				LM_ERR("Invalid type\n");
666
+				return -1;
667
+			}
668
+			rp_send_data->destination.s = pkg_malloc(val->rs.len);
669
+			rp_send_data->destination.len = val->rs.len;
670
+			memcpy(rp_send_data->destination.s, val->rs.s, val->rs.len);
671
+			break;
672
+		case SMS_TPDU_TYPE:
673
+			if (val == NULL) {
674
+				rp_send_data->pdu.msg_type = 0;
675
+				return 0;
676
+			}
677
+			if (!(val->flags & PV_VAL_INT)) {
678
+				LM_ERR("Invalid value type\n");
679
+				return -1;
680
+			}
681
+			rp_send_data->pdu.msg_type = (unsigned char)val->ri;
682
+			break;
683
+
684
+		case SMS_TPDU_FLAGS:
685
+			if (val == NULL) {
686
+				rp_send_data->pdu.flags = 0;
687
+				return 0;
688
+			}
689
+			if (!(val->flags & PV_VAL_INT)) {
690
+				LM_ERR("Invalid value type\n");
691
+				return -1;
692
+			}
693
+			rp_send_data->pdu.flags = (unsigned char)val->ri;
694
+			break;
695
+		case SMS_TPDU_CODING:
696
+			if (val == NULL) {
697
+				rp_send_data->pdu.coding = 0;
698
+				return 0;
699
+			}
700
+			if (!(val->flags & PV_VAL_INT)) {
701
+				LM_ERR("Invalid value type\n");
702
+				return -1;
703
+			}
704
+			rp_send_data->pdu.coding = (unsigned char)val->ri;
705
+			break;
706
+		case SMS_TPDU_PROTOCOL:
707
+			if (val == NULL) {
708
+				rp_send_data->pdu.pid = 0;
709
+				return 0;
710
+			}
711
+			if (!(val->flags & PV_VAL_INT)) {
712
+				LM_ERR("Invalid value type\n");
713
+				return -1;
714
+			}
715
+			rp_send_data->pdu.pid = (unsigned char)val->ri;
716
+			break;
717
+		case SMS_TPDU_REFERENCE:
718
+			if (val == NULL) {
719
+				rp_send_data->pdu.reference = 0;
720
+				return 0;
721
+			}
722
+			if (!(val->flags & PV_VAL_INT)) {
723
+				LM_ERR("Invalid value type\n");
724
+				return -1;
725
+			}
726
+			rp_send_data->pdu.reference = (unsigned char)val->ri;
727
+			break;
728
+		case SMS_TPDU_VALIDITY:
729
+			if (val == NULL) {
730
+				rp_send_data->pdu.validity = 0;
731
+				return 0;
732
+			}
733
+			if (!(val->flags & PV_VAL_INT)) {
734
+				LM_ERR("Invalid value type\n");
735
+				return -1;
736
+			}
737
+			rp_send_data->pdu.validity = (unsigned char)val->ri;
738
+			break;
739
+		case SMS_TPDU_PAYLOAD:
740
+			if (rp_send_data->pdu.payload.s) {
741
+				pkg_free(rp_send_data->pdu.payload.s);
742
+				rp_send_data->pdu.payload.s = 0;
743
+				rp_send_data->pdu.payload.len = 0;
744
+			}
745
+			if (val == NULL)
746
+				return 0;
747
+			if (!(val->flags&PV_VAL_STR)) {
748
+				LM_ERR("Invalid type\n");
749
+				return -1;
750
+			}
751
+			rp_send_data->pdu.payload.s = pkg_malloc(val->rs.len);
752
+			rp_send_data->pdu.payload.len = val->rs.len;
753
+			memcpy(rp_send_data->pdu.payload.s, val->rs.s, val->rs.len);
754
+			break;
755
+		case SMS_TPDU_DESTINATION:
756
+			if (rp_send_data->pdu.destination.s) {
757
+				pkg_free(rp_send_data->pdu.destination.s);
758
+				rp_send_data->pdu.destination.s = 0;
759
+				rp_send_data->pdu.destination.len = 0;
760
+			}
761
+			if (val == NULL)
762
+				return 0;
763
+			if (!(val->flags&PV_VAL_STR)) {
764
+				LM_ERR("Invalid type\n");
765
+				return -1;
766
+			}
767
+			rp_send_data->pdu.destination.s = pkg_malloc(val->rs.len);
768
+			rp_send_data->pdu.destination.len = val->rs.len;
769
+			memcpy(rp_send_data->pdu.destination.s, val->rs.s, val->rs.len);
770
+			break;
771
+		case SMS_TPDU_ORIGINATING_ADDRESS:
772
+			if (rp_send_data->pdu.originating_address.s) {
773
+				pkg_free(rp_send_data->pdu.originating_address.s);
774
+				rp_send_data->pdu.originating_address.s = 0;
775
+				rp_send_data->pdu.originating_address.len = 0;
776
+			}
777
+			if (val == NULL)
778
+				return 0;
779
+			if (!(val->flags&PV_VAL_STR)) {
780
+				LM_ERR("Invalid type\n");
781
+				return -1;
782
+			}
783
+			rp_send_data->pdu.originating_address.s = pkg_malloc(val->rs.len);
784
+			rp_send_data->pdu.originating_address.len = val->rs.len;
785
+			memcpy(rp_send_data->pdu.originating_address.s, val->rs.s, val->rs.len);
786
+			break;
787
+
788
+	}
789
+	return 0;
790
+}
791
+
792
+int pv_parse_rpdata_name(pv_spec_p sp, str *in) {
793
+	if (sp==NULL || in==NULL || in->len<=0) return -1;
794
+
795
+	switch(in->len) {
796
+		case 3: 
797
+			if (strncmp(in->s, "all", 3) == 0) sp->pvp.pvn.u.isname.name.n = SMS_ALL;
798
+			else goto error;
799
+			break;
800
+		case 4: 
801
+			if (strncmp(in->s, "type", 4) == 0) sp->pvp.pvn.u.isname.name.n = SMS_RPDATA_TYPE;
802
+			else goto error;
803
+			break;
804
+		case 9: 
805
+			if (strncmp(in->s, "reference", 9) == 0) sp->pvp.pvn.u.isname.name.n = SMS_RPDATA_REFERENCE;
806
+			else goto error;
807
+			break;
808
+		case 10: 
809
+			if (strncmp(in->s, "originator", 10) == 0) sp->pvp.pvn.u.isname.name.n = SMS_RPDATA_ORIGINATOR;
810
+			else goto error;
811
+			break;
812
+		case 11: 
813
+			if (strncmp(in->s, "destination", 11) == 0) sp->pvp.pvn.u.isname.name.n = SMS_RPDATA_DESTINATION;
814
+			else goto error;
815
+			break;
816
+		default:
817
+			goto error;
818
+	}
819
+	sp->pvp.pvn.type = PV_NAME_INTSTR;
820
+	sp->pvp.pvn.u.isname.type = 0;
821
+
822
+	return 0;
823
+
824
+error:
825
+	LM_ERR("unknown uac_req name %.*s\n", in->len, in->s);
826
+	return -1;
827
+}
828
+
829
+int pv_parse_tpdu_name(pv_spec_p sp, str *in) {
830
+	if (sp==NULL || in==NULL || in->len<=0) return -1;
831
+
832
+	switch(in->len) {
833
+		case 3: 
834
+			if (strncmp(in->s, "all", 3) == 0) sp->pvp.pvn.u.isname.name.n = SMS_ALL;
835
+			else goto error;
836
+			break;
837
+		case 4: 
838
+			if (strncmp(in->s, "type", 4) == 0) sp->pvp.pvn.u.isname.name.n = SMS_TPDU_TYPE;
839
+			else goto error;
840
+			break;
841
+		case 5: 
842
+			if (strncmp(in->s, "flags", 5) == 0) sp->pvp.pvn.u.isname.name.n = SMS_TPDU_FLAGS;
843
+			else goto error;
844
+			break;
845
+		case 6: 
846
+			if (strncmp(in->s, "coding", 6) == 0) sp->pvp.pvn.u.isname.name.n = SMS_TPDU_CODING;
847
+			else if (strncmp(in->s, "origen", 6) == 0) sp->pvp.pvn.u.isname.name.n = SMS_TPDU_ORIGINATING_ADDRESS;
848
+			else goto error;
849
+			break;
850
+		case 7: 
851
+			if (strncmp(in->s, "payload", 7) == 0) sp->pvp.pvn.u.isname.name.n = SMS_TPDU_PAYLOAD;
852
+			else goto error;
853
+			break;
854
+		case 8: 
855
+			if (strncmp(in->s, "protocol", 8) == 0) sp->pvp.pvn.u.isname.name.n = SMS_TPDU_PROTOCOL;
856
+			else if (strncmp(in->s, "validity", 8) == 0) sp->pvp.pvn.u.isname.name.n = SMS_TPDU_VALIDITY;
857
+			else goto error;
858
+			break;
859
+		case 9: 
860
+			if (strncmp(in->s, "reference", 9) == 0) sp->pvp.pvn.u.isname.name.n = SMS_TPDU_REFERENCE;
861
+			else goto error;
862
+			break;
863
+		case 11: 
864
+			if (strncmp(in->s, "destination", 11) == 0) sp->pvp.pvn.u.isname.name.n = SMS_TPDU_DESTINATION;
865
+			else goto error;
866
+			break;
867
+		default:
868
+			goto error;
869
+	}
870
+	sp->pvp.pvn.type = PV_NAME_INTSTR;
871
+	sp->pvp.pvn.u.isname.type = 0;
872
+
873
+	return 0;
874
+
875
+error:
876
+	LM_ERR("unknown pdu name %.*s\n", in->len, in->s);
877
+	return -1;
878
+}
879
+
880
+/*
881
+ * Dumps the content of the SMS-Message:
882
+ */
883
+int smsdump(struct sip_msg *msg, char *str1, char *str2) {
884
+	// Decode the 3GPP-SMS:
885
+	if (decode_3gpp_sms(msg) != 1) {
886
+		LM_ERR("Error getting/decoding RP-Data from request!\n");
887
+		return -1;
888
+	}
889
+
890
+	return dumpRPData(rp_data, L_DBG);
891
+}
892
+
893
+int isRPDATA(struct sip_msg *msg, char *str1, char *str2) {
894
+	// Decode the 3GPP-SMS:
895
+	if (decode_3gpp_sms(msg) != 1) {
896
+		LM_ERR("Error getting/decoding RP-Data from request!\n");
897
+		return -1;
898
+	}
899
+	if ((rp_data->msg_type == RP_DATA_MS_TO_NETWORK) || (rp_data->msg_type == RP_DATA_NETWORK_TO_MS))
900
+		return 1;
901
+	else
902
+		return -1;
903
+}
904
+
0 905
new file mode 100644
... ...
@@ -0,0 +1,41 @@
1
+/*
2
+ * Copyright (C) 2015 Carsten Bock, ng-voice GmbH
3
+ *
4
+ * This file is part of Kamailio, a free SIP server.
5
+ *
6
+ * Kamailio is free software; you can redistribute it and/or modify
7
+ * it under the terms of the GNU General Public License as published by
8
+ * the Free Software Foundation; either version 2 of the License, or
9
+ * (at your option) any later version
10
+ *
11
+ * Kamailio is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
+ * GNU General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU General Public License 
17
+ * along with this program; if not, write to the Free Software 
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19
+ *
20
+ */
21
+
22
+#ifndef _SMSOPS_TRANS_H_
23
+#define _SMSOPS_TRANS_H_
24
+
25
+#include "../../pvar.h"
26
+
27
+
28
+int smsdump(struct sip_msg *, char *, char *);
29
+int isRPDATA(struct sip_msg *, char *, char *);
30
+
31
+int pv_parse_rpdata_name(pv_spec_p, str *);
32
+int pv_parse_tpdu_name(pv_spec_p, str *);
33
+int pv_get_sms(struct sip_msg *, pv_param_t *, pv_value_t *);
34
+int pv_set_sms(struct sip_msg *, pv_param_t *, int, pv_value_t *);
35
+
36
+// Generate SMS-ACK
37
+int pv_sms_ack(struct sip_msg *, pv_param_t *, pv_value_t *);
38
+// Generate a SMS-Body
39
+int pv_sms_body(struct sip_msg *, pv_param_t *, pv_value_t *);
40
+
41
+#endif