1 /* ====================================================================
2 * The Kannel Software License, Version 1.0
3 *
4 * Copyright (c) 2001-2014 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 */
128 enum dcs_body_type {
129 DCS_GSM_TEXT = 0,
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 {
156 struct ois_listentry *next;
157 Msg *msg;
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
ois_open(int receiveport,const char * hostname,int port,int debug_level)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
ois_close(SMSCenter * smsc)263 int ois_close(SMSCenter *smsc)
264 {
265 ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
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);
273 smscenter_remove_from_buffer(smsc, smsc->buflen);
274 ois_swap_buffering(smsc);
275 smscenter_remove_from_buffer(smsc, smsc->buflen);
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
ois_reopen(SMSCenter * smsc)287 int ois_reopen(SMSCenter *smsc)
288 {
289 int ret;
290
291 ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
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
ois_pending_smsmessage(SMSCenter * smsc)318 int ois_pending_smsmessage(SMSCenter *smsc)
319 {
320 int ret;
321
322 ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
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
ois_submit_msg(SMSCenter * smsc,const Msg * msg)346 int ois_submit_msg(SMSCenter *smsc, const Msg *msg)
347 {
348 int ret;
349
350 ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
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
ois_receive_msg(SMSCenter * smsc,Msg ** msg)396 int ois_receive_msg(SMSCenter *smsc, Msg **msg)
397 {
398 ois_listentry *item;
399
400 ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
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
ois_delete_queue(SMSCenter * smsc)423 void ois_delete_queue(SMSCenter *smsc)
424 {
425 Msg *msg;
426
427 ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
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
ois_open_listener(SMSCenter * smsc)448 static int ois_open_listener(SMSCenter *smsc)
449 {
450 SAY(2, "ois_open_listener");
451
452 smsc->ois_listening_socket = make_server_socket(smsc->receive_port,
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
ois_open_sender(SMSCenter * smsc)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
ois_open_receiver(SMSCenter * smsc)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
ois_disconnect_all(SMSCenter * smsc)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
ois_disconnect(SMSCenter * smsc)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
ois_read_into_buffer(SMSCenter * smsc,long wait_usec)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
ois_check_input(SMSCenter * smsc,long wait_usec)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
ois_check_incoming(SMSCenter * smsc,long wait_usec)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");
754 smsc->ois_flags |= OIS_FLAG_MULTIPLE_CALL;
755 }
756 return 0;
757 }
758
759 smsc->ois_flags &= ~OIS_FLAG_MULTIPLE_CALL;
760 return ois_open_receiver(smsc);
761 }
762
763
ois_append_to_list(ois_listentry ** head,Msg * msg)764 static void ois_append_to_list(ois_listentry **head, Msg *msg)
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
ois_int_to_i4(char * raw,int nbr)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
ois_increment_counter(void)799 static int ois_increment_counter(void)
800 {
801 SAY(3, "ois_increment_counter");
802
803 ois_counter = (ois_counter+1) % MAXCOUNTER;
804 return ois_counter;
805 }
806
807
ois_submit_sm_invoke(SMSCenter * smsc,const Msg * msg)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
ois_encode_submit_sm_invoke(char * str,const Msg * msg)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
ois_append_msisdn(char * raw,const Msg * msg)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
ois_append_sme_reference_number(char * raw)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
ois_append_priority(char * raw)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
ois_append_originating_address(char * raw)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
ois_append_validity_period(char * raw)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
ois_append_data_coding_scheme(char * raw,const Msg * msg)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
ois_append_status_report_request(char * raw)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
ois_append_protocol_id(char * raw)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
ois_append_submission_options(char * raw,const Msg * msg)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
ois_append_sm_text(char * raw,const Msg * msg)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
ois_submit_sm_result(SMSCenter * smsc,const char * buffer)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
ois_decode_submit_sm_result(int * code,const char * str)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
ois_deliver_sm_invoke(SMSCenter * smsc,const char * buffer)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;
1089 ois_append_to_list(mo, msg);
1090
1091 return 0;
1092
1093 error:
1094 msg_destroy(msg);
1095 return -1;
1096 }
1097
1098
ois_decode_deliver_sm_invoke(Msg * msg,const char * str)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
ois_check_deliver_sm_invoke(const char * str)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
ois_adjust_destination_address(Msg * msg,const char * raw)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
ois_ignore_smsc_reference_number(const char * raw)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
ois_adjust_originating_address(Msg * msg,const char * raw)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
ois_adjust_data_coding_scheme(Msg * msg,const char * raw)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
ois_ignore_protocol_id(const char * raw)1244 static int ois_ignore_protocol_id(const char *raw)
1245 {
1246 SAY(3, "ois_ignore_protocol_id");
1247
1248 return 1;
1249 }
1250
ois_adjust_additional_information(Msg * msg,const char * raw)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
ois_adjust_sm_text(Msg * msg,const char * raw)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
ois_ignore_time(const char * raw)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
ois_deliver_sm_result(SMSCenter * smsc,int result,const char * str)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
ois_encode_deliver_sm_result(char * str,int result)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
ois_expand_gsm7(char * raw8,const char * raw7,int len)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
ois_expand_gsm7_to_bits(char * bits,const char * raw7,int len)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
ois_expand_gsm7_from_bits(const char * bits,int pos)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
ois_convert_to_ia5(char * str,const char * raw,int len)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
ois_convert_from_ia5(char * raw,const char * str)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
ois_convert_to_iso88591(char * raw,int len)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
ois_extract_msg_from_buffer(char * str,SMSCenter * smsc)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
ois_extract_line_from_buffer(char * str,SMSCenter * smsc)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
ois_swap_buffering(SMSCenter * smsc)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
ois_debug_str(const char * raw,int len)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 }
1732