Kannel: Open Source WAP and SMS gateway  svn-r5335
smsc_ois.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2018 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  * smsc_ois.c - Sema Group SMS2000 (G6.0) Center (OIS 5.0).
59  * Jouko Koski (EDS) for WapIT Ltd.
60  *
61  * The SMS2000 has a general X.25 access gateway for accessing the SMSC,
62  * as described in the Open Interface Specification 5.0 document.
63  * A protocol translator - like the Cisco 2501 router - hides all the
64  * X.25 trickery from us. We just connect to a preconfigured router
65  * address/port, and the translator forwards the connection to the SMS2000.
66  * Correspondingly, if the SMSC has something to say, it looks like
67  * the router were contacting our port. The router should be configured so,
68  * that it has a pre-defined address and tcp port in X.25 automode establishing
69  * a X.25 link and a similar configuration in X.25 side connecting to a pre-
70  * defined address and port, it shall not encapsulate everything in Telnet
71  * (set the stream mode), and it should suppress banner messages like "Trying
72  * 9876...Open" (set the quiet mode).
73  *
74  * Whenever possible, I've tried to steal ideas and code from other smsc_*
75  * files, particularly from Hao Shi's (EDS) original implementation for a
76  * serial-line-connected PAD. However, the code is highly evolutionary,
77  * because during the implementation new technical details kept popping
78  * up all the time (initially, PAD commands were supposed to be used,
79  * but the router was configured to "automode", so they weren't necessary;
80  * instead the router gave banner messages and wanted some telnet negotiations;
81  * the router insisted echoing everything and delayed <nul>s after <cr>s;
82  * telnet transmit-binary mode solved that; then the stream mode (no telnet
83  * encapsulation) was discovered; suddenly the banners were turned off also;
84  * but still the smsc didn't deliver mo messages, because it wanted to
85  * connect instead of using our existing connection; then we began to use
86  * short connection sessions for transmitting instead of a single ever-
87  * lasting connection, and also started to specifically listen for smsc
88  * initiated connections, which yielded two separate input buffers; then
89  * suddenly the banners were there again, so some intelligence had to be
90  * added to adapt their (non-)existence; then revealed the spec version 4.5
91  * had been obsolete all the time and we got 5.0; the router apparently
92  * caused some extra packets on the x.25 side and everybody was blaming the
93  * application; then the connection maintenance and buffering was again
94  * revisited to achieve better performance and reliability... Really an
95  * interesting story but think if it were about you instead of me :-)
96  *
97  * Really funny thing is that according to the spec the SMS2000 does have
98  * a direct TCP/IP access interface. However, here we have the general X.25
99  * access interface, since we started with the old spec and probably the
100  * simpler TCP/IP access is not available in our particular customer's
101  * installation, not at least when this was written. In the direct access
102  * only single ever-lasting connection is necessary, and the messages are
103  * the same but their format is different. Encoding tricks are the same.
104  * So, if you are implementing that access mode some day, there are probably
105  * differences between this access mode and yours on so many levels, that
106  * simple if () selections won't work; write your own code from (nearly)
107  * scratch and take appropriate encoding conversion functions here. Or do
108  * just whatever you want, what should I care :-).
109  */
110 
111 #include <unistd.h>
112 #include <ctype.h>
113 #include <errno.h>
114 #include <string.h>
115 #include <sys/time.h>
116 #include <sys/types.h>
117 #include <sys/timeb.h>
118 #include <sys/socket.h>
119 #include <netinet/in.h>
120 #include <arpa/inet.h>
121 
122 #include "smsc.h"
123 #include "smsc_p.h"
124 #include "gwlib/gwlib.h"
125 #include "sms.h"
126 
127 /* XXX Delete me and replace dcs with dcs_to_fields */
130  DCS_OCTET_DATA = 4 /* flag_8bit */
131 };
132 
133 
134 /* 'private:' */
135 
136 int ois_debug_level = 0; /* some extra verbosity in debug logging */
137 /* 0=just normal debugging, 1=input/output messages, 2=function entries, */
138 /* 3=message assembly/disassembly, 4=disconnection tracing, */
139 /* 5=message conversions, and 8=message polling (=too much) */
140 
141 #define SAY(d,s) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s); }
142 #define SAY2(d,s,t) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s,t); }
143 #define SAY3(d,s,t,u) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s,t,u); }
144 #define IOTRACE(x,s,l) SAY3(1,"%s [%s]",x,ois_debug_str(s,l))
145 
146 
147 #define BUFLEN (511) /* sure enough for ois messages */
148 #define OIS_OPEN_WAITTIME (15) /* seconds, waiting for banners */
149 #define OIS_MESSAGE_WAITTIME (30) /* seconds, until closing idle connection */
150 #define OIS_WAITTIME (999999) /* microseconds, waiting for banners at a time */
151 #define OIS_NOWAIT (0) /* microseconds, not waiting */
152 #define MAXCOUNTER (10000) /* ois message id */
153 #define EOL ('\r') /* ois definition for the eol */
154 
155 typedef struct ois_listentry {
158 } ois_listentry;
159 
160 #define OIS_FLAG_DEBUG (0x000f)
161 #define OIS_FLAG_ERROR (0x0100)
162 #define OIS_FLAG_NOBANNER (0x0200)
163 #define OIS_FLAG_MULTIPLE_CALL (0x0400)
164 #define OIS_FLAG_CLOSED (0x0800)
165 
166 static int ois_counter = 0; /* [0..MAXCOUNTER), ois "unique" message id */
167 static int ois_open_listener(SMSCenter *smsc);
168 static int ois_open_sender(SMSCenter *smsc);
169 static int ois_open_receiver(SMSCenter *smsc);
170 static void ois_disconnect_all(SMSCenter *smsc);
171 static void ois_disconnect(SMSCenter *smsc);
172 static int ois_read_into_buffer(SMSCenter *smsc, long wait_usec);
173 static int ois_check_input(SMSCenter *smsc, long wait_usec);
174 static int ois_check_incoming(SMSCenter *smsc, long wait_usec);
175 static void ois_append_to_list(ois_listentry **head, Msg *msg);
176 static int ois_int_to_i4(char *raw, int nbr);
177 static int ois_increment_counter(void);
178 static int ois_submit_sm_invoke(SMSCenter *smsc, const Msg *msg);
179 static int ois_encode_submit_sm_invoke(char *str, const Msg *msg);
180 static int ois_append_msisdn(char *raw, const Msg *msg);
181 static int ois_append_sme_reference_number(char *raw);
182 static int ois_append_priority(char *raw);
183 static int ois_append_originating_address(char *raw);
184 static int ois_append_validity_period(char *raw);
185 static int ois_append_data_coding_scheme(char *raw, const Msg *msg);
186 static int ois_append_status_report_request(char *raw);
187 static int ois_append_protocol_id(char *raw);
188 static int ois_append_submission_options(char *raw, const Msg *msg);
189 static int ois_append_sm_text(char *raw, const Msg *msg);
190 static int ois_submit_sm_result(SMSCenter *smsc, const char *buffer);
191 static int ois_decode_submit_sm_result(int *code, const char *str);
192 static int ois_deliver_sm_invoke(SMSCenter *smsc, const char *buffer);
193 static int ois_decode_deliver_sm_invoke(Msg *msg, const char *str);
194 static int ois_check_deliver_sm_invoke(const char *str);
195 static int ois_adjust_destination_address(Msg *msg, const char *raw);
196 static int ois_ignore_smsc_reference_number(const char *raw);
197 static int ois_adjust_originating_address(Msg *msg, const char *raw);
198 static int ois_adjust_data_coding_scheme(Msg *msg, const char *raw);
199 static int ois_ignore_protocol_id(const char *raw);
200 static int ois_adjust_additional_information(Msg *msg, const char *raw);
201 static int ois_adjust_sm_text(Msg *msg, const char *raw);
202 static int ois_ignore_time(const char *raw);
203 static int ois_deliver_sm_result(SMSCenter *smsc, int result, const char *str);
204 static int ois_encode_deliver_sm_result(char *str, int result);
205 static int ois_expand_gsm7(char *raw8, const char *raw7, int len);
206 static int ois_expand_gsm7_to_bits(char *bits, const char *raw7, int len);
207 static char ois_expand_gsm7_from_bits(const char *bits, int pos);
208 static int ois_convert_to_ia5(char *str, const char *raw, int len);
209 static int ois_convert_from_ia5(char *raw, const char *str);
210 static int ois_convert_to_iso88591(char *raw, int len);
211 static int ois_extract_msg_from_buffer(char *str, SMSCenter *smsc);
212 static int ois_extract_line_from_buffer(char *str, SMSCenter *smsc);
213 static void ois_swap_buffering(SMSCenter *smsc);
214 static const char *ois_debug_str(const char *raw, int len);
215 
216 /* 'public:' */
217 
218 /*
219  * Establish a connection to the SMSC.
220  */
221 
222 SMSCenter *ois_open(int receiveport, const char *hostname, int port, int debug_level)
223 {
224  SMSCenter *smsc;
225  int ret;
226 
227  ois_debug_level = debug_level & OIS_FLAG_DEBUG;
228  SAY(2, "ois_open");
229 
230  /* create a SMSCenter structure */
231 
232  smsc = smscenter_construct();
233  if (smsc == NULL) {
234  goto error;
235  }
236 
237  smsc->type = SMSC_TYPE_OIS;
238  smsc->receive_port = receiveport;
239  smsc->hostname = gw_strdup(hostname);
240  smsc->port = port;
241  smsc->ois_flags = ois_debug_level;
242 
243  ret = ois_open_listener(smsc);
244  if (ret < 0) {
245  goto error;
246  }
247  sprintf(smsc->name, "OIS:TCP/X.25-Translator:localhost:%d:TCP:%.512s:%d",
248  smsc->receive_port, smsc->hostname, smsc->port);
249 
250  return smsc;
251 
252  error:
253  error(0, "ois_open: could not open");
254  smscenter_destruct(smsc);
255  return NULL;
256 }
257 
258 
259 /*
260  * Terminate the SMSC connection.
261  */
262 
264 {
266  SAY(2, "ois_close");
267 
268  if (smsc->type != SMSC_TYPE_OIS) {
269  warning(0, "ois_close: closing a not-ois connection...");
270  }
271 
272  ois_swap_buffering(smsc);
274  ois_swap_buffering(smsc);
276  SAY(4, "ois_close: ois_disconnect_all");
277  ois_disconnect_all(smsc);
278 
279  return 0;
280 }
281 
282 
283 /*
284  * Re-establish a SMSC connection.
285  */
286 
288 {
289  int ret;
290 
292  SAY(2, "ois_reopen");
293 
294  ois_close(smsc);
295 
296  if (smsc->type == SMSC_TYPE_OIS) {
297  ret = ois_open_listener(smsc);
298  if (ret < 0) {
299  goto error;
300  }
301  } else {
302  error(0, "ois_reopen: wrong smsc type");
303  goto error;
304  }
305  return 0;
306 
307  error:
308  error(0, "ois_reopen: could not open");
309  return -1;
310 }
311 
312 
313 /*
314  * Check for MO messages.
315  * Put all incoming MO messages into an internal queue.
316  */
317 
319 {
320  int ret;
321 
323  SAY(8, "ois_pending_smsmessage");
324 
325  ret = ois_check_incoming(smsc, OIS_NOWAIT);
326  if (ret == 0 && smsc->socket != -1) {
327  ret = ois_check_input(smsc, OIS_NOWAIT);
328  }
329  if (ret == 0 && smsc->ois_socket != -1) {
330  ois_swap_buffering(smsc);
331  ret = ois_check_input(smsc, OIS_NOWAIT);
332  ois_swap_buffering(smsc);
333  if (smsc->ois_socket == -1 && smsc->ois_ack_debt != 0) {
334  warning(0, "ois_pending_smsmessage: missing %d ack(s)...",
335  smsc->ois_ack_debt);
336  }
337  }
338  return ret;
339 }
340 
341 
342 /*
343  * Send a MT message.
344  */
345 
346 int ois_submit_msg(SMSCenter *smsc, const Msg *msg)
347 {
348  int ret;
349 
351  SAY(2, "ois_submit_msg");
352  ois_swap_buffering(smsc);
353 
354  if (msg_type((Msg *)msg) != sms) {
355  error(0, "ois_submit_msg: can not handle message types other than smart_msg");
356  goto error;
357  }
358 
359  if (smsc->socket == -1) {
360  ret = ois_open_sender(smsc);
361  if (ret < 0) {
362  goto error;
363  }
364  }
365 
366  ret = ois_submit_sm_invoke(smsc, msg);
367  if (ret < 0) {
368  goto error_close;
369  }
370 
371  ++smsc->ois_ack_debt;
372  time(&smsc->ois_alive);
373  ret = 0;
374  goto out;
375 
376  error_close:
377  if (smsc->ois_ack_debt != 0) {
378  warning(0, "ois_submit_msg: missing %d ack(s)...",
379  smsc->ois_ack_debt);
380  }
381  SAY(4, "ois_submit_msg: ois_disconnect in error_close");
382  ois_disconnect(smsc);
383  error:
384  SAY(2, "ois_submit_msg error");
385  ret = -1;
386  out:
387  ois_swap_buffering(smsc);
388  return ret;
389 }
390 
391 
392 /*
393  * Receive a MO message (from the internal queue).
394  */
395 
397 {
398  ois_listentry *item;
399 
401  SAY(2, "ois_receive_msg");
402 
403  item = smsc->ois_received_mo;
404  if (item == NULL) { /* no mo messages */
405  if ((smsc->ois_flags & OIS_FLAG_ERROR) == 0) {
406  return 0; /* should actually not happen */
407  } else {
408  return -1; /* error pending, reopen? */
409  }
410  } else { /* we have a message waiting */
411  smsc->ois_received_mo = item->next;
412  *msg = item->msg;
413  gw_free(item);
414  return 1; /* got the message */
415  }
416 }
417 
418 
419 /*
420  * Destruct the internal queue.
421  */
422 
424 {
425  Msg *msg;
426 
428  SAY(2, "ois_delete_queue");
429 
430  while (ois_receive_msg(smsc, &msg) > 0) {
431  gw_free(msg);
432  }
433  return;
434 }
435 
436 
437 
438 
439 
440 
441 
442 
443 /*
444  * Implementation of 'private:'
445  */
446 
447 
448 static int ois_open_listener(SMSCenter *smsc)
449 {
450  SAY(2, "ois_open_listener");
451 
453  NULL);
454  /* XXX add interface_name if required */
455  if (smsc->ois_listening_socket < 0) {
456  goto error;
457  }
458  if (socket_set_blocking(smsc->ois_listening_socket, 0) < 0) {
459  ois_close(smsc);
460  goto error;
461  }
462  smsc->ois_flags &= ~OIS_FLAG_ERROR;
463  smsc->ois_flags &= ~OIS_FLAG_NOBANNER;
464  smsc->ois_alive2 = time(&smsc->ois_alive);
465 
466  SAY2(2, "ois_open_listener fd=%d", smsc->ois_listening_socket);
467  return 0;
468 
469  error:
470  error(0, "ois_open_listener: failed to open listening socket");
471  return -1;
472 }
473 
474 
475 static int ois_open_sender(SMSCenter *smsc)
476 {
477  int ret;
478  char buffer[BUFLEN+1];
479  time_t now;
480  time_t beginning;
481 
482  SAY(2, "ois_open_sender");
483  debug("bb.sms.ois", 0, "connecting to host %s port %d",
484  smsc->hostname, smsc->port);
485 
486  time(&beginning);
487  smsc->socket = tcpip_connect_to_server(smsc->hostname, smsc->port,
488  NULL);
489  /* XXX add interface_name if required */
490  if (smsc->socket < 0) {
491  return -1;
492  } else {
493  smsc->buflen = 0;
494  time(&smsc->ois_alive);
495  smsc->ois_ack_debt = 0;
496  }
497 
498  SAY2(2, "ois_open_sender fd=%d", smsc->socket);
499  if (smsc->ois_flags & OIS_FLAG_NOBANNER) {
500  return 0;
501  }
502 
503  buffer[0] = '\0';
504  for (time(&now); (now - beginning) < OIS_OPEN_WAITTIME; time(&now)) {
505  ret = ois_read_into_buffer(smsc, OIS_WAITTIME);
506  if (ret < 0) {
507  goto error;
508  }
509 
510  if (smsc->buflen == 0) {
511  /* assume that the router is in the quiet mode */
512  /* there will be no banners */
513  smsc->ois_flags |= OIS_FLAG_NOBANNER;
514  debug("bb.sms.ois", 0, "assuming that %s:%d is in the quiet mode",
515  smsc->hostname, smsc->port);
516  return 0;
517  }
518  ret = ois_extract_line_from_buffer(buffer, smsc);
519  if (ret > 0) {
520  if (strncmp(buffer, "Trying", 6) == 0 &&
521  strstr(buffer, "...Open\r\n") != NULL) {
522  time(&smsc->ois_alive);
523  return 0;
524  } else {
525  break;
526  }
527  }
528  }
529 
530  error:
531  SAY(4, "ois_open_sender: ois_disconnect in error");
532  ois_disconnect(smsc);
533  error(0, "ois_open_sender: failed to connect [%s%s]",
534  buffer, ois_debug_str(smsc->buffer, smsc->buflen));
535  return -1;
536 }
537 
538 
539 static int ois_open_receiver(SMSCenter *smsc)
540 {
541  struct sockaddr_in addr;
542  int addrlen;
543  Octstr *os;
544 
545  SAY(2, "ois_open_receiver");
546 
547  /* the listening socket should be non-blocking... */
548 
549  addrlen = sizeof(addr);
550  smsc->socket = accept(smsc->ois_listening_socket,
551  (struct sockaddr *)&addr, (socklen_t *)&addrlen);
552  if (smsc->socket == -1) {
553  if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
554  /* || errno == ECONNABORTED || errno == EPROTO) -Kalle 6.7 */
555  {
556  return 0;
557  } else {
558  error(errno, "ois_open_receiver: accept failed");
559  smsc->ois_flags |= OIS_FLAG_ERROR;
560  return -1;
561  }
562  }
563 
564  SAY2(2, "ois_open_receiver fd=%d", smsc->socket);
565  os = gw_netaddr_to_octstr(AF_INET, &addr.sin_addr);
566  debug("bb.sms.ois", 0, "connection from host %s port %hu",
567  octstr_get_cstr(os), ntohs(addr.sin_port));
568  octstr_destroy(os);
569  time(&smsc->ois_alive);
570  return 0;
571 }
572 
573 
574 static void ois_disconnect_all(SMSCenter *smsc)
575 {
576  SAY2(2, "ois_disconnect_all fd=%d", smsc->ois_listening_socket);
577 
578  ois_swap_buffering(smsc);
579  SAY(4, "ois_disconnect_all: ois_disconnect");
580  ois_disconnect(smsc); /* smsc->socket */
581  ois_swap_buffering(smsc);
582  SAY(4, "ois_disconnect_all: ois_disconnect");
583  ois_disconnect(smsc); /* smsc->socket */
584 
585  if (smsc->ois_listening_socket != -1) {
586  if (close(smsc->ois_listening_socket) == -1) {
587  warning(errno, "ois_disconnect_all: close failed...");
588  }
589  smsc->ois_listening_socket = -1;
590  }
591  return;
592 }
593 
594 
595 static void ois_disconnect(SMSCenter *smsc)
596 {
597  SAY2(2, "ois_disconnect fd=%d", smsc->socket);
598 
599  if (smsc->socket != -1) {
600  if (close(smsc->socket) == -1) {
601  warning(errno, "ois_disconnect: close failed...");
602  }
603  smsc->socket = -1;
604  }
605  return;
606 }
607 
608 
609 static int ois_read_into_buffer(SMSCenter *smsc, long wait_usec)
610 {
611  int ret;
612 
613  SAY(8, "ois_read_into_buffer");
614 
615  if (smsc->socket == -1) {
616  if ((smsc->ois_flags & OIS_FLAG_CLOSED) == 0) {
617  debug("bb.sms.ois", 0, "attempting to read from a closed socket");
618  smsc->ois_flags |= OIS_FLAG_CLOSED;
619  }
620  return 0;
621  } else {
622  smsc->ois_flags &= ~OIS_FLAG_CLOSED;
623  }
624 
625  ret = read_available(smsc->socket, wait_usec);
626  if (ret > 0) {
627  time(&smsc->ois_alive);
628  ret = smscenter_read_into_buffer(smsc);
629  if (ret > 0 || (ret == 0 && smsc->buflen > 0)) {
630  SAY(2, "ois_read_into_buffer got something");
631  } else if (ret == 0) {
632  if (smsc->buflen > 0) {
633  SAY(2, "ois_read_into_buffer has something");
634  ret = 1;
635  }
636  SAY(4, "ois_read_into_buffer: ois_disconnect");
637  ois_disconnect(smsc);
638  }
639  }
640  return ret;
641 }
642 
643 
644 static int ois_check_input(SMSCenter *smsc, long wait_usec)
645 {
646  char buffer[BUFLEN+1];
647  time_t now;
648  int ret;
649 
650  SAY(8, "ois_check_input");
651 
652  ret = ois_read_into_buffer(smsc, wait_usec);
653  if (ret < 0) {
654  goto error;
655  }
656 
657  ret = ois_extract_msg_from_buffer(buffer, smsc);
658  if (ret > 0) {
659  IOTRACE("received", buffer, ret);
660  switch (buffer[0]) {
661  case 's':
662  ret = ois_submit_sm_result(smsc, buffer);
663  if (ret > 0) {
664  warning(0, "ois_check_input: submit sm result signals (%d)...", ret);
665  } else if (ret < 0) {
666  error(0, "ois_check_input: invalid submit sm result");
667  goto error;
668  }
669  --smsc->ois_ack_debt;
670  time(&smsc->ois_alive);
671  break;
672  case 'M':
673  ret = ois_deliver_sm_invoke(smsc, buffer);
674  if (ret >= 0) {
675  ret = ois_deliver_sm_result(smsc, ret, buffer);
676  if (ret < 0) {
677  goto error;
678  }
679  } else {
680  error(0, "ois_check_input: invalid deliver sm invoke");
681  goto error;
682  }
683  time(&smsc->ois_alive);
684  break;
685  default:
686  warning(0, "ois_check_input: unexpected message [%s]...",
687  ois_debug_str(buffer, ret));
688  break;
689  }
690  } else {
691  if (smsc->socket != -1) {
692  time(&now);
693  if ((now - smsc->ois_alive) > OIS_MESSAGE_WAITTIME) {
694  debug("bb.sms.ois", 0, "closing an idle connection");
695  SAY(4, "ois_check_input: ois_disconnect");
696  ois_disconnect(smsc);
697  }
698  }
699  }
700 
701  if (ret < 0) {
702  error(0, "ois_check_input: malformatted message [%s]",
703  ois_debug_str(buffer, -ret));
704  goto error;
705  }
706 
707  if (smsc->ois_received_mo != NULL ||
708  (smsc->ois_flags & OIS_FLAG_ERROR) != 0) {
709  SAY(2, "ois_check_input has something");
710  return 1; /* at least one message in the queue or an error pending */
711  } else {
712  return 0; /* no messages this time */
713  }
714 
715  error:
716  smsc->ois_flags |= OIS_FLAG_ERROR;
717  return 1;
718 }
719 
720 
721 static int ois_check_incoming(SMSCenter *smsc, long wait_usec)
722 {
723  fd_set read_fd;
724  struct timeval tv;
725  int ret;
726 
727  SAY(8, "ois_check_incoming");
728 
729  tv.tv_sec = 0;
730  tv.tv_usec = wait_usec;
731 
732  FD_ZERO(&read_fd);
733  FD_SET(smsc->ois_listening_socket, &read_fd);
734  ret = select(smsc->ois_listening_socket + 1, &read_fd, NULL, NULL, &tv);
735  if (ret == -1) {
736  if (errno == EINTR || errno == EAGAIN) {
737  return 0;
738  } else {
739  error(errno, "ois_check_incoming: select failed");
740  smsc->ois_flags |= OIS_FLAG_ERROR;
741  return -1;
742  }
743  } else if (ret == 0) {
744  return 0;
745  }
746 
747  /* if we end up here, someone is trying to connect */
748 
749  if (smsc->socket != -1) {
750  if ((smsc->ois_flags & OIS_FLAG_MULTIPLE_CALL) == 0) {
751  /* if you see lots of these, maybe we should accept */
752  /* multiple incoming connections at a time... */
753  debug("bb.sms.ois", 0, "letting an incoming call to wait until the old one disconnects");
755  }
756  return 0;
757  }
758 
760  return ois_open_receiver(smsc);
761 }
762 
763 
765 {
766  ois_listentry *item;
767  ois_listentry *tail;
768 
769  SAY(2, "ois_append_to_list");
770 
771  item = gw_malloc(sizeof(ois_listentry));
772  item->next = NULL;
773  item->msg = msg;
774 
775  if (*head == NULL) {
776  *head = item;
777  } else { /* not so bright algorithm, but ok with relatively short lists */
778  for (tail = *head; tail->next != NULL; tail = tail->next) ;
779  tail->next = item;
780  }
781  return;
782 }
783 
784 
785 
786 static int ois_int_to_i4(char *raw, int nbr)
787 {
788  int pos;
789 
790  SAY(3, "ois_int_to_i4");
791 
792  for (pos = 0; pos < 4; ++pos) {
793  raw[pos] = (char)(nbr % 0x100);
794  nbr /= 0x100;
795  }
796  return 4;
797 }
798 
799 static int ois_increment_counter(void)
800 {
801  SAY(3, "ois_increment_counter");
802 
804  return ois_counter;
805 }
806 
807 
808 static int ois_submit_sm_invoke(SMSCenter *smsc, const Msg *msg)
809 {
810  char body[BUFLEN+1];
811  char buffer[BUFLEN+1];
812  int len;
813  int count;
814  int i;
815  int ret;
816 
817  SAY(2, "ois_submit_sm_invoke");
818 
819  /* construct a message */
820 
821  ois_increment_counter(); /* once per invoke */
822  len = ois_encode_submit_sm_invoke(body, msg);
823 
824  /* the x.25 gear should be capable to fragment large messages, but... */
825  /* let's just use an explicit 128 byte blocks */
826 
827  count = (len-1) / 121; /* 121 = 128 - 6 - 1 */
828 
829  /* first part */
830 
831  sprintf(buffer, "%c%c%04d%.121s%c",
832  'S', /* submit sm invoke */
833  (char)(0x50|count), /* ia5 encoding, first part */
834  ois_counter,
835  &body[0],
836  EOL);
837  IOTRACE("sending", buffer, strlen(buffer));
838  ret = write_to_socket(smsc->socket, buffer);
839  if (ret < 0) {
840  goto error;
841  }
842 
843  /* additional parts */
844 
845  for (i = 1; i <= count; ++i) {
846  sprintf(buffer, "%c%c%04d%.121s%c",
847  'S', /* submit sm invoke */
848  (char)(0x60|(count-i)), /* ia5, additional part */
849  ois_counter,
850  &body[i*121],
851  EOL);
852  IOTRACE("sending", buffer, strlen(buffer));
853  ret = write_to_socket(smsc->socket, buffer);
854  if (ret < 0) {
855  goto error;
856  }
857  }
858 
859  SAY(2, "ois_submit_sm_invoke ok");
860  return 0;
861 
862  error:
863  SAY(2, "ois_submit_sm_invoke error");
864  return -1;
865 }
866 
867 
868 static int ois_encode_submit_sm_invoke(char *str, const Msg *msg)
869 {
870  char raw[BUFLEN];
871  int pos;
872  int ret;
873 
874  SAY(3, "ois_encode_submit_sm_invoke");
875 
876  /* construct the submit sm invoke body content */
877 
878  pos = 0;
879  pos += ois_append_msisdn(&raw[pos], msg);
880  pos += ois_append_sme_reference_number(&raw[pos]);
881  pos += ois_append_priority(&raw[pos]);
882  pos += ois_append_originating_address(&raw[pos]);
883  pos += ois_append_validity_period(&raw[pos]);
884  pos += ois_append_data_coding_scheme(&raw[pos], msg);
885  pos += ois_append_status_report_request(&raw[pos]);
886  pos += ois_append_protocol_id(&raw[pos]);
887  pos += ois_append_submission_options(&raw[pos], msg);
888  pos += ois_append_sm_text(&raw[pos], msg);
889 
890  ret = ois_convert_to_ia5(str, raw, pos);
891  return ret;
892 }
893 
894 static int ois_append_msisdn(char *raw, const Msg *msg)
895 {
896  int len;
897 
898  SAY(3, "ois_append_msisdn");
899 
900  len = octstr_len(msg->sms.receiver);
901  raw[0] = (char) len;
902  memcpy(&raw[1], octstr_get_cstr(msg->sms.receiver), len);
903  return 1 + len;
904 }
905 
906 static int ois_append_sme_reference_number(char *raw)
907 {
908  SAY(3, "ois_append_sme_reference_number");
909 
910  /* 1=key, 2=not key (OIS 4.5) */
911  /* or 1=reject duplicates, 2=allow duplicates (OIS 5.0) */
912  raw[0] = (char) 2;
913  return 1 + ois_int_to_i4(&raw[1], ois_counter);
914 }
915 
916 static int ois_append_priority(char *raw)
917 {
918  SAY(3, "ois_append_priority");
919 
920  raw[0] = (char) 1; /* 0=high, 1=normal */
921  return 1;
922 }
923 
924 static int ois_append_originating_address(char *raw)
925 {
926  SAY(3, "ois_append_originating_address");
927 
928  raw[0] = (char) 2; /* length */
929  raw[1] = 'A'; /* A3=address type, actual address is unnecessary */
930  raw[2] = '3';
931 
932  return 3;
933 }
934 
935 static int ois_append_validity_period(char *raw)
936 {
937  SAY(3, "ois_append_validity_period");
938 
939  raw[0] = (char) 2; /* 0=none, 1=absolute, 2=relative */
940  raw[1] = (char) 1; /* relative, (v+1)*5 minutes, v<144 */
941  return 2;
942 }
943 
944 static int ois_append_data_coding_scheme(char *raw, const Msg *msg)
945 {
946  SAY(3, "ois_append_data_coding_scheme");
947 
948  /* 0x0f is a special code for ASCII text, the SMSC will convert
949  * this to GSM and set the DCS to 0.
950  * FIXME: Convert to GSM ourselves and use DCS_GSM_TEXT.
951  * FIXME: use fields_to_dcs and try to support DC_UCS2 too ;) */
952  raw[0] = (char) (msg->sms.coding == DC_8BIT ? DCS_OCTET_DATA : 0x0f);
953  return 1;
954 }
955 
956 static int ois_append_status_report_request(char *raw)
957 {
958  SAY(3, "ois_append_status_report_request");
959 
960  raw[0] = (char) 0x00; /* bit field, bit 0=abandoned, bit 2=delivered */
961  return 1;
962 }
963 
964 static int ois_append_protocol_id(char *raw)
965 {
966  SAY(3, "ois_append_protocol_id");
967 
968  raw[0] = (char) 0; /* 0=default */
969  return 1;
970 }
971 
972 static int ois_append_submission_options(char *raw, const Msg *msg)
973 {
974  SAY(3, "ois_append_submission_options");
975 
976  /* bit field, bit 0=reply path, bit 1=udh, bits 3-4=dcs interpretation */
977  raw[0] = (char) 0x00;
978  if (octstr_len(msg->sms.udhdata)) {
979  raw[0] |= (char) 0x02;
980  }
981  if (msg->sms.coding == DC_8BIT) { /* XXX and UCS-2? */
982  raw[0] |= (char) 0x10;
983  }
984  return 1;
985 }
986 
987 
988 static int ois_append_sm_text(char *raw, const Msg *msg)
989 {
990  int udhlen7, udhlen8;
991  int msglen7, msglen8;
992  int len;
993 
994  SAY(3, "ois_append_sm_text");
995 
996  if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF) {
997  charset_utf8_to_gsm(msg->sms.udhdata);
998  charset_utf8_to_gsm(msg->sms.msgdata);
999  }
1000 
1001 
1002  /* calculate lengths */
1003 
1004  udhlen8 = octstr_len(msg->sms.udhdata);
1005  msglen8 = octstr_len(msg->sms.msgdata);
1006 
1007  udhlen7 = udhlen8;
1008  msglen7 = msglen8;
1009  len = udhlen8 + msglen8;
1010 
1011  /* copy text */
1012 
1013  raw[0] = (char) (len);
1014  raw[1] = (char) (udhlen7 + msglen7);
1015  memcpy(&raw[2], octstr_get_cstr(msg->sms.udhdata), udhlen8);
1016  memcpy(&raw[2+udhlen8], octstr_get_cstr(msg->sms.msgdata), msglen8);
1017 
1018  IOTRACE("encoding", &raw[2], len);
1019 
1020  return 2 + len;
1021 }
1022 
1023 
1024 static int ois_submit_sm_result(SMSCenter *smsc, const char *buffer)
1025 {
1026  int status;
1027  int ret;
1028 
1029  SAY(2, "ois_submit_sm_result");
1030 
1031  ret = ois_decode_submit_sm_result(&status, buffer);
1032  if (ret < 0) {
1033  goto error;
1034  }
1035 
1036  return status;
1037 
1038  error:
1039  return -1;
1040 }
1041 
1042 
1043 static int ois_decode_submit_sm_result(int *code, const char *str)
1044 {
1045  int buflen;
1046  char raw[BUFLEN];
1047  int len;
1048 
1049  SAY(3, "ois_decode_submit_sm_result");
1050 
1051  buflen = strlen(str) - 1;
1052  if (buflen < 7 || str[0] != 's' || str[1] != 0x50 || str[buflen] != EOL) {
1053  goto error;
1054  }
1055 
1056  len = ois_convert_from_ia5(raw, &str[6]);
1057  if (len <= 0) {
1058  goto error;
1059  }
1060 
1061  *code = raw[0];
1062  *code &= 0xff;
1063 
1064  /* there is smsc reference number and accept time, but we ignore them */
1065 
1066  return 0;
1067 
1068  error:
1069  return -1;
1070 }
1071 
1072 
1073 static int ois_deliver_sm_invoke(SMSCenter *smsc, const char *buffer)
1074 {
1075  Msg *msg;
1076  int ret;
1077  ois_listentry **mo;
1078 
1079  SAY(2, "ois_deliver_sm_invoke");
1080 
1081  msg = msg_create(sms);
1082 
1083  ret = ois_decode_deliver_sm_invoke(msg, buffer);
1084  if (ret < 0) {
1085  goto error;
1086  }
1087 
1088  mo = (ois_listentry **)&smsc->ois_received_mo;
1090 
1091  return 0;
1092 
1093  error:
1094  msg_destroy(msg);
1095  return -1;
1096 }
1097 
1098 
1099 static int ois_decode_deliver_sm_invoke(Msg *msg, const char *str)
1100 {
1101  char body[BUFLEN+1];
1102  char raw[BUFLEN];
1103  int len;
1104  int i;
1105  int pos;
1106  int ret;
1107 
1108  SAY(3, "ois_decode_deliver_sm_invoke");
1109 
1110  ret = ois_check_deliver_sm_invoke(str);
1111  if (ret < 0) {
1112  goto error;
1113  }
1114 
1115  /* extract body */
1116 
1117  len = strlen(str);
1118  for (pos = 0, i = 6; i < len; ++i) {
1119  if (str[i] != EOL) {
1120  body[pos++] = str[i];
1121  } else {
1122  i += 6;
1123  }
1124  }
1125  body[pos] = '\0';
1126  memset(raw, '\0', sizeof(raw));
1127  len = ois_convert_from_ia5(raw, body);
1128 
1129  /* adjust msg values */
1130 
1131  pos = 0;
1132  pos += ois_adjust_destination_address(msg, &raw[pos]);
1133  pos += ois_ignore_smsc_reference_number(&raw[pos]);
1134  pos += ois_adjust_originating_address(msg, &raw[pos]);
1135  pos += ois_adjust_data_coding_scheme(msg, &raw[pos]);
1136  pos += ois_ignore_protocol_id(&raw[pos]);
1137  pos += ois_adjust_additional_information(msg, &raw[pos]);
1138  pos += ois_adjust_sm_text(msg, &raw[pos]);
1139  pos += ois_ignore_time(&raw[pos]); /* accept time */
1140  pos += ois_ignore_time(&raw[pos]); /* invoke time */
1141  if (pos != len) {
1142  error(0, "ois_decode_deliver_sm_invoke: message parsing error (%d!=%d)",
1143  pos, len);
1144  goto error;
1145  }
1146  return 0;
1147 
1148  error:
1149  return -1;
1150 }
1151 
1152 
1153 static int ois_check_deliver_sm_invoke(const char *str)
1154 {
1155  int buflen;
1156  char buffer[BUFLEN+1];
1157  int count;
1158 
1159  SAY(3, "ois_check_deliver_sm_invoke");
1160 
1161  /* check the (initial) header and trailer */
1162 
1163  buflen = strlen(str) - 1;
1164  if (buflen < 7 || str[0] != 'M' || (str[1] & 0x50) != 0x50
1165  || str[buflen] != EOL) {
1166  goto error;
1167  }
1168 
1169  count = str[1] & 0x0f;
1170  while (--count >= 0)
1171  {
1172  /* check the additional header */
1173 
1174  sprintf(buffer, "%c%c%c%.4s",
1175  EOL,
1176  'M', /* deliver sm invoke */
1177  (char)(0x60|count), /* ia5 encoding, additional part */
1178  &str[2]);
1179  if (strstr(str, buffer) == NULL) {
1180  goto error;
1181  }
1182  }
1183 
1184  return 0;
1185 
1186  error:
1187  return -1;
1188 }
1189 
1190 
1191 static int ois_adjust_destination_address(Msg *msg, const char *raw)
1192 {
1193  int len;
1194 
1195  SAY(3, "ois_adjust_destination_address");
1196 
1197  len = raw[0] & 0xff;
1198  msg->sms.receiver = octstr_create_from_data(&raw[1+2], len-2);
1199 
1200  return 1 + len;
1201 }
1202 
1203 static int ois_ignore_smsc_reference_number(const char *raw)
1204 {
1205  int value;
1206 
1207  SAY(3, "ois_ignore_smsc_reference_number");
1208 
1209  value = raw[3] & 0xff;
1210  value <<= 8;
1211  value |= raw[2] & 0xff;
1212  value <<= 8;
1213  value |= raw[1] & 0xff;
1214  value <<= 8;
1215  value |= raw[0] & 0xff;
1216 
1217  return 4;
1218 }
1219 
1220 static int ois_adjust_originating_address(Msg *msg, const char *raw)
1221 {
1222  int len;
1223 
1224  SAY(3, "ois_adjust_originating_address");
1225 
1226  len = raw[0] & 0xff;
1227  msg->sms.sender = octstr_create_from_data(&raw[1+2], len-2);
1228 
1229  return 1 + len;
1230 }
1231 
1232 static int ois_adjust_data_coding_scheme(Msg *msg, const char *raw)
1233 {
1234  SAY(3, "ois_adjust_data_coding_scheme");
1235 
1236  /* we're using this variable temporarily:
1237  * ois_adjust_sm_text will set the correct value */
1238 
1239  msg->sms.coding = (raw[0] & 0xff) + 1;
1240 
1241  return 1;
1242 }
1243 
1244 static int ois_ignore_protocol_id(const char *raw)
1245 {
1246  SAY(3, "ois_ignore_protocol_id");
1247 
1248  return 1;
1249 }
1250 
1251 static int ois_adjust_additional_information(Msg *msg, const char *raw)
1252 {
1253  SAY(3, "ois_adjust_additional_information");
1254 
1255  /* we're using this variable temporarily:
1256  * ois_adjust_sm_text will set the correct value */
1257  msg->sms.mclass = raw[0] & 0xff;
1258 
1259  return 1;
1260 }
1261 
1262 static int ois_adjust_sm_text(Msg *msg, const char *raw)
1263 {
1264  int msglen7, msglen8;
1265  char buffer[BUFLEN+1];
1266 
1267  SAY(3, "ois_adjust_sm_text");
1268 
1269  /* calculate lengths */
1270 
1271  msglen7 = raw[0] & 0xff;
1272  msglen8 = raw[1] & 0xff;
1273 
1274  /* copy text, note: flag contains temporarily the raw type description */
1275 
1276  switch ((msg->sms.coding - 1) & 0xff) {
1277  case 0x00: /* gsm7 */
1278  ois_expand_gsm7(buffer, &raw[2], msglen7);
1279  ois_convert_to_iso88591(buffer, msglen7);
1280  if (msg->sms.mclass & 0x02) { /* XXX mclass temporarily */
1281  msg->sms.msgdata = octstr_create("");
1282  msg->sms.udhdata = octstr_create_from_data(buffer, msglen7);
1283  } else {
1284  msg->sms.msgdata = octstr_create_from_data(buffer, msglen7);
1285  msg->sms.udhdata = octstr_create("");
1286  }
1287  msg->sms.coding = DC_7BIT;
1288  break;
1289  case 0x0f: /* ia5 */
1290  memcpy(buffer, &raw[2], msglen8);
1291  ois_convert_to_iso88591(buffer, msglen8);
1292  if (msg->sms.mclass & 0x02) { /* XXX mclass temporarily */
1293  msg->sms.msgdata = octstr_create("");
1294  msg->sms.udhdata = octstr_create_from_data(buffer, msglen8);
1295  } else {
1296  msg->sms.msgdata = octstr_create_from_data(buffer, msglen8);
1297  msg->sms.udhdata = octstr_create("");
1298  }
1299  msg->sms.coding = DC_7BIT;
1300  break;
1301  default: /* 0xf4, 0xf5, 0xf6, 0xf7; 8bit to disp, mem, sim or term */
1302  if (msg->sms.mclass & 0x02) { /* XXX mclass temporarily */
1303  msg->sms.msgdata = octstr_create("");
1304  msg->sms.udhdata = octstr_create_from_data(&raw[2], msglen8);
1305  } else {
1306  msg->sms.msgdata = octstr_create_from_data(&raw[2], msglen8);
1307  msg->sms.udhdata = octstr_create("");
1308  }
1309  msg->sms.coding = DC_8BIT;
1310  break;
1311  }
1312  msg->sms.mclass = MC_UNDEF;
1313 
1314  if (octstr_len(msg->sms.udhdata)) {
1315  IOTRACE("decoded udh", octstr_get_cstr(msg->sms.udhdata),
1316  octstr_len(msg->sms.udhdata));
1317  } else {
1318  IOTRACE("decoded", octstr_get_cstr(msg->sms.msgdata),
1319  octstr_len(msg->sms.msgdata));
1320  }
1321 
1322  return 2 + msglen8;
1323 }
1324 
1325 
1326 static int ois_ignore_time(const char *raw)
1327 {
1328  char str[15];
1329 
1330  SAY(3, "ois_ignore_time");
1331 
1332  strncpy(str, raw, 14); str[14] = '\0';
1333 
1334  return 14;
1335 }
1336 
1337 
1338 
1339 static int ois_deliver_sm_result(SMSCenter *smsc, int result, const char *str)
1340 {
1341  char body[BUFLEN+1];
1342  char buffer[BUFLEN+1];
1343  int ret;
1344 
1345  SAY(2, "ois_deliver_sm_result");
1346 
1347  /* construct a message */
1348 
1349  ois_encode_deliver_sm_result(body, result);
1350 
1351  /* first and only part */
1352 
1353  sprintf(buffer, "%c%c%.4s%.121s%c",
1354  'm', /* deliver sm result */
1355  (char)(0x50), /* ia5 encoding, the only part */
1356  &str[2],
1357  &body[0],
1358  EOL);
1359 
1360  IOTRACE("sending", buffer, strlen(buffer));
1361  ret = write_to_socket(smsc->socket, buffer);
1362  if (ret < 0) {
1363  goto error;
1364  }
1365 
1366  return 0;
1367 
1368  error:
1369  return -1;
1370 }
1371 
1372 
1373 static int ois_encode_deliver_sm_result(char *str, int result)
1374 {
1375  char raw[4];
1376 
1377  SAY(3, "ois_encode_deliver_sm_result");
1378 
1379  /* construct the deliver sm result body content */
1380 
1381  raw[0] = (char) result;
1382 
1383  return ois_convert_to_ia5(str, raw, 1);
1384 }
1385 
1386 
1387 static int ois_expand_gsm7(char *raw8, const char *raw7, int len)
1388 {
1389  int i;
1390  char bits[8*(BUFLEN+1)];
1391 
1392  SAY2(3, "ois_expand_gsm7 len=%d", len);
1393 
1394  /* yeah, there are also better algorithms, but... */
1395  /* well, at least this is fairly portable and ok for small messages... */
1396 
1397  ois_expand_gsm7_to_bits(bits, raw7, len);
1398  for (i = 0; i < len; ++i) {
1399  raw8[i] = ois_expand_gsm7_from_bits(bits, i);
1400  }
1401 
1402  SAY2(5, "ois_expand_gsm7 gave [%s]", ois_debug_str(raw8, i));
1403  return i;
1404 }
1405 
1406 static int ois_expand_gsm7_to_bits(char *bits, const char *raw7, int len)
1407 {
1408  int i, j, k;
1409  char ch;
1410 
1411  SAY(3, "ois_expand_gsm7_to_bits");
1412 
1413  len *= 7; /* number of bits in the gms 7-bit msg */
1414 
1415  for (j = i = 0; j < len; ++i) {
1416  ch = raw7[i];
1417  for (k = 0; k < 8; ++k) {
1418  bits[j++] = (char) (ch & 0x01);
1419  ch >>= 1;
1420  }
1421  }
1422 
1423  return j;
1424 }
1425 
1426 static char ois_expand_gsm7_from_bits(const char *bits, int pos)
1427 {
1428  int i;
1429  char ch;
1430 
1431  SAY2(8, "ois_expand_gsm7_from_bits pos=%d", pos);
1432 
1433  pos *= 7; /* septet position in bits */
1434  ch = '\0';
1435  for (i = 6; i >= 0; --i) {
1436  ch <<= 1;
1437  ch |= bits[pos+i];
1438  }
1439 
1440  return ch;
1441 }
1442 
1443 
1444 static int ois_convert_to_ia5(char *str, const char *raw, int len)
1445 {
1446  int j;
1447  int i;
1448  int ch;
1449 
1450  SAY2(3, "ois_convert_to_ia5 len=%d", len);
1451 
1452  for (j = i = 0; i < len; ++i) {
1453  ch = raw[i] & 0xff;
1454  if (ch == 0x5c || ch == 0x5e || ch == 0x60 || ch == 0x7e) {
1455  str[j++] = (char) 0x5c;
1456  str[j++] = (char) ch;
1457  } else if (0x20 <= ch && ch < 0x7f) {
1458  str[j++] = (char) ch;
1459  } else if (0x00 <= ch && ch < 0x20) {
1460  str[j++] = (char) 0x5e;
1461  str[j++] = (char) ch + 0x40;
1462  } else if (0xa0 <= ch && ch < 0xff) {
1463  str[j++] = (char) 0x60;
1464  str[j++] = (char) ch - 0x80;
1465  } else if (0x80 <= ch && ch < 0xa0) {
1466  str[j++] = (char) 0x7e;
1467  str[j++] = (char) ch - 0x40;
1468  } else if (ch == 0x7f) {
1469  str[j++] = (char) 0x5e;
1470  str[j++] = (char) 0x7e;
1471  } else { /* ch == 0xff */
1472  str[j++] = (char) 0x7e;
1473  str[j++] = (char) 0x7e;
1474  }
1475  }
1476 
1477  str[j] = '\0';
1478  SAY2(5, "ois_convert_to_ia5 gave [%s]", ois_debug_str(str, j));
1479  return j;
1480 }
1481 
1482 
1483 static int ois_convert_from_ia5(char *raw, const char *str)
1484 {
1485  int j;
1486  int i;
1487  int ch;
1488 
1489  SAY(3, "ois_convert_from_ia5");
1490 
1491  for (j = i = 0; ; ++i) {
1492  ch = str[i] & 0xff;
1493  if (ch < 0x20 || 0x7f <= ch) {
1494  break;
1495  } else if (ch == 0x5c) {
1496  ch = str[++i] & 0xff;
1497  if (ch == 0x5c || ch == 0x5e || ch == 0x60 || ch == 0x7e) {
1498  raw[j++] = (char) ch;
1499  } else {
1500  break;
1501  }
1502  } else if (ch == 0x5e) {
1503  ch = str[++i] & 0xff;
1504  if (0x40 <= ch && ch < 0x60) {
1505  raw[j++] = (char) ch - 0x40;
1506  } else if (ch == 0x7e) {
1507  raw[j++] = (char) 0x7f;
1508  } else {
1509  break;
1510  }
1511  } else if (ch == 0x60) {
1512  ch = str[++i] & 0xff;
1513  if (0x20 <= ch && ch < 0x7f) {
1514  raw[j++] = (char) ch + 0x80;
1515  } else {
1516  break;
1517  }
1518  } else if (ch == 0x7e) {
1519  ch = str[++i] & 0xff;
1520  if (0x40 <= ch && ch < 0x60) {
1521  raw[j++] = (char) ch + 0x40;
1522  } else if (ch == 0x7e) {
1523  raw[j++] = (char) 0xff;
1524  } else {
1525  break;
1526  }
1527  } else { /* 0x20 <= ch && ch < 0x7f */
1528  raw[j++] = (char) ch;
1529  }
1530  }
1531 
1532  SAY2(5, "ois_convert_from_ia5 gave [%s]", ois_debug_str(raw, j));
1533  return j;
1534 }
1535 
1536 
1537 static int ois_convert_to_iso88591(char *raw, int len)
1538 {
1539  /* a best effort 1-to-1 conversion according to ois appendix a */
1540 
1541  static const char gsm_to_iso88591[] = {
1542  '@', 0xa3,'$', 0xa5,0xe8,0xe9,0xf9,0xec, /* 0x00 - 0x07 */
1543  0xf2,0xc7,'\n',0xd8,0xf8,'\r',0xc5,0xe5, /* 0x08 - 0x0f */
1544  'D', ' ', 'F', 'G', 'L', 'W', 'P', 'Y', /* 0x10 - 0x17, poor! */
1545  'Y', 'S', 'X', ' ', 0xc6,0xe6,'b', 0xc9, /* 0x18 - 0x1f, poor! */
1546  ' ', '!', '"', '#', 0xa4, '%', '&', '\'',/* 0x20 - 0x27 */
1547  '(', ')', '*', '+', ',', '-', '.', '/', /* 0x28 - 0x2f */
1548  '0', '1', '2', '3', '4', '5', '6', '7', /* 0x30 - 0x37 */
1549  '8', '9', ':', ';', '<', '=', '>', '?', /* 0x38 - 0x3f */
1550  0xa1,'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 0x40 - 0x47 */
1551  'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 0x48 - 0x4f */
1552  'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 0x50 - 0x57 */
1553  'X', 'Y', 'Z', 0xc4,0xd6,0xd1,0xdc,0xa7, /* 0x58 - 0x5f */
1554  0xbf,'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 0x60 - 0x67 */
1555  'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 0x68 - 0x6f */
1556  'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 0x70 - 0x77 */
1557  'x', 'y', 'z', 0xe4,0xf6,0xf1,0xfc,0xe0 /* 0x78 - 0x7f */
1558  };
1559 
1560  int i;
1561 
1562  SAY2(3, "ois_convert_to_iso88591 len=%d", len);
1563 
1564  for (i = 0; i < len; ++i) {
1565  raw[i] = gsm_to_iso88591[raw[i] & 0x7f];
1566  }
1567 
1568  SAY2(5, "ois_convert_to_iso88591 gave [%s]", ois_debug_str(raw, i));
1569  return i;
1570 }
1571 
1572 
1573 /*
1574  * Extract a message from the internal buffer.
1575  */
1576 
1577 static int ois_extract_msg_from_buffer(char *str, SMSCenter *smsc)
1578 {
1579  int len;
1580  int count;
1581 
1582  SAY2(8, "ois_extract_msg_from_buffer buflen=%ld", (long)smsc->buflen);
1583 
1584  str[0] = '\0';
1585 
1586  if (smsc->buflen < 7) { /* 7 = 6 + 1 */
1587  return 0; /* we don't have a message yet */
1588  }
1589 
1590  if (strchr("SRDATECQLMPOVsrdatecqlmpov", smsc->buffer[0]) == NULL
1591  || (smsc->buffer[1] & 0xf0) != 0x50) {
1592 
1593  goto error;
1594  }
1595 
1596  /* a valid message type, find the end of the message */
1597 
1598  count = smsc->buffer[1] & 0x0f;
1599  for (len = 0; (size_t) len < smsc->buflen; ++len) {
1600  if (smsc->buffer[len] == EOL) {
1601  if (--count < 0) {
1602  ++len;
1603  break;
1604  }
1605  }
1606  }
1607 
1608  if (count >= 0) { /* we don't have all the pieces */
1609  if (len < BUFLEN) {
1610  return 0; /* ...but maybe later */
1611  }
1612  goto error;
1613  }
1614 
1615  /* the buffer contains a promising message candidate */
1616 
1617  memcpy(str, smsc->buffer, len);
1618  str[len] = '\0';
1619  smscenter_remove_from_buffer(smsc, len); /* just the message */
1620 
1621  return len;
1622 
1623  error:
1624  for (len = 0; (size_t) len < smsc->buflen && smsc->buffer[len] != EOL;
1625  ++len) ;
1626  if (len > BUFLEN) len = BUFLEN;
1627 
1628  memcpy(str, smsc->buffer, len);
1629  str[len] = '\0';
1630  smscenter_remove_from_buffer(smsc, smsc->buflen); /* everything */
1631 
1632  return -len;
1633 }
1634 
1635 
1636 
1637 /*
1638  * Extract a line from the internal buffer.
1639  */
1640 
1641 static int ois_extract_line_from_buffer(char *str, SMSCenter *smsc)
1642 {
1643  int len;
1644 
1645  SAY2(3, "ois_extract_line_from_buffer buflen=%ld", (long)smsc->buflen);
1646 
1647  str[0] = '\0';
1648 
1649  for (len = 0; (size_t) len < smsc->buflen && smsc->buffer[len] != '\n';
1650  ++len) ;
1651 
1652  if ((size_t) len >= smsc->buflen) {
1653  return 0;
1654  } else {
1655  ++len;
1656  }
1657 
1658  /* the buffer contains a line */
1659 
1660  memcpy(str, smsc->buffer, len);
1661  str[len] = '\0';
1662  smscenter_remove_from_buffer(smsc, len); /* just the line */
1663 
1664  return len;
1665 }
1666 
1667 
1668 static void ois_swap_buffering(SMSCenter *smsc)
1669 {
1670  time_t alive;
1671  int socket;
1672  char *buffer;
1673  size_t bufsize;
1674  size_t buflen;
1675 
1676  SAY(8, "ois_swap_buffering");
1677 
1678  if (smsc->ois_bufsize == 0) {
1679  smsc->ois_buflen = 0;
1680  smsc->ois_bufsize = smsc->bufsize;
1681  smsc->ois_buffer = gw_malloc(smsc->ois_bufsize);
1682  memset(smsc->ois_buffer, 0, smsc->ois_bufsize);
1683  }
1684 
1685  alive = smsc->ois_alive;
1686  smsc->ois_alive = smsc->ois_alive2;
1687  smsc->ois_alive2 = alive;
1688 
1689  socket = smsc->socket;
1690  smsc->socket = smsc->ois_socket;
1691  smsc->ois_socket = socket;
1692 
1693  buffer = smsc->buffer;
1694  smsc->buffer = smsc->ois_buffer;
1695  smsc->ois_buffer = buffer;
1696 
1697  buflen = smsc->buflen;
1698  smsc->buflen = smsc->ois_buflen;
1699  smsc->ois_buflen = buflen;
1700 
1701  bufsize = smsc->bufsize;
1702  smsc->bufsize = smsc->ois_bufsize;
1703  smsc->ois_bufsize = bufsize;
1704 
1705  return;
1706 }
1707 
1708 
1709 static const char *ois_debug_str(const char *raw, int len)
1710 {
1711  static const char hex[] = "0123456789abcdef";
1712  static char str[4*(BUFLEN+1)+1];
1713  int pos;
1714  int ch;
1715  int i;
1716 
1717  pos = 0;
1718  for (i = 0; i < len; ++i) {
1719  ch = raw[i] & 0xff;
1720  if (0x20 <= ch && ch < 0x7f && ch != 0x5c) {
1721  str[pos++] = (char) ch;
1722  } else {
1723  str[pos++] = '\\';
1724  str[pos++] = 'x';
1725  str[pos++] = hex[ch/16];
1726  str[pos++] = hex[ch%16];
1727  }
1728  }
1729  str[pos] = '\0';
1730  return str;
1731 }
int ois_pending_smsmessage(SMSCenter *smsc)
Definition: smsc_ois.c:318
struct ois_listentry ois_listentry
int ois_ack_debt
Definition: smsc_p.h:174
void error(int err, const char *fmt,...)
Definition: log.c:648
int ois_debug_level
Definition: smsc_ois.c:136
static int ois_ignore_smsc_reference_number(const char *raw)
Definition: smsc_ois.c:1203
static int ois_adjust_sm_text(Msg *msg, const char *raw)
Definition: smsc_ois.c:1262
int socket_set_blocking(int fd, int blocking)
Definition: socket.c:368
Definition: http.c:2014
static void ois_swap_buffering(SMSCenter *smsc)
Definition: smsc_ois.c:1668
static int ois_check_input(SMSCenter *smsc, long wait_usec)
Definition: smsc_ois.c:644
static int ois_adjust_additional_information(Msg *msg, const char *raw)
Definition: smsc_ois.c:1251
static int ois_open_sender(SMSCenter *smsc)
Definition: smsc_ois.c:475
static char ois_expand_gsm7_from_bits(const char *bits, int pos)
Definition: smsc_ois.c:1426
dcs_body_type
Definition: smsc_ois.c:128
struct ois_listentry * next
Definition: smsc_ois.c:156
int ois_receive_msg(SMSCenter *smsc, Msg **msg)
Definition: smsc_ois.c:396
size_t bufsize
Definition: smsc_p.h:185
Definition: msg.h:106
int ois_submit_msg(SMSCenter *smsc, const Msg *msg)
Definition: smsc_ois.c:346
int tcpip_connect_to_server(char *hostname, int port, const char *source_addr)
Definition: socket.c:149
#define OIS_FLAG_CLOSED
Definition: smsc_ois.c:164
static int ois_encode_deliver_sm_result(char *str, int result)
Definition: smsc_ois.c:1373
static int ois_append_data_coding_scheme(char *raw, const Msg *msg)
Definition: smsc_ois.c:944
static int ois_ignore_time(const char *raw)
Definition: smsc_ois.c:1326
size_t ois_bufsize
Definition: smsc_p.h:179
int ois_flags
Definition: smsc_p.h:175
static int ois_decode_submit_sm_result(int *code, const char *str)
Definition: smsc_ois.c:1043
static int ois_extract_line_from_buffer(char *str, SMSCenter *smsc)
Definition: smsc_ois.c:1641
int code
Definition: smsc_cimd2.c:346
static int ois_convert_to_ia5(char *str, const char *raw, int len)
Definition: smsc_ois.c:1444
void charset_utf8_to_gsm(Octstr *ostr)
Definition: charset.c:288
msg_type
Definition: msg.h:73
size_t buflen
Definition: smsc_p.h:186
int smscenter_read_into_buffer(SMSCenter *smsc)
Definition: smsc.c:348
static int ois_expand_gsm7_to_bits(char *bits, const char *raw7, int len)
Definition: smsc_ois.c:1406
static int ois_append_priority(char *raw)
Definition: smsc_ois.c:916
#define DC_8BIT
Definition: sms.h:111
static int ois_check_incoming(SMSCenter *smsc, long wait_usec)
Definition: smsc_ois.c:721
#define OIS_WAITTIME
Definition: smsc_ois.c:150
#define msg_create(type)
Definition: msg.h:136
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
#define SAY(d, s)
Definition: smsc_ois.c:141
void * ois_received_mo
Definition: smsc_p.h:173
static const char * ois_debug_str(const char *raw, int len)
Definition: smsc_ois.c:1709
int ois_reopen(SMSCenter *smsc)
Definition: smsc_ois.c:287
int receive_port
Definition: smsc_p.h:123
#define OIS_OPEN_WAITTIME
Definition: smsc_ois.c:148
#define EOL
Definition: smsc_ois.c:153
int write_to_socket(int socket, char *str)
Definition: socket.c:345
static int ois_decode_deliver_sm_invoke(Msg *msg, const char *str)
Definition: smsc_ois.c:1099
static int port
Definition: fakesmsc.c:121
#define OIS_FLAG_ERROR
Definition: smsc_ois.c:161
static int ois_submit_sm_result(SMSCenter *smsc, const char *buffer)
Definition: smsc_ois.c:1024
static int ois_convert_to_iso88591(char *raw, int len)
Definition: smsc_ois.c:1537
Definition: msg.h:79
static void ois_append_to_list(ois_listentry **head, Msg *msg)
Definition: smsc_ois.c:764
static int ois_append_originating_address(char *raw)
Definition: smsc_ois.c:924
int ois_close(SMSCenter *smsc)
Definition: smsc_ois.c:263
static int ois_convert_from_ia5(char *raw, const char *str)
Definition: smsc_ois.c:1483
#define SAY2(d, s, t)
Definition: smsc_ois.c:142
static int ois_ignore_protocol_id(const char *raw)
Definition: smsc_ois.c:1244
static int ois_encode_submit_sm_invoke(char *str, const Msg *msg)
Definition: smsc_ois.c:868
static int ois_append_validity_period(char *raw)
Definition: smsc_ois.c:935
int port
Definition: smsc_p.h:122
int ois_listening_socket
Definition: smsc_p.h:176
static int ois_append_sme_reference_number(char *raw)
Definition: smsc_ois.c:906
SMSCenter * ois_open(int receiveport, const char *hostname, int port, int debug_level)
Definition: smsc_ois.c:222
static int ois_extract_msg_from_buffer(char *str, SMSCenter *smsc)
Definition: smsc_ois.c:1577
void smscenter_remove_from_buffer(SMSCenter *smsc, size_t n)
Definition: smsc.c:412
static int ois_deliver_sm_invoke(SMSCenter *smsc, const char *buffer)
Definition: smsc_ois.c:1073
static int ois_append_sm_text(char *raw, const Msg *msg)
Definition: smsc_ois.c:988
static void ois_disconnect(SMSCenter *smsc)
Definition: smsc_ois.c:595
Octstr * gw_netaddr_to_octstr(int af, void *src)
Definition: socket.c:677
void msg_destroy(Msg *msg)
Definition: msg.c:132
SMSCenter * smscenter_construct(void)
Definition: smsc.c:101
static int ois_append_msisdn(char *raw, const Msg *msg)
Definition: smsc_ois.c:894
int make_server_socket(int port, const char *interface_name)
Definition: socket.c:93
void warning(int err, const char *fmt,...)
Definition: log.c:660
void smscenter_destruct(SMSCenter *smsc)
Definition: smsc.c:168
Octstr * hostname
Definition: fakewap.c:232
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:324
static int ois_read_into_buffer(SMSCenter *smsc, long wait_usec)
Definition: smsc_ois.c:609
#define octstr_create(cstr)
Definition: octstr.h:125
#define MAXCOUNTER
Definition: smsc_ois.c:152
static int ois_open_listener(SMSCenter *smsc)
Definition: smsc_ois.c:448
#define OIS_FLAG_DEBUG
Definition: smsc_ois.c:160
static int ois_int_to_i4(char *raw, int nbr)
Definition: smsc_ois.c:786
static int ois_check_deliver_sm_invoke(const char *str)
Definition: smsc_ois.c:1153
int socket
Definition: smsc_p.h:115
static void ois_disconnect_all(SMSCenter *smsc)
Definition: smsc_ois.c:574
static int ois_increment_counter(void)
Definition: smsc_ois.c:799
long octstr_len(const Octstr *ostr)
Definition: octstr.c:342
size_t ois_buflen
Definition: smsc_p.h:180
#define BUFLEN
Definition: smsc_ois.c:147
#define OIS_NOWAIT
Definition: smsc_ois.c:151
#define MC_UNDEF
Definition: sms.h:93
Definition: octstr.c:118
char * ois_buffer
Definition: smsc_p.h:178
int read_available(int fd, long wait_usec)
Definition: socket.c:406
time_t ois_alive2
Definition: smsc_p.h:172
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:726
static int ois_adjust_destination_address(Msg *msg, const char *raw)
Definition: smsc_ois.c:1191
static int ois_submit_sm_invoke(SMSCenter *smsc, const Msg *msg)
Definition: smsc_ois.c:808
int type
Definition: smsc_p.h:93
void ois_delete_queue(SMSCenter *smsc)
Definition: smsc_ois.c:423
char * buffer
Definition: smsc_p.h:184
static int ois_append_protocol_id(char *raw)
Definition: smsc_ois.c:964
int socklen_t
Definition: socket.h:73
static int ois_append_status_report_request(char *raw)
Definition: smsc_ois.c:956
static int ois_append_submission_options(char *raw, const Msg *msg)
Definition: smsc_ois.c:972
static int ois_deliver_sm_result(SMSCenter *smsc, int result, const char *str)
Definition: smsc_ois.c:1339
#define DC_UNDEF
Definition: sms.h:109
static int ois_adjust_data_coding_scheme(Msg *msg, const char *raw)
Definition: smsc_ois.c:1232
static int ois_open_receiver(SMSCenter *smsc)
Definition: smsc_ois.c:539
static int ois_counter
Definition: smsc_ois.c:166
#define IOTRACE(x, s, l)
Definition: smsc_ois.c:144
char name[1024]
Definition: smsc_p.h:96
#define OIS_MESSAGE_WAITTIME
Definition: smsc_ois.c:149
#define OIS_FLAG_NOBANNER
Definition: smsc_ois.c:162
static int ois_adjust_originating_address(Msg *msg, const char *raw)
Definition: smsc_ois.c:1220
char * hostname
Definition: smsc_p.h:121
static int ois_expand_gsm7(char *raw8, const char *raw7, int len)
Definition: smsc_ois.c:1387
#define octstr_create_from_data(data, len)
Definition: octstr.h:134
int ois_socket
Definition: smsc_p.h:177
static XMLRPCDocument * msg
Definition: test_xmlrpc.c:86
time_t ois_alive
Definition: smsc_p.h:171
#define DC_7BIT
Definition: sms.h:110
#define OIS_FLAG_MULTIPLE_CALL
Definition: smsc_ois.c:163
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.