2005-09-02 11:41:28 +00:00
|
|
|
/*
|
|
|
|
* Mbuni - Open Source MMS Gateway
|
|
|
|
*
|
|
|
|
* MMSBOX: MMS Content engine
|
|
|
|
*
|
|
|
|
* 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>
|
2005-09-07 10:10:41 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include "mms_queue.h"
|
|
|
|
#include "mms_uaprof.h"
|
|
|
|
#include "mmsbox.h"
|
2005-09-02 11:41:28 +00:00
|
|
|
|
2006-05-02 13:02:15 +00:00
|
|
|
/* XXX warning, do not octstr_destroy cgi variables. They are destroyed by the http module! */
|
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
int rstop = 0;
|
2005-09-02 11:41:28 +00:00
|
|
|
static void quit_now(int notused)
|
|
|
|
{
|
2005-09-09 13:11:38 +00:00
|
|
|
int i, n;
|
|
|
|
MmscGrp *mmc;
|
2005-09-02 11:41:28 +00:00
|
|
|
rstop = 1;
|
|
|
|
|
|
|
|
/* Close all MMSC http ports, kill all MMSC threads, kill sendmms port... */
|
2005-09-09 13:11:38 +00:00
|
|
|
|
|
|
|
if (sendmms_port.port > 0)
|
|
|
|
http_close_port(sendmms_port.port);
|
|
|
|
|
|
|
|
for (i = 0, n = list_len(mmscs); i < n; i++)
|
|
|
|
if ((mmc = list_get(mmscs, i)) != NULL &&
|
|
|
|
mmc->incoming.port > 0)
|
|
|
|
http_close_port(mmc->incoming.port);
|
2005-09-02 11:41:28 +00:00
|
|
|
}
|
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
static MIMEEntity *find_textpart(MIMEEntity *m)
|
|
|
|
{
|
|
|
|
Octstr *ctype = NULL, *params = NULL;
|
|
|
|
MIMEEntity *res = NULL;
|
|
|
|
|
|
|
|
if (!m) return NULL;
|
|
|
|
|
|
|
|
get_content_type(m->headers, &ctype, ¶ms);
|
|
|
|
|
|
|
|
if (ctype && octstr_str_compare(ctype, "text/plain") == 0) {
|
|
|
|
res = m;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m->multiparts) {
|
|
|
|
int i, n = list_len(m->multiparts);
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
if ((res = find_textpart(list_get(m->multiparts, i))) != NULL)
|
2005-09-09 13:11:38 +00:00
|
|
|
goto done2;
|
2005-09-07 10:10:41 +00:00
|
|
|
}
|
|
|
|
done:
|
|
|
|
|
|
|
|
if (res) { /* We got it! Convert charset if needed. */
|
|
|
|
List *params_h = get_value_parameters(params);
|
|
|
|
Octstr *charset = http_header_value(params_h, octstr_imm("charset"));
|
|
|
|
|
|
|
|
if (charset == NULL ||
|
|
|
|
octstr_str_compare(charset, "unknown") == 0) {
|
|
|
|
if (charset) octstr_destroy(charset);
|
|
|
|
charset = octstr_imm(DEFAULT_CHARSET);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (octstr_case_compare(charset, octstr_imm(DEFAULT_CHARSET)) != 0)
|
|
|
|
charset_convert(m->body, DEFAULT_CHARSET, octstr_get_cstr(charset)); /* XXX error ignored? */
|
|
|
|
http_destroy_headers(params_h);
|
|
|
|
octstr_destroy(charset);
|
|
|
|
}
|
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
done2:
|
|
|
|
if (ctype)
|
|
|
|
octstr_destroy(ctype);
|
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
if (params)
|
|
|
|
octstr_destroy(params);
|
|
|
|
return res;
|
|
|
|
}
|
2005-09-09 13:11:38 +00:00
|
|
|
|
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
/* Gets the keyword, if any, from the text part of the message.
|
|
|
|
* converts charset as needed.
|
|
|
|
*/
|
|
|
|
static Octstr *get_keyword(MIMEEntity *me)
|
|
|
|
{
|
|
|
|
|
|
|
|
MIMEEntity *t = find_textpart(me);
|
|
|
|
Octstr *txt = t ? t->body : NULL;
|
|
|
|
List *l = t ? octstr_split_words(txt) : NULL;
|
|
|
|
Octstr *keyword = l ? list_get(l, 0) : NULL;
|
|
|
|
|
|
|
|
|
|
|
|
if (keyword)
|
|
|
|
keyword = octstr_duplicate(keyword);
|
|
|
|
if (l)
|
|
|
|
list_destroy(l, (list_item_destructor_t *)octstr_destroy);
|
|
|
|
|
|
|
|
return keyword;
|
|
|
|
}
|
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
static int _x_octstr_comp(Octstr *x, Octstr *y)
|
|
|
|
{
|
|
|
|
return (octstr_case_compare(x,y) == 0);
|
|
|
|
}
|
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
static MmsService *get_service(Octstr *keyword, Octstr *mmc_id)
|
|
|
|
{
|
|
|
|
int i, n;
|
2005-09-09 13:11:38 +00:00
|
|
|
MmsService *catch_all = NULL;
|
2005-09-07 10:10:41 +00:00
|
|
|
|
|
|
|
for (i = 0, n = list_len(mms_services); i < n; i++) {
|
|
|
|
MmsService *ms = list_get(mms_services,i);
|
|
|
|
|
|
|
|
/* Check that mmc_id is allowed:
|
|
|
|
* denied list is not null and we are on it, or allowed list is not null and we
|
|
|
|
* are *not* on it.
|
|
|
|
*/
|
|
|
|
if (ms->denied_mmscs &&
|
|
|
|
list_search(ms->denied_mmscs, mmc_id, (list_item_matches_t *)octstr_compare) != NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (ms->allowed_mmscs &&
|
|
|
|
list_search(ms->allowed_mmscs, mmc_id, (list_item_matches_t *)octstr_compare) == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (keyword == NULL ||
|
|
|
|
list_search(ms->keywords, keyword,
|
2005-09-09 13:11:38 +00:00
|
|
|
(list_item_matches_t *)_x_octstr_comp) != NULL)
|
2005-09-07 10:10:41 +00:00
|
|
|
return ms;
|
2005-09-09 13:11:38 +00:00
|
|
|
|
|
|
|
if (ms->isdefault) /* We also find the catch-all for this sender. */
|
|
|
|
catch_all = ms;
|
2005-09-07 10:10:41 +00:00
|
|
|
}
|
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
return catch_all;
|
2005-09-07 10:10:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void add_all_matching_parts(MIMEEntity *plist, MmsServiceUrlParam *pm,
|
|
|
|
MIMEEntity *me, MmsMsg *msg, int lev)
|
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
|
|
|
|
Octstr *data = NULL, *ctype = NULL, *xctype = NULL, *params = NULL;
|
|
|
|
|
|
|
|
if (pm->type == WHOLE_BINARY && lev == 0) {
|
|
|
|
data = mms_tobinary(msg);
|
|
|
|
ctype = octstr_imm("application/vnd.wap.mms-message");
|
2005-09-09 13:11:38 +00:00
|
|
|
} else if (pm->type == NO_PART && lev == 0) {
|
|
|
|
data = octstr_create(""); /* We'll add value below. */
|
|
|
|
goto done;
|
2005-09-07 10:10:41 +00:00
|
|
|
}
|
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
if (me->multiparts && list_len(me->multiparts) > 0) { /* Don't process multipart. */
|
2005-09-07 10:10:41 +00:00
|
|
|
for (i = 0, n = list_len(me->multiparts); i < n; i++)
|
|
|
|
add_all_matching_parts(plist, pm,
|
|
|
|
list_get(me->multiparts, i), msg, lev+1);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
get_content_type(me->headers, &xctype, ¶ms);
|
|
|
|
|
|
|
|
#define BEGINSWITH(s, prefix) (octstr_case_search(s, octstr_imm(prefix),0) == 0)
|
|
|
|
#define TYPE_MATCH(typ, prefix) ((pm->type) == (typ) && \
|
|
|
|
BEGINSWITH(xctype, prefix))
|
|
|
|
|
|
|
|
if (xctype)
|
|
|
|
if (TYPE_MATCH(IMAGE_PART,"image/") ||
|
2005-09-15 07:57:56 +00:00
|
|
|
TYPE_MATCH(AUDIO_PART,"audio/") ||
|
2005-09-07 10:10:41 +00:00
|
|
|
TYPE_MATCH(VIDEO_PART,"video/") ||
|
|
|
|
TYPE_MATCH(TEXT_PART,"text/") ||
|
|
|
|
TYPE_MATCH(SMIL_PART,"application/smil") ||
|
|
|
|
pm->type == ANY_PART || /* Skip top-level for 'any' parts. */
|
|
|
|
(pm->type == OTHER_PART &&
|
|
|
|
(!BEGINSWITH(xctype, "text/") &&
|
|
|
|
!BEGINSWITH(xctype, "video/") &&
|
|
|
|
!BEGINSWITH(xctype, "image/") &&
|
|
|
|
!BEGINSWITH(xctype, "application/smil")))) {
|
|
|
|
|
|
|
|
ctype = http_header_value(me->headers, octstr_imm("Content-Type"));
|
|
|
|
data = me->body ? octstr_duplicate(me->body) : octstr_create("");
|
|
|
|
}
|
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
done:
|
|
|
|
if (data) {
|
2005-09-07 10:10:41 +00:00
|
|
|
MIMEEntity *p = mime_entity_create();
|
|
|
|
Octstr *cd = octstr_format("form-data; name=\"%S\"", pm->name);
|
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
if (ctype) {
|
|
|
|
/* If name parameter given, pass it as filename. */
|
|
|
|
Octstr *c = NULL, *q = NULL;
|
|
|
|
split_header_value(ctype, &c, &q);
|
|
|
|
|
|
|
|
if (q) {
|
|
|
|
List *ph = get_value_parameters(q);
|
|
|
|
Octstr *v = http_header_value(ph, octstr_imm("name"));
|
|
|
|
|
2006-05-29 14:00:36 +00:00
|
|
|
if (!v) /* make up a fake name. */
|
|
|
|
v = octstr_format("%S-file", pm->name);
|
|
|
|
|
|
|
|
octstr_format_append(cd, "; filename=\"%S\"", v);
|
|
|
|
http_header_remove_all(ph, "name");
|
|
|
|
|
|
|
|
octstr_destroy(v);
|
|
|
|
octstr_destroy(ctype);
|
|
|
|
v = make_value_parameters(ph);
|
|
|
|
if (v && octstr_len(v) > 0)
|
|
|
|
ctype = octstr_format("%S; %S", c, v);
|
|
|
|
else
|
|
|
|
ctype = octstr_duplicate(c);
|
|
|
|
if (v)
|
2005-09-09 13:11:38 +00:00
|
|
|
octstr_destroy(v);
|
2006-05-29 14:00:36 +00:00
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
http_destroy_headers(ph);
|
|
|
|
octstr_destroy(q);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c)
|
|
|
|
octstr_destroy(c);
|
|
|
|
}
|
|
|
|
http_header_add(p->headers, "Content-Disposition", octstr_get_cstr(cd));
|
|
|
|
if (ctype) /* This header must come after the above it seems. */
|
|
|
|
http_header_add(p->headers, "Content-Type", octstr_get_cstr(ctype));
|
2005-09-07 10:10:41 +00:00
|
|
|
|
|
|
|
p->body = data;
|
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
if (pm->value) /* add value part as needed. */
|
|
|
|
octstr_append(p->body, pm->value);
|
2005-09-12 09:51:31 +00:00
|
|
|
#if 0
|
2005-09-07 10:10:41 +00:00
|
|
|
base64_mimeparts(p);
|
2005-09-12 09:51:31 +00:00
|
|
|
#endif
|
2005-09-07 10:10:41 +00:00
|
|
|
list_append(plist->multiparts, p);
|
|
|
|
|
|
|
|
octstr_destroy(cd);
|
|
|
|
|
|
|
|
}
|
2005-09-09 13:11:38 +00:00
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
if (xctype)
|
|
|
|
octstr_destroy(xctype);
|
|
|
|
if (params)
|
|
|
|
octstr_destroy(params);
|
2005-09-09 13:11:38 +00:00
|
|
|
if (ctype)
|
|
|
|
octstr_destroy(ctype);
|
2005-09-07 10:10:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
enum _xurltype {FILE_TYPE, URL_TYPE};
|
|
|
|
static Octstr *url_path_prefix(Octstr *url, int type);
|
|
|
|
static Octstr *filename2content_type(char *fname);
|
|
|
|
static int make_and_queue_msg(Octstr *data, Octstr *ctype, List *reply_headers,
|
|
|
|
Octstr *base_url, int type, MmsEnvelope *e,
|
|
|
|
Octstr *svc_name, Octstr *faked_sender,
|
2006-05-03 13:52:40 +00:00
|
|
|
int accept_x_headers,
|
|
|
|
List *passthro_headers,
|
|
|
|
Octstr **err);
|
2005-09-07 10:10:41 +00:00
|
|
|
static int fetch_serviceurl(MmsEnvelope *e,
|
|
|
|
MmsService *ms, MmsMsg *m,
|
|
|
|
MIMEEntity *msg,
|
|
|
|
Octstr **err)
|
|
|
|
{
|
|
|
|
List *rh, *rph = NULL;
|
|
|
|
Octstr *body = NULL, *rb = NULL;
|
|
|
|
Octstr *ctype = NULL, *params = NULL;
|
|
|
|
int i, n, method, typ = FILE_TYPE;
|
|
|
|
FILE *fp = NULL;
|
|
|
|
|
|
|
|
int res = -1;
|
|
|
|
|
|
|
|
switch (ms->type) {
|
|
|
|
case TRANS_TYPE_GET_URL:
|
|
|
|
case TRANS_TYPE_POST_URL:
|
|
|
|
rh = http_create_empty_headers();
|
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
http_header_add(rh, "User-Agent", MM_NAME "/" VERSION);
|
2005-09-07 10:10:41 +00:00
|
|
|
/* Put in some useful headers. */
|
|
|
|
if (e->msgId)
|
|
|
|
http_header_add(rh, "X-Mbuni-Message-ID", octstr_get_cstr(e->msgId));
|
|
|
|
if (e->fromproxy)
|
|
|
|
http_header_add(rh, "X-Mbuni-MMSC-ID", octstr_get_cstr(e->fromproxy));
|
|
|
|
if (e->from)
|
|
|
|
http_header_add(rh, "X-Mbuni-From", octstr_get_cstr(e->from));
|
|
|
|
|
|
|
|
if (e->subject)
|
|
|
|
http_header_add(rh, "X-Mbuni-Subject", octstr_get_cstr(e->subject));
|
|
|
|
for (i = 0, n = list_len(e->to); i < n; i++) {
|
|
|
|
MmsEnvelopeTo *r = list_get(e->to, i);
|
|
|
|
if (r && r->rcpt)
|
|
|
|
http_header_add(rh, "X-Mbuni-To", octstr_get_cstr(r->rcpt));
|
|
|
|
}
|
|
|
|
if (ms->type == TRANS_TYPE_POST_URL) { /* Put in the parameters. */
|
|
|
|
MIMEEntity *x = mime_entity_create();
|
|
|
|
|
|
|
|
http_header_add(rh, "Content-Type", "multipart/form-data");
|
|
|
|
|
|
|
|
http_destroy_headers(x->headers);
|
|
|
|
x->headers = rh;
|
|
|
|
for (i = 0, n = list_len(ms->params); i < n; i++) {
|
|
|
|
MmsServiceUrlParam *p = list_get(ms->params, i);
|
|
|
|
add_all_matching_parts(x, p, msg, m, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
mime_entity_body_and_headers(x, &body, &rh);
|
|
|
|
mime_entity_destroy(x);
|
|
|
|
|
|
|
|
method = HTTP_METHOD_POST;
|
|
|
|
} else
|
|
|
|
method = HTTP_METHOD_GET;
|
|
|
|
|
|
|
|
typ = URL_TYPE;
|
2005-09-09 13:11:38 +00:00
|
|
|
if (mmsbox_url_fetch_content(method, ms->url, rh, body, &rph, &rb) == HTTP_OK)
|
2005-09-07 10:10:41 +00:00
|
|
|
get_content_type(rph, &ctype, ¶ms);
|
|
|
|
else
|
|
|
|
*err = octstr_format("MMSBox: Failed to fetch content for Service %S, url %S!",
|
|
|
|
ms->name, ms->url);
|
|
|
|
http_destroy_headers(rh);
|
|
|
|
if (body)
|
|
|
|
octstr_destroy(body);
|
|
|
|
break;
|
|
|
|
case TRANS_TYPE_FILE:
|
2006-05-29 06:30:39 +00:00
|
|
|
if ((fp = fopen(octstr_get_cstr(ms->url), "r")) != NULL) {
|
|
|
|
rb = octstr_read_pipe(fp);
|
|
|
|
fclose(fp);
|
|
|
|
ctype = filename2content_type(octstr_get_cstr(ms->url));
|
|
|
|
}
|
2005-09-07 10:10:41 +00:00
|
|
|
|
2006-05-29 06:30:39 +00:00
|
|
|
if (!rb)
|
|
|
|
*err = octstr_format("MMSBox: Failed to open file %S for service %S!",
|
|
|
|
ms->url, ms->name);
|
|
|
|
typ = FILE_TYPE;
|
|
|
|
break;
|
|
|
|
case TRANS_TYPE_EXEC:
|
|
|
|
if ((fp = popen(octstr_get_cstr(ms->url), "r+")) != NULL) {
|
|
|
|
Octstr *s = mime_entity_to_octstr(msg);
|
|
|
|
if (s) { /* Send the MMS to the exec program */
|
|
|
|
octstr_print(fp, s);
|
|
|
|
fflush(fp);
|
|
|
|
octstr_destroy(s);
|
|
|
|
}
|
|
|
|
rb = octstr_read_pipe(fp);
|
2005-09-07 10:10:41 +00:00
|
|
|
ctype = octstr_imm("application/smil");
|
|
|
|
pclose(fp);
|
|
|
|
}
|
|
|
|
if (!rb)
|
2006-05-29 06:30:39 +00:00
|
|
|
*err = octstr_format("MMSBox: Failed to fetch content for Service %S, exec path = %S!",
|
2005-09-07 10:10:41 +00:00
|
|
|
ms->name, ms->url);
|
|
|
|
typ = FILE_TYPE;
|
|
|
|
break;
|
|
|
|
case TRANS_TYPE_TEXT:
|
|
|
|
rb = octstr_duplicate(ms->url);
|
|
|
|
ctype = octstr_imm("text/plain");
|
|
|
|
typ = URL_TYPE;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
*err = octstr_format(0, "MMSBOX: Unknown Service type for service %S!", ms->name);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-05-03 13:52:40 +00:00
|
|
|
/* If we have the content, make the message and write it to out-going.
|
|
|
|
* if we have no content, or we have been told to suppress the reply, then we suppress
|
|
|
|
*/
|
|
|
|
if (!ctype || !rb ||
|
|
|
|
(octstr_len(rb) == 0 && ms->omitempty) ||
|
|
|
|
ms->noreply) {
|
|
|
|
info(0, "MMSBox.service_request: Suppressed reply for service %s, "
|
|
|
|
"suppress-reply=%s, omit-empty=%s, reply-len=%ld, content-type=%s",
|
|
|
|
octstr_get_cstr(ms->name), ms->noreply ? "true" : "false",
|
|
|
|
ms->omitempty ? "true" : "false",
|
|
|
|
rb ? octstr_len(rb) : 0,
|
|
|
|
ctype ? octstr_get_cstr(ctype) : "");
|
2005-09-07 10:10:41 +00:00
|
|
|
goto done;
|
2006-05-03 13:52:40 +00:00
|
|
|
} else {
|
2005-09-07 10:10:41 +00:00
|
|
|
Octstr *base_url = url_path_prefix(ms->url, typ);
|
|
|
|
res = make_and_queue_msg(rb, ctype, rph, base_url,
|
|
|
|
typ, e, ms->name, ms->faked_sender,
|
2006-05-03 13:52:40 +00:00
|
|
|
ms->accept_x_headers, ms->passthro_headers,
|
|
|
|
err);
|
2005-09-07 10:10:41 +00:00
|
|
|
|
|
|
|
if (base_url)
|
|
|
|
octstr_destroy(base_url);
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (ctype)
|
|
|
|
octstr_destroy(ctype);
|
|
|
|
if (rb)
|
|
|
|
octstr_destroy(rb);
|
|
|
|
if (rph)
|
|
|
|
http_destroy_headers(rph);
|
|
|
|
if (params)
|
|
|
|
octstr_destroy(params);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int mmsbox_service_dispatch(MmsEnvelope *e)
|
|
|
|
{
|
|
|
|
MmsMsg *msg = NULL;
|
|
|
|
MIMEEntity *me = NULL;
|
|
|
|
int i, n, res = 0;
|
|
|
|
time_t tnow = time(NULL);
|
|
|
|
Octstr *err = NULL, *keyword = NULL;
|
|
|
|
MmsService *ms;
|
|
|
|
|
|
|
|
gw_assert(e->msgtype == MMS_MSGTYPE_SEND_REQ);
|
|
|
|
|
|
|
|
if ((msg = mms_queue_getdata(e)) == NULL) {
|
|
|
|
err = octstr_format("Failed to read message for queue entry %s!",
|
|
|
|
e->xqfname);
|
|
|
|
res = -1;
|
|
|
|
goto done;
|
|
|
|
} else if (e->expiryt != 0 && /* Handle message expiry. */
|
|
|
|
e->expiryt < tnow) {
|
|
|
|
err = octstr_format("Queue entry [msgid=%S,mmc_id=%S] "
|
|
|
|
"expired while sending to service!", e->msgId, e->fromproxy);
|
|
|
|
res = -1;
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
} else if (e->attempts >= mmsbox_maxsendattempts) {
|
|
|
|
err = octstr_format("Failed to deliver [msgid=%S,mmc_id=%S] "
|
|
|
|
"after %ld attempts. (max attempts allowed is %ld)!",
|
|
|
|
e->msgId, e->fromproxy, e->attempts,
|
|
|
|
mmsbox_maxsendattempts);
|
|
|
|
res = -1;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
me = mms_tomime(msg, 0);
|
|
|
|
keyword = get_keyword(me);
|
|
|
|
|
|
|
|
ms = get_service(keyword, e->fromproxy);
|
|
|
|
|
|
|
|
if (!ms) {
|
|
|
|
err = octstr_format("No Service to handle %S (keyword %S)!",
|
|
|
|
e->msgId, keyword ? octstr_imm("") : keyword);
|
|
|
|
res = -1;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
e->_x = ms; /* Remember it for later. */
|
|
|
|
|
|
|
|
res = fetch_serviceurl(e, ms, msg, me, &err);
|
|
|
|
done:
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
error(0, "MMSBox error: %s", octstr_get_cstr(err));
|
|
|
|
octstr_destroy(err);
|
|
|
|
}
|
|
|
|
if (res == -1 || res == 0) /* Fatal error, or success delete queue entry. */
|
|
|
|
for (i = 0, n = list_len(e->to); i < n; i++) {
|
|
|
|
MmsEnvelopeTo *r = list_get(e->to,i);
|
|
|
|
if (r)
|
|
|
|
r->process = 0;
|
|
|
|
}
|
|
|
|
else { /* Not succeeded so we need to wait a bit and try later. */
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (keyword)
|
|
|
|
octstr_destroy(keyword);
|
|
|
|
if (msg)
|
|
|
|
mms_destroy(msg);
|
|
|
|
if (me)
|
|
|
|
mime_entity_destroy(me);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sendmms_func(void *unused);
|
2005-09-02 11:41:28 +00:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
Octstr *fname;
|
|
|
|
int cfidx;
|
2006-02-17 11:48:33 +00:00
|
|
|
mCfg *cfg;
|
2005-09-07 10:10:41 +00:00
|
|
|
|
|
|
|
long qthread = 0, sthread = 0;
|
2005-09-02 11:41:28 +00:00
|
|
|
|
|
|
|
mms_lib_init();
|
|
|
|
|
|
|
|
srandom(time(NULL));
|
|
|
|
|
|
|
|
cfidx = get_and_set_debugs(argc, argv, NULL);
|
|
|
|
|
|
|
|
if (argv[cfidx] == NULL)
|
|
|
|
fname = octstr_imm("mbuni.conf");
|
|
|
|
else
|
|
|
|
fname = octstr_create(argv[cfidx]);
|
|
|
|
|
2006-02-17 11:48:33 +00:00
|
|
|
cfg = mms_cfg_read(fname);
|
2005-09-02 11:41:28 +00:00
|
|
|
|
2006-02-17 11:48:33 +00:00
|
|
|
if (cfg == NULL)
|
2005-09-02 11:41:28 +00:00
|
|
|
panic(0, "Couldn't read configuration from '%s'.", octstr_get_cstr(fname));
|
|
|
|
|
|
|
|
octstr_destroy(fname);
|
|
|
|
|
|
|
|
info(0, "----------------------------------------");
|
|
|
|
info(0, " " MM_NAME " MMSBox version %s starting", MMSC_VERSION);
|
|
|
|
|
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
mms_load_mmsbox_settings(cfg,(gwthread_func_t *)mmsc_receive_func);
|
2005-09-02 11:41:28 +00:00
|
|
|
|
2006-02-17 11:48:33 +00:00
|
|
|
mms_cfg_destroy(cfg);
|
2005-09-02 11:41:28 +00:00
|
|
|
|
|
|
|
signal(SIGHUP, quit_now);
|
|
|
|
signal(SIGTERM, quit_now);
|
|
|
|
signal(SIGPIPE,SIG_IGN); /* Ignore pipe errors. They kill us sometimes for nothing*/
|
2005-09-07 10:10:41 +00:00
|
|
|
|
2005-09-12 09:51:31 +00:00
|
|
|
/* Start sendmms port */
|
2005-09-07 10:10:41 +00:00
|
|
|
if (sendmms_port.port > 0)
|
|
|
|
sthread = gwthread_create((gwthread_func_t *)sendmms_func, NULL);
|
2005-09-09 13:11:38 +00:00
|
|
|
|
2005-09-14 07:01:09 +00:00
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
/* Start out-going queue thread. */
|
|
|
|
qthread = gwthread_create((gwthread_func_t *)mmsbox_outgoing_queue_runner, &rstop);
|
2005-09-15 07:57:56 +00:00
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
mms_queue_run(octstr_get_cstr(incoming_qdir),
|
|
|
|
mmsbox_service_dispatch,
|
|
|
|
queue_interval, maxthreads, &rstop);
|
2005-09-15 07:57:56 +00:00
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
/* Wait for the sender thread, then quit. */
|
|
|
|
gwthread_join(qthread); /* Wait for it to die... */
|
|
|
|
|
|
|
|
if (sendmms_port.port > 0)
|
|
|
|
gwthread_join(sthread);
|
|
|
|
sleep(2);
|
2006-01-11 05:29:21 +00:00
|
|
|
mms_lib_shutdown();
|
2005-09-02 11:41:28 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2005-09-07 10:10:41 +00:00
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
int mmsbox_url_fetch_content(int method, Octstr *url, List *request_headers,
|
2005-09-07 10:10:41 +00:00
|
|
|
Octstr *body, List **reply_headers, Octstr **reply_body)
|
|
|
|
{
|
2005-09-09 13:11:38 +00:00
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
int status = 0;
|
|
|
|
Octstr *furl = NULL;
|
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
if (octstr_search(url, octstr_imm("data:"), 0) == 0) {
|
|
|
|
int i = octstr_search_char(url, ',',0);
|
|
|
|
Octstr *ctype = (i >= 0) ? octstr_copy(url, 5, i-5) : octstr_create("text/plain; charset=us-ascii");
|
|
|
|
Octstr *data = (i >= 0) ? octstr_copy(url, i+1, octstr_len(url)) : octstr_duplicate(url);
|
|
|
|
|
|
|
|
Octstr *n = NULL, *h = NULL;
|
|
|
|
|
|
|
|
if (octstr_len(ctype) == 0)
|
|
|
|
octstr_append_cstr(ctype, "text/plain; charset=us-ascii");
|
|
|
|
|
|
|
|
split_header_value(ctype, &n, &h);
|
|
|
|
|
|
|
|
if (h) {
|
|
|
|
List *ph = get_value_parameters(h);
|
|
|
|
Octstr *v = NULL;
|
|
|
|
|
|
|
|
if (ph && (v = http_header_value(ph, octstr_imm("base64"))) != NULL) { /* has base64 item */
|
|
|
|
Octstr *p = NULL;
|
2005-09-07 10:10:41 +00:00
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
octstr_base64_to_binary(data);
|
|
|
|
http_header_remove_all(ph, "base64");
|
|
|
|
|
|
|
|
octstr_destroy(ctype);
|
|
|
|
|
|
|
|
if (list_len(ph) > 0) {
|
|
|
|
p = make_value_parameters(ph);
|
|
|
|
ctype = octstr_format("%S; %S",
|
|
|
|
n,p);
|
|
|
|
octstr_destroy(p);
|
|
|
|
} else
|
|
|
|
ctype = octstr_format("%S", n);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ph)
|
|
|
|
http_destroy_headers(ph);
|
2005-09-07 10:10:41 +00:00
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
octstr_destroy(v);
|
|
|
|
octstr_destroy(h);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n)
|
|
|
|
octstr_destroy(n);
|
|
|
|
|
|
|
|
*reply_body = data;
|
|
|
|
*reply_headers = http_create_empty_headers();
|
|
|
|
http_header_add(*reply_headers, "Content-Type", octstr_get_cstr(ctype));
|
|
|
|
|
|
|
|
octstr_destroy(ctype);
|
|
|
|
status = HTTP_OK;
|
|
|
|
} else {
|
|
|
|
HTTPCaller *c = http_caller_create();
|
|
|
|
http_start_request(c, method, url, request_headers, body, 1, NULL, NULL);
|
|
|
|
if (http_receive_result(c, &status, &furl, reply_headers, reply_body) == NULL)
|
|
|
|
status = -1;
|
|
|
|
http_caller_destroy(c);
|
|
|
|
}
|
2005-09-07 10:10:41 +00:00
|
|
|
if (furl)
|
|
|
|
octstr_destroy(furl);
|
2005-09-09 13:11:38 +00:00
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Mapping file extensions to content types. */
|
|
|
|
static struct {
|
|
|
|
char *ctype, *file_ext;
|
|
|
|
} exts[] = {
|
|
|
|
{"text/plain", "txt"},
|
|
|
|
{"image/jpeg", "jpg"},
|
|
|
|
{"image/jpeg", "jpeg"},
|
|
|
|
{"image/png", "png"},
|
|
|
|
{"image/tiff", "tiff"},
|
|
|
|
{"image/gif", "gif"},
|
|
|
|
{"image/bmp", "bmp"},
|
|
|
|
{"image/vnd.wap.wbmp", "wbmp"},
|
|
|
|
{"image/x-bmp", "bmp"},
|
|
|
|
{"image/x-wmf", "bmp"},
|
|
|
|
{"image/vnd.wap.wpng", "png"},
|
|
|
|
{"image/x-up-wpng", "png"},
|
|
|
|
{"audio/mpeg", "mp3"},
|
|
|
|
{"audio/wav", "wav"},
|
|
|
|
{"audio/x-wav", "wav"},
|
|
|
|
{"audio/basic", "au"},
|
|
|
|
{"audio/amr", "amr"},
|
|
|
|
{"audio/x-amr", "amr"},
|
|
|
|
{"audio/amr-wb", "amr"},
|
|
|
|
{"audio/midi", "mid"},
|
|
|
|
{"audio/sp-midi", "mid"},
|
|
|
|
{"application/smil", "smil"},
|
|
|
|
{NULL, NULL}
|
|
|
|
};
|
|
|
|
|
|
|
|
static Octstr *filename2content_type(char *fname)
|
|
|
|
{
|
|
|
|
char *p = strrchr(fname, '.');
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (p)
|
|
|
|
for (i = 0; exts[i].file_ext; i++)
|
|
|
|
if (strcasecmp(p+1, exts[i].file_ext) == 0)
|
|
|
|
return octstr_imm(exts[i].ctype);
|
|
|
|
|
|
|
|
return octstr_imm("application/octet-stream");
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return the prefix part of a url or file. */
|
|
|
|
static Octstr *url_path_prefix(Octstr *url, int type)
|
|
|
|
{
|
|
|
|
int i, j, len = octstr_len(url);
|
|
|
|
char *p = octstr_get_cstr(url);
|
|
|
|
|
|
|
|
/* Set lower/upper limit of search. */
|
|
|
|
if (type == URL_TYPE) { /* then skip first slashes. */
|
|
|
|
char *x;
|
|
|
|
i = octstr_search(url, octstr_imm("://"),0);
|
|
|
|
if (i > 0)
|
|
|
|
i += 3;
|
|
|
|
else
|
|
|
|
i = 0;
|
|
|
|
x = rindex(p, '#'); /* look for fragment if any. */
|
|
|
|
|
|
|
|
if (x)
|
|
|
|
j = x - p - 1;
|
|
|
|
else
|
|
|
|
j = len - 1;
|
|
|
|
} else {
|
|
|
|
i = 0;
|
|
|
|
j = len - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now search backwards for the last '/'.
|
|
|
|
* if you don't find one, set to end of string.
|
|
|
|
*/
|
|
|
|
|
|
|
|
for (;j > i; j--)
|
|
|
|
if (p[j] == '/')
|
|
|
|
break;
|
|
|
|
if (j <= i)
|
|
|
|
j = len;
|
|
|
|
|
|
|
|
return octstr_copy(url, 0, j);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get's just the host:port part, leaving out UrI */
|
|
|
|
static Octstr *get_toplevel_url(Octstr *url)
|
|
|
|
{
|
|
|
|
int i, len = octstr_len(url);
|
|
|
|
char *p = octstr_get_cstr(url);
|
|
|
|
|
|
|
|
i = octstr_search(url, octstr_imm("://"),0);
|
|
|
|
|
|
|
|
if (i > 0)
|
|
|
|
i += 3;
|
|
|
|
else
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
for ( ; i < len; i++)
|
|
|
|
if (p[i] == '/')
|
|
|
|
break;
|
|
|
|
|
|
|
|
return octstr_copy(url, 0, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* little dirty method to see if file begins with url scheme. */
|
|
|
|
static int has_url_scheme(char *url)
|
|
|
|
{
|
|
|
|
char *p = strstr(url, "://");
|
2005-09-09 13:11:38 +00:00
|
|
|
char *q = strstr(url, "data:"); /* data url scheme. */
|
|
|
|
|
|
|
|
if (q && q == url)
|
|
|
|
return 1;
|
2005-09-07 10:10:41 +00:00
|
|
|
if (!p)
|
|
|
|
return 0;
|
|
|
|
for (p -= 1; p >= url; p--)
|
|
|
|
if (!isalpha(*p))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int add_msg_part(MIMEEntity *res, xmlNodePtr node, Octstr *base_url,
|
|
|
|
Octstr *top_url,
|
2006-01-23 07:11:33 +00:00
|
|
|
int type, Octstr *svc_name, Dict *url_map)
|
2005-09-07 10:10:41 +00:00
|
|
|
{
|
|
|
|
Octstr *curl = NULL, *ctype = NULL, *body = NULL;
|
|
|
|
char *src = NULL;
|
|
|
|
int isurl, slash_prefix;
|
2006-01-23 07:11:33 +00:00
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
static int cntr; /* For generating cids */
|
2005-09-09 13:11:38 +00:00
|
|
|
Octstr *cid = NULL;
|
2005-09-07 10:10:41 +00:00
|
|
|
|
|
|
|
/* For each node in the smil doc, if it has an src attribute, then:
|
|
|
|
* - if our type of base_url is FILE *and the src attribute does not look
|
|
|
|
* like a url, then file the file referenced, load it into the message and go
|
|
|
|
* - if our type is URL and the url scheme is http/https (or has no scheme)
|
|
|
|
* then fetch it and put into message.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (!node || node->type != XML_ELEMENT_NODE ||
|
|
|
|
(src = (char *)xmlGetProp(node, (unsigned char *)"src")) == NULL)
|
|
|
|
return 0; /* Nothing to do. */
|
|
|
|
|
|
|
|
if (src[0] == '\\') { /* User can escape url to prevent substitution. */
|
|
|
|
xmlSetProp(node, (xmlChar *)"src", (xmlChar *)(src + 1));
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
isurl = has_url_scheme(src);
|
|
|
|
slash_prefix = (src[0] == '/');
|
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
if (isurl && strstr(src, "http") != src) /* Only http and https allowed! */
|
2005-09-07 10:10:41 +00:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (isurl)
|
2005-09-09 13:11:38 +00:00
|
|
|
curl = octstr_create(src);
|
2005-09-07 10:10:41 +00:00
|
|
|
else if (slash_prefix) {
|
|
|
|
if (type == URL_TYPE)
|
|
|
|
curl = octstr_format("%S%s",
|
|
|
|
top_url, src);
|
|
|
|
else
|
|
|
|
curl = octstr_create(src);
|
|
|
|
} else
|
|
|
|
curl = octstr_format("%S/%s",base_url, src);
|
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
if ((cid = dict_get(url_map, curl)) != NULL) { /* We've seen it before. */
|
|
|
|
xmlSetProp(node, (xmlChar *)"src", (xmlChar *)octstr_get_cstr(cid));
|
|
|
|
/* Don't delete cid! */
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
isurl |= (type == URL_TYPE); /* From now on, this flag tells us whether we are fetching a url.*/
|
|
|
|
|
|
|
|
if (isurl) {
|
|
|
|
List *rh = http_create_empty_headers(), *rph = NULL;
|
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
http_header_add(rh, "User-Agent", MM_NAME "/" VERSION);
|
|
|
|
if (mmsbox_url_fetch_content(HTTP_METHOD_GET, curl, rh, NULL, &rph, &body) == HTTP_OK)
|
2005-09-07 10:10:41 +00:00
|
|
|
ctype = http_header_value(rph, octstr_imm("Content-Type"));
|
|
|
|
else
|
|
|
|
error(0, "MMSBOX: Failed to load url %s within SMIL content from service %s!",
|
2006-01-23 07:11:33 +00:00
|
|
|
octstr_get_cstr(curl),
|
|
|
|
svc_name ? octstr_get_cstr(svc_name) : "unknown");
|
2005-09-07 10:10:41 +00:00
|
|
|
if (rph)
|
|
|
|
http_destroy_headers(rph);
|
|
|
|
http_destroy_headers(rh);
|
|
|
|
} else {
|
|
|
|
body = octstr_read_file(octstr_get_cstr(curl));
|
|
|
|
ctype = filename2content_type(src);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ctype && body) { /* If we got it, put it in. */
|
|
|
|
Octstr *attr = octstr_format("cid:%06d", ++cntr);
|
|
|
|
char *p = octstr_get_cstr(attr) + 4;
|
|
|
|
Octstr *cid_header_val = octstr_format("<%s>", p);
|
|
|
|
MIMEEntity *x = mime_entity_create();
|
|
|
|
|
|
|
|
http_header_add(x->headers, "Content-Type", octstr_get_cstr(ctype));
|
|
|
|
http_header_add(x->headers, "Content-ID", octstr_get_cstr(cid_header_val));
|
|
|
|
x->body = body;
|
|
|
|
|
|
|
|
list_append(res->multiparts, x);
|
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
dict_put_once(url_map, curl, octstr_duplicate(attr)); /* Store the cid. */
|
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
xmlSetProp(node, (xmlChar *)"src", (xmlChar *)octstr_get_cstr(attr));
|
|
|
|
|
|
|
|
octstr_destroy(attr);
|
|
|
|
octstr_destroy(cid_header_val);
|
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (curl)
|
|
|
|
octstr_destroy(curl);
|
|
|
|
if (ctype)
|
|
|
|
octstr_destroy(ctype);
|
|
|
|
xmlFree(src);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Traverse the tree doing the above. */
|
|
|
|
static void add_msg_parts(MIMEEntity *res, xmlNodePtr node, Octstr *base_url,
|
|
|
|
Octstr *top_url,
|
2006-01-23 07:11:33 +00:00
|
|
|
int type, Octstr *svc_name, Dict *url_map)
|
2005-09-07 10:10:41 +00:00
|
|
|
{
|
|
|
|
xmlNodePtr n;
|
|
|
|
/* Do all the children recursively, then come back and do parent. */
|
|
|
|
for (n = node; n; n = n->next)
|
|
|
|
if (n->type != XML_COMMENT_NODE) {
|
2006-01-23 07:11:33 +00:00
|
|
|
add_msg_part(res, n, base_url, top_url, type, svc_name, url_map);
|
|
|
|
add_msg_parts(res, n->xmlChildrenNode, base_url, top_url, type, svc_name, url_map);
|
2005-09-07 10:10:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Given content, make a message. We'll also use this for send-mms-user! */
|
|
|
|
static int make_and_queue_msg(Octstr *data, Octstr *ctype, List *reply_headers,
|
|
|
|
Octstr *base_url, int type, MmsEnvelope *e,
|
|
|
|
Octstr *svc_name, Octstr *faked_sender,
|
2006-05-03 13:52:40 +00:00
|
|
|
int accept_x_headers, List *passthro_headers,
|
|
|
|
Octstr **err)
|
2005-09-07 10:10:41 +00:00
|
|
|
{
|
|
|
|
Octstr *from = NULL, *subject = NULL, *turl = get_toplevel_url(base_url);
|
|
|
|
Octstr *dlr_url = NULL, *rr_url = NULL, *mmc = NULL;
|
|
|
|
MmsMsg *m = NULL;
|
|
|
|
MIMEEntity *me = mime_entity_create();
|
2006-05-03 13:52:40 +00:00
|
|
|
List *hdrs = NULL;
|
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
time_t expiryt = 0;
|
|
|
|
Octstr *x;
|
|
|
|
List *xto = list_create();;
|
|
|
|
int i, n, res = -1;
|
2005-09-12 09:51:31 +00:00
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
gw_assert(svc_name);
|
2005-09-12 09:51:31 +00:00
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
/* Get the from address. */
|
|
|
|
if (faked_sender)
|
|
|
|
from = octstr_duplicate(faked_sender);
|
|
|
|
else if (accept_x_headers && reply_headers &&
|
|
|
|
(from = http_header_value(reply_headers, octstr_imm("X-Mbuni-From"))) != NULL)
|
|
|
|
(void)0; /* all done above. */
|
|
|
|
else {
|
|
|
|
/* get first recipient, set that as sender. */
|
|
|
|
MmsEnvelopeTo *r = (e) ? list_get(e->to, 0) : NULL;
|
|
|
|
if (r)
|
|
|
|
from = octstr_duplicate(r->rcpt);
|
|
|
|
else
|
|
|
|
from = octstr_imm("anon@anon");
|
2005-09-12 09:51:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (from)
|
|
|
|
_mms_fixup_address(from);
|
2005-09-07 10:10:41 +00:00
|
|
|
|
|
|
|
/* start with the easy one... */
|
2005-09-09 13:11:38 +00:00
|
|
|
if (octstr_case_compare(ctype, octstr_imm("application/vnd.wap.mms-message")) == 0)
|
2005-09-07 10:10:41 +00:00
|
|
|
m = mms_frombinary(data, from);
|
2005-09-09 13:11:38 +00:00
|
|
|
else if (octstr_case_compare(ctype, octstr_imm("application/smil")) == 0) {
|
2005-09-07 10:10:41 +00:00
|
|
|
xmlDocPtr smil;
|
|
|
|
xmlChar *buf = NULL;
|
|
|
|
int bsize = 0;
|
2005-09-09 13:11:38 +00:00
|
|
|
Dict *url_map = dict_create(97, (void (*)(void *))octstr_destroy);
|
|
|
|
|
|
|
|
/* This is the hard bit: Fetch each external reference in smil, add it to message! */
|
2005-09-07 10:10:41 +00:00
|
|
|
http_header_add(me->headers, "Content-Type", "multipart/related; "
|
|
|
|
"type=\"application/smil\"; start=\"<presentation>\"");
|
|
|
|
|
|
|
|
/* Parse the smil as XML. */
|
|
|
|
smil = xmlParseMemory(octstr_get_cstr(data), octstr_len(data));
|
|
|
|
if (!smil || !smil->xmlChildrenNode) {
|
|
|
|
*err = octstr_format("MMSBox: Error parsing SMIL response from service[%s], "
|
|
|
|
" msgid %s!", octstr_get_cstr(svc_name),
|
|
|
|
(e && e->msgId) ? octstr_get_cstr(e->msgId) : "(none)");
|
2005-09-09 13:11:38 +00:00
|
|
|
dict_destroy(url_map);
|
2005-09-07 10:10:41 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2006-01-23 07:11:33 +00:00
|
|
|
add_msg_parts(me, smil->xmlChildrenNode, base_url, turl, type, svc_name, url_map);
|
2005-09-07 10:10:41 +00:00
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
dict_destroy(url_map);
|
2005-09-07 10:10:41 +00:00
|
|
|
/* SMIL has been modified, convert it to text, put it in. */
|
|
|
|
xmlDocDumpFormatMemory(smil, &buf, &bsize, 1);
|
|
|
|
xmlFreeDoc(smil);
|
|
|
|
if (buf) {
|
|
|
|
MIMEEntity *sm = mime_entity_create();
|
|
|
|
|
|
|
|
http_header_add(sm->headers, "Content-Type", "application/smil");
|
|
|
|
http_header_add(sm->headers, "Content-ID", "<presentation>");
|
|
|
|
sm->body = octstr_create_from_data((char *)buf, bsize);
|
|
|
|
list_append(me->multiparts, sm);
|
|
|
|
me->start = sm;
|
|
|
|
xmlFree(buf);
|
|
|
|
} else {
|
|
|
|
*err = octstr_format("MMSBox: Error writing converted SMIL "
|
|
|
|
"for response from service[%s], "
|
|
|
|
" msgid %s!",
|
|
|
|
octstr_get_cstr(svc_name),
|
|
|
|
(e && e->msgId) ? octstr_get_cstr(e->msgId) : "(none)");
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
} else { /* all others, make the message as-is and hope for the best! */
|
2006-04-12 06:52:54 +00:00
|
|
|
http_header_add(me->headers, "Content-Type", octstr_get_cstr(ctype));
|
2005-09-07 10:10:41 +00:00
|
|
|
me->body = octstr_duplicate(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get headers needed, if we are allowed to do so. */
|
|
|
|
if (accept_x_headers && reply_headers) {
|
|
|
|
Octstr *x = NULL;
|
|
|
|
List *l = NULL;
|
|
|
|
subject = http_header_value(reply_headers, octstr_imm("X-Mbuni-Subject"));
|
|
|
|
|
|
|
|
if ((x = http_header_value(reply_headers, octstr_imm("X-Mbuni-Expiry"))) != NULL)
|
|
|
|
expiryt = date_parse_http(x);
|
|
|
|
|
|
|
|
if ((l = http_header_find_all(reply_headers, "X-Mbuni-To")) != NULL) {
|
|
|
|
int i, n;
|
|
|
|
for (i = 0, n = list_len(l); i<n; i++) {
|
|
|
|
Octstr *h = NULL, *v = NULL;
|
2005-09-15 07:57:56 +00:00
|
|
|
List *hv = NULL;
|
|
|
|
int j;
|
2005-09-07 10:10:41 +00:00
|
|
|
http_header_get(l, i, &h, &v);
|
|
|
|
|
2005-09-15 07:57:56 +00:00
|
|
|
hv = http_header_split_value(v);
|
2005-09-12 09:51:31 +00:00
|
|
|
|
2005-09-15 07:57:56 +00:00
|
|
|
for (j = 0; j < list_len(hv); j++) {
|
|
|
|
Octstr *v = list_get(hv, j);
|
|
|
|
/* Fix the address. */
|
|
|
|
_mms_fixup_address(v);
|
|
|
|
list_append(xto, v);
|
|
|
|
}
|
|
|
|
octstr_destroy(v);
|
2005-09-07 10:10:41 +00:00
|
|
|
octstr_destroy(h);
|
2005-09-15 07:57:56 +00:00
|
|
|
list_destroy(hv, NULL); /* Don't kill strings since we added them to xto above! */
|
2005-09-07 10:10:41 +00:00
|
|
|
}
|
|
|
|
http_destroy_headers(l);
|
|
|
|
}
|
|
|
|
dlr_url = http_header_value(reply_headers, octstr_imm("X-Mbuni-DLR-Url"));
|
|
|
|
rr_url = http_header_value(reply_headers, octstr_imm("X-Mbuni-RR-Url"));
|
|
|
|
|
|
|
|
mmc = http_header_value(reply_headers, octstr_imm("X-Mbuni-MMSC"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (list_len(xto) == 0 && e && e->from)
|
|
|
|
list_append(xto, octstr_duplicate(e->from));
|
|
|
|
|
|
|
|
if (!subject && e && e->subject)
|
|
|
|
subject = octstr_duplicate(e->subject);
|
|
|
|
|
|
|
|
if (!mmc && e)
|
|
|
|
mmc = e->fromproxy;
|
|
|
|
|
|
|
|
/* Add some nice headers. */
|
|
|
|
http_header_add(me->headers, "From", octstr_get_cstr(from));
|
|
|
|
|
|
|
|
for (i = 0, n = list_len(xto); i < n; i++) {
|
2005-09-09 13:11:38 +00:00
|
|
|
Octstr *v;
|
|
|
|
v = list_get(xto, i);
|
2005-09-07 10:10:41 +00:00
|
|
|
http_header_add(me->headers, "To", octstr_get_cstr(v));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dlr_url)
|
|
|
|
http_header_add(me->headers, "X-Mms-Delivery-Report", "Yes");
|
|
|
|
if (rr_url)
|
|
|
|
http_header_add(me->headers, "X-Mms-Read-Report", "Yes");
|
|
|
|
if (subject)
|
|
|
|
http_header_add(me->headers, "Subject", octstr_get_cstr(subject));
|
|
|
|
if (expiryt > 0) {
|
|
|
|
Octstr *x = date_format_http(expiryt);
|
|
|
|
http_header_add(me->headers, "X-Mms-Expiry", octstr_get_cstr(x));
|
|
|
|
octstr_destroy(x);
|
|
|
|
}
|
|
|
|
|
2005-09-09 13:11:38 +00:00
|
|
|
if (me && !m) /* Set m if it hasn't been set yet. */
|
2005-09-07 10:10:41 +00:00
|
|
|
m = mms_frommime(me);
|
|
|
|
if (!m) {
|
|
|
|
*err = octstr_format("MMSBox: Failed to convert Mms Message from service %s!",
|
|
|
|
octstr_get_cstr(svc_name));
|
|
|
|
goto done;
|
|
|
|
}
|
2006-05-03 13:52:40 +00:00
|
|
|
|
|
|
|
if (passthro_headers && reply_headers) { /* if user wants passthro headers, get them and add them. */
|
|
|
|
int n = list_len(reply_headers);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
hdrs = http_create_empty_headers();
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
Octstr *h = NULL, *v = NULL;
|
|
|
|
int j;
|
|
|
|
http_header_get(reply_headers, i, &h, &v);
|
|
|
|
if (h == NULL || v == NULL)
|
|
|
|
goto loop;
|
|
|
|
|
|
|
|
/* Check for this header in
|
|
|
|
* pass thro list.
|
|
|
|
*/
|
|
|
|
for (j = 0; j < list_len(passthro_headers); j++)
|
|
|
|
if (octstr_case_compare(h, list_get(passthro_headers, j)) == 0) {
|
|
|
|
http_header_add(hdrs, octstr_get_cstr(h), octstr_get_cstr(v));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
loop:
|
|
|
|
if (h)
|
|
|
|
octstr_destroy(h);
|
|
|
|
if (v)
|
|
|
|
octstr_destroy(v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
/* Write to queue. */
|
|
|
|
x = mms_queue_add(from, xto, subject,
|
|
|
|
e ? e->fromproxy : NULL,
|
|
|
|
mmc,
|
|
|
|
time(NULL), expiryt, m, NULL,
|
|
|
|
NULL, svc_name,
|
|
|
|
dlr_url, rr_url,
|
2006-05-03 13:52:40 +00:00
|
|
|
hdrs,
|
2005-09-07 10:10:41 +00:00
|
|
|
(dlr_url != NULL),
|
|
|
|
octstr_get_cstr(outgoing_qdir),
|
|
|
|
octstr_imm(MM_NAME));
|
|
|
|
info(0, "MMSBox: Queued message from service [%s] to outgoing: %s",
|
|
|
|
octstr_get_cstr(svc_name), octstr_get_cstr(x));
|
|
|
|
octstr_destroy(x);
|
|
|
|
res = 0;
|
|
|
|
done:
|
|
|
|
|
|
|
|
if (dlr_url)
|
|
|
|
octstr_destroy(dlr_url);
|
|
|
|
|
|
|
|
if (rr_url)
|
|
|
|
octstr_destroy(rr_url);
|
|
|
|
|
|
|
|
if (from)
|
|
|
|
octstr_destroy(from);
|
|
|
|
if (subject)
|
|
|
|
octstr_destroy(subject);
|
|
|
|
if (me)
|
|
|
|
mime_entity_destroy(me);
|
|
|
|
if (m)
|
|
|
|
mms_destroy(m);
|
|
|
|
if (xto)
|
|
|
|
list_destroy(xto, (list_item_destructor_t *)octstr_destroy);
|
2006-05-03 13:52:40 +00:00
|
|
|
if (hdrs)
|
|
|
|
http_destroy_headers(hdrs);
|
2005-09-07 10:10:41 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static SendMmsUser *auth_user(Octstr *user, Octstr *pass)
|
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
SendMmsUser *u = NULL;
|
2005-09-12 09:51:31 +00:00
|
|
|
|
|
|
|
if (!user || !pass)
|
|
|
|
return NULL;
|
2005-09-07 10:10:41 +00:00
|
|
|
for (i = 0, n = list_len(sendmms_users); i < n; i++)
|
|
|
|
if ((u = list_get(sendmms_users, i)) != NULL &&
|
|
|
|
octstr_compare(u->user, user) == 0 &&
|
|
|
|
octstr_compare(u->pass, pass) == 0)
|
|
|
|
return u;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void sendmms_func(void *unused)
|
|
|
|
{
|
|
|
|
HTTPClient *client = NULL;
|
|
|
|
Octstr *ip = NULL, *url = NULL;
|
|
|
|
Octstr *body = NULL;
|
|
|
|
List *cgivars = NULL, *h = NULL;
|
|
|
|
|
|
|
|
while (!rstop &&
|
|
|
|
(client = http_accept_request(sendmms_port.port,
|
|
|
|
&ip, &url, &h, &body, &cgivars)) != NULL) {
|
|
|
|
SendMmsUser *u = NULL;
|
|
|
|
List *hh = http_create_empty_headers();
|
|
|
|
Octstr *username = http_cgi_variable(cgivars, "username");
|
|
|
|
Octstr *password = http_cgi_variable(cgivars, "password");
|
|
|
|
Octstr *err = NULL;
|
|
|
|
|
|
|
|
if ((u = auth_user(username, password)) != NULL &&
|
2005-09-23 04:28:32 +00:00
|
|
|
is_allowed_ip(sendmms_port.allow_ip, sendmms_port.deny_ip, ip)) {
|
2005-09-07 10:10:41 +00:00
|
|
|
Octstr *data, *ctype = NULL, *mmc, *to, *from, *dlr_url;
|
|
|
|
Octstr *rr_url, *subject = NULL;
|
|
|
|
List *lto = NULL, *rh = http_create_empty_headers();
|
2006-05-03 13:52:40 +00:00
|
|
|
Octstr *rb = NULL, *base_url;
|
2005-09-07 10:10:41 +00:00
|
|
|
int i, n, res = 0;
|
2006-04-12 06:52:54 +00:00
|
|
|
Octstr *vasid = http_cgi_variable(cgivars, "vasid");
|
2006-05-03 13:52:40 +00:00
|
|
|
|
|
|
|
if ((base_url = http_cgi_variable(cgivars, "base-url")) == NULL)
|
|
|
|
base_url = octstr_imm("http://localhost");
|
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
if ((data = http_cgi_variable(cgivars, "text")) != NULL) { /* text. */
|
|
|
|
Octstr *charset = http_cgi_variable(cgivars, "charset");
|
|
|
|
|
|
|
|
ctype = octstr_format("text/plain");
|
2005-09-12 09:51:31 +00:00
|
|
|
if (charset)
|
2005-09-07 10:10:41 +00:00
|
|
|
octstr_format_append(ctype, "; charset=%S", charset);
|
|
|
|
} else if ((data = http_cgi_variable(cgivars, "smil")) != NULL) /* smil. */
|
|
|
|
ctype = octstr_imm("application/smil");
|
2006-05-03 13:52:40 +00:00
|
|
|
else if (body) { /* if all above fails, use send-mms msg body if any. */
|
|
|
|
data = octstr_duplicate(body);
|
|
|
|
ctype = http_header_value(h, octstr_imm("Content-Type"));
|
|
|
|
} else
|
2005-09-07 10:10:41 +00:00
|
|
|
rb = octstr_imm("Missing content");
|
2005-09-12 09:51:31 +00:00
|
|
|
|
|
|
|
dlr_url = http_cgi_variable(cgivars, "dlr-url");
|
|
|
|
rr_url = http_cgi_variable(cgivars, "rr-url");
|
2005-09-07 10:10:41 +00:00
|
|
|
mmc = http_cgi_variable(cgivars, "mmsc");
|
|
|
|
subject = http_cgi_variable(cgivars, "subject");
|
|
|
|
|
|
|
|
if ((to = http_cgi_variable(cgivars, "to")) == NULL)
|
|
|
|
rb = octstr_imm("Missing recipient!");
|
|
|
|
else
|
|
|
|
lto = octstr_split_words(to);
|
|
|
|
|
|
|
|
/* Build the fake reply headers. */
|
|
|
|
if (ctype)
|
|
|
|
http_header_add(rh, "Content-Type", octstr_get_cstr(ctype));
|
|
|
|
|
2005-09-12 09:51:31 +00:00
|
|
|
if ((from = http_cgi_variable(cgivars, "from")) != NULL) {
|
|
|
|
from = octstr_duplicate(from);
|
|
|
|
_mms_fixup_address(from);
|
2005-09-07 10:10:41 +00:00
|
|
|
http_header_add(rh, "X-Mbuni-From", octstr_get_cstr(from));
|
|
|
|
octstr_destroy(from);
|
2005-09-12 09:51:31 +00:00
|
|
|
} else if (!u->faked_sender)
|
|
|
|
rb = octstr_imm("Missing Sender address");
|
2005-09-07 10:10:41 +00:00
|
|
|
|
|
|
|
if (lto) {
|
|
|
|
for (i = 0, n = list_len(lto); i < n; i++) {
|
|
|
|
Octstr *x = list_get(lto, i);
|
|
|
|
http_header_add(rh, "X-Mbuni-To", octstr_get_cstr(x));
|
|
|
|
}
|
|
|
|
list_destroy(lto, (list_item_destructor_t *)octstr_destroy);
|
|
|
|
}
|
2005-09-12 09:51:31 +00:00
|
|
|
if (dlr_url)
|
2005-09-07 10:10:41 +00:00
|
|
|
http_header_add(rh, "X-Mbuni-DLR-Url", octstr_get_cstr(dlr_url));
|
|
|
|
|
2005-09-12 09:51:31 +00:00
|
|
|
if (rr_url)
|
2005-09-07 10:10:41 +00:00
|
|
|
http_header_add(rh, "X-Mbuni-RR-Url", octstr_get_cstr(rr_url));
|
|
|
|
|
2005-09-12 09:51:31 +00:00
|
|
|
if (mmc)
|
2005-09-07 10:10:41 +00:00
|
|
|
http_header_add(rh, "X-Mbuni-MMSC", octstr_get_cstr(mmc));
|
|
|
|
|
2005-09-12 09:51:31 +00:00
|
|
|
if (subject)
|
2005-09-07 10:10:41 +00:00
|
|
|
http_header_add(rh, "X-Mbuni-Subject", octstr_get_cstr(subject));
|
2005-09-12 09:51:31 +00:00
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
/* Requests to make_and_queue below can block, but for now we don't care. */
|
2005-09-12 09:51:31 +00:00
|
|
|
if (ctype && data && !rb) { /* only send if no error. */
|
2005-09-07 10:10:41 +00:00
|
|
|
res = make_and_queue_msg(data, ctype, rh, base_url, URL_TYPE, NULL,
|
2006-04-12 06:52:54 +00:00
|
|
|
vasid ? vasid : octstr_imm("sendmms-user"),
|
|
|
|
u->faked_sender,
|
2006-05-03 13:52:40 +00:00
|
|
|
1, NULL, &err);
|
2005-09-07 10:10:41 +00:00
|
|
|
if (res < 0)
|
|
|
|
rb = octstr_imm("Error in message conversion");
|
|
|
|
} else if (!rb)
|
2006-05-03 13:52:40 +00:00
|
|
|
rb = octstr_imm("Failed to send message");
|
2005-09-12 09:51:31 +00:00
|
|
|
http_send_reply(client, HTTP_BAD_REQUEST, hh,
|
|
|
|
rb ? rb : octstr_imm("Sent"));
|
2005-09-07 10:10:41 +00:00
|
|
|
info(0, "MMSBox.mmssend: u=%s, %s",
|
|
|
|
u ? octstr_get_cstr(u->user) : "none",
|
|
|
|
(res == 0) ? "Sent" : "Not Sent");
|
2006-05-02 13:02:15 +00:00
|
|
|
|
|
|
|
if (rh)
|
|
|
|
http_destroy_headers(rh);
|
2005-09-07 10:10:41 +00:00
|
|
|
if (ctype)
|
|
|
|
octstr_destroy(ctype);
|
2006-05-02 13:02:15 +00:00
|
|
|
if (rb)
|
|
|
|
octstr_destroy(rb);
|
2005-09-07 10:10:41 +00:00
|
|
|
} else {
|
|
|
|
http_send_reply(client, HTTP_UNAUTHORIZED, hh,
|
|
|
|
octstr_imm("Authentication failed"));
|
|
|
|
err = octstr_format("MMSBox: SendMMS, Authentication failed, "
|
|
|
|
"username=%s, password=%s!",
|
|
|
|
username ? octstr_get_cstr(username) : "(null)",
|
|
|
|
password ? octstr_get_cstr(password) : "(null)");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
error(0, "%s", octstr_get_cstr(err));
|
|
|
|
octstr_destroy(err);
|
|
|
|
}
|
|
|
|
|
2005-09-12 09:51:31 +00:00
|
|
|
/* Free the ip and other stuff here. */
|
2005-09-07 10:10:41 +00:00
|
|
|
octstr_destroy(ip);
|
2006-05-02 13:02:15 +00:00
|
|
|
if (body)
|
|
|
|
octstr_destroy(body);
|
2005-09-12 09:51:31 +00:00
|
|
|
if (url)
|
|
|
|
octstr_destroy(url);
|
|
|
|
if (cgivars)
|
|
|
|
http_destroy_cgiargs(cgivars);
|
|
|
|
if (h)
|
|
|
|
http_destroy_headers(h);
|
2006-05-02 13:02:15 +00:00
|
|
|
if (hh)
|
|
|
|
http_destroy_headers(hh);
|
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|