1
0
Fork 0
mbuni/mbuni/mmsc/mmsproxy.c

1480 lines
45 KiB
C

/*
* Mbuni - Open Source MMS Gateway
*
* MMS Proxy interface, implements HTTP interface for client transactions
*
* 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 <signal.h>
#include <errno.h>
#include <unistd.h>
#include "mms_msg.h"
#include "mms_queue.h"
#include "mms_uaprof.h"
#include "mms_util.h"
static Cfg *cfg;
static List *proxyrelays;
static MmsBoxSettings *settings;
static int rstop = 0;
static void quit_now(int notused)
{
rstop = 1;
if (settings)
http_close_port(settings->port);
}
typedef struct MmsHTTPClientInfo {
HTTPClient *client;
Octstr *ua;
Octstr *ip;
List *headers;
Octstr *url;
Octstr *body;
List *cgivars;
MmsUaProfile *prof;
Octstr *base_client_addr;
Octstr *client_addr;
} MmsHTTPClientInfo;
static void fetchmms_proxy(MmsHTTPClientInfo *h);
static void sendmms_proxy(MmsHTTPClientInfo *h);
int main(int argc, char *argv[])
{
int cfidx;
Octstr *fname;
CfgGroup *grp;
Octstr *log, *alog;
long loglevel;
MmsHTTPClientInfo h;
mms_lib_init();
srandom(time(NULL));
cfidx = get_and_set_debugs(argc, argv, NULL);
if (argv[cfidx] == NULL)
fname = octstr_imm("mmsc.conf");
else
fname = octstr_create(argv[cfidx]);
cfg = cfg_create(fname);
if (cfg_read(cfg) == -1)
panic(0, "Couldn't read configuration from '%s'.", octstr_get_cstr(fname));
octstr_destroy(fname);
info(0, "----------------------------------------");
info(0, " MMSC Proxy Relay server version %s starting", MMSC_VERSION);
grp = cfg_get_single_group(cfg, octstr_imm("core"));
log = cfg_get(grp, octstr_imm("log-file"));
if (log != NULL) {
if (cfg_get_integer(&loglevel, grp, octstr_imm("log-level")) == -1)
loglevel = 0;
log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL);
octstr_destroy(log);
}
/* Get access log and open it. */
alog = cfg_get(grp, octstr_imm("access-log"));
if (alog) {
alog_open(octstr_get_cstr(alog), 1, 1);
octstr_destroy(alog);
}
/* Load proxy relays. */
proxyrelays = mms_proxy_relays(cfg);
/* Load settings. */
settings = mms_load_mmsbox_settings(cfg);
if (!settings)
panic(0, "No global MMSC configuration!");
signal(SIGHUP, quit_now);
signal(SIGTERM, quit_now);
/* Start cache engine. */
mms_start_profile_engine(octstr_get_cstr(settings->ua_profile_cache_dir));
/* Now open port and start dispatching requests. */
if (http_open_port(settings->port, 0) < 0) {
error(0, "MMS Proxy: Failed to start http server: %d => %s!",
errno, strerror(errno));
return -1;
}
while(rstop == 0 && (h.client = http_accept_request(settings->port,
&h.ip, &h.url, &h.headers,
&h.body, &h.cgivars)) != NULL)
if (is_allowed_ip(settings->deny_ip, settings->allow_ip, h.ip)) {
MmsHTTPClientInfo *hx = gw_malloc(sizeof *hx);
Octstr *profile_url;
h.ua = http_header_value(h.headers, octstr_imm("User-Agent"));
/* Get the profile URL and store it. Has effect of fetching if missing. */
if ((profile_url = http_header_value(h.headers,
octstr_imm("X-Wap-Profile"))) == NULL)
profile_url = http_header_value(h.headers, octstr_imm("Profile"));
if (profile_url) {
octstr_strip_nonalphanums(profile_url);
h.prof = mms_get_ua_profile(octstr_get_cstr(profile_url));
octstr_destroy(profile_url);
} else
h.prof = mms_make_ua_profile(h.headers);
/* Get the sender address. */
h.base_client_addr = mms_find_sender_msisdn(&h.url, h.headers, settings->wap_gw_msisdn_header, settings->mms_detokenizefuncs);
if (!h.base_client_addr) { /* Set to IP sender... XXXX assumes ipv4 only for now*/
if (settings->allow_ip_type) {
int ipv6 = 0;
h.base_client_addr = mms_find_sender_ip(h.headers,
settings->wap_gw_ip_header,
h.ip, &ipv6);
h.client_addr = octstr_format("%S/TYPE=IPv%s",
h.ip, ipv6 ? "6" : "4");
} else {
h.client_addr = NULL;
}
} else {
normalize_number(octstr_get_cstr(settings->unified_prefix), &h.base_client_addr);
h.client_addr = octstr_format("%S/TYPE=PLMN", h.base_client_addr);
}
/* Dump headers, url etc. */
#if 0
http_header_dump(h.headers);
if (h.body) octstr_dump(h.body, 0);
if (h.ip) octstr_dump(h.ip, 0);
#endif
/* Determine if this is the fetch interface or the send interface being used,
* by checking if http request has a body.
* then call relevant function in a thread (use threads because these functions
* can block)
*/
*hx = h; /* Copy it all over. */
if (hx->body == NULL || octstr_len(hx->body) == 0)
gwthread_create((gwthread_func_t *)fetchmms_proxy, hx);
else
gwthread_create((gwthread_func_t *)sendmms_proxy, hx);
} else {
octstr_destroy(h.ip);
octstr_destroy(h.url);
if (h.ua) octstr_destroy(h.ua);
if (h.base_client_addr)
octstr_destroy(h.base_client_addr);
octstr_destroy(h.client_addr);
octstr_destroy(h.body);
http_destroy_headers(h.headers);
http_destroy_headers(h.cgivars);
http_close_client(h.client);
}
debug("proxy", 0, "Shutdown requested");
http_close_all_ports();
debug("proxy", 0, "Port closed");
sleep(2); /* Give them time to shut down. */
mms_stop_profile_engine();
sleep(2); /* Give them time to shut down. */
return 0;
}
void fetchmms_proxy(MmsHTTPClientInfo *h)
{
Octstr *qf = NULL, *token = NULL, *s = NULL, *transid = NULL;
MmsEnvelope *e = NULL;
MmsMsg *m = NULL, *mr = NULL;
List *rh;
int loc, menc = MS_1_1;
debug("proxy.fetchinterface", 0, " ---> Entered fetch interface <---");
rh = http_create_empty_headers();
http_header_add(rh, "Pragma", "no-cache");
http_header_add(rh, "Cache-Control", "no-cache");
if (mms_decodefetchurl(h->url, &qf, &token,&loc) != 0) {
error(0, "MMS Fetch interface: failed to decode request url (%s) from %s!",
octstr_get_cstr(h->url),
octstr_get_cstr(h->ip));
goto failed;
}
if (loc == MMS_LOC_MQUEUE) { /* where is the message? */
e = mms_queue_readenvelope(octstr_get_cstr(qf),
octstr_get_cstr(settings->mm1_queuedir), 1);
if (!e ||
(m = mms_queue_getdata(e)) == NULL) {
error(0, "MMS Fetch interface: failed to find envelope/data %s for request url (%s) from %s (e=%s)!",
octstr_get_cstr(qf), octstr_get_cstr(h->url), octstr_get_cstr(h->ip),
(e)? "found" : "not found");
mr = mms_retrieveconf(NULL, NULL, "Error-permanent-message-not-found", "Message not found",
settings->system_user, MS_1_1);
s = mms_tobinary(mr);
goto failed;
}
} else { /* it is in mmbox, so get it from there. */
unsigned long msize;
if ((m = mms_mmbox_get(octstr_get_cstr(settings->mmbox_rootdir),
octstr_get_cstr(h->client_addr), qf, &msize)) == NULL) {
error(0, "MMS Fetch interface: failed to find data in MMBOX %s, url=%s, from=%s (e=%s)!",
octstr_get_cstr(qf), octstr_get_cstr(h->url), octstr_get_cstr(h->ip),
(e)? "found" : "not found");
mr = mms_retrieveconf(NULL, NULL, "Error-permanent-message-not-found", "Message not found",
settings->system_user, MS_1_1);
s = mms_tobinary(mr);
goto failed;
}
menc = MS_1_2;
}
/* Adapt content. */
transid = mms_maketransid(octstr_get_cstr(qf), settings->host_alias);
if (h->prof) {
MmsMsg *outmsg = NULL;
int x = mms_transform_msg(m, h->prof, &outmsg);
if (x == -1) { /* Temporary failure, we need to fetch profile. */
mr = mms_retrieveconf(NULL, transid, "Error-transient-failure", "Mobile MMS Settings not found",
settings->system_user,MS_1_1);
s = mms_tobinary(mr);
goto failed;
} else if (x < 0) { /* Doesn't support MMS */
mr = mms_retrieveconf(NULL, transid,
"Error-permanent-content-unsupported", "No MMS Support",
settings->system_user,MS_1_1);
s = mms_tobinary(mr);
goto failed;
} else if (x == 0) {
if (outmsg == NULL) { /* Too large so truncated. */
Octstr *xx = octstr_format(octstr_get_cstr(settings->mms_toolarge), (e) ? e->from : h->client_addr);
mr = mms_retrieveconf(NULL, transid,
#if 0
"Error-permanent-content-unsupported",
#else
"Ok",
#endif
octstr_get_cstr(xx),
settings->system_user,MS_1_1);
octstr_destroy(xx);
s = mms_tobinary(mr);
goto failed;
} else {
mms_destroy(m);
m = outmsg;
}
}
}
mr = mms_retrieveconf(m, transid, "Error-permanent-message-not-found", NULL,
(e) ? e->from : h->client_addr, menc);
s = mms_tobinary(mr);
if (loc == MMS_LOC_MQUEUE)
if ((token == NULL && e->token != NULL) ||
(e->token == NULL && token != NULL) ||
(octstr_compare(e->token, token) != 0)) {
error(0, "MMS Fetch interface: token mismatch, did client mod the fetch url?? "
" env=%s for request url (%s) from %s!",
octstr_get_cstr(qf), octstr_get_cstr(h->url), octstr_get_cstr(h->ip));
goto failed;
}
if (!m) {
error(0, "MMS Fetch interface: Failed to get message, url=%s, loc=%d from %s!",
octstr_get_cstr(h->url), loc, octstr_get_cstr(h->ip));
goto failed;
}
if (!s) {
error(0, "MMS Fetch interface: Failed to convert message to binary for "
"request url (%s) from %s!",
octstr_get_cstr(h->url), octstr_get_cstr(h->ip));
goto failed;
}
if (e) {
e->lastaccess = time(NULL); /* No more notifications requests. */
e->sendt = e->expiryt + 3600*24*30*12;
mms_queue_update(e);
}
http_header_add(rh, "Content-Type", "application/vnd.wap.mms-message");
http_send_reply(h->client, HTTP_OK, rh, s);
#if 1
debug("proxy.fetchinterface", 0,
" $$$$$$ fetch message replying with [type=%s,content_len=%ld]: ",
mr ? mms_message_type_to_cstr(mms_messagetype(mr)) : (unsigned char *)"none",
s ? octstr_len(s) : 0);
if (mr)
mms_msgdump(mr,1);
#endif
/* Send to access log with success. */
mms_log2("Fetched", e ? e->from : NULL, h->client_addr,
e ? e->msize : 0, e ? e->msgId : NULL, NULL, NULL, "MM1",
h->ua, (loc == MMS_LOC_MMBOX) ? qf : NULL);
goto free_stuff; /* Skip to end. */
failed:
#if 1
debug("proxy.fetchinterface", 0,
" $$$$$$ fetch message [fail] replying with [type=%s,content_len=%ld]: ",
mr ? mms_message_type_to_cstr(mms_messagetype(mr)) : (unsigned char *)"none",
s ? octstr_len(s) : 0);
if (mr)
mms_msgdump(mr,1);
#endif
/* Send to access log on failure?? */
mms_log2("Failed Fetch", e ? e->from : NULL, h->client_addr,
e ? e->msize : 0, e ? e->msgId : NULL, NULL, NULL, "MM1", h->ua,
(loc == MMS_LOC_MMBOX) ? qf : NULL);
if (!s) {
http_header_add(rh, "Content-Type", "text/plain");
http_send_reply(h->client, HTTP_NOT_FOUND, rh, octstr_imm("Not found"));
} else {
http_header_add(rh, "Content-Type", "application/vnd.wap.mms-message");
http_send_reply(h->client, HTTP_OK, rh, s);
}
free_stuff:
http_destroy_headers(rh);
if (e) mms_queue_free_env(e);
if (s) octstr_destroy(s);
if (m) mms_destroy(m);
if (mr) mms_destroy(mr);
if (qf) octstr_destroy(qf);
if (token) octstr_destroy(token);
if (transid) octstr_destroy(transid);
octstr_destroy(h->ip);
octstr_destroy(h->url);
if (h->ua) octstr_destroy(h->ua);
if (h->body) octstr_destroy(h->body);
if (h->base_client_addr)
octstr_destroy(h->base_client_addr);
octstr_destroy(h->client_addr);
http_destroy_cgiargs(h->cgivars);
http_destroy_headers(h->headers);
gw_free(h);
}
/* Make list of recipients and also sender. */
static void collect_senddata(List *mh, List **xto,
Octstr **subject,
Octstr **otransid, time_t *expiryt, time_t *deliveryt)
{
Octstr *s;
List *l = http_header_find_all(mh, "To");
if (l) {
int i, n;
for (i = 0, n = list_len(l); i<n; i++) {
Octstr *name, *value;
http_header_get(l, i, &name, &value);
list_append(*xto, value);
octstr_destroy(name);
}
http_destroy_headers(l);
}
l = http_header_find_all(mh, "Cc");
if (l) {
int i, n;
for (i = 0, n = list_len(l); i<n; i++) {
Octstr *name, *value;
http_header_get(l, i, &name, &value);
list_append(*xto, value);
octstr_destroy(name);
}
http_destroy_headers(l);
}
l = http_header_find_all(mh, "Bcc");
if (l) {
int i, n;
for (i = 0, n = list_len(l); i<n; i++) {
Octstr *name, *value;
http_header_get(l, i, &name, &value);
list_append(*xto, value);
octstr_destroy(name);
}
http_destroy_headers(l);
}
/* Find expiry and delivery times */
if (expiryt) {
s = http_header_value(mh, octstr_imm("X-Mms-Expiry"));
if (s) {
*expiryt = date_parse_http(s);
octstr_destroy(s);
} else
*expiryt = time(NULL) + settings->default_msgexpiry;
}
if (deliveryt) {
s = http_header_value(mh, octstr_imm("X-Mms-Delivery-Time"));
if (s) {
*deliveryt = date_parse_http(s);
octstr_destroy(s);
} else
*deliveryt = 0;
}
if (subject)
*subject = http_header_value(mh, octstr_imm("Subject"));
if (otransid)
*otransid = http_header_value(mh, octstr_imm("X-Mms-Transaction-ID"));
}
static void sendmms_proxy(MmsHTTPClientInfo *h)
{
List *rh = http_create_empty_headers();
MmsMsg *m, *mresp = NULL;
Octstr *reply_body = NULL;
int ctype_set = 0;
int mtype = 0, menc;
int hstatus = HTTP_OK;
char *notify_cmd = NULL;
int msize = h->body ? octstr_len(h->body) : 0;
debug("proxy.sendinterface", 0,
" --> Enterred sendmms interface, blen=%d <--- ",
msize);
http_header_add(rh, "Pragma", "no-cache");
http_header_add(rh, "Cache-Control", "no-cache");
if (!h->body) { /* A body is required. */
http_header_add(rh, "Content-Type", "text/plain");
hstatus = HTTP_FORBIDDEN;
reply_body = octstr_format("Unexpected MMS message[%s], no body?",
mms_message_type_to_cstr(mtype));
goto done;
}
m = mms_frombinary(h->body, h->client_addr ? h->client_addr : octstr_imm("") );
if (!m) {
http_header_add(rh, "Content-Type", "text/plain");
ctype_set = 1;
hstatus = HTTP_BAD_REQUEST;
reply_body = octstr_format("Malformed MMS message");
debug("proxy.sendinterface", 0, " Parse error on incoming message.");
goto done;
}
debug("proxy.sendinterface", 0, " Client sent us: ");
#if 0
mms_msgdump(m,1);
/* octstr_dump(h->body, 0); */
#endif
mtype = mms_messagetype(m);
menc = mms_message_enc(m);
switch(mtype) {
case MMS_MSGTYPE_SEND_REQ:
{
Octstr *qf;
List *mh = mms_message_headers(m);
Octstr *from = octstr_duplicate(h->client_addr);
List *to = list_create();
Octstr *subject;
time_t expiryt, deliveryt;
Octstr *otransid = NULL, *value = NULL, *msgid = NULL;
int dlr;
char *mmbox_store_status = NULL;
Octstr *mmbox_loc = NULL;
Octstr *sdf = NULL;
collect_senddata(mh, &to, &subject, &otransid, &expiryt, &deliveryt);
if (!h->client_addr) {
mresp = mms_sendconf("Error-sending-address-unresolved", "None", octstr_get_cstr(otransid),0,
menc);
} else {
Octstr *x = mms_get_header_value(m, octstr_imm("X-Mms-Store"));
mms_remove_headers(m, "X-Mms-Store");
msgid = mms_maketransid(NULL, settings->host_alias);
mms_replace_header_value(m, "Message-ID", octstr_get_cstr(msgid)); /* Put in message id -- for later. */
if (menc >= MS_1_2 &&
x != NULL &&
octstr_case_compare(x, octstr_imm("Yes")) == 0) {
sdf = mms_mmbox_addmsg(octstr_get_cstr(settings->mmbox_rootdir),
octstr_get_cstr(h->client_addr), m,
NULL,
octstr_imm("Sent"));
/* XXX perhaps qualify errors better? */
mmbox_store_status = sdf ? "Success" : "Error-permanent-failure";
if (sdf)
mmbox_loc = mms_makefetchurl(octstr_get_cstr(sdf), NULL, MMS_LOC_MMBOX, settings);
}
if (x)
octstr_destroy(x);
/*Delete some headers that must be sent on. */
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");
mms_remove_headers(m, "X-Mms-MM-Flags");
mms_remove_headers(m, "X-Mms-MM-State");
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;
qf = mms_queue_add(from, to, msgid, subject,
NULL, NULL, deliveryt, expiryt, m, NULL, dlr,
octstr_get_cstr(settings->global_queuedir));
if (!qf)
mresp = mms_sendconf("Error-transient-failure", "None", octstr_get_cstr(otransid),0,
menc);
else {
mresp = mms_sendconf("Ok", octstr_get_cstr(msgid), octstr_get_cstr(otransid),0,
menc);
/* Log to access log */
mms_log("Received", from, to, msize, msgid, NULL, NULL, "MM1", h->ua, sdf);
octstr_destroy(qf);
}
if (mmbox_store_status) /* If saved to mmbox, ... */
mms_replace_header_value(mresp,
"X-Mms-Store-Status", mmbox_store_status);
if (mmbox_loc)
mms_replace_header_value(mresp,
"X-Mms-Content-Location",
octstr_get_cstr(mmbox_loc));
}
if (otransid)
octstr_destroy(otransid);
if (value)
octstr_destroy(value);
if (msgid)
octstr_destroy(msgid);
if (mmbox_loc)
octstr_destroy(mmbox_loc);
if (sdf)
octstr_destroy(sdf);
octstr_destroy(from);
octstr_destroy(subject);
http_destroy_headers(mh);
list_destroy(to, (list_item_destructor_t *)octstr_destroy);
notify_cmd = "sent";
reply_body = mms_tobinary(mresp);
}
break;
case MMS_MSGTYPE_FORWARD_REQ:
{
Octstr *qf = NULL, *token = NULL;
List *mh = mms_message_headers(m);
Octstr *from = octstr_duplicate(h->client_addr);
List *to = list_create();
Octstr *subject;
time_t expiryt, deliveryt;
MmsMsg *mfwd = NULL;
MmsEnvelope *e = NULL;
int mloc;
Octstr *otransid;
Octstr *url = http_header_value(mh, octstr_imm("X-Mms-Content-Location"));
Octstr *read_report = http_header_value(mh, octstr_imm("X-Mms-Read-Report"));
Octstr *delivery_report = http_header_value(mh,
octstr_imm("X-Mms-Delivery-Report"));
Octstr *allow_report = http_header_value(mh,
octstr_imm("X-Mms-Report-Allowed"));
int dlr;
unsigned long msize;
char *mmbox_store_status = NULL;
Octstr *mmbox_loc = NULL;
Octstr *sdf = NULL;
collect_senddata(mh, &to, &subject, &otransid, &expiryt, &deliveryt);
if (mms_decodefetchurl(url, &qf, &token,&mloc) != 0) {
error(0, "MMS Send interface: failed to decode forward url (%s) from %s!",
octstr_get_cstr(url),
octstr_get_cstr(h->ip));
mresp = mms_sendconf("Error-permanent-message-not-found", "None",
octstr_get_cstr(otransid),1,menc);
goto forward_done;
}
if (mloc == MMS_LOC_MQUEUE) { /* where is the message? */
e = mms_queue_readenvelope(octstr_get_cstr(qf),
octstr_get_cstr(settings->mm1_queuedir), 1);
if (!e ||
(mfwd = mms_queue_getdata(e)) == NULL) {
error(0,
"MMS Send interface: failed to find envelope/data %s for forward url "
"(%s) from %s (e=%s)!",
octstr_get_cstr(qf), octstr_get_cstr(url), octstr_get_cstr(h->ip),
(e) ? "found" : "not found");
mresp = mms_sendconf("Error-permanent-message-not-found", "None",
octstr_get_cstr(otransid),1,menc);
goto forward_done;
}
} else /* it is in mmbox, so get it from there. */
if ((mfwd = mms_mmbox_get(octstr_get_cstr(settings->mmbox_rootdir),
octstr_get_cstr(h->client_addr), qf, &msize)) == NULL) {
error(0, "MMS Send interface: failed to find data in MMBOX %s, "
"forward_url=%s, from=%s (e=%s)!",
octstr_get_cstr(qf), octstr_get_cstr(h->url), octstr_get_cstr(h->ip),
(e)? "found" : "not found");
mresp = mms_sendconf("Error-permanent-message-not-found", "None",
octstr_get_cstr(otransid),1,menc);
goto forward_done;
}
{ /* Found it, etc. */
Octstr *pfrom = mms_get_header_value(mfwd, octstr_imm("From"));
Octstr *pdate = mms_get_header_value(mfwd, octstr_imm("Date"));
Octstr *pmsgid = mms_get_header_value(mfwd, octstr_imm("Message-ID"));
Octstr *pdelivery_report = mms_get_header_value(mfwd,
octstr_imm("X-Mms-Delivery-Report"));
Octstr *msgid = mms_maketransid(NULL, settings->host_alias);
Octstr *s;
Octstr *qf2;
int n = 0;
Octstr *xstate = mms_get_header_value(m, octstr_imm("X-Mms-MM-State"));
List *xflags = mms_get_header_values(m, octstr_imm("X-Mms-MM-Flags"));
Octstr *x = NULL;
/* Modify the message before sending on as per spec. */
mms_replace_header_value(mfwd, "From", octstr_get_cstr(from));
mms_replace_header_value(mfwd, "Message-ID", octstr_get_cstr(msgid)); /* Put in message id -- for later. */
mms_remove_headers(mfwd, "X-Mms-Read-Report");
if (read_report)
mms_replace_header_value(mfwd, "X-Mms-Read-Report",
octstr_get_cstr(read_report));
mms_remove_headers(mfwd, "X-Mms-Delivery-Report");
if (delivery_report)
mms_replace_header_value(mfwd, "X-Mms-Delivery-Report",
octstr_get_cstr(delivery_report));
if ((s = mms_get_header_value(mfwd, octstr_imm("X-Mms-Previously-Sent-By"))) != NULL) {
sscanf(octstr_get_cstr(s), "%d", &n);
octstr_destroy(s);
}
s = octstr_format("%d%S", n+1, pfrom);
mms_replace_header_value(mfwd, "X-Mms-Previously-Sent-By", octstr_get_cstr(s));
if ((s = mms_get_header_value(mfwd,
octstr_imm("X-Mms-Previously-Sent-Date")))
!= NULL) {
sscanf(octstr_get_cstr(s), "%d", &n);
octstr_destroy(s);
}
s = octstr_format("%d%S", n+1, pdate);
mms_replace_header_value(mfwd,
"X-Mms-Previously-Sent-Date",
octstr_get_cstr(s));
octstr_destroy(pdate);
if (delivery_report &&
octstr_case_compare(delivery_report, octstr_imm("Yes")) == 0)
dlr = 1;
else
dlr = 0;
/* Message to forward is now ready, write it to queue. */
qf2 = mms_queue_add(from, to, msgid, subject,
NULL, NULL, deliveryt, expiryt, mfwd, NULL,
dlr,
octstr_get_cstr(settings->global_queuedir));
/* Process any requests for writing to mmbox. */
x = mms_get_header_value(m, octstr_imm("X-Mms-Store"));
mms_remove_headers(m, "X-Mms-Store");
if (menc >= MS_1_2 &&
x != NULL &&
octstr_case_compare(x, octstr_imm("Yes")) == 0) {
if (mloc != MMS_LOC_MMBOX) { /* not in mmbox, add it. */
sdf = mms_mmbox_addmsg(octstr_get_cstr(settings->mmbox_rootdir),
octstr_get_cstr(h->client_addr), mfwd,
xflags,
xstate ? xstate : octstr_imm("Forwarded"));
/* XXX perhaps qualify errors better? */
mmbox_store_status = sdf ? "Success" : "Error-permanent-failure";
if (sdf)
mmbox_loc = mms_makefetchurl(octstr_get_cstr(sdf), NULL,
MMS_LOC_MMBOX, settings);
} else { /* otherwise simply mod it. */
int xret;
xret = mms_mmbox_modmsg(octstr_get_cstr(settings->mmbox_rootdir),
octstr_get_cstr(h->client_addr), qf,
xstate ? xstate : octstr_imm("Forwarded"),
xflags);
/* XXX perhaps qualify errors better? */
mmbox_store_status = (xret == 0) ? "Success" : "Error-permanent-failure";
if (xret == 0)
mmbox_loc = mms_makefetchurl(octstr_get_cstr(qf), NULL,
MMS_LOC_MMBOX, settings);
}
}
if (x)
octstr_destroy(x);
if (!qf2)
mresp = mms_sendconf("Error-transient-failure",
"None", octstr_get_cstr(otransid),1,menc);
else {
mresp = mms_sendconf("Ok",
octstr_get_cstr(msgid),
octstr_get_cstr(otransid),1,menc);
/* Log to access log */
mms_log("Forwarded", h->client_addr, to, msize, msgid, NULL, NULL, "MM1",
h->ua, sdf);
octstr_destroy(qf2);
}
if (mmbox_store_status) /* If saved to mmbox, ... */
mms_replace_header_value(mresp,
"X-Mms-Store-Status", mmbox_store_status);
if (mmbox_loc)
mms_replace_header_value(mresp,
"X-Mms-Content-Location",
octstr_get_cstr(mmbox_loc));
/* You have queued it, now check if the original sender asked for a delivery notify.
* if so and this forward has not refused it, then send a notify and we are done for now.
*/
if ((!allow_report ||
octstr_case_compare(allow_report, octstr_imm("Yes")) == 0) &&
(pdelivery_report && octstr_case_compare(pdelivery_report,
octstr_imm("Yes")))) {
MmsMsg *mrep = mms_deliveryreport(pmsgid, h->client_addr, time(NULL), octstr_imm("Forwarded"));
Octstr *x;
List *l = list_create();
list_append(l, pfrom);
x = mms_queue_add(settings->system_user, l, NULL, NULL, NULL, NULL, 0,
time(NULL) + settings->default_msgexpiry,
mrep, NULL,0,
octstr_get_cstr(settings->global_queuedir));
octstr_destroy(x);
list_destroy(l, NULL);
mms_destroy(mrep);
}
octstr_destroy(pfrom);
octstr_destroy(pdelivery_report);
if (pmsgid)
octstr_destroy(pmsgid);
if (msgid)
octstr_destroy(msgid);
if (xstate)
octstr_destroy(xstate);
if (xflags)
list_destroy(xflags, (list_item_destructor_t *)octstr_destroy);
}
forward_done:
if (mfwd)
mms_destroy(mfwd);
if (e) { /* Update the message queue and go. */
e->lastaccess = time(NULL);
if (mms_queue_update(e) != 1) /* Should be freed. */
mms_queue_free_env(e);
e = NULL;
}
if (qf)
octstr_destroy(qf);
if (token)
octstr_destroy(token);
if (from)
octstr_destroy(from);
if (subject)
octstr_destroy(subject);
if (mh)
http_destroy_headers(mh);
if (to)
list_destroy(to, (list_item_destructor_t *)octstr_destroy);
if (otransid)
octstr_destroy(otransid);
if (url)
octstr_destroy(url);
if (read_report)
octstr_destroy(read_report);
if (allow_report)
octstr_destroy(allow_report);
if (delivery_report)
octstr_destroy(delivery_report);
if (mmbox_loc)
octstr_destroy(mmbox_loc);
if (sdf)
octstr_destroy(sdf);
reply_body = mms_tobinary(mresp);
notify_cmd = "fetched";
}
break;
case MMS_MSGTYPE_NOTIFYRESP:
case MMS_MSGTYPE_ACKNOWLEDGE_IND:
{
Octstr *transid = mms_get_header_value(m, octstr_imm("X-Mms-Transaction-ID"));
Octstr *allow_report = mms_get_header_value(m, octstr_imm("X-Mms-Report-Allowed"));
Octstr *qf = mms_getqf_fromtransid(transid);
MmsEnvelope *e = mms_queue_readenvelope(octstr_get_cstr(qf),
octstr_get_cstr(settings->mm1_queuedir), 1);
Octstr *status;
MmsMsg *mrpt;
if (mtype == MMS_MSGTYPE_NOTIFYRESP)
status = mms_get_header_value(m, octstr_imm("X-Mms-Status"));
else /* This (acknowledge-ind) is the same as notify_resp with status=retrieved. */
status = octstr_imm("Retrieved");
if (!e) {
error(0, "MMS Send interface: Received notification type=%s "
"[url=%s, transid=%s, qf=%s] but could not find queue entry!\n",
mms_message_type_to_cstr(mtype), octstr_get_cstr(h->url),
octstr_get_cstr(transid), octstr_get_cstr(qf));
goto mdone;
}
if (octstr_str_compare(status, "Retrieved") == 0) {
MmsEnvelopeTo *t = list_get(e->to, 0);
if (t)
t->process = 0;
} else
e->lastaccess = time(NULL); /* Note now that it has been touched. */
/* If the allow report header is missing (default is Yes)
* or it is there and has said we must send report,
* and sender requested a report, then queue a report.
*/
if ((allow_report == NULL
|| octstr_case_compare(allow_report, octstr_imm("Yes")) == 0) &&
e->dlr) {
Octstr *x;
List *l = list_create();
mrpt = mms_deliveryreport(e->msgId, h->client_addr, time(NULL), status);
list_append(l, octstr_duplicate(e->from));
x = mms_queue_add(settings->system_user, l, NULL, NULL, NULL, NULL, 0,
time(NULL) + settings->default_msgexpiry, mrpt, NULL, 0,
octstr_get_cstr(settings->global_queuedir));
octstr_destroy(x);
list_destroy(l, (list_item_destructor_t *)octstr_destroy);
mms_destroy(mrpt);
}
mdone:
/* Log to access log */
mms_log2("NotifyResp", h->client_addr, NULL, msize, transid, NULL, NULL, "MM1", h->ua, NULL);
if (e &&
mms_queue_update(e) != 1) /* Should be freed. */
mms_queue_free_env(e);
octstr_destroy(qf);
octstr_destroy(transid);
octstr_destroy(allow_report);
octstr_destroy(status);
http_header_add(rh, "Content-Type", "text/plain");
ctype_set = 1;
reply_body = octstr_imm("Received");
notify_cmd = "fetched";
}
break;
case MMS_MSGTYPE_READ_REC_IND:
{
List *mh = mms_message_headers(m);
Octstr *from = octstr_duplicate(h->client_addr);
List *to = list_create();
Octstr *x;
if (mms_convert_readrec2readorig(m) < 0)
goto mdone2;
collect_senddata(mh, &to, NULL, NULL, NULL, NULL);
x = mms_queue_add(from, to, NULL, NULL, NULL,
NULL, time(NULL), time(NULL) + settings->default_msgexpiry,
m, NULL, 0, octstr_get_cstr(settings->global_queuedir));
/* Log to access log */
mms_log("ReadReport", h->client_addr, NULL, msize, NULL, NULL, NULL, "MM1", h->ua,NULL);
octstr_destroy(x);
octstr_destroy(from);
http_destroy_headers(mh);
mdone2:
list_destroy(to, (list_item_destructor_t *)octstr_destroy);
http_header_add(rh, "Content-Type", "text/plain");
ctype_set = 1;
reply_body = octstr_imm("Received");
notify_cmd = "fetched";
break;
}
break;
/* mmbox transactions. */
case MMS_MSGTYPE_MBOX_STORE_REQ:
{
Octstr *qf = NULL, *token = NULL;
List *mh = mms_message_headers(m);
MmsMsg *mstore = NULL;
MmsEnvelope *e = NULL;
int mloc;
Octstr *xstate = mms_get_header_value(m, octstr_imm("X-Mms-MM-State"));
List *xflags = mms_get_header_values(m, octstr_imm("X-Mms-MM-Flags"));
Octstr *otransid = http_header_value(mh, octstr_imm("X-Mms-Transaction-ID"));
Octstr *url = http_header_value(mh, octstr_imm("X-Mms-Content-Location"));
char *mmbox_store_status = NULL;
Octstr *mmbox_loc = NULL;
Octstr *sdf = NULL;
if (mms_decodefetchurl(url, &qf, &token,&mloc) != 0) {
error(0, "MMS Send interface: failed to decode store url (%s) from %s!",
octstr_get_cstr(url),
octstr_get_cstr(h->ip));
mresp = mms_storeconf("Error-permanent-message-not-found",
octstr_get_cstr(otransid), NULL, 0,menc);
goto store_done;
}
if (mloc == MMS_LOC_MQUEUE) { /* where is the message? */
e = mms_queue_readenvelope(octstr_get_cstr(qf),
octstr_get_cstr(settings->mm1_queuedir), 1);
if (!e ||
(mstore = mms_queue_getdata(e)) == NULL) {
error(0,
"MMS Send interface: failed to find envelope/data %s for store url "
"(%s) from %s (e=%s)!",
octstr_get_cstr(qf), octstr_get_cstr(url), octstr_get_cstr(h->ip),
(e) ? "found" : "not found");
mresp = mms_storeconf("Error-permanent-message-not-found",
octstr_get_cstr(otransid),NULL, 0,menc);
goto store_done;
}
sdf = mms_mmbox_addmsg(octstr_get_cstr(settings->mmbox_rootdir),
octstr_get_cstr(h->client_addr), mstore,
xflags,
xstate ? xstate : octstr_imm("New"));
/* XXX perhaps qualify errors better? */
mmbox_store_status = sdf ? "Success" : "Error-permanent-failure";
if (sdf)
mmbox_loc = mms_makefetchurl(octstr_get_cstr(sdf), NULL,
MMS_LOC_MMBOX, settings);
} else { /* it is in mmbox, just update. */
int xret;
xret = mms_mmbox_modmsg(octstr_get_cstr(settings->mmbox_rootdir),
octstr_get_cstr(h->client_addr), qf,
xstate,
xflags);
/* XXX perhaps qualify errors better? */
mmbox_store_status = (xret == 0) ? "Success" : "Error-permanent-failure";
if (xret == 0)
mmbox_loc = mms_makefetchurl(octstr_get_cstr(qf), NULL,
MMS_LOC_MMBOX, settings);
}
if (mmbox_loc) {
mresp = mms_storeconf("Success",
octstr_get_cstr(otransid),
mmbox_loc,0,menc);
mms_log("Stored", h->client_addr, NULL, msize, otransid, NULL, NULL, "MM1",
h->ua, sdf ? sdf : qf);
} else
mresp = mms_storeconf("Error-transient-failure",
octstr_get_cstr(otransid),NULL, 0,menc);
store_done:
if (xstate)
octstr_destroy(xstate);
if (xflags)
list_destroy(xflags, (list_item_destructor_t *)octstr_destroy);
if (mstore)
mms_destroy(mstore);
if (e) { /* Update the message queue and go. */
e->lastaccess = time(NULL);
if (mms_queue_update(e) != 1) /* Should be freed. */
mms_queue_free_env(e);
e = NULL;
}
if (qf)
octstr_destroy(qf);
if (token)
octstr_destroy(token);
if (mh)
http_destroy_headers(mh);
if (otransid)
octstr_destroy(otransid);
if (url)
octstr_destroy(url);
if (mmbox_loc)
octstr_destroy(mmbox_loc);
if (sdf)
octstr_destroy(sdf);
reply_body = mms_tobinary(mresp);
notify_cmd = "stored";
}
break;
case MMS_MSGTYPE_MBOX_UPLOAD_REQ:
{
List *mh = mms_message_headers(m);
MmsMsg *mstore = NULL;
Octstr *ctype = NULL, *charset = NULL;
Octstr *otransid = http_header_value(mh, octstr_imm("X-Mms-Transaction-ID"));
char *mmbox_store_status = NULL;
Octstr *mmbox_loc = NULL;
Octstr *sdf = NULL;
Octstr *s = NULL;
http_header_get_content_type(mh, &ctype, &charset);
if (charset)
octstr_destroy(charset);
/* If:
* - body type is not mms type, or
* - we are unable to parse it
* we fail.
*/
if (!ctype ||
octstr_case_compare(ctype, octstr_imm("application/vnd.wap.mms-message")) != 0 ||
(s = mms_msgbody(m)) == NULL ||
(mstore = mms_frombinary(s,octstr_imm("anon@anon"))) == NULL)
mresp = mms_storeconf("Error-permanent-message-format-corrupt",
octstr_get_cstr(otransid),
NULL,1,menc);
else {
sdf = mms_mmbox_addmsg(octstr_get_cstr(settings->mmbox_rootdir),
octstr_get_cstr(h->client_addr), mstore,
NULL,
octstr_imm("Draft"));
/* XXX perhaps qualify errors better? */
mmbox_store_status = sdf ? "Success" : "Error-permanent-failure";
if (sdf)
mmbox_loc = mms_makefetchurl(octstr_get_cstr(sdf), NULL,
MMS_LOC_MMBOX, settings);
if (mmbox_loc) {
mresp = mms_storeconf("Success",
octstr_get_cstr(otransid),
mmbox_loc,1,menc);
mms_log("Stored", h->client_addr, NULL, msize, otransid, NULL, NULL, "MM1",
h->ua, sdf);
} else
mresp = mms_storeconf("Error-transient-failure",
octstr_get_cstr(otransid),NULL, 1,menc);
}
if (mstore)
mms_destroy(mstore);
if (mh)
http_destroy_headers(mh);
if (otransid)
octstr_destroy(otransid);
if (s)
octstr_destroy(s);
if (ctype)
octstr_destroy(ctype);
if (mmbox_loc)
octstr_destroy(mmbox_loc);
if (sdf)
octstr_destroy(sdf);
reply_body = mms_tobinary(mresp);
notify_cmd = "uploaded";
}
break;
case MMS_MSGTYPE_MBOX_DELETE_REQ:
{
List *lh = mms_get_header_values(m, octstr_imm("X-Mms-Content-Location"));
Octstr *otransid = mms_get_header_value(m, octstr_imm("X-Mms-Transaction-ID"));
int i;
List *cls = list_create();
List *rss = list_create();
mresp = mms_deleteconf(menc, octstr_get_cstr(otransid));
for (i = 0; i < list_len(lh); i++) {
Octstr *url = list_get(lh,i);
int mloc;
Octstr *qf = NULL, *token = NULL;
Octstr *cl, *rs = NULL;
int j, m;
cl = octstr_format("%d%S", i, url);
if (mms_decodefetchurl(url, &qf, &token,&mloc) != 0) {
error(0, "MMS Send interface: failed to decode delete url (%s) from %s!",
octstr_get_cstr(url),
octstr_get_cstr(h->ip));
rs = octstr_format("%dError-permanent-message-not-found", i);
} else if (mloc == MMS_LOC_MQUEUE) {
MmsEnvelope *e = mms_queue_readenvelope(octstr_get_cstr(qf),
octstr_get_cstr(settings->mm1_queuedir), 1);
if (!e)
rs = octstr_format("%dError-permanent-message-not-found", i);
else {
for (j = 0, m = (e->to ? list_len(e->to) : 0); j < m; j++) {
MmsEnvelopeTo *x = list_get(e->to,j);
if (x) x->process = 0;
}
if (mms_queue_update(e) != 1) /* Should be freed. */
mms_queue_free_env(e);
rs = octstr_format("%dOk", i);
}
} else if (mloc == MMS_LOC_MMBOX) {
int ret2 = mms_mmbox_delmsg(octstr_get_cstr(settings->mmbox_rootdir),
octstr_get_cstr(h->client_addr),qf);
if (ret2 == 0)
rs = octstr_format("%dOk", i);
else /* XXX better error reporting... */
rs = octstr_format("%dError-permanent-message-not-found", i);
}
if (!rs)
rs = octstr_format("%dError-permanent-message-not-found", i);
list_append(rss, rs);
list_append(cls, cl);
if (qf)
octstr_destroy(qf);
if (token)
octstr_destroy(token);
}
/* put in response codes. */
mms_replace_header_values(mresp, "X-Mms-Content-Location", cls);
mms_replace_header_values(mresp, "X-Mms-Response-Status", rss);
list_destroy(cls, (list_item_destructor_t *)octstr_destroy);
list_destroy(rss, (list_item_destructor_t *)octstr_destroy);
list_destroy(lh, (list_item_destructor_t *)octstr_destroy);
if (otransid)
octstr_destroy(otransid);
reply_body = mms_tobinary(mresp);
notify_cmd = "deleted";
}
break;
case MMS_MSGTYPE_MBOX_VIEW_REQ:
{
/* Get the search params, search, build response, go. */
Octstr *otransid = mms_get_header_value(m, octstr_imm("X-Mms-Transaction-ID"));
List *xstates = mms_get_header_values(m, octstr_imm("X-Mms-MM-State"));
List *xflags = mms_get_header_values(m, octstr_imm("X-Mms-MM-Flags"));
List *msgs = mms_get_header_values(m, octstr_imm("X-Mms-Content-Location"));
List *required_headers = mms_get_header_values(m, octstr_imm("X-Mms-Attributes"));
List *otherhdrs = http_create_empty_headers();
List *msgrefs = NULL, *msglocs = NULL;
char *err = "Ok";
Octstr *x;
int start, limit;
if ((x = mms_get_header_value(m, octstr_imm("X-Mms-Start"))) != NULL) {
sscanf(octstr_get_cstr(x), "%d", &start);
octstr_destroy(x);
} else
start = 0;
if ((x = mms_get_header_value(m, octstr_imm("X-Mms-Limit"))) != NULL) {
sscanf(octstr_get_cstr(x), "%d", &limit);
octstr_destroy(x);
} else
limit = INT_MAX;
/* Check for quota and count requests. */
if ((x = mms_get_header_value(m, octstr_imm("X-Mms-Totals"))) != NULL) {
if (octstr_case_compare(x, octstr_imm("Yes")) == 0) {
unsigned long byte_count = 0, msg_count = 0;
char y[64];
mms_mmbox_count(octstr_get_cstr(settings->mmbox_rootdir),
octstr_get_cstr(h->client_addr),
&msg_count, &byte_count);
sprintf(y, "%d bytes", (int)byte_count);
http_header_add(otherhdrs, "X-Mms-Mbox-Totals", y);
sprintf(y, "%d msgs", (int)msg_count);
http_header_add(otherhdrs, "X-Mms-Mbox-Totals", y);
}
octstr_destroy(x);
}
if ((x = mms_get_header_value(m, octstr_imm("X-Mms-Quotas"))) != NULL) {
if (octstr_case_compare(x, octstr_imm("Yes")) == 0) { /* will we ever implement message quota?? */
char y[64];
sprintf(y, "%d bytes", USER_MMBOX_DATA_QUOTA);
http_header_add(otherhdrs, "X-Mms-Mbox-Quotas", y);
}
octstr_destroy(x);
}
/* Should we add the filter and limit headers to otherhdrs?
* why bother when send knows them?
*/
if (h->prof) {
int i, n;
for (i = 0, n = msgs ? list_len(msgs) : 0; i<n; i++) { /* Make message references. */
Octstr *x = list_get(msgs, i);
Octstr *sdf = NULL, *token = NULL;
int loc;
if (mms_decodefetchurl(x, &sdf, &token, &loc) == 0) {
list_insert(msgs, i, sdf);
list_delete(msgs, i+1, 1);
octstr_destroy(x);
} else {
if (sdf)
octstr_destroy(sdf);
}
if (token) octstr_destroy(token);
}
msgrefs = mms_mmbox_search(octstr_get_cstr(settings->mmbox_rootdir),
octstr_get_cstr(h->client_addr), xstates,
xflags, start, limit, msgs);
/* Make the locations. */
msglocs = list_create();
for (i = 0, n = list_len(msgrefs); i < n; i++) {
Octstr *sdf = list_get(msgrefs, i);
list_append(msglocs,
mms_makefetchurl(octstr_get_cstr(sdf),
NULL, MMS_LOC_MMBOX, settings));
}
} else /* Profile not loaded... */
err = "Error-transient-network-problem";
mresp = mms_viewconf(octstr_get_cstr(otransid),
msgrefs,
msglocs,
err,
required_headers,
(MmsMsgGetFunc_t *)mms_mmbox_get,
octstr_get_cstr(settings->mmbox_rootdir),
octstr_get_cstr(h->client_addr),
mms_ua_maxmsgsize(h->prof),
MS_1_2,
otherhdrs);
reply_body = mms_tobinary(mresp);
notify_cmd = "deleted";
if (xflags)
list_destroy(xflags, (list_item_destructor_t *)octstr_destroy);
if (xstates)
list_destroy(xstates, (list_item_destructor_t *)octstr_destroy);
if (required_headers)
list_destroy(required_headers, (list_item_destructor_t *)octstr_destroy);
if (msgrefs)
list_destroy(msgrefs, (list_item_destructor_t *)octstr_destroy);
if (msglocs)
list_destroy(msglocs, (list_item_destructor_t *)octstr_destroy);
if (msgs)
list_destroy(msgs, (list_item_destructor_t *)octstr_destroy);
if (otherhdrs)
http_destroy_headers(otherhdrs);
if (otransid)
octstr_destroy(otransid);
}
break;
default:
http_header_add(rh, "Content-Type", "text/plain");
ctype_set = 1;
hstatus = HTTP_FORBIDDEN;
reply_body = octstr_format("Unexpected MMS message type %s", mms_message_type_to_cstr(mtype));
break;
}
if (notify_cmd) /* Inform provisioning server */
notify_prov_server(octstr_get_cstr(settings->prov_notify),
h->base_client_addr ? octstr_get_cstr(h->base_client_addr) : "unknown",
notify_cmd,
octstr_get_cstr(settings->prov_notify_arg));
mms_destroy(m);
/* Send reply. */
done:
if (mresp)
mms_destroy(mresp);
if (!ctype_set)
http_header_add(rh, "Content-Type", "application/vnd.wap.mms-message");
http_send_reply(h->client, hstatus, rh, reply_body);
http_destroy_headers(rh);
octstr_destroy(reply_body);
octstr_destroy(h->ip);
octstr_destroy(h->url);
if (h->base_client_addr)
octstr_destroy(h->base_client_addr);
if (h->client_addr)
octstr_destroy(h->client_addr);
if (h->ua) octstr_destroy(h->ua);
if (h->body) octstr_destroy(h->body);
http_destroy_cgiargs(h->cgivars);
http_destroy_headers(h->headers);
gw_free(h);
}