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>
|
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"
|
|
|
|
|
|
|
|
#define MAXQTRIES 100
|
|
|
|
#define BACKOFF_FACTOR 5*60 /* In seconds */
|
|
|
|
#define QUEUERUN_INTERVAL 15*60 /* 15 minutes. */
|
|
|
|
#define DEFAULT_EXPIRE 3600*24*7 /* One week */
|
|
|
|
#define MMS_PORT 8191 /* Default content fetch port. */
|
|
|
|
|
|
|
|
static Octstr *cfg_getx(CfgGroup *grp, Octstr *item)
|
|
|
|
{
|
|
|
|
Octstr *v = cfg_get(grp, item);
|
|
|
|
|
|
|
|
return v ? v : octstr_create("");
|
|
|
|
}
|
|
|
|
|
2005-04-04 13:47:03 +00:00
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
static void *load_module(CfgGroup *grp, char *config_key, char *symbolname)
|
|
|
|
{
|
|
|
|
Octstr *s;
|
|
|
|
void *retval = NULL;
|
|
|
|
|
|
|
|
s = cfg_get(grp, octstr_imm(config_key));
|
|
|
|
if (s) {
|
|
|
|
void *x = dlopen(octstr_get_cstr(s), RTLD_LAZY);
|
|
|
|
void *y = NULL;
|
2005-04-04 13:47:03 +00:00
|
|
|
#ifdef __APPLE__
|
|
|
|
char sbuf[512];
|
2005-03-10 08:01:02 +00:00
|
|
|
|
2005-04-04 13:47:03 +00:00
|
|
|
sprintf(sbuf, "_%s", symbolname);
|
2005-04-15 08:21:23 +00:00
|
|
|
#endif
|
2005-04-04 13:47:03 +00:00
|
|
|
if (x == NULL || ((y = dlsym(x, symbolname)) == NULL
|
|
|
|
#ifdef __APPLE__ /* fink version of dlsym has issues it seems. */
|
|
|
|
&& (y = dlsym(x, sbuf)) == NULL
|
|
|
|
#endif
|
|
|
|
))
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
panic(0,
|
2005-03-10 08:52:29 +00:00
|
|
|
"Error, unable to load dynamic libary (%s): "
|
|
|
|
"libhandle is %s, funcs is %s, err=%s",
|
2005-03-10 08:01:02 +00:00
|
|
|
octstr_get_cstr(s),
|
|
|
|
x ? "OK" : "Not OK", y ? "OK" : "Not OK", dlerror());
|
|
|
|
else
|
|
|
|
retval = y;
|
|
|
|
|
|
|
|
octstr_destroy(s);
|
|
|
|
}
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
MmsBoxSettings *mms_load_mmsbox_settings(Cfg *cfg)
|
|
|
|
{
|
|
|
|
Octstr *s;
|
|
|
|
List *l;
|
|
|
|
CfgGroup *grp = cfg_get_single_group(cfg, octstr_imm("mmsbox"));
|
|
|
|
MmsBoxSettings *m = gw_malloc(sizeof *m);
|
|
|
|
long port = -1;
|
|
|
|
Octstr *user, *pass, *from;
|
2005-04-22 14:27:50 +00:00
|
|
|
Octstr *qdir = NULL;
|
2005-04-14 11:27:23 +00:00
|
|
|
int i, n;
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
memset(m, 0, sizeof *m);
|
|
|
|
|
|
|
|
s = cfg_getx(grp, octstr_imm("local-mmsc-domains"));
|
|
|
|
|
|
|
|
if (s) {
|
|
|
|
l = octstr_split(s, octstr_imm(","));
|
|
|
|
octstr_destroy(s);
|
|
|
|
} else
|
|
|
|
l = list_create();
|
|
|
|
m->local_domains = l;
|
|
|
|
|
|
|
|
if (cfg_get_integer(&m->maxthreads, grp, octstr_imm("max-send-threads")) == -1)
|
|
|
|
m->maxthreads = 10;
|
|
|
|
|
|
|
|
m->unified_prefix = cfg_getx(grp, octstr_imm("unified-prefix"));
|
|
|
|
m->local_prefix = cfg_getx(grp, octstr_imm("local-prefixes"));
|
|
|
|
m->hostname = cfg_getx(grp, octstr_imm("hostname"));
|
|
|
|
|
|
|
|
if (m->hostname == NULL || octstr_len(m->hostname) == 0)
|
2005-04-14 11:27:23 +00:00
|
|
|
m->hostname = octstr_create("localhost");
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
m->name = cfg_getx(grp, octstr_imm("name"));
|
|
|
|
m->host_alias = cfg_getx(grp, octstr_imm("host-alias"));
|
|
|
|
|
|
|
|
m->sendmail = cfg_getx(grp, octstr_imm("send-mail-prog"));
|
|
|
|
|
2005-04-22 14:27:50 +00:00
|
|
|
qdir = cfg_getx(grp, octstr_imm("storage-directory"));
|
|
|
|
|
|
|
|
if (mkdir(octstr_get_cstr(qdir),
|
|
|
|
S_IRWXU|S_IRWXG) < 0 &&
|
|
|
|
errno != EEXIST)
|
|
|
|
panic(0, "Failed to create queue directory: %s - %s!",
|
|
|
|
octstr_get_cstr(qdir), strerror(errno));
|
|
|
|
|
|
|
|
m->global_queuedir = octstr_format("%S/global", qdir);
|
|
|
|
m->mm1_queuedir = octstr_format("%S/mm1", qdir);
|
|
|
|
m->mm4_queuedir = octstr_format("%S/mm4", qdir);
|
2005-04-19 09:11:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
if (mms_init_queuedir(m->mm1_queuedir) < 0)
|
|
|
|
panic(0, "Failed to initialise local queue directory: %s - %s!",
|
|
|
|
octstr_get_cstr(m->mm1_queuedir), strerror(errno));
|
|
|
|
else if (mms_init_queuedir(m->global_queuedir) < 0)
|
|
|
|
panic(0, "Failed to initialise global queue directory: %s - %s!",
|
|
|
|
octstr_get_cstr(m->global_queuedir), strerror(errno));
|
2005-04-22 14:27:50 +00:00
|
|
|
else if (mms_init_queuedir(m->mm4_queuedir) < 0)
|
|
|
|
panic(0, "Failed to initialise global queue directory: %s - %s!",
|
|
|
|
octstr_get_cstr(m->mm4_queuedir), strerror(errno));
|
2005-04-19 09:11:43 +00:00
|
|
|
|
2005-04-22 14:27:50 +00:00
|
|
|
m->mmbox_rootdir = octstr_format("%S/mmbox", qdir);
|
|
|
|
|
|
|
|
if (mmbox_root_init(octstr_get_cstr(m->mmbox_rootdir)) != 0)
|
|
|
|
panic(0, "Failed to initialise mmbox root directory, error: %s!",
|
|
|
|
strerror(errno));
|
2005-03-19 06:46:24 +00:00
|
|
|
|
2005-04-22 14:27:50 +00:00
|
|
|
m->ua_profile_cache_dir = octstr_format("%S/UserAgent_Profiles", qdir);
|
|
|
|
|
|
|
|
if (mkdir(octstr_get_cstr(m->ua_profile_cache_dir),
|
|
|
|
S_IRWXU|S_IRWXG) < 0 &&
|
|
|
|
errno != EEXIST)
|
|
|
|
panic(0, "Failed to initialise UA Profile directory, error: %s!",
|
|
|
|
strerror(errno));
|
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
if (cfg_get_integer(&m->maxsendattempts, grp, octstr_imm("maximum-send-attempts")) == -1)
|
|
|
|
m->maxsendattempts = MAXQTRIES;
|
|
|
|
|
|
|
|
if (cfg_get_integer(&m->default_msgexpiry, grp, octstr_imm("default-message-expiry")) == -1)
|
|
|
|
m->default_msgexpiry = DEFAULT_EXPIRE;
|
|
|
|
|
|
|
|
s = cfg_getx(grp, octstr_imm("queue-run-interval"));
|
|
|
|
if (!s || (m->queue_interval = atof(octstr_get_cstr(s))) <= 0)
|
|
|
|
m->queue_interval = QUEUERUN_INTERVAL;
|
|
|
|
|
|
|
|
if (cfg_get_integer(&m->send_back_off, grp, octstr_imm("send-attempt-back-off")) == -1)
|
|
|
|
m->send_back_off = BACKOFF_FACTOR;
|
|
|
|
|
|
|
|
/* Make send sms url. */
|
|
|
|
m->sendsms_url = cfg_getx(grp, octstr_imm("sendsms-url"));
|
|
|
|
|
|
|
|
user = cfg_getx(grp, octstr_imm("sendsms-username"));
|
|
|
|
pass = cfg_getx(grp, octstr_imm("sendsms-password"));
|
|
|
|
from = cfg_get(grp, octstr_imm("sendsms-global-sender"));
|
|
|
|
|
|
|
|
if (user && octstr_len(user) > 1)
|
|
|
|
octstr_url_encode(user);
|
|
|
|
if (pass && octstr_len(pass) > 1)
|
|
|
|
octstr_url_encode(pass);
|
|
|
|
if (from && octstr_len(from) > 1)
|
|
|
|
octstr_url_encode(from);
|
|
|
|
|
|
|
|
|
|
|
|
octstr_format_append(m->sendsms_url,
|
|
|
|
(from && octstr_len(from) > 1) ?
|
|
|
|
"?username=%S&password=%S&from=%S" :
|
|
|
|
"?username=%S&password=%S",
|
|
|
|
user,
|
|
|
|
pass,from);
|
|
|
|
|
|
|
|
m->system_user = octstr_format("system-user@%S",
|
|
|
|
m->hostname);
|
|
|
|
octstr_destroy(user);
|
|
|
|
octstr_destroy(pass);
|
|
|
|
if (from) octstr_destroy(from);
|
|
|
|
|
|
|
|
cfg_get_integer(&port, grp, octstr_imm("mms-port"));
|
|
|
|
|
|
|
|
m->port = (port > 0) ? port : MMS_PORT;
|
|
|
|
|
2005-04-14 11:27:23 +00:00
|
|
|
m->mm7port = -1;
|
|
|
|
cfg_get_integer(&m->mm7port, grp, octstr_imm("mm7-port"));
|
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
m->allow_ip = cfg_getx(grp, octstr_imm("allow-ip"));
|
|
|
|
m->deny_ip = cfg_getx(grp, octstr_imm("deny-ip"));
|
|
|
|
|
|
|
|
m->email2mmsrelay_prefixes = cfg_getx(grp,
|
|
|
|
octstr_imm("email2mms-relay-prefixes"));
|
2005-04-22 14:27:50 +00:00
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
m->prov_notify = cfg_getx(grp,octstr_imm("prov-server-notify-script"));
|
|
|
|
|
|
|
|
m->prov_getstatus = cfg_getx(grp,octstr_imm("prov-server-sub-status-script"));
|
|
|
|
m->mms_notify_txt = cfg_getx(grp, octstr_imm("mms-notify-text"));
|
|
|
|
m->mms_notify_unprov_txt = cfg_getx(grp, octstr_imm("mms-notify-unprovisioned-text"));
|
2005-03-31 08:43:04 +00:00
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
m->mms_email_txt = cfg_getx(grp, octstr_imm("mms-to-email-txt"));
|
|
|
|
m->mms_email_html = cfg_getx(grp, octstr_imm("mms-to-email-html"));
|
|
|
|
|
|
|
|
m->mms_toolarge = cfg_getx(grp, octstr_imm("mms-message-too-large-txt"));
|
|
|
|
|
|
|
|
m->wap_gw_msisdn_header = cfg_get(grp, octstr_imm("mms-client-msisdn-header"));
|
|
|
|
if (!m->wap_gw_msisdn_header) m->wap_gw_msisdn_header = octstr_imm(XMSISDN_HEADER);
|
|
|
|
|
|
|
|
m->wap_gw_ip_header = cfg_get(grp, octstr_imm("mms-client-ip-header"));
|
|
|
|
if (!m->wap_gw_ip_header) m->wap_gw_ip_header = octstr_imm(XIP_HEADER);
|
|
|
|
|
|
|
|
cfg_get_bool(&m->notify_unprovisioned, grp, octstr_imm("notify-unprovisioned"));
|
|
|
|
|
|
|
|
m->billing_params = cfg_getx(grp,
|
|
|
|
octstr_imm("billing-module-parameters"));
|
|
|
|
/* Get and load the billing lib if any. */
|
|
|
|
|
2005-04-07 12:21:35 +00:00
|
|
|
if ((m->mms_billfuncs = load_module(grp, "billing-library", "mms_billfuncs"))) {
|
2005-03-10 08:01:02 +00:00
|
|
|
if (m->mms_billfuncs->mms_billingmodule_init == NULL ||
|
|
|
|
m->mms_billfuncs->mms_billmsg == NULL ||
|
|
|
|
m->mms_billfuncs->mms_billingmodule_fini == NULL ||
|
|
|
|
m->mms_billfuncs->mms_logcdr == NULL)
|
|
|
|
panic(0, "Missing or NULL functions in billing module!");
|
|
|
|
} else
|
|
|
|
m->mms_billfuncs = &mms_billfuncs; /* The default one. */
|
|
|
|
|
|
|
|
m->mms_bill_module_data = m->mms_billfuncs->mms_billingmodule_init(octstr_get_cstr(m->billing_params));
|
|
|
|
|
|
|
|
m->resolver_params = cfg_getx(grp,
|
2005-03-10 08:52:29 +00:00
|
|
|
octstr_imm("resolver-module-parameters"));
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
/* Get and load the resolver lib if any. */
|
2005-04-07 12:21:35 +00:00
|
|
|
if ((m->mms_resolvefuncs = load_module(grp, "resolver-library", "mms_resolvefuncs"))) {
|
2005-03-10 08:01:02 +00:00
|
|
|
if (m->mms_resolvefuncs->mms_resolvermodule_init == NULL ||
|
|
|
|
m->mms_resolvefuncs->mms_resolve == NULL ||
|
|
|
|
m->mms_resolvefuncs->mms_resolvermodule_fini == NULL)
|
|
|
|
panic(0, "Missing or NULL functions in resolver module!");
|
|
|
|
} else
|
|
|
|
m->mms_resolvefuncs = &mms_resolvefuncs; /* The default one. */
|
2005-03-10 08:52:29 +00:00
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
m->mms_resolver_module_data = m->mms_resolvefuncs->mms_resolvermodule_init(octstr_get_cstr(m->resolver_params));
|
|
|
|
|
2005-03-11 20:29:10 +00:00
|
|
|
m->detokenizer_params = cfg_getx(grp, octstr_imm("detokenizer-module-parameters"));
|
|
|
|
|
|
|
|
/* Get and load the detokenizer lib if any. */
|
2005-04-07 12:21:35 +00:00
|
|
|
if ((m->mms_detokenizefuncs = load_module(grp, "detokenizer-library", "mms_detokenizefuncs"))) {
|
2005-03-11 20:29:10 +00:00
|
|
|
if (m->mms_detokenizefuncs->mms_detokenizer_init == NULL ||
|
|
|
|
m->mms_detokenizefuncs->mms_detokenize == NULL ||
|
2005-04-04 13:47:03 +00:00
|
|
|
m->mms_detokenizefuncs->mms_gettoken == NULL ||
|
2005-03-11 20:29:10 +00:00
|
|
|
m->mms_detokenizefuncs->mms_detokenizer_fini == NULL)
|
|
|
|
panic(0, "Missing or NULL functions in detokenizer module!");
|
|
|
|
if (m->mms_detokenizefuncs->mms_detokenizer_init(octstr_get_cstr(m->detokenizer_params)))
|
|
|
|
panic(0, "Detokenizer module failed to initialize");
|
|
|
|
} else
|
|
|
|
m->mms_detokenizefuncs = NULL;
|
|
|
|
|
2005-04-01 05:22:12 +00:00
|
|
|
if (cfg_get_bool(&m->allow_ip_type, grp, octstr_imm("allow-ip-type")) < 0)
|
|
|
|
m->allow_ip_type = 1;
|
2005-03-16 05:16:09 +00:00
|
|
|
cfg_get_bool(&m->optimize_notification_size, grp, octstr_imm("optimize-notification-size"));
|
2005-03-19 06:46:24 +00:00
|
|
|
|
2005-04-22 14:27:50 +00:00
|
|
|
if (qdir)
|
|
|
|
octstr_destroy(qdir);
|
2005-04-14 11:27:23 +00:00
|
|
|
|
|
|
|
/* Now load the VASP list. */
|
|
|
|
l = cfg_get_multi_group(cfg, octstr_imm("mms-vasp"));
|
|
|
|
m->vasp_list = list_create();
|
|
|
|
for (i=0, n=list_len(l); i<n; i++) {
|
|
|
|
CfgGroup *grp = list_get(l, i);
|
|
|
|
MmsVasp *mv = gw_malloc(sizeof *mv);
|
|
|
|
Octstr *s;
|
|
|
|
mv->id = cfg_getx(grp, octstr_imm("vasp-id"));
|
|
|
|
mv->short_code = -1;
|
|
|
|
cfg_get_integer(&mv->short_code, grp, octstr_imm("short-code"));
|
|
|
|
|
|
|
|
mv->vasp_username = cfg_getx(grp, octstr_imm("vasp-username"));
|
|
|
|
mv->vasp_password = cfg_getx(grp, octstr_imm("vasp-password"));
|
|
|
|
|
|
|
|
mv->vasp_url = cfg_getx(grp, octstr_imm("vasp-url"));
|
|
|
|
|
|
|
|
mv->mmsc_username = cfg_getx(grp, octstr_imm("mmsc-username"));
|
|
|
|
mv->mmsc_password = cfg_getx(grp, octstr_imm("mmsc-password"));
|
|
|
|
|
|
|
|
s = cfg_getx(grp, octstr_imm("type"));
|
|
|
|
|
|
|
|
if (octstr_case_compare(s, octstr_imm("soap")) == 0)
|
|
|
|
mv->type = SOAP_VASP;
|
|
|
|
else if (octstr_case_compare(s, octstr_imm("eaif")) == 0)
|
|
|
|
mv->type = EAIF_VASP;
|
|
|
|
else
|
|
|
|
mv->type = NONE_VASP;
|
|
|
|
octstr_destroy(s);
|
|
|
|
|
|
|
|
list_append(m->vasp_list, mv);
|
|
|
|
}
|
|
|
|
list_destroy(l, NULL);
|
2005-03-10 08:01:02 +00:00
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
List *mms_proxy_relays(Cfg *cfg)
|
|
|
|
{
|
|
|
|
List *gl = cfg_get_multi_group(cfg, octstr_imm("mmsproxy"));
|
|
|
|
int i, n;
|
|
|
|
List *l = list_create();
|
|
|
|
|
|
|
|
for (i = 0, n = list_len(gl); i < n; i++) {
|
|
|
|
CfgGroup *grp = list_get(gl, i);
|
|
|
|
MmsProxyRelay *m = gw_malloc(sizeof *m);
|
|
|
|
|
|
|
|
m->host = cfg_getx(grp, octstr_imm("host"));
|
|
|
|
m->name = cfg_getx(grp, octstr_imm("name"));
|
|
|
|
m->allowed_prefix = cfg_getx(grp, octstr_imm("allowed-prefix"));
|
|
|
|
m->denied_prefix = cfg_getx(grp, octstr_imm("denied-prefix"));
|
|
|
|
|
|
|
|
list_append(l, m);
|
|
|
|
}
|
|
|
|
|
|
|
|
list_destroy(gl, NULL);
|
|
|
|
|
|
|
|
return l;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-21 16:11:51 +00:00
|
|
|
Octstr *mms_makefetchurl(char *qf, Octstr *token, int loc,
|
2005-04-04 13:47:03 +00:00
|
|
|
Octstr *to,
|
2005-03-10 08:01:02 +00:00
|
|
|
MmsBoxSettings *settings)
|
|
|
|
{
|
|
|
|
Octstr *url = octstr_create("");
|
|
|
|
Octstr *host_alias = settings->host_alias;
|
|
|
|
Octstr *hstr;
|
2005-04-04 13:47:03 +00:00
|
|
|
Octstr *endtoken, *x;
|
2005-03-10 08:01:02 +00:00
|
|
|
|
2005-04-04 13:47:03 +00:00
|
|
|
MmsDetokenizerFuncStruct *tfs = settings->mms_detokenizefuncs;
|
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
if (host_alias && octstr_len(host_alias) > 0)
|
|
|
|
hstr = octstr_duplicate(host_alias);
|
|
|
|
else
|
|
|
|
hstr = octstr_format("%S:%d",
|
|
|
|
settings->hostname, settings->port);
|
|
|
|
|
2005-04-04 13:47:03 +00:00
|
|
|
octstr_format_append(url, "http://%S/%s@%d",
|
2005-03-10 08:01:02 +00:00
|
|
|
hstr,
|
2005-04-04 13:47:03 +00:00
|
|
|
qf, loc);
|
|
|
|
|
|
|
|
if (tfs && tfs->mms_gettoken) { /* we append the recipient token or we append the message token. */
|
|
|
|
endtoken = tfs->mms_gettoken(to);
|
2005-04-07 12:21:35 +00:00
|
|
|
if (!endtoken)
|
|
|
|
endtoken = octstr_imm("x");
|
2005-04-04 13:47:03 +00:00
|
|
|
} else {
|
|
|
|
if (!token)
|
2005-04-07 12:21:35 +00:00
|
|
|
endtoken = octstr_imm("x");
|
2005-04-04 13:47:03 +00:00
|
|
|
else
|
|
|
|
endtoken = octstr_duplicate(token);
|
|
|
|
}
|
|
|
|
|
|
|
|
x = octstr_duplicate(endtoken); /* might be immutable, so we duplicate it. */
|
|
|
|
octstr_url_encode(x);
|
|
|
|
octstr_format_append(url, "/%S", x);
|
|
|
|
|
|
|
|
octstr_destroy(endtoken);
|
|
|
|
octstr_destroy(x);
|
2005-03-10 08:01:02 +00:00
|
|
|
octstr_destroy(hstr);
|
|
|
|
return url;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-04-04 13:47:03 +00:00
|
|
|
Octstr *mms_find_sender_msisdn(Octstr *send_url, List *request_hdrs, Octstr *msisdn_header,
|
|
|
|
MmsDetokenizerFuncStruct* detokenizerfuncs)
|
2005-03-10 08:01:02 +00:00
|
|
|
{
|
|
|
|
/* Either we have a WAP gateway header as defined, or we look for
|
2005-04-04 13:47:03 +00:00
|
|
|
* last part of url, pass it to detokenizer lib if defined, and back comes our number.
|
2005-03-10 08:01:02 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
Octstr *phonenum = http_header_value(request_hdrs,
|
|
|
|
msisdn_header);
|
|
|
|
|
|
|
|
if (!phonenum || octstr_len(phonenum) == 0) {
|
2005-04-04 13:47:03 +00:00
|
|
|
List *l = octstr_split(send_url, octstr_imm("/"));
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
if (l && list_len(l) > 1) {
|
2005-04-01 10:21:53 +00:00
|
|
|
if (detokenizerfuncs)
|
2005-03-11 20:29:10 +00:00
|
|
|
phonenum = detokenizerfuncs->mms_detokenize(list_get(l, list_len(l) - 1));
|
2005-03-10 08:01:02 +00:00
|
|
|
}
|
|
|
|
if (l)
|
|
|
|
list_destroy(l, (list_item_destructor_t *)octstr_destroy);
|
|
|
|
}
|
|
|
|
|
|
|
|
return phonenum;
|
|
|
|
}
|
|
|
|
|
|
|
|
Octstr *mms_find_sender_ip(List *request_hdrs, Octstr *ip_header, Octstr *ip, int *isv6)
|
|
|
|
{
|
|
|
|
Octstr *xip;
|
|
|
|
/* Look in the headers, if none is defined, return actual IP */
|
|
|
|
Octstr *client_ip = http_header_value(request_hdrs, ip_header);
|
|
|
|
char *s;
|
|
|
|
|
2005-04-01 10:21:53 +00:00
|
|
|
xip = client_ip ? client_ip : octstr_duplicate(ip);
|
2005-03-10 08:01:02 +00:00
|
|
|
|
|
|
|
s = octstr_get_cstr(xip);
|
|
|
|
|
|
|
|
/* Crude test for ipv6 */
|
|
|
|
*isv6 = (index(s, ':') >= 0);
|
|
|
|
return xip;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mms_decodefetchurl(Octstr *fetch_url,
|
2005-03-21 16:11:51 +00:00
|
|
|
Octstr **qf, Octstr **token, int *loc)
|
2005-03-10 08:01:02 +00:00
|
|
|
{
|
|
|
|
Octstr *xfurl = octstr_duplicate(fetch_url);
|
|
|
|
int i, j, n;
|
|
|
|
char *s, *p;
|
|
|
|
|
|
|
|
for (i = 0, n = 0, s = octstr_get_cstr(xfurl);
|
|
|
|
i < octstr_len(xfurl); i++)
|
|
|
|
if (s[i] == '/')
|
|
|
|
n++;
|
|
|
|
if (n < 2) /* We need at least two slashes. */
|
|
|
|
octstr_append_char(xfurl, '/');
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
n = octstr_len(xfurl);
|
|
|
|
s = octstr_get_cstr(xfurl);
|
|
|
|
|
|
|
|
p = strrchr(s, '/'); /* Find last slash. */
|
|
|
|
if (p)
|
|
|
|
i = (p - s) - 1;
|
|
|
|
else
|
|
|
|
i = n-1;
|
|
|
|
|
|
|
|
if (i < 0)
|
|
|
|
i = 0;
|
|
|
|
|
|
|
|
while (i>0 && s[i] != '/')
|
|
|
|
i--; /* Go back, find first slash */
|
|
|
|
if (i>=0 && s[i] == '/')
|
|
|
|
i++;
|
|
|
|
|
|
|
|
/* Now we have qf, find its end. */
|
|
|
|
|
|
|
|
j = i;
|
|
|
|
while (j<n && s[j] != '/')
|
|
|
|
j++; /* Skip to next slash. */
|
|
|
|
|
|
|
|
*qf = octstr_copy(fetch_url, i, j-i);
|
|
|
|
|
|
|
|
if (j<n)
|
|
|
|
*token = octstr_copy(fetch_url, j + 1, n - (j+1));
|
|
|
|
else
|
|
|
|
*token = octstr_create("");
|
|
|
|
octstr_destroy(xfurl);
|
2005-03-21 16:11:51 +00:00
|
|
|
|
|
|
|
/* Now get loc out of qf. */
|
|
|
|
*loc = MMS_LOC_MQUEUE;
|
|
|
|
i = octstr_search_char(*qf, '@', 0);
|
|
|
|
if (i >= 0) {
|
|
|
|
long l;
|
|
|
|
int j = octstr_parse_long(&l, *qf, i+1, 10);
|
|
|
|
if (j > 0)
|
|
|
|
*loc = l;
|
|
|
|
octstr_delete(*qf, i, octstr_len(*qf));
|
|
|
|
}
|
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Octstr *mms_maketransid(char *qf, Octstr *mmscname)
|
|
|
|
{
|
2005-03-21 16:11:51 +00:00
|
|
|
Octstr *res;
|
|
|
|
Octstr *x;
|
|
|
|
static int ct;
|
|
|
|
|
|
|
|
if (!qf)
|
|
|
|
x = octstr_format("msg.%ld.x%d.%d.%d",
|
|
|
|
time(NULL), ++ct, getpid(), random()%10000);
|
|
|
|
else
|
|
|
|
x = octstr_create(qf);
|
|
|
|
|
|
|
|
res = octstr_format("%S@%S", x, mmscname);
|
|
|
|
|
|
|
|
octstr_destroy(x);
|
|
|
|
|
2005-03-10 08:01:02 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern Octstr *mms_getqf_fromtransid(Octstr *transid)
|
|
|
|
{
|
|
|
|
int i = octstr_search_char(transid, '@', 0);
|
2005-04-14 11:27:23 +00:00
|
|
|
|
|
|
|
return (i >= 0) ? octstr_copy(transid, 0, i) : 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();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
if (isspace(ch) || ispunct(ch))
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Octstr *make_value_parameters(List *params)
|
|
|
|
{
|
|
|
|
Octstr *s = octstr_create(""), *name, *value;
|
|
|
|
int i, n;
|
|
|
|
|
|
|
|
for (i = 0, n = params ? list_len(params) : 0; i<n; i++) {
|
|
|
|
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();
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0, n = list_len(mm->headers); i<n; i++) {
|
|
|
|
Octstr *header = NULL, *value = NULL;
|
|
|
|
List *l = NULL;
|
|
|
|
int j, m;
|
|
|
|
int skip;
|
|
|
|
|
|
|
|
http_header_get(mm->headers, i, &header, &value);
|
|
|
|
|
|
|
|
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 &&
|
|
|
|
list_len(l) > 1)
|
|
|
|
for (j = 0, m = list_len(l); j<m; j++)
|
|
|
|
http_header_add(h, octstr_get_cstr(header),
|
|
|
|
octstr_get_cstr(list_get(l, j)));
|
|
|
|
else
|
|
|
|
http_header_add(h, octstr_get_cstr(header),
|
|
|
|
octstr_get_cstr(value));
|
|
|
|
|
|
|
|
if (l) list_destroy(l, (list_item_destructor_t *)octstr_destroy);
|
|
|
|
|
|
|
|
loop:
|
|
|
|
if (header) octstr_destroy(header);
|
|
|
|
if (value) octstr_destroy(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
http_destroy_headers(mm->headers);
|
|
|
|
mm->headers = h;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Undo base64 content coding for mime entities that need it. */
|
|
|
|
void unbase64_mimeparts(MIMEEntity *m)
|
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
|
|
|
|
if (m->multiparts && list_len(m->multiparts) > 0)
|
|
|
|
for (i = 0, n = list_len(m->multiparts); i<n; i++)
|
|
|
|
unbase64_mimeparts(list_get(m->multiparts, i));
|
|
|
|
else { /* A non-multipart message .*/
|
|
|
|
Octstr *ctype = http_header_value(m->headers, octstr_imm("Content-Type"));
|
|
|
|
Octstr *te = http_header_value(m->headers, octstr_imm("Content-Transfer-Encoding"));
|
|
|
|
|
|
|
|
if (ctype && te &&
|
2005-03-16 06:37:25 +00:00
|
|
|
octstr_case_compare(te,octstr_imm("base64")) == 0)
|
2005-03-10 08:01:02 +00:00
|
|
|
octstr_base64_to_binary(m->body);
|
2005-03-16 06:37:25 +00:00
|
|
|
|
|
|
|
http_header_remove_all(m->headers, "Content-Transfer-Encoding"); /* Remove it in all cases (?).*/
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
}
|
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;
|
|
|
|
|
|
|
|
if (m->multiparts && list_len(m->multiparts) > 0)
|
|
|
|
for (i = 0, n = list_len(m->multiparts); i<n; i++)
|
|
|
|
base64_mimeparts(list_get(m->multiparts, i));
|
|
|
|
else { /* A non-multipart message .*/
|
|
|
|
Octstr *ctype = http_header_value(m->headers, octstr_imm("Content-Type"));
|
|
|
|
Octstr *te = http_header_value(m->headers, octstr_imm("Content-Transfer-Encoding"));
|
|
|
|
|
|
|
|
if (ctype && !te
|
|
|
|
#if 1
|
|
|
|
&&
|
2005-07-01 06:13:59 +00:00
|
|
|
(m->body && octstr_check_range(m->body, 0, octstr_len(m->body), _mms_gw_isprint) == 0)
|
2005-03-10 08:01:02 +00:00
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
octstr_binary_to_base64(m->body);
|
|
|
|
http_header_add(m->headers, "Content-Transfer-Encoding", "base64");
|
|
|
|
}
|
|
|
|
if (ctype)
|
|
|
|
octstr_destroy(ctype);
|
|
|
|
if (te)
|
|
|
|
octstr_destroy(te);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void notify_prov_server(char *cmd, char *from, char *event, char *arg)
|
|
|
|
{
|
|
|
|
Octstr *s;
|
|
|
|
|
|
|
|
if (cmd == NULL || cmd[0] == '\0')
|
|
|
|
return;
|
|
|
|
s = octstr_format("%s '%s' '%s' '%s'", cmd, event, from, arg);
|
|
|
|
if (s) {
|
|
|
|
system(octstr_get_cstr(s));
|
|
|
|
octstr_destroy(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int mms_ind_send(Octstr *prov_cmd, Octstr *to)
|
|
|
|
{
|
|
|
|
|
|
|
|
Octstr *s;
|
|
|
|
int res = 1;
|
|
|
|
|
|
|
|
if (prov_cmd == NULL ||
|
|
|
|
octstr_len(prov_cmd) == 0)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
s = octstr_format("%S %S", prov_cmd, to);
|
|
|
|
|
|
|
|
if (s) {
|
|
|
|
int x = system(octstr_get_cstr(s));
|
|
|
|
int y = WEXITSTATUS(x);
|
|
|
|
|
|
|
|
if (x < 0) {
|
|
|
|
error(0, "Checking MMS Ind.Send: Failed to run command %s!",
|
|
|
|
octstr_get_cstr(s));
|
|
|
|
res = 1;
|
|
|
|
} else if (y != 0 && y != 1)
|
|
|
|
res = -1;
|
|
|
|
else
|
|
|
|
res = y;
|
|
|
|
octstr_destroy(s);
|
|
|
|
} else
|
|
|
|
warning(0, "Checking MMS Ind.Send: Failed call to compose command [%s] ",
|
|
|
|
octstr_get_cstr(prov_cmd));
|
|
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
Octstr *cmd = octstr_create("");
|
|
|
|
|
|
|
|
if (append_hostname) { /* Add our hostname to all phone numbers. */
|
|
|
|
int i, n;
|
|
|
|
List *l = http_create_empty_headers();
|
|
|
|
Octstr *xfrom = http_header_value(m->headers, octstr_imm("From"));
|
|
|
|
List *lto = http_header_find_all(m->headers, "To");
|
|
|
|
List *lcc = http_header_find_all(m->headers, "Cc");
|
|
|
|
|
|
|
|
if (xfrom) {
|
|
|
|
addmmscname(xfrom, myhostname);
|
|
|
|
http_header_add(l, "From", octstr_get_cstr(xfrom));
|
|
|
|
octstr_destroy(xfrom);
|
|
|
|
}
|
|
|
|
http_header_remove_all(m->headers, "From");
|
|
|
|
|
|
|
|
for (i = 0, n = list_len(lto); i < n; i++) {
|
|
|
|
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);
|
|
|
|
http_header_remove_all(m->headers, "To");
|
|
|
|
|
|
|
|
for (i = 0, n = list_len(lcc); i < n; i++) {
|
|
|
|
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);
|
|
|
|
http_header_remove_all(m->headers, "Cc");
|
|
|
|
|
|
|
|
http_append_headers(m->headers, l); /* combine old with new. */
|
|
|
|
http_destroy_headers(l);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pack headers, get string rep of mime entity. */
|
|
|
|
http_header_pack(m->headers);
|
|
|
|
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 (;;) {
|
|
|
|
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':
|
|
|
|
octstr_append(cmd, to);
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
if (append_hostname) {
|
|
|
|
Octstr *xfrom = octstr_duplicate(from);
|
|
|
|
addmmscname(xfrom, myhostname);
|
|
|
|
octstr_append(cmd, xfrom);
|
|
|
|
octstr_destroy(xfrom);
|
|
|
|
} else
|
|
|
|
octstr_append(cmd, from);
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
octstr_append(cmd, subject);
|
|
|
|
break;
|
|
|
|
case 'm':
|
|
|
|
octstr_append(cmd, msgid);
|
|
|
|
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:
|
|
|
|
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;
|
|
|
|
|
|
|
|
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)
|
2005-07-01 05:54:35 +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) : "");
|
|
|
|
http_header_combine(newhdrs, m->headers);
|
|
|
|
http_destroy_headers(m->headers);
|
|
|
|
m->headers = newhdrs;
|
|
|
|
|
|
|
|
|
|
|
|
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) {
|
|
|
|
l = list_create();
|
|
|
|
list_append(l, to);
|
|
|
|
} 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)
|
|
|
|
list_destroy(l, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
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("");
|
|
|
|
int i, n = to ? list_len(to) : 0;
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
octstr_format_append(xto,
|
|
|
|
"%s%S",
|
|
|
|
(i == 0) ? "" : ", ",
|
|
|
|
list_get(to,i));
|
|
|
|
|
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
|
|
|
|
|
|
|
MIMEEntity *mime_entity_duplicate(MIMEEntity *m)
|
|
|
|
{
|
|
|
|
MIMEEntity *mx = gw_malloc(sizeof *mx);
|
|
|
|
|
|
|
|
mx->headers = http_header_duplicate(m->headers);
|
|
|
|
if (m->multiparts && list_len(m->multiparts) > 0) {
|
|
|
|
int i, n;
|
|
|
|
mx->multiparts = list_create();
|
|
|
|
for (i = 0, n = list_len(m->multiparts); i < n; i++) {
|
|
|
|
MIMEEntity *x = mime_entity_duplicate(list_get(m->multiparts, i));
|
|
|
|
list_append(mx->multiparts, x);
|
|
|
|
}
|
|
|
|
mx->body = NULL;
|
|
|
|
} else {
|
|
|
|
mx->body = m->body ? octstr_duplicate(m->body) : NULL;
|
|
|
|
mx->multiparts = NULL;
|
|
|
|
}
|
|
|
|
mx->start = NULL;
|
|
|
|
|
|
|
|
return mx;
|
|
|
|
}
|