2009-07-07 07:12:47 +00:00
|
|
|
/*
|
|
|
|
* Mbuni - Open Source MMS Gateway
|
|
|
|
*
|
|
|
|
* Mbuni MmsBox MM1 Component - Send & Receive MMS using a GPRS/EDGE/3G modem
|
|
|
|
*
|
|
|
|
* Copyright (C) 2007-2009, 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)
|
2009-07-02 04:32:23 +00:00
|
|
|
*/
|
2009-07-07 07:12:47 +00:00
|
|
|
|
2009-07-02 04:32:23 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <signal.h>
|
2009-09-08 12:47:33 +00:00
|
|
|
#include <sys/wait.h>
|
|
|
|
|
2009-07-02 04:32:23 +00:00
|
|
|
#include "mmsbox_mmsc.h"
|
|
|
|
#include "mmsbox_cfg.h"
|
|
|
|
#include "mmsbox.h"
|
|
|
|
#include "mms_util.h"
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
Octstr *mmsc_url; /* mmsc-url. */
|
|
|
|
Octstr *msisdn; /* my msisdn. */
|
|
|
|
Octstr *proxy; /* form is host:port. */
|
|
|
|
Octstr *gprs_on; /* Command to start GPRS link. Must not exit. */
|
2011-01-12 09:47:14 +00:00
|
|
|
Octstr *gprs_off; /* Command to stop GPRS link. */
|
2009-07-02 04:32:23 +00:00
|
|
|
Octstr *gprs_pid; /* command to call to get PID of GPRS for stopping GPRS link (i.e. pppd). */
|
|
|
|
Octstr *smsc_on; /* command to start smsc connection */
|
|
|
|
Octstr *smsc_off; /* commadn to stop smsc connection */
|
|
|
|
int port; /* port for incoming messages. */
|
|
|
|
Octstr *interface; /* specific interface to listen on. */
|
|
|
|
|
|
|
|
Octstr *unified_prefix; /* copies from above, do not edit! */
|
|
|
|
List *strip_prefixes;
|
|
|
|
|
|
|
|
/* internal data. */
|
|
|
|
MmscGrp *info;
|
|
|
|
MmsQueueHandlerFuncs *qfs;
|
|
|
|
List *requests; /* list of requests. */
|
|
|
|
long h_tid, d_tid; /* thread IDs. */
|
|
|
|
|
|
|
|
int sender_alive;
|
2011-03-24 12:58:11 +00:00
|
|
|
|
2009-07-02 04:32:23 +00:00
|
|
|
} MM1Settings;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
enum {MM1_GET, MM1_PUSH} type;
|
|
|
|
int waiter_exists; /* set to true if after handling, should signal and NOT destroy struct.*/
|
|
|
|
pthread_cond_t cond;
|
|
|
|
pthread_mutex_t mutex;
|
|
|
|
union {
|
|
|
|
MmsMsg *m; /* for push. */
|
|
|
|
Octstr *url; /* for get */
|
|
|
|
} u;
|
|
|
|
void *result; /* set to the result for a PUSH */
|
|
|
|
Octstr *error;
|
|
|
|
} MM1Request;
|
|
|
|
|
2011-01-12 09:47:14 +00:00
|
|
|
static void stop_gprs(Octstr *cmd);
|
2009-07-02 04:32:23 +00:00
|
|
|
static void handle_notify(MM1Settings *mm1);
|
|
|
|
static void handle_mm1(MM1Settings *mm1);
|
|
|
|
static int open_mm1(MmscGrp *mmc, MmsQueueHandlerFuncs *qfs,
|
|
|
|
Octstr *unified_prefix, List *strip_prefixes,
|
|
|
|
void **data)
|
|
|
|
{
|
|
|
|
Octstr *x, *y;
|
|
|
|
List *l;
|
|
|
|
Octstr *mmsc_url = NULL;
|
|
|
|
Octstr *proxy = NULL;
|
|
|
|
Octstr *gprs_on = NULL;
|
2011-01-12 09:47:14 +00:00
|
|
|
Octstr *gprs_off = NULL;
|
2009-07-02 04:32:23 +00:00
|
|
|
Octstr *gprs_pid = NULL;
|
|
|
|
Octstr *smsc_on = NULL;
|
|
|
|
Octstr *smsc_off = NULL;
|
|
|
|
int port = 80;
|
|
|
|
Octstr *interface = NULL;
|
|
|
|
Octstr *msisdn = NULL;
|
|
|
|
|
|
|
|
MM1Settings *mm1;
|
|
|
|
|
|
|
|
/* parse the settings. */
|
|
|
|
|
|
|
|
x = octstr_duplicate(mmc->settings);
|
|
|
|
l = octstr_split(x, octstr_imm(";"));
|
|
|
|
octstr_destroy(x);
|
|
|
|
if (l)
|
|
|
|
while ((y = gwlist_extract_first(l)) != NULL) {
|
|
|
|
int i = octstr_search_char(y, '=', 0);
|
|
|
|
Octstr *item = (i>=0) ? octstr_copy(y, 0, i) : NULL;
|
|
|
|
Octstr *value = (i>=0) ? octstr_copy(y, i+1, octstr_len(y)) : NULL;
|
|
|
|
|
|
|
|
if (item == NULL)
|
|
|
|
octstr_destroy(value);
|
|
|
|
else if (octstr_str_case_compare(item, "mmsc-url") == 0)
|
|
|
|
mmsc_url = value;
|
|
|
|
else if (octstr_str_case_compare(item, "proxy") == 0)
|
|
|
|
proxy = value;
|
|
|
|
else if (octstr_str_case_compare(item, "gprs-on") == 0)
|
|
|
|
gprs_on = value;
|
2011-03-24 12:58:11 +00:00
|
|
|
else if (octstr_str_case_compare(item, "gprs-off") == 0)
|
|
|
|
gprs_off = value;
|
2009-07-02 04:32:23 +00:00
|
|
|
else if (octstr_str_case_compare(item, "gprs-pid") == 0)
|
|
|
|
gprs_pid = value;
|
|
|
|
else if (octstr_str_case_compare(item, "port") == 0) {
|
|
|
|
port = value ? atoi(octstr_get_cstr(value)) : 80;
|
|
|
|
if (http_open_port(port, 0) != 0)
|
|
|
|
mms_warning(0, "mmsbox-mm1", NULL, "failed to open incoming notifications port %d: %s",
|
2011-03-24 12:58:11 +00:00
|
|
|
port, strerror(errno));
|
2009-07-02 04:32:23 +00:00
|
|
|
}else if (octstr_str_case_compare(item, "http-interface") == 0)
|
|
|
|
interface = value;
|
|
|
|
else if (octstr_str_case_compare(item, "smsc-on") == 0)
|
|
|
|
smsc_on = value;
|
|
|
|
else if (octstr_str_case_compare(item, "smsc-off") == 0)
|
|
|
|
smsc_off = value;
|
|
|
|
else if (octstr_str_case_compare(item, "msisdn") == 0)
|
|
|
|
msisdn = value;
|
|
|
|
else {
|
|
|
|
mms_error(0, "mmsbox-mm1", NULL, "unknown/unsupported option: %s", octstr_get_cstr(item));
|
|
|
|
octstr_destroy(value);
|
|
|
|
}
|
|
|
|
octstr_destroy(item);
|
|
|
|
octstr_destroy(y);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mms_error(0, "mmsbox-mm1", NULL, "failed to parse settings string: %s", octstr_get_cstr(mmc->settings));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
gwlist_destroy(l, NULL);
|
|
|
|
|
|
|
|
mm1 = gw_malloc(sizeof *mm1);
|
|
|
|
mm1->mmsc_url = mmsc_url;
|
|
|
|
mm1->proxy = proxy;
|
|
|
|
mm1->gprs_on = gprs_on;
|
2011-01-12 09:47:14 +00:00
|
|
|
mm1->gprs_off = gprs_off;
|
2009-07-02 04:32:23 +00:00
|
|
|
mm1->gprs_pid = gprs_pid;
|
|
|
|
mm1->smsc_on = smsc_on;
|
|
|
|
mm1->smsc_off = smsc_off;
|
|
|
|
mm1->port = port;
|
|
|
|
mm1->interface = interface;
|
|
|
|
mm1->msisdn = msisdn;
|
|
|
|
|
|
|
|
mm1->unified_prefix = unified_prefix;
|
|
|
|
mm1->strip_prefixes = strip_prefixes;
|
|
|
|
|
|
|
|
mm1->qfs = qfs;
|
|
|
|
mm1->info = mmc;
|
|
|
|
mm1->requests = gwlist_create();
|
|
|
|
mm1->sender_alive = 0;
|
|
|
|
gwlist_add_producer(mm1->requests); /* so that when first listener starts, knows there is a consumer. */
|
|
|
|
mm1->h_tid = gwthread_create((gwthread_func_t *)handle_notify, mm1);
|
|
|
|
mm1->d_tid = gwthread_create((gwthread_func_t *)handle_mm1, mm1);
|
|
|
|
|
|
|
|
*data = mm1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void handle_notify(MM1Settings *mm1)
|
|
|
|
{
|
|
|
|
HTTPClient *client = NULL;
|
|
|
|
Octstr *ip = NULL, *url = NULL;
|
|
|
|
Octstr *body = NULL;
|
|
|
|
List *cgivars = NULL, *h = NULL;
|
|
|
|
|
|
|
|
while ((client = http_accept_request(mm1->port, &ip, &url, &h, &body, &cgivars)) != NULL) {
|
|
|
|
List *cgivar_ctypes = NULL;
|
|
|
|
Octstr *text, *rb = NULL, *s = NULL, *loc = NULL;
|
|
|
|
MmsMsg *m = NULL;
|
|
|
|
int hdrlen, status = HTTP_ACCEPTED, mtype;
|
|
|
|
List *mh = NULL, *to = gwlist_create(), *rh = http_create_empty_headers();
|
|
|
|
time_t expiryt = -1, deliveryt = -1;
|
|
|
|
Octstr *from = NULL, *subject = NULL, *otransid = NULL, *mmc_id = NULL;
|
|
|
|
Octstr *qdir;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
parse_cgivars(h, body, &cgivars, &cgivar_ctypes);
|
|
|
|
text = http_cgi_variable(cgivars, "text");
|
|
|
|
|
|
|
|
if (!text) {
|
|
|
|
rb = octstr_imm("mmsbox-mm1: missing 'text' CGI parameter!");
|
|
|
|
status = HTTP_NOT_FOUND;
|
|
|
|
goto loop;
|
|
|
|
}
|
|
|
|
/* now parse the MMS, determine what kind it is,
|
|
|
|
queue the fetch request or deal with it directly.
|
|
|
|
*/
|
|
|
|
hdrlen = octstr_get_char(text, 2);
|
|
|
|
if ((s = octstr_copy(text, 3 + hdrlen, octstr_len(text))) != NULL)
|
|
|
|
m = mms_frombinary(s, mm1->msisdn);
|
|
|
|
else
|
|
|
|
m = NULL;
|
|
|
|
|
|
|
|
if (m == NULL) {
|
|
|
|
rb = octstr_imm("mmsbox-mm1: mal-formed mms packet on interface!");
|
|
|
|
status = HTTP_FORBIDDEN;
|
|
|
|
goto loop;
|
|
|
|
} else
|
|
|
|
mms_msgdump(m, 1);
|
|
|
|
|
|
|
|
/* rest of this copied largely from EAIF code. */
|
|
|
|
mh = mms_message_headers(m);
|
|
|
|
mtype = mms_messagetype(m);
|
|
|
|
mms_collect_envdata_from_msgheaders(mh, &to, &subject,
|
|
|
|
&otransid, &expiryt, &deliveryt,
|
|
|
|
DEFAULT_EXPIRE, -1,
|
|
|
|
octstr_get_cstr(mm1->unified_prefix),
|
|
|
|
mm1->strip_prefixes);
|
|
|
|
from = http_header_value(mh, octstr_imm("From"));
|
|
|
|
|
|
|
|
qdir = get_mmsbox_queue_dir(from, to, mm1->info, &mmc_id); /* get routing info. */
|
|
|
|
switch (mtype) {
|
|
|
|
Octstr *qf;
|
|
|
|
Octstr *dlr_url, *status_value, *msgid;
|
|
|
|
List *rqh;
|
|
|
|
case MMS_MSGTYPE_DELIVERY_IND: /* notification of a delivery. */
|
|
|
|
case MMS_MSGTYPE_READ_ORIG_IND: /* message read. */
|
|
|
|
msgid = http_header_value(mh, octstr_imm("Message-ID"));
|
|
|
|
status_value = http_header_value(mh,
|
|
|
|
(mtype == MMS_MSGTYPE_DELIVERY_IND) ?
|
|
|
|
octstr_imm("X-Mms-Status") :
|
|
|
|
octstr_imm("X-Mms-Read-Status"));
|
|
|
|
|
|
|
|
rqh = http_create_empty_headers();
|
|
|
|
|
|
|
|
dlr_url = mmsbox_get_report_info(m, mm1->info, mmc_id,
|
|
|
|
(mtype == MMS_MSGTYPE_DELIVERY_IND) ?
|
|
|
|
"delivery-report" : "read-report",
|
2011-03-24 12:58:11 +00:00
|
|
|
status_value, rqh, NULL, 0, msgid);
|
2009-07-02 04:32:23 +00:00
|
|
|
|
|
|
|
qf = mm1->qfs->mms_queue_add(from, to, NULL,
|
|
|
|
mm1->info->id, mmc_id,
|
|
|
|
0, time(NULL) + default_msgexpiry, m, NULL,
|
|
|
|
NULL, NULL,
|
|
|
|
dlr_url, NULL,
|
|
|
|
rqh,
|
|
|
|
0,
|
|
|
|
octstr_get_cstr(qdir),
|
|
|
|
"MM7/MM1-IN",
|
|
|
|
octstr_imm(MM_NAME));
|
|
|
|
if (qf)
|
|
|
|
/* Log to access log */
|
|
|
|
mms_log((mtype == MMS_MSGTYPE_DELIVERY_IND) ? "Received DLR" : "Received RR",
|
|
|
|
from, to, -1, msgid, status_value, mm1->info->id,
|
|
|
|
"MMSBox", octstr_imm("MM1"), NULL);
|
|
|
|
else
|
|
|
|
status = HTTP_INTERNAL_SERVER_ERROR;
|
|
|
|
octstr_destroy(qf);
|
|
|
|
octstr_destroy(msgid);
|
|
|
|
octstr_destroy(dlr_url);
|
|
|
|
octstr_destroy(status_value);
|
|
|
|
http_destroy_headers(rqh);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MMS_MSGTYPE_NOTIFICATION_IND: /* notification of an incoming message. */
|
|
|
|
if ((loc = http_header_value(mh, octstr_imm("X-Mms-Content-Location"))) != NULL) {
|
|
|
|
MM1Request *r = gw_malloc(sizeof *r);
|
|
|
|
|
|
|
|
memset(r, 0, sizeof *r);
|
|
|
|
r->type = MM1_GET;
|
|
|
|
r->u.url = loc;
|
|
|
|
r->waiter_exists = 0;
|
|
|
|
loc = NULL;
|
|
|
|
|
|
|
|
gwlist_produce(mm1->requests, r);
|
|
|
|
} else
|
|
|
|
rb = octstr_format("mmsbox-mm1: notification with content-location??");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rb = octstr_format("mmsbox-mm1: unexpected message type: %s",
|
|
|
|
mms_message_type_to_cstr(mtype));
|
|
|
|
status = HTTP_NOT_FOUND;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
loop:
|
|
|
|
/* send reply. */
|
|
|
|
http_header_add(rh, "Content-Type", "text/plain");
|
|
|
|
http_send_reply(client, status, rh, rb ? rb : octstr_imm(""));
|
|
|
|
|
|
|
|
octstr_destroy(s);
|
|
|
|
octstr_destroy(ip);
|
|
|
|
octstr_destroy(url);
|
|
|
|
octstr_destroy(loc);
|
|
|
|
octstr_destroy(mmc_id);
|
|
|
|
octstr_destroy(from);
|
|
|
|
octstr_destroy(subject);
|
|
|
|
octstr_destroy(otransid);
|
|
|
|
octstr_destroy(body);
|
|
|
|
octstr_destroy(rb);
|
|
|
|
|
|
|
|
gwlist_destroy(to, (void *)octstr_destroy);
|
|
|
|
http_destroy_headers(h);
|
|
|
|
http_destroy_headers(rh);
|
|
|
|
http_destroy_headers(mh);
|
|
|
|
http_destroy_cgiargs(cgivars);
|
|
|
|
http_destroy_cgiargs(cgivar_ctypes);
|
|
|
|
mms_destroy(m);
|
|
|
|
}
|
|
|
|
|
|
|
|
mms_info(0, "mmsbox-mm1", NULL, "handle_notify exits");
|
|
|
|
gwlist_remove_producer(mm1->requests); /* cause consumers to shut down. */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static Octstr *send_msg(void *data, Octstr *from, Octstr *to,
|
2011-03-24 12:58:11 +00:00
|
|
|
Octstr *transid,
|
|
|
|
Octstr *linkedid, char *vasid, Octstr *service_code,
|
|
|
|
MmsMsg *m, List *hdrs, Octstr **err, int *retry)
|
2009-07-02 04:32:23 +00:00
|
|
|
{
|
|
|
|
MM1Request *r = gw_malloc(sizeof *r);
|
|
|
|
MM1Settings *s = data;
|
|
|
|
Octstr *id;
|
|
|
|
|
|
|
|
gw_assert(data);
|
|
|
|
gw_assert(m);
|
|
|
|
|
|
|
|
if (!s->sender_alive) {
|
|
|
|
*err = octstr_imm("internal error, mm1 notify not started!");
|
|
|
|
*retry = 1;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove the from address first of all, replace the to address as well */
|
|
|
|
mms_replace_header_value(m, "From", "#insert");
|
|
|
|
mms_replace_header_value(m, "To", octstr_get_cstr(to));
|
|
|
|
mms_remove_headers(m, "Message-ID");
|
|
|
|
|
|
|
|
r->u.m = m;
|
|
|
|
pthread_cond_init(&r->cond, NULL);
|
|
|
|
pthread_mutex_init(&r->mutex, NULL);
|
|
|
|
r->waiter_exists = 1;
|
|
|
|
r->type = MM1_PUSH;
|
|
|
|
r->result = NULL;
|
|
|
|
r->error = NULL;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&r->mutex); /* at pickup, must grab mutex before signalling. otherwise race condition.*/
|
|
|
|
|
|
|
|
gwlist_produce(s->requests, r);
|
|
|
|
|
|
|
|
pthread_cond_wait(&r->cond, &r->mutex);
|
|
|
|
|
|
|
|
*err = r->error;
|
|
|
|
|
|
|
|
id = r->result;
|
|
|
|
mms_info(0, "mmsbox-mm1", NULL, "sent message, type=%s, result=%s",
|
2011-03-24 12:58:11 +00:00
|
|
|
mms_message_type_to_cstr(mms_messagetype(m)), r->error ? octstr_get_cstr(r->error) : "(none)");
|
2009-07-02 04:32:23 +00:00
|
|
|
/* destroy the structure. */
|
2011-01-04 18:16:18 +00:00
|
|
|
if(r->error && (octstr_compare(r->error, octstr_imm("Error-service-denied")) == 0 ||
|
|
|
|
octstr_compare(r->error, octstr_imm("Error-permanent-failure")) == 0))
|
2011-03-24 12:58:11 +00:00
|
|
|
*retry = 0;
|
2011-01-04 18:16:18 +00:00
|
|
|
else
|
2011-03-24 12:58:11 +00:00
|
|
|
*retry = 1;
|
2009-07-02 04:32:23 +00:00
|
|
|
|
|
|
|
pthread_cond_destroy(&r->cond);
|
|
|
|
pthread_mutex_destroy(&r->mutex);
|
|
|
|
gw_free(r);
|
|
|
|
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
|
|
|
static long start_gprs(Octstr *cmd, Octstr *pid_cmd);
|
|
|
|
static Octstr *fetch_content(Octstr *url, Octstr *proxy, Octstr *body, int *hstatus);
|
|
|
|
static void handle_mm1(MM1Settings *mm1)
|
|
|
|
{
|
|
|
|
/* stop smsc, start GPRS, transact, stop GPRS, start SMSC. And so on. */
|
|
|
|
MM1Request *r;
|
2010-08-04 10:02:46 +00:00
|
|
|
|
2009-07-02 04:32:23 +00:00
|
|
|
mms_info(0, "mmsbox-mm1", NULL, "handle_mm1 started");
|
|
|
|
mm1->sender_alive++;
|
|
|
|
while ((r = gwlist_consume(mm1->requests)) != NULL) {
|
|
|
|
long n, pid = -1;
|
|
|
|
if (mm1->smsc_off) {
|
|
|
|
n = system(octstr_get_cstr(mm1->smsc_off));
|
|
|
|
gwthread_sleep(5); /* allow it to die. */
|
|
|
|
}
|
|
|
|
if (mm1->gprs_on)
|
|
|
|
pid = start_gprs(mm1->gprs_on, mm1->gprs_pid);
|
|
|
|
|
|
|
|
if (pid < 0) {
|
2011-03-24 12:58:11 +00:00
|
|
|
mms_warning(0, "mmsbox-mm1", NULL,
|
|
|
|
"Failed to start GPRS connection. waiting...");
|
2009-07-02 04:32:23 +00:00
|
|
|
gwthread_sleep(2);
|
|
|
|
goto kill_gprs;
|
|
|
|
} else
|
|
|
|
mms_info(0, "mmsbox-mm1", NULL, "start_gprs returned PID: %ld", pid);
|
|
|
|
|
|
|
|
do {
|
|
|
|
Octstr *body;
|
|
|
|
Octstr *url;
|
|
|
|
int hstatus = 0;
|
|
|
|
Octstr *ms;
|
|
|
|
MmsMsg *m;
|
|
|
|
int msize;
|
|
|
|
|
|
|
|
if (r->waiter_exists)
|
|
|
|
pthread_mutex_lock(&r->mutex); /* grab lock to avoid race condition */
|
|
|
|
|
|
|
|
body = (r->type == MM1_PUSH) ? mms_tobinary(r->u.m) : NULL;
|
|
|
|
url = (r->type == MM1_PUSH) ? mm1->mmsc_url : r->u.url;
|
|
|
|
ms = fetch_content(url, mm1->proxy, body, &hstatus);
|
|
|
|
msize = ms ? octstr_len(ms) : 0;
|
|
|
|
m = (hstatus == 0 && ms) ? mms_frombinary(ms, mm1->msisdn) : NULL;
|
|
|
|
|
|
|
|
if (r->type == MM1_GET) {
|
|
|
|
if (m == NULL)
|
|
|
|
mms_error(0, "mmsbox-mm1", NULL, "failed to fetch mms from URL: %s!",
|
2011-03-24 12:58:11 +00:00
|
|
|
octstr_get_cstr(url));
|
2009-07-02 04:32:23 +00:00
|
|
|
else {
|
|
|
|
List *mh = mms_message_headers(m), *to = gwlist_create();
|
|
|
|
Octstr *subject = NULL, *otransid = NULL, *msgid = NULL, *value;
|
|
|
|
Octstr *hfrom = mh ? http_header_value(mh, octstr_imm("From")) : octstr_imm("anon@anon");
|
|
|
|
Octstr *qf = NULL, *qdir = NULL, *mmc_id = NULL;
|
|
|
|
time_t expiryt = -1, deliveryt = -1;
|
|
|
|
int dlr;
|
|
|
|
|
|
|
|
/* we assume it is a true message (send_req|retrieve_conf) */
|
|
|
|
mms_collect_envdata_from_msgheaders(mh, &to, &subject,
|
|
|
|
&otransid, &expiryt, &deliveryt,
|
|
|
|
DEFAULT_EXPIRE, -1,
|
|
|
|
octstr_get_cstr(mm1->unified_prefix),
|
|
|
|
mm1->strip_prefixes);
|
|
|
|
|
|
|
|
msgid = http_header_value(mh, octstr_imm("Message-ID"));
|
|
|
|
value = http_header_value(mh, octstr_imm("X-Mms-Delivery-Report"));
|
|
|
|
if (value &&
|
|
|
|
octstr_case_compare(value, octstr_imm("Yes")) == 0)
|
|
|
|
dlr = 1;
|
|
|
|
else
|
|
|
|
dlr = 0;
|
|
|
|
octstr_destroy(value);
|
|
|
|
|
|
|
|
if (deliveryt < 0)
|
|
|
|
deliveryt = time(NULL);
|
|
|
|
|
|
|
|
if (expiryt < 0)
|
|
|
|
expiryt = time(NULL) + DEFAULT_EXPIRE;
|
|
|
|
|
|
|
|
if (hfrom == NULL)
|
|
|
|
hfrom = http_header_value(mh, octstr_imm("From"));
|
|
|
|
|
|
|
|
mms_remove_headers(m, "Bcc");
|
|
|
|
mms_remove_headers(m, "X-Mms-Delivery-Time");
|
|
|
|
mms_remove_headers(m, "X-Mms-Expiry");
|
|
|
|
mms_remove_headers(m, "X-Mms-Sender-Visibility");
|
|
|
|
|
|
|
|
qdir = get_mmsbox_queue_dir(hfrom, to, mm1->info, &mmc_id); /* get routing info. */
|
|
|
|
/* Save it, put message id in header, return. */
|
|
|
|
qf = qfs->mms_queue_add(hfrom, to, subject,
|
|
|
|
mm1->info->id, mmc_id,
|
|
|
|
deliveryt, expiryt, m, NULL,
|
|
|
|
NULL, NULL,
|
|
|
|
NULL, NULL,
|
|
|
|
NULL,
|
|
|
|
dlr,
|
|
|
|
octstr_get_cstr(qdir),
|
|
|
|
"MM7/MM1-IN",
|
|
|
|
octstr_imm(MM_NAME));
|
|
|
|
|
|
|
|
if (qf)
|
|
|
|
/* Log to access log */
|
|
|
|
mms_log("Received", hfrom, to, msize,
|
|
|
|
msgid, NULL, mm1->info->id, "MMSBox",octstr_imm("MM1"), NULL);
|
|
|
|
else
|
|
|
|
mms_error(0, "mmsbox-mm1", NULL, "failed to create queue entry for URL %s",
|
2011-03-24 12:58:11 +00:00
|
|
|
octstr_get_cstr(url));
|
2009-07-02 04:32:23 +00:00
|
|
|
|
|
|
|
if (otransid) { /* tell mmsc that we fetched fine. */
|
|
|
|
int _status;
|
|
|
|
MmsMsg *mresp = mms_notifyresp_ind(octstr_get_cstr(otransid),
|
|
|
|
mms_message_enc(m), "Retrieved", 1);
|
|
|
|
Octstr *sm = mms_tobinary(mresp);
|
|
|
|
Octstr *_x = fetch_content(mm1->mmsc_url, mm1->proxy,
|
|
|
|
sm, &_status);
|
|
|
|
|
|
|
|
octstr_destroy(_x);
|
|
|
|
octstr_destroy(sm);
|
|
|
|
mms_destroy(mresp);
|
|
|
|
}
|
|
|
|
gwlist_destroy(to, (gwlist_item_destructor_t *)octstr_destroy);
|
|
|
|
octstr_destroy(hfrom);
|
|
|
|
octstr_destroy(subject);
|
|
|
|
octstr_destroy(otransid);
|
|
|
|
octstr_destroy(msgid);
|
|
|
|
octstr_destroy(qf);
|
|
|
|
octstr_destroy(mmc_id);
|
|
|
|
|
|
|
|
http_destroy_headers(mh);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else if (r->type == MM1_PUSH) {
|
|
|
|
/* we expect a send-conf. */
|
2009-08-13 04:03:36 +00:00
|
|
|
if (ms) {
|
|
|
|
octstr_dump(ms, 0);
|
|
|
|
|
|
|
|
mms_msgdump(m, 1);
|
|
|
|
} else
|
|
|
|
mms_warning(0, "mmsbox-mm1", NULL,"No send-conf returned by operator");
|
|
|
|
|
2009-07-02 04:32:23 +00:00
|
|
|
if (m == NULL ||
|
2011-01-04 18:16:18 +00:00
|
|
|
(r->result = mms_get_header_value(m, octstr_imm("Message-ID"))) == NULL ||
|
|
|
|
octstr_compare(mms_get_header_value(m, octstr_imm("X-Mms-Response-Status")),
|
|
|
|
octstr_imm("Ok")) != 0
|
2011-03-24 12:58:11 +00:00
|
|
|
) {
|
2009-07-02 04:32:23 +00:00
|
|
|
Octstr *err = m ? mms_get_header_value(m, octstr_imm("X-Mms-Response-Text")) : NULL;
|
|
|
|
Octstr *status = m ? mms_get_header_value(m, octstr_imm("X-Mms-Response-Status")) : NULL;
|
2011-01-04 18:16:18 +00:00
|
|
|
if(status && (octstr_compare(status, octstr_imm("Error-service-denied")) == 0 ||
|
|
|
|
octstr_compare(status, octstr_imm("Error-permanent-failure")) == 0)) {
|
2011-03-24 12:58:11 +00:00
|
|
|
r->error = octstr_duplicate(status);
|
2011-01-04 18:16:18 +00:00
|
|
|
}
|
|
|
|
r->result = NULL; /* indicate failure to bearerbox */
|
2009-07-02 04:32:23 +00:00
|
|
|
mms_error(0, "mmsbox-mm1", NULL, "Sending failed: %s, %s!",
|
2011-03-24 12:58:11 +00:00
|
|
|
err ? octstr_get_cstr(err) : "(none)",
|
|
|
|
status ? octstr_get_cstr(status) : "(none)");
|
2009-07-02 04:32:23 +00:00
|
|
|
octstr_destroy(err);
|
|
|
|
octstr_destroy(status);
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
mms_error(0, "mmsbox-mm1", NULL, "unknown type: %d", r->type);
|
|
|
|
|
|
|
|
if (r->waiter_exists) {
|
|
|
|
pthread_mutex_unlock(&r->mutex);
|
|
|
|
pthread_cond_signal(&r->cond);
|
|
|
|
} else /* no waiter, so we free it ourselves. */
|
|
|
|
gw_free(r);
|
|
|
|
|
|
|
|
octstr_destroy(body);
|
|
|
|
octstr_destroy(ms);
|
|
|
|
mms_destroy(m);
|
2010-08-04 10:02:46 +00:00
|
|
|
r = NULL;
|
|
|
|
pid_t wp;
|
|
|
|
int st;
|
|
|
|
wp = waitpid(pid, &st, WNOHANG);
|
|
|
|
if(wp == pid && WIFEXITED(st)) {
|
2011-03-24 12:58:11 +00:00
|
|
|
mms_info(0, "mmsbox-mm1", NULL, "GPRS pid (%d) appears to be dead - quitting loop", pid);
|
|
|
|
goto after_gprs_dead;
|
2010-08-04 10:02:46 +00:00
|
|
|
}
|
2010-08-09 09:38:55 +00:00
|
|
|
gwthread_sleep(2); /* according to Piotr Isajew, this makes life better */
|
2010-08-04 10:02:46 +00:00
|
|
|
} while (gwlist_len(mm1->requests) > 0 &&
|
2009-07-02 04:32:23 +00:00
|
|
|
(r = gwlist_consume(mm1->requests)) != NULL);
|
|
|
|
|
|
|
|
kill_gprs:
|
2010-08-04 10:02:46 +00:00
|
|
|
if(r != NULL) {
|
2011-03-24 12:58:11 +00:00
|
|
|
if(r->waiter_exists) {
|
|
|
|
pthread_mutex_unlock(&r->mutex);
|
|
|
|
pthread_cond_signal(&r->cond);
|
|
|
|
} else{
|
|
|
|
gw_free(r);
|
|
|
|
}
|
2010-08-04 10:02:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
}
|
2011-01-12 09:47:14 +00:00
|
|
|
|
|
|
|
if (mm1->gprs_off) {
|
|
|
|
stop_gprs(mm1->gprs_off);
|
2011-03-24 12:58:11 +00:00
|
|
|
} else if (pid > 0) { /* stop GPRS, restart SMSC connection. */
|
2009-07-02 04:32:23 +00:00
|
|
|
int xkill, status;
|
|
|
|
pid_t wpid;
|
|
|
|
do {
|
|
|
|
xkill = kill(pid, SIGTERM);
|
|
|
|
mms_info(0, "mmsbox-mm1", NULL, "GPRS turned off returned: %d", xkill);
|
|
|
|
if (xkill < 0 && errno == ESRCH)
|
|
|
|
break;
|
|
|
|
wpid = waitpid(pid, &status, 0);
|
|
|
|
if (wpid == pid && WIFEXITED(status))
|
|
|
|
break;
|
|
|
|
else if (wpid < 0 && errno == ECHILD)
|
|
|
|
break;
|
|
|
|
} while (1);
|
|
|
|
gwthread_sleep(2);
|
|
|
|
}
|
2010-08-04 10:02:46 +00:00
|
|
|
after_gprs_dead:
|
2009-07-02 04:32:23 +00:00
|
|
|
if (mm1->smsc_on) {
|
|
|
|
system(octstr_get_cstr(mm1->smsc_on));
|
|
|
|
gwthread_sleep(5);
|
|
|
|
mms_info(0, "mmsbox-mm1", NULL, "SMSC turned on");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
mm1->sender_alive--;
|
|
|
|
mms_info(0, "mmsbox-mm1", NULL, "handle_mm1 exits");
|
|
|
|
}
|
|
|
|
|
|
|
|
static int close_mm1(void *data)
|
|
|
|
{
|
|
|
|
MM1Settings *s = data;
|
|
|
|
|
|
|
|
/* close the port, and all will die. */
|
|
|
|
http_close_port(s->port);
|
|
|
|
gwthread_sleep(2);
|
|
|
|
gwthread_join(s->h_tid);
|
|
|
|
gwthread_sleep(2);
|
|
|
|
gwthread_join(s->d_tid);
|
|
|
|
|
|
|
|
octstr_destroy(s->mmsc_url);
|
|
|
|
octstr_destroy(s->msisdn);
|
|
|
|
octstr_destroy(s->proxy);
|
|
|
|
octstr_destroy(s->gprs_on);
|
2011-01-12 09:47:14 +00:00
|
|
|
octstr_destroy(s->gprs_off);
|
2009-07-02 04:32:23 +00:00
|
|
|
octstr_destroy(s->gprs_pid);
|
|
|
|
octstr_destroy(s->smsc_on);
|
|
|
|
octstr_destroy(s->smsc_off);
|
|
|
|
octstr_destroy(s->interface);
|
|
|
|
|
|
|
|
gwlist_destroy(s->requests, NULL);
|
|
|
|
|
|
|
|
gw_free(s);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
MmsBoxMmscFuncs mmsc_funcs = {
|
|
|
|
open_mm1,
|
|
|
|
close_mm1,
|
|
|
|
send_msg
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#include <curl/curl.h>
|
|
|
|
|
|
|
|
|
|
|
|
static int write_octstr_data(void *buffer, size_t size, size_t nmemb, void *userp)
|
|
|
|
{
|
|
|
|
Octstr *out = userp;
|
|
|
|
|
|
|
|
octstr_append_data(out, buffer, size*nmemb);
|
2011-03-24 12:58:11 +00:00
|
|
|
mms_info(0, "mmsbox-mm1", NULL, "write_data called with nmemn=%ld, size=%ld",
|
|
|
|
nmemb, size);
|
2009-07-02 04:32:23 +00:00
|
|
|
return size*nmemb;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Octstr *fetch_content(Octstr *url, Octstr *proxy, Octstr *body, int *hstatus)
|
|
|
|
{
|
|
|
|
CURL *cl;
|
|
|
|
struct curl_slist *h = NULL;
|
|
|
|
char errbuf[512];
|
|
|
|
static int curl_inited = 0;
|
|
|
|
Octstr *s = octstr_create("");
|
|
|
|
|
|
|
|
if (curl_inited == 0) {
|
|
|
|
curl_global_init(CURL_GLOBAL_ALL);
|
|
|
|
curl_inited = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
cl = curl_easy_init();
|
|
|
|
curl_easy_setopt(cl, CURLOPT_URL, octstr_get_cstr(url));
|
|
|
|
if (proxy && octstr_len(proxy) > 0)
|
|
|
|
curl_easy_setopt(cl, CURLOPT_PROXY, octstr_get_cstr(proxy));
|
|
|
|
curl_easy_setopt(cl, CURLOPT_WRITEFUNCTION, write_octstr_data);
|
|
|
|
curl_easy_setopt(cl, CURLOPT_WRITEDATA, s);
|
|
|
|
curl_easy_setopt(cl, CURLOPT_NOSIGNAL, 1L);
|
2010-08-04 10:02:46 +00:00
|
|
|
curl_easy_setopt(cl, CURLOPT_TIMEOUT, 120L);
|
|
|
|
curl_easy_setopt(cl, CURLOPT_FORBID_REUSE, 1L);
|
|
|
|
curl_easy_setopt(cl, CURLOPT_CONNECTTIMEOUT, 40L);
|
2009-07-02 04:32:23 +00:00
|
|
|
|
|
|
|
h = curl_slist_append(h, "Accept: */*");
|
|
|
|
if (body) { /* POST. */
|
2010-08-04 10:02:46 +00:00
|
|
|
h = curl_slist_append(h, "Content-Type: application/vnd.wap.mms-message");
|
2011-03-24 12:58:11 +00:00
|
|
|
h = curl_slist_append(h, "User-Agent: Mozilla/5.0 (SymbianOS/9.4;U;"
|
|
|
|
"Series60/5.0 Nokia5800d-1/52.50.2008.24;"
|
|
|
|
"Profile/MIDP-2.1Configuration/CLDC-1.1 ) "
|
|
|
|
"AppleWebKit/413 (KHTML, like Gecko) "
|
|
|
|
"Safari/413");
|
2009-07-02 04:32:23 +00:00
|
|
|
curl_easy_setopt(cl, CURLOPT_POSTFIELDS, octstr_get_cstr(body));
|
|
|
|
curl_easy_setopt(cl, CURLOPT_POSTFIELDSIZE, octstr_len(body));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
curl_easy_setopt(cl, CURLOPT_HTTPHEADER, h);
|
|
|
|
curl_easy_setopt(cl, CURLOPT_ERRORBUFFER, errbuf);
|
|
|
|
|
|
|
|
*hstatus = curl_easy_perform(cl); /* post away! */
|
|
|
|
if (*hstatus != 0)
|
2011-03-24 12:58:11 +00:00
|
|
|
mms_error(0, "mmsbox-mm1", NULL, "failed to fetch/post content to host %s [proxy: %s] [http_status=%d] : %.256s",
|
|
|
|
octstr_get_cstr(url), octstr_len(proxy) > 0 ? octstr_get_cstr(proxy) : "n/a",
|
|
|
|
*hstatus, errbuf);
|
2009-07-02 04:32:23 +00:00
|
|
|
|
|
|
|
curl_slist_free_all(h); /* free the header list */
|
2011-03-24 12:58:11 +00:00
|
|
|
curl_easy_setopt(cl, CURLOPT_NOSIGNAL, 0L);
|
2009-07-02 04:32:23 +00:00
|
|
|
curl_easy_cleanup(cl);
|
|
|
|
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2011-01-12 09:47:14 +00:00
|
|
|
static void stop_gprs(Octstr *cmd)
|
|
|
|
{
|
2011-03-24 12:58:11 +00:00
|
|
|
pid_t pid = fork();
|
|
|
|
if (pid == 0) {
|
|
|
|
/* in child */
|
|
|
|
List *l = octstr_split_words(cmd);
|
|
|
|
int i, n = gwlist_len(l);
|
|
|
|
char **args = gw_malloc((n+1) * sizeof *args);
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
Octstr *x = gwlist_get(l, i);
|
|
|
|
args[i] = octstr_get_cstr(x);
|
|
|
|
printf("arg %d: %s\n", i, args[i]);
|
|
|
|
}
|
|
|
|
args[i] = NULL;
|
|
|
|
printf("Not reached: %d!", execvp(args[0], args));
|
|
|
|
}
|
2011-01-12 09:47:14 +00:00
|
|
|
}
|
|
|
|
|
2010-08-04 10:02:46 +00:00
|
|
|
#define MAX_GPRS_WAIT 80
|
2009-07-02 04:32:23 +00:00
|
|
|
#define GPRS_POLL 5
|
|
|
|
static long start_gprs(Octstr *cmd, Octstr *pid_cmd)
|
|
|
|
{
|
|
|
|
pid_t pid = fork();
|
|
|
|
|
|
|
|
if (pid > 0) { /* parent. */
|
|
|
|
int ct = 0;
|
|
|
|
do {
|
|
|
|
FILE *f;
|
|
|
|
long xpid = -1, cpid;
|
|
|
|
int status;
|
|
|
|
gwthread_sleep(GPRS_POLL); /* wait a little. */
|
|
|
|
if ((f = popen(octstr_get_cstr(pid_cmd), "r")) != NULL) {
|
|
|
|
fscanf(f, "%ld", &xpid);
|
|
|
|
pclose(f);
|
|
|
|
if (xpid >= 0)
|
|
|
|
return xpid;
|
|
|
|
}
|
|
|
|
cpid = waitpid(pid, &status, WNOHANG); /* also wait for the child. */
|
|
|
|
mms_info(0, "mmsbox-mm1", NULL, "waiting for connection: %d, pid=%ld cpid=%ld, ifexited=%d, exitstatus=%d",
|
2011-03-24 12:58:11 +00:00
|
|
|
ct, (long)pid, cpid, WIFEXITED(status), WEXITSTATUS(status));
|
2009-07-02 04:32:23 +00:00
|
|
|
if (cpid == pid &&
|
|
|
|
WIFEXITED(status))
|
2011-03-24 12:58:11 +00:00
|
|
|
return -1;
|
2009-07-02 04:32:23 +00:00
|
|
|
} while (GPRS_POLL*ct++ < MAX_GPRS_WAIT);
|
2010-08-04 10:02:46 +00:00
|
|
|
/* Timed out, but still need to wait for child pid, as
|
2011-03-24 12:58:11 +00:00
|
|
|
start-gprs script is still running and we don't need a
|
|
|
|
zombie */
|
2010-08-04 10:02:46 +00:00
|
|
|
pid_t rpid;
|
|
|
|
int st;
|
|
|
|
|
|
|
|
rpid = waitpid(pid, &st, 0);
|
|
|
|
mms_info(0, "mmsbox-mm1", NULL, "pid %d terminated", pid);
|
2009-07-02 04:32:23 +00:00
|
|
|
return -1;
|
2011-03-24 12:58:11 +00:00
|
|
|
} else if (pid == 0) { /* child. */
|
2009-07-02 04:32:23 +00:00
|
|
|
List *l = octstr_split_words(cmd);
|
|
|
|
int i, n = gwlist_len(l);
|
|
|
|
char **args = gw_malloc((n+1) * sizeof *args);
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
Octstr *x = gwlist_get(l, i);
|
|
|
|
args[i] = octstr_get_cstr(x);
|
|
|
|
printf("arg %d: %s\n", i, args[i]);
|
|
|
|
}
|
|
|
|
args[i] = NULL;
|
|
|
|
printf("Not reached: %d!", execvp(args[0], args));
|
|
|
|
} else
|
|
|
|
mms_error(0, "mmsbox-mm1", NULL, "failed to start process!");
|
|
|
|
return -1;
|
|
|
|
}
|