1
0
Fork 0
mbuni/mbuni/mmsbox/bearerbox.c

909 lines
26 KiB
C

/*
* Mbuni - Open Source MMS Gateway
*
* MMSC handler functions: Receive and send MMS messages to MMSCs
*
* Copyright (C) 2003 - 2005, Digital Solutions Ltd. - http://www.dsmagic.com
*
* Paul Bagyenda <bagyenda@dsmagic.com>
*
* This program is free software, distributed under the terms of
* the GNU General Public License, with a few exceptions granted (see LICENSE)
*/
#include <sys/file.h>
#include <ctype.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <errno.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mmsbox.h"
#include "mms_queue.h"
#include "mmsbox.h"
typedef struct MmsHTTPClientInfo {
HTTPClient *client;
Octstr *ua;
Octstr *ip;
List *headers;
Octstr *url;
Octstr *body;
List *cgivars;
MmscGrp *m;
} MmsHTTPClientInfo;
static void free_clientInfo(MmsHTTPClientInfo *h, int freeh);
static int auth_check(Octstr *user, Octstr *pass, List *headers)
{
int i, res = -1;
Octstr *v = http_header_value(headers, octstr_imm("Authorization"));
Octstr *p = NULL, *q = NULL;
if (user == NULL ||
octstr_len(user) == 0) {
res = 0;
goto done;
}
if (!v ||
octstr_search(v, octstr_imm("Basic "), 0) != 0)
goto done;
p = octstr_copy(v, sizeof "Basic", octstr_len(v));
octstr_base64_to_binary(p);
i = octstr_search_char(p, ':', 0);
q = octstr_copy(p, i+1, octstr_len(p));
octstr_delete(p, i, octstr_len(p));
/* p = user, q = pass. */
if (octstr_compare(user, p) != 0 ||
octstr_compare(pass, q) != 0)
res = -1;
else
res = 0;
done:
if (v)
octstr_destroy(v);
if (p)
octstr_destroy(p);
if (q)
octstr_destroy(q);
return res;
}
static int send_report(Octstr *from, char *report_type, Octstr *status,
Octstr *msgid, Octstr *mmc_id)
{
Octstr *url = mms_dlr_url_get(msgid, report_type, mmc_id);
List *rh, *rph = NULL;
Octstr *furl = NULL, *rb = NULL;
if (!url)
return 0;
rh = http_create_empty_headers();
http_header_add(rh, "X-Mbuni-Report-Type", report_type);
http_header_add(rh, "X-Mbuni-MM-Status", octstr_get_cstr(status));
http_header_add(rh, "X-Mbuni-Message-ID", octstr_get_cstr(msgid));
http_header_add(rh, "X-Mbuni-MMSC-ID", octstr_get_cstr(mmc_id));
http_header_add(rh, "X-Mbuni-From", octstr_get_cstr(from));
http_get_real(HTTP_METHOD_GET, url, rh, &furl, &rph, &rb);
if (furl)
octstr_destroy(furl);
if (rb)
octstr_destroy(rb);
octstr_destroy(url);
if (rph)
http_destroy_headers(rph);
http_destroy_headers(rh);
/* At what point do we delete it? For now, when we get a read report,
* and also when we get a delivery report that is not 'deferred'
*/
if (strcmp(report_type, "read-report") == 0 ||
octstr_case_compare(status, octstr_imm("Deferred")) != 0)
mms_dlr_url_remove(msgid, report_type, mmc_id);
return 0;
}
/* These functions are very similar to those in mmsproxy */
static void mm7soap_receive(MmsHTTPClientInfo *h)
{
MSoapMsg_t *mreq = NULL, *mresp = NULL;
int hstatus = HTTP_OK;
List *rh = NULL;
Octstr *reply_body = NULL, *value;
List *to = NULL;
Octstr *from = NULL, *subject = NULL, *vasid = NULL, *msgid = NULL;
time_t expiryt = -1, delivert = -1;
MmsMsg *m = NULL;
int status = 1000;
unsigned char *msgtype = (unsigned char *)"";
Octstr *qf = NULL;
if (h->body)
mreq = mm7_parse_soap(h->headers, h->body);
if (mreq)
msgtype = mms_mm7tag_to_cstr(mm7_msgtype(mreq));
debug("mmsbox.mm7sendinterface", 0,
" --> Enterred mm7dispatch interface, mreq=%s mtype = %s <-- ",
mreq ? "Ok" : "Null",
mreq ? (char *)msgtype : "Null");
if (!mreq) {
mresp = mm7_make_resp(NULL, MM7_SOAP_FORMAT_CORRUPT, NULL);
goto done;
}
mm7_get_envelope(mreq, &from, &to, &subject, &vasid, &expiryt, &delivert);
if (!from)
from = octstr_imm("anon@anon");
switch (mm7_msgtype(mreq)) {
case MM7_TAG_DeliverReq:
m = mm7_soap_to_mmsmsg(mreq, from);
if (m) {
Octstr *value = NULL;
/* Store linked id so we use it in response. */
Octstr *linkedid = mm7_soap_header_value(mreq, octstr_imm("LinkedID"));
int dlr;
value = mms_get_header_value(m, octstr_imm("X-Mms-Delivery-Report"));
if (value &&
octstr_case_compare(value, octstr_imm("Yes")) == 0)
dlr = 1;
else
dlr = 0;
if (delivert < 0)
delivert = time(NULL);
if (expiryt < 0)
expiryt = time(NULL) + DEFAULT_EXPIRE;
qf = mms_queue_add(from, to, subject,
h->m->id, NULL,
delivert, expiryt, m, linkedid,
NULL, NULL,
NULL, NULL,
NULL,
dlr,
octstr_get_cstr(incoming_qdir),
octstr_imm(MM_NAME));
msgid = mms_maketransid(octstr_get_cstr(qf), octstr_imm(MM_NAME));
mms_log("Received", from, to, -1, msgid, NULL, h->m->id, "MMSBox", h->ua, NULL);
if (linkedid)
octstr_destroy(linkedid);
octstr_destroy(value);
} else
status = 4000;
mresp = mm7_make_resp(mreq, status, NULL);
break;
case MM7_TAG_DeliveryReportReq:
msgid = mm7_soap_header_value(mreq, octstr_imm("MessageID"));
value = mm7_soap_header_value(mreq, octstr_imm("MMStatus"));
send_report(from, "delivery-report", value, msgid, h->m->id);
if (value)
octstr_destroy(value);
mms_log("DeliveryReport",
from, NULL, -1, msgid, NULL, h->m->id, "MMSBox", h->ua, NULL);
mresp = mm7_make_resp(mreq, status, NULL);
break;
case MM7_TAG_ReadReplyReq:
msgid = mm7_soap_header_value(mreq, octstr_imm("MessageID"));
value = mm7_soap_header_value(mreq, octstr_imm("MMStatus"));
send_report(from, "read-report", value, msgid, h->m->id);
if (value)
octstr_destroy(value);
mms_log("ReadReport",
from, NULL, -1, msgid, NULL, h->m->id, "MMSBox", h->ua, NULL);
mresp = mm7_make_resp(mreq, status, NULL);
break;
default:
mresp = mm7_make_resp(mreq, MM7_SOAP_UNSUPPORTED_OPERATION, NULL);
break;
}
done:
if (mresp && mm7_soapmsg_to_httpmsg(mresp, &rh, &reply_body) == 0)
http_send_reply(h->client, hstatus, rh, reply_body);
else
http_close_client(h->client);
debug("mmsbox.mm7sendinterface", 0,
" --> leaving mm7dispatch interface, mresp=%s, body=%s <-- ",
mresp ? "ok" : "(null)",
reply_body ? "ok" : "(null)");
if (from)
octstr_destroy(from);
if (subject)
octstr_destroy(subject);
if (vasid)
octstr_destroy(vasid);
if (msgid)
octstr_destroy(msgid);
if (qf)
octstr_destroy(qf);
if (m)
mms_destroy(m);
if (rh)
http_destroy_headers(rh);
if (reply_body)
octstr_destroy(reply_body);
if (mresp)
mm7_soap_destroy(mresp);
if (mreq)
mm7_soap_destroy(mreq);
if (to)
gwlist_destroy(to, (gwlist_item_destructor_t *)octstr_destroy);
}
static void mm7eaif_receive(MmsHTTPClientInfo *h)
{
MmsMsg *m = NULL;
List *mh = NULL;
int hstatus = HTTP_NO_CONTENT;
List *rh = http_create_empty_headers();
Octstr *reply_body = NULL, *value, *value2;
List *to = gwlist_create(), *hto = NULL;
Octstr *subject = NULL, *otransid = NULL, *msgid = NULL;
Octstr *hfrom = NULL;
time_t expiryt = -1, deliveryt = -1;
Octstr *qf = NULL;
int msize = h->body ? octstr_len(h->body) : 0;
int dlr;
int mtype;
debug("mmsbox.mm7eaif.sendinterface", 0,
" --> Enterred eaif send interface, blen=%d <--- ",
msize);
hfrom = http_header_value(h->headers, octstr_imm("X-NOKIA-MMSC-From"));
if (!h->body || /* A body is required, and must parse */
(m = mms_frombinary(h->body, hfrom ? hfrom : octstr_imm("anon@anon"))) == NULL) {
http_header_add(rh, "Content-Type", "text/plain");
hstatus = HTTP_BAD_REQUEST;
reply_body = octstr_format("Unexpected MMS message, no body?");
goto done;
}
/* XXXX handle delivery reports differently. */
mtype = mms_messagetype(m);
mh = mms_message_headers(m);
/* Now get sender and receiver data.
* for now we ignore adaptation flags.
*/
mms_collect_envdata_from_msgheaders(mh, &to, &subject,
&otransid, &expiryt, &deliveryt,
DEFAULT_EXPIRE);
if ((hto = http_header_find_all(h->headers, "X-NOKIA-MMSC-To")) != NULL &&
gwlist_len(hto) > 0) { /* To address is in headers. */
int i, n;
if (to)
gwlist_destroy(to, (gwlist_item_destructor_t *)octstr_destroy);
to = gwlist_create();
for (i = 0, n = gwlist_len(hto); i < n; i++) {
Octstr *h = NULL, *v = NULL;
List *l;
int j, m;
http_header_get(hto,i, &h, &v);
l = http_header_split_value(v);
for (j = 0, m = gwlist_len(l); j < m; j++)
gwlist_append(to, gwlist_get(l, j));
gwlist_destroy(l, NULL);
if (h) octstr_destroy(h);
if (v) octstr_destroy(v);
}
}
switch(mtype) {
case MMS_MSGTYPE_SEND_REQ:
case MMS_MSGTYPE_RETRIEVE_CONF:
/* Get Message ID */
if ((msgid = http_header_value(h->headers, octstr_imm("X-NOKIA-MMSC-Message-Id"))) == NULL)
msgid = http_header_value(mh, octstr_imm("Message-ID"));
else
mms_replace_header_value(m, "Message-ID", octstr_get_cstr(msgid)); /* replace it in the message.*/
value = http_header_value(mh, octstr_imm("X-Mms-Delivery-Report"));
if (value &&
octstr_case_compare(value, octstr_imm("Yes")) == 0)
dlr = 1;
else
dlr = 0;
if (value)
octstr_destroy(value);
if (deliveryt < 0)
deliveryt = time(NULL);
if (expiryt < 0)
expiryt = time(NULL) + DEFAULT_EXPIRE;
if (hfrom == NULL)
hfrom = http_header_value(mh, octstr_imm("From"));
mms_remove_headers(m, "Bcc");
mms_remove_headers(m, "X-Mms-Delivery-Time");
mms_remove_headers(m, "X-Mms-Expiry");
mms_remove_headers(m, "X-Mms-Sender-Visibility");
/* Save it, put message id in header, return. */
qf = mms_queue_add(hfrom, to, subject,
h->m->id, NULL, deliveryt, expiryt, m, NULL,
NULL, NULL,
NULL, NULL,
NULL,
dlr,
octstr_get_cstr(incoming_qdir),
octstr_imm(MM_NAME));
if (qf) {
/* Log to access log */
mms_log("Received", hfrom, to, msize, msgid, NULL, h->m->id, "MMSBox", h->ua, NULL);
octstr_destroy(qf);
hstatus = HTTP_NO_CONTENT;
} else
hstatus = HTTP_INTERNAL_SERVER_ERROR;
break;
case MMS_MSGTYPE_DELIVERY_IND:
value = http_header_value(mh, octstr_imm("X-Mms-Status"));
value2 = http_header_value(mh, octstr_imm("Message-ID"));
send_report(hfrom, "delivery-report", value, value2, h->m->id);
if (value)
octstr_destroy(value);
if (value2)
octstr_destroy(value2);
break;
case MMS_MSGTYPE_READ_ORIG_IND:
value = http_header_value(mh, octstr_imm("X-Mms-Read-Status"));
value2 = http_header_value(mh, octstr_imm("Message-ID"));
send_report(hfrom, "read-report", value, value2, h->m->id);
if (value)
octstr_destroy(value);
if (value2)
octstr_destroy(value2);
break;
}
done:
http_header_add(rh, "X-NOKIA-MMSC-Version", EAIF_VERSION);
http_send_reply(h->client, hstatus, rh, octstr_imm(""));
if (hto)
http_destroy_headers(hto);
if (to)
gwlist_destroy(to, (gwlist_item_destructor_t *)octstr_destroy);
if (hfrom)
octstr_destroy(hfrom);
if (subject)
octstr_destroy(subject);
if (otransid)
octstr_destroy(otransid);
if (msgid)
octstr_destroy(msgid);
if (mh)
http_destroy_headers(mh);
if (m) mms_destroy(m);
}
void mmsc_receive_func(MmscGrp *m)
{
MmsHTTPClientInfo h = {NULL};
h.m = m;
while(rstop == 0 &&
(h.client = http_accept_request(m->incoming.port,
&h.ip, &h.url, &h.headers,
&h.body, &h.cgivars)) != NULL)
if (is_allowed_ip(m->incoming.deny_ip, m->incoming.allow_ip, h.ip)) {
h.ua = http_header_value(h.headers, octstr_imm("User-Agent"));
debug("mmsbox", 0,
" MM7 Incoming, ip=%s, mmsc id=%s ",
h.ip ? octstr_get_cstr(h.ip) : "",
octstr_get_cstr(m->id));
/* Dump headers, url etc. */
#if 1
http_header_dump(h.headers);
if (h.body) octstr_dump(h.body, 0);
if (h.ip) octstr_dump(h.ip, 0);
#endif
if (auth_check(m->incoming.user,
m->incoming.pass,
h.headers) != 0) { /* Ask it to authenticate... */
List *hh = http_create_empty_headers();
http_header_add(hh, "WWW-Authenticate",
"Basic realm=\"" MM_NAME "\"");
http_send_reply(h.client, HTTP_UNAUTHORIZED, hh,
octstr_imm(""));
http_destroy_headers(hh);
info(0, "MMSBox: Auth failed, incoming connection, MMC group=%s",
m->id ? octstr_get_cstr(m->id) : "(none)");
} else if (m->type == SOAP_MMSC)
mm7soap_receive(&h);
else
mm7eaif_receive(&h);
free_clientInfo(&h, 0);
} else {
free_clientInfo(&h, 0);
http_close_client(h.client);
}
debug("proxy", 0, "MMSBox: MM7 Shutting down...");
}
static void free_clientInfo(MmsHTTPClientInfo *h, int freeh)
{
debug("free info", 0,
" entered free_clientinfo %d, ip=%d", freeh, (int)h->ip);
if (h->ip)
octstr_destroy(h->ip);
if (h->url)
octstr_destroy(h->url);
if (h->ua) octstr_destroy(h->ua);
if (h->body) octstr_destroy(h->body);
if (h->cgivars)
http_destroy_cgiargs(h->cgivars);
if (h->headers)
http_destroy_headers(h->headers);
if (freeh)
gw_free(h);
debug("free info", 0,
" left free_clientinfo");
}
/* XXX Returns msgid in mmsc or NULL if error. Caller uses this for DLR issues.
* Caller must make sure throughput issues
* are observed!
* Don't remove from queue on fail, just leave it to expire.
*/
static Octstr *mm7soap_send(MmscGrp *mmc, Octstr *from, Octstr *to,
Octstr *transid,
Octstr *linkedid,
char *vasid,
Octstr *service_code,
List *hdrs,
MmsMsg *m, Octstr **error)
{
Octstr *ret = NULL;
int mtype = mms_messagetype(m);
int hstatus = HTTP_OK, tstatus;
List *xto = gwlist_create();
MSoapMsg_t *mreq = NULL, *mresp = NULL;
List *rh = NULL, *ph = NULL;
Octstr *body = NULL, *rbody = NULL, *url = NULL;
Octstr *s;
info(0, "MMSBox: Send[soap] to MMSC[%s], msg type [%s], from %s, to %s",
mmc->id ? octstr_get_cstr(mmc->id) : "",
mms_message_type_to_cstr(mtype),
octstr_get_cstr(from), octstr_get_cstr(to));
gwlist_append(xto, to);
if ((mreq = mm7_mmsmsg_to_soap(m, from, xto, transid,
service_code,
linkedid,
1, octstr_get_cstr(mmc->id), vasid)) == NULL) {
*error = octstr_format("Failed to convert Msg[%s] 2 SOAP message!",
mms_message_type_to_cstr(mtype));
goto done1;
}
if (mm7_soapmsg_to_httpmsg(mreq, &rh, &body) < 0) {
*error = octstr_format("Failed to convert SOAP message 2 HTTP Msg!");
goto done1;
}
if (hdrs)
http_header_combine(rh, hdrs); /* If specified, then update and pass on. */
hstatus = mmsbox_url_fetch_content(HTTP_METHOD_POST, mmc->mmsc_url, rh, body, &ph,&rbody);
if (http_status_class(hstatus) != HTTP_STATUS_SUCCESSFUL) {
*error = octstr_format("Failed to contact MMC[url=%s] => HTTP returned status = %d!",
octstr_get_cstr(mmc->mmsc_url), hstatus);
goto done1;
}
if ((mresp = mm7_parse_soap(ph, rbody)) == NULL) {
*error = octstr_format("Failed to parse MMSC[url=%s, id=%s] response!",
octstr_get_cstr(mmc->mmsc_url),
octstr_get_cstr(mmc->id));
goto done1;
}
/* Now look at response code and use it to tell you what you want. */
if ((s = mm7_soap_header_value(mresp, octstr_imm("StatusCode"))) != NULL) {
tstatus = atoi(octstr_get_cstr(s));
octstr_destroy(s);
} else if ((s = mm7_soap_header_value(mresp, octstr_imm("faultstring"))) != NULL) {
tstatus = atoi(octstr_get_cstr(s));
octstr_destroy(s);
} else
tstatus = MM7_SOAP_FORMAT_CORRUPT;
if (!MM7_SOAP_STATUS_OK(tstatus)) {
Octstr *detail = mm7_soap_header_value(mresp, octstr_imm("Details"));
if (detail == NULL)
mm7_soap_header_value(mresp, octstr_imm("faultcode"));
ret = NULL;
info(0, "Send to MMSC[%s], failed, code=[%d=>%s], detail=%s",
mmc ? octstr_get_cstr(mmc->id) : "",
tstatus, mms_soap_status_to_cstr(tstatus),
detail ? octstr_get_cstr(detail) : "");
*error = octstr_format("Failed to deliver to MMC[url=%s, id=%s], status=[%d=>%s]!",
octstr_get_cstr(mmc->mmsc_url),
octstr_get_cstr(mmc->id),
tstatus,
mms_soap_status_to_cstr(tstatus));
if (detail)
octstr_destroy(detail);
} else
ret = mm7_soap_header_value(mresp, octstr_imm("MessageID"));
info(0, "Sent to MMC[%s], code=[%d=>%s], msgid [%s]", octstr_get_cstr(mmc->id),
tstatus, mms_soap_status_to_cstr(tstatus), ret ? octstr_get_cstr(ret) : "(none)");
if (ret)
mms_log2("Sent", from, to, -1, ret, NULL, mmc->id, "MMSBox", NULL, NULL);
done1:
if (mreq)
mm7_soap_destroy(mreq);
if (mresp)
mm7_soap_destroy(mresp);
if (rh)
http_destroy_headers(rh);
if (body)
octstr_destroy(body);
if (ph)
http_destroy_headers(ph);
if (rbody)
octstr_destroy(rbody);
if (url)
octstr_destroy(url);
gwlist_destroy(xto, NULL);
return ret;
}
static Octstr *mm7eaif_send(MmscGrp *mmc, Octstr *from, Octstr *to,
Octstr *transid,
char *vasid,
List *hdrs,
MmsMsg *m, Octstr **error)
{
Octstr *ret = NULL, *resp = NULL;
int mtype = mms_messagetype(m);
int hstatus = HTTP_OK;
List *rh = http_create_empty_headers(), *ph = NULL;
Octstr *body = NULL, *rbody = NULL, *url = NULL;
char *msgtype;
info(0, "MMSBox: Send [eaif] to MMC[%s], msg type [%s], from %s, to %s",
mmc ? octstr_get_cstr(mmc->id) : "",
mms_message_type_to_cstr(mtype),
octstr_get_cstr(from), octstr_get_cstr(to));
http_header_add(rh, "X-NOKIA-MMSC-To", octstr_get_cstr(to));
http_header_add(rh, "X-NOKIA-MMSC-From", octstr_get_cstr(from));
http_header_add(rh, "X-NOKIA-MMSC-Version", EAIF_VERSION);
if (mtype == MMS_MSGTYPE_SEND_REQ ||
mtype == MMS_MSGTYPE_RETRIEVE_CONF) {
msgtype = "MultiMediaMessage";
mms_make_sendreq(m); /* ensure it is a sendreq. */
} else if (mtype == MMS_MSGTYPE_DELIVERY_IND)
msgtype = "DeliveryReport";
else
msgtype = "ReadReply";
http_header_add(rh, "X-NOKIA-MMSC-Message-Type", msgtype);
if (hdrs)
http_header_combine(rh, hdrs); /* If specified, then update and pass on. */
http_header_add(rh, "Content-Type", "application/vnd.wap.mms-message");
/* Patch the message FROM and TO fields. */
mms_replace_header_value(m, "From", octstr_get_cstr(from));
mms_replace_header_value(m, "To", octstr_get_cstr(to));
mms_replace_header_value(m,"X-Mms-Transaction-ID",
transid ? octstr_get_cstr(transid) : "000");
body = mms_tobinary(m);
hstatus = mmsbox_url_fetch_content(HTTP_METHOD_POST, mmc->mmsc_url, rh, body, &ph, &rbody);
if (http_status_class(hstatus) != HTTP_STATUS_SUCCESSFUL) {
*error = octstr_format("Failed to contact MMC[url=%s] => HTTP returned status = %d !",
octstr_get_cstr(mmc->mmsc_url), hstatus);
} else {
MmsMsg *mresp = rbody ? mms_frombinary(rbody, octstr_imm("anon@anon")) : NULL;
resp = octstr_imm("Ok");
if (mresp && mms_messagetype(mresp) == MMS_MSGTYPE_SEND_CONF)
resp = mms_get_header_value(mresp, octstr_imm("X-Mms-Response-Status"));
if (octstr_case_compare(resp, octstr_imm("ok")) != 0)
hstatus = HTTP_STATUS_SERVER_ERROR; /* error. */
else if (mresp)
ret = mms_get_header_value(mresp, octstr_imm("Message-ID"));
if (mresp)
mms_destroy(mresp);
}
if (hstatus < 0)
ret = NULL;
else {
hstatus = http_status_class(hstatus);
if (hstatus == HTTP_STATUS_SERVER_ERROR)
ret = NULL;
else if (!ret)
ret = http_header_value(ph, octstr_imm("X-Nokia-MMSC-Message-Id"));
}
if (ret)
mms_log2("Sent", from, to, -1, ret, NULL, mmc->id, "MMSBox", NULL, NULL);
info(0, "Sent to MMC[%s], code=[%d], resp=%s msgid [%s]", octstr_get_cstr(mmc->id),
hstatus, resp ? octstr_get_cstr(resp) : "(none)", ret ? octstr_get_cstr(ret) : "(none)");
if (rh)
http_destroy_headers(rh);
if (body)
octstr_destroy(body);
if (ph)
http_destroy_headers(ph);
if (rbody)
octstr_destroy(rbody);
if (url)
octstr_destroy(url);
if (resp)
octstr_destroy(resp);
return ret;
}
static int mms_sendtommsc(MmscGrp *mmc, Octstr *from, Octstr *to, Octstr *transid,
Octstr *linkedid,
char *vasid,
Octstr *service_code,
MmsMsg *m,
Octstr *dlr_url,
Octstr *rr_url,
List *hdrs,
Octstr **err)
{
Octstr *id = NULL;
mutex_lock(mmc->mutex); { /* Grab a lock on it. */
if (mmc->type == SOAP_MMSC)
id = mm7soap_send(mmc, from, to, transid, linkedid, vasid, service_code, hdrs, m, err);
else if (mmc->type == EAIF_MMSC)
id = mm7eaif_send(mmc, from, to, transid, vasid, hdrs, m, err);
else
error(0, "MMC[%s] of unknown type, can't send!",
mmc->id ? octstr_get_cstr(mmc->id) : "");
if (id && mmc->throughput > 0)
gwthread_sleep(1.0/mmc->throughput);
} mutex_unlock(mmc->mutex); /* release lock */
if (id) {
if (dlr_url) /* remember the url's for reporting purposes. */
mms_dlr_url_put(id, "delivery-report", mmc->id, dlr_url);
if (rr_url)
mms_dlr_url_put(id, "read-report", mmc->id, rr_url);
octstr_destroy(id);
return MMS_SEND_OK;
} else
return MMS_SEND_ERROR_TRANSIENT; /* don't kill entry, wait a little. */
}
/* Get the MMC that should handler this recipient. */
static MmscGrp *get_handler_mmc(Octstr *id, Octstr *to)
{
MmscGrp *mmc = NULL;
int i, j, n;
Octstr *phonenum = NULL;
if (id)
for (i = 0, n = gwlist_len(mmscs); i < n; i++)
if ((mmc = gwlist_get(mmscs, i)) != NULL &&
mmc->id && octstr_compare(mmc->id, id) == 0)
return mmc;
if (octstr_search_char(to, '@', 0) > 0 ||
octstr_case_search(to, octstr_imm("/TYPE=IPv"), 0) > 0) /* For emails, or ip take first mmsc. */
return gwlist_get(mmscs, 0);
j = octstr_case_search(to, octstr_imm("/TYPE=PLMN"), 0);
if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == octstr_len(to))
phonenum = octstr_copy(to, 0, j);
else
phonenum = octstr_duplicate(to);
normalize_number(octstr_get_cstr(unified_prefix), &phonenum);
for (i = 0, n = gwlist_len(mmscs); i < n; i++)
if ((mmc = gwlist_get(mmscs, i)) != NULL &&
(mmc->allowed_prefix == NULL ||
does_prefix_match(mmc->allowed_prefix, phonenum)) &&
(mmc->denied_prefix == NULL ||
!does_prefix_match(mmc->denied_prefix, phonenum)))
return mmc;
if (phonenum)
octstr_destroy(phonenum);
return NULL;
}
static int sendMsg(MmsEnvelope *e)
{
MmsMsg *msg = NULL;
int i, n;
msg = mms_queue_getdata(e);
for (i = 0, n = gwlist_len(e->to); i<n; i++) {
int res = MMS_SEND_OK;
MmsEnvelopeTo *to = gwlist_get(e->to, i);
Octstr *err = NULL;
time_t tnow = time(NULL);
MmscGrp *mmc = NULL;
if (!to || !to->process)
continue;
if (e->expiryt != 0 && /* Handle message expiry. */
e->expiryt < tnow) {
err = octstr_format("MMSC error: Message expired while sending to %S!", to->rcpt);
res = MMS_SEND_ERROR_FATAL;
goto done;
} else if (e->attempts >= mmsbox_maxsendattempts) {
err = octstr_format("MMSBox error: Failed to deliver to "
"%S after %ld attempts. (max attempts allowed is %ld)!",
to->rcpt, e->attempts,
mmsbox_maxsendattempts);
res = MMS_SEND_ERROR_FATAL;
goto done;
}
if ((mmc = get_handler_mmc(e->viaproxy, to->rcpt)) == NULL) {
err = octstr_format("MMSBox error: Failed to deliver to "
"%S. Don't know how to route!",
to->rcpt);
res = MMS_SEND_ERROR_TRANSIENT;
goto done;
}
res = mms_sendtommsc(mmc, e->from, to->rcpt,
e->msgId,
e->token, /* token = linkedid */
e->vasid ? octstr_get_cstr(e->vasid) : NULL,
e->vaspid,
msg,
e->url1, e->url2,
e->hdrs,
&err);
done:
if (res == MMS_SEND_OK)
to->process = 0;
else if (res == MMS_SEND_ERROR_FATAL && mmc)
send_report(to->rcpt, "delivery-report",
(e->expiryt != 0 && e->expiryt < tnow) ?
octstr_imm("Expired") : octstr_imm("Rejected"),
e->msgId, mmc->id);
if (res == MMS_SEND_ERROR_FATAL)
to->process = 0; /* No more attempts. */
info(0, "%s MMSBox Outgoing Queue MMS Send: From %s, to %s, msgsize=%ld: err=%s",
SEND_ERROR_STR(res),
octstr_get_cstr(e->from), octstr_get_cstr(to->rcpt), e->msize,
err ? octstr_get_cstr(err) : "(null)");
e->lasttry = tnow;
if (mms_queue_update(e) == 1) {
e = NULL;
break; /* Queue entry gone. */
}
}
if (msg)
mms_destroy(msg);
if (e) { /* Update the queue if it is still valid (e.g. recipients not handled)
* XXX can this happen here??...
*/
e->lasttry = time(NULL);
e->attempts++; /* Update count of number of delivery attempts. */
e->sendt = e->lasttry + mmsbox_send_back_off * e->attempts;
if (mms_queue_update(e) != 1)
mms_queue_free_env(e);
}
return 1; /* always delete queue entry. */
}
void mmsbox_outgoing_queue_runner(int *rstop)
{
mms_queue_run(octstr_get_cstr(outgoing_qdir),
sendMsg, queue_interval, maxthreads, rstop);
}