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

411 lines
13 KiB
C
Raw Permalink Normal View History

2005-03-10 08:01:02 +00:00
/*
2005-03-23 05:55:16 +00:00
* Mbuni - Open Source MMS Gateway
*
* MMS client sender: notifications/reports to clients via WAP Push,
* manages out-going messages.
*
2008-07-10 09:46:58 +00:00
* Copyright (C) 2003 - 2008, Digital Solutions Ltd. - http://www.dsmagic.com
2005-03-23 05:55:16 +00:00
*
* 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-10 08:01:02 +00:00
*/
#include "mmsc.h"
2008-07-09 04:40:35 +00:00
#include <errno.h>
2008-09-22 10:18:19 +00:00
#include <unistd.h>
2008-07-09 04:40:35 +00:00
#include <strings.h>
2005-03-10 08:01:02 +00:00
#define WAPPUSH_PORT 2948
2009-01-16 05:47:43 +00:00
static MmsEnvelope *update_env(MmsEnvelope *e, MmsEnvelopeTo *xto, int success)
2005-03-10 08:01:02 +00:00
{
time_t tnow = time(NULL);
2009-01-22 06:09:36 +00:00
if (success && xto &&
2009-05-06 05:54:51 +00:00
e->msgtype != MMS_MSGTYPE_SEND_REQ &&
e->msgtype != MMS_MSGTYPE_RETRIEVE_CONF)
xto->process = 0; /* No more processing, unless it is a SEND/RETRIEVE */
2009-01-22 06:09:36 +00:00
e->lasttry = tnow;
e->attempts++;
e->sendt = tnow + settings->send_back_off * e->attempts;
2008-12-24 19:00:30 +00:00
if (settings->qfs->mms_queue_update(e) == 1)
e = NULL;
2005-03-10 08:01:02 +00:00
2008-12-17 17:29:40 +00:00
return e;
2005-03-10 08:01:02 +00:00
}
2008-12-17 17:29:40 +00:00
static void do_mm1_push(Octstr *rcpt_to, int isphonenum, MmsEnvelope *e, MmsMsg *msg)
2005-03-10 08:01:02 +00:00
{
List *pheaders;
static unsigned char ct; /* Transaction counter -- do we need it? */
2008-12-17 17:29:40 +00:00
Octstr *to = NULL;
Octstr *pduhdr = octstr_create("");
Octstr *s = NULL;
2005-03-10 08:01:02 +00:00
if (!rcpt_to) {
2008-09-04 17:20:42 +00:00
mms_error(0, "MM1", NULL, "mobilesender: Queue entry %s has no recipient address!", e->xqfname);
2005-03-10 08:01:02 +00:00
goto done;
} else
to = octstr_duplicate(rcpt_to);
ct++;
2008-04-28 05:26:20 +00:00
octstr_append_char(pduhdr, ct); /* Pushd id */
octstr_append_char(pduhdr, 0x06); /* PUSH */
2005-03-10 08:01:02 +00:00
#if 1
octstr_append_char(pduhdr, 1 + 1 + 1);
octstr_append_char(pduhdr, 0xbe); /* content type. */
#else
octstr_append_char(pduhdr,
2009-02-09 08:48:56 +00:00
1 + 1 + strlen("application/vnd.wap.mms-message") + 1); /*header length. */
2005-03-10 08:01:02 +00:00
octstr_append_cstr(pduhdr, "application/vnd.wap.mms-message");
octstr_append_char(pduhdr, 0x0); /* string terminator. */
#endif
2008-04-28 05:26:20 +00:00
octstr_append_char(pduhdr, 0xaf); /* push application ID header and value follows. */
2005-03-10 08:01:02 +00:00
octstr_append_char(pduhdr, 0x84); /* ... */
s = mms_tobinary(msg);
if (isphonenum) {
2008-12-17 17:29:40 +00:00
Octstr *url = octstr_format("%S&text=%E%E&to=%E&udh=%%06%%05%%04%%0B%%84%%23%%F0",
settings->sendsms_url, pduhdr, s, to);
int status;
List *rph = NULL;
Octstr *rbody = NULL;
MmsEnvelopeTo *xto = gwlist_get(e->to, 0);
2005-03-10 08:01:02 +00:00
pheaders = http_create_empty_headers();
http_header_add(pheaders, "Connection", "close");
http_header_add(pheaders, "User-Agent", MM_NAME "/" MMSC_VERSION);
2005-03-10 08:01:02 +00:00
2008-12-17 17:29:40 +00:00
if ((status = mms_url_fetch_content(HTTP_METHOD_GET, url, pheaders, NULL, &rph, &rbody)) < 0 ||
http_status_class(status) != HTTP_STATUS_SUCCESSFUL) {
mms_error(0, "MM1", NULL, " Push[%s] from %s, to %s, failed, HTTP code => %d", e->xqfname,
octstr_get_cstr(e->from), octstr_get_cstr(to), status);
2009-01-16 05:47:43 +00:00
e = update_env(e,xto,0);
2008-12-17 17:29:40 +00:00
} else { /* Successful push. */
mms_log2("Notify", octstr_imm("system"), to,
-1, e ? e->msgId : NULL, NULL, NULL, "MM1", NULL,NULL);
2009-01-16 05:47:43 +00:00
e = update_env(e, xto, 1);
2008-12-17 17:29:40 +00:00
}
2005-03-10 08:01:02 +00:00
http_destroy_headers(pheaders);
2008-12-17 17:29:40 +00:00
http_destroy_headers(rph);
octstr_destroy(rbody);
2005-03-10 08:01:02 +00:00
octstr_destroy(url);
} else { /* An IP Address: Send packet, forget. */
Octstr *addr = udp_create_address(to, WAPPUSH_PORT);
int sock = udp_client_socket();
2009-01-22 06:09:36 +00:00
MmsEnvelopeTo *xto = gwlist_get(e->to,0);
2005-03-10 08:01:02 +00:00
if (sock > 0) {
octstr_append(pduhdr, s);
#if 0
octstr_dump(pduhdr, 0);
#endif
2005-03-10 08:01:02 +00:00
udp_sendto(sock, pduhdr, addr);
close(sock); /* ?? */
mms_log2("Notify", octstr_imm("system"), to,
-1, e ? e->msgId : NULL,
2005-03-21 16:11:51 +00:00
NULL, NULL, "MM1", NULL,NULL);
2009-01-16 05:47:43 +00:00
e = update_env(e, xto, 1);
2005-03-10 08:01:02 +00:00
} else {
2009-01-22 06:09:36 +00:00
e = update_env(e, xto, 0);
mms_error(0, "MM1", NULL, "push to %s:%d failed: %s",
octstr_get_cstr(to), WAPPUSH_PORT, strerror(errno));
2005-03-10 08:01:02 +00:00
}
octstr_destroy(addr);
}
done:
2007-09-11 09:56:24 +00:00
octstr_destroy(to);
octstr_destroy(pduhdr);
octstr_destroy(s);
2005-03-10 08:01:02 +00:00
2008-12-17 17:29:40 +00:00
if (e)
settings->qfs->mms_queue_free_env(e);
2005-03-10 08:01:02 +00:00
}
static int sendNotify(MmsEnvelope *e)
{
Octstr *to;
2008-12-24 19:00:30 +00:00
MmsMsg *smsg = NULL;
MmsEnvelopeTo *xto = gwlist_get(e->to, 0);
2005-03-10 08:01:02 +00:00
Octstr *err = NULL;
time_t tnow = time(NULL);
int j, k, len;
Octstr *phonenum = NULL, *rcpt_ip = NULL, *msgId, *from, *fromproxy;
int mtype, msize;
int res = MMS_SEND_OK, dlr;
time_t expiryt;
char *prov_notify_event = NULL;
char *rtype = NULL;
2008-12-17 17:29:40 +00:00
2009-02-16 05:55:47 +00:00
#if 0 /* ... because we don't want fetched messages sticking around in queue forever */
if (e->lastaccess != 0) { /* This message has been fetched at least once, no more signals. */
2009-02-16 05:55:47 +00:00
2008-09-04 17:20:42 +00:00
mms_info(0, "MM1", NULL, "Message [ID: %s] fetched/touched at least once. Skipping",
e->xqfname);
2007-08-20 11:49:30 +00:00
return settings->qfs->mms_queue_update(e);
2005-03-10 08:01:02 +00:00
}
2009-02-16 05:55:47 +00:00
#endif
2005-03-10 08:01:02 +00:00
if (!xto) {
2008-09-04 17:20:42 +00:00
mms_error(0, "MM1", NULL, "mobilesender: Queue entry %s with no recipients!",
e->xqfname);
2005-03-10 08:01:02 +00:00
return 0;
}
to = octstr_duplicate(xto->rcpt);
expiryt = e->expiryt;
msgId = e->msgId ? octstr_duplicate(e->msgId) : NULL;
from = octstr_duplicate(e->from);
fromproxy = e->fromproxy ? octstr_duplicate(e->fromproxy) : NULL;
msize = e->msize;
dlr = e->dlr;
2008-12-24 19:00:30 +00:00
mtype = e->msgtype;
2005-03-10 08:01:02 +00:00
if (e->expiryt != 0 && /* Handle message expiry. */
e->expiryt < tnow) {
2009-05-06 07:24:57 +00:00
err = octstr_format("MM1 error: Message expired while sending to %S!", to);
2005-03-10 08:01:02 +00:00
res = MMS_SEND_ERROR_FATAL;
prov_notify_event = "failedfetch";
rtype = "Expired";
goto done;
2009-05-06 07:51:53 +00:00
} else if (e->attempts >= settings->mm1_maxsendattempts) {
2009-05-06 07:24:57 +00:00
err = octstr_format("MM1: Maximum delivery attempts [%d] to %S reached. Delivery suspended!",
e->attempts, to);
res = MMS_SEND_OK;
2005-03-10 08:01:02 +00:00
2009-05-06 07:24:57 +00:00
e->sendt = e->expiryt + 1; /* no retry until expiry */
if (settings->qfs->mms_queue_update(e) != 1)
settings->qfs->mms_queue_free_env(e);
e = NULL;
2009-02-16 05:55:47 +00:00
goto done;
2009-05-06 07:24:57 +00:00
2009-02-16 05:55:47 +00:00
} else if (e->lastaccess != 0) {
e->sendt = e->expiryt + 1;
res = MMS_SEND_OK;
err = octstr_create("Skipped");
mms_info(0, "MM1", NULL, "Message [ID: %s] fetched/touched at least once. Skipping",
e->xqfname);
if (settings->qfs->mms_queue_update(e) != 1)
settings->qfs->mms_queue_free_env(e);
e = NULL;
2005-03-10 08:01:02 +00:00
goto done;
}
2009-02-16 05:55:47 +00:00
2005-03-10 08:01:02 +00:00
j = octstr_case_search(to, octstr_imm("/TYPE=PLMN"), 0);
k = octstr_case_search(to, octstr_imm("/TYPE=IPv"), 0);
len = octstr_len(to);
if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == len) { /* A proper number. */
phonenum = octstr_copy(to, 0, j);
2008-05-05 19:29:49 +00:00
mms_normalize_phonenum(&phonenum,
octstr_get_cstr(settings->unified_prefix),
settings->strip_prefixes);
2009-01-22 06:09:36 +00:00
} else if (k > 0 && k + sizeof "/TYPE=IPv" == len)
2005-03-10 08:01:02 +00:00
rcpt_ip = octstr_copy(to, 0, k);
else {
/* We only handle phone numbers here. */
err = octstr_format("Unexpected recipient %s in MT queue!", octstr_get_cstr(to));
res = MMS_SEND_ERROR_FATAL;
goto done;
}
/* For phone, getting here means the message can be delivered. So:
* - Check whether the recipient is provisioned, if not, wait (script called will queue creation req)
* - If the recipient can't take MMS, then send SMS.
*/
/* We handle two types of requests: send and delivery/read notifications.
* other types of messages cannot possibly be in this queue!
*/
if (mtype == MMS_MSGTYPE_SEND_REQ ||
mtype == MMS_MSGTYPE_RETRIEVE_CONF) {
Octstr *url, *transid;
if (phonenum) {
int send_ind = mms_ind_send(settings->prov_getstatus, phonenum);
if (send_ind < 0 &&
settings->notify_unprovisioned)
send_ind = 0;
2005-03-10 08:01:02 +00:00
if (send_ind < 0) { /* That is, recipient is not (yet) provisioned. */
res = MMS_SEND_ERROR_TRANSIENT;
err = octstr_format("%S is not provisioned for MMS reception, delivery deferred!",
phonenum);
/* Do not increase delivery attempts counter. */
e->lasttry = tnow;
e->sendt = e->lasttry + settings->send_back_off * (1 + e->attempts);
2007-08-20 11:49:30 +00:00
if (settings->qfs->mms_queue_update(e) == 1)
2005-03-10 08:01:02 +00:00
e = NULL; /* Queue entry gone. */
else
2007-08-20 11:49:30 +00:00
settings->qfs->mms_queue_free_env(e);
2005-03-10 08:01:02 +00:00
goto done;
} else if (send_ind == 0) { /* provisioned but does not support */
Octstr *s = octstr_format(octstr_get_cstr(settings->mms_notify_txt),
from);
if (settings->notify_unprovisioned && s && octstr_len(s) > 0) { /* Only send if the string was set. */
2008-12-17 17:29:40 +00:00
List *pheaders = http_create_empty_headers(), *rph = NULL;
Octstr *rbody = NULL;
int status;
2008-12-17 17:29:40 +00:00
url = octstr_format("%S&text=%E&to=%E",settings->sendsms_url,s, phonenum);
http_header_add(pheaders, "Connection", "close");
http_header_add(pheaders, "User-Agent", MM_NAME "/" VERSION);
2008-12-17 17:29:40 +00:00
if ((status = mms_url_fetch_content(HTTP_METHOD_GET, url,
pheaders, NULL, &rph, &rbody)) <0 ||
http_status_class(status) != HTTP_STATUS_SUCCESSFUL)
mms_error(0, "MM1", NULL, "Notify unprovisioned url fetch failed => %d", status);
http_destroy_headers(pheaders);
2008-12-17 17:29:40 +00:00
http_destroy_headers(rph);
octstr_destroy(url);
2008-12-17 17:29:40 +00:00
octstr_destroy(rbody);
}
octstr_destroy(s);
2005-03-10 08:01:02 +00:00
res = MMS_SEND_OK;
err = octstr_imm("No MMS Ind support, sent SMS instead");
xto->process = 0; /* No more processing. */
2007-08-20 11:49:30 +00:00
if (settings->qfs->mms_queue_update(e) == 1)
2005-03-10 08:01:02 +00:00
e = NULL;
else
2007-08-20 11:49:30 +00:00
settings->qfs->mms_queue_free_env(e);
2005-03-10 08:01:02 +00:00
goto done;
}
2005-03-10 08:01:02 +00:00
}
/* To get here means we can send Ind. */
url = mms_makefetchurl(e->xqfname, e->token, MMS_LOC_MQUEUE,
2007-09-10 12:04:49 +00:00
phonenum ? phonenum : to,
2005-03-10 08:01:02 +00:00
settings);
2008-09-04 17:20:42 +00:00
mms_info(0, "MM1", NULL, "Preparing to notify client to fetch message at URL: %s",
2008-07-10 09:46:58 +00:00
octstr_get_cstr(url));
transid = mms_maketransid(e->xqfname, settings->host_alias);
2005-03-10 08:01:02 +00:00
2008-12-24 19:00:30 +00:00
smsg = mms_notification(e->from, e->subject, e->mclass, e->msize, url, transid,
2005-03-10 08:01:02 +00:00
e->expiryt ? e->expiryt :
tnow + settings->default_msgexpiry,
settings->optimize_notification_size);
2005-03-10 08:01:02 +00:00
octstr_destroy(transid);
octstr_destroy(url);
} else if (mtype == MMS_MSGTYPE_DELIVERY_IND ||
mtype == MMS_MSGTYPE_READ_ORIG_IND)
2008-12-24 19:00:30 +00:00
smsg = settings->qfs->mms_queue_getdata(e);
2005-03-10 08:01:02 +00:00
else {
2009-01-22 06:09:36 +00:00
mms_error(0, "MM1", NULL, "Unexpected message type [%s] for [%s] found in MT queue!",
2005-03-10 08:01:02 +00:00
mms_message_type_to_cstr(mtype), octstr_get_cstr(to));
res = MMS_SEND_ERROR_FATAL;
goto done;
}
2008-12-17 17:29:40 +00:00
if (smsg) {
do_mm1_push(phonenum ? phonenum : rcpt_ip,
phonenum ? 1 : 0,
e, smsg); /* Don't touch 'e' after this point. It is gone */
e = NULL;
}
2005-03-10 08:01:02 +00:00
2008-12-24 19:00:30 +00:00
if (smsg)
2005-03-10 08:01:02 +00:00
mms_destroy(smsg);
done:
2008-12-17 17:29:40 +00:00
if (e != NULL &&
err != NULL &&
res != MMS_SEND_ERROR_TRANSIENT && dlr) { /* If there was a report request and this is a legit error
* queue it.
*/
2008-08-06 17:45:08 +00:00
MmsMsg *m = mms_deliveryreport(msgId, to, e->from, tnow,
2005-03-10 08:01:02 +00:00
rtype ? octstr_imm(rtype) :
octstr_imm("Indeterminate"));
List *l = gwlist_create();
2005-03-10 08:01:02 +00:00
Octstr *res;
gwlist_append(l, from);
2005-03-10 08:01:02 +00:00
/* Add to queue, switch via proxy to be from proxy. */
2007-08-20 11:49:30 +00:00
res = settings->qfs->mms_queue_add(to ? to : settings->system_user, l, err,
2008-06-24 10:01:03 +00:00
NULL, fromproxy,
tnow, tnow+settings->default_msgexpiry, m, NULL,
NULL, NULL,
NULL, NULL,
NULL,
0,
2009-12-01 05:15:45 +00:00
octstr_get_cstr(settings->global_queuedir),
2008-06-24 10:01:03 +00:00
"MM2",
settings->host_alias);
gwlist_destroy(l, NULL);
2005-03-10 08:01:02 +00:00
mms_destroy(m);
2008-12-17 17:29:40 +00:00
octstr_destroy(res);
2005-03-10 08:01:02 +00:00
}
/* Write to log */
2010-05-26 10:36:27 +00:00
mms_info(0, "MM1", NULL, "%s Mobile Queue MMS Send Notify: From=%s, to=%s, msgsize=%d, reason=%s. Processed in %d secs",
2009-01-22 06:09:36 +00:00
SEND_ERROR_STR(res),
octstr_get_cstr(from), octstr_get_cstr(to), msize,
2008-12-17 17:29:40 +00:00
err ? octstr_get_cstr(err) : "",
(int)(time(NULL) - tnow));
2005-03-10 08:01:02 +00:00
2009-05-06 07:24:57 +00:00
if (xto && e) {
if (res == MMS_SEND_ERROR_FATAL)
xto->process = 0; /* No more attempts to deliver, delete this. */
2007-08-20 11:49:30 +00:00
if (settings->qfs->mms_queue_update(e) == 1)
2005-03-10 08:01:02 +00:00
e = NULL; /* Queue entry gone. */
else
2007-08-20 11:49:30 +00:00
settings->qfs->mms_queue_free_env(e);
2005-03-10 08:01:02 +00:00
} /* Else queue will be updated/freed elsewhere. */
if (prov_notify_event)
notify_prov_server(octstr_get_cstr(settings->prov_notify),
to ? octstr_get_cstr(to) : "unknown",
prov_notify_event,
rtype ? rtype : "",
2007-08-08 05:38:20 +00:00
e ? e->msgId : NULL, NULL, NULL);
2008-12-17 17:29:40 +00:00
2008-07-09 04:40:35 +00:00
octstr_destroy(phonenum);
octstr_destroy(rcpt_ip);
2005-03-10 08:01:02 +00:00
octstr_destroy(to);
2008-07-09 04:40:35 +00:00
octstr_destroy(msgId);
octstr_destroy(fromproxy);
2005-03-10 08:01:02 +00:00
octstr_destroy(from);
2008-07-09 04:40:35 +00:00
octstr_destroy(err);
2005-03-10 08:01:02 +00:00
2008-12-17 17:29:40 +00:00
return 1; /* Tell caller we dealt with envelope */
2005-03-10 08:01:02 +00:00
}
2010-05-26 10:36:27 +00:00
void mbuni_mm1_queue_runner(volatile sig_atomic_t *rstop)
2005-03-10 08:01:02 +00:00
{
2007-08-20 11:49:30 +00:00
settings->qfs->mms_queue_run(octstr_get_cstr(settings->mm1_queuedir),
2009-05-06 05:38:41 +00:00
sendNotify, settings->mm1_queue_interval, settings->maxthreads, rstop);
2008-09-22 10:18:19 +00:00
gwthread_sleep(2); /* Wait for it to die. */
2005-04-15 05:14:05 +00:00
return;
2005-03-10 08:01:02 +00:00
}