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

smsc_http.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_http.c - interface to various HTTP based content/SMS gateways
00059  *
00060  * HTTP based "SMSC Connection" is meant for gateway connections,
00061  * and has following features:
00062  *
00063  * o Kannel listens to certain (HTTP server) port for MO SMS messages.
00064  *   The exact format of these HTTP calls are defined by type of HTTP based
00065  *   connection. Kannel replies to these messages as ACK, but does not
00066  *   support immediate reply. Thus, if Kannel is linked to another Kannel,
00067  *   only 'max-messages = 0' services are practically supported - any
00068  *   replies must be done with SMS PUSH (sendsms)
00069  *
00070  * o For MT messages, Kannel does HTTP GET or POST to given address, in format
00071  *   defined by type of HTTP based protocol
00072  *
00073  * The 'type' of requests and replies are defined by 'system-type' variable.
00074  * The only type of HTTP requests currently supported are basic Kannel.
00075  * If new support is added, smsc_http_create is modified accordingly and new
00076  * functions added.
00077  *
00078  *
00079  * KANNEL->KANNEL linking: (UDH not supported in MO messages)
00080  *
00081  *****
00082  * FOR CLIENT/END-POINT KANNEL:
00083  *
00084  *  group = smsc
00085  *  smsc = http
00086  *  system-type = kannel
00087  *  port = NNN
00088  *  smsc-username = XXX
00089  *  smsc-password = YYY
00090  *  send-url = "server.host:PORT"
00091  *
00092  *****
00093  * FOR SERVER/RELAY KANNEL:
00094  *
00095  *  group = smsbox
00096  *  sendsms-port = PORT
00097  *  ...
00098  * 
00099  *  group = sms-service
00100  *  keyword = ...
00101  *  url = "client.host:NNN/sms?user=XXX&pass=YYY&from=%p&to=%P&text=%a"
00102  *  max-messages = 0
00103  *
00104  *  group = send-sms
00105  *  username = XXX
00106  *  password = YYY
00107  *  
00108  * Kalle Marjola for Project Kannel 2001
00109  * Stipe Tolj <st@tolj.org>
00110  * Alexander Malysh <amalysh at kannel.org>
00111  * Tobias Weber <weber@wapme.de>
00112  */
00113 
00114 #include <sys/types.h>
00115 #include <sys/socket.h>
00116 #include <unistd.h>
00117 #include <errno.h>
00118 #include <time.h>
00119 #include <limits.h>
00120 
00121 #include "gwlib/gwlib.h"
00122 #include "smscconn.h"
00123 #include "smscconn_p.h"
00124 #include "bb_smscconn_cb.h"
00125 #include "msg.h"
00126 #include "sms.h"
00127 #include "dlr.h"
00128 #include "urltrans.h"
00129 
00130 #define DEFAULT_CHARSET "UTF-8"
00131 
00132 typedef struct conndata {
00133     HTTPCaller *http_ref;
00134     long receive_thread;
00135     long send_cb_thread;
00136     int shutdown;
00137     int port;   /* port for receiving SMS'es */
00138     Octstr *allow_ip;
00139     Octstr *send_url;
00140     Octstr *dlr_url;    /* our own DLR MO URL */
00141     long open_sends;
00142     Octstr *username;   /* if needed */
00143     Octstr *password;   /* as said */
00144     Octstr *system_id;  /* api id for clickatell */
00145     int no_sender;      /* ditto */
00146     int no_coding;      /* this, too */
00147     int no_sep;         /* not to mention this */
00148     Octstr *proxy;      /* proxy a constant string */
00149     Octstr *alt_charset;    /* alternative charset use */
00150 
00151     /* The following are compiled regex for the 'generic' type for handling 
00152      * success, permanent failure and temporary failure. For types that use
00153      * simple HTTP body parsing, these may be used also for other types,
00154      * ie. for our own Kannel reply parsing. */
00155     regex_t *success_regex;   
00156     regex_t *permfail_regex;
00157     regex_t *tempfail_regex;
00158 
00159     /* callback functions set by HTTP-SMSC type */
00160     void (*send_sms) (SMSCConn *conn, Msg *msg);
00161     void (*parse_reply) (SMSCConn *conn, Msg *msg, int status,
00162                          List *headers, Octstr *body);
00163     void (*receive_sms) (SMSCConn *conn, HTTPClient *client,
00164                          List *headers, Octstr *body, List *cgivars);
00165 } ConnData;
00166 
00167 
00168 static void conndata_destroy(ConnData *conndata)
00169 {
00170     if (conndata == NULL)
00171         return;
00172     if (conndata->http_ref)
00173         http_caller_destroy(conndata->http_ref);
00174     if (conndata->success_regex)
00175         gw_regex_destroy(conndata->success_regex);
00176     if (conndata->permfail_regex)
00177         gw_regex_destroy(conndata->permfail_regex);
00178     if (conndata->tempfail_regex)
00179         gw_regex_destroy(conndata->tempfail_regex);
00180     octstr_destroy(conndata->allow_ip);
00181     octstr_destroy(conndata->send_url);
00182     octstr_destroy(conndata->dlr_url);
00183     octstr_destroy(conndata->username);
00184     octstr_destroy(conndata->password);
00185     octstr_destroy(conndata->proxy);
00186     octstr_destroy(conndata->system_id);
00187     octstr_destroy(conndata->alt_charset);
00188 
00189     gw_free(conndata);
00190 }
00191 
00192 
00193 /*
00194  * Thread to listen to HTTP requests from SMSC entity
00195  */
00196 static void httpsmsc_receiver(void *arg)
00197 {
00198     SMSCConn *conn = arg;
00199     ConnData *conndata = conn->data;
00200     HTTPClient *client;
00201     Octstr *ip, *url, *body;
00202     List *headers, *cgivars;
00203 
00204     ip = url = body = NULL;
00205     headers = cgivars = NULL;
00206 
00207     /* Make sure we log into our own log-file if defined */
00208     log_thread_to(conn->log_idx);
00209  
00210     while (conndata->shutdown == 0) {
00211 
00212         /* XXX if conn->is_stopped, do not receive new messages.. */
00213     
00214         client = http_accept_request(conndata->port, &ip, &url,
00215                                      &headers, &body, &cgivars);
00216         if (client == NULL)
00217             break;
00218 
00219         debug("smsc.http", 0, "HTTP[%s]: Got request `%s'", 
00220               octstr_get_cstr(conn->id), octstr_get_cstr(url));
00221 
00222         if (connect_denied(conndata->allow_ip, ip)) {
00223             info(0, "HTTP[%s]: Connection `%s' tried from denied "
00224                     "host %s, ignored", octstr_get_cstr(conn->id),
00225                     octstr_get_cstr(url), octstr_get_cstr(ip));
00226             http_close_client(client);
00227         } else
00228             conndata->receive_sms(conn, client, headers, body, cgivars);
00229 
00230         debug("smsc.http", 0, "HTTP[%s]: Destroying client information",
00231               octstr_get_cstr(conn->id));
00232         octstr_destroy(url);
00233         octstr_destroy(ip);
00234         octstr_destroy(body);
00235         http_destroy_headers(headers);
00236         http_destroy_cgiargs(cgivars);
00237     }
00238     debug("smsc.http", 0, "HTTP[%s]: httpsmsc_receiver dying",
00239           octstr_get_cstr(conn->id));
00240 
00241     conndata->shutdown = 1;
00242     http_close_port(conndata->port);
00243     
00244     /* unblock http_receive_result() if there are no open sends */
00245     if (conndata->open_sends == 0)
00246         http_caller_signal_shutdown(conndata->http_ref);
00247 }
00248 
00249 
00250 /*
00251  * Thread to handle finished sendings
00252  */
00253 static void httpsmsc_send_cb(void *arg)
00254 {
00255     SMSCConn *conn = arg;
00256     ConnData *conndata = conn->data;
00257     Msg *msg;
00258     int status;
00259     List *headers;
00260     Octstr *final_url, *body;
00261 
00262     /* Make sure we log into our own log-file if defined */
00263     log_thread_to(conn->log_idx);
00264 
00265     while (conndata->shutdown == 0 || conndata->open_sends) {
00266 
00267         msg = http_receive_result(conndata->http_ref, &status,
00268                                   &final_url, &headers, &body);
00269 
00270         if (msg == NULL)
00271             break;  /* they told us to die, by unlocking */
00272 
00273         /* Handle various states here. */
00274 
00275         /* request failed and we are not in shutdown mode */
00276         if (status == -1 && conndata->shutdown == 0) { 
00277             error(0, "HTTP[%s]: Couldn't connect to SMS center "
00278                      "(retrying in %ld seconds).",
00279                      octstr_get_cstr(conn->id), conn->reconnect_delay);
00280             conn->status = SMSCCONN_RECONNECTING; 
00281             gwthread_sleep(conn->reconnect_delay);
00282             debug("smsc.http.kannel", 0, "HTTP[%s]: Re-sending request",
00283                   octstr_get_cstr(conn->id));
00284             conndata->send_sms(conn, msg);
00285             continue; 
00286         } 
00287         /* request failed and we *are* in shutdown mode, drop the message */ 
00288         else if (status == -1 && conndata->shutdown == 1) {
00289         }
00290         /* request succeeded */    
00291         else {
00292             /* we received a response, so this link is considered online again */
00293             if (status && conn->status != SMSCCONN_ACTIVE) {
00294                 conn->status = SMSCCONN_ACTIVE;
00295                 time(&conn->connect_time);
00296             }
00297             conndata->parse_reply(conn, msg, status, headers, body);
00298         }
00299    
00300         conndata->open_sends--;
00301 
00302         http_destroy_headers(headers);
00303         octstr_destroy(final_url);
00304         octstr_destroy(body);
00305     }
00306     debug("smsc.http", 0, "HTTP[%s]: httpsmsc_send_cb dying",
00307           octstr_get_cstr(conn->id));
00308     conndata->shutdown = 1;
00309 
00310     if (conndata->open_sends) {
00311         warning(0, "HTTP[%s]: Shutdown while <%ld> requests are pending.",
00312                 octstr_get_cstr(conn->id), conndata->open_sends);
00313     }
00314 
00315     gwthread_join(conndata->receive_thread);
00316 
00317     conn->data = NULL;
00318     conndata_destroy(conndata);
00319 
00320     conn->status = SMSCCONN_DEAD;
00321     bb_smscconn_killed();
00322 }
00323 
00324 
00325 /*----------------------------------------------------------------
00326  * SMSC-type specific functions
00327  *
00328  * 3 functions are needed for each:
00329  *
00330  *   1) send SMS
00331  *   2) parse send SMS result
00332  *   3) receive SMS (and send reply)
00333  *
00334  *   These functions do not return anything and do not destroy
00335  *   arguments. They must handle everything that happens therein
00336  *   and must call appropriate bb_smscconn functions
00337  */
00338 
00339 /*----------------------------------------------------------------
00340  * Kannel
00341  * 
00342  * This type allows concatenation of Kannel instances, ie:
00343  * 
00344  *  <smsc>--<bearerbox2><smsbox2>--HTTP--<smsc_http><bearerbox1><smsbox1>
00345  * 
00346  * Where MT messages are injected via the sendsms HTTP interface at smsbox1,
00347  * forwarded to bearerbo1 and routed via the SMSC HTTP type kannel to 
00348  * sendsms HTTP interface of smsbox2 and further on.
00349  * 
00350  * This allows chaining of Kannel instances for MO and MT traffic.
00351  * 
00352  * DLR handling:
00353  * For DLR handling we have the usual effect that the "last" smsbox instance
00354  * of the chain is signaling the DLR-URL, since the last instance receives
00355  * the DLR from the upstream SMSC and the associated smsbox triggers the
00356  * DLR-URL.
00357  * For some considerations this is not what we want. If we want to transport
00358  * the orginal DLR-URL to the "first" smsbox instance of the calling chain
00359  * then we need to define a 'dlr-url' config directive in the smsc group.
00360  * This value defines the inbound MO/DLR port of our own smsc group and
00361  * maps arround the orginal DLR-URL. So the next smsbox does not signal the
00362  * orginal DLR-URL, but our own smsc group instance with the DLR, and we can
00363  * forward on to smsbox and possibly further on the chain to the first
00364  * instance.
00365  * 
00366  * Example: (consider the 2 chain architecture from above)
00367  * A MT is put to smsbox1 with dlr-url=http://foobar/aaa as DLR-URL. The MT
00368  * is forwarded to bearerbox.
00369  * If no 'dlr-url' is given in the smsc HTTP for the next smsbox2, then we
00370  * simply pass the same value to smsbox2. Resulting that smsbox2 will call
00371  * the DLR-URL when we receive a DLR from the upstream SMSC connection of
00372  * bearerbox2.
00373  * If 'dlr-url = http://localhost:15015/' is given in the smsc HTTP for the
00374  * next smsbox2, then we map the orginal DLR-URL into this value, resulting
00375  * in a dlr-url=http://lcoalhost:15015/&dlr-url=http://foobar/aaa call to
00376  * smsbox2. So smsbox2 is not signaling http://foobar/aaa directly, but our
00377  * own bearerbox1's smsc HTTP port for MO/DLR receive.
00378  */
00379 
00380 enum { HEX_NOT_UPPERCASE = 0 };
00381 
00382 
00383 static void kannel_send_sms(SMSCConn *conn, Msg *sms)
00384 {
00385     ConnData *conndata = conn->data;
00386     Octstr *url;
00387     List *headers;
00388 
00389     if (!conndata->no_sep) {
00390         url = octstr_format("%S?"
00391                 "username=%E&password=%E&to=%E&text=%E",
00392                  conndata->send_url,
00393                  conndata->username, conndata->password,
00394                  sms->sms.receiver, sms->sms.msgdata);
00395     } else {
00396         octstr_binary_to_hex(sms->sms.msgdata, HEX_NOT_UPPERCASE);
00397         url = octstr_format("%S?"
00398                 "username=%E&password=%E&to=%E&text=%S",
00399                  conndata->send_url,
00400                  conndata->username, conndata->password,
00401                  sms->sms.receiver, 
00402                              sms->sms.msgdata); 
00403     }   
00404 
00405     if (octstr_len(sms->sms.udhdata)) {
00406         if (!conndata->no_sep) {
00407         octstr_format_append(url, "&udh=%E", sms->sms.udhdata);
00408         } else {
00409         octstr_binary_to_hex(sms->sms.udhdata, HEX_NOT_UPPERCASE);
00410             octstr_format_append(url, "&udh=%S", sms->sms.udhdata);
00411     }
00412     }
00413 
00414     if (!conndata->no_sender)
00415         octstr_format_append(url, "&from=%E", sms->sms.sender);
00416     if (sms->sms.mclass != MC_UNDEF)
00417         octstr_format_append(url, "&mclass=%d", sms->sms.mclass);
00418     if (!conndata->no_coding && sms->sms.coding != DC_UNDEF)
00419         octstr_format_append(url, "&coding=%d", sms->sms.coding);
00420 
00421     /* Obey that smsbox's sendsms HTTP interface is still expecting 
00422      * WINDOWS-1252 as default charset, while all other internal parts
00423      * use UTF-8 as internal encoding. This means, when we pass a SMS
00424      * into a next Kannel instance, we need to let the smsbox know which
00425      * charset we have in use.
00426      * XXX TODO: change smsbox interface to use UTF-8 as default
00427      * in next major release. */
00428     if (sms->sms.coding == DC_7BIT)
00429         octstr_append_cstr(url, "&charset=UTF-8");
00430     else if (sms->sms.coding == DC_UCS2)
00431         octstr_append_cstr(url, "&charset=UTF-16BE");
00432 
00433     if (sms->sms.mwi != MWI_UNDEF)
00434         octstr_format_append(url, "&mwi=%d", sms->sms.mwi);
00435     if (sms->sms.account) /* prepend account with local username */
00436         octstr_format_append(url, "&account=%E:%E", sms->sms.service, sms->sms.account);
00437     if (sms->sms.binfo) /* prepend billing info */
00438         octstr_format_append(url, "&binfo=%S", sms->sms.binfo);
00439     if (sms->sms.smsc_id) /* proxy the smsc-id to the next instance */
00440         octstr_format_append(url, "&smsc=%S", sms->sms.smsc_id);
00441     if (sms->sms.dlr_url) {
00442         if (conndata->dlr_url) {
00443             char id[UUID_STR_LEN + 1];
00444             Octstr *mid;
00445 
00446             /* create Octstr from UUID */  
00447             uuid_unparse(sms->sms.id, id);
00448             mid = octstr_create(id); 
00449 
00450             octstr_format_append(url, "&dlr-url=%E", conndata->dlr_url);
00451 
00452             /* encapsulate the orginal DLR-URL, escape code for DLR mask
00453              * and message id */
00454             octstr_format_append(url, "%E%E%E%E%E", 
00455                 octstr_imm("&dlr-url="), sms->sms.dlr_url,
00456                 octstr_imm("&dlr-mask=%d"),
00457                 octstr_imm("&dlr-mid="), mid);
00458                 
00459             octstr_destroy(mid);
00460         } else             
00461             octstr_format_append(url, "&dlr-url=%E", sms->sms.dlr_url);
00462     }
00463     if (sms->sms.dlr_mask != DLR_UNDEFINED && sms->sms.dlr_mask != DLR_NOTHING)
00464         octstr_format_append(url, "&dlr-mask=%d", sms->sms.dlr_mask);
00465 
00466     headers = gwlist_create();
00467     debug("smsc.http.kannel", 0, "HTTP[%s]: Start request",
00468           octstr_get_cstr(conn->id));
00469     http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers, 
00470                        NULL, 0, sms, NULL);
00471 
00472     octstr_destroy(url);
00473     http_destroy_headers(headers);
00474 }
00475 
00476 static void kannel_parse_reply(SMSCConn *conn, Msg *msg, int status,
00477                    List *headers, Octstr *body)
00478 {
00479     /* Test on three cases:
00480      * 1. an smsbox reply of an remote kannel instance
00481      * 2. an smsc_http response (if used for MT to MO looping)
00482      * 3. an smsbox reply of partly successful sendings */
00483     if ((status == HTTP_OK || status == HTTP_ACCEPTED)
00484         && (octstr_case_compare(body, octstr_imm("0: Accepted for delivery")) == 0 ||
00485             octstr_case_compare(body, octstr_imm("Sent.")) == 0 ||
00486             octstr_case_compare(body, octstr_imm("Ok.")) == 0 ||
00487             octstr_ncompare(body, octstr_imm("Result: OK"),10) == 0)) {
00488         char id[UUID_STR_LEN + 1];
00489         Octstr *mid;
00490 
00491         /* create Octstr from UUID */  
00492         uuid_unparse(msg->sms.id, id);
00493         mid = octstr_create(id); 
00494     
00495         /* add to our own DLR storage */               
00496         if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask))
00497             dlr_add(conn->id, mid, msg);
00498 
00499         octstr_destroy(mid);            
00500             
00501         bb_smscconn_sent(conn, msg, NULL);
00502     } else {
00503         bb_smscconn_send_failed(conn, msg,
00504                 SMSCCONN_FAILED_MALFORMED, octstr_duplicate(body));
00505     }
00506 }
00507 
00508 
00509 static void kannel_receive_sms(SMSCConn *conn, HTTPClient *client,
00510                                List *headers, Octstr *body, List *cgivars)
00511 {
00512     ConnData *conndata = conn->data;
00513     Octstr *user, *pass, *from, *to, *text, *udh, *account, *binfo;
00514     Octstr *dlrurl, *dlrmid;
00515     Octstr *tmp_string, *retmsg;
00516     int mclass, mwi, coding, validity, deferred, dlrmask;
00517     List *reply_headers;
00518     int ret;
00519 
00520     mclass = mwi = coding = validity = 
00521         deferred = dlrmask = SMS_PARAM_UNDEFINED;
00522 
00523     user = http_cgi_variable(cgivars, "username");
00524     pass = http_cgi_variable(cgivars, "password");
00525     from = http_cgi_variable(cgivars, "from");
00526     to = http_cgi_variable(cgivars, "to");
00527     text = http_cgi_variable(cgivars, "text");
00528     udh = http_cgi_variable(cgivars, "udh");
00529     account = http_cgi_variable(cgivars, "account");
00530     binfo = http_cgi_variable(cgivars, "binfo");
00531     dlrurl = http_cgi_variable(cgivars, "dlr-url");
00532     dlrmid = http_cgi_variable(cgivars, "dlr-mid");
00533     tmp_string = http_cgi_variable(cgivars, "flash");
00534     if (tmp_string) {
00535         sscanf(octstr_get_cstr(tmp_string),"%d", &mclass);
00536     }
00537     tmp_string = http_cgi_variable(cgivars, "mclass");
00538     if (tmp_string) {
00539         sscanf(octstr_get_cstr(tmp_string),"%d", &mclass);
00540     }
00541     tmp_string = http_cgi_variable(cgivars, "mwi");
00542     if (tmp_string) {
00543         sscanf(octstr_get_cstr(tmp_string),"%d", &mwi);
00544     }
00545     tmp_string = http_cgi_variable(cgivars, "coding");
00546     if (tmp_string) {
00547         sscanf(octstr_get_cstr(tmp_string),"%d", &coding);
00548     }
00549     tmp_string = http_cgi_variable(cgivars, "validity");
00550     if (tmp_string) {
00551         sscanf(octstr_get_cstr(tmp_string),"%d", &validity);
00552     }
00553     tmp_string = http_cgi_variable(cgivars, "deferred");
00554     if (tmp_string) {
00555         sscanf(octstr_get_cstr(tmp_string),"%d", &deferred);
00556     }
00557     tmp_string = http_cgi_variable(cgivars, "dlr-mask");
00558     if (tmp_string) {
00559         sscanf(octstr_get_cstr(tmp_string),"%d", &dlrmask);
00560     }
00561     debug("smsc.http.kannel", 0, "HTTP[%s]: Received an HTTP request",
00562           octstr_get_cstr(conn->id));
00563     
00564     if (user == NULL || pass == NULL ||
00565         octstr_compare(user, conndata->username) != 0 ||
00566         octstr_compare(pass, conndata->password) != 0) {
00567 
00568         error(0, "HTTP[%s]: Authorization failure",
00569               octstr_get_cstr(conn->id));
00570         retmsg = octstr_create("Authorization failed for sendsms");
00571     }
00572     else if (dlrurl != NULL && dlrmask != 0 && dlrmid != NULL) {
00573         /* we got a DLR, and we don't require additional values */
00574         Msg *dlrmsg;
00575         
00576         dlrmsg = dlr_find(conn->id,
00577             dlrmid, /* message id */
00578             to, /* destination */
00579             dlrmask);
00580 
00581         if (dlrmsg != NULL) {
00582             dlrmsg->sms.sms_type = report_mo;
00583 
00584             debug("smsc.http.kannel", 0, "HTTP[%s]: Received DLR for DLR-URL <%s>",
00585                   octstr_get_cstr(conn->id), octstr_get_cstr(dlrmsg->sms.dlr_url));
00586     
00587             ret = bb_smscconn_receive(conn, dlrmsg);
00588             if (ret == -1)
00589                 retmsg = octstr_create("Not accepted");
00590             else
00591                 retmsg = octstr_create("Sent.");
00592         } else {
00593             error(0,"HTTP[%s]: Got DLR but could not find message or was not interested "
00594                   "in it id<%s> dst<%s>, type<%d>",
00595                   octstr_get_cstr(conn->id), octstr_get_cstr(dlrmid),
00596                   octstr_get_cstr(to), dlrmask);
00597             retmsg = octstr_create("Unknown DLR, not accepted");
00598         }                    
00599     }
00600     else if (from == NULL || to == NULL || text == NULL) {
00601     
00602         error(0, "HTTP[%s]: Insufficient args",
00603               octstr_get_cstr(conn->id));
00604         retmsg = octstr_create("Insufficient args, rejected");
00605     }
00606     else if (udh != NULL && (octstr_len(udh) != octstr_get_char(udh, 0) + 1)) {
00607         error(0, "HTTP[%s]: UDH field misformed, rejected",
00608               octstr_get_cstr(conn->id));
00609         retmsg = octstr_create("UDH field misformed, rejected");
00610     }
00611     else if (udh != NULL && octstr_len(udh) > MAX_SMS_OCTETS) {
00612         error(0, "HTTP[%s]: UDH field is too long, rejected",
00613               octstr_get_cstr(conn->id));
00614         retmsg = octstr_create("UDH field is too long, rejected");
00615     }
00616     else {
00617         /* we got a normal MO SMS */
00618         Msg *msg;
00619         msg = msg_create(sms);
00620 
00621         debug("smsc.http.kannel", 0, "HTTP[%s]: Constructing new SMS",
00622               octstr_get_cstr(conn->id));
00623     
00624         msg->sms.service = octstr_duplicate(user);
00625         msg->sms.sender = octstr_duplicate(from);
00626         msg->sms.receiver = octstr_duplicate(to);
00627         msg->sms.msgdata = octstr_duplicate(text);
00628         msg->sms.udhdata = octstr_duplicate(udh);
00629 
00630         msg->sms.smsc_id = octstr_duplicate(conn->id);
00631         msg->sms.time = time(NULL);
00632         msg->sms.mclass = mclass;
00633         msg->sms.mwi = mwi;
00634         msg->sms.coding = coding;
00635         msg->sms.validity = validity;
00636         msg->sms.deferred = deferred;
00637         msg->sms.account = octstr_duplicate(account);
00638         msg->sms.binfo = octstr_duplicate(binfo);
00639         ret = bb_smscconn_receive(conn, msg);
00640         if (ret == -1)
00641             retmsg = octstr_create("Not accepted");
00642         else
00643             retmsg = octstr_create("Sent.");
00644     }
00645 
00646     reply_headers = gwlist_create();
00647     http_header_add(reply_headers, "Content-Type", "text/plain");
00648     debug("smsc.http.kannel", 0, "HTTP[%s]: Sending reply",
00649           octstr_get_cstr(conn->id));
00650     http_send_reply(client, HTTP_ACCEPTED, reply_headers, retmsg);
00651 
00652     octstr_destroy(retmsg);
00653     http_destroy_headers(reply_headers);
00654 }
00655 
00656 
00657 /*----------------------------------------------------------------
00658  * Clickatell - http://api.clickatell.com/
00659  *
00660  * Rene Kluwen <rene.kluwen@chimit.nl>
00661  * Stipe Tolj <st@tolj.org>, <stolj@kannel.org>
00662  */
00663 
00664 /* MT related function */
00665 static void clickatell_send_sms(SMSCConn *conn, Msg *sms)
00666 {
00667     ConnData *conndata = conn->data;
00668     Octstr *url, *os;
00669     char id[UUID_STR_LEN + 1];
00670     List *headers;
00671 
00672     /* form the basic URL */
00673     url = octstr_format("%S/sendmsg?to=%E&from=%E&api_id=%E&user=%E&password=%E",
00674         conndata->send_url, sms->sms.receiver, sms->sms.sender, 
00675         conndata->system_id, conndata->username, conndata->password);
00676     
00677     /* append MD5 digest as msg ID from our UUID */
00678     uuid_unparse(sms->sms.id, id);
00679     os = octstr_create(id);
00680     octstr_replace(os, octstr_imm("-"), octstr_imm(""));
00681     octstr_format_append(url, "&cliMsgId=%E", os);
00682     octstr_destroy(os);
00683     
00684     /* add UDH header */
00685     if (octstr_len(sms->sms.udhdata)) {
00686         octstr_format_append(url, "&data=%H", sms->sms.msgdata);
00687         octstr_format_append(url, "&udh=%H", sms->sms.udhdata);
00688     } else {
00689         octstr_format_append(url, "&text=%E", sms->sms.msgdata);
00690         if (conndata->alt_charset) {
00691             octstr_format_append(url, "&charset=%E", conndata->alt_charset);
00692         } else {
00693             octstr_append_cstr(url, "&charset=UTF-8");
00694         }
00695     }
00696 
00697     if (DLR_IS_ENABLED_DEVICE(sms->sms.dlr_mask))
00698     octstr_format_append(url, "&callback=3&deliv_ack=1");
00699 
00700     headers = http_create_empty_headers();
00701     debug("smsc.http.clickatell", 0, "HTTP[%s]: Sending request <%s>",
00702           octstr_get_cstr(conn->id), octstr_get_cstr(url));
00703 
00704     /* 
00705      * Clickatell requires optionally an SSL-enabled HTTP client call, this is handled
00706      * transparently by the Kannel HTTP layer module.
00707      */
00708     http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers, NULL, 0, sms, NULL);
00709 
00710     octstr_destroy(url);
00711     http_destroy_headers(headers);
00712 }
00713 
00714 
00715 /*
00716  * Parse a line in the format: ID: XXXXXXXXXXXXXXXXXX
00717  * and return a Dict with the 'ID' as key and the value as value,
00718  * otherwise return NULL if a parsing error occures.
00719  */
00720 static Dict *clickatell_parse_body(Octstr *body)
00721 {
00722     Dict *param = NULL;
00723     List *words = NULL;
00724     long len;
00725     Octstr *word, *value;
00726 
00727     words = octstr_split_words(body);
00728     if ((len = gwlist_len(words)) > 1) {
00729         word = gwlist_extract_first(words);
00730         if (octstr_compare(word, octstr_imm("ID:")) == 0) {
00731             value = gwlist_extract_first(words);
00732             param = dict_create(4, (void(*)(void *)) octstr_destroy);
00733             dict_put(param, octstr_imm("ID"), value);
00734         } else if (octstr_compare(word, octstr_imm("ERR:")) == 0) {
00735             value = gwlist_extract_first(words);
00736             param = dict_create(4, (void(*)(void *)) octstr_destroy);
00737             dict_put(param, octstr_imm("ERR"), value);
00738         }
00739         octstr_destroy(word);
00740     }
00741     gwlist_destroy(words, (void(*)(void *)) octstr_destroy);
00742 
00743     return param;
00744 }
00745 
00746 
00747 static void clickatell_parse_reply(SMSCConn *conn, Msg *msg, int status,
00748                                List *headers, Octstr *body)
00749 {
00750     if (status == HTTP_OK || status == HTTP_ACCEPTED) {
00751         Dict *param;
00752         Octstr *msgid;
00753 
00754         if ((param = clickatell_parse_body(body)) != NULL &&
00755             (msgid = dict_get(param, octstr_imm("ID"))) != NULL &&
00756             msgid != NULL) {
00757 
00758             /* SMSC ACK.. now we have the message id. */
00759             if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask))
00760                 dlr_add(conn->id, msgid, msg);
00761 
00762             bb_smscconn_sent(conn, msg, NULL);
00763 
00764         } else {
00765             error(0, "HTTP[%s]: Message was malformed or error was returned. SMSC response `%s'.",
00766                   octstr_get_cstr(conn->id), octstr_get_cstr(body));
00767             bb_smscconn_send_failed(conn, msg, SMSCCONN_FAILED_MALFORMED, octstr_duplicate(body));
00768         }
00769         dict_destroy(param);
00770 
00771     } else {
00772         error(0, "HTTP[%s]: Message was rejected. SMSC reponse `%s'.",
00773               octstr_get_cstr(conn->id), octstr_get_cstr(body));
00774         bb_smscconn_send_failed(conn, msg,
00775                 SMSCCONN_FAILED_REJECTED, octstr_duplicate(body));
00776     }
00777 }
00778 
00779 /* MO related function */
00780 static void clickatell_receive_sms(SMSCConn *conn, HTTPClient *client,
00781                                List *headers, Octstr *body, List *cgivars)
00782 {
00783     List *reply_headers;
00784     int ret;
00785     Octstr *apimsgid, *status, *timestamp, *retmsg, *dest, *charge;
00786     Octstr *api_id, *from, *to, *text, *charset, *udh;
00787     int httpstatus = HTTP_UNAUTHORIZED, dlrstat;
00788     Msg *dlrmsg, *momsg;
00789     struct tm tm;
00790 
00791     /* dlr parameters */
00792     apimsgid = http_cgi_variable(cgivars, "apiMsgId");
00793     status = http_cgi_variable(cgivars, "status");
00794     /* timestamp is for both DLR & MO */
00795     timestamp = http_cgi_variable(cgivars, "timestamp");
00796     dest = http_cgi_variable(cgivars, "to");
00797     charge = http_cgi_variable(cgivars, "charge");
00798     /* MO parameters */
00799     api_id = http_cgi_variable(cgivars, "api_id");
00800     from = http_cgi_variable(cgivars, "from");
00801     to = http_cgi_variable(cgivars, "to");
00802     text = http_cgi_variable(cgivars, "text");
00803     charset = http_cgi_variable(cgivars, "charset");
00804     udh = http_cgi_variable(cgivars, "udh");
00805 
00806     debug("smsc.http.clickatell", 0, "HTTP[%s]: Received a request",
00807           octstr_get_cstr(conn->id));
00808  
00809     if (api_id != NULL && from != NULL && to != NULL && timestamp != NULL && text != NULL && charset != NULL && udh != NULL) {
00810     /* we received an MO message */
00811     debug("smsc.http.clickatell", 0, "HTTP[%s]: Received MO message from %s: <%s>",
00812             octstr_get_cstr(conn->id), octstr_get_cstr(from), octstr_get_cstr(text));
00813     momsg = msg_create(sms);
00814     momsg->sms.sms_type = mo;
00815     momsg->sms.sender = octstr_duplicate(from);
00816     momsg->sms.receiver = octstr_duplicate(to);
00817     momsg->sms.msgdata = octstr_duplicate(text);
00818     momsg->sms.charset = octstr_duplicate(charset);
00819     momsg->sms.service = octstr_duplicate(api_id);
00820     momsg->sms.binfo = octstr_duplicate(api_id);
00821         momsg->sms.smsc_id = octstr_duplicate(conn->id);
00822     if (octstr_len(udh) > 0) {
00823         momsg->sms.udhdata = octstr_duplicate(udh);
00824     }
00825         strptime(octstr_get_cstr(timestamp), "%Y-%m-%d %H:%M:%S", &tm);
00826         momsg->sms.time = gw_mktime(&tm);
00827  
00828     /* note: implicit msg_destroy */
00829     ret = bb_smscconn_receive(conn, momsg);
00830         httpstatus = HTTP_OK;
00831     retmsg = octstr_create("Thanks");
00832     } else if (apimsgid == NULL || status == NULL || timestamp == NULL || dest == NULL) {
00833         error(0, "HTTP[%s]: Insufficient args.",
00834               octstr_get_cstr(conn->id));
00835         httpstatus = HTTP_BAD_REQUEST;
00836         retmsg = octstr_create("Insufficient arguments, rejected.");
00837     } else {
00838     switch (atoi(octstr_get_cstr(status))) {
00839     case  1: /* message unknown */
00840     case  5: /* error with message */
00841     case  6: /* user cancelled message */
00842     case  7: /* error delivering message */
00843     case  9: /* routing error */
00844     case 10: /* message expired */
00845         dlrstat = 2; /* delivery failure */
00846         break;
00847     case  2: /* message queued */
00848     case  3: /* delivered */
00849     case 11: /* message queued for later delivery */
00850         dlrstat = 4; /* message buffered */
00851         break;
00852     case  4: /* received by recipient */
00853     case  8: /* OK */
00854         dlrstat = 1; /* message received */
00855         break;
00856     default: /* unknown status code */
00857         dlrstat = 16; /* smsc reject */
00858         break;
00859     }
00860         dlrmsg = dlr_find(conn->id,
00861             apimsgid, /* smsc message id */
00862             dest , /* destination */
00863             dlrstat);
00864 
00865         if (dlrmsg != NULL) {
00866             /* dlrmsg->sms.msgdata = octstr_duplicate(apimsgid); */
00867             dlrmsg->sms.sms_type = report_mo;
00868         dlrmsg->sms.time = atoi(octstr_get_cstr(timestamp));
00869         if (charge) {
00870         /* unsure if smsbox relays the binfo field to dlrs.
00871            But it is here in case they will start to do it. */
00872         dlrmsg->sms.binfo = octstr_duplicate(charge);
00873         }
00874             
00875             ret = bb_smscconn_receive(conn, dlrmsg);
00876             httpstatus = (ret == 0 ? HTTP_OK : HTTP_FORBIDDEN);
00877             retmsg = octstr_create("Sent");
00878         } else {
00879             error(0,"HTTP[%s]: got DLR but could not find message or was not interested "
00880                     "in it id<%s> dst<%s>, type<%d>",
00881             octstr_get_cstr(conn->id), octstr_get_cstr(apimsgid),
00882             octstr_get_cstr(dest), dlrstat);
00883             httpstatus = HTTP_OK;
00884             retmsg = octstr_create("Thanks");
00885         }
00886     }
00887 
00888     reply_headers = gwlist_create();
00889     http_header_add(reply_headers, "Content-Type", "text/plain");
00890     debug("smsc.http.clickatell", 0, "HTTP[%s]: Sending reply `%s'.",
00891           octstr_get_cstr(conn->id), octstr_get_cstr(retmsg));
00892     http_send_reply(client, httpstatus, reply_headers, retmsg);
00893 
00894     octstr_destroy(retmsg);
00895     http_destroy_headers(reply_headers);
00896 }
00897 
00898 
00899 /*----------------------------------------------------------------
00900  * Brunet - A german aggregator (mainly doing T-Mobil D1 connections)
00901  *
00902  *  o bruHTT v1.3L (for MO traffic) 
00903  *  o bruHTP v2.1 (date 22.04.2003) (for MT traffic)
00904  *
00905  * Stipe Tolj <stolj@wapme.de>
00906  * Tobias Weber <weber@wapme.de>
00907  */
00908 
00909 /* MT related function */
00910 static void brunet_send_sms(SMSCConn *conn, Msg *sms)
00911 {
00912     ConnData *conndata = conn->data;
00913     Octstr *url, *tid, *xser;
00914     List *headers;
00915     char id[UUID_STR_LEN + 1];
00916     int dcs;
00917 
00918     /* 
00919      * Construct TransactionId.
00920      * Beware that brunet needs an "clean" octstr representation, 
00921      * without the dashes in the string. So remove them.
00922      */
00923     uuid_unparse(sms->sms.id, id);
00924     tid = octstr_create(id);
00925     octstr_replace(tid, octstr_imm("-"), octstr_imm(""));
00926 
00927     /* form the basic URL */
00928     url = octstr_format("%S?MsIsdn=%E&Originator=%E",
00929         conndata->send_url, sms->sms.receiver, sms->sms.sender);
00930     
00931     /* 
00932      * We use &binfo=<foobar> from sendsms interface to encode
00933      * additional paramters. If a mandatory value is not set,
00934      * a default value is applied
00935      */
00936     if (octstr_len(sms->sms.binfo)) {
00937         octstr_url_decode(sms->sms.binfo);
00938         octstr_format_append(url, "&%S", sms->sms.binfo);
00939     }
00940     /* CustomerId */
00941     if (octstr_search(url, octstr_create("CustomerId="), 0) == -1) {
00942         octstr_format_append(url, "&CustomerId=%S", conndata->username);
00943     }
00944     /* TransactionId */
00945     if (octstr_search(url, octstr_create("TransactionId="), 0) == -1) {
00946         octstr_format_append(url, "&TransactionId=%S", tid);
00947     }
00948     /* SMSCount */
00949     if (octstr_search(url, octstr_create("SMSCount="), 0) == -1) {
00950         octstr_format_append(url, "&%s", "SMSCount=1");
00951     }
00952     /* ActionType */
00953     if (octstr_search(url, octstr_create("ActionType="), 0) == -1) {
00954         octstr_format_append(url, "&%s", "ActionType=A");
00955     }
00956     /* ServiceDeliveryType */
00957     if (octstr_search(url, octstr_create("ServiceDeliveryType="), 0) == -1) {
00958         octstr_format_append(url, "&%s", "ServiceDeliveryType=P");
00959     }
00960 
00961     /* if coding is not set and UDH exists, assume DC_8BIT
00962      * else default to DC_7BIT */
00963     if (sms->sms.coding == DC_UNDEF)
00964         sms->sms.coding = octstr_len(sms->sms.udhdata) > 0 ? DC_8BIT : DC_7BIT;
00965 
00966     if (sms->sms.coding == DC_8BIT)
00967         octstr_format_append(url, "&MessageType=B&Text=%H", sms->sms.msgdata);
00968     else
00969         octstr_format_append(url, "&MessageType=S&Text=%E", sms->sms.msgdata);
00970 
00971     dcs = fields_to_dcs(sms,
00972         (sms->sms.alt_dcs != SMS_PARAM_UNDEFINED ? sms->sms.alt_dcs : 0));
00973 
00974     /* XSer processing */    
00975     xser = octstr_create("");
00976     /* XSer DCS values */
00977     if (dcs != 0 && dcs != 4)
00978         octstr_format_append(xser, "0201%02x", dcs & 0xff);
00979     /* add UDH header */
00980     if (octstr_len(sms->sms.udhdata)) {
00981         octstr_format_append(xser, "01%02x%H", octstr_len(sms->sms.udhdata), 
00982                              sms->sms.udhdata);
00983     }
00984     if (octstr_len(xser) > 0)
00985         octstr_format_append(url, "&XSer=%S", xser);
00986     octstr_destroy(xser);
00987 
00988 
00989     headers = http_create_empty_headers();
00990     debug("smsc.http.brunet", 0, "HTTP[%s]: Sending request <%s>",
00991           octstr_get_cstr(conn->id), octstr_get_cstr(url));
00992 
00993     /* 
00994      * Brunet requires an SSL-enabled HTTP client call, this is handled
00995      * transparently by the Kannel HTTP layer module.
00996      */
00997     http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers, 
00998                        NULL, 0, sms, NULL);
00999 
01000     octstr_destroy(url);
01001     octstr_destroy(tid);
01002     http_destroy_headers(headers);
01003 }
01004 
01005 
01006 /*
01007  * Parse a line in the format: <name=value name=value ...>
01008  * and return a Dict with the name as key and the value as value,
01009  * otherwise return NULL if a parsing error occures.
01010  */
01011 static Dict *brunet_parse_body(Octstr *body)
01012 {
01013     Dict *param = NULL;
01014     List *words = NULL;
01015     long len;
01016     Octstr *word;
01017 
01018     words = octstr_split_words(body);
01019     if ((len = gwlist_len(words)) > 0) {
01020         param = dict_create(4, (void(*)(void *)) octstr_destroy);
01021         while ((word = gwlist_extract_first(words)) != NULL) {
01022             List *l = octstr_split(word, octstr_imm("="));
01023             Octstr *key = gwlist_extract_first(l);
01024             Octstr *value = gwlist_extract_first(l);
01025             if (octstr_len(key))
01026                 dict_put(param, key, value);
01027             octstr_destroy(key);
01028             octstr_destroy(word);
01029             gwlist_destroy(l, (void(*)(void *)) octstr_destroy);
01030         }
01031     }
01032     gwlist_destroy(words, (void(*)(void *)) octstr_destroy);
01033 
01034     return param;
01035 }
01036 
01037 
01038 static void brunet_parse_reply(SMSCConn *conn, Msg *msg, int status,
01039                                List *headers, Octstr *body)
01040 {
01041     if (status == HTTP_OK || status == HTTP_ACCEPTED) {
01042         Dict *param;
01043         Octstr *status;
01044 
01045         if ((param = brunet_parse_body(body)) != NULL &&
01046             (status = dict_get(param, octstr_imm("Status"))) != NULL &&
01047             octstr_case_compare(status, octstr_imm("0")) == 0) {
01048             Octstr *msg_id;
01049 
01050             /* pass the MessageId for this MT to the logging facility */
01051             if ((msg_id = dict_get(param, octstr_imm("MessageId"))) != NULL)
01052                 msg->sms.binfo = octstr_duplicate(msg_id);
01053 
01054             bb_smscconn_sent(conn, msg, NULL);
01055 
01056         } else {
01057             error(0, "HTTP[%s]: Message was malformed. SMSC response `%s'.",
01058                   octstr_get_cstr(conn->id), octstr_get_cstr(body));
01059             bb_smscconn_send_failed(conn, msg,
01060                     SMSCCONN_FAILED_MALFORMED, octstr_duplicate(body));
01061         }
01062         dict_destroy(param);
01063 
01064     } else {
01065         error(0, "HTTP[%s]: Message was rejected. SMSC reponse `%s'.",
01066               octstr_get_cstr(conn->id), octstr_get_cstr(body));
01067         bb_smscconn_send_failed(conn, msg,
01068                 SMSCCONN_FAILED_REJECTED, octstr_duplicate(body));
01069     }
01070 }
01071 
01072 /* MO related function */
01073 static void brunet_receive_sms(SMSCConn *conn, HTTPClient *client,
01074                                List *headers, Octstr *body, List *cgivars)
01075 {
01076     ConnData *conndata = conn->data;
01077     Octstr *user, *from, *to, *text, *udh, *date, *type;
01078     Octstr *retmsg;
01079     int mclass, mwi, coding, validity, deferred;
01080     List *reply_headers;
01081     int ret;
01082 
01083     mclass = mwi = coding = validity = deferred = 0;
01084 
01085     user = http_cgi_variable(cgivars, "CustomerId");
01086     from = http_cgi_variable(cgivars, "MsIsdn");
01087     to = http_cgi_variable(cgivars, "Recipient");
01088     text = http_cgi_variable(cgivars, "SMMO");
01089     udh = http_cgi_variable(cgivars, "XSer");
01090     date = http_cgi_variable(cgivars, "DateReceived");
01091     type = http_cgi_variable(cgivars, "MessageType");
01092 
01093     debug("smsc.http.brunet", 0, "HTTP[%s]: Received a request",
01094           octstr_get_cstr(conn->id));
01095     
01096     if (user == NULL || octstr_compare(user, conndata->username) != 0) {
01097         error(0, "HTTP[%s]: Authorization failure. CustomerId was <%s>.",
01098               octstr_get_cstr(conn->id), octstr_get_cstr(user));
01099         retmsg = octstr_create("Authorization failed for MO submission.");
01100     }
01101     else if (from == NULL || to == NULL || text == NULL) {
01102         error(0, "HTTP[%s]: Insufficient args.",
01103               octstr_get_cstr(conn->id));
01104         retmsg = octstr_create("Insufficient arguments, rejected.");
01105     }
01106     else {
01107         Msg *msg;
01108         msg = msg_create(sms);
01109 
01110         debug("smsc.http.brunet", 0, "HTTP[%s]: Received new MO SMS.",
01111               octstr_get_cstr(conn->id));
01112     
01113         msg->sms.sender = octstr_duplicate(from);
01114         msg->sms.receiver = octstr_duplicate(to);
01115         msg->sms.msgdata = octstr_duplicate(text);
01116         msg->sms.udhdata = octstr_duplicate(udh);
01117 
01118         msg->sms.smsc_id = octstr_duplicate(conn->id);
01119         msg->sms.time = time(NULL); /* XXX maybe extract from DateReceived */ 
01120         msg->sms.mclass = mclass;
01121         msg->sms.mwi = mwi;
01122         msg->sms.coding = coding;
01123         msg->sms.validity = validity;
01124         msg->sms.deferred = deferred;
01125 
01126         ret = bb_smscconn_receive(conn, msg);
01127         if (ret == -1)
01128             retmsg = octstr_create("Status=1");
01129         else
01130             retmsg = octstr_create("Status=0");
01131     }
01132 
01133     reply_headers = gwlist_create();
01134     http_header_add(reply_headers, "Content-Type", "text/plain");
01135     debug("smsc.http.brunet", 0, "HTTP[%s]: Sending reply `%s'.",
01136           octstr_get_cstr(conn->id), octstr_get_cstr(retmsg));
01137     http_send_reply(client, HTTP_OK, reply_headers, retmsg);
01138 
01139     octstr_destroy(retmsg);
01140     http_destroy_headers(reply_headers);
01141 }
01142 
01143 
01144 /*----------------------------------------------------------------
01145  * 3united.com (formerly Xidris) - An austrian (AT) SMS aggregator 
01146  * Implementing version 1.3, 2003-05-06
01147  * Updating to version 1.9.1, 2004-09-28
01148  *
01149  * Stipe Tolj <stolj@wapme.de>
01150  */
01151 
01152 /* MT related function */
01153 static void xidris_send_sms(SMSCConn *conn, Msg *sms)
01154 {
01155     ConnData *conndata = conn->data;
01156     Octstr *url, *new_msg;
01157     List *headers;
01158     int dcs, esm_class;
01159 
01160     url = new_msg = NULL;
01161     dcs = esm_class = 0;
01162 
01163     /* format the URL for call */
01164     url = octstr_format("%S?"
01165         "app_id=%E&key=%E&dest_addr=%E&source_addr=%E",
01166         conndata->send_url, conndata->username, 
01167         conndata->password, sms->sms.receiver, sms->sms.sender);
01168 
01169     if (octstr_len(sms->sms.udhdata)) {
01170         /* RAW additions for binary (8bit) msgs  */
01171 
01172         /* set the data coding scheme (DCS) and ESM class fields */
01173         dcs = fields_to_dcs(sms, sms->sms.alt_dcs);
01174         /* ESM_CLASS_SUBMIT_STORE_AND_FORWARD_MODE | 
01175            ESM_CLASS_SUBMIT_UDH_INDICATOR */
01176         esm_class = 0x03 | 0x40; 
01177     
01178         /* prepend UDH header to message block */
01179         new_msg = octstr_duplicate(sms->sms.udhdata);
01180         octstr_append(new_msg, sms->sms.msgdata);
01181 
01182         octstr_format_append(url, "&type=200&dcs=%d&esm=%d&message=%H",
01183                              dcs, esm_class, new_msg);
01184     }  else {
01185         /* additions for text (7bit) msgs */
01186 
01187         octstr_format_append(url, "&type=%E&message=%E",
01188                             (sms->sms.mclass ? octstr_imm("1") : octstr_imm("0")),
01189                             sms->sms.msgdata);
01190     }
01191 
01192     /* 
01193      * We use &account=<foobar> from sendsms interface to encode any additionaly
01194      * proxied parameters, ie. billing information.
01195      */
01196     if (octstr_len(sms->sms.account)) {
01197         octstr_url_decode(sms->sms.account);
01198         octstr_format_append(url, "&%s", octstr_get_cstr(sms->sms.account));
01199     }
01200 
01201     headers = gwlist_create();
01202     debug("smsc.http.xidris", 0, "HTTP[%s]: Sending request <%s>",
01203           octstr_get_cstr(conn->id), octstr_get_cstr(url));
01204 
01205     http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers, 
01206                        NULL, 0, sms, NULL);
01207 
01208     octstr_destroy(url);
01209     octstr_destroy(new_msg);
01210     http_destroy_headers(headers);
01211 }
01212 
01213 
01214 /* 
01215  * Parse for an parameter of an given XML tag and return it as Octstr
01216  */
01217 static Octstr *parse_xml_tag(Octstr *body, Octstr *tag)
01218 {
01219     Octstr *stag, *etag, *ret;
01220     int spos, epos;
01221    
01222     stag = octstr_format("<%s>", octstr_get_cstr(tag));
01223     if ((spos = octstr_search(body, stag, 0)) == -1) {
01224         octstr_destroy(stag);
01225         return NULL;
01226     }
01227     etag = octstr_format("</%s>", octstr_get_cstr(tag));
01228     if ((epos = octstr_search(body, etag, spos+octstr_len(stag))) == -1) {
01229         octstr_destroy(stag);
01230         octstr_destroy(etag);
01231         return NULL;
01232     }
01233     
01234     ret = octstr_copy(body, spos+octstr_len(stag), epos+1 - (spos+octstr_len(etag)));  
01235     octstr_strip_blanks(ret);
01236     octstr_strip_crlfs(ret);
01237 
01238     octstr_destroy(stag);
01239     octstr_destroy(etag);
01240 
01241     return ret;
01242 }
01243 
01244 static void xidris_parse_reply(SMSCConn *conn, Msg *msg, int status,
01245                                List *headers, Octstr *body)
01246 {
01247     Octstr *code, *desc, *mid;
01248 
01249     if (status == HTTP_OK || status == HTTP_ACCEPTED) {
01250         /* now parse the XML document for error code */
01251         code = parse_xml_tag(body, octstr_imm("status"));
01252         desc = parse_xml_tag(body, octstr_imm("description"));
01253         
01254         /* The following parsing assumes we get only *one* message id in the 
01255          * response XML. Which is ok, since we garantee via previous concat
01256          * splitting, that we only pass PDUs of 1 SMS size to SMSC. */
01257         mid = parse_xml_tag(body, octstr_imm("message_id"));
01258 
01259         if (octstr_case_compare(code, octstr_imm("0")) == 0 && mid != NULL) {
01260             /* ensure the message id gets logged */
01261             msg->sms.binfo = octstr_duplicate(mid);
01262 
01263             /* SMSC ACK.. now we have the message id. */
01264             if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask))
01265                 dlr_add(conn->id, mid, msg);
01266 
01267             octstr_destroy(mid);
01268             bb_smscconn_sent(conn, msg, NULL);
01269 
01270         } else {
01271             error(0, "HTTP[%s]: Message not accepted. Status code <%s> "
01272                   "description `%s'.", octstr_get_cstr(conn->id),
01273                   octstr_get_cstr(code), octstr_get_cstr(desc));
01274             bb_smscconn_send_failed(conn, msg,
01275                     SMSCCONN_FAILED_MALFORMED, octstr_duplicate(desc));
01276         }
01277     } else {
01278         error(0, "HTTP[%s]: Message was rejected. SMSC reponse was:",
01279               octstr_get_cstr(conn->id));
01280         octstr_dump(body, 0);
01281         bb_smscconn_send_failed(conn, msg,
01282                 SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED"));
01283     }
01284 }
01285 
01286 /* MO related function */
01287 static void xidris_receive_sms(SMSCConn *conn, HTTPClient *client,
01288                                List *headers, Octstr *body, List *cgivars)
01289 {
01290     ConnData *conndata = conn->data;
01291     Octstr *user, *pass, *from, *to, *text, *account, *binfo;
01292     Octstr *state, *mid, *dest;
01293     Octstr *retmsg;
01294     int mclass, mwi, coding, validity, deferred; 
01295     List *reply_headers;
01296     int ret, status;
01297 
01298     mclass = mwi = coding = validity = deferred = 0;
01299     retmsg = NULL;
01300 
01301     /* generic values */
01302     user = http_cgi_variable(cgivars, "app_id");
01303     pass = http_cgi_variable(cgivars, "key");
01304 
01305     /* MO specific values */
01306     from = http_cgi_variable(cgivars, "source_addr");
01307     to = http_cgi_variable(cgivars, "dest_addr");
01308     text = http_cgi_variable(cgivars, "message");
01309     account = http_cgi_variable(cgivars, "operator");
01310     binfo = http_cgi_variable(cgivars, "tariff");
01311 
01312     /* DLR (callback) specific values */
01313     state = http_cgi_variable(cgivars, "state");
01314     mid = http_cgi_variable(cgivars, "message_id");
01315     dest = http_cgi_variable(cgivars, "dest_addr");
01316 
01317     debug("smsc.http.xidris", 0, "HTTP[%s]: Received a request",
01318           octstr_get_cstr(conn->id));
01319 
01320     if (user == NULL || pass == NULL ||
01321         octstr_compare(user, conndata->username) != 0 ||
01322         octstr_compare(pass, conndata->password) != 0) {
01323         error(0, "HTTP[%s]: Authorization failure. username was <%s>.",
01324               octstr_get_cstr(conn->id), octstr_get_cstr(user));
01325         retmsg = octstr_create("Authorization failed for MO submission.");
01326         status = HTTP_UNAUTHORIZED;
01327     }
01328     else if (state != NULL && mid != NULL && dest != NULL) {    /* a DLR message */
01329         Msg *dlrmsg;
01330         int dlrstat = -1;
01331 
01332         if (octstr_compare(state, octstr_imm("DELIVRD")) == 0)
01333             dlrstat = DLR_SUCCESS;
01334         else if (octstr_compare(state, octstr_imm("ACCEPTD")) == 0)
01335             dlrstat = DLR_BUFFERED;
01336         else
01337             dlrstat = DLR_FAIL;
01338 
01339         dlrmsg = dlr_find(conn->id,
01340             mid, /* smsc message id */
01341             dest , /* destination */
01342             dlrstat);
01343 
01344         if (dlrmsg != NULL) {
01345             dlrmsg->sms.msgdata = octstr_duplicate(mid);
01346             dlrmsg->sms.sms_type = report_mo;
01347             
01348             ret = bb_smscconn_receive(conn, dlrmsg);
01349             status = (ret == 0 ? HTTP_OK : HTTP_FORBIDDEN);
01350         } else {
01351             error(0,"HTTP[%s]: got DLR but could not find message or was not interested "
01352                     "in it id<%s> dst<%s>, type<%d>",
01353                 octstr_get_cstr(conn->id), octstr_get_cstr(mid),
01354                 octstr_get_cstr(dest), dlrstat);
01355             status = HTTP_OK;
01356         }
01357 
01358     }
01359     else if (from == NULL || to == NULL || text == NULL) {
01360         error(0, "HTTP[%s]: Insufficient args.",
01361               octstr_get_cstr(conn->id));
01362         retmsg = octstr_create("Insufficient arguments, rejected.");
01363         status = HTTP_BAD_REQUEST;
01364     }
01365     else {
01366         Msg *msg;
01367         msg = msg_create(sms);
01368 
01369         debug("smsc.http.xidris", 0, "HTTP[%s]: Received new MO SMS.",
01370               octstr_get_cstr(conn->id));
01371     
01372         msg->sms.sender = octstr_duplicate(from);
01373         msg->sms.receiver = octstr_duplicate(to);
01374         msg->sms.msgdata = octstr_duplicate(text);
01375         msg->sms.account = octstr_duplicate(account);
01376         msg->sms.binfo = octstr_duplicate(binfo);
01377 
01378         msg->sms.smsc_id = octstr_duplicate(conn->id);
01379         msg->sms.time = time(NULL);
01380         msg->sms.mclass = mclass;
01381         msg->sms.mwi = mwi;
01382         msg->sms.coding = coding;
01383         msg->sms.validity = validity;
01384         msg->sms.deferred = deferred;
01385 
01386         ret = bb_smscconn_receive(conn, msg);
01387         status = (ret == 0 ? HTTP_OK : HTTP_FORBIDDEN);
01388     }
01389 
01390     reply_headers = gwlist_create();
01391     debug("smsc.http.xidris", 0, "HTTP[%s]: Sending reply with HTTP status <%d>.",
01392           octstr_get_cstr(conn->id), status);
01393 
01394     http_send_reply(client, status, reply_headers, retmsg);
01395 
01396     octstr_destroy(retmsg);
01397     http_destroy_headers(reply_headers);
01398 }
01399 
01400 
01401 /*----------------------------------------------------------------
01402  * Wapme SMS Proxy
01403  *
01404  * Stipe Tolj <stolj@kannel.org>
01405  */
01406 
01407 static void wapme_smsproxy_send_sms(SMSCConn *conn, Msg *sms)
01408 {
01409     ConnData *conndata = conn->data;
01410     Octstr *url;
01411     List *headers;
01412 
01413     url = octstr_format("%S?command=forward&smsText=%E&phoneNumber=%E"
01414                         "&serviceNumber=%E&smsc=%E",
01415                         conndata->send_url,
01416                         sms->sms.msgdata, sms->sms.sender, sms->sms.receiver,
01417                         sms->sms.smsc_id);
01418 
01419     headers = gwlist_create();
01420     debug("smsc.http.wapme", 0, "HTTP[%s]: Start request",
01421           octstr_get_cstr(conn->id));
01422     http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers, 
01423                        NULL, 0, sms, NULL);
01424 
01425     octstr_destroy(url);
01426     http_destroy_headers(headers);
01427 }
01428 
01429 static void wapme_smsproxy_parse_reply(SMSCConn *conn, Msg *msg, int status,
01430                    List *headers, Octstr *body)
01431 {
01432     if (status == HTTP_OK || status == HTTP_ACCEPTED) {
01433         bb_smscconn_sent(conn, msg, NULL);
01434     } else {
01435         bb_smscconn_send_failed(conn, msg,
01436                 SMSCCONN_FAILED_MALFORMED, octstr_duplicate(body));
01437     }
01438 }
01439 
01440 /*
01441  * static void wapme_smsproxy_receive_sms(SMSCConn *conn, HTTPClient *client,
01442  *                                List *headers, Octstr *body, List *cgivars)
01443  *
01444  * The HTTP server for MO messages will act with the same interface as smsbox's 
01445  * sendsms interface, so that the logical difference is hidden and SMS Proxy 
01446  * can act transparently. So there is no need for an explicite implementation
01447  * here.
01448  */
01449 
01450 
01451 /*----------------------------------------------------------------
01452  * (Semi-)generic HTTP interface
01453  *
01454  * This 'generic' type will handle the 'send-url' directive in the 
01455  * group the same way the 'sms-service' for smsbox does, via 
01456  * URLTranslation. Response interpretation is based on the three
01457  * regex value that match against the reponse body. The HTTP reponse
01458  * code is not obeyed.
01459  * 
01460  * It handles mainly MT messages, due to the fact that MO traffic
01461  * can't be abstracted in a universal way. Therefor we use the
01462  * Kannel sendsms interface layout as generic fallback. So if your
01463  * SMSC provider needs to send MO messages, he needs to implement
01464  * the Kannel sendsms HTTP interface variables.
01465  * 
01466  * Example config group:
01467  * 
01468  *  group = smsc
01469  *  smsc = http
01470  *  system-type = generic
01471  *  send-url = "http://<foobar>/<uri>?from=%P&to=%p&text=%b"
01472  *  status-success-regex = "ok"
01473  *  status-permfail-regex = "failure"
01474  *  status-tempfail-regex = "retry later"
01475  * 
01476  * Note that neither 'smsc-username' nor 'smsc-password' is required,
01477  * since they are coded into the the 'send-url' value directly. 
01478  * 
01479  * Stipe Tolj <st@tolj.org>
01480  */
01481 
01482 static void generic_send_sms(SMSCConn *conn, Msg *sms)
01483 {
01484     ConnData *conndata = conn->data;
01485     Octstr *url;
01486     List *headers;
01487 
01488     /* We use the escape code population function from our
01489      * URLTranslation module to fill in the appropriate values
01490      * into the URL scheme. */
01491     url = urltrans_fill_escape_codes(conndata->send_url, sms);
01492 
01493     headers = gwlist_create();
01494     debug("smsc.http.generic", 0, "HTTP[%s]: Sending request <%s>",
01495           octstr_get_cstr(conn->id), octstr_get_cstr(url));
01496     http_start_request(conndata->http_ref, HTTP_METHOD_GET, url, headers, 
01497                        NULL, 0, sms, NULL);
01498 
01499     octstr_destroy(url);
01500     http_destroy_headers(headers);
01501 }
01502 
01503 static void generic_parse_reply(SMSCConn *conn, Msg *msg, int status,
01504                                 List *headers, Octstr *body)
01505 {
01506     ConnData *conndata = conn->data;
01507     size_t n_match = 1;
01508     regmatch_t p_match[10];
01509     
01510     /* 
01511      * Our generic type checks only content on the HTTP reponse body.
01512      * We use the pre-compiled regex to match against the states.
01513      * This is the most generic criteria (at the moment). 
01514      */
01515     if ((conndata->success_regex != NULL) && 
01516         (gw_regex_exec(conndata->success_regex, body, n_match, p_match, 0) == 0)) {
01517         bb_smscconn_sent(conn, msg, NULL);
01518     } 
01519     else if ((conndata->permfail_regex != NULL) &&        
01520         (gw_regex_exec(conndata->permfail_regex, body, n_match, p_match, 0) == 0)) {
01521         error(0, "HTTP[%s]: Message not accepted.", octstr_get_cstr(conn->id));
01522         bb_smscconn_send_failed(conn, msg,
01523             SMSCCONN_FAILED_MALFORMED, octstr_duplicate(body));
01524     }
01525     else if ((conndata->tempfail_regex != NULL) &&        
01526         (gw_regex_exec(conndata->tempfail_regex, body, n_match, p_match, 0) == 0)) {
01527         warning(0, "HTTP[%s]: Message temporary not accepted, will retry.", 
01528                 octstr_get_cstr(conn->id));
01529         bb_smscconn_send_failed(conn, msg,
01530             SMSCCONN_FAILED_TEMPORARILY, octstr_duplicate(body));
01531     }
01532     else {
01533         error(0, "HTTP[%s]: Message was rejected. SMSC reponse was:",
01534               octstr_get_cstr(conn->id));
01535         octstr_dump(body, 0);
01536         bb_smscconn_send_failed(conn, msg,
01537             SMSCCONN_FAILED_REJECTED, octstr_create("REJECTED"));
01538     }
01539 }
01540 
01541 
01542 /*-----------------------------------------------------------------
01543  * functions to implement various smscconn operations
01544  */
01545 
01546 static int httpsmsc_send(SMSCConn *conn, Msg *msg)
01547 {
01548     ConnData *conndata = conn->data;
01549     Msg *sms = msg_duplicate(msg);
01550     double delay = 0;
01551 
01552     if (conn->throughput > 0) {
01553         delay = 1.0 / conn->throughput;
01554     }
01555 
01556     /* convert character encoding if required */
01557     if (conndata->alt_charset && 
01558         charset_convert(sms->sms.msgdata, DEFAULT_CHARSET,
01559                         octstr_get_cstr(conndata->alt_charset)) != 0)
01560         error(0, "Failed to convert msgdata from charset <%s> to <%s>, will send as is.",
01561                  DEFAULT_CHARSET, octstr_get_cstr(conndata->alt_charset));
01562 
01563     conndata->open_sends++;
01564     conndata->send_sms(conn, sms);
01565 
01566     /* obey throughput speed limit, if any */
01567     if (conn->throughput > 0)
01568         gwthread_sleep(delay);
01569 
01570     return 0;
01571 }
01572 
01573 
01574 static long httpsmsc_queued(SMSCConn *conn)
01575 {
01576     ConnData *conndata = conn->data;
01577 
01578     return (conndata ? (conn->status != SMSCCONN_DEAD ? 
01579             conndata->open_sends : 0) : 0);
01580 }
01581 
01582 
01583 static int httpsmsc_shutdown(SMSCConn *conn, int finish_sending)
01584 {
01585     ConnData *conndata = conn->data;
01586 
01587     debug("httpsmsc_shutdown", 0, "HTTP[%s]: Shutting down",
01588           octstr_get_cstr(conn->id));
01589     conn->why_killed = SMSCCONN_KILLED_SHUTDOWN;
01590     conndata->shutdown = 1;
01591 
01592     http_close_port(conndata->port);
01593     return 0;
01594 }
01595 
01596 
01597 int smsc_http_create(SMSCConn *conn, CfgGroup *cfg)
01598 {
01599     ConnData *conndata = NULL;
01600     Octstr *type;
01601     long portno;   /* has to be long because of cfg_get_integer */
01602     int ssl = 0;   /* indicate if SSL-enabled server should be used */
01603     Octstr *os;
01604 
01605     if (cfg_get_integer(&portno, cfg, octstr_imm("port")) == -1) {
01606         error(0, "HTTP[%s]: 'port' invalid in smsc 'http' record.",
01607               octstr_get_cstr(conn->id));
01608         return -1;
01609     }
01610     cfg_get_bool(&ssl, cfg, octstr_imm("use-ssl"));
01611     if ((type = cfg_get(cfg, octstr_imm("system-type")))==NULL) {
01612         error(0, "HTTP[%s]: 'type' missing in smsc 'http' record.",
01613               octstr_get_cstr(conn->id));
01614         octstr_destroy(type);
01615         return -1;
01616     }
01617     conndata = gw_malloc(sizeof(ConnData));
01618     conndata->http_ref = NULL;
01619     conndata->success_regex = 
01620         conndata->permfail_regex = conndata->tempfail_regex = NULL;
01621 
01622     conndata->allow_ip = cfg_get(cfg, octstr_imm("connect-allow-ip"));
01623     conndata->send_url = cfg_get(cfg, octstr_imm("send-url"));
01624     conndata->dlr_url = cfg_get(cfg, octstr_imm("dlr-url"));
01625     conndata->username = cfg_get(cfg, octstr_imm("smsc-username"));
01626     conndata->password = cfg_get(cfg, octstr_imm("smsc-password"));
01627     conndata->system_id = cfg_get(cfg, octstr_imm("system-id"));
01628     cfg_get_bool(&conndata->no_sender, cfg, octstr_imm("no-sender"));
01629     cfg_get_bool(&conndata->no_coding, cfg, octstr_imm("no-coding"));
01630     cfg_get_bool(&conndata->no_sep, cfg, octstr_imm("no-sep"));
01631     conndata->proxy = cfg_get(cfg, octstr_imm("system-id"));
01632     conndata->alt_charset = cfg_get(cfg, octstr_imm("alt-charset"));
01633 
01634     if (conndata->send_url == NULL)
01635         panic(0, "HTTP[%s]: Sending not allowed. No 'send-url' specified.",
01636               octstr_get_cstr(conn->id));
01637 
01638     if (octstr_case_compare(type, octstr_imm("kannel")) == 0) {
01639         if (conndata->username == NULL || conndata->password == NULL) {
01640             error(0, "HTTP[%s]: 'username' and 'password' required for Kannel http smsc",
01641                   octstr_get_cstr(conn->id));
01642             goto error;
01643         }
01644         conndata->receive_sms = kannel_receive_sms;
01645         conndata->send_sms = kannel_send_sms;
01646         conndata->parse_reply = kannel_parse_reply;
01647     }
01648     else if (octstr_case_compare(type, octstr_imm("brunet")) == 0) {
01649         if (conndata->username == NULL) {
01650             error(0, "HTTP[%s]: 'username' (=CustomerId) required for bruNET http smsc",
01651                   octstr_get_cstr(conn->id));
01652             goto error;
01653         }
01654         conndata->receive_sms = brunet_receive_sms;
01655         conndata->send_sms = brunet_send_sms;
01656         conndata->parse_reply = brunet_parse_reply;
01657     }
01658     else if (octstr_case_compare(type, octstr_imm("xidris")) == 0) {
01659         if (conndata->username == NULL || conndata->password == NULL) {
01660             error(0, "HTTP[%s]: 'username' and 'password' required for Xidris http smsc",
01661                   octstr_get_cstr(conn->id));
01662             goto error;
01663         }
01664         conndata->receive_sms = xidris_receive_sms;
01665         conndata->send_sms = xidris_send_sms;
01666         conndata->parse_reply = xidris_parse_reply;
01667     }
01668     else if (octstr_case_compare(type, octstr_imm("wapme")) == 0) {
01669         if (conndata->username == NULL || conndata->password == NULL) {
01670             error(0, "HTTP[%s]: 'username' and 'password' required for Wapme http smsc",
01671                   octstr_get_cstr(conn->id));
01672             goto error;
01673         }
01674         conndata->receive_sms = kannel_receive_sms; /* emulate sendsms interface */
01675         conndata->send_sms = wapme_smsproxy_send_sms;
01676         conndata->parse_reply = wapme_smsproxy_parse_reply;
01677     }
01678     else if (octstr_case_compare(type, octstr_imm("clickatell")) == 0) {
01679         /* no required data checks here? */
01680         conndata->receive_sms = clickatell_receive_sms;
01681         conndata->send_sms = clickatell_send_sms;
01682         conndata->parse_reply = clickatell_parse_reply;
01683     }
01684     else if (octstr_case_compare(type, octstr_imm("generic")) == 0) {
01685         /* we need at least the criteria for a successfull sent */
01686         if ((os = cfg_get(cfg, octstr_imm("status-success-regex"))) == NULL) {
01687             error(0, "HTTP[%s]: 'status-success-regex' required for generic http smsc",
01688                   octstr_get_cstr(conn->id));
01689             goto error;
01690         }
01691         conndata->receive_sms = kannel_receive_sms; /* emulate sendsms interface */
01692         conndata->send_sms = generic_send_sms;
01693         conndata->parse_reply = generic_parse_reply;
01694 
01695         /* pre-compile regex expressions */
01696         if (os != NULL) {   /* this is implicite due to the above if check */
01697             if ((conndata->success_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL)
01698                 panic(0, "Could not compile regex pattern '%s'", octstr_get_cstr(os));
01699             octstr_destroy(os);
01700         }
01701         if ((os = cfg_get(cfg, octstr_imm("status-permfail-regex"))) != NULL) {
01702             if ((conndata->permfail_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL)
01703                 panic(0, "Could not compile regex pattern '%s'", octstr_get_cstr(os));
01704             octstr_destroy(os);
01705         }
01706         if ((os = cfg_get(cfg, octstr_imm("status-tempfail-regex"))) != NULL) {
01707             if ((conndata->tempfail_regex = gw_regex_comp(os, REG_EXTENDED)) == NULL)
01708                 panic(0, "Could not compile regex pattern '%s'", octstr_get_cstr(os));
01709             octstr_destroy(os);
01710         }
01711     }
01712     /*
01713      * ADD NEW HTTP SMSC TYPES HERE
01714      */
01715     else {
01716     error(0, "HTTP[%s]: system-type '%s' unknown smsc 'http' record.",
01717           octstr_get_cstr(conn->id), octstr_get_cstr(type));
01718 
01719     goto error;
01720     }   
01721     conndata->open_sends = 0;
01722     conndata->http_ref = http_caller_create();
01723     
01724     conn->data = conndata;
01725     conn->name = octstr_format("HTTP:%S", type);
01726     conn->status = SMSCCONN_ACTIVE;
01727     conn->connect_time = time(NULL);
01728 
01729     conn->shutdown = httpsmsc_shutdown;
01730     conn->queued = httpsmsc_queued;
01731     conn->send_msg = httpsmsc_send;
01732 
01733     if (http_open_port_if(portno, ssl, conn->our_host)==-1)
01734     goto error;
01735 
01736     conndata->port = portno;
01737     conndata->shutdown = 0;
01738     
01739     if ((conndata->receive_thread =
01740      gwthread_create(httpsmsc_receiver, conn)) == -1)
01741     goto error;
01742 
01743     if ((conndata->send_cb_thread =
01744      gwthread_create(httpsmsc_send_cb, conn)) == -1)
01745     goto error;
01746 
01747     info(0, "HTTP[%s]: Initiated and ready", octstr_get_cstr(conn->id));
01748     
01749     octstr_destroy(type);
01750     return 0;
01751 
01752 error:
01753     error(0, "HTTP[%s]: Failed to create http smsc connection",
01754           octstr_get_cstr(conn->id));
01755 
01756     conn->data = NULL;
01757     conndata_destroy(conndata);
01758     conn->why_killed = SMSCCONN_KILLED_CANNOT_CONNECT;
01759     conn->status = SMSCCONN_DEAD;
01760     octstr_destroy(type);
01761     return -1;
01762 }
01763 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.