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

smsc_emi.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_emi.c - interface to EMI/UCP SMS centers
00059  *
00060  * Uoti Urpala 2001
00061  * Alexander Malysh and Stipe Tolj 2002-2003
00062  * Vincent Chavanis 2005-2006
00063  *
00064  * References:
00065  *
00066  *   [1] Short Message Service Centre 4.6 EMI - UCP Interface Specification
00067  *       document version 4.6, April 2003, CMG Wireless Data Solutions.
00068  */
00069 
00070 /* Doesn't warn about unrecognized configuration variables */
00071 /* The EMI specification doesn't document how connections should be
00072  * opened/used. The way they currently work might need to be changed. */
00073 
00074 
00075 #include <sys/types.h>
00076 #include <sys/socket.h>
00077 #include <unistd.h>
00078 #include <errno.h>
00079 #include <time.h>
00080 #include <limits.h>
00081 #include <float.h>
00082 
00083 #include "gwlib/gwlib.h"
00084 #include "smscconn.h"
00085 #include "smscconn_p.h"
00086 #include "bb_smscconn_cb.h"
00087 #include "msg.h"
00088 #include "sms.h"
00089 #include "emimsg.h"
00090 #include "dlr.h"
00091 #include "alt_charsets.h"
00092 
00093 #define EMI2_MAX_TRN 100
00094 
00095 typedef struct privdata {
00096     Octstr  *name;
00097     gw_prioqueue_t *outgoing_queue;
00098     long    receiver_thread;
00099     long    sender_thread;
00100     int     shutdown;     /* Internal signal to shut down */
00101     int     listening_socket; /* File descriptor */
00102     int     send_socket;
00103     int     port, alt_port;       /* SMSC port */
00104     int     our_port;     /* Optional local port number in which to
00105                    * bind our end of send connection */
00106     int     rport;        /* Receive-port to listen */
00107     Octstr  *allow_ip, *deny_ip;
00108     Octstr  *host, *alt_host, *username, *password;
00109     Octstr  *my_number; /* My number if we want to force one */
00110     int     unacked;    /* Sent messages not acked */
00111     struct {
00112     time_t  sendtime;   /* When we sent out a message with a given
00113                  * TRN. Is 0 if the TRN slot is currently free. */
00114     int     sendtype;   /* OT of message, undefined if time == 0 */
00115     Msg     *sendmsg;   /* Corresponding message for OT == 51 */
00116     } slots[EMI2_MAX_TRN];
00117     int     keepalive;  /* Seconds to send a Keepalive Command (OT=31) */
00118     int     flowcontrol;    /* 0=Windowing, 1=Stop-and-Wait */
00119     int     waitack;    /* Seconds to wait to ack */
00120     int     waitack_expire; /* What to do on waitack expire */
00121     int     window;     /* In windowed flow-control, the window size */
00122     int         can_write;      /* write = 1, read = 0, for stop-and-wait flow control */
00123     int         priv_nexttrn;   /* next TRN, this should never be accessed directly.
00124                  * use int emi2_next_trn (SMSCConn *conn) instead.
00125                  */
00126     time_t  last_activity_time; /* the last time something was sent over the main
00127                      * SMSC connection
00128                      */
00129     time_t      check_time;
00130     int         idle_timeout;   /* Seconds a Main connection to the SMSC is allowed to be idle.
00131                    If 0, no idle timeout is in effect */
00132     Octstr   *npid; /* Notification PID value */
00133     Octstr   *nadc; /* Notification Address */
00134     int alt_charset; /* Alternative GSM charset, defined via values in gwlib/alt_charsets.h */
00135 } PrivData;
00136 
00137 typedef enum {
00138     EMI2_SENDREQ,  /* somebody asked this driver to send a SMS message */
00139     EMI2_SMSCREQ,  /* the SMSC wants something from us */
00140     EMI2_CONNERR,  /* an error condition in the SMSC main connection */
00141     EMI2_TIMEOUT,  /* timeout on the SMSC main connection */
00142 } EMI2Event;
00143 
00144 #define PRIVDATA(conn) ((PrivData *)((conn)->data))
00145 
00146 #define SLOTBUSY(conn,i) (PRIVDATA(conn)->slots[(i)].sendtime != 0)
00147 
00148 #define CONNECTIONIDLE(conn)                                \
00149 ((PRIVDATA(conn)->unacked == 0) &&                          \
00150  (PRIVDATA(conn)->idle_timeout ?                            \
00151   (PRIVDATA(conn)->last_activity_time + PRIVDATA(conn)->idle_timeout) <= time(0):0))
00152 
00153 #define emi2_can_send(conn)                 \
00154 ((PRIVDATA(conn)->can_write || !PRIVDATA(conn)->flowcontrol) && \
00155  (PRIVDATA(conn)->unacked < PRIVDATA(conn)->window) &&      \
00156  (!PRIVDATA(conn)->shutdown))
00157 
00158 #define emi2_needs_keepalive(conn)                          \
00159 (emi2_can_send(conn) &&                                 \
00160  (PRIVDATA(conn)->keepalive > 0) &&                         \
00161  (time(NULL) > (PRIVDATA(conn)->last_activity_time + PRIVDATA(conn)->keepalive)))
00162 
00163 /*
00164  * Send an EMI message and update the last_activity_time field.
00165  */
00166 static int emi2_emimsg_send(SMSCConn *conn, Connection *server, struct emimsg *emimsg)
00167 {
00168     int result = emimsg_send(server, emimsg, PRIVDATA(conn)->name);
00169 
00170     if (result >= 0 && emimsg->or == 'O' && ( emimsg->ot == 31 || emimsg->ot == 51)) {
00171     PRIVDATA(conn)->last_activity_time = time (NULL);
00172     }
00173 
00174     return result;
00175 }
00176 
00177 /* Wait for a message of type 'ot', sent with TRN 0, to be acked.
00178  * Timeout after 't' seconds. Any other packets received are ignored.
00179  * This function is meant for initial login packet(s) and testing.
00180  * Return 1 for positive ACK, 0 for timeout, -1 for broken/closed connection,
00181  * -2 for negative NACK. */
00182 static int wait_for_ack(PrivData *privdata, Connection *server, int ot, int t)
00183 {
00184     time_t timeout_time;
00185     int time_left;
00186     Octstr *str;
00187     struct emimsg *emimsg;
00188 
00189     timeout_time = time(NULL) + t;
00190     while (1) {
00191     str = conn_read_packet(server, 2, 3);
00192     if (conn_eof(server)) {
00193         error(0, "EMI2[%s]: connection closed in wait_for_ack",
00194           octstr_get_cstr(privdata->name));
00195         return -1;
00196     }
00197     if (conn_error(server)) {
00198         error(0, "EMI2[%s]: connection error in wait_for_ack",
00199           octstr_get_cstr(privdata->name));
00200         return -1;
00201     }
00202     if (str) {
00203         emimsg = get_fields(str, privdata->name);
00204         if (emimsg == NULL) {
00205         octstr_destroy(str);
00206         continue;
00207         }
00208         if (emimsg->ot == ot && emimsg->trn == 0 && emimsg->or == 'R') {
00209         octstr_destroy(str);
00210         break;
00211         }
00212         warning(0, "EMI2[%s]: ignoring message %s while waiting for ack to"
00213             "ot:%d trn:%d", octstr_get_cstr(privdata->name),
00214             octstr_get_cstr(str), ot, 0);
00215         emimsg_destroy(emimsg);
00216         octstr_destroy(str);
00217     }
00218     time_left = timeout_time - time(NULL);
00219     if (time_left < 0 || privdata->shutdown)
00220         return 0;
00221     conn_wait(server, time_left);
00222     }
00223     if (octstr_get_char(emimsg->fields[0], 0) == 'N') {
00224     emimsg_destroy(emimsg);
00225     return -2;
00226     }
00227     emimsg_destroy(emimsg);
00228     return 1;
00229 }
00230 
00231 
00232 static struct emimsg *make_emi31(PrivData *privdata, int trn)
00233 {
00234     struct emimsg *emimsg;
00235 
00236     if(octstr_len(privdata->username) || octstr_len(privdata->my_number)) {
00237         emimsg = emimsg_create_op(31, trn, privdata->name);
00238         if(octstr_len(privdata->username)) {
00239             emimsg->fields[0] = octstr_duplicate(privdata->username);
00240     } else {
00241             emimsg->fields[0] = octstr_duplicate(privdata->my_number);
00242     }
00243         emimsg->fields[1] = octstr_create("0539");
00244         return emimsg;
00245     } else {
00246         return NULL;
00247     }
00248 }
00249 
00250 
00251 static struct emimsg *make_emi60(PrivData *privdata)
00252 {
00253     struct emimsg *emimsg;
00254 
00255     emimsg = emimsg_create_op(60, 0, privdata->name);
00256     emimsg->fields[E60_OADC] = octstr_duplicate(privdata->username);
00257     emimsg->fields[E60_OTON] = octstr_create("6");
00258     emimsg->fields[E60_ONPI] = octstr_create("5");
00259     emimsg->fields[E60_STYP] = octstr_create("1");
00260     emimsg->fields[E60_PWD] = octstr_duplicate(privdata->password);
00261     octstr_binary_to_hex(emimsg->fields[E60_PWD], 1);
00262     emimsg->fields[E60_VERS] = octstr_create("0100");
00263     return emimsg;
00264 }
00265 
00266 
00267 static Connection *open_send_connection(SMSCConn *conn)
00268 {
00269     PrivData *privdata = conn->data;
00270     int result, alt_host, do_alt_host;
00271     struct emimsg *emimsg;
00272     Connection *server;
00273     Msg *msg;
00274     int connect_error = 0;
00275     int wait_ack = 0;
00276 
00277     do_alt_host = octstr_len(privdata->alt_host) != 0 || privdata->alt_port != 0;
00278 
00279     alt_host = 0;
00280 
00281     mutex_lock(conn->flow_mutex);
00282     conn->status = SMSCCONN_RECONNECTING;
00283     mutex_unlock(conn->flow_mutex);
00284 
00285     while (!privdata->shutdown) {
00286 
00287     while ((msg = gw_prioqueue_remove(privdata->outgoing_queue))) {
00288         bb_smscconn_send_failed(conn, msg,
00289                          SMSCCONN_FAILED_TEMPORARILY, NULL);
00290     }
00291 
00292     /* if there is no alternative host, sleep and try to re-connect */
00293     if (alt_host == 0 && connect_error) {
00294         error(0, "EMI2[%s]: Couldn't connect to SMS center (retrying in %ld seconds).",
00295               octstr_get_cstr(privdata->name), conn->reconnect_delay);
00296         gwthread_sleep(conn->reconnect_delay);
00297     }
00298 
00299     if (alt_host != 1) {
00300         info(0, "EMI2[%s]: connecting to Primary SMSC",
00301                 octstr_get_cstr(privdata->name));
00302         mutex_lock(conn->flow_mutex);
00303         octstr_destroy(conn->name);
00304         conn->name = octstr_format("EMI2:%S:%d:%S", privdata->host, privdata->port, privdata->username ? privdata->username : octstr_imm("null"));
00305         mutex_unlock(conn->flow_mutex);
00306         server = conn_open_tcp_with_port(privdata->host, privdata->port,
00307                          privdata->our_port,
00308                          conn->our_host);
00309         if(do_alt_host)
00310             alt_host=1;
00311         else
00312             alt_host=0;
00313     } else {
00314         info(0, "EMI2[%s]: connecting to Alternate SMSC",
00315                 octstr_get_cstr(privdata->name));
00316         /* use alt_host or/and alt_port if defined */
00317         mutex_lock(conn->flow_mutex);
00318         octstr_destroy(conn->name);
00319         conn->name = octstr_format("EMI2:%S:%d:%S", octstr_len(privdata->alt_host) ? privdata->alt_host : privdata->host,
00320                                   privdata->alt_port ? privdata->alt_port : privdata->port,
00321                                   privdata->username ? privdata->username : octstr_imm("null"));
00322         mutex_unlock(conn->flow_mutex);
00323         server = conn_open_tcp_with_port(
00324         (octstr_len(privdata->alt_host) ? privdata->alt_host : privdata->host),
00325         (privdata->alt_port ? privdata->alt_port : privdata->port),
00326         privdata->our_port, conn->our_host);
00327         alt_host=0;
00328     }
00329     if (privdata->shutdown) {
00330         conn_destroy(server);
00331         return NULL;
00332     }
00333     if (server == NULL) {
00334         error(0, "EMI2[%s]: opening TCP connection to %s failed",
00335           octstr_get_cstr(privdata->name),
00336           octstr_get_cstr(privdata->host));
00337         connect_error = 1;  
00338         continue;
00339     }
00340 
00341     if (privdata->username && privdata->password) {
00342         emimsg = make_emi60(privdata);
00343         emi2_emimsg_send(conn, server, emimsg);
00344         emimsg_destroy(emimsg);
00345         wait_ack = privdata->waitack > 30 ? privdata->waitack : 30;
00346         result = wait_for_ack(privdata, server, 60, wait_ack);
00347         if (result == -2) {
00348             /* 
00349              * Are SMSCs going to return any temporary errors? If so,
00350              * testing for those error codes should be added here. 
00351              */
00352             error(0, "EMI2[%s]: Server rejected our login",
00353                   octstr_get_cstr(privdata->name));
00354             conn_destroy(server);
00355             connect_error = 1;
00356             continue;
00357         } else if (result == 0) {
00358             error(0, "EMI2[%s]: Got no reply to login attempt "
00359                      "within %d seconds", octstr_get_cstr(privdata->name),
00360                      wait_ack);
00361             conn_destroy(server);
00362             connect_error = 1;
00363             continue;
00364         } else if (result == -1) { /* Broken connection, already logged */
00365             conn_destroy(server);
00366             connect_error = 1;
00367             continue;
00368         }
00369         privdata->last_activity_time = 0; /* to force keepalive after login */
00370         privdata->can_write = 1;
00371     }
00372 
00373     mutex_lock(conn->flow_mutex);
00374     conn->status = SMSCCONN_ACTIVE;
00375     conn->connect_time = time(NULL);
00376     mutex_unlock(conn->flow_mutex);
00377     bb_smscconn_connected(conn);
00378     return server;
00379     }
00380     return NULL;
00381 }
00382 
00383 
00384 static void pack_7bit(Octstr *str)
00385 {
00386     Octstr *result;
00387     int len, i;
00388     int numbits, value;
00389 
00390     result = octstr_create("0");
00391     len = octstr_len(str);
00392     value = 0;
00393     numbits = 0;
00394     for (i = 0; i < len; i++) {
00395     value += octstr_get_char(str, i) << numbits;
00396     numbits += 7;
00397     if (numbits >= 8) {
00398         octstr_append_char(result, value & 0xff);
00399         value >>= 8;
00400         numbits -= 8;
00401     }
00402     }
00403     if (numbits > 0)
00404     octstr_append_char(result, value);
00405     octstr_set_char(result, 0, (len * 7 + 3) / 4);
00406     octstr_delete(str, 0, LONG_MAX);
00407     octstr_append(str, result);
00408     octstr_binary_to_hex(str, 1);
00409     octstr_destroy(result);
00410 }
00411 
00412 
00413 static struct emimsg *msg_to_emimsg(Msg *msg, int trn, PrivData *privdata)
00414 {
00415     Octstr *str;
00416     struct emimsg *emimsg;
00417     int dcs;
00418     struct tm tm;
00419     char p[20];
00420 
00421     emimsg = emimsg_create_op(51, trn, privdata->name);
00422     str = octstr_duplicate(msg->sms.sender);
00423     if(octstr_get_char(str,0) == '+') {
00424         /* either alphanum or international */
00425         if (!octstr_check_range(str, 1, 256, gw_isdigit)) {
00426         /* alphanumeric sender address with + in front*/
00427         charset_utf8_to_gsm(str);
00428         octstr_truncate(str, 11); /* max length of alphanumeric OaDC */
00429         emimsg->fields[E50_OTOA] = octstr_create("5039");
00430         pack_7bit(str);
00431     }
00432     else {
00433         /* international number. Set format and remove + */
00434         emimsg->fields[E50_OTOA] = octstr_create("1139");
00435         octstr_delete(str, 0, 1);
00436         octstr_truncate(str, 22);  /* max length of numeric OaDC */
00437     }
00438     }
00439     else {
00440     if (!octstr_check_range(str, 0, 256, gw_isdigit)) {
00441         /* alphanumeric sender address */
00442             charset_utf8_to_gsm(str);
00443         octstr_truncate(str, 11); /* max length of alphanumeric OaDC */
00444         emimsg->fields[E50_OTOA] = octstr_create("5039");
00445         pack_7bit(str);
00446     }
00447     }
00448  
00449     emimsg->fields[E50_OADC] = str;
00450 
00451     /* set protocol id */
00452     if (msg->sms.pid >= 0) {
00453         emimsg->fields[E50_RPID] = octstr_format("%04d", msg->sms.pid);
00454     }
00455 
00456     /* set reply path indicator */
00457     if (msg->sms.rpi == 2)
00458         emimsg->fields[E50_RPI] = octstr_create("2");
00459     else if (msg->sms.rpi > 0)
00460         emimsg->fields[E50_RPI] = octstr_create("1");
00461 
00462     str = octstr_duplicate(msg->sms.receiver);
00463     if(octstr_get_char(str,0) == '+') {
00464          /* international number format */
00465          /* EMI doesnt understand + so we have to replace it with something useful */
00466          /* we try 00 here. Should really be done in the config instead so this */
00467          /* is only a workaround to make wrong configs work  */
00468      octstr_delete(str, 0, 1);
00469      octstr_insert_data(str, 0, "00",2);
00470     }
00471     octstr_truncate(str, 16); /* max length of ADC */
00472     emimsg->fields[E50_ADC] = str;
00473    
00474     emimsg->fields[E50_XSER] = octstr_create("");
00475 
00476     /* XSer 01: UDH */
00477     if (octstr_len(msg->sms.udhdata)) {
00478         str = octstr_create("");
00479         octstr_append_char(str, 0x01);
00480         octstr_append_char(str, octstr_len(msg->sms.udhdata));
00481         octstr_append(str, msg->sms.udhdata);
00482         octstr_binary_to_hex(str, 1);
00483         octstr_append(emimsg->fields[E50_XSER], str);
00484         octstr_destroy(str);
00485     }
00486     
00487     /* XSer 02: DCS */
00488     dcs = fields_to_dcs(msg, msg->sms.alt_dcs);
00489     if (dcs != 0 && dcs != 4) {
00490         str = octstr_create("");
00491         octstr_append_char(str, 0x02);
00492         octstr_append_char(str, 1); /* len 01 */
00493         octstr_append_char(str, dcs);
00494         octstr_binary_to_hex(str, 1);
00495         octstr_append(emimsg->fields[E50_XSER], str);
00496         octstr_destroy(str);
00497     }
00498 
00499     /* XSer 0c: billing identifier */
00500     if (octstr_len(msg->sms.binfo)) {
00501         str = octstr_create("");
00502         octstr_append_char(str, 0x0c);
00503         octstr_append_char(str, octstr_len(msg->sms.binfo));
00504         octstr_append(str, msg->sms.binfo);
00505         octstr_binary_to_hex(str, 1);
00506         octstr_append(emimsg->fields[E50_XSER], str);
00507         octstr_destroy(str);
00508     }
00509 
00510     if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) {
00511     emimsg->fields[E50_MT] = octstr_create("4");
00512     emimsg->fields[E50_MCLS] = octstr_create("1");
00513     str = octstr_duplicate(msg->sms.msgdata);
00514     emimsg->fields[E50_NB] =
00515         octstr_format("%04d", 8 * octstr_len(str));
00516     octstr_binary_to_hex(str, 1);
00517     emimsg->fields[E50_TMSG] = str;
00518     }
00519     else {
00520     emimsg->fields[E50_MT] = octstr_create("3");
00521     str = octstr_duplicate(msg->sms.msgdata);
00522     charset_utf8_to_gsm(str);
00523 
00524     /*
00525      * Check if we have to apply some after GSM transcoding kludges
00526      */
00527     if (privdata->alt_charset == EMI_NRC_ISO_21)
00528         charset_gsm_to_nrc_iso_21_german(str);
00529 
00530     /* Could still be too long after truncation if there's an UDH part,
00531      * but this is only to notice errors elsewhere (should never happen).*/
00532     if (charset_gsm_truncate(str, 160))
00533         error(0, "EMI2[%s]: Message to send is longer "
00534           "than 160 gsm characters",
00535           octstr_get_cstr(privdata->name));
00536     octstr_binary_to_hex(str, 1);
00537     emimsg->fields[E50_AMSG] = str;
00538     }
00539 
00540     if (msg->sms.validity >= 0) {
00541     tm = gw_localtime(time(NULL) + msg->sms.validity * 60);
00542     sprintf(p, "%02d%02d%02d%02d%02d",
00543         tm.tm_mday, tm.tm_mon + 1, tm.tm_year % 100, 
00544         tm.tm_hour, tm.tm_min);
00545     str = octstr_create(p);
00546     emimsg->fields[E50_VP] = str;
00547     }
00548     if (msg->sms.deferred >= 0) {
00549     str = octstr_create("1");
00550     emimsg->fields[E50_DD] = str;
00551     tm = gw_localtime(time(NULL) + msg->sms.deferred * 60);
00552     sprintf(p, "%02d%02d%02d%02d%02d",
00553         tm.tm_mday, tm.tm_mon + 1, tm.tm_year % 100, 
00554         tm.tm_hour, tm.tm_min);
00555     str = octstr_create(p);
00556     emimsg->fields[E50_DDT] = str;
00557     }
00558 
00559     /* if delivery reports are asked, lets ask for them too */
00560     /* even the sender might not be interested in delivery or non delivery */
00561     /* we still need them back to clear out the memory after the message */
00562     /* has been delivered or non delivery has been confirmed */
00563     if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) {
00564     emimsg->fields[E50_NRQ] = octstr_create("1");
00565     emimsg->fields[E50_NT] = octstr_create("");
00566     octstr_append_decimal(emimsg->fields[E50_NT], 3 + (DLR_IS_BUFFERED(msg->sms.dlr_mask) ? 4 : 0));
00567     if (privdata->npid)
00568         emimsg->fields[E50_NPID] = octstr_duplicate(privdata->npid);
00569     if (privdata->nadc)
00570         emimsg->fields[E50_NADC] = octstr_duplicate(privdata->nadc); 
00571     }
00572     return emimsg;
00573 }
00574 
00575 
00576 /* Return -1 if the connection broke, 0 if the request couldn't be handled
00577  * (unknown type), or 1 if everything was successful */
00578 static int handle_operation(SMSCConn *conn, Connection *server,
00579                struct emimsg *emimsg)
00580 {
00581     struct emimsg *reply;
00582     Octstr *tempstr, *xser;
00583     int type, len;
00584     Msg *msg = NULL;
00585     struct universaltime unitime;
00586     int st_code;
00587     PrivData *privdata = conn->data;
00588 
00589 
00590     switch(emimsg->ot) {
00591 
00592     /*
00593      * Handle OP/01 call input operation. This operation delivery MO messages
00594      * from SMSC to SMT according to [1], section 4.2, p. 9.
00595      */
00596     case 01:
00597     msg = msg_create(sms);
00598     if (emimsg->fields[E01_AMSG] == NULL)
00599         emimsg->fields[E01_AMSG] = octstr_create("");
00600     else if (octstr_hex_to_binary(emimsg->fields[E01_AMSG]) == -1)
00601         warning(0, "EMI2[%s]: Couldn't decode message text",
00602             octstr_get_cstr(privdata->name));
00603 
00604     if (emimsg->fields[E01_MT] == NULL) {
00605         warning(0, "EMI2[%s]: required field MT missing",
00606             octstr_get_cstr(privdata->name));
00607         /* This guess could be incorrect, maybe the message should just
00608            be dropped */
00609         emimsg->fields[E01_MT] = octstr_create("3");
00610     }
00611 
00612     if (octstr_get_char(emimsg->fields[E01_MT], 0) == '3') {
00613         msg->sms.msgdata = emimsg->fields[E01_AMSG];
00614         emimsg->fields[E01_AMSG] = NULL; /* So it's not freed */
00615 
00616         /* obey the NRC (national replacement codes) */
00617         if (privdata->alt_charset == EMI_NRC_ISO_21)
00618             charset_nrc_iso_21_german_to_gsm(msg->sms.msgdata);
00619 
00620         charset_gsm_to_utf8(msg->sms.msgdata);
00621     }
00622     else {
00623         error(0, "EMI2[%s]: MT == %s isn't supported for operation type 01",
00624           octstr_get_cstr(privdata->name),
00625           octstr_get_cstr(emimsg->fields[E01_MT]));
00626         msg->sms.msgdata = octstr_create("");
00627     }
00628 
00629     msg->sms.sender = octstr_duplicate(emimsg->fields[E01_OADC]);
00630     if (msg->sms.sender == NULL) {
00631         warning(0, "EMI2[%s]: Empty sender field in received message",
00632             octstr_get_cstr(privdata->name));
00633         msg->sms.sender = octstr_create("");
00634     }
00635 
00636     if(octstr_len(PRIVDATA(conn)->my_number)) {
00637         msg->sms.receiver = octstr_duplicate(PRIVDATA(conn)->my_number);
00638     }
00639     else {
00640         msg->sms.receiver = octstr_duplicate(emimsg->fields[E01_ADC]);
00641     }
00642     if (msg->sms.receiver == NULL) {
00643         warning(0, "EMI2[%s]: Empty receiver field in received message",
00644             octstr_get_cstr(privdata->name));
00645         msg->sms.receiver = octstr_create("");
00646     }
00647 
00648     /* Operation type 01 doesn't have a time stamp field */
00649     time(&msg->sms.time);
00650 
00651     msg->sms.smsc_id = octstr_duplicate(conn->id);
00652     bb_smscconn_receive(conn, msg);
00653     reply = emimsg_create_reply(01, emimsg->trn, 1, privdata->name);
00654     if (emi2_emimsg_send(conn, server, reply) < 0) {
00655         emimsg_destroy(reply);
00656         return -1;
00657     }
00658     emimsg_destroy(reply);
00659     return 1;
00660 
00661     /*
00662      * Handle OP/52 delivery short message. This is the MO side of the protocol
00663      * implementation. See [1], section 5.4, p. 40.
00664      */
00665     case 52:
00666     msg = msg_create(sms);
00667     /* AMSG is the same field as TMSG */
00668     if (emimsg->fields[E50_AMSG] == NULL)
00669         emimsg->fields[E50_AMSG] = octstr_create("");
00670     else if (octstr_hex_to_binary(emimsg->fields[E50_AMSG]) == -1)
00671         warning(0, "EMI2[%s]: Couldn't decode message text",
00672               octstr_get_cstr(privdata->name));
00673 
00674     /* Process XSer fields */
00675     xser = emimsg->fields[E50_XSER];
00676     while (octstr_len(xser) > 0) {
00677         int tempint;
00678         tempstr = octstr_copy(xser, 0, 4);
00679         if (octstr_hex_to_binary(tempstr) == -1)
00680         error(0, "EMI2[%s]: Invalid XSer",
00681               octstr_get_cstr(privdata->name));
00682         type = octstr_get_char(tempstr, 0);
00683         len = octstr_get_char(tempstr, 1);
00684         octstr_destroy(tempstr);
00685         if (len < 0) {
00686         error(0, "EMI2[%s]: Malformed emi XSer field",
00687               octstr_get_cstr(privdata->name));
00688         break;
00689         }
00690 
00691         /* Handle supported XSer fields */
00692         switch (type) {
00693 
00694             case 0x01:  /* XSer 01, GSM UDH information */
00695                 tempstr = octstr_copy(xser, 4, len * 2);
00696                 if (octstr_hex_to_binary(tempstr) == -1)
00697                     error(0, "EMI2[%s]: Invalid UDH contents",
00698                           octstr_get_cstr(privdata->name));
00699                 msg->sms.udhdata = tempstr;
00700                 break;
00701 
00702             case 0x02:  /* XSer 02, GSM DCS information */
00703                 tempstr = octstr_copy(xser, 4, 2);
00704                 octstr_hex_to_binary(tempstr);
00705                 tempint = octstr_get_char(tempstr, 0);
00706                 octstr_destroy(tempstr);
00707                 if (!dcs_to_fields(&msg, tempint)) {
00708                     error(0, "EMI2[%s]: Invalid DCS received",
00709                           octstr_get_cstr(privdata->name));
00710                     /* XXX Should we discard message ? */
00711                     dcs_to_fields(&msg, 0);
00712                 }
00713                 break;
00714 
00715             /* 
00716              * XSer 03-0b are for CDMA/TDMA information exchange and are currently
00717              * not implemented in this EMI interface. See CMG EMI/UCP spec 4.6,
00718              * section 5.1.2.4 for more information.
00719              */
00720 
00721             case 0x0c:  /* XSer 0c, billing identifier */
00722                 tempstr = octstr_copy(xser, 4, len * 2);
00723                 if (octstr_hex_to_binary(tempstr) == -1) {
00724                     error(0, "EMI2[%s] Invalid XSer 0c billing identifier <%s>",
00725                           octstr_get_cstr(privdata->name), 
00726                           octstr_get_cstr(tempstr));
00727                 } else {
00728                     msg->sms.binfo = tempstr;
00729                 }
00730                 break;
00731                 
00732             case 0x0d:  /* XSer 0d, single shot indicator */
00733                 tempstr = octstr_copy(xser, 4, 2);
00734                 octstr_hex_to_binary(tempstr);
00735                 tempint = octstr_get_char(tempstr, 0);
00736                 octstr_destroy(tempstr);
00737                 if (tempint) 
00738                     info(0, "EMI2[%s]: Single shot indicator set.",
00739                          octstr_get_cstr(privdata->name));
00740                 break;
00741 
00742             /* XSer fields 0e-ff are reserved for future use and should not be used. */
00743 
00744             default:
00745                 warning(0, "EMI2[%s]: Unsupported EMI XSer field %d",
00746                         octstr_get_cstr(privdata->name), type);
00747                 break;
00748         }
00749 
00750         octstr_delete(xser, 0, 2 * len + 4);
00751     }
00752 
00753     if (emimsg->fields[E50_MT] == NULL) {
00754         warning(0, "EMI2[%s]: required field MT missing",
00755             octstr_get_cstr(privdata->name));
00756         /* This guess could be incorrect, maybe the message should just
00757            be dropped */
00758         emimsg->fields[E50_MT] = octstr_create("3");
00759     }
00760     if (octstr_get_char(emimsg->fields[E50_MT], 0) == '3') {
00761         msg->sms.msgdata = emimsg->fields[E50_AMSG];
00762         emimsg->fields[E50_AMSG] = NULL; /* So it's not freed */
00763 
00764         /* obey the NRC (national replacement codes) */
00765         if (privdata->alt_charset == EMI_NRC_ISO_21)
00766             charset_nrc_iso_21_german_to_gsm(msg->sms.msgdata);
00767 
00768         charset_gsm_to_utf8(msg->sms.msgdata);
00769     }
00770     else if (octstr_get_char(emimsg->fields[E50_MT], 0) == '4') {
00771         msg->sms.msgdata = emimsg->fields[E50_TMSG];
00772         emimsg->fields[E50_TMSG] = NULL;
00773     }
00774     else {
00775         error(0, "EMI2[%s]: MT == %s isn't supported yet",
00776           octstr_get_cstr(privdata->name),
00777           octstr_get_cstr(emimsg->fields[E50_MT]));
00778         msg->sms.msgdata = octstr_create("");
00779     }
00780 
00781     msg->sms.sender = octstr_duplicate(emimsg->fields[E50_OADC]);
00782     if (msg->sms.sender == NULL) {
00783         warning(0, "EMI2[%s]: Empty sender field in received message",
00784             octstr_get_cstr(privdata->name));
00785         msg->sms.sender = octstr_create("");
00786     }
00787 
00788     if(octstr_len(PRIVDATA(conn)->my_number)) {
00789         msg->sms.receiver = octstr_duplicate(PRIVDATA(conn)->my_number);
00790     }
00791     else {
00792         msg->sms.receiver = octstr_duplicate(emimsg->fields[E50_ADC]);
00793     }
00794     if (msg->sms.receiver == NULL) {
00795         warning(0, "EMI2[%s]: Empty receiver field in received message",
00796             octstr_get_cstr(privdata->name));
00797         msg->sms.receiver = octstr_create("");
00798     }
00799 
00800     tempstr = emimsg->fields[E50_SCTS]; /* Just a shorter name */
00801     if (tempstr == NULL) {
00802         warning(0, "EMI2[%s]: Received EMI message doesn't have required timestamp",
00803             octstr_get_cstr(privdata->name));
00804         goto notime;
00805     }
00806     if (octstr_len(tempstr) != 12) {
00807         warning(0, "EMI2[%s]: EMI SCTS field must have length 12, now %ld",
00808             octstr_get_cstr(privdata->name), octstr_len(tempstr));
00809         goto notime;
00810     }
00811     if (octstr_parse_long(&unitime.second, tempstr, 10, 10) != 12 ||
00812         (octstr_delete(tempstr, 10, 2),
00813          octstr_parse_long(&unitime.minute, tempstr, 8, 10) != 10) ||
00814         (octstr_delete(tempstr, 8, 2),
00815          octstr_parse_long(&unitime.hour, tempstr, 6, 10) != 8) ||
00816         (octstr_delete(tempstr, 6, 2),
00817          octstr_parse_long(&unitime.year, tempstr, 4, 10) != 6) ||
00818         (octstr_delete(tempstr, 4, 2),
00819          octstr_parse_long(&unitime.month, tempstr, 2, 10) != 4) ||
00820         (octstr_delete(tempstr, 2, 2),
00821          octstr_parse_long(&unitime.day, tempstr, 0, 10) != 2)) {
00822         error(0, "EMI2[%s]: EMI delivery time stamp looks malformed",
00823           octstr_get_cstr(privdata->name));
00824     notime:
00825         time(&msg->sms.time);
00826     }
00827     else {
00828         unitime.year += 2000; /* Conversion function expects full year */
00829             unitime.month -= 1; /* conversion function expects 0-based months */
00830         msg->sms.time = date_convert_universal(&unitime);
00831     }
00832 
00833     msg->sms.smsc_id = octstr_duplicate(conn->id);
00834     bb_smscconn_receive(conn, msg);
00835     reply = emimsg_create_reply(52, emimsg->trn, 1, privdata->name);
00836     if (emi2_emimsg_send(conn, server, reply) < 0) {
00837         emimsg_destroy(reply);
00838         return -1;
00839     }
00840     emimsg_destroy(reply);
00841     return 1;
00842 
00843     /*
00844      * Handle OP/53 delivery notification. See [1], section 5.5, p. 43.
00845      */
00846     case 53:        
00847     st_code = atoi(octstr_get_cstr(emimsg->fields[E50_DST]));
00848     switch(st_code)
00849     {
00850     case 0: /* delivered */
00851         msg = dlr_find((conn->id ? conn->id : privdata->name),
00852             emimsg->fields[E50_SCTS], /* timestamp */
00853             emimsg->fields[E50_OADC], /* destination */
00854             DLR_SUCCESS);
00855         break;
00856     case 1: /* buffered */
00857         msg = dlr_find((conn->id ? conn->id : privdata->name),
00858             emimsg->fields[E50_SCTS], /* timestamp */
00859             emimsg->fields[E50_OADC], /* destination */
00860             DLR_BUFFERED);
00861         break;
00862     case 2: /* not delivered */
00863         msg = dlr_find((conn->id ? conn->id : privdata->name),
00864             emimsg->fields[E50_SCTS], /* timestamp */
00865             emimsg->fields[E50_OADC], /* destination */
00866             DLR_FAIL);
00867         break;
00868     }
00869     if (msg != NULL) {     
00870         /*
00871          * Recode the msg structure with the given msgdata.
00872          * Note: the DLR URL is delivered in msg->sms.dlr_url already.
00873          */
00874         if ((emimsg->fields[E50_AMSG]) == NULL)
00875             msg->sms.msgdata = octstr_create("Delivery Report without text");
00876         else
00877             msg->sms.msgdata = octstr_duplicate(emimsg->fields[E50_AMSG]);
00878         octstr_hex_to_binary(msg->sms.msgdata);
00879         if (octstr_get_char(emimsg->fields[E50_MT], 0) == '3') {
00880             /* obey the NRC (national replacement codes) */
00881             if (privdata->alt_charset == EMI_NRC_ISO_21)
00882                 charset_nrc_iso_21_german_to_gsm(msg->sms.msgdata);
00883             charset_gsm_to_utf8(msg->sms.msgdata);
00884         }
00885         bb_smscconn_receive(conn, msg);
00886     }
00887     reply = emimsg_create_reply(53, emimsg->trn, 1, privdata->name);
00888     if (emi2_emimsg_send(conn, server, reply) < 0) {
00889         emimsg_destroy(reply);
00890         return -1;
00891     }
00892     emimsg_destroy(reply);
00893     return 1;
00894 
00895     /* 
00896      * Handle OP/31 from SMSC side. This is not "purely" spec conform since,
00897      * the protocol says "This operation can be used by a SMT to alert the SC.",
00898      * which implies semantically only the opposite way. For the sake of EMI/UCP
00899      * server implementations that send alert messages to SMTs we handle this 
00900      * without breaking any core protocol concept.
00901      *
00902      * See [1], section 4.6, p. 19.
00903      */
00904     case 31:
00905         reply = emimsg_create_reply(31, emimsg->trn, 1, privdata->name);
00906         st_code = emi2_emimsg_send(conn, server, reply);
00907         emimsg_destroy(reply);
00908         return (st_code < 0 ? -1 : 1);
00909 
00910     default:
00911     error(0, "EMI2[%s]: I don't know how to handle operation type %d", 
00912           octstr_get_cstr(privdata->name), emimsg->ot);
00913     return 0;
00914     }
00915 }
00916 
00917 /*
00918  * get all unacknowledged messages from the ringbuffer and queue them
00919  * for retransmission.
00920  */
00921 static void clear_sent(PrivData *privdata)
00922 {
00923     int i;
00924     debug("smsc.emi2", 0, "EMI2[%s]: clear_sent called",
00925       octstr_get_cstr(privdata->name));
00926     for (i = 0; i < EMI2_MAX_TRN; i++) {
00927     if (privdata->slots[i].sendtime && privdata->slots[i].sendtype == 51)
00928         gw_prioqueue_produce(privdata->outgoing_queue, privdata->slots[i].sendmsg);
00929     privdata->slots[i].sendtime = 0;
00930     }
00931     privdata->unacked = 0;
00932 }
00933 
00934 /*
00935  * wait seconds seconds for something to happen (a send SMS request, activity
00936  * on the SMSC main connection, an error or timeout) and tell the caller
00937  * what happened.
00938  */
00939 static EMI2Event emi2_wait (SMSCConn *conn, Connection *server, double seconds)
00940 {
00941     if (emi2_can_send(conn) && gw_prioqueue_len(PRIVDATA(conn)->outgoing_queue)) {
00942     return EMI2_SENDREQ;
00943     }
00944     
00945     if (server != NULL) {
00946     switch (conn_wait(server, seconds)) {
00947     case 1: return gw_prioqueue_len(PRIVDATA(conn)->outgoing_queue) ? EMI2_SENDREQ : EMI2_TIMEOUT;
00948     case 0: return EMI2_SMSCREQ;
00949     default: return EMI2_CONNERR;
00950     }
00951     } else {
00952     gwthread_sleep(seconds);
00953     return gw_prioqueue_len(PRIVDATA(conn)->outgoing_queue) ? EMI2_SENDREQ : EMI2_TIMEOUT;
00954     }
00955 }
00956 
00957 /*
00958  * obtain the next free TRN.
00959  */
00960 static int emi2_next_trn (SMSCConn *conn)
00961 {
00962 #define INC_TRN(x) ((x)=((x) + 1) % EMI2_MAX_TRN)
00963     int result;
00964     
00965     while (SLOTBUSY(conn,PRIVDATA(conn)->priv_nexttrn))
00966     INC_TRN(PRIVDATA(conn)->priv_nexttrn); /* pick unused TRN */
00967     
00968     result = PRIVDATA(conn)->priv_nexttrn;
00969     INC_TRN(PRIVDATA(conn)->priv_nexttrn);
00970 
00971     return result;
00972 #undef INC_TRN
00973 }
00974 
00975 /*
00976  * send an EMI type 31 message when required.
00977  */
00978 static int emi2_keepalive_handling (SMSCConn *conn, Connection *server)
00979 {
00980     struct emimsg *emimsg;
00981     int nexttrn = emi2_next_trn (conn);
00982     
00983     emimsg = make_emi31(PRIVDATA(conn), nexttrn);
00984     if(emimsg) {
00985         PRIVDATA(conn)->slots[nexttrn].sendtype= 31;
00986         PRIVDATA(conn)->slots[nexttrn].sendtime = time(NULL);
00987         PRIVDATA(conn)->unacked++;
00988     
00989         if (emi2_emimsg_send(conn, server, emimsg) == -1) {
00990            emimsg_destroy(emimsg);
00991            return -1;
00992         }
00993         emimsg_destroy(emimsg);
00994     }
00995     
00996     PRIVDATA(conn)->can_write = 0;
00997 
00998     return 0;
00999 }
01000 
01001 
01002 /*
01003  * the actual send logic: Send all queued messages in a burst.
01004  */
01005 static int emi2_do_send(SMSCConn *conn, Connection *server)
01006 {
01007     struct emimsg *emimsg;
01008     Msg *msg;
01009     double delay = 0;
01010 
01011     if (conn->throughput > 0) {
01012         delay = 1.0 / conn->throughput;
01013     }
01014     
01015     /* Send messages if there's room in the sending window */
01016     while (emi2_can_send(conn) &&
01017            (msg = gw_prioqueue_remove(PRIVDATA(conn)->outgoing_queue)) != NULL) {
01018         int nexttrn = emi2_next_trn(conn);
01019 
01020         if (conn->throughput > 0)
01021             gwthread_sleep(delay);
01022 
01023         /* convert the generic Kannel message into an EMI type message */
01024         emimsg = msg_to_emimsg(msg, nexttrn, PRIVDATA(conn));
01025 
01026         /* remember the message for retransmission or DLR */
01027         PRIVDATA(conn)->slots[nexttrn].sendmsg = msg;
01028         PRIVDATA(conn)->slots[nexttrn].sendtype = 51;
01029         PRIVDATA(conn)->slots[nexttrn].sendtime = time(NULL);
01030 
01031         /* send the message */
01032         if (emi2_emimsg_send(conn, server, emimsg) == -1) {
01033             emimsg_destroy(emimsg);
01034             return -1;
01035         }
01036 
01037         /* we just sent a message */
01038         PRIVDATA(conn)->unacked++;
01039 
01040         emimsg_destroy(emimsg);
01041 
01042         /*
01043          * remember that there is an open request for stop-wait flow control
01044          * FIXME: couldn't this be done with the unacked field as well? After
01045          * all stop-wait is just a window of size 1.
01046          */
01047         PRIVDATA(conn)->can_write = 0;
01048     }
01049 
01050     return 0;
01051 }
01052 
01053 static int emi2_handle_smscreq(SMSCConn *conn, Connection *server)
01054 {
01055     Octstr *str;
01056     struct emimsg *emimsg;
01057     PrivData *privdata = conn->data;
01058     
01059     /* Read acks/nacks/ops from the server */
01060     while ((str = conn_read_packet(server, 2, 3))) {
01061     debug("smsc.emi2", 0, "EMI2[%s]: Got packet from the main socket",
01062           octstr_get_cstr(privdata->name));
01063 
01064     /* parse the msg */
01065     emimsg = get_fields(str, privdata->name);
01066     octstr_destroy(str);
01067     
01068     if (emimsg == NULL) {
01069         continue; /* The parse functions logged errors */
01070     }
01071     
01072     if (emimsg->or == 'O') {
01073         /* If the SMSC wants to send operations through this
01074          * socket, we'll have to read them because there
01075          * might be ACKs too. We just drop them while stopped,
01076          * hopefully the SMSC will resend them later. */
01077         if (!conn->is_stopped) {
01078         if (handle_operation(conn, server, emimsg) < 0)
01079             return -1; /* Connection broke */
01080         } else {
01081         info(0, "EMI2[%s]: Ignoring operation from main socket "
01082              "because the connection is stopped.",
01083              octstr_get_cstr(privdata->name));
01084         }
01085     } else {   /* Already checked to be 'O' or 'R' */
01086         if (!SLOTBUSY(conn,emimsg->trn) ||
01087         emimsg->ot != PRIVDATA(conn)->slots[emimsg->trn].sendtype) {
01088         error(0, "EMI2[%s]: Got ack for TRN %d, don't remember sending O?",
01089               octstr_get_cstr(privdata->name), emimsg->trn);
01090         } else {
01091         PRIVDATA(conn)->can_write = 1;
01092         PRIVDATA(conn)->slots[emimsg->trn].sendtime = 0;
01093         PRIVDATA(conn)->unacked--;
01094 
01095         if (emimsg->ot == 51) {
01096             if (octstr_get_char(emimsg->fields[0], 0) == 'A') {
01097             /* we got an ack back. We might have to store the */
01098             /* timestamp for delivery notifications now */
01099             Octstr *ts, *adc;
01100             int i;
01101             Msg *m;
01102 
01103             ts = octstr_duplicate(emimsg->fields[2]);
01104             if (octstr_len(ts)) {
01105                 i = octstr_search_char(ts,':',0);
01106                 if (i>0) {
01107                 octstr_delete(ts,0,i+1);
01108                 adc = octstr_duplicate(emimsg->fields[2]);
01109                 octstr_truncate(adc,i);
01110 
01111                 m = PRIVDATA(conn)->slots[emimsg->trn].sendmsg;
01112                 if(m == NULL) {
01113                     info(0,"EMI2[%s]: uhhh m is NULL, very bad",
01114                      octstr_get_cstr(privdata->name));
01115                 } else if (DLR_IS_ENABLED_DEVICE(m->sms.dlr_mask)) {
01116                     dlr_add((conn->id ? conn->id : privdata->name), ts, m);
01117                 }
01118                 octstr_destroy(ts);
01119                 octstr_destroy(adc);
01120                 } else {
01121                 octstr_destroy(ts);
01122                 }
01123             }
01124             /*
01125              * report the successful transmission to the generic bb code.
01126              */
01127             bb_smscconn_sent(conn,
01128                 PRIVDATA(conn)->slots[emimsg->trn].sendmsg,
01129                 NULL);
01130             } else {
01131                 Octstr *reply;
01132 
01133                         /* create reply message */
01134                         reply = octstr_create("");
01135                         octstr_append(reply, emimsg->fields[1]);
01136                         octstr_append_char(reply, '-');
01137                         /* system message is optional */
01138                         if (emimsg->fields[2] != NULL)
01139                             octstr_append(reply, emimsg->fields[2]);
01140 
01141             /* XXX Process error code here
01142             long errorcode;
01143             octstr_parse_long(&errorcode, emimsg->fields[1], 0, 10);
01144             ... switch(errorcode) ...
01145             }
01146 
01147             else { */
01148                 bb_smscconn_send_failed(conn,
01149                     PRIVDATA(conn)->slots[emimsg->trn].sendmsg,
01150                     SMSCCONN_FAILED_REJECTED, reply);
01151             /* } */
01152             }
01153         } else if (emimsg->ot == 31) {
01154             /* XXX Process error codes here
01155             if (octstr_get_char(emimsg->fields[0], 0) == 'N') {
01156             long errorcode;
01157             octstr_parse_long(&errorcode, emimsg->fields[1], 0, 10);
01158             ... switch errorcode ...
01159             }
01160 
01161             else { */
01162             ;
01163             /* } */
01164         } else {
01165             panic(0, "EMI2[%s]: Bug, ACK handler missing for sent packet",
01166               octstr_get_cstr(privdata->name));
01167         }
01168         }
01169     }
01170     emimsg_destroy(emimsg);
01171     }
01172 
01173     if (conn_error(server)) {
01174     error(0, "EMI2[%s]: Error trying to read ACKs from SMSC",
01175           octstr_get_cstr(privdata->name));
01176     return -1;
01177     }
01178     
01179     if (conn_eof(server)) {
01180     info(0, "EMI2[%s]: Main connection closed by SMSC",
01181          octstr_get_cstr(privdata->name));
01182     return -1;
01183     }
01184 
01185     return 0;
01186 }
01187 
01188 static void emi2_idleprocessing(SMSCConn *conn, Connection **server)
01189 {
01190     time_t current_time;
01191     int i;
01192     PrivData *privdata = conn->data;
01193     
01194     /*
01195      * Check whether there are messages the server hasn't acked in a
01196      * reasonable time
01197      */
01198     current_time = time(NULL);
01199     
01200     if (PRIVDATA(conn)->unacked && (current_time > (PRIVDATA(conn)->check_time + 30))) {
01201     PRIVDATA(conn)->check_time = current_time;
01202         for (i = 0; i < PRIVDATA(conn)->window; i++) {
01203         if (SLOTBUSY(conn,i)
01204         && PRIVDATA(conn)->slots[i].sendtime < (current_time - PRIVDATA(conn)->waitack)) {
01205 
01206                 if (PRIVDATA(conn)->slots[i].sendtype == 51) {
01207                     if (PRIVDATA(conn)->waitack_expire == 0x00) {
01208                         /* 0x00 - disconnect/reconnect */
01209                         warning(0, "EMI2[%s]: received neither ACK nor NACK for message %d "
01210                             "in %d seconds, disconnecting and reconnection",
01211                             octstr_get_cstr(privdata->name), i, PRIVDATA(conn)->waitack);
01212         PRIVDATA(conn)->slots[i].sendtime = 0;
01213         PRIVDATA(conn)->unacked--;
01214                         info(0, "EMI2[%s]: closing connection.",
01215                                   octstr_get_cstr(privdata->name));
01216                         conn_destroy(*server);
01217                         *server = NULL;
01218                         break;
01219                     } else if (PRIVDATA(conn)->waitack_expire == 0x01) {
01220                         /* 0x01 - resend */
01221             warning(0, "EMI2[%s]: received neither ACK nor NACK for message %d " 
01222                 "in %d seconds, resending message", octstr_get_cstr(privdata->name),
01223                 i, PRIVDATA(conn)->waitack);
01224             gw_prioqueue_produce(PRIVDATA(conn)->outgoing_queue,
01225                  PRIVDATA(conn)->slots[i].sendmsg);
01226                         PRIVDATA(conn)->slots[i].sendtime = 0;
01227                         PRIVDATA(conn)->unacked--;
01228             if (PRIVDATA(conn)->flowcontrol) PRIVDATA(conn)->can_write=1;
01229             /* Wake up this same thread to send again
01230              * (simpler than avoiding sleep) */
01231             gwthread_wakeup(PRIVDATA(conn)->sender_thread);
01232                     } else if (PRIVDATA(conn)->waitack_expire == 0x02) {
01233                         /* 0x02 - carry on waiting */
01234                            warning(0, "EMI2[%s]: received neither ACK nor NACK for message %d "
01235                                 "in %d seconds, carrying on waiting", octstr_get_cstr(privdata->name),
01236                                 i, PRIVDATA(conn)->waitack);
01237                     }
01238         } else if (PRIVDATA(conn)->slots[i].sendtype == 31) {
01239             warning(0, "EMI2[%s]: Alert (operation 31) was not "
01240                 "ACKed within %d seconds", octstr_get_cstr(privdata->name),
01241                 PRIVDATA(conn)->waitack);
01242             if (PRIVDATA(conn)->flowcontrol) PRIVDATA(conn)->can_write=1;
01243         } else {
01244             panic(0, "EMI2[%s]: Bug, no timeout handler for sent packet",
01245               octstr_get_cstr(privdata->name));
01246         }
01247         }
01248     }
01249     }
01250 }
01251 
01252 static void emi2_idletimeout_handling (SMSCConn *conn, Connection **server)
01253 {
01254     PrivData *privdata = conn->data;
01255 
01256     /*
01257      * close the connection if there was no activity.
01258      */
01259     if ((*server != NULL) && CONNECTIONIDLE(conn)) {
01260     info(0, "EMI2[%s]: closing idle connection.",
01261          octstr_get_cstr(privdata->name));
01262     conn_destroy(*server);
01263     *server = NULL;
01264     }
01265 }
01266 
01267 /*
01268  * this function calculates the new timeouttime.
01269  */
01270 static double emi2_get_timeouttime (SMSCConn *conn, Connection *server)
01271 {
01272     double ka_timeouttime = PRIVDATA(conn)->keepalive ? PRIVDATA(conn)->keepalive + 1 : DBL_MAX;
01273     double idle_timeouttime = (PRIVDATA(conn)->idle_timeout && server) ? PRIVDATA(conn)->idle_timeout : DBL_MAX;
01274     double result = ka_timeouttime < idle_timeouttime ? ka_timeouttime : idle_timeouttime;
01275 
01276     if (result == DBL_MAX)
01277     result = 30;
01278 
01279     return result;
01280 }
01281 
01282 /*
01283  * the main event processing loop.
01284  */
01285 static void emi2_send_loop(SMSCConn *conn, Connection **server)
01286 {
01287     PrivData *privdata = conn->data;
01288 
01289     for (;;) {
01290     double timeouttime;
01291     EMI2Event event;
01292     
01293     if (emi2_needs_keepalive (conn)) {
01294         if (*server == NULL) {
01295         return; /* reopen the connection */
01296         }
01297         
01298         emi2_keepalive_handling (conn, *server);
01299     }
01300     
01301     timeouttime = emi2_get_timeouttime (conn, *server);
01302     
01303     event = emi2_wait (conn, *server, timeouttime);
01304     
01305     switch (event) {
01306     case EMI2_CONNERR:
01307         return;
01308         
01309     case EMI2_SENDREQ:
01310         if (*server == NULL) {
01311         return; /* reopen the connection */
01312         }
01313         
01314         if (emi2_do_send (conn, *server) < 0) {
01315         return; /* reopen the connection */
01316         }
01317         break;
01318         
01319     case EMI2_SMSCREQ:
01320         if (emi2_handle_smscreq (conn, *server) < 0) {
01321         return; /* reopen the connection */
01322         }
01323         break;
01324         
01325     case EMI2_TIMEOUT:
01326         break;
01327     }
01328 
01329         if ((*server !=NULL) && (emi2_handle_smscreq (conn, *server) < 0)) {
01330             return; /* reopen the connection */
01331         }
01332     
01333     emi2_idleprocessing (conn, server);
01334     emi2_idletimeout_handling (conn, server);
01335 
01336     if (PRIVDATA(conn)->shutdown && (PRIVDATA(conn)->unacked == 0)) {
01337         /* shutdown and no open messages */
01338         break;
01339     }
01340 
01341     if (*server != NULL) {
01342         if (conn_error(*server)) {
01343         warning(0, "EMI2[%s]: Error reading from the main connection",
01344             octstr_get_cstr(privdata->name));
01345         break;
01346         }
01347     
01348         if (conn_eof(*server)) {
01349         info(0, "EMI2[%s]: Main connection closed by SMSC",
01350              octstr_get_cstr(privdata->name));
01351         break;
01352         }
01353     }
01354     }
01355 }
01356 
01357 static void emi2_sender(void *arg)
01358 {
01359     SMSCConn *conn = arg;
01360     PrivData *privdata = conn->data;
01361     Msg *msg;
01362     Connection *server;
01363 
01364     /* Make sure we log into our own log-file if defined */
01365     log_thread_to(conn->log_idx);
01366 
01367     while (!privdata->shutdown) {
01368     if ((server = open_send_connection(conn)) == NULL) {
01369         privdata->shutdown = 1;
01370         if (privdata->rport > 0)
01371         gwthread_wakeup(privdata->receiver_thread);
01372         break;
01373     }
01374     emi2_send_loop(conn, &server);
01375     clear_sent(privdata);
01376 
01377     if (server != NULL) {
01378         conn_destroy(server);
01379     }
01380     }
01381 
01382     while((msg = gw_prioqueue_remove(privdata->outgoing_queue)) != NULL)
01383     bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL);
01384     if (privdata->rport > 0)
01385     gwthread_join(privdata->receiver_thread);
01386     mutex_lock(conn->flow_mutex);
01387 
01388     conn->status = SMSCCONN_DEAD;
01389 
01390     debug("bb.sms", 0, "EMI2[%s]: connection has completed shutdown.",
01391       octstr_get_cstr(privdata->name));
01392 
01393     gw_prioqueue_destroy(privdata->outgoing_queue, NULL);
01394     octstr_destroy(privdata->name);
01395     octstr_destroy(privdata->allow_ip);
01396     octstr_destroy(privdata->deny_ip);
01397     octstr_destroy(privdata->host);
01398     octstr_destroy(privdata->alt_host);
01399     octstr_destroy(privdata->my_number);
01400     octstr_destroy(privdata->username);
01401     octstr_destroy(privdata->password);
01402     octstr_destroy(privdata->npid);
01403     octstr_destroy(privdata->nadc);
01404     gw_free(privdata);
01405     conn->data = NULL;
01406 
01407     mutex_unlock(conn->flow_mutex);
01408     bb_smscconn_killed();
01409 }
01410 
01411 
01412 static void emi2_receiver(SMSCConn *conn, Connection *server)
01413 {
01414     PrivData *privdata = conn->data;
01415     Octstr *str;
01416     struct emimsg *emimsg;
01417 
01418     while (1) {
01419     if (conn_eof(server)) {
01420         info(0, "EMI2[%s]: receive connection closed by SMSC",
01421          octstr_get_cstr(privdata->name));
01422         return;
01423     }
01424     if (conn_error(server)) {
01425         error(0, "EMI2[%s]: receive connection broken",
01426           octstr_get_cstr(privdata->name));
01427         return;
01428     }
01429     if (conn->is_stopped)
01430         str = NULL;
01431     else
01432         str = conn_read_packet(server, 2, 3);
01433     if (str) {
01434         debug("smsc.emi2", 0, "EMI2[%s]: Got packet from the receive connection.",
01435           octstr_get_cstr(privdata->name));
01436         if ( (emimsg = get_fields(str, privdata->name)) ) {
01437         if (emimsg->or == 'O') {
01438             if (handle_operation(conn, server, emimsg) < 0) {
01439             emimsg_destroy(emimsg);
01440             return;
01441             }
01442         }
01443         else
01444             error(0, "EMI2[%s]: No ACKs expected on receive connection!",
01445               octstr_get_cstr(privdata->name));
01446         emimsg_destroy(emimsg);
01447         }
01448         octstr_destroy(str);
01449     }
01450     else
01451         conn_wait(server, -1);
01452     if (privdata->shutdown)
01453         break;
01454     }
01455     return;
01456 }
01457 
01458 
01459 static int emi2_open_listening_socket(SMSCConn *conn, PrivData *privdata)
01460 {
01461     int s;
01462 
01463     if ( (s = make_server_socket(privdata->rport, (conn->our_host ? octstr_get_cstr(conn->our_host) : NULL))) == -1) {
01464     error(0, "EMI2[%s]: could not create listening socket in port %d",
01465           octstr_get_cstr(privdata->name), privdata->rport);
01466     return -1;
01467     }
01468     if (socket_set_blocking(s, 0) == -1) {
01469     error(0, "EMI2[%s]: couldn't make listening socket port %d "
01470          "non-blocking", octstr_get_cstr(privdata->name), privdata->rport);
01471     close(s);
01472     return -1;
01473     }
01474     privdata->listening_socket = s;
01475     return 0;
01476 }
01477 
01478 
01479 static void emi2_listener(void *arg)
01480 {
01481     SMSCConn    *conn = arg;
01482     PrivData    *privdata = conn->data;
01483     struct sockaddr_in server_addr;
01484     socklen_t   server_addr_len;
01485     Octstr  *ip;
01486     Connection  *server;
01487     int     s, ret;
01488 
01489     /* Make sure we log into our own log-file if defined */
01490     log_thread_to(conn->log_idx);
01491 
01492     while (!privdata->shutdown) {
01493     server_addr_len = sizeof(server_addr);
01494     ret = gwthread_pollfd(privdata->listening_socket, POLLIN, -1);
01495     if (ret == -1) {
01496         if (errno == EINTR)
01497         continue;
01498         error(0, "EMI2[%s]: Poll for emi2 smsc connections failed, shutting down",
01499           octstr_get_cstr(privdata->name));
01500         break;
01501     }
01502     if (privdata->shutdown)
01503         break;
01504     if (ret == 0) /* This thread was woken up from elsewhere, but
01505              if we're not shutting down nothing to do here. */
01506         continue;
01507     s = accept(privdata->listening_socket, (struct sockaddr *)&server_addr,
01508            &server_addr_len);
01509     if (s == -1) {
01510         warning(errno, "EMI2[%s]: emi2_listener: accept() failed, retrying...",
01511             octstr_get_cstr(privdata->name));
01512         continue;
01513     }
01514     ip = host_ip(server_addr);
01515     if (!is_allowed_ip(privdata->allow_ip, privdata->deny_ip, ip)) {
01516         info(0, "EMI2[%s]: smsc connection tried from denied host <%s>,"
01517          " disconnected", octstr_get_cstr(privdata->name), 
01518          octstr_get_cstr(ip));
01519         octstr_destroy(ip);
01520         close(s);
01521         continue;
01522     }
01523     server = conn_wrap_fd(s, 0);
01524     if (server == NULL) {
01525         error(0, "EMI2[%s]: emi2_listener: conn_wrap_fd failed on accept()ed fd",
01526           octstr_get_cstr(privdata->name));
01527         octstr_destroy(ip);
01528         close(s);
01529         continue;
01530     }
01531     conn_claim(server);
01532     info(0, "EMI2[%s]: smsc connected from %s", 
01533          octstr_get_cstr(privdata->name), octstr_get_cstr(ip));
01534     octstr_destroy(ip);
01535 
01536     emi2_receiver(conn, server);
01537     conn_destroy(server);
01538     }
01539     if (close(privdata->listening_socket) == -1)
01540     warning(errno, "EMI2[%s]: couldn't close listening socket "
01541         "at shutdown", octstr_get_cstr(privdata->name));
01542     gwthread_wakeup(privdata->sender_thread);
01543 }
01544 
01545 
01546 static int add_msg_cb(SMSCConn *conn, Msg *sms)
01547 {
01548     PrivData *privdata = conn->data;
01549     Msg *copy;
01550 
01551     copy = msg_duplicate(sms);
01552     gw_prioqueue_produce(privdata->outgoing_queue, copy);
01553     gwthread_wakeup(privdata->sender_thread);
01554 
01555     return 0;
01556 }
01557 
01558 
01559 static int shutdown_cb(SMSCConn *conn, int finish_sending)
01560 {
01561     PrivData *privdata = conn->data;
01562 
01563     debug("bb.sms", 0, "EMI2[%s]: Shutting down SMSCConn EMI2, %s",
01564       octstr_get_cstr(privdata->name), 
01565       finish_sending ? "slow" : "instant");
01566 
01567     /* Documentation claims this would have been done by smscconn.c,
01568        but isn't when this code is being written. */
01569     conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
01570     privdata->shutdown = 1; /* Separate from why_killed to avoid locking, as
01571                why_killed may be changed from outside? */
01572 
01573     if (finish_sending == 0) {
01574     Msg *msg;
01575     while((msg = gw_prioqueue_remove(privdata->outgoing_queue)) != NULL) {
01576         bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_SHUTDOWN, NULL);
01577     }
01578     }
01579 
01580     if (privdata->rport > 0)
01581     gwthread_wakeup(privdata->receiver_thread);
01582     return 0;
01583 }
01584 
01585 
01586 static void start_cb(SMSCConn *conn)
01587 {
01588     PrivData *privdata = conn->data;
01589 
01590     /* in case there are messages in the buffer already */
01591     if (privdata->rport > 0)
01592     gwthread_wakeup(privdata->receiver_thread);
01593     debug("smsc.emi2", 0, "EMI2[%s]: start called",
01594       octstr_get_cstr(privdata->name));
01595 }
01596 
01597 
01598 static long queued_cb(SMSCConn *conn)
01599 {
01600     PrivData *privdata = conn->data;
01601     long ret;
01602 
01603     ret = (privdata ? gw_prioqueue_len(privdata->outgoing_queue) : 0);
01604 
01605     /* use internal queue as load, maybe something else later */
01606 
01607     conn->load = ret;
01608     return ret;
01609 }
01610 
01611 
01612 int smsc_emi2_create(SMSCConn *conn, CfgGroup *cfg)
01613 {
01614     PrivData *privdata;
01615     Octstr *allow_ip, *deny_ip, *host, *alt_host;
01616     long portno, our_port, keepalive, flowcontrol, waitack, 
01617          idle_timeout, alt_portno, alt_charset, waitack_expire;
01618     long window;
01619         /* has to be long because of cfg_get_integer */
01620     int i;
01621 
01622     allow_ip = deny_ip = host = alt_host = NULL; 
01623 
01624     privdata = gw_malloc(sizeof(PrivData));
01625     privdata->outgoing_queue = gw_prioqueue_create(sms_priority_compare);
01626     privdata->listening_socket = -1;
01627     privdata->can_write = 1;
01628     privdata->priv_nexttrn = 0;
01629     privdata->last_activity_time = 0;
01630     privdata->check_time = 0;
01631     
01632     host = cfg_get(cfg, octstr_imm("host"));
01633     if (host == NULL) {
01634     error(0, "EMI2[-]: 'host' missing in emi2 configuration.");
01635     goto error;
01636     }
01637     privdata->host = host;
01638 
01639     if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1)
01640     portno = 0;
01641     privdata->port = portno;
01642     if (privdata->port <= 0 || privdata->port > 65535) {
01643     error(0, "EMI2[%s]: 'port' missing/invalid in emi2 configuration.",
01644           octstr_get_cstr(host));
01645     goto error;
01646     }
01647 
01648     if (cfg_get_integer(&our_port, cfg, octstr_imm("our-port")) == -1)
01649     privdata->our_port = 0; /* 0 means use any port */
01650     else
01651     privdata->our_port = our_port;
01652 
01653     privdata->name = cfg_get(cfg, octstr_imm("smsc-id"));
01654     if(privdata->name == NULL) {
01655     privdata->name = octstr_create("");
01656 
01657     /* Add our_host */
01658     if(octstr_len(conn->our_host)) {
01659         octstr_append(privdata->name, conn->our_host);
01660     }
01661 
01662     /* Add our_port */
01663     if(privdata->our_port != 0) {
01664         /* if we have our_port but not our_host, add kannel:our_port */
01665         if(octstr_len(privdata->name) == 0) {
01666         octstr_append(privdata->name, octstr_imm("kannel"));
01667         }
01668         octstr_append_char(privdata->name, ':');
01669         octstr_append_decimal(privdata->name, privdata->our_port);
01670     } else {
01671         if(octstr_len(privdata->name) != 0) {
01672         octstr_append(privdata->name, octstr_imm(":*"));
01673         }
01674     }
01675         
01676     /* if we have our_host neither our_port */
01677     if(octstr_len(privdata->name) != 0)
01678         octstr_append(privdata->name, octstr_imm("->"));
01679 
01680     octstr_append(privdata->name, privdata->host);
01681     octstr_append_char(privdata->name, ':');
01682     octstr_append_decimal(privdata->name, privdata->port);
01683     }
01684 
01685 
01686     if (cfg_get_integer(&idle_timeout, cfg, octstr_imm("idle-timeout")) == -1)
01687     idle_timeout = 0;
01688     
01689     privdata->idle_timeout = idle_timeout;
01690 
01691     alt_host = cfg_get(cfg, octstr_imm("alt-host"));
01692     privdata->alt_host = alt_host;
01693 
01694     if (cfg_get_integer(&portno, cfg, octstr_imm("receive-port")) < 0)
01695     portno = 0;
01696     privdata->rport = portno;
01697 
01698     if (cfg_get_integer(&alt_portno, cfg, octstr_imm("alt-port")) < 0) 
01699     alt_portno = 0;
01700     privdata->alt_port = alt_portno;
01701 
01702     allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip"));
01703     if (allow_ip)
01704     deny_ip = octstr_create("*.*.*.*");
01705     else
01706     deny_ip = NULL;
01707     privdata->username = cfg_get(cfg, octstr_imm("smsc-username"));
01708     privdata->password = cfg_get(cfg, octstr_imm("smsc-password"));
01709 
01710     privdata->my_number = cfg_get(cfg, octstr_imm("my-number"));
01711 
01712     privdata->npid = cfg_get(cfg, octstr_imm("notification-pid"));
01713     privdata->nadc = cfg_get(cfg, octstr_imm("notification-addr"));
01714     
01715     if ( (privdata->username == NULL && privdata->my_number == NULL)
01716          || cfg_get_integer(&keepalive, cfg, octstr_imm("keepalive")) < 0)
01717     privdata->keepalive = 0;
01718     else
01719     privdata->keepalive = keepalive;
01720 
01721     if (cfg_get_integer(&flowcontrol, cfg, octstr_imm("flow-control")) < 0)
01722     privdata->flowcontrol = 0;
01723     else
01724     privdata->flowcontrol = flowcontrol;
01725     if (privdata->flowcontrol < 0 || privdata->flowcontrol > 1) {
01726     error(0, "EMI2[%s]: 'flow-control' invalid in emi2 configuration.",
01727           octstr_get_cstr(privdata->name));
01728     goto error;
01729     }
01730 
01731     if (cfg_get_integer(&window, cfg, octstr_imm("window")) < 0)
01732     privdata->window = EMI2_MAX_TRN;
01733     else
01734     privdata->window = window;
01735     if (privdata->window > EMI2_MAX_TRN) {
01736     warning(0, "EMI2[%s]: Value of 'window' should be lesser or equal to %d..", 
01737         octstr_get_cstr(privdata->name), EMI2_MAX_TRN);
01738     privdata->window = EMI2_MAX_TRN;
01739     }
01740 
01741     if (cfg_get_integer(&waitack, cfg, octstr_imm("wait-ack")) < 0)
01742     privdata->waitack = 60;
01743     else
01744     privdata->waitack = waitack;
01745     if (privdata->waitack < 30 ) {
01746     error(0, "EMI2[%s]: 'wait-ack' invalid in emi2 configuration.",
01747           octstr_get_cstr(privdata->name));
01748     goto error;
01749     }
01750 
01751     if (cfg_get_integer(&waitack_expire, cfg, octstr_imm("wait-ack-expire")) < 0)
01752     privdata->waitack_expire = 0;
01753     else
01754     privdata->waitack_expire = waitack_expire;
01755     if (privdata->waitack_expire >3  ) {
01756     error(0, "EMI2[%s]: 'wait-ack-expire' invalid in emi2 configuration.",
01757           octstr_get_cstr(privdata->name));
01758     goto error;
01759     }
01760 
01761     if (privdata->rport < 0 || privdata->rport > 65535) {
01762     error(0, "EMI2[%s]: 'receive-port' missing/invalid in emi2 configuration.",
01763           octstr_get_cstr(privdata->name));
01764     goto error;
01765     }
01766 
01767     if (cfg_get_integer(&alt_charset, cfg, octstr_imm("alt-charset")) < 0)
01768         privdata->alt_charset = 0;
01769     else
01770         privdata->alt_charset = alt_charset;    
01771 
01772     privdata->allow_ip = allow_ip;
01773     privdata->deny_ip = deny_ip;
01774 
01775     if (privdata->rport > 0 && emi2_open_listening_socket(conn,privdata) < 0) {
01776     gw_free(privdata);
01777     privdata = NULL;
01778     goto error;
01779     }
01780 
01781     conn->data = privdata;
01782 
01783     conn->name = octstr_format("EMI2:%S:%d:%S", privdata->host, privdata->port,
01784                                privdata->username ? privdata->username : octstr_imm("null"));
01785 
01786     privdata->shutdown = 0;
01787 
01788     for (i = 0; i < EMI2_MAX_TRN; i++)
01789     privdata->slots[i].sendtime = 0;
01790     privdata->unacked = 0;
01791 
01792     conn->status = SMSCCONN_CONNECTING;
01793     conn->connect_time = time(NULL);
01794 
01795     if ( privdata->rport > 0 && (privdata->receiver_thread =
01796       gwthread_create(emi2_listener, conn)) == -1)
01797       goto error;
01798 
01799     if ((privdata->sender_thread = gwthread_create(emi2_sender, conn)) == -1) {
01800     privdata->shutdown = 1;
01801     if (privdata->rport > 0) {
01802         gwthread_wakeup(privdata->receiver_thread);
01803         gwthread_join(privdata->receiver_thread);
01804     }
01805     goto error;
01806     }
01807 
01808     conn->shutdown = shutdown_cb;
01809     conn->queued = queued_cb;
01810     conn->start_conn = start_cb;
01811     conn->send_msg = add_msg_cb;
01812 
01813     return 0;
01814 
01815 error:
01816     error(0, "EMI2[%s]: Failed to create emi2 smsc connection",
01817       octstr_get_cstr(privdata->name));
01818     if (privdata != NULL) {
01819     gw_prioqueue_destroy(privdata->outgoing_queue, NULL);
01820     }
01821     gw_free(privdata);
01822     octstr_destroy(allow_ip);
01823     octstr_destroy(deny_ip);
01824     octstr_destroy(host);
01825     conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT;
01826     conn->status = SMSCCONN_DEAD;
01827     info(0, "EMI2[%s]: exiting", octstr_get_cstr(privdata->name));
01828     return -1;
01829 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.