Index: gw/smsc/smsc_http.c =================================================================== RCS file: /home/cvs/gateway/gw/smsc/smsc_http.c,v retrieving revision 1.61 diff -u -b -w -r1.61 smsc_http.c --- gw/smsc/smsc_http.c 14 Jan 2009 11:11:46 -0000 1.61 +++ gw/smsc/smsc_http.c 28 May 2009 17:22:01 -0000 @@ -129,8 +129,33 @@ #define DEFAULT_CHARSET "UTF-8" +/* + * This maps fields to values for MO parameters + */ +typedef struct fieldmap { + Octstr *username; + Octstr *password; + Octstr *from; + Octstr *to; + Octstr *text; + Octstr *udh; + Octstr *account; + Octstr *binfo; + Octstr *dlr_mask; + Octstr *dlr_url; + Octstr *dlr_mid; + Octstr *flash; + Octstr *mclass; + Octstr *mwi; + Octstr *coding; + Octstr *validity; + Octstr *deferred; + Octstr *foreign_id; +} FieldMap; + typedef struct conndata { HTTPCaller *http_ref; + FieldMap *fieldmap; long receive_thread; long send_cb_thread; int shutdown; @@ -165,6 +190,35 @@ } ConnData; +/* + * Destroys the FieldMap structure + */ +static void fieldmap_destroy(FieldMap *fieldmap) +{ + if (fieldmap == NULL) + return; + octstr_destroy(fieldmap->username); + octstr_destroy(fieldmap->password); + octstr_destroy(fieldmap->from); + octstr_destroy(fieldmap->to); + octstr_destroy(fieldmap->text); + octstr_destroy(fieldmap->udh); + octstr_destroy(fieldmap->account); + octstr_destroy(fieldmap->binfo); + octstr_destroy(fieldmap->dlr_mask); + octstr_destroy(fieldmap->dlr_url); + octstr_destroy(fieldmap->dlr_mid); + octstr_destroy(fieldmap->flash); + octstr_destroy(fieldmap->mclass); + octstr_destroy(fieldmap->mwi); + octstr_destroy(fieldmap->coding); + octstr_destroy(fieldmap->validity); + octstr_destroy(fieldmap->deferred); + octstr_destroy(fieldmap->foreign_id); + gw_free(fieldmap); +} + + static void conndata_destroy(ConnData *conndata) { if (conndata == NULL) @@ -177,6 +231,7 @@ gw_regex_destroy(conndata->permfail_regex); if (conndata->tempfail_regex) gw_regex_destroy(conndata->tempfail_regex); + fieldmap_destroy(conndata->fieldmap); octstr_destroy(conndata->allow_ip); octstr_destroy(conndata->send_url); octstr_destroy(conndata->dlr_url); @@ -1454,7 +1509,7 @@ /*---------------------------------------------------------------- - * (Semi-)generic HTTP interface + * Generic HTTP interface * * This 'generic' type will handle the 'send-url' directive in the * group the same way the 'sms-service' for smsbox does, via @@ -1462,12 +1517,6 @@ * regex value that match against the reponse body. The HTTP reponse * code is not obeyed. * - * It handles mainly MT messages, due to the fact that MO traffic - * can't be abstracted in a universal way. Therefor we use the - * Kannel sendsms interface layout as generic fallback. So if your - * SMSC provider needs to send MO messages, he needs to implement - * the Kannel sendsms HTTP interface variables. - * * Example config group: * * group = smsc @@ -1477,6 +1526,9 @@ * status-success-regex = "ok" * status-permfail-regex = "failure" * status-tempfail-regex = "retry later" + * generic-param-from = "phoneNumber" + * generic-param-to = "shortCode" + * generic-param-text = "message" * * Note that neither 'smsc-username' nor 'smsc-password' is required, * since they are coded into the the 'send-url' value directly. @@ -1484,6 +1536,221 @@ * Stipe Tolj */ +/* + * Get the FieldMap struct to map MO parameters + */ +static FieldMap *generic_get_field_map(CfgGroup *grp) +{ + FieldMap *fm = NULL; + fm = gw_malloc(sizeof(FieldMap)); + gw_assert(fm != NULL); + fm->username = cfg_get(grp, octstr_imm("generic-param-username")); + if (fm->username == NULL) + fm->username = octstr_create("username"); + fm->password = cfg_get(grp, octstr_imm("generic-param-password")); + if (fm->password == NULL) + fm->password = octstr_create("password"); + fm->from = cfg_get(grp, octstr_imm("generic-param-from")); + if (fm->from == NULL) + fm->from = octstr_create("from"); + fm->to = cfg_get(grp, octstr_imm("generic-param-to")); + if (fm->to == NULL) + fm->to = octstr_create("to"); + fm->text = cfg_get(grp, octstr_imm("generic-param-text")); + if (fm->text == NULL) + fm->text = octstr_create("text"); + fm->udh = cfg_get(grp, octstr_imm("generic-param-udh")); + if (fm->udh == NULL) + fm->udh = octstr_create("udh"); + fm->account = cfg_get(grp, octstr_imm("generic-param-account")); + if (fm->account == NULL) + fm->account = octstr_create("account"); + fm->binfo = cfg_get(grp, octstr_imm("generic-param-binfo")); + if (fm->binfo == NULL) + fm->binfo = octstr_create("binfo"); + fm->dlr_mask = cfg_get(grp, octstr_imm("generic-param-dlr-mask")); + if (fm->dlr_mask == NULL) + fm->dlr_mask = octstr_create("dlr-mask"); + fm->dlr_url = cfg_get(grp, octstr_imm("generic-param-dlr-url")); + if (fm->dlr_url == NULL) + fm->dlr_url = octstr_create("dlr-url"); + fm->dlr_mid = cfg_get(grp, octstr_imm("generic-param-dlr-mid")); + if (fm->dlr_mid == NULL) + fm->dlr_mid = octstr_create("dlr-mid"); + fm->flash = cfg_get(grp, octstr_imm("generic-param-flash")); + if (fm->flash == NULL) + fm->flash = octstr_create("flash"); + fm->mclass = cfg_get(grp, octstr_imm("generic-param-mclass")); + if (fm->mclass == NULL) + fm->mclass = octstr_create("mclass"); + fm->mwi = cfg_get(grp, octstr_imm("generic-param-mwi")); + if (fm->mwi == NULL) + fm->mwi = octstr_create("mwi"); + fm->coding = cfg_get(grp, octstr_imm("generic-param-coding")); + if (fm->coding == NULL) + fm->coding = octstr_create("coding"); + fm->validity = cfg_get(grp, octstr_imm("generic-param-validity")); + if (fm->validity == NULL) + fm->validity = octstr_create("validity"); + fm->deferred = cfg_get(grp, octstr_imm("generic-param-deferred")); + if (fm->deferred == NULL) + fm->deferred = octstr_create("deferred"); + fm->foreign_id = cfg_get(grp, octstr_imm("generic-param-foreign-id")); + if (fm->foreign_id == NULL) + fm->foreign_id = octstr_create("foreign-id"); + + return fm; +} + +static void generic_receive_sms(SMSCConn *conn, HTTPClient *client, + List *headers, Octstr *body, List *cgivars) +{ + ConnData *conndata = conn->data; + FieldMap *fm = conndata->fieldmap; + Octstr *user, *pass, *from, *to, *text, *udh, *account, *binfo; + Octstr *dlrurl, *dlrmid; + Octstr *tmp_string, *retmsg; + int mclass, mwi, coding, validity, deferred, dlrmask; + List *reply_headers; + int ret; + + mclass = mwi = coding = validity = + deferred = dlrmask = SMS_PARAM_UNDEFINED; + + user = http_cgi_variable(cgivars, octstr_get_cstr(fm->username)); + pass = http_cgi_variable(cgivars, octstr_get_cstr(fm->password)); + from = http_cgi_variable(cgivars, octstr_get_cstr(fm->from)); + to = http_cgi_variable(cgivars, octstr_get_cstr(fm->to)); + text = http_cgi_variable(cgivars, octstr_get_cstr(fm->text)); + udh = http_cgi_variable(cgivars, octstr_get_cstr(fm->udh)); + account = http_cgi_variable(cgivars, octstr_get_cstr(fm->account)); + binfo = http_cgi_variable(cgivars, octstr_get_cstr(fm->binfo)); + dlrurl = http_cgi_variable(cgivars, octstr_get_cstr(fm->dlr_url)); + dlrmid = http_cgi_variable(cgivars, octstr_get_cstr(fm->dlr_mid)); + tmp_string = http_cgi_variable(cgivars, octstr_get_cstr(fm->flash)); + if (tmp_string) { + sscanf(octstr_get_cstr(tmp_string),"%d", &mclass); + } + tmp_string = http_cgi_variable(cgivars, octstr_get_cstr(fm->mclass)); + if (tmp_string) { + sscanf(octstr_get_cstr(tmp_string),"%d", &mclass); + } + tmp_string = http_cgi_variable(cgivars, octstr_get_cstr(fm->mwi)); + if (tmp_string) { + sscanf(octstr_get_cstr(tmp_string),"%d", &mwi); + } + tmp_string = http_cgi_variable(cgivars, octstr_get_cstr(fm->coding)); + if (tmp_string) { + sscanf(octstr_get_cstr(tmp_string),"%d", &coding); + } + tmp_string = http_cgi_variable(cgivars, octstr_get_cstr(fm->validity)); + if (tmp_string) { + sscanf(octstr_get_cstr(tmp_string),"%d", &validity); + } + tmp_string = http_cgi_variable(cgivars, octstr_get_cstr(fm->deferred)); + if (tmp_string) { + sscanf(octstr_get_cstr(tmp_string),"%d", &deferred); + } + tmp_string = http_cgi_variable(cgivars, octstr_get_cstr(fm->dlr_mask)); + if (tmp_string) { + sscanf(octstr_get_cstr(tmp_string),"%d", &dlrmask); + } + debug("smsc.http.kannel", 0, "HTTP[%s]: Received an HTTP request", + octstr_get_cstr(conn->id)); + + if ((conndata->username != NULL && conndata->password != NULL) && + (user == NULL || pass == NULL || + octstr_compare(user, conndata->username) != 0 || + octstr_compare(pass, conndata->password) != 0)) { + error(0, "HTTP[%s]: Authorization failure", + octstr_get_cstr(conn->id)); + retmsg = octstr_create("Authorization failed for sendsms"); + } + else if (dlrurl != NULL && dlrmask != 0 && dlrmid != NULL) { + /* we got a DLR, and we don't require additional values */ + Msg *dlrmsg; + + dlrmsg = dlr_find(conn->id, + dlrmid, /* message id */ + to, /* destination */ + dlrmask); + + if (dlrmsg != NULL) { + dlrmsg->sms.sms_type = report_mo; + + debug("smsc.http.kannel", 0, "HTTP[%s]: Received DLR for DLR-URL <%s>", + octstr_get_cstr(conn->id), octstr_get_cstr(dlrmsg->sms.dlr_url)); + + ret = bb_smscconn_receive(conn, dlrmsg); + if (ret == -1) + retmsg = octstr_create("Not accepted"); + else + retmsg = octstr_create("Sent."); + } else { + error(0,"HTTP[%s]: Got DLR but could not find message or was not interested " + "in it id<%s> dst<%s>, type<%d>", + octstr_get_cstr(conn->id), octstr_get_cstr(dlrmid), + octstr_get_cstr(to), dlrmask); + retmsg = octstr_create("Unknown DLR, not accepted"); + } + } + else if (from == NULL || to == NULL || text == NULL) { + + error(0, "HTTP[%s]: Insufficient args", + octstr_get_cstr(conn->id)); + retmsg = octstr_create("Insufficient args, rejected"); + } + else if (udh != NULL && (octstr_len(udh) != octstr_get_char(udh, 0) + 1)) { + error(0, "HTTP[%s]: UDH field misformed, rejected", + octstr_get_cstr(conn->id)); + retmsg = octstr_create("UDH field misformed, rejected"); + } + else if (udh != NULL && octstr_len(udh) > MAX_SMS_OCTETS) { + error(0, "HTTP[%s]: UDH field is too long, rejected", + octstr_get_cstr(conn->id)); + retmsg = octstr_create("UDH field is too long, rejected"); + } + else { + /* we got a normal MO SMS */ + Msg *msg; + msg = msg_create(sms); + + debug("smsc.http.kannel", 0, "HTTP[%s]: Constructing new SMS", + octstr_get_cstr(conn->id)); + + msg->sms.service = octstr_duplicate(user); + msg->sms.sender = octstr_duplicate(from); + msg->sms.receiver = octstr_duplicate(to); + msg->sms.msgdata = octstr_duplicate(text); + msg->sms.udhdata = octstr_duplicate(udh); + + msg->sms.smsc_id = octstr_duplicate(conn->id); + msg->sms.time = time(NULL); + msg->sms.mclass = mclass; + msg->sms.mwi = mwi; + msg->sms.coding = coding; + msg->sms.validity = validity; + msg->sms.deferred = deferred; + msg->sms.account = octstr_duplicate(account); + msg->sms.binfo = octstr_duplicate(binfo); + ret = bb_smscconn_receive(conn, msg); + if (ret == -1) + retmsg = octstr_create("Not accepted"); + else + retmsg = octstr_create("Sent."); + } + + reply_headers = gwlist_create(); + http_header_add(reply_headers, "Content-Type", "text/plain"); + debug("smsc.http.kannel", 0, "HTTP[%s]: Sending reply", + octstr_get_cstr(conn->id)); + http_send_reply(client, HTTP_ACCEPTED, reply_headers, retmsg); + + octstr_destroy(retmsg); + http_destroy_headers(reply_headers); +} + + static void generic_send_sms(SMSCConn *conn, Msg *sms) { ConnData *conndata = conn->data; @@ -1635,6 +1902,7 @@ cfg_get_bool(&conndata->no_sep, cfg, octstr_imm("no-sep")); conndata->proxy = cfg_get(cfg, octstr_imm("system-id")); conndata->alt_charset = cfg_get(cfg, octstr_imm("alt-charset")); + conndata->fieldmap = generic_get_field_map(cfg); if (conndata->send_url == NULL) panic(0, "HTTP[%s]: Sending not allowed. No 'send-url' specified.", @@ -1693,7 +1961,7 @@ octstr_get_cstr(conn->id)); goto error; } - conndata->receive_sms = kannel_receive_sms; /* emulate sendsms interface */ + conndata->receive_sms = generic_receive_sms; /* emulate sendsms interface */ conndata->send_sms = generic_send_sms; conndata->parse_reply = generic_parse_reply; Index: gwlib/cfg.def =================================================================== RCS file: /home/cvs/gateway/gwlib/cfg.def,v retrieving revision 1.139 diff -u -b -w -r1.139 cfg.def --- gwlib/cfg.def 6 May 2009 18:47:34 -0000 1.139 +++ gwlib/cfg.def 28 May 2009 17:22:01 -0000 @@ -386,6 +386,24 @@ OCTSTR(max-sms-octets) OCTSTR(login-prompt) OCTSTR(password-prompt) + OCTSTR(generic-param-username) + OCTSTR(generic-param-password) + OCTSTR(generic-param-from) + OCTSTR(generic-param-to) + OCTSTR(generic-param-text) + OCTSTR(generic-param-udh) + OCTSTR(generic-param-account) + OCTSTR(generic-param-binfo) + OCTSTR(generic-param-dlr-mask) + OCTSTR(generic-param-dlr-url) + OCTSTR(generic-param-dlr-mid) + OCTSTR(generic-param-flash) + OCTSTR(generic-param-mclass) + OCTSTR(generic-param-mwi) + OCTSTR(generic-param-coding) + OCTSTR(generic-param-validity) + OCTSTR(generic-param-deferred) + OCTSTR(generic-param-foreign-id) )