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