Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
emimsg.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * emimsg.c
59  *
60  * Functions for working with EMI messages
61  * Uoti Urpala 2001 */
62 
63 
64 #include "emimsg.h"
65 
66 /* Return an error string corresponding to the number. */
67 static char *emi_strerror(int errnum)
68 {
69  switch (errnum) {
70  case 1: return "Checksum error";
71  case 2: return "Syntax error";
72  case 3: return "Operation not supported by system";
73  case 4: return "Operation not allowed";
74  case 5: return "Call barring active";
75  case 6: return "AdC invalid";
76  case 7: return "Authentication failure";
77  case 8: return "Legitimisation code for all calls, failure";
78  case 9: return "GA not valid";
79  case 10: return "Repetition not allowed";
80  case 11: return "Legitimisation code for repetition, failure";
81  case 12: return "Priority call not allowed";
82  case 13: return "Legitimisation code for priority call, failure";
83  case 14: return "Urgent message not allowed";
84  case 15: return "Legitimisation code for urgent message, failure";
85  case 16: return "Reverse charging not allowed";
86  case 17: return "Legitimisation code for reverse charging, failure";
87  case 18: return "Deferred delivery not allowed";
88  case 19: return "New AC not valid";
89  case 20: return "New legitimisation code not valid";
90  case 21: return "Standard text not valid";
91  case 22: return "Time period not valid";
92  case 23: return "Message type not supported by system";
93  case 24: return "Message too long";
94  case 25: return "Requested standard text not valid";
95  case 26: return "Message type not valid for the pager type";
96  case 27: return "Message not found in smsc";
97  case 30: return "Subscriber hang-up";
98  case 31: return "Fax group not supported";
99  case 32: return "Fax message type not supported";
100  case 33: return "Address already in list (60 series)";
101  case 34: return "Address not in list (60 series)";
102  case 35: return "List full, cannot add address to list (60 series)";
103  case 36: return "RPID already in use";
104  case 37: return "Delivery in progress";
105  case 38: return "Message forwarded";
106  default: return "!UNRECOGNIZED ERROR CODE!";
107  }
108 }
109 
110 
111 static int field_count_op(int ot, Octstr *whoami)
112 {
113  switch (ot) {
114  case 01:
115  return SZ01;
116  case 31:
117  return 2;
118  case 51:
119  case 52:
120  case 53:
121  return SZ50;
122  case 60:
123  return SZ60;
124  default:
125  error(0, "EMI2[%s]: Unsupported EMI operation request type %d",
126  octstr_get_cstr(whoami), ot);
127  return -1;
128  }
129 }
130 
131 
132 static int field_count_reply(int ot, int posit, Octstr *whoami)
133 {
134  switch(ot) {
135  case 01:
136  return posit ? 2 : 3;
137  case 31:
138  return posit ? 2 : 3;
139  case 51:
140  case 52:
141  case 53:
142  return 3;
143  case 60:
144  return posit ? 2 : 3;
145  default:
146  error(0, "EMI2[%s]: Unsupported EMI operation reply type %d",
147  octstr_get_cstr(whoami), ot);
148  return -1;
149  }
150 }
151 
152 
153 static struct emimsg *emimsg_create_withlen(int len)
154 {
155  struct emimsg *ret;
156 
157  ret = gw_malloc(sizeof(struct emimsg));
158  ret->fields = gw_malloc(len * sizeof(Octstr *));
159  ret->num_fields = len;
160  while (--len >= 0)
161  ret->fields[len] = NULL;
162  return ret;
163 }
164 
165 
166 struct emimsg *emimsg_create_op(int ot, int trn, Octstr *whoami)
167 {
168  int len;
169  struct emimsg *ret;
170 
171  len = field_count_op(ot, whoami);
172  if (len < 0)
173  return NULL;
174  ret = emimsg_create_withlen(len);
175  ret->ot = ot;
176  ret->or = 'O';
177  ret->trn = trn;
178  return ret;
179 }
180 
181 
182 static struct emimsg *emimsg_create_reply_s(int ot, int trn, int positive,
183  Octstr *whoami)
184 {
185  int len;
186  struct emimsg *ret;
187 
188  len = field_count_reply(ot, positive, whoami);
189  if (len < 0)
190  return NULL;
191  ret = emimsg_create_withlen(len);
192  ret->ot = ot;
193  ret->or = 'R';
194  ret->trn = trn;
195  return ret;
196 }
197 
198 
199 struct emimsg *emimsg_create_reply(int ot, int trn, int positive,
200  Octstr *whoami)
201 {
202  struct emimsg *ret;
203 
204  ret = emimsg_create_reply_s(ot, trn, positive, whoami);
205  if (ret) {
206  if (positive)
207  ret->fields[0] = octstr_create("A");
208  else
209  ret->fields[0] = octstr_create("N");
210  }
211  return ret;
212 }
213 
214 
216 {
217  int len;
218 
219  len = emimsg->num_fields;
220  while (--len >= 0) {
221  octstr_destroy(emimsg->fields[len]); /* octstr_destroy(NULL) is ok */
222  emimsg->fields[len] = NULL;
223  }
224  gw_free(emimsg->fields);
225  gw_free(emimsg);
226 }
227 
228 
230 {
231  int len;
232  struct emimsg *ret;
233 
234  len = emimsg->num_fields;
235  if (len < 0)
236  return NULL;
237  ret = gw_malloc(sizeof(struct emimsg));
238  ret->fields = gw_malloc(len * sizeof(Octstr *));
239  ret->num_fields = len;
240  while (--len >= 0)
241  ret->fields[len] = octstr_duplicate(emimsg->fields[len]);
242  ret->ot = emimsg->ot;
243  ret->or = emimsg->or;
244  ret->trn = emimsg->trn;
245 
246  return ret;
247 }
248 
249 
250 /* The argument can be either the whole message (with the stx/etx start/end
251  characters), or miss the last 3 characters (checksum digits and etx) */
252 static int calculate_checksum(Octstr *message)
253 {
254  int end, i, checksum;
255 
256  end = octstr_len(message);
257  if (octstr_get_char(message, end - 1) == 3) /* etx, whole message */
258  end -= 3;
259  checksum = 0;
260  for (i = 1; i < end; i++)
261  checksum += octstr_get_char(message, i);
262  return checksum & 0xff;
263 }
264 
265 
267 {
268  int i, checksum;
269  Octstr *result, *data;
270  char *hexits = "0123456789ABCDEF";
271 
272  data = octstr_create("");
273  for (i = 0; i < emimsg->num_fields; i++) {
274  if (emimsg->fields[i])
275  octstr_append(data, emimsg->fields[i]);
276  octstr_append_char(data, '/');
277  }
278  result = octstr_format("\02%02d/%05d/%c/%02d/%S", emimsg->trn,
279  octstr_len(data) + 16, emimsg->or, emimsg->ot, data);
280  checksum = calculate_checksum(result);
281  octstr_append_char(result, hexits[checksum >> 4 & 15]);
282  octstr_append_char(result, hexits[checksum & 15]);
283  octstr_append_char(result, 3);
284  octstr_destroy(data);
285  return result;
286 }
287 
288 
289 /* Doesn't check that the string is strictly according to format */
290 struct emimsg *get_fields(Octstr *message, Octstr *whoami)
291 {
292  long trn, len, ot, checksum; /* because of Octstr_parse_long... */
293  char or, posit;
294  long fieldno, pos, pos2;
295  struct emimsg *result = NULL;
296 
297  debug("smsc.emi2", 0, "EMI2[%s]: emi2 parsing packet: <%s>",
298  octstr_get_cstr(whoami), octstr_get_cstr(message));
299  if (octstr_get_char(message, 0) != 2 ||
300  octstr_get_char(message, octstr_len(message) - 1) != 3)
301  goto error;
302  if (octstr_parse_long(&trn, message, 1, 10) != 3)
303  goto error;
304  if (octstr_parse_long(&len, message, 4, 10) != 9)
305  goto error;
306  if (octstr_len(message) != len + 2) /* +2 for start/end markers */
307  goto error;
308  if ( (or = octstr_get_char(message, 10)) != 'O' && or != 'R')
309  goto error;
310  if (octstr_parse_long(&ot, message, 12, 10) != 14)
311  goto error;
312  if (or == 'O')
313  result = emimsg_create_op(ot, trn, whoami);
314  else {
315  posit = octstr_get_char(message, 15);
316  if (posit == 'A')
317  result = emimsg_create_reply_s(ot, trn, 1, whoami);
318  else if (posit == 'N')
319  result = emimsg_create_reply_s(ot, trn, 0, whoami);
320  else
321  goto error;
322  }
323  if (result == NULL)
324  goto error;
325  pos2 = 14;
326  for (fieldno = 0; fieldno < result->num_fields; fieldno++) {
327  pos = pos2 + 1;
328  if ( (pos2 = octstr_search_char(message, '/', pos)) == -1)
329  goto error;
330  if (pos2 > pos)
331  result->fields[fieldno] = octstr_copy(message, pos, pos2 - pos);
332  }
333  if (octstr_search_char(message, '/', pos2 + 1) != -1) {
334  int extrafields = 0;
335 
336  pos = pos2;
337  while ((pos = octstr_search_char(message, '/', pos + 1)) != -1) {
338  extrafields++;
339  pos2 = pos;
340  }
341  /* The extra fields are ignored */
342  warning(0, "get_fields: EMI message of type %d/%c has %d more fields "
343  "than expected.", result->ot, result->or, extrafields);
344  }
345  if (octstr_parse_long(&checksum, message, pos2 + 1, 16) !=
346  octstr_len(message) - 1 || checksum != calculate_checksum(message))
347  goto error;
348  if (result->or == 'R' && octstr_get_char(result->fields[0], 0) == 'N') {
349  long errcode;
350  if (!result->fields[1] ||
351  octstr_parse_long(&errcode, result->fields[1], 0, 10) != 2)
352  goto error;
353  error(0, "EMI2[%s]: Got negative ack. op:%d, trn:%d, error:%ld (%s), message:%s",
354  octstr_get_cstr(whoami),
355  result->ot, result->trn, errcode, emi_strerror(errcode),
356  result->fields[2] ? octstr_get_cstr(result->fields[2]) : "");
357  }
358  return result;
359 error:
360  error(0, "EMI2[%s]: Invalid EMI packet: %s", octstr_get_cstr(whoami),
361  octstr_get_cstr(message));
362  if (result)
363  emimsg_destroy(result);
364  return NULL;
365 }
366 
367 
368 int emimsg_send(Connection *conn, struct emimsg *emimsg, Octstr *whoami)
369 {
370  Octstr *string;
371 
372  string = emimsg_tostring(emimsg);
373  if (!string) {
374  error(0, "EMI2[%s]: emimsg_send: conversion to string failed",
375  octstr_get_cstr(whoami));
376  return -1;
377  }
378  if (emimsg->ot == 60)
379  debug("smsc.emi2", 0, "EMI2[%s]: Sending operation type 60, message with "
380  "password not shown in log file.", octstr_get_cstr(whoami));
381  else
382  debug("smsc.emi2", 0, "EMI2[%s]: emi2 sending packet: <%s>",
383  octstr_get_cstr(whoami), octstr_get_cstr(string));
384  if (conn_write(conn, string) == -1) {
385  octstr_destroy(string);
386  error(0, "EMI2[%s]: emimsg_send: write failed",
387  octstr_get_cstr(whoami));
388  return -1;
389  }
390  octstr_destroy(string);
391  return 1;
392 }
struct emimsg * emimsg_duplicate(struct emimsg *emimsg)
Definition: emimsg.c:229
void error(int err, const char *fmt,...)
Definition: log.c:612
int emimsg_send(Connection *conn, struct emimsg *emimsg, Octstr *whoami)
Definition: emimsg.c:368
char or
Definition: emimsg.h:72
Definition: emimsg.h:91
void octstr_append(Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:1502
void emimsg_destroy(struct emimsg *emimsg)
Definition: emimsg.c:215
static Octstr * emimsg_tostring(struct emimsg *emimsg)
Definition: emimsg.c:266
void octstr_append_char(Octstr *ostr, int ch)
Definition: octstr.c:1515
static int field_count_reply(int ot, int posit, Octstr *whoami)
Definition: emimsg.c:132
int trn
Definition: emimsg.h:71
struct emimsg * emimsg_create_op(int ot, int trn, Octstr *whoami)
Definition: emimsg.c:166
Definition: emimsg.h:70
struct emimsg * get_fields(Octstr *message, Octstr *whoami)
Definition: emimsg.c:290
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define octstr_copy(ostr, from, len)
Definition: octstr.h:178
long octstr_search_char(const Octstr *ostr, int ch, long pos)
Definition: octstr.c:1010
static int calculate_checksum(Octstr *message)
Definition: emimsg.c:252
int conn_write(Connection *conn, Octstr *data)
Definition: conn.c:1043
static struct emimsg * emimsg_create_withlen(int len)
Definition: emimsg.c:153
Definition: emimsg.h:81
#define octstr_duplicate(ostr)
Definition: octstr.h:187
Definition: emimsg.h:97
struct emimsg * emimsg_create_reply(int ot, int trn, int positive, Octstr *whoami)
Definition: emimsg.c:199
void warning(int err, const char *fmt,...)
Definition: log.c:624
Octstr * octstr_format(const char *fmt,...)
Definition: octstr.c:2462
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
static char * emi_strerror(int errnum)
Definition: emimsg.c:67
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
int ot
Definition: emimsg.h:73
Definition: octstr.c:118
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
static int field_count_op(int ot, Octstr *whoami)
Definition: emimsg.c:111
Octstr ** fields
Definition: emimsg.h:75
long octstr_parse_long(long *nump, Octstr *ostr, long pos, int base)
Definition: octstr.c:747
int octstr_get_char(const Octstr *ostr, long pos)
Definition: octstr.c:404
static struct emimsg * emimsg_create_reply_s(int ot, int trn, int positive, Octstr *whoami)
Definition: emimsg.c:182
int num_fields
Definition: emimsg.h:74
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.