Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

smsc_ois.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*****************************************************************************
00058  * smsc_ois.c - Sema Group SMS2000 (G6.0) Center (OIS 5.0).
00059  * Jouko Koski (EDS) for WapIT Ltd.
00060  *
00061  * The SMS2000 has a general X.25 access gateway for accessing the SMSC,
00062  * as described in the Open Interface Specification 5.0 document.
00063  * A protocol translator - like the Cisco 2501 router - hides all the
00064  * X.25 trickery from us. We just connect to a preconfigured router
00065  * address/port, and the translator forwards the connection to the SMS2000.
00066  * Correspondingly, if the SMSC has something to say, it looks like
00067  * the router were contacting our port. The router should be configured so,
00068  * that it has a pre-defined address and tcp port in X.25 automode establishing
00069  * a X.25 link and a similar configuration in X.25 side connecting to a pre-
00070  * defined address and port, it shall not encapsulate everything in Telnet
00071  * (set the stream mode), and it should suppress banner messages like "Trying
00072  * 9876...Open" (set the quiet mode).
00073  *
00074  * Whenever possible, I've tried to steal ideas and code from other smsc_*
00075  * files, particularly from Hao Shi's (EDS) original implementation for a
00076  * serial-line-connected PAD. However, the code is highly evolutionary,
00077  * because during the implementation new technical details kept popping
00078  * up all the time (initially, PAD commands were supposed to be used,
00079  * but the router was configured to "automode", so they weren't necessary;
00080  * instead the router gave banner messages and wanted some telnet negotiations;
00081  * the router insisted echoing everything and delayed <nul>s after <cr>s;
00082  * telnet transmit-binary mode solved that; then the stream mode (no telnet
00083  * encapsulation) was discovered; suddenly the banners were turned off also;
00084  * but still the smsc didn't deliver mo messages, because it wanted to
00085  * connect instead of using our existing connection; then we began to use
00086  * short connection sessions for transmitting instead of a single ever-
00087  * lasting connection, and also started to specifically listen for smsc
00088  * initiated connections, which yielded two separate input buffers; then
00089  * suddenly the banners were there again, so some intelligence had to be
00090  * added to adapt their (non-)existence; then revealed the spec version 4.5
00091  * had been obsolete all the time and we got 5.0; the router apparently
00092  * caused some extra packets on the x.25 side and everybody was blaming the
00093  * application; then the connection maintenance and buffering was again
00094  * revisited to achieve better performance and reliability... Really an
00095  * interesting story but think if it were about you instead of me :-)
00096  *
00097  * Really funny thing is that according to the spec the SMS2000 does have
00098  * a direct TCP/IP access interface. However, here we have the general X.25
00099  * access interface, since we started with the old spec and probably the
00100  * simpler TCP/IP access is not available in our particular customer's
00101  * installation, not at least when this was written. In the direct access
00102  * only single ever-lasting connection is necessary, and the messages are
00103  * the same but their format is different. Encoding tricks are the same.
00104  * So, if you are implementing that access mode some day, there are probably
00105  * differences between this access mode and yours on so many levels, that
00106  * simple if () selections won't work; write your own code from (nearly)
00107  * scratch and take appropriate encoding conversion functions here. Or do
00108  * just whatever you want, what should I care :-).
00109  */
00110 
00111 #include <unistd.h>
00112 #include <ctype.h>
00113 #include <errno.h>
00114 #include <string.h>
00115 #include <sys/time.h>
00116 #include <sys/types.h>
00117 #include <sys/timeb.h>
00118 #include <sys/socket.h>
00119 #include <netinet/in.h>
00120 #include <arpa/inet.h>
00121 
00122 #include "smsc.h"
00123 #include "smsc_p.h"
00124 #include "gwlib/gwlib.h"
00125 #include "sms.h"
00126 
00127 /* XXX Delete me and replace dcs with dcs_to_fields */
00128 enum dcs_body_type {
00129     DCS_GSM_TEXT = 0,
00130     DCS_OCTET_DATA = 4    /* flag_8bit */
00131 };
00132 
00133 
00134 /* 'private:' */
00135 
00136 int ois_debug_level = 0; /* some extra verbosity in debug logging */
00137 /* 0=just normal debugging, 1=input/output messages, 2=function entries, */
00138 /* 3=message assembly/disassembly, 4=disconnection tracing, */
00139 /* 5=message conversions, and 8=message polling (=too much) */
00140 
00141 #define SAY(d,s) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s); }
00142 #define SAY2(d,s,t) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s,t); }
00143 #define SAY3(d,s,t,u) { if (d<=ois_debug_level) debug("bb.sms.ois",0,s,t,u); }
00144 #define IOTRACE(x,s,l) SAY3(1,"%s [%s]",x,ois_debug_str(s,l))
00145 
00146 
00147 #define BUFLEN (511) /* sure enough for ois messages */
00148 #define OIS_OPEN_WAITTIME (15) /* seconds, waiting for banners */
00149 #define OIS_MESSAGE_WAITTIME (30) /* seconds, until closing idle connection */
00150 #define OIS_WAITTIME (999999) /* microseconds, waiting for banners at a time */
00151 #define OIS_NOWAIT (0) /* microseconds, not waiting */
00152 #define MAXCOUNTER (10000) /* ois message id */
00153 #define EOL ('\r') /* ois definition for the eol */
00154 
00155 typedef struct ois_listentry {
00156     struct ois_listentry *next;
00157     Msg *msg;
00158 } ois_listentry;
00159 
00160 #define OIS_FLAG_DEBUG (0x000f)
00161 #define OIS_FLAG_ERROR (0x0100)
00162 #define OIS_FLAG_NOBANNER (0x0200)
00163 #define OIS_FLAG_MULTIPLE_CALL (0x0400)
00164 #define OIS_FLAG_CLOSED (0x0800)
00165 
00166 static int ois_counter = 0; /* [0..MAXCOUNTER), ois "unique" message id */
00167 static int ois_open_listener(SMSCenter *smsc);
00168 static int ois_open_sender(SMSCenter *smsc);
00169 static int ois_open_receiver(SMSCenter *smsc);
00170 static void ois_disconnect_all(SMSCenter *smsc);
00171 static void ois_disconnect(SMSCenter *smsc);
00172 static int ois_read_into_buffer(SMSCenter *smsc, long wait_usec);
00173 static int ois_check_input(SMSCenter *smsc, long wait_usec);
00174 static int ois_check_incoming(SMSCenter *smsc, long wait_usec);
00175 static void ois_append_to_list(ois_listentry **head, Msg *msg);
00176 static int ois_int_to_i4(char *raw, int nbr);
00177 static int ois_increment_counter(void);
00178 static int ois_submit_sm_invoke(SMSCenter *smsc, const Msg *msg);
00179 static int ois_encode_submit_sm_invoke(char *str, const Msg *msg);
00180 static int ois_append_msisdn(char *raw, const Msg *msg);
00181 static int ois_append_sme_reference_number(char *raw);
00182 static int ois_append_priority(char *raw);
00183 static int ois_append_originating_address(char *raw);
00184 static int ois_append_validity_period(char *raw);
00185 static int ois_append_data_coding_scheme(char *raw, const Msg *msg);
00186 static int ois_append_status_report_request(char *raw);
00187 static int ois_append_protocol_id(char *raw);
00188 static int ois_append_submission_options(char *raw, const Msg *msg);
00189 static int ois_append_sm_text(char *raw, const Msg *msg);
00190 static int ois_submit_sm_result(SMSCenter *smsc, const char *buffer);
00191 static int ois_decode_submit_sm_result(int *code, const char *str);
00192 static int ois_deliver_sm_invoke(SMSCenter *smsc, const char *buffer);
00193 static int ois_decode_deliver_sm_invoke(Msg *msg, const char *str);
00194 static int ois_check_deliver_sm_invoke(const char *str);
00195 static int ois_adjust_destination_address(Msg *msg, const char *raw);
00196 static int ois_ignore_smsc_reference_number(const char *raw);
00197 static int ois_adjust_originating_address(Msg *msg, const char *raw);
00198 static int ois_adjust_data_coding_scheme(Msg *msg, const char *raw);
00199 static int ois_ignore_protocol_id(const char *raw);
00200 static int ois_adjust_additional_information(Msg *msg, const char *raw);
00201 static int ois_adjust_sm_text(Msg *msg, const char *raw);
00202 static int ois_ignore_time(const char *raw);
00203 static int ois_deliver_sm_result(SMSCenter *smsc, int result, const char *str);
00204 static int ois_encode_deliver_sm_result(char *str, int result);
00205 static int ois_expand_gsm7(char *raw8, const char *raw7, int len);
00206 static int ois_expand_gsm7_to_bits(char *bits, const char *raw7, int len);
00207 static char ois_expand_gsm7_from_bits(const char *bits, int pos);
00208 static int ois_convert_to_ia5(char *str, const char *raw, int len);
00209 static int ois_convert_from_ia5(char *raw, const char *str);
00210 static int ois_convert_to_iso88591(char *raw, int len);
00211 static int ois_extract_msg_from_buffer(char *str, SMSCenter *smsc);
00212 static int ois_extract_line_from_buffer(char *str, SMSCenter *smsc);
00213 static void ois_swap_buffering(SMSCenter *smsc);
00214 static const char *ois_debug_str(const char *raw, int len);
00215 
00216 /* 'public:' */
00217 
00218 /*
00219  * Establish a connection to the SMSC.
00220  */
00221 
00222 SMSCenter *ois_open(int receiveport, const char *hostname, int port, int debug_level)
00223 {
00224     SMSCenter *smsc;
00225     int ret;
00226 
00227     ois_debug_level = debug_level & OIS_FLAG_DEBUG;
00228     SAY(2, "ois_open");
00229 
00230     /* create a SMSCenter structure */
00231 
00232     smsc = smscenter_construct();
00233     if (smsc == NULL) {
00234     goto error;
00235     }
00236 
00237     smsc->type = SMSC_TYPE_OIS;
00238     smsc->receive_port = receiveport;
00239     smsc->hostname = gw_strdup(hostname);
00240     smsc->port = port;
00241     smsc->ois_flags = ois_debug_level;
00242 
00243     ret = ois_open_listener(smsc);
00244     if (ret < 0) {
00245     goto error;
00246     }
00247     sprintf(smsc->name, "OIS:TCP/X.25-Translator:localhost:%d:TCP:%.512s:%d",
00248         smsc->receive_port, smsc->hostname, smsc->port);
00249 
00250     return smsc;
00251 
00252  error:
00253     error(0, "ois_open: could not open");
00254     smscenter_destruct(smsc);
00255     return NULL;
00256 }
00257 
00258 
00259 /*
00260  * Terminate the SMSC connection.
00261  */
00262 
00263 int ois_close(SMSCenter *smsc)
00264 {
00265     ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
00266     SAY(2, "ois_close");
00267 
00268     if (smsc->type != SMSC_TYPE_OIS) {
00269     warning(0, "ois_close: closing a not-ois connection...");
00270     }
00271 
00272     ois_swap_buffering(smsc);
00273     smscenter_remove_from_buffer(smsc, smsc->buflen);
00274     ois_swap_buffering(smsc);
00275     smscenter_remove_from_buffer(smsc, smsc->buflen);
00276     SAY(4, "ois_close: ois_disconnect_all");
00277     ois_disconnect_all(smsc);
00278 
00279     return 0;
00280 }
00281 
00282 
00283 /*
00284  * Re-establish a SMSC connection.
00285  */
00286 
00287 int ois_reopen(SMSCenter *smsc)
00288 {
00289     int ret;
00290 
00291     ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
00292     SAY(2, "ois_reopen");
00293 
00294     ois_close(smsc);
00295 
00296     if (smsc->type == SMSC_TYPE_OIS) {
00297     ret = ois_open_listener(smsc);
00298     if (ret < 0) {
00299         goto error;
00300     }
00301     } else {
00302     error(0, "ois_reopen: wrong smsc type");
00303     goto error;
00304     }
00305     return 0;
00306 
00307  error:
00308     error(0, "ois_reopen: could not open");
00309     return -1;
00310 }
00311 
00312 
00313 /*
00314  * Check for MO messages.
00315  * Put all incoming MO messages into an internal queue.
00316  */
00317 
00318 int ois_pending_smsmessage(SMSCenter *smsc)
00319 {
00320     int ret;
00321 
00322     ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
00323     SAY(8, "ois_pending_smsmessage");
00324 
00325     ret = ois_check_incoming(smsc, OIS_NOWAIT);
00326     if (ret == 0 && smsc->socket != -1) {
00327     ret = ois_check_input(smsc, OIS_NOWAIT);
00328     }
00329     if (ret == 0 && smsc->ois_socket != -1) {
00330     ois_swap_buffering(smsc);
00331     ret = ois_check_input(smsc, OIS_NOWAIT);
00332     ois_swap_buffering(smsc);
00333     if (smsc->ois_socket == -1 && smsc->ois_ack_debt != 0) {
00334         warning(0, "ois_pending_smsmessage: missing %d ack(s)...",
00335             smsc->ois_ack_debt);
00336     }
00337     }
00338     return ret;
00339 }
00340 
00341 
00342 /*
00343  * Send a MT message.
00344  */
00345 
00346 int ois_submit_msg(SMSCenter *smsc, const Msg *msg)
00347 {
00348     int ret;
00349 
00350     ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
00351     SAY(2, "ois_submit_msg");
00352     ois_swap_buffering(smsc);
00353 
00354     if (msg_type((Msg *)msg) != sms) {
00355     error(0, "ois_submit_msg: can not handle message types other than smart_msg");
00356     goto error;
00357     }
00358 
00359     if (smsc->socket == -1) {
00360     ret = ois_open_sender(smsc);
00361     if (ret < 0) {
00362         goto error;
00363     }
00364     }
00365 
00366     ret = ois_submit_sm_invoke(smsc, msg);
00367     if (ret < 0) {
00368     goto error_close;
00369     }
00370 
00371     ++smsc->ois_ack_debt;
00372     time(&smsc->ois_alive);
00373     ret = 0;
00374     goto out;
00375 
00376  error_close:
00377     if (smsc->ois_ack_debt != 0) {
00378     warning(0, "ois_submit_msg: missing %d ack(s)...",
00379         smsc->ois_ack_debt);
00380     }
00381     SAY(4, "ois_submit_msg: ois_disconnect in error_close");
00382     ois_disconnect(smsc);
00383  error:
00384     SAY(2, "ois_submit_msg error");
00385     ret = -1;
00386  out:
00387     ois_swap_buffering(smsc);
00388     return ret;
00389 }
00390 
00391 
00392 /*
00393  * Receive a MO message (from the internal queue).
00394  */
00395 
00396 int ois_receive_msg(SMSCenter *smsc, Msg **msg)
00397 {
00398     ois_listentry *item;
00399 
00400     ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
00401     SAY(2, "ois_receive_msg");
00402 
00403     item = smsc->ois_received_mo;
00404     if (item == NULL) { /* no mo messages */
00405     if ((smsc->ois_flags & OIS_FLAG_ERROR) == 0) {
00406         return 0;   /* should actually not happen */
00407     } else {
00408         return -1;  /* error pending, reopen? */
00409     }
00410     } else {            /* we have a message waiting */
00411     smsc->ois_received_mo = item->next;
00412     *msg = item->msg;
00413     gw_free(item);
00414     return 1;       /* got the message */
00415     }
00416 }
00417 
00418 
00419 /*
00420  * Destruct the internal queue.
00421  */
00422 
00423 void ois_delete_queue(SMSCenter *smsc)
00424 {
00425     Msg *msg;
00426 
00427     ois_debug_level = smsc->ois_flags & OIS_FLAG_DEBUG;
00428     SAY(2, "ois_delete_queue");
00429 
00430     while (ois_receive_msg(smsc, &msg) > 0) {
00431     gw_free(msg);
00432     }
00433     return;
00434 }
00435 
00436 
00437 
00438 
00439 
00440 
00441 
00442 
00443 /*
00444  * Implementation of 'private:'
00445  */
00446 
00447 
00448 static int ois_open_listener(SMSCenter *smsc)
00449 {
00450     SAY(2, "ois_open_listener");
00451 
00452     smsc->ois_listening_socket = make_server_socket(smsc->receive_port, 
00453             NULL);
00454     /* XXX add interface_name if required */
00455     if (smsc->ois_listening_socket < 0) {
00456     goto error;
00457     }
00458     if (socket_set_blocking(smsc->ois_listening_socket, 0) < 0) {
00459     ois_close(smsc);
00460     goto error;
00461     }
00462     smsc->ois_flags &= ~OIS_FLAG_ERROR;
00463     smsc->ois_flags &= ~OIS_FLAG_NOBANNER;
00464     smsc->ois_alive2 = time(&smsc->ois_alive);
00465 
00466     SAY2(2, "ois_open_listener fd=%d", smsc->ois_listening_socket);
00467     return 0;
00468 
00469  error:
00470     error(0, "ois_open_listener: failed to open listening socket");
00471     return -1;
00472 }
00473 
00474 
00475 static int ois_open_sender(SMSCenter *smsc)
00476 {
00477     int ret;
00478     char buffer[BUFLEN+1];
00479     time_t now;
00480     time_t beginning;
00481     
00482     SAY(2, "ois_open_sender");
00483     debug("bb.sms.ois", 0, "connecting to host %s port %d",
00484       smsc->hostname, smsc->port);
00485 
00486     time(&beginning);
00487     smsc->socket = tcpip_connect_to_server(smsc->hostname, smsc->port,
00488             NULL);
00489     /* XXX add interface_name if required */
00490     if (smsc->socket < 0) {
00491     return -1;
00492     } else {
00493     smsc->buflen = 0;
00494     time(&smsc->ois_alive);
00495     smsc->ois_ack_debt = 0;
00496     }
00497 
00498     SAY2(2, "ois_open_sender fd=%d", smsc->socket);
00499     if (smsc->ois_flags & OIS_FLAG_NOBANNER) {
00500     return 0;
00501     }
00502 
00503     buffer[0] = '\0';
00504     for (time(&now); (now - beginning) < OIS_OPEN_WAITTIME; time(&now)) {
00505     ret = ois_read_into_buffer(smsc, OIS_WAITTIME);
00506     if (ret < 0) {
00507         goto error;
00508     }
00509 
00510     if (smsc->buflen == 0) {
00511         /* assume that the router is in the quiet mode */
00512         /* there will be no banners */
00513         smsc->ois_flags |= OIS_FLAG_NOBANNER;
00514         debug("bb.sms.ois", 0, "assuming that %s:%d is in the quiet mode",
00515           smsc->hostname, smsc->port);
00516         return 0;
00517     }
00518     ret = ois_extract_line_from_buffer(buffer, smsc);
00519     if (ret > 0) {
00520         if (strncmp(buffer, "Trying", 6) == 0 &&
00521         strstr(buffer, "...Open\r\n") != NULL) {
00522         time(&smsc->ois_alive);
00523         return 0;
00524         } else {
00525         break;
00526         }
00527     }
00528     }
00529 
00530  error:
00531     SAY(4, "ois_open_sender: ois_disconnect in error");
00532     ois_disconnect(smsc);
00533     error(0, "ois_open_sender: failed to connect [%s%s]",
00534       buffer, ois_debug_str(smsc->buffer, smsc->buflen));
00535     return -1;
00536 }
00537 
00538 
00539 static int ois_open_receiver(SMSCenter *smsc)
00540 {
00541     struct sockaddr_in addr;
00542     int addrlen;
00543     Octstr *os;
00544 
00545     SAY(2, "ois_open_receiver");
00546 
00547     /* the listening socket should be non-blocking... */
00548 
00549     addrlen = sizeof(addr);
00550     smsc->socket = accept(smsc->ois_listening_socket,
00551               (struct sockaddr *)&addr, (socklen_t *)&addrlen);
00552     if (smsc->socket == -1) {
00553     if (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
00554         /* || errno == ECONNABORTED || errno == EPROTO) -Kalle 6.7 */
00555     {
00556         return 0;
00557     } else {
00558         error(errno, "ois_open_receiver: accept failed");
00559         smsc->ois_flags |= OIS_FLAG_ERROR;
00560         return -1;
00561     }
00562     }
00563 
00564     SAY2(2, "ois_open_receiver fd=%d", smsc->socket);
00565     os = gw_netaddr_to_octstr(AF_INET, &addr.sin_addr);
00566     debug("bb.sms.ois", 0, "connection from host %s port %hu",
00567       octstr_get_cstr(os), ntohs(addr.sin_port));
00568     octstr_destroy(os);
00569     time(&smsc->ois_alive);
00570     return 0;
00571 }
00572 
00573 
00574 static void ois_disconnect_all(SMSCenter *smsc)
00575 {
00576     SAY2(2, "ois_disconnect_all fd=%d", smsc->ois_listening_socket);
00577 
00578     ois_swap_buffering(smsc);
00579     SAY(4, "ois_disconnect_all: ois_disconnect");
00580     ois_disconnect(smsc); /* smsc->socket */
00581     ois_swap_buffering(smsc);
00582     SAY(4, "ois_disconnect_all: ois_disconnect");
00583     ois_disconnect(smsc); /* smsc->socket */
00584 
00585     if (smsc->ois_listening_socket != -1) {
00586     if (close(smsc->ois_listening_socket) == -1) {
00587         warning(errno, "ois_disconnect_all: close failed...");
00588     }
00589     smsc->ois_listening_socket = -1;
00590     }
00591     return;
00592 }
00593 
00594 
00595 static void ois_disconnect(SMSCenter *smsc)
00596 {
00597     SAY2(2, "ois_disconnect fd=%d", smsc->socket);
00598 
00599     if (smsc->socket != -1) {
00600     if (close(smsc->socket) == -1) {
00601         warning(errno, "ois_disconnect: close failed...");
00602     }
00603     smsc->socket = -1;
00604     }
00605     return;
00606 }
00607 
00608 
00609 static int ois_read_into_buffer(SMSCenter *smsc, long wait_usec)
00610 {
00611     int ret;
00612 
00613     SAY(8, "ois_read_into_buffer");
00614 
00615     if (smsc->socket == -1) {
00616     if ((smsc->ois_flags & OIS_FLAG_CLOSED) == 0) {
00617         debug("bb.sms.ois", 0, "attempting to read from a closed socket");
00618         smsc->ois_flags |= OIS_FLAG_CLOSED;
00619     }
00620     return 0;
00621     } else {
00622     smsc->ois_flags &= ~OIS_FLAG_CLOSED;
00623     }
00624 
00625     ret = read_available(smsc->socket, wait_usec);
00626     if (ret > 0) {
00627     time(&smsc->ois_alive);
00628     ret = smscenter_read_into_buffer(smsc);
00629     if (ret > 0 || (ret == 0 && smsc->buflen > 0)) {
00630         SAY(2, "ois_read_into_buffer got something");
00631     } else if (ret == 0) {
00632         if (smsc->buflen > 0) {
00633         SAY(2, "ois_read_into_buffer has something");
00634         ret = 1;
00635         }
00636         SAY(4, "ois_read_into_buffer: ois_disconnect");
00637         ois_disconnect(smsc);
00638     }
00639     }
00640     return ret;
00641 }
00642 
00643 
00644 static int ois_check_input(SMSCenter *smsc, long wait_usec)
00645 {
00646     char buffer[BUFLEN+1];
00647     time_t now;
00648     int ret;
00649 
00650     SAY(8, "ois_check_input");
00651 
00652     ret = ois_read_into_buffer(smsc, wait_usec);
00653     if (ret < 0) {
00654     goto error;
00655     }
00656 
00657     ret = ois_extract_msg_from_buffer(buffer, smsc);
00658     if (ret > 0) {
00659     IOTRACE("received", buffer, ret);
00660     switch (buffer[0]) {
00661     case 's':
00662         ret = ois_submit_sm_result(smsc, buffer);
00663         if (ret > 0) {
00664         warning(0, "ois_check_input: submit sm result signals (%d)...", ret);
00665         } else if (ret < 0) {
00666         error(0, "ois_check_input: invalid submit sm result");
00667         goto error;
00668         }
00669         --smsc->ois_ack_debt;
00670         time(&smsc->ois_alive);
00671         break;
00672     case 'M':
00673         ret = ois_deliver_sm_invoke(smsc, buffer);
00674         if (ret >= 0) {
00675         ret = ois_deliver_sm_result(smsc, ret, buffer);
00676         if (ret < 0) {
00677             goto error;
00678         }
00679         } else {
00680         error(0, "ois_check_input: invalid deliver sm invoke");
00681         goto error;
00682         }
00683         time(&smsc->ois_alive);
00684         break;
00685     default:
00686         warning(0, "ois_check_input: unexpected message [%s]...",
00687             ois_debug_str(buffer, ret));
00688         break;
00689     }
00690     } else {
00691     if (smsc->socket != -1) {
00692         time(&now);
00693         if ((now - smsc->ois_alive) > OIS_MESSAGE_WAITTIME) {
00694         debug("bb.sms.ois", 0, "closing an idle connection");
00695         SAY(4, "ois_check_input: ois_disconnect");
00696         ois_disconnect(smsc);
00697         }
00698     }
00699     }
00700 
00701     if (ret < 0) {
00702     error(0, "ois_check_input: malformatted message [%s]",
00703           ois_debug_str(buffer, -ret));
00704     goto error;
00705     }
00706 
00707     if (smsc->ois_received_mo != NULL ||
00708     (smsc->ois_flags & OIS_FLAG_ERROR) != 0) {
00709     SAY(2, "ois_check_input has something");
00710     return 1; /* at least one message in the queue or an error pending */
00711     } else {
00712     return 0; /* no messages this time */
00713     }
00714 
00715  error:
00716     smsc->ois_flags |= OIS_FLAG_ERROR;
00717     return 1;
00718 }
00719 
00720 
00721 static int ois_check_incoming(SMSCenter *smsc, long wait_usec)
00722 {
00723     fd_set read_fd;
00724     struct timeval tv;
00725     int ret;
00726 
00727     SAY(8, "ois_check_incoming");
00728 
00729     tv.tv_sec = 0;
00730     tv.tv_usec = wait_usec;
00731 
00732     FD_ZERO(&read_fd);
00733     FD_SET(smsc->ois_listening_socket, &read_fd);
00734     ret = select(smsc->ois_listening_socket + 1, &read_fd, NULL, NULL, &tv);
00735     if (ret == -1) {
00736     if (errno == EINTR || errno == EAGAIN) {
00737         return 0;
00738     } else {
00739         error(errno, "ois_check_incoming: select failed");
00740         smsc->ois_flags |= OIS_FLAG_ERROR;
00741         return -1;
00742     }
00743     } else if (ret == 0) {
00744     return 0;
00745     }
00746 
00747     /* if we end up here, someone is trying to connect */
00748 
00749     if (smsc->socket != -1) {
00750     if ((smsc->ois_flags & OIS_FLAG_MULTIPLE_CALL) == 0) {
00751         /* if you see lots of these, maybe we should accept */
00752         /* multiple incoming connections at a time... */
00753         debug("bb.sms.ois", 0, "letting an incoming call to wait until the old one disconnects");
00754         smsc->ois_flags |= OIS_FLAG_MULTIPLE_CALL;
00755     }
00756     return 0;
00757     }
00758 
00759     smsc->ois_flags &= ~OIS_FLAG_MULTIPLE_CALL;
00760     return ois_open_receiver(smsc);
00761 }
00762 
00763 
00764 static void ois_append_to_list(ois_listentry **head, Msg *msg)
00765 {
00766     ois_listentry *item;
00767     ois_listentry *tail;
00768 
00769     SAY(2, "ois_append_to_list");
00770 
00771     item = gw_malloc(sizeof(ois_listentry));
00772     item->next = NULL;
00773     item->msg = msg;
00774 
00775     if (*head == NULL) {
00776     *head = item;
00777     } else { /* not so bright algorithm, but ok with relatively short lists */
00778     for (tail = *head; tail->next != NULL; tail = tail->next) ;
00779     tail->next = item;
00780     }
00781     return;
00782 }
00783 
00784 
00785 
00786 static int ois_int_to_i4(char *raw, int nbr)
00787 {
00788     int pos;
00789 
00790     SAY(3, "ois_int_to_i4");
00791 
00792     for (pos = 0; pos < 4; ++pos) {
00793     raw[pos] = (char)(nbr % 0x100);
00794     nbr /= 0x100;
00795     }
00796     return 4;
00797 }
00798 
00799 static int ois_increment_counter(void)
00800 {
00801     SAY(3, "ois_increment_counter");
00802 
00803     ois_counter = (ois_counter+1) % MAXCOUNTER;
00804     return ois_counter;
00805 }
00806 
00807 
00808 static int ois_submit_sm_invoke(SMSCenter *smsc, const Msg *msg)
00809 {
00810     char body[BUFLEN+1];
00811     char buffer[BUFLEN+1];
00812     int len;
00813     int count;
00814     int i;
00815     int ret;
00816 
00817     SAY(2, "ois_submit_sm_invoke");
00818 
00819     /* construct a message */
00820 
00821     ois_increment_counter();                  /* once per invoke */
00822     len = ois_encode_submit_sm_invoke(body, msg);
00823 
00824     /* the x.25 gear should be capable to fragment large messages, but... */
00825     /* let's just use an explicit 128 byte blocks */
00826 
00827     count = (len-1) / 121;                    /* 121 = 128 - 6 - 1 */
00828 
00829     /* first part */
00830 
00831     sprintf(buffer, "%c%c%04d%.121s%c",
00832         'S',                              /* submit sm invoke */
00833         (char)(0x50|count),               /* ia5 encoding, first part */
00834         ois_counter,
00835         &body[0],
00836         EOL);
00837     IOTRACE("sending", buffer, strlen(buffer));
00838     ret = write_to_socket(smsc->socket, buffer);
00839     if (ret < 0) {
00840     goto error;
00841     }
00842 
00843     /* additional parts */
00844 
00845     for (i = 1; i <= count; ++i) {
00846     sprintf(buffer, "%c%c%04d%.121s%c",
00847         'S',                          /* submit sm invoke */
00848         (char)(0x60|(count-i)),       /* ia5, additional part */
00849         ois_counter,
00850         &body[i*121],
00851         EOL);
00852     IOTRACE("sending", buffer, strlen(buffer));
00853     ret = write_to_socket(smsc->socket, buffer);
00854     if (ret < 0) {
00855         goto error;
00856     }
00857     }
00858 
00859     SAY(2, "ois_submit_sm_invoke ok");
00860     return 0;
00861 
00862  error:
00863     SAY(2, "ois_submit_sm_invoke error");
00864     return -1;
00865 }
00866 
00867 
00868 static int ois_encode_submit_sm_invoke(char *str, const Msg *msg)
00869 {
00870     char raw[BUFLEN];
00871     int pos;
00872     int ret;
00873 
00874     SAY(3, "ois_encode_submit_sm_invoke");
00875 
00876     /* construct the submit sm invoke body content */
00877 
00878     pos = 0;
00879     pos += ois_append_msisdn(&raw[pos], msg);
00880     pos += ois_append_sme_reference_number(&raw[pos]);
00881     pos += ois_append_priority(&raw[pos]);
00882     pos += ois_append_originating_address(&raw[pos]);
00883     pos += ois_append_validity_period(&raw[pos]);
00884     pos += ois_append_data_coding_scheme(&raw[pos], msg);
00885     pos += ois_append_status_report_request(&raw[pos]);
00886     pos += ois_append_protocol_id(&raw[pos]);
00887     pos += ois_append_submission_options(&raw[pos], msg);
00888     pos += ois_append_sm_text(&raw[pos], msg);
00889 
00890     ret = ois_convert_to_ia5(str, raw, pos);
00891     return ret;
00892 }
00893 
00894 static int ois_append_msisdn(char *raw, const Msg *msg)
00895 {
00896     int len;
00897 
00898     SAY(3, "ois_append_msisdn");
00899 
00900     len = octstr_len(msg->sms.receiver);
00901     raw[0] = (char) len;
00902     memcpy(&raw[1], octstr_get_cstr(msg->sms.receiver), len);
00903     return 1 + len;
00904 }
00905 
00906 static int ois_append_sme_reference_number(char *raw)
00907 {
00908     SAY(3, "ois_append_sme_reference_number");
00909 
00910     /* 1=key, 2=not key (OIS 4.5) */
00911     /* or 1=reject duplicates, 2=allow duplicates (OIS 5.0) */
00912     raw[0] = (char) 2;
00913     return 1 + ois_int_to_i4(&raw[1], ois_counter);
00914 }
00915 
00916 static int ois_append_priority(char *raw)
00917 {
00918     SAY(3, "ois_append_priority");
00919 
00920     raw[0] = (char) 1; /* 0=high, 1=normal */
00921     return 1;
00922 }
00923 
00924 static int ois_append_originating_address(char *raw)
00925 {
00926     SAY(3, "ois_append_originating_address");
00927 
00928     raw[0] = (char) 2; /* length */
00929     raw[1] = 'A'; /* A3=address type, actual address is unnecessary */
00930     raw[2] = '3';
00931 
00932     return 3;
00933 }
00934 
00935 static int ois_append_validity_period(char *raw)
00936 {
00937     SAY(3, "ois_append_validity_period");
00938 
00939     raw[0] = (char) 2; /* 0=none, 1=absolute, 2=relative */
00940     raw[1] = (char) 1; /* relative, (v+1)*5 minutes, v<144 */
00941     return 2;
00942 }
00943 
00944 static int ois_append_data_coding_scheme(char *raw, const Msg *msg)
00945 {
00946     SAY(3, "ois_append_data_coding_scheme");
00947 
00948     /* 0x0f is a special code for ASCII text, the SMSC will convert
00949      * this to GSM and set the DCS to 0.
00950      * FIXME: Convert to GSM ourselves and use DCS_GSM_TEXT.
00951      * FIXME: use fields_to_dcs and try to support DC_UCS2 too ;) */
00952     raw[0] = (char) (msg->sms.coding == DC_8BIT ? DCS_OCTET_DATA : 0x0f);
00953     return 1;
00954 }
00955 
00956 static int ois_append_status_report_request(char *raw)
00957 {
00958     SAY(3, "ois_append_status_report_request");
00959 
00960     raw[0] = (char) 0x00; /* bit field, bit 0=abandoned, bit 2=delivered */
00961     return 1;
00962 }
00963 
00964 static int ois_append_protocol_id(char *raw)
00965 {
00966     SAY(3, "ois_append_protocol_id");
00967 
00968     raw[0] = (char) 0; /* 0=default */
00969     return 1;
00970 }
00971 
00972 static int ois_append_submission_options(char *raw, const Msg *msg)
00973 {
00974     SAY(3, "ois_append_submission_options");
00975 
00976     /* bit field, bit 0=reply path, bit 1=udh, bits 3-4=dcs interpretation */
00977     raw[0] = (char) 0x00;
00978     if (octstr_len(msg->sms.udhdata)) {
00979     raw[0] |= (char) 0x02;
00980     }
00981     if (msg->sms.coding == DC_8BIT) { /* XXX and UCS-2? */
00982     raw[0] |= (char) 0x10;
00983     }
00984     return 1;
00985 }
00986 
00987 
00988 static int ois_append_sm_text(char *raw, const Msg *msg)
00989 {
00990     int udhlen7, udhlen8;
00991     int msglen7, msglen8;
00992     int len;
00993 
00994     SAY(3, "ois_append_sm_text");
00995 
00996     if (msg->sms.coding == DC_7BIT || msg->sms.coding == DC_UNDEF) {
00997         charset_utf8_to_gsm(msg->sms.udhdata);
00998         charset_utf8_to_gsm(msg->sms.msgdata);
00999     }
01000 
01001 
01002     /* calculate lengths */
01003 
01004     udhlen8 = octstr_len(msg->sms.udhdata);
01005     msglen8 = octstr_len(msg->sms.msgdata);
01006 
01007     udhlen7 = udhlen8;
01008     msglen7 = msglen8;
01009     len = udhlen8 + msglen8;
01010 
01011     /* copy text */
01012 
01013     raw[0] = (char) (len);
01014     raw[1] = (char) (udhlen7 + msglen7);
01015     memcpy(&raw[2], octstr_get_cstr(msg->sms.udhdata), udhlen8);
01016     memcpy(&raw[2+udhlen8], octstr_get_cstr(msg->sms.msgdata), msglen8);
01017 
01018     IOTRACE("encoding", &raw[2], len);
01019 
01020     return 2 + len;
01021 }
01022 
01023 
01024 static int ois_submit_sm_result(SMSCenter *smsc, const char *buffer)
01025 {
01026     int status;
01027     int ret;
01028 
01029     SAY(2, "ois_submit_sm_result");
01030 
01031     ret = ois_decode_submit_sm_result(&status, buffer);
01032     if (ret < 0) {
01033     goto error;
01034     }
01035 
01036     return status;
01037 
01038  error:
01039     return -1;
01040 }
01041 
01042 
01043 static int ois_decode_submit_sm_result(int *code, const char *str)
01044 {
01045     int buflen;
01046     char raw[BUFLEN];
01047     int len;
01048 
01049     SAY(3, "ois_decode_submit_sm_result");
01050 
01051     buflen = strlen(str) - 1;
01052     if (buflen < 7 || str[0] != 's' || str[1] != 0x50 || str[buflen] != EOL) {
01053     goto error;
01054     }
01055 
01056     len = ois_convert_from_ia5(raw, &str[6]);
01057     if (len <= 0) {
01058     goto error;
01059     }
01060 
01061     *code = raw[0];
01062     *code &= 0xff;
01063 
01064     /* there is smsc reference number and accept time, but we ignore them */
01065 
01066     return 0;
01067 
01068  error:
01069     return -1;
01070 }
01071 
01072 
01073 static int ois_deliver_sm_invoke(SMSCenter *smsc, const char *buffer)
01074 {
01075     Msg *msg;
01076     int ret;
01077     ois_listentry **mo;
01078     
01079     SAY(2, "ois_deliver_sm_invoke");
01080 
01081     msg = msg_create(sms);
01082 
01083     ret = ois_decode_deliver_sm_invoke(msg, buffer);
01084     if (ret < 0) {
01085     goto error;
01086     }
01087 
01088     mo = (ois_listentry **)&smsc->ois_received_mo;
01089     ois_append_to_list(mo, msg);
01090 
01091     return 0;
01092     
01093  error:
01094     msg_destroy(msg);
01095     return -1;
01096 }
01097 
01098 
01099 static int ois_decode_deliver_sm_invoke(Msg *msg, const char *str)
01100 {
01101     char body[BUFLEN+1];
01102     char raw[BUFLEN];
01103     int len;
01104     int i;
01105     int pos;
01106     int ret;
01107 
01108     SAY(3, "ois_decode_deliver_sm_invoke");
01109 
01110     ret = ois_check_deliver_sm_invoke(str);
01111     if (ret < 0) {
01112     goto error;
01113     }
01114 
01115     /* extract body */
01116 
01117     len = strlen(str);
01118     for (pos = 0, i = 6; i < len; ++i) {
01119     if (str[i] != EOL) {
01120         body[pos++] = str[i];
01121     } else {
01122         i += 6;
01123     }
01124     }
01125     body[pos] = '\0';
01126     memset(raw, '\0', sizeof(raw));
01127     len = ois_convert_from_ia5(raw, body);
01128 
01129     /* adjust msg values */
01130 
01131     pos = 0;
01132     pos += ois_adjust_destination_address(msg, &raw[pos]);
01133     pos += ois_ignore_smsc_reference_number(&raw[pos]);
01134     pos += ois_adjust_originating_address(msg, &raw[pos]);
01135     pos += ois_adjust_data_coding_scheme(msg, &raw[pos]);
01136     pos += ois_ignore_protocol_id(&raw[pos]);
01137     pos += ois_adjust_additional_information(msg, &raw[pos]);
01138     pos += ois_adjust_sm_text(msg, &raw[pos]);
01139     pos += ois_ignore_time(&raw[pos]); /* accept time */
01140     pos += ois_ignore_time(&raw[pos]); /* invoke time */
01141     if (pos != len) {
01142     error(0, "ois_decode_deliver_sm_invoke: message parsing error (%d!=%d)",
01143           pos, len);
01144     goto error;
01145     }
01146     return 0;
01147 
01148  error:
01149     return -1;
01150 }
01151 
01152 
01153 static int ois_check_deliver_sm_invoke(const char *str)
01154 {
01155     int buflen;
01156     char buffer[BUFLEN+1];
01157     int count;
01158 
01159     SAY(3, "ois_check_deliver_sm_invoke");
01160 
01161     /* check the (initial) header and trailer */
01162 
01163     buflen = strlen(str) - 1;
01164     if (buflen < 7 || str[0] != 'M' || (str[1] & 0x50) != 0x50
01165     || str[buflen] != EOL) {
01166     goto error;
01167     }
01168 
01169     count = str[1] & 0x0f;
01170     while (--count >= 0)
01171     {
01172     /* check the additional header */
01173 
01174     sprintf(buffer, "%c%c%c%.4s",
01175         EOL,
01176         'M',                      /* deliver sm invoke */
01177         (char)(0x60|count),       /* ia5 encoding, additional part */
01178         &str[2]);
01179     if (strstr(str, buffer) == NULL) {
01180         goto error;
01181     }
01182     }
01183 
01184     return 0;
01185     
01186  error:
01187     return -1;
01188 }
01189 
01190 
01191 static int ois_adjust_destination_address(Msg *msg, const char *raw)
01192 {
01193     int len;
01194 
01195     SAY(3, "ois_adjust_destination_address");
01196 
01197     len = raw[0] & 0xff;
01198     msg->sms.receiver = octstr_create_from_data(&raw[1+2], len-2);
01199 
01200     return 1 + len;
01201 }
01202 
01203 static int ois_ignore_smsc_reference_number(const char *raw)
01204 {
01205     int value;
01206 
01207     SAY(3, "ois_ignore_smsc_reference_number");
01208 
01209     value = raw[3] & 0xff;
01210     value <<= 8;
01211     value |= raw[2] & 0xff;
01212     value <<= 8;
01213     value |= raw[1] & 0xff;
01214     value <<= 8;
01215     value |= raw[0] & 0xff;
01216 
01217     return 4;
01218 }
01219 
01220 static int ois_adjust_originating_address(Msg *msg, const char *raw)
01221 {
01222     int len;
01223 
01224     SAY(3, "ois_adjust_originating_address");
01225 
01226     len = raw[0] & 0xff;
01227     msg->sms.sender = octstr_create_from_data(&raw[1+2], len-2);
01228 
01229     return 1 + len;
01230 }
01231 
01232 static int ois_adjust_data_coding_scheme(Msg *msg, const char *raw)
01233 {
01234     SAY(3, "ois_adjust_data_coding_scheme");
01235 
01236     /* we're using this variable temporarily: 
01237      * ois_adjust_sm_text will set the correct value */
01238 
01239     msg->sms.coding = (raw[0] & 0xff) + 1;
01240 
01241     return 1;
01242 }
01243 
01244 static int ois_ignore_protocol_id(const char *raw)
01245 {
01246     int value;
01247 
01248     SAY(3, "ois_ignore_protocol_id");
01249 
01250     value = raw[0] & 0xff;
01251 
01252     return 1;
01253 }
01254 
01255 static int ois_adjust_additional_information(Msg *msg, const char *raw)
01256 {
01257     SAY(3, "ois_adjust_additional_information");
01258 
01259     /* we're using this variable temporarily: 
01260      * ois_adjust_sm_text will set the correct value */
01261     msg->sms.mclass = raw[0] & 0xff;
01262 
01263     return 1;
01264 }
01265 
01266 static int ois_adjust_sm_text(Msg *msg, const char *raw)
01267 {
01268     int msglen7, msglen8;
01269     char buffer[BUFLEN+1];
01270 
01271     SAY(3, "ois_adjust_sm_text");
01272 
01273     /* calculate lengths */
01274 
01275     msglen7 = raw[0] & 0xff;
01276     msglen8 = raw[1] & 0xff;
01277 
01278     /* copy text, note: flag contains temporarily the raw type description */
01279 
01280     switch ((msg->sms.coding - 1) & 0xff) { 
01281     case 0x00: /* gsm7 */
01282     ois_expand_gsm7(buffer, &raw[2], msglen7);
01283     ois_convert_to_iso88591(buffer, msglen7);
01284     if (msg->sms.mclass & 0x02) { /* XXX mclass temporarily */
01285         msg->sms.msgdata = octstr_create("");
01286         msg->sms.udhdata = octstr_create_from_data(buffer, msglen7);
01287     } else {
01288         msg->sms.msgdata = octstr_create_from_data(buffer, msglen7);
01289         msg->sms.udhdata = octstr_create("");
01290     }
01291     msg->sms.coding = DC_7BIT;
01292     break;
01293     case 0x0f: /* ia5 */
01294     memcpy(buffer, &raw[2], msglen8);
01295     ois_convert_to_iso88591(buffer, msglen8);
01296     if (msg->sms.mclass & 0x02) { /* XXX mclass temporarily */
01297         msg->sms.msgdata = octstr_create("");
01298         msg->sms.udhdata = octstr_create_from_data(buffer, msglen8);
01299     } else {
01300         msg->sms.msgdata = octstr_create_from_data(buffer, msglen8);
01301         msg->sms.udhdata = octstr_create("");
01302     }
01303     msg->sms.coding = DC_7BIT;
01304     break;
01305     default: /* 0xf4, 0xf5, 0xf6, 0xf7; 8bit to disp, mem, sim or term */ 
01306     if (msg->sms.mclass & 0x02) { /* XXX mclass temporarily */
01307         msg->sms.msgdata = octstr_create("");
01308         msg->sms.udhdata = octstr_create_from_data(&raw[2], msglen8);
01309     } else {
01310         msg->sms.msgdata = octstr_create_from_data(&raw[2], msglen8);
01311         msg->sms.udhdata = octstr_create("");
01312     }
01313     msg->sms.coding = DC_8BIT;
01314     break;
01315     }
01316     msg->sms.mclass = MC_UNDEF;
01317 
01318     if (octstr_len(msg->sms.udhdata)) {
01319     IOTRACE("decoded udh", octstr_get_cstr(msg->sms.udhdata),
01320         octstr_len(msg->sms.udhdata));
01321     } else {
01322     IOTRACE("decoded", octstr_get_cstr(msg->sms.msgdata),
01323         octstr_len(msg->sms.msgdata));
01324     }
01325 
01326     return 2 + msglen8;
01327 }
01328 
01329 
01330 static int ois_ignore_time(const char *raw)
01331 {
01332     char str[15];
01333 
01334     SAY(3, "ois_ignore_time");
01335 
01336     strncpy(str, raw, 14); str[14] = '\0';
01337 
01338     return 14;
01339 }
01340 
01341 
01342 
01343 static int ois_deliver_sm_result(SMSCenter *smsc, int result, const char *str)
01344 {
01345     char body[BUFLEN+1];
01346     char buffer[BUFLEN+1];
01347     int len;
01348     int ret;
01349 
01350     SAY(2, "ois_deliver_sm_result");
01351 
01352     /* construct a message */
01353 
01354     len = ois_encode_deliver_sm_result(body, result);
01355 
01356     /* first and only part */
01357 
01358     sprintf(buffer, "%c%c%.4s%.121s%c",
01359         'm',                              /* deliver sm result */
01360         (char)(0x50),                     /* ia5 encoding, the only part */
01361         &str[2],
01362         &body[0],
01363         EOL);
01364 
01365     IOTRACE("sending", buffer, strlen(buffer));
01366     ret = write_to_socket(smsc->socket, buffer);
01367     if (ret < 0) {
01368     goto error;
01369     }
01370 
01371     return 0;
01372 
01373  error:
01374     return -1;
01375 }
01376 
01377 
01378 static int ois_encode_deliver_sm_result(char *str, int result)
01379 {
01380     char raw[4];
01381 
01382     SAY(3, "ois_encode_deliver_sm_result");
01383 
01384     /* construct the deliver sm result body content */
01385 
01386     raw[0] = (char) result;
01387 
01388     return ois_convert_to_ia5(str, raw, 1);
01389 }
01390 
01391 
01392 static int ois_expand_gsm7(char *raw8, const char *raw7, int len)
01393 {
01394     int i;
01395     char bits[8*(BUFLEN+1)];
01396 
01397     SAY2(3, "ois_expand_gsm7 len=%d", len);
01398 
01399     /* yeah, there are also better algorithms, but... */
01400     /* well, at least this is fairly portable and ok for small messages... */
01401 
01402     ois_expand_gsm7_to_bits(bits, raw7, len);
01403     for (i = 0; i < len; ++i) {
01404     raw8[i] = ois_expand_gsm7_from_bits(bits, i);
01405     }
01406 
01407     SAY2(5, "ois_expand_gsm7 gave [%s]", ois_debug_str(raw8, i));
01408     return i;
01409 }
01410 
01411 static int ois_expand_gsm7_to_bits(char *bits, const char *raw7, int len)
01412 {
01413     int i, j, k;
01414     char ch;
01415 
01416     SAY(3, "ois_expand_gsm7_to_bits");
01417 
01418     len *= 7; /* number of bits in the gms 7-bit msg */
01419 
01420     for (j = i = 0; j < len; ++i) {
01421     ch = raw7[i];
01422     for (k = 0; k < 8; ++k) {
01423         bits[j++] = (char) (ch & 0x01);
01424         ch >>= 1;
01425     }
01426     }
01427 
01428     return j;
01429 }
01430 
01431 static char ois_expand_gsm7_from_bits(const char *bits, int pos)
01432 {
01433     int i;
01434     char ch;
01435 
01436     SAY2(8, "ois_expand_gsm7_from_bits pos=%d", pos);
01437 
01438     pos *= 7; /* septet position in bits */
01439     ch = '\0';
01440     for (i = 6; i >= 0; --i) {
01441     ch <<= 1;
01442     ch |= bits[pos+i];
01443     }
01444 
01445     return ch;
01446 }
01447 
01448 
01449 static int ois_convert_to_ia5(char *str, const char *raw, int len)
01450 {
01451     int j;
01452     int i;
01453     int ch;
01454 
01455     SAY2(3, "ois_convert_to_ia5 len=%d", len);
01456 
01457     for (j = i = 0; i < len; ++i) {
01458     ch = raw[i] & 0xff;
01459     if (ch == 0x5c || ch == 0x5e || ch == 0x60 || ch == 0x7e) {
01460         str[j++] = (char) 0x5c;
01461         str[j++] = (char) ch;
01462     } else if (0x20 <= ch && ch < 0x7f) {
01463         str[j++] = (char) ch;
01464     } else if (0x00 <= ch && ch < 0x20) {
01465         str[j++] = (char) 0x5e;
01466         str[j++] = (char) ch + 0x40;
01467     } else if (0xa0 <= ch && ch < 0xff) {
01468         str[j++] = (char) 0x60;
01469         str[j++] = (char) ch - 0x80;
01470     } else if (0x80 <= ch && ch < 0xa0) {
01471         str[j++] = (char) 0x7e;
01472         str[j++] = (char) ch - 0x40;
01473     } else if (ch == 0x7f) {
01474         str[j++] = (char) 0x5e;
01475         str[j++] = (char) 0x7e;
01476     } else { /* ch == 0xff */
01477         str[j++] = (char) 0x7e;
01478         str[j++] = (char) 0x7e;
01479     }
01480     }
01481 
01482     str[j] = '\0';
01483     SAY2(5, "ois_convert_to_ia5 gave [%s]", ois_debug_str(str, j));
01484     return j;
01485 }
01486 
01487 
01488 static int ois_convert_from_ia5(char *raw, const char *str)
01489 {
01490     int j;
01491     int i;
01492     int ch;
01493 
01494     SAY(3, "ois_convert_from_ia5");
01495 
01496     for (j = i = 0; ; ++i) {
01497     ch = str[i] & 0xff;
01498     if (ch < 0x20 || 0x7f <= ch) {
01499         break;
01500     } else if (ch == 0x5c) {
01501         ch = str[++i] & 0xff;
01502         if (ch == 0x5c || ch == 0x5e || ch == 0x60 || ch == 0x7e) {
01503         raw[j++] = (char) ch;
01504         } else {
01505         break;
01506         }
01507     } else if (ch == 0x5e) {
01508         ch = str[++i] & 0xff;
01509         if (0x40 <= ch && ch < 0x60) {
01510         raw[j++] = (char) ch - 0x40;
01511         } else if (ch == 0x7e) {
01512         raw[j++] = (char) 0x7f;
01513         } else {
01514         break;
01515         }
01516     } else if (ch == 0x60) {
01517         ch = str[++i] & 0xff;
01518         if (0x20 <= ch && ch < 0x7f) {
01519         raw[j++] = (char) ch + 0x80;
01520         } else {
01521         break;
01522         }
01523     } else if (ch == 0x7e) {
01524         ch = str[++i] & 0xff;
01525         if (0x40 <= ch && ch < 0x60) {
01526         raw[j++] = (char) ch + 0x40;
01527         } else if (ch == 0x7e) {
01528         raw[j++] = (char) 0xff;
01529         } else {
01530         break;
01531         }
01532     } else { /* 0x20 <= ch && ch < 0x7f */
01533         raw[j++] = (char) ch;
01534     }
01535     }
01536 
01537     SAY2(5, "ois_convert_from_ia5 gave [%s]", ois_debug_str(raw, j));
01538     return j;
01539 }
01540 
01541 
01542 static int ois_convert_to_iso88591(char *raw, int len)
01543 {
01544     /* a best effort 1-to-1 conversion according to ois appendix a */
01545 
01546     static const char gsm_to_iso88591[] = {
01547     '@', 0xa3,'$', 0xa5,0xe8,0xe9,0xf9,0xec, /* 0x00 - 0x07 */
01548     0xf2,0xc7,'\n',0xd8,0xf8,'\r',0xc5,0xe5, /* 0x08 - 0x0f */
01549     'D', ' ', 'F', 'G', 'L', 'W', 'P', 'Y',  /* 0x10 - 0x17, poor! */
01550     'Y', 'S', 'X', ' ', 0xc6,0xe6,'b', 0xc9, /* 0x18 - 0x1f, poor! */
01551     ' ', '!', '"', '#', 0xa4, '%', '&', '\'',/* 0x20 - 0x27 */
01552     '(', ')', '*', '+', ',', '-', '.', '/',  /* 0x28 - 0x2f */
01553     '0', '1', '2', '3', '4', '5', '6', '7',  /* 0x30 - 0x37 */
01554     '8', '9', ':', ';', '<', '=', '>', '?',  /* 0x38 - 0x3f */
01555     0xa1,'A', 'B', 'C', 'D', 'E', 'F', 'G',  /* 0x40 - 0x47 */
01556     'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',  /* 0x48 - 0x4f */
01557     'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',  /* 0x50 - 0x57 */
01558     'X', 'Y', 'Z', 0xc4,0xd6,0xd1,0xdc,0xa7, /* 0x58 - 0x5f */
01559     0xbf,'a', 'b', 'c', 'd', 'e', 'f', 'g',  /* 0x60 - 0x67 */
01560     'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',  /* 0x68 - 0x6f */
01561     'p', 'q', 'r', 's', 't', 'u', 'v', 'w',  /* 0x70 - 0x77 */
01562     'x', 'y', 'z', 0xe4,0xf6,0xf1,0xfc,0xe0  /* 0x78 - 0x7f */
01563     };
01564 
01565     int i;
01566 
01567     SAY2(3, "ois_convert_to_iso88591 len=%d", len);
01568 
01569     for (i = 0; i < len; ++i) {
01570     raw[i] = gsm_to_iso88591[raw[i] & 0x7f];
01571     }
01572 
01573     SAY2(5, "ois_convert_to_iso88591 gave [%s]", ois_debug_str(raw, i));
01574     return i;
01575 }
01576 
01577 
01578 /*
01579  * Extract a message from the internal buffer.
01580  */
01581 
01582 static int ois_extract_msg_from_buffer(char *str, SMSCenter *smsc)
01583 {
01584     int len;
01585     int count;
01586 
01587     SAY2(8, "ois_extract_msg_from_buffer buflen=%ld", (long)smsc->buflen);
01588 
01589     str[0] = '\0';
01590 
01591     if (smsc->buflen < 7) {             /* 7 = 6 + 1 */
01592     return 0;              /* we don't have a message yet */
01593     }
01594 
01595     if (strchr("SRDATECQLMPOVsrdatecqlmpov", smsc->buffer[0]) == NULL
01596     || (smsc->buffer[1] & 0xf0) != 0x50) {
01597 
01598     goto error;
01599     }
01600 
01601     /* a valid message type, find the end of the message */
01602 
01603     count = smsc->buffer[1] & 0x0f;
01604     for (len = 0; (size_t) len < smsc->buflen; ++len) {
01605     if (smsc->buffer[len] == EOL) {
01606         if (--count < 0) {
01607         ++len;
01608         break;
01609         }
01610     }
01611     }
01612 
01613     if (count >= 0) {          /* we don't have all the pieces */
01614     if (len < BUFLEN) {
01615         return 0;          /* ...but maybe later */
01616     }
01617     goto error;
01618     }
01619 
01620     /* the buffer contains a promising message candidate */
01621 
01622     memcpy(str, smsc->buffer, len);
01623     str[len] = '\0';
01624     smscenter_remove_from_buffer(smsc, len); /* just the message */
01625 
01626     return len;
01627 
01628  error:
01629     for (len = 0; (size_t) len < smsc->buflen && smsc->buffer[len] != EOL; 
01630          ++len) ;
01631     if (len > BUFLEN) len = BUFLEN;
01632 
01633     memcpy(str, smsc->buffer, len);
01634     str[len] = '\0';
01635     smscenter_remove_from_buffer(smsc, smsc->buflen); /* everything */
01636 
01637     return -len;
01638 }
01639 
01640 
01641 
01642 /*
01643  * Extract a line from the internal buffer.
01644  */
01645 
01646 static int ois_extract_line_from_buffer(char *str, SMSCenter *smsc)
01647 {
01648     int len;
01649 
01650     SAY2(3, "ois_extract_line_from_buffer buflen=%ld", (long)smsc->buflen);
01651 
01652     str[0] = '\0';
01653 
01654     for (len = 0; (size_t) len < smsc->buflen && smsc->buffer[len] != '\n'; 
01655          ++len) ;
01656 
01657     if ((size_t) len >= smsc->buflen) {
01658     return 0;
01659     } else {
01660     ++len;
01661     }
01662 
01663     /* the buffer contains a line */
01664 
01665     memcpy(str, smsc->buffer, len);
01666     str[len] = '\0';
01667     smscenter_remove_from_buffer(smsc, len); /* just the line */
01668 
01669     return len;
01670 }
01671 
01672 
01673 static void ois_swap_buffering(SMSCenter *smsc)
01674 {
01675     time_t alive;
01676     int socket;
01677     char *buffer;
01678     size_t bufsize;
01679     size_t buflen;
01680 
01681     SAY(8, "ois_swap_buffering");
01682 
01683     if (smsc->ois_bufsize == 0) {
01684     smsc->ois_buflen = 0;
01685     smsc->ois_bufsize = smsc->bufsize;
01686     smsc->ois_buffer = gw_malloc(smsc->ois_bufsize);
01687     memset(smsc->ois_buffer, 0, smsc->ois_bufsize);
01688     }
01689 
01690     alive = smsc->ois_alive;
01691     smsc->ois_alive = smsc->ois_alive2;
01692     smsc->ois_alive2 = alive;
01693 
01694     socket = smsc->socket;
01695     smsc->socket = smsc->ois_socket;
01696     smsc->ois_socket = socket;
01697 
01698     buffer = smsc->buffer;
01699     smsc->buffer = smsc->ois_buffer;
01700     smsc->ois_buffer = buffer;
01701 
01702     buflen = smsc->buflen;
01703     smsc->buflen = smsc->ois_buflen;
01704     smsc->ois_buflen = buflen;
01705 
01706     bufsize = smsc->bufsize;
01707     smsc->bufsize = smsc->ois_bufsize;
01708     smsc->ois_bufsize = bufsize;
01709 
01710     return;
01711 }
01712 
01713 
01714 static const char *ois_debug_str(const char *raw, int len)
01715 {
01716     static const char hex[] = "0123456789abcdef";
01717     static char str[4*(BUFLEN+1)+1];
01718     int pos;
01719     int ch;
01720     int i;
01721 
01722     pos = 0;
01723     for (i = 0; i < len; ++i) {
01724     ch = raw[i] & 0xff;
01725     if (0x20 <= ch && ch < 0x7f && ch != 0x5c) {
01726         str[pos++] = (char) ch;
01727     } else {
01728         str[pos++] = '\\';
01729         str[pos++] = 'x';
01730         str[pos++] = hex[ch/16];
01731         str[pos++] = hex[ch%16];
01732     }
01733     }
01734     str[pos] = '\0';
01735     return str;
01736 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.