2005-03-23 05:55:16 +00:00
|
|
|
/*
|
|
|
|
* Mbuni - Open Source MMS Gateway
|
|
|
|
*
|
|
|
|
* Misc. functions
|
|
|
|
*
|
|
|
|
* 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)
|
|
|
|
*/
|
2005-03-19 06:46:24 +00:00
|
|
|
#include <sys/file.h>
|
2005-03-10 08:01:02 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <dlfcn.h>
|
2006-05-06 14:29:14 +00:00
|
|
|
#include <strings.h>
|
2005-03-19 06:46:24 +00:00
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
#include "mms_util.h"
|
2005-04-19 09:11:43 +00:00
|
|
|
#include "mms_queue.h"
|
2005-03-10 08:01:02 +00:00
|
|
|
#include "mms_uaprof.h"
|
|
|
|
|
|
|
|
|
2006-02-17 11:48:33 +00:00
|
|
|
Octstr *_mms_cfg_getx(mCfgGrp *grp, Octstr *item)
|
2005-09-02 11:41:28 +00:00
|
|
|
{
|
2006-02-17 11:48:33 +00:00
|
|
|
Octstr *v = mms_cfg_get(grp, item);
|
2005-09-02 11:41:28 +00:00
|
|
|
|
|
|
|
return v ? v : octstr_create("");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-02-17 11:48:33 +00:00
|
|
|
int mms_load_core_settings(mCfgGrp *cgrp)
|
2005-09-02 11:41:28 +00:00
|
|
|
{
|
|
|
|
Octstr *log, *alog;
|
|
|
|
Octstr *http_proxy_host;
|
|
|
|
long loglevel;
|
|
|
|
|
2006-03-10 05:38:29 +00:00
|
|
|
if (cgrp == NULL)
|
|
|
|
panic(0,"Missing required group `core' in config file!");
|
|
|
|
|
2005-09-02 11:41:28 +00:00
|
|
|
/* Set the log file. */
|
2006-02-17 11:48:33 +00:00
|
|
|
log = mms_cfg_get(cgrp, octstr_imm("log-file"));
|
2005-09-02 11:41:28 +00:00
|
|
|
if (log != NULL) {
|
2006-02-17 11:48:33 +00:00
|
|
|
if (mms_cfg_get_int(cgrp, octstr_imm("log-level"), &loglevel) == -1)
|
2005-09-02 11:41:28 +00:00
|
|
|
loglevel = 0;
|
|
|
|
log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL);
|
|
|
|
octstr_destroy(log);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get access log and open it. */
|
2006-02-17 11:48:33 +00:00
|
|
|
alog = mms_cfg_get(cgrp, octstr_imm("access-log"));
|
2005-09-02 11:41:28 +00:00
|
|
|
if (alog) {
|
|
|
|
alog_open(octstr_get_cstr(alog), 1, 1);
|
|
|
|
octstr_destroy(alog);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* look for http proxy. If set, use it. */
|
2006-02-17 11:48:33 +00:00
|
|
|
if ((http_proxy_host = mms_cfg_get(cgrp, octstr_imm("http-proxy-host"))) != NULL) {
|
2005-09-02 11:41:28 +00:00
|
|
|
|
2006-02-17 11:48:33 +00:00
|
|
|
Octstr *username = mms_cfg_get(cgrp,
|
2005-09-02 11:41:28 +00:00
|
|
|
octstr_imm("http-proxy-username"));
|
2006-02-17 11:48:33 +00:00
|
|
|
Octstr *password = mms_cfg_get(cgrp,
|
2005-09-02 11:41:28 +00:00
|
|
|
octstr_imm("http-proxy-password"));
|
2006-02-17 11:48:33 +00:00
|
|
|
List *exceptions = mms_cfg_get_list(cgrp,
|
2005-09-02 11:41:28 +00:00
|
|
|
octstr_imm("http-proxy-exceptions"));
|
2006-10-12 15:21:46 +00:00
|
|
|
Octstr *except_regex = mms_cfg_get(cgrp,
|
|
|
|
octstr_imm("http-proxy-exceptions-regex"));
|
2005-09-02 11:41:28 +00:00
|
|
|
long http_proxy_port = -1;
|
|
|
|
|
2006-02-17 11:48:33 +00:00
|
|
|
mms_cfg_get_int(cgrp, octstr_imm("http-proxy-port"), &http_proxy_port);
|
2005-09-02 11:41:28 +00:00
|
|
|
|
|
|
|
if (http_proxy_port > 0)
|
|
|
|
http_use_proxy(http_proxy_host, http_proxy_port,
|
2006-10-12 15:21:46 +00:00
|
|
|
exceptions, username, password, except_regex);
|
2005-09-02 11:41:28 +00:00
|
|
|
octstr_destroy(http_proxy_host);
|
|
|
|
octstr_destroy(username);
|
|
|
|
octstr_destroy(password);
|
2006-10-12 15:21:46 +00:00
|
|
|
octstr_destroy(except_regex);
|
|
|
|
gwlist_destroy(exceptions, octstr_destroy_item);
|
2005-09-02 11:41:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_LIBSSL
|
2006-02-17 11:48:33 +00:00
|
|
|
/* We expect that gwlib_init() has been called already, so only need
|
|
|
|
* to setup cert files.
|
|
|
|
* -- adapted from gwlib/conn.c
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
Octstr *ssl_client_certkey_file = NULL;
|
|
|
|
Octstr *ssl_server_cert_file = NULL;
|
|
|
|
Octstr *ssl_server_key_file = NULL;
|
|
|
|
Octstr *ssl_trusted_ca_file = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* check if SSL is desired for HTTP servers and then
|
|
|
|
* load SSL client and SSL server public certificates
|
|
|
|
* and private keys
|
|
|
|
*/
|
|
|
|
ssl_client_certkey_file = mms_cfg_get(cgrp, octstr_imm("ssl-client-certkey-file"));
|
|
|
|
if (ssl_client_certkey_file != NULL)
|
|
|
|
use_global_client_certkey_file(ssl_client_certkey_file);
|
|
|
|
|
|
|
|
ssl_server_cert_file = mms_cfg_get(cgrp, octstr_imm("ssl-server-cert-file"));
|
|
|
|
ssl_server_key_file = mms_cfg_get(cgrp, octstr_imm("ssl-server-key-file"));
|
|
|
|
|
|
|
|
if (ssl_server_cert_file != NULL && ssl_server_key_file != NULL)
|
|
|
|
use_global_server_certkey_file(ssl_server_cert_file,
|
|
|
|
ssl_server_key_file);
|
|
|
|
|
|
|
|
ssl_trusted_ca_file = mms_cfg_get(cgrp, octstr_imm("ssl-trusted-ca-file"));
|
|
|
|
|
|
|
|
use_global_trusted_ca_file(ssl_trusted_ca_file);
|
|
|
|
|
|
|
|
octstr_destroy(ssl_client_certkey_file);
|
|
|
|
octstr_destroy(ssl_server_cert_file);
|
|
|
|
octstr_destroy(ssl_server_key_file);
|
|
|
|
octstr_destroy(ssl_trusted_ca_file);
|
|
|
|
}
|
2005-09-02 11:41:28 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
Octstr *mms_maketransid(char *qf, Octstr *mmscname)
|
|
|
|
{
|
2005-03-21 16:11:51 +00:00
|
|
|
Octstr *res;
|
2005-11-06 08:56:13 +00:00
|
|
|
Octstr *x, *y = NULL;
|
2005-03-21 16:11:51 +00:00
|
|
|
static int ct;
|
|
|
|
|
|
|
|
if (!qf)
|
|
|
|
x = octstr_format("msg.%ld.x%d.%d.%d",
|
2006-05-29 06:30:39 +00:00
|
|
|
(long)time(NULL) % 10000, (++ct % 1000), getpid()%100, random()%100);
|
2005-03-21 16:11:51 +00:00
|
|
|
else
|
|
|
|
x = octstr_create(qf);
|
2006-04-12 07:14:45 +00:00
|
|
|
|
|
|
|
res = octstr_format("%S@%S", mmscname, x);
|
2005-03-21 16:11:51 +00:00
|
|
|
|
|
|
|
octstr_destroy(x);
|
2005-11-06 08:56:13 +00:00
|
|
|
octstr_destroy(y);
|
2005-03-21 16:11:51 +00:00
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern Octstr *mms_getqf_fromtransid(Octstr *transid)
|
|
|
|
{
|
2006-01-07 05:03:13 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (transid == NULL)
|
|
|
|
return NULL;
|
|
|
|
i = octstr_search_char(transid, '@', 0);
|
2005-04-14 11:27:23 +00:00
|
|
|
|
2006-04-12 07:14:45 +00:00
|
|
|
return (i >= 0) ? octstr_copy(transid, i+1, octstr_len(transid)) : octstr_duplicate(transid);
|
2005-03-10 08:01:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Octstr *mms_isodate(time_t t)
|
|
|
|
{
|
|
|
|
Octstr *current_time;
|
|
|
|
struct tm now;
|
|
|
|
|
|
|
|
now = gw_gmtime(t);
|
|
|
|
current_time = octstr_format("%04d-%02d-%02dT%02d:%02d:%02dZ",
|
|
|
|
now.tm_year + 1900, now.tm_mon + 1,
|
|
|
|
now.tm_mday, now.tm_hour, now.tm_min,
|
|
|
|
now.tm_sec);
|
|
|
|
|
|
|
|
return current_time;
|
|
|
|
}
|
|
|
|
|
|
|
|
void mms_lib_init(void)
|
|
|
|
{
|
|
|
|
gwlib_init();
|
|
|
|
mms_strings_init();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2006-01-11 05:29:21 +00:00
|
|
|
void mms_lib_shutdown(void)
|
|
|
|
{
|
|
|
|
mms_strings_shutdown();
|
|
|
|
gwlib_shutdown();
|
|
|
|
}
|
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
static void strip_quotes(Octstr *s)
|
|
|
|
{
|
|
|
|
int l = s ? octstr_len(s) : 0;
|
|
|
|
|
|
|
|
if (l == 0)
|
|
|
|
return;
|
|
|
|
if (octstr_get_char(s, 0) == '"') {
|
|
|
|
octstr_delete(s, 0, 1);
|
|
|
|
l--;
|
|
|
|
}
|
|
|
|
if (octstr_get_char(s, l-1) == '"')
|
|
|
|
octstr_delete(s, l-1, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
List *get_value_parameters(Octstr *params)
|
|
|
|
{
|
|
|
|
int i,n, k = 0;
|
|
|
|
List *h = http_create_empty_headers();
|
|
|
|
Octstr *xparams = octstr_duplicate(params);
|
|
|
|
|
|
|
|
octstr_format_append(xparams, ";"); /* So parsing is easier. (aka cheap hack) */
|
|
|
|
|
|
|
|
for (i = 0, n = octstr_len(xparams); i < n; i++) {
|
|
|
|
int c = octstr_get_char(xparams, i);
|
|
|
|
|
|
|
|
if (c == ';') {
|
|
|
|
int j = octstr_search_char(xparams, '=', k);
|
|
|
|
Octstr *name, *value;
|
|
|
|
if (j > 0 && j < i) {
|
|
|
|
name = octstr_copy(xparams, k, j - k);
|
|
|
|
value = octstr_copy(xparams, j+1,i-j-1);
|
|
|
|
octstr_strip_blanks(name);
|
|
|
|
octstr_strip_blanks(value);
|
|
|
|
strip_quotes(value);
|
|
|
|
if (octstr_len(name) > 0)
|
|
|
|
http_header_add(h,
|
|
|
|
octstr_get_cstr(name),
|
|
|
|
octstr_get_cstr(value));
|
|
|
|
octstr_destroy(name);
|
|
|
|
octstr_destroy(value);
|
|
|
|
}
|
|
|
|
k = i + 1;
|
|
|
|
} else if (c == '"')
|
|
|
|
i += http_header_quoted_string_len(xparams, i) - 1;
|
|
|
|
}
|
|
|
|
octstr_destroy(xparams);
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
2005-03-16 05:04:03 +00:00
|
|
|
int split_header_value(Octstr *value, Octstr **base_value, Octstr **params)
|
2005-03-10 08:01:02 +00:00
|
|
|
{
|
|
|
|
|
2005-03-16 05:04:03 +00:00
|
|
|
int i, n;
|
|
|
|
for (i = 0, n = octstr_len(value); i < n; i++) {
|
|
|
|
int c = octstr_get_char(value, i);
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
if (c == ';')
|
|
|
|
break;
|
|
|
|
else if (c == '"')
|
2005-03-16 05:04:03 +00:00
|
|
|
i += http_header_quoted_string_len(value, i) - 1;
|
2005-03-10 08:01:02 +00:00
|
|
|
}
|
2005-03-16 05:04:03 +00:00
|
|
|
|
|
|
|
*base_value = octstr_duplicate(value);
|
2005-03-10 08:01:02 +00:00
|
|
|
if (i < n) {
|
2005-03-16 05:04:03 +00:00
|
|
|
*params = octstr_copy(value, i+1, octstr_len(value));
|
|
|
|
octstr_delete(*base_value, i, octstr_len(*base_value));
|
2005-03-10 08:01:02 +00:00
|
|
|
} else
|
|
|
|
*params = octstr_create("");
|
2005-03-16 05:04:03 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_content_type(List *hdrs, Octstr **type, Octstr **params)
|
|
|
|
{
|
2005-03-10 08:01:02 +00:00
|
|
|
|
2005-03-16 05:04:03 +00:00
|
|
|
Octstr *v;
|
|
|
|
|
|
|
|
v = http_header_find_first(hdrs, "Content-Type");
|
|
|
|
*params =NULL;
|
|
|
|
|
|
|
|
if (!v) {
|
|
|
|
*type = octstr_create("application/octet-stream");
|
|
|
|
*params = octstr_create("");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
split_header_value(v, type, params);
|
|
|
|
|
|
|
|
octstr_destroy(v);
|
2005-03-10 08:01:02 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int needs_quotes(Octstr *s)
|
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
if (!s)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for (i = 0, n = octstr_len(s); i<n; i++) {
|
|
|
|
int ch = octstr_get_char(s,i);
|
2006-10-12 15:21:46 +00:00
|
|
|
if (isspace(ch) || ch == '=' || ch == ';' || ch == '<' || ch == '>')
|
2005-03-10 08:01:02 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Octstr *make_value_parameters(List *params)
|
|
|
|
{
|
|
|
|
Octstr *s = octstr_create(""), *name, *value;
|
|
|
|
int i, n;
|
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
for (i = 0, n = params ? gwlist_len(params) : 0; i<n; i++) {
|
2005-03-10 08:01:02 +00:00
|
|
|
int space;
|
|
|
|
http_header_get(params, i, &name, &value);
|
|
|
|
space = needs_quotes(value);
|
|
|
|
octstr_format_append(s, "%s%S=%s%S%s",
|
|
|
|
(i==0) ? "" : "; ",
|
|
|
|
name,
|
|
|
|
(space) ? "\"" : "",
|
|
|
|
value,
|
|
|
|
(space) ? "\"" : "");
|
|
|
|
octstr_destroy(name);
|
|
|
|
octstr_destroy(value);
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Take each header with a comma separated set of values (for To,Cc,Bcc),
|
|
|
|
* re-create as a series of header/value pairs.
|
|
|
|
* Remove all non-conformant headers (e.g. old unix-style from
|
|
|
|
*/
|
|
|
|
void unpack_mimeheaders(MIMEEntity *mm)
|
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
List *h = http_create_empty_headers();
|
2006-10-12 15:21:46 +00:00
|
|
|
List *headers = _x_mime_entity_headers(mm);
|
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
for (i = 0, n = gwlist_len(headers); i<n; i++) {
|
2005-03-10 08:01:02 +00:00
|
|
|
Octstr *header = NULL, *value = NULL;
|
|
|
|
List *l = NULL;
|
|
|
|
int j, m;
|
|
|
|
int skip;
|
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
http_header_get(headers, i, &header, &value);
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
if (header == NULL ||
|
|
|
|
octstr_str_compare(header, "X-Unknown") == 0 ||
|
|
|
|
octstr_search_chars(header, octstr_imm(" \n\t"), 0) >= 0) /* Don't allow space in the name. */
|
|
|
|
goto loop;
|
|
|
|
|
|
|
|
if (octstr_case_compare(header, octstr_imm("Cc")) == 0 ||
|
|
|
|
octstr_case_compare(header, octstr_imm("To")) == 0 ||
|
|
|
|
octstr_case_compare(header, octstr_imm("Bcc")) == 0)
|
|
|
|
skip = 0;
|
|
|
|
else
|
|
|
|
skip = 1;
|
|
|
|
/* XXX This may not be safe. Need to skip over quotes. */
|
|
|
|
if (!skip && octstr_search_char(value, ',', 0) > 0 &&
|
|
|
|
(l = http_header_split_value(value)) != NULL &&
|
2006-10-12 15:21:46 +00:00
|
|
|
gwlist_len(l) > 1)
|
|
|
|
for (j = 0, m = gwlist_len(l); j<m; j++)
|
2005-03-10 08:01:02 +00:00
|
|
|
http_header_add(h, octstr_get_cstr(header),
|
2006-10-12 15:21:46 +00:00
|
|
|
octstr_get_cstr(gwlist_get(l, j)));
|
2005-03-10 08:01:02 +00:00
|
|
|
else
|
|
|
|
http_header_add(h, octstr_get_cstr(header),
|
|
|
|
octstr_get_cstr(value));
|
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
if (l) gwlist_destroy(l, (gwlist_item_destructor_t *)octstr_destroy);
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
loop:
|
|
|
|
if (header) octstr_destroy(header);
|
|
|
|
if (value) octstr_destroy(value);
|
|
|
|
}
|
2006-10-12 15:21:46 +00:00
|
|
|
|
|
|
|
mime_replace_headers(mm, h);
|
|
|
|
http_destroy_headers(headers);
|
|
|
|
http_destroy_headers(h);
|
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Undo base64 content coding for mime entities that need it. */
|
|
|
|
void unbase64_mimeparts(MIMEEntity *m)
|
|
|
|
{
|
|
|
|
int i, n;
|
2006-10-12 15:21:46 +00:00
|
|
|
|
|
|
|
if ((n = mime_entity_num_parts(m)) > 0)
|
|
|
|
for (i = 0; i<n; i++) {
|
|
|
|
MIMEEntity *x = mime_entity_get_part(m, i);
|
|
|
|
unbase64_mimeparts(x);
|
|
|
|
mime_entity_replace_part(m, i, x);
|
|
|
|
mime_entity_destroy(x);
|
|
|
|
}
|
2005-03-10 08:01:02 +00:00
|
|
|
else { /* A non-multipart message .*/
|
2006-10-12 15:21:46 +00:00
|
|
|
List *headers = _x_mime_entity_headers(m);
|
|
|
|
Octstr *ctype = http_header_value(headers, octstr_imm("Content-Type"));
|
|
|
|
Octstr *te = http_header_value(headers, octstr_imm("Content-Transfer-Encoding"));
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
if (ctype && te &&
|
2006-10-12 15:21:46 +00:00
|
|
|
octstr_case_compare(te,octstr_imm("base64")) == 0) {
|
|
|
|
Octstr *s = mime_entity_body(m);
|
|
|
|
octstr_base64_to_binary(s);
|
|
|
|
mime_entity_set_body(m, s);
|
|
|
|
octstr_destroy(s);
|
|
|
|
}
|
|
|
|
http_header_remove_all(headers, "Content-Transfer-Encoding"); /* Remove it in all cases (?).*/
|
|
|
|
mime_replace_headers(m, headers);
|
2005-03-16 06:37:25 +00:00
|
|
|
|
|
|
|
/* XXX may be we should deal with other transfer encodings here as well... */
|
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
if (ctype)
|
|
|
|
octstr_destroy(ctype);
|
|
|
|
if (te)
|
|
|
|
octstr_destroy(te);
|
2006-10-12 15:21:46 +00:00
|
|
|
http_destroy_headers(headers);
|
2005-03-10 08:01:02 +00:00
|
|
|
}
|
|
|
|
}
|
2005-07-01 06:13:59 +00:00
|
|
|
|
|
|
|
int _mms_gw_isprint(int c)
|
2005-03-10 08:01:02 +00:00
|
|
|
{
|
|
|
|
return isprint(c) || isspace(c);
|
|
|
|
}
|
2005-07-01 06:13:59 +00:00
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
/* Change content coding for mime entities that need it. */
|
|
|
|
void base64_mimeparts(MIMEEntity *m)
|
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
if ((n = mime_entity_num_parts(m)) > 0)
|
|
|
|
for (i = 0; i<n; i++) {
|
|
|
|
MIMEEntity *x = mime_entity_get_part(m, i);
|
|
|
|
base64_mimeparts(x);
|
|
|
|
mime_entity_replace_part(m, i, x);
|
|
|
|
mime_entity_destroy(x);
|
|
|
|
}
|
2005-03-10 08:01:02 +00:00
|
|
|
else { /* A non-multipart message .*/
|
2006-10-12 15:21:46 +00:00
|
|
|
List *headers = _x_mime_entity_headers(m);
|
|
|
|
Octstr *ctype = http_header_value(headers, octstr_imm("Content-Type"));
|
|
|
|
Octstr *te = http_header_value(headers, octstr_imm("Content-Transfer-Encoding"));
|
|
|
|
Octstr *body = mime_entity_body(m);
|
|
|
|
if (ctype && !te &&
|
|
|
|
(body && octstr_check_range(body, 0, octstr_len(body), _mms_gw_isprint) == 0)) {
|
|
|
|
octstr_binary_to_base64(body);
|
|
|
|
|
|
|
|
http_header_add(headers, "Content-Transfer-Encoding", "base64");
|
|
|
|
mime_entity_set_body(m, body);
|
|
|
|
mime_replace_headers(m, headers);
|
2005-03-10 08:01:02 +00:00
|
|
|
}
|
|
|
|
if (ctype)
|
|
|
|
octstr_destroy(ctype);
|
|
|
|
if (te)
|
|
|
|
octstr_destroy(te);
|
2006-10-12 15:21:46 +00:00
|
|
|
octstr_destroy(body);
|
|
|
|
http_destroy_headers(headers);
|
2005-03-10 08:01:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void addmmscname(Octstr *s, Octstr *myhostname)
|
|
|
|
{
|
|
|
|
int j;
|
|
|
|
int len = octstr_len(s);
|
|
|
|
|
|
|
|
if (octstr_search_char(s, '@', 0) >= 0)
|
|
|
|
return; /* Nothing to do. */
|
|
|
|
|
|
|
|
j = octstr_case_search(s, octstr_imm("/TYPE=PLMN"), 0);
|
|
|
|
if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == len) { /* A proper number. */
|
|
|
|
octstr_delete(s, j, -1 + sizeof "/TYPE=PLMN"); /* XXX We strip off /TYPE=PLMN, should we ? */
|
|
|
|
octstr_format_append(s, "@%S", myhostname);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
static int send2email(Octstr *to, Octstr *from, Octstr *subject,
|
|
|
|
Octstr *msgid,
|
|
|
|
MIMEEntity *m, int append_hostname, Octstr **error,
|
|
|
|
char *sendmail_cmd, Octstr *myhostname)
|
|
|
|
{
|
|
|
|
Octstr *s;
|
|
|
|
FILE *f;
|
|
|
|
int ret = MMS_SEND_OK, i;
|
2006-10-12 15:21:46 +00:00
|
|
|
Octstr *cmd = octstr_create("");
|
|
|
|
List *headers = mime_entity_headers(m); /* we don't want the mime version header removed. */
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
if (append_hostname) { /* Add our hostname to all phone numbers. */
|
|
|
|
int i, n;
|
|
|
|
List *l = http_create_empty_headers();
|
2006-10-12 15:21:46 +00:00
|
|
|
Octstr *xfrom = http_header_value(headers, octstr_imm("From"));
|
|
|
|
List *lto = http_header_find_all(headers, "To");
|
|
|
|
List *lcc = http_header_find_all(headers, "Cc");
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
if (xfrom) {
|
|
|
|
addmmscname(xfrom, myhostname);
|
|
|
|
http_header_add(l, "From", octstr_get_cstr(xfrom));
|
|
|
|
octstr_destroy(xfrom);
|
|
|
|
}
|
2006-10-12 15:21:46 +00:00
|
|
|
http_header_remove_all(headers, "From");
|
2005-03-10 08:01:02 +00:00
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
for (i = 0, n = gwlist_len(lto); i < n; i++) {
|
2005-03-10 08:01:02 +00:00
|
|
|
Octstr *name, *value;
|
|
|
|
|
|
|
|
http_header_get(lto, i, &name, &value);
|
|
|
|
|
|
|
|
if (!value || !name ||
|
|
|
|
octstr_case_compare(name, octstr_imm("To")) != 0)
|
|
|
|
goto loop;
|
|
|
|
|
|
|
|
addmmscname(value, myhostname);
|
|
|
|
http_header_add(l, "To", octstr_get_cstr(value));
|
|
|
|
loop:
|
|
|
|
if (value) octstr_destroy(value);
|
|
|
|
if (name) octstr_destroy(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
http_destroy_headers(lto);
|
2006-10-12 15:21:46 +00:00
|
|
|
http_header_remove_all(headers, "To");
|
2005-03-10 08:01:02 +00:00
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
for (i = 0, n = gwlist_len(lcc); i < n; i++) {
|
2005-03-10 08:01:02 +00:00
|
|
|
Octstr *name, *value;
|
|
|
|
|
|
|
|
http_header_get(lcc, i, &name, &value);
|
|
|
|
|
|
|
|
if (!value || !name ||
|
|
|
|
octstr_case_compare(name, octstr_imm("Cc")) != 0)
|
|
|
|
goto loop2;
|
|
|
|
|
|
|
|
addmmscname(value, myhostname);
|
|
|
|
http_header_add(l, "Cc", octstr_get_cstr(value));
|
|
|
|
loop2:
|
|
|
|
if (value) octstr_destroy(value);
|
|
|
|
if (name) octstr_destroy(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
http_destroy_headers(lcc);
|
2006-10-12 15:21:46 +00:00
|
|
|
http_header_remove_all(headers, "Cc");
|
2005-03-10 08:01:02 +00:00
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
http_append_headers(headers, l); /* combine old with new. */
|
2005-03-10 08:01:02 +00:00
|
|
|
http_destroy_headers(l);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pack headers, get string rep of mime entity. */
|
2006-10-12 15:21:46 +00:00
|
|
|
http_header_pack(headers);
|
|
|
|
mime_replace_headers(m, headers);
|
2005-03-10 08:01:02 +00:00
|
|
|
s = mime_entity_to_octstr(m);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make the command: Transpose % formatting characters:
|
|
|
|
* f - from address
|
|
|
|
* t - recipient
|
|
|
|
* s - subject
|
|
|
|
* m - message id
|
|
|
|
*/
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
for (;;) {
|
2006-03-02 10:57:19 +00:00
|
|
|
Octstr *tmp;
|
2005-03-10 08:01:02 +00:00
|
|
|
while (sendmail_cmd[i]) {
|
|
|
|
char c = sendmail_cmd[i];
|
|
|
|
if (c == '%' && sendmail_cmd[i + 1])
|
|
|
|
break;
|
|
|
|
octstr_append_char(cmd, c);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
if (!sendmail_cmd[i])
|
|
|
|
break;
|
|
|
|
|
|
|
|
switch(sendmail_cmd[i+1]) {
|
|
|
|
case 't':
|
2006-03-02 10:57:19 +00:00
|
|
|
tmp = octstr_duplicate(to);
|
|
|
|
escape_shell_chars(tmp);
|
|
|
|
octstr_append(cmd, tmp);
|
|
|
|
octstr_destroy(tmp);
|
2005-03-10 08:01:02 +00:00
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
if (append_hostname) {
|
|
|
|
Octstr *xfrom = octstr_duplicate(from);
|
|
|
|
addmmscname(xfrom, myhostname);
|
2006-03-02 10:57:19 +00:00
|
|
|
escape_shell_chars(xfrom);
|
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
octstr_append(cmd, xfrom);
|
|
|
|
octstr_destroy(xfrom);
|
2006-03-02 10:57:19 +00:00
|
|
|
} else {
|
|
|
|
tmp = octstr_duplicate(from);
|
|
|
|
escape_shell_chars(tmp);
|
|
|
|
octstr_append(cmd, tmp);
|
|
|
|
octstr_destroy(tmp);
|
|
|
|
}
|
2005-03-10 08:01:02 +00:00
|
|
|
break;
|
|
|
|
case 's':
|
2006-03-02 10:57:19 +00:00
|
|
|
tmp = octstr_duplicate(subject);
|
|
|
|
escape_shell_chars(tmp);
|
2005-03-10 08:01:02 +00:00
|
|
|
octstr_append(cmd, subject);
|
2006-03-02 10:57:19 +00:00
|
|
|
octstr_destroy(tmp);
|
2005-03-10 08:01:02 +00:00
|
|
|
break;
|
|
|
|
case 'm':
|
2006-03-02 10:57:19 +00:00
|
|
|
tmp = octstr_duplicate(msgid);
|
|
|
|
escape_shell_chars(tmp);
|
2005-03-10 08:01:02 +00:00
|
|
|
octstr_append(cmd, msgid);
|
2006-03-02 10:57:19 +00:00
|
|
|
octstr_destroy(tmp);
|
2005-03-10 08:01:02 +00:00
|
|
|
break;
|
|
|
|
case '%':
|
|
|
|
octstr_format_append(cmd, "%%");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
octstr_format_append(cmd, "%%%c", sendmail_cmd[i+1]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
i += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
debug("mms.sendtoemail", 0, "preparing to execute %s to send to email: ", octstr_get_cstr(cmd));
|
|
|
|
|
|
|
|
if ((f = popen(octstr_get_cstr(cmd), "w")) == NULL) {
|
|
|
|
*error = octstr_format("popen failed for %S: %d: %s",
|
|
|
|
cmd, errno, strerror(errno));
|
|
|
|
ret = MMS_SEND_ERROR_TRANSIENT;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (octstr_print(f, s) < 0) {
|
|
|
|
*error = octstr_format("send email failed in octstr_print %d: %s",
|
|
|
|
errno, strerror(errno));
|
|
|
|
pclose(f);
|
|
|
|
ret = MMS_SEND_ERROR_TRANSIENT;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = pclose(f)) != 0) {
|
|
|
|
*error = octstr_format("Send email command returned non-zero %d: errno=%s",
|
|
|
|
ret, strerror(errno));
|
|
|
|
ret = MMS_SEND_ERROR_TRANSIENT;
|
|
|
|
} else
|
|
|
|
ret = MMS_SEND_OK;
|
|
|
|
|
|
|
|
done:
|
2006-10-12 15:21:46 +00:00
|
|
|
http_destroy_headers(headers);
|
2005-03-10 08:01:02 +00:00
|
|
|
octstr_destroy(cmd);
|
|
|
|
octstr_destroy(s);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Send this message to email recipient. */
|
|
|
|
int mms_sendtoemail(Octstr *from, Octstr *to,
|
|
|
|
Octstr *subject, Octstr *msgid,
|
|
|
|
MmsMsg *msg, int dlr, Octstr **error, char *sendmail_cmd,
|
|
|
|
Octstr *myhostname,
|
|
|
|
int trans_msg,
|
|
|
|
int trans_smil, char *txt, char *html,
|
|
|
|
int append_hostname)
|
|
|
|
{
|
|
|
|
|
|
|
|
MIMEEntity *m = NULL;
|
2006-10-12 15:21:46 +00:00
|
|
|
List *headers = NULL;
|
2005-03-10 08:01:02 +00:00
|
|
|
List *newhdrs = http_create_empty_headers();
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!to ||
|
|
|
|
octstr_search_char(to, '@', 0) < 0) {
|
|
|
|
*error = octstr_format("Invalid email address %S!", to);
|
|
|
|
return MMS_SEND_ERROR_FATAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!trans_msg)
|
2006-10-12 15:21:46 +00:00
|
|
|
m = mms_tomime(msg,0);
|
2005-03-10 08:01:02 +00:00
|
|
|
else
|
|
|
|
if ((ret = mms_format_special(msg, trans_smil, txt, html, &m)) < 0 ||
|
|
|
|
m == NULL) {
|
|
|
|
warning(0, "MMS: send2email failed to format message (msg=%s,ret=%d)",
|
|
|
|
m ? "OK" : "Not transformed",ret);
|
|
|
|
return -ret;
|
|
|
|
}
|
|
|
|
|
2005-07-01 05:54:35 +00:00
|
|
|
base64_mimeparts(m); /* make sure parts are base64 formatted. */
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
/* Before we send it, we insert some email friendly headers if they are missing. */
|
|
|
|
http_header_add(newhdrs, "Subject", subject ? octstr_get_cstr(subject) : "MMS Message");
|
|
|
|
http_header_add(newhdrs, "From", octstr_get_cstr(from));
|
|
|
|
http_header_add(newhdrs, "To", octstr_get_cstr(to));
|
|
|
|
http_header_add(newhdrs, "Message-ID", msgid ? octstr_get_cstr(msgid) : "");
|
2006-07-14 13:11:08 +00:00
|
|
|
|
|
|
|
http_header_add(newhdrs, "MIME-Version", "1.0");
|
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
headers = _x_mime_entity_headers(m);
|
|
|
|
http_header_combine(headers, newhdrs);
|
|
|
|
mime_replace_headers(m, headers);
|
|
|
|
|
|
|
|
http_destroy_headers(headers);
|
|
|
|
http_destroy_headers(newhdrs);
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
ret = send2email(to, from, subject, msgid, m, append_hostname, error, sendmail_cmd, myhostname);
|
|
|
|
mime_entity_destroy(m);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void mms_log2(char *logmsg, Octstr *from, Octstr *to,
|
|
|
|
int msize, Octstr *msgid,
|
|
|
|
Octstr *acct,
|
|
|
|
Octstr *viaproxy,
|
2005-03-21 16:11:51 +00:00
|
|
|
char *interface, Octstr *ua, Octstr *mmboxloc)
|
2005-03-10 08:01:02 +00:00
|
|
|
{
|
|
|
|
List *l;
|
|
|
|
if (to) {
|
2006-10-12 15:21:46 +00:00
|
|
|
l = gwlist_create();
|
|
|
|
gwlist_append(l, to);
|
2005-03-10 08:01:02 +00:00
|
|
|
} else
|
|
|
|
l = NULL;
|
|
|
|
|
2005-03-21 16:11:51 +00:00
|
|
|
mms_log(logmsg, from,l,msize,msgid,acct,viaproxy,interface,ua,mmboxloc);
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
if (l)
|
2006-10-12 15:21:46 +00:00
|
|
|
gwlist_destroy(l, NULL);
|
2005-03-10 08:01:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void mms_log(char *logmsg, Octstr *from, List *to,
|
|
|
|
int msize, Octstr *msgid,
|
|
|
|
Octstr *acct,
|
|
|
|
Octstr *viaproxy,
|
2005-03-21 16:11:51 +00:00
|
|
|
char *interface, Octstr *ua, Octstr *mmboxloc)
|
2005-03-10 08:01:02 +00:00
|
|
|
{
|
|
|
|
Octstr *xto = octstr_create("");
|
2006-10-12 15:21:46 +00:00
|
|
|
int i, n = to ? gwlist_len(to) : 0;
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
octstr_format_append(xto,
|
|
|
|
"%s%S",
|
|
|
|
(i == 0) ? "" : ", ",
|
2006-10-12 15:21:46 +00:00
|
|
|
gwlist_get(to,i));
|
2005-03-10 08:01:02 +00:00
|
|
|
|
2005-03-21 16:11:51 +00:00
|
|
|
alog("%s MMS [INT:%s] [ACT:%s] [MMSC:%s] [from:%s] [to:%s] [msgid:%s] [size=%d] [UA:%s] [MMBox:%s]",
|
2005-03-10 08:01:02 +00:00
|
|
|
logmsg, interface,
|
|
|
|
acct ? octstr_get_cstr(acct) : "",
|
|
|
|
viaproxy ? octstr_get_cstr(viaproxy) : "",
|
|
|
|
from ? octstr_get_cstr(from) : "",
|
|
|
|
octstr_get_cstr(xto),
|
|
|
|
msgid ? octstr_get_cstr(msgid) : "",
|
|
|
|
msize,
|
2005-03-21 16:11:51 +00:00
|
|
|
ua ? octstr_get_cstr(ua) : "",
|
|
|
|
mmboxloc ? octstr_get_cstr(mmboxloc) : "");
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
octstr_destroy(xto);
|
|
|
|
}
|
|
|
|
|
2005-03-19 06:46:24 +00:00
|
|
|
|
|
|
|
static int lockfile(int fd, int shouldblock)
|
|
|
|
{
|
|
|
|
int n, stop;
|
|
|
|
unsigned flg = shouldblock ? 0 : LOCK_NB;
|
|
|
|
|
|
|
|
do {
|
|
|
|
n = flock(fd, LOCK_EX|flg);
|
|
|
|
if (n < 0) {
|
|
|
|
if (errno == EINTR)
|
|
|
|
stop = 0;
|
|
|
|
else
|
|
|
|
stop = 1;
|
|
|
|
} else
|
|
|
|
stop = 1;
|
|
|
|
} while (!stop);
|
|
|
|
|
|
|
|
return (n == 0) ? 0 : errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_lock(int fd, char *fname)
|
|
|
|
{
|
|
|
|
struct stat fs = {0}, ds = {0};
|
|
|
|
|
|
|
|
/* You might grab a lock on a file, but the file
|
|
|
|
* might be changed just before you grabbed the lock. Detect that and fail..
|
|
|
|
*/
|
|
|
|
if (fstat(fd, &ds) < 0 ||
|
|
|
|
stat(fname, &fs) < 0 ||
|
|
|
|
|
|
|
|
ds.st_nlink != fs.st_nlink ||
|
|
|
|
memcmp(&ds.st_dev,&fs.st_dev, sizeof ds.st_dev) != 0 ||
|
|
|
|
memcmp(&ds.st_ino,&fs.st_ino, sizeof ds.st_ino) != 0 ||
|
|
|
|
ds.st_uid != fs.st_uid ||
|
|
|
|
ds.st_gid != fs.st_gid ||
|
|
|
|
ds.st_size != fs.st_size)
|
|
|
|
return -1;
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mm_lockfile(int fd, char *fname, int shouldblock)
|
|
|
|
{
|
|
|
|
int ret = lockfile(fd,shouldblock);
|
|
|
|
|
|
|
|
if (ret != 0 ||
|
|
|
|
(ret = check_lock(fd,fname)) != 0)
|
|
|
|
return ret;
|
|
|
|
return 0;
|
|
|
|
}
|
2005-04-14 11:27:23 +00:00
|
|
|
|
2005-09-07 10:10:41 +00:00
|
|
|
void mms_collect_envdata_from_msgheaders(List *mh, List **xto,
|
|
|
|
Octstr **subject,
|
|
|
|
Octstr **otransid, time_t *expiryt,
|
|
|
|
time_t *deliveryt, long default_msgexpiry)
|
|
|
|
{
|
|
|
|
|
|
|
|
Octstr *s;
|
|
|
|
List *l = http_header_find_all(mh, "To");
|
|
|
|
if (l) {
|
|
|
|
int i, n;
|
2006-10-12 15:21:46 +00:00
|
|
|
for (i = 0, n = gwlist_len(l); i<n; i++) {
|
2005-09-07 10:10:41 +00:00
|
|
|
Octstr *name, *value;
|
|
|
|
http_header_get(l, i, &name, &value);
|
2006-10-12 15:21:46 +00:00
|
|
|
gwlist_append(*xto, value);
|
2005-09-07 10:10:41 +00:00
|
|
|
octstr_destroy(name);
|
|
|
|
|
|
|
|
}
|
|
|
|
http_destroy_headers(l);
|
|
|
|
}
|
|
|
|
|
|
|
|
l = http_header_find_all(mh, "Cc");
|
|
|
|
if (l) {
|
|
|
|
int i, n;
|
2006-10-12 15:21:46 +00:00
|
|
|
for (i = 0, n = gwlist_len(l); i<n; i++) {
|
2005-09-07 10:10:41 +00:00
|
|
|
Octstr *name, *value;
|
|
|
|
http_header_get(l, i, &name, &value);
|
2006-10-12 15:21:46 +00:00
|
|
|
gwlist_append(*xto, value);
|
2005-09-07 10:10:41 +00:00
|
|
|
octstr_destroy(name);
|
|
|
|
|
|
|
|
}
|
|
|
|
http_destroy_headers(l);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
l = http_header_find_all(mh, "Bcc");
|
|
|
|
if (l) {
|
|
|
|
int i, n;
|
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
for (i = 0, n = gwlist_len(l); i<n; i++) {
|
2005-09-07 10:10:41 +00:00
|
|
|
Octstr *name, *value;
|
|
|
|
http_header_get(l, i, &name, &value);
|
2006-10-12 15:21:46 +00:00
|
|
|
gwlist_append(*xto, value);
|
2005-09-07 10:10:41 +00:00
|
|
|
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) + 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"));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long _mshash(char *s)
|
|
|
|
{
|
|
|
|
unsigned h = 0;
|
|
|
|
|
|
|
|
while (*s) {
|
|
|
|
unsigned int ch = tolower(*s);
|
|
|
|
s++;
|
|
|
|
h += ((unsigned)(ch) << 4) + 1249;
|
|
|
|
}
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
int isphonenum(Octstr *s)
|
|
|
|
{
|
|
|
|
int i = 0, n = octstr_len(s);
|
|
|
|
char *cs;
|
|
|
|
|
|
|
|
if (s && octstr_len(s) >= 1 &&
|
|
|
|
octstr_get_cstr(s)[0] == '+')
|
|
|
|
i++;
|
|
|
|
for ( cs = octstr_get_cstr(s); i<n; i++)
|
|
|
|
if (!gw_isdigit(cs[i]))
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Doesn't handle IP addresses. */
|
|
|
|
void _mms_fixup_address(Octstr *address)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
|
|
if (!address) return;
|
|
|
|
i = octstr_search_char(address, '@', 0);
|
|
|
|
if (i>0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
i = octstr_search(address, octstr_imm("/TYPE="), 0);
|
|
|
|
if (i > 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (isphonenum(address))
|
|
|
|
octstr_append(address, octstr_imm("/TYPE=PLMN"));
|
|
|
|
else
|
|
|
|
octstr_append(address, octstr_imm("@unknown"));
|
|
|
|
}
|
2006-02-28 10:36:36 +00:00
|
|
|
|
|
|
|
/* compare, reversed result! */
|
|
|
|
static int comp_fn(void *item, void *pattern)
|
|
|
|
{
|
|
|
|
return (octstr_case_compare(item, pattern) == 0) ? 1 : 0;
|
|
|
|
}
|
|
|
|
int is_allowed_host(Octstr *host, Octstr *host_list)
|
|
|
|
{
|
|
|
|
List *l;
|
|
|
|
int ret;
|
|
|
|
gw_assert(host_list);
|
|
|
|
gw_assert(host);
|
|
|
|
|
|
|
|
l = octstr_split(host_list, octstr_imm(";"));
|
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
ret = (gwlist_search(l, host, comp_fn) != NULL) ? 1 : 0;
|
2006-02-28 10:36:36 +00:00
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
gwlist_destroy(l, (void *)octstr_destroy);
|
2006-02-28 10:36:36 +00:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
2006-03-02 10:57:19 +00:00
|
|
|
|
2006-03-03 05:36:07 +00:00
|
|
|
#define SHELLCHARS "'|\"()[]{}$&!?*><%`\n \t\\"
|
2006-03-02 10:57:19 +00:00
|
|
|
void escape_shell_chars(Octstr *str)
|
|
|
|
{
|
|
|
|
Octstr *tmp;
|
2006-03-03 05:36:07 +00:00
|
|
|
int i, n;
|
2006-03-02 10:57:19 +00:00
|
|
|
|
|
|
|
octstr_strip_blanks(str);
|
|
|
|
|
|
|
|
tmp = octstr_duplicate(str);
|
|
|
|
octstr_delete(str, 0, octstr_len(str));
|
|
|
|
|
2006-03-03 05:36:07 +00:00
|
|
|
for (i = 0, n = octstr_len(tmp); i < n; i++) {
|
2006-03-02 10:57:19 +00:00
|
|
|
int ch = octstr_get_char(tmp,i);
|
|
|
|
|
2006-03-03 05:36:07 +00:00
|
|
|
if (strchr(SHELLCHARS, ch) != NULL)
|
2006-03-02 10:57:19 +00:00
|
|
|
octstr_append_char(str, '\\');
|
|
|
|
octstr_append_char(str, ch);
|
|
|
|
}
|
|
|
|
octstr_destroy(tmp);
|
|
|
|
}
|
2006-06-20 13:32:54 +00:00
|
|
|
|
|
|
|
int parse_cgivars(List *request_headers, Octstr *request_body,
|
|
|
|
List **cgivars, List **cgivar_ctypes)
|
|
|
|
{
|
|
|
|
Octstr *ctype = NULL, *charset = NULL;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (request_body == NULL ||
|
|
|
|
octstr_len(request_body) == 0 || cgivars == NULL)
|
|
|
|
return 0; /* Nothing to do, this is a normal GET request. */
|
|
|
|
|
|
|
|
http_header_get_content_type(request_headers, &ctype, &charset);
|
|
|
|
|
|
|
|
if (*cgivars == NULL)
|
2006-10-12 15:21:46 +00:00
|
|
|
*cgivars = gwlist_create();
|
2006-06-20 13:32:54 +00:00
|
|
|
|
|
|
|
if (*cgivar_ctypes == NULL)
|
2006-10-12 15:21:46 +00:00
|
|
|
*cgivar_ctypes = gwlist_create();
|
2006-06-20 13:32:54 +00:00
|
|
|
|
|
|
|
if (!ctype) {
|
|
|
|
warning(0, "MMS: Parse CGI Vars: Missing Content Type!");
|
|
|
|
ret = -1;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (octstr_case_compare(ctype, octstr_imm("application/x-www-form-urlencoded")) == 0) {
|
|
|
|
/* This is a normal POST form */
|
|
|
|
List *l = octstr_split(request_body, octstr_imm("&"));
|
|
|
|
Octstr *v;
|
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
while ((v = gwlist_extract_first(l)) != NULL) {
|
2006-06-20 13:32:54 +00:00
|
|
|
List *r = octstr_split(v, octstr_imm("="));
|
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
if (gwlist_len(r) == 0)
|
2006-06-20 13:32:54 +00:00
|
|
|
warning(0, "MMS: Parse CGI Vars: Missing CGI var name/value in POST data: %s",
|
|
|
|
octstr_get_cstr(request_body));
|
|
|
|
else {
|
|
|
|
HTTPCGIVar *x = gw_malloc(sizeof *x);
|
2006-10-12 15:21:46 +00:00
|
|
|
x->name = gwlist_extract_first(r);
|
|
|
|
x->value = gwlist_extract_first(r);
|
2006-06-20 13:32:54 +00:00
|
|
|
if (!x->value)
|
|
|
|
x->value = octstr_imm("");
|
|
|
|
|
|
|
|
octstr_strip_blanks(x->name);
|
|
|
|
octstr_strip_blanks(x->value);
|
|
|
|
|
|
|
|
octstr_url_decode(x->name);
|
|
|
|
octstr_url_decode(x->value);
|
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
gwlist_append(*cgivars, x);
|
2006-06-20 13:32:54 +00:00
|
|
|
}
|
|
|
|
octstr_destroy(v);
|
2006-10-12 15:21:46 +00:00
|
|
|
gwlist_destroy(r, octstr_destroy_item);
|
2006-06-20 13:32:54 +00:00
|
|
|
}
|
2006-10-12 15:21:46 +00:00
|
|
|
gwlist_destroy(l, NULL);
|
2006-06-20 13:32:54 +00:00
|
|
|
} else if (octstr_case_compare(ctype, octstr_imm("multipart/form-data")) == 0) {
|
|
|
|
/* multi-part form data */
|
|
|
|
MIMEEntity *m = mime_http_to_entity(request_headers, request_body);
|
|
|
|
int i, n;
|
|
|
|
|
|
|
|
if (!m) {
|
|
|
|
warning(0, "MMS: Parse CGI Vars: Failed to parse multipart/form-data body: %s",
|
|
|
|
octstr_get_cstr(request_body));
|
|
|
|
ret = -1;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
/* Go through body parts, pick out what we need. */
|
2006-10-12 15:21:46 +00:00
|
|
|
for (i = 0, n = mime_entity_num_parts(m); i < n; i++) {
|
|
|
|
MIMEEntity *mp = mime_entity_get_part(m, i);
|
|
|
|
List *headers = _x_mime_entity_headers(mp);
|
|
|
|
Octstr *body = mime_entity_body(mp);
|
|
|
|
Octstr *ct = http_header_value(headers,
|
2006-07-13 12:01:24 +00:00
|
|
|
octstr_imm("Content-Type"));
|
2006-10-12 15:21:46 +00:00
|
|
|
Octstr *cd = http_header_value(headers,
|
2006-07-13 12:01:24 +00:00
|
|
|
octstr_imm("Content-Disposition"));
|
2006-06-20 13:32:54 +00:00
|
|
|
Octstr *name = http_get_header_parameter(cd, octstr_imm("name"));
|
2006-10-12 15:21:46 +00:00
|
|
|
|
2006-06-20 13:32:54 +00:00
|
|
|
if (name) {
|
|
|
|
HTTPCGIVar *x = gw_malloc(sizeof *x);
|
2006-10-12 15:21:46 +00:00
|
|
|
|
2006-06-20 13:32:54 +00:00
|
|
|
/* Strip quotes */
|
|
|
|
if (octstr_get_char(name, 0) == '"') {
|
|
|
|
octstr_delete(name, 0, 1);
|
|
|
|
octstr_truncate(name, octstr_len(name) - 1);
|
|
|
|
}
|
2006-10-12 15:21:46 +00:00
|
|
|
|
2006-06-20 13:32:54 +00:00
|
|
|
x->name = octstr_duplicate(name);
|
2006-10-12 15:21:46 +00:00
|
|
|
x->value = octstr_duplicate(body);
|
|
|
|
|
|
|
|
gwlist_append(*cgivars, x);
|
2006-06-20 13:32:54 +00:00
|
|
|
|
|
|
|
if (ct) { /* If the content type is set, use it. */
|
|
|
|
x = gw_malloc(sizeof *x);
|
|
|
|
x->name = octstr_duplicate(name);
|
|
|
|
x->value = octstr_duplicate(ct);
|
|
|
|
|
2006-10-12 15:21:46 +00:00
|
|
|
gwlist_append(*cgivar_ctypes, x);
|
2006-06-20 13:32:54 +00:00
|
|
|
}
|
|
|
|
octstr_destroy(name);
|
|
|
|
}
|
|
|
|
if (ct)
|
|
|
|
octstr_destroy(ct);
|
|
|
|
|
|
|
|
if (cd)
|
|
|
|
octstr_destroy(cd);
|
2006-10-12 15:21:46 +00:00
|
|
|
octstr_destroy(body);
|
|
|
|
http_destroy_headers(headers);
|
|
|
|
mime_entity_destroy(mp);
|
2006-06-20 13:32:54 +00:00
|
|
|
}
|
|
|
|
mime_entity_destroy(m);
|
|
|
|
|
|
|
|
} else /* else it is nothing that we know about, so simply go away... */
|
|
|
|
ret = -1;
|
|
|
|
done:
|
|
|
|
if (ctype)
|
|
|
|
octstr_destroy(ctype);
|
|
|
|
if (charset)
|
|
|
|
octstr_destroy(charset);
|
|
|
|
return ret;
|
|
|
|
}
|
2006-10-12 15:21:46 +00:00
|
|
|
|
|
|
|
/* We need this because of boundary element adding bug in gwlib/mime.c */
|
|
|
|
List *_x_mime_entity_headers(MIMEEntity *m)
|
|
|
|
{
|
|
|
|
List *h = mime_entity_headers(m);
|
|
|
|
http_header_remove_all(h, "MIME-Version");
|
|
|
|
|
|
|
|
/* also remove boundary element -- it was added erroneously */
|
|
|
|
if (mime_entity_num_parts(m) == 0)
|
|
|
|
strip_boundary_element(h,NULL);
|
|
|
|
mime_replace_headers(m, h);
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get content-ID header, fix: WAP decoder may leave " at beginning */
|
|
|
|
Octstr *_x_get_content_id(List *headers)
|
|
|
|
{
|
|
|
|
Octstr *cid = http_header_value(headers, octstr_imm("Content-ID"));
|
|
|
|
|
|
|
|
if (cid)
|
|
|
|
if (octstr_get_char(cid, 0) == '"' &&
|
|
|
|
octstr_get_char(cid, octstr_len(cid) - 1) != '"')
|
|
|
|
octstr_delete(cid, 0,1);
|
|
|
|
return cid;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Utility: Take a header list, remove any boundary parameter from the content-type
|
|
|
|
* element. We don't want this in the WSP packed content.
|
|
|
|
*/
|
|
|
|
void strip_boundary_element(List *headers, char *s)
|
|
|
|
{
|
|
|
|
Octstr *ctype = NULL, *params = NULL;
|
|
|
|
Octstr *value;
|
|
|
|
|
|
|
|
gw_assert(headers);
|
|
|
|
get_content_type(headers, &ctype, ¶ms);
|
|
|
|
|
|
|
|
if (s) {/* we are replacing the content type as well as stripping */
|
|
|
|
if (ctype)
|
|
|
|
octstr_destroy(ctype);
|
|
|
|
ctype = octstr_create(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (params) {
|
|
|
|
List *h = get_value_parameters(params);
|
|
|
|
Octstr *ps;
|
|
|
|
http_header_remove_all(h,"boundary"); /* We don't need the boundary param if it is there. */
|
|
|
|
ps = make_value_parameters(h);
|
|
|
|
|
|
|
|
value = octstr_format("%S%s%S", ctype,
|
|
|
|
(ps && octstr_len(ps) > 0) ? "; " : "",
|
|
|
|
ps);
|
|
|
|
octstr_destroy(ps);
|
|
|
|
http_destroy_headers(h);
|
|
|
|
} else
|
|
|
|
value = ctype;
|
|
|
|
|
|
|
|
http_header_remove_all(headers, "Content-Type");
|
|
|
|
http_header_add(headers, "Content-Type", octstr_get_cstr(value));
|
|
|
|
if (ctype != value)
|
|
|
|
octstr_destroy(ctype);
|
|
|
|
octstr_destroy(value);
|
|
|
|
}
|