diff --git a/mbuni/misc-patches/mbuni-kannel-patch-full b/mbuni/misc-patches/mbuni-kannel-patch-full index ca0ebb2..225057e 100644 --- a/mbuni/misc-patches/mbuni-kannel-patch-full +++ b/mbuni/misc-patches/mbuni-kannel-patch-full @@ -717,8 +717,8 @@ diff -Naur gateway-1.4.0/gw/xml_shared.h gateway/gw/xml_shared.h /* diff -Naur gateway-1.4.0/gwlib/cfg.def gateway/gwlib/cfg.def --- gateway-1.4.0/gwlib/cfg.def 2004-06-28 18:18:35.000000000 +0300 -+++ gateway/gwlib/cfg.def 2005-09-02 13:50:06.000000000 +0300 -@@ -544,6 +544,106 @@ ++++ gateway/gwlib/cfg.def 2005-09-05 11:30:55.000000000 +0300 +@@ -544,6 +544,113 @@ OCTSTR(unified-prefix) ) @@ -792,6 +792,8 @@ diff -Naur gateway-1.4.0/gwlib/cfg.def gateway/gwlib/cfg.def + OCTSTR(username) + OCTSTR(password) + OCTSTR(faked-sender) ++ OCTSTR(delivery-report-url) ++ OCTSTR(read-report-url) +) + +MULTI_GROUP(mmsc, @@ -800,6 +802,10 @@ diff -Naur gateway-1.4.0/gwlib/cfg.def gateway/gwlib/cfg.def + OCTSTR(incoming-username) + OCTSTR(incoming-password) + OCTSTR(incoming-port) ++ OCTSTR(allow-ip) ++ OCTSTR(deny-ip) ++ OCTSTR(allowed-prefix) ++ OCTSTR(denied-prefix) + OCTSTR(incoming-port-ssl) + OCTSTR(max-throughput) + OCTSTR(type) @@ -818,6 +824,7 @@ diff -Naur gateway-1.4.0/gwlib/cfg.def gateway/gwlib/cfg.def + OCTSTR(accept-x-mbuni-headers) + OCTSTR(assume-plain-text) + OCTSTR(accepted-mmscs) ++ OCTSTR(denied-mmscs) + OCTSTR(keyword) + OCTSTR(aliases) + OCTSTR(http-post-parameters) diff --git a/mbuni/mmlib/mms_mm7soap.c b/mbuni/mmlib/mms_mm7soap.c index 8f51c1d..cacca86 100644 --- a/mbuni/mmlib/mms_mm7soap.c +++ b/mbuni/mmlib/mms_mm7soap.c @@ -847,7 +847,9 @@ static MSoapMsg_t *mm7_soap_create(int msgtype, Octstr *otransid) } MSoapMsg_t *mm7_mmsmsg_to_soap(MmsMsg *msg, Octstr *from, List *xto, - Octstr *transid, Octstr *serverID) + Octstr *transid, Octstr *srvcode, + int isclientside, + char *vaspid, char *vasid) { int mtype = mms_messagetype(msg); MSoapMsg_t *m = NULL; @@ -859,7 +861,8 @@ MSoapMsg_t *mm7_mmsmsg_to_soap(MmsMsg *msg, Octstr *from, List *xto, switch(mtype) { case MMS_MSGTYPE_SEND_REQ: case MMS_MSGTYPE_RETRIEVE_CONF: - m = mm7_soap_create(MM7_TAG_DeliverReq, transid); + m = mm7_soap_create(isclientside ? MM7_TAG_SubmitReq : MM7_TAG_DeliverReq, + transid); m->msg = mms_tomime(msg,1); for (i = 0, n = xto ? list_len(xto) : 0; i < n; i++) { /* Add recipients. */ @@ -869,10 +872,47 @@ MSoapMsg_t *mm7_mmsmsg_to_soap(MmsMsg *msg, Octstr *from, List *xto, octstr_destroy(xx); } - if (serverID) - http_header_add(m->envelope, "MMSRelayServerID", octstr_get_cstr(serverID)); + if (srvcode) + http_header_add(m->envelope, + isclientside ? "ServiceCode" : "MMSRelayServerID", + octstr_get_cstr(srvcode)); + http_header_add(m->envelope, "LinkedID", octstr_get_cstr(transid)); - http_header_add(m->envelope, "Sender", octstr_get_cstr(xfrom)); + http_header_add(m->envelope, + isclientside ? "SenderAddress" : "Sender", + octstr_get_cstr(xfrom)); + + if (isclientside) { + if (vaspid) + http_header_add(m->envelope, "VASPID", vaspid); + if (vasid) + http_header_add(m->envelope, "VASID", vaspid); + + if ((s = mms_get_header_value(msg, octstr_imm("X-Mms-Message-Class"))) != NULL) { + http_header_add(m->envelope, "MessageClass", octstr_get_cstr(s)); + octstr_destroy(s); + } + + if ((s = mms_get_header_value(msg, octstr_imm("X-Mms-Expiry"))) != NULL) { + http_header_add(m->envelope, "ExpiryDate", octstr_get_cstr(s)); + octstr_destroy(s); + } + + if ((s = mms_get_header_value(msg, octstr_imm("X-Mms-Delivery-Report"))) != NULL) { + char *val = (octstr_case_compare(s, octstr_imm("Yes")) == 0) ? + "true" : "false"; + http_header_add(m->envelope, "DeliveryReport", val); + octstr_destroy(s); + } + + if ((s = mms_get_header_value(msg, octstr_imm("X-Mms-Read-Report"))) != NULL) { + char *val = (octstr_case_compare(s, octstr_imm("Yes")) == 0) ? + "true" : "false"; + http_header_add(m->envelope, "ReadReply", val); + octstr_destroy(s); + } + + } if ((s = mms_get_header_value(msg, octstr_imm("X-Mms-Priority"))) != NULL) { http_header_add(m->envelope, "Priority", octstr_get_cstr(s)); diff --git a/mbuni/mmlib/mms_mm7soap.h b/mbuni/mmlib/mms_mm7soap.h index 981da87..575fd1e 100644 --- a/mbuni/mmlib/mms_mm7soap.h +++ b/mbuni/mmlib/mms_mm7soap.h @@ -39,7 +39,9 @@ extern void mm7_soap_destroy(MSoapMsg_t *m); /* Convert a message to a SOAP message. */ MSoapMsg_t *mm7_mmsmsg_to_soap(MmsMsg *msg, Octstr *from, List *xto, - Octstr *transid, Octstr *serverID); + Octstr *transid, Octstr *srvcode, + int isclientside, + char *vaspid, char *vasid); MSoapMsg_t *mm7_make_resp(MSoapMsg_t *mreq, int status, Octstr *msgid); /* Return the header value for some header. */ Octstr *mm7_soap_header_value(MSoapMsg_t *m, Octstr *header); diff --git a/mbuni/mmlib/mms_mmbox.c b/mbuni/mmlib/mms_mmbox.c index 79f282e..2ed5f7e 100644 --- a/mbuni/mmlib/mms_mmbox.c +++ b/mbuni/mmlib/mms_mmbox.c @@ -35,17 +35,6 @@ #define ITEM_DEL 2 #define ITEM_MOD 3 -static unsigned long hash(char *s) -{ - unsigned h = 0; - - while (*s) { - unsigned int ch = tolower(*s); - s++; - h += ((unsigned)(ch) << 4) + 1249; - } - return h; -} /* Initialise the root of the mmbox. Should be called once from load settings. */ @@ -82,7 +71,7 @@ int mmbox_root_init(char *mmbox_root) static Octstr *user_mmbox_dir(char *mmbox_root, char *userid) { - unsigned long h = hash(userid); + unsigned long h = _mshash(userid); char d1[2], d2[3], fbuf[512]; Octstr *t, *s; diff --git a/mbuni/mmlib/mms_queue.c b/mbuni/mmlib/mms_queue.c index 6f74c27..8036c64 100644 --- a/mbuni/mmlib/mms_queue.c +++ b/mbuni/mmlib/mms_queue.c @@ -89,6 +89,8 @@ static int free_envelope(MmsEnvelope *e, int removefromqueue); * M - Application specific data (string) * V - VASID -- from VASP * v - vasid -- from VASP + * U - url1 -- e.g. for delivery report + * u - url2 -- e.g. for read report */ @@ -267,6 +269,15 @@ MmsEnvelope *mms_queue_readenvelope(char *qf, char *mms_queuedir, int shouldbloc case 'v': e->vasid = octstr_create(res); break; + + case 'U': + e->url1 = octstr_create(res); + break; + + case 'u': + e->url2 = octstr_create(res); + break; + case '.': okfile = 1; break; @@ -412,6 +423,11 @@ static int writeenvelope(MmsEnvelope *e, int newenv) if (e->vasid) _putline(fd, "v", octstr_get_cstr(e->vasid)); + if (e->url1) + _putline(fd, "U", octstr_get_cstr(e->url1)); + + if (e->url2) + _putline(fd, "u", octstr_get_cstr(e->url2)); if (e->dlr) _putline(fd, "r", "Yes"); @@ -602,6 +618,7 @@ Octstr *mms_queue_add(Octstr *from, List *to, Octstr *fromproxy, Octstr *viaproxy, time_t senddate, time_t expirydate, MmsMsg *m, Octstr *token, Octstr *vaspid, Octstr *vasid, + Octstr *url1, Octstr *url2, int dlr, char *directory, Octstr *mmscname) { @@ -652,6 +669,8 @@ Octstr *mms_queue_add(Octstr *from, List *to, e->token = token; e->vaspid = vaspid; e->vasid = vasid; + e->url1 = url1; + e->url2 = url2; e->dlr = dlr; e->bill.billed = 0; @@ -702,12 +721,14 @@ Octstr *mms_queue_add(Octstr *from, List *to, gw_free(to); } list_destroy(e->to, NULL); - gw_free(e); + + gw_free(e); /* Free struct only, caller responsible for arguments. */ + octstr_destroy(ms); octstr_destroy(msgid); + if (xfrom) octstr_destroy(xfrom); - return res; } @@ -741,6 +762,18 @@ static int free_envelope(MmsEnvelope *e, int removefromqueue) if (e->subject) octstr_destroy(e->subject); + if (e->vaspid) + octstr_destroy(e->vaspid); + + if (e->vasid) + octstr_destroy(e->vasid); + + if (e->url1) + octstr_destroy(e->url1); + + if (e->url2) + octstr_destroy(e->url2); + if (removefromqueue) { char fname[2*QFNAMEMAX]; diff --git a/mbuni/mmlib/mms_queue.h b/mbuni/mmlib/mms_queue.h index 594c41a..004e9c8 100644 --- a/mbuni/mmlib/mms_queue.h +++ b/mbuni/mmlib/mms_queue.h @@ -34,9 +34,12 @@ typedef struct MmsEnvelope { Octstr *from; /* from address. */ Octstr *vaspid; /* VASPID (if any) */ - Octstr *vasid; /* VASID (if any) */ - - List *to; /* List of recipients: MmsEnvelopeTo */ + Octstr *vasid; /* VASID (if any) */ + + Octstr *url1; /* Generic URLs (2) associated with message. */ + Octstr *url2; + + List *to; /* List of recipients: MmsEnvelopeTo */ Octstr *subject; /* Message subject (if any). */ @@ -60,6 +63,10 @@ typedef struct MmsEnvelope { Octstr *mdata; /* Generic string data used by any interface. */ Octstr *fromproxy; /* Which proxy sent us this message.*/ Octstr *viaproxy; /* Which proxy must we send this message through. */ + + void *_x; /* Generic storage field used by module clients. */ + + /* DO NOT MODIFY ANYTHING BEYOND THIS POINT. */ struct { /* Name of the queue file, pointer to it (locked). DO NOT USE THESE! */ char name[QFNAMEMAX]; /* Name of the file. */ char dir[QFNAMEMAX]; /* Directory in which file is .*/ @@ -82,6 +89,7 @@ extern Octstr *mms_queue_add(Octstr *from, List *to, Octstr *fromproxy, Octstr *viaproxy, time_t senddate, time_t expirydate, MmsMsg *m, Octstr *token, Octstr *vaspid, Octstr *vasid, + Octstr *url1, Octstr *url2, int dlr, char *directory, Octstr *mmscname); diff --git a/mbuni/mmlib/mms_strings.def b/mbuni/mmlib/mms_strings.def index 66c3a5b..0f93c77 100644 --- a/mbuni/mmlib/mms_strings.def +++ b/mbuni/mmlib/mms_strings.def @@ -253,7 +253,6 @@ VNSTRING(MM7_5, "Content",MM7_TAG_Content) VNSTRING(MM7_5, "Date",MM7_TAG_Date) VNSTRING(MM7_5, "DeliverReq",MM7_TAG_DeliverReq) VNSTRING(MM7_5, "DeliverRsp",MM7_TAG_DeliverRsp) -VNSTRING(MM7_5, "DeliveryReport",MM7_TAG_DeliveryReport) VNSTRING(MM7_5, "DeliveryReportReq",MM7_TAG_DeliveryReportReq) VNSTRING(MM7_5, "DeliveryReportRsp",MM7_TAG_DeliveryReportRsp) VNSTRING(MM7_5, "DistributionIndicator",MM7_TAG_DistributionIndicator) @@ -269,7 +268,6 @@ VNSTRING(MM7_5, "Number",MM7_TAG_Number) VNSTRING(MM7_5, "Priority",MM7_TAG_Priority) VNSTRING(MM7_5, "RFC2822Address",MM7_TAG_RFC2822Address) VNSTRING(MM7_5, "RSErrorRsp",MM7_TAG_RSErrorRsp) -VNSTRING(MM7_5, "ReadReply",MM7_TAG_ReadReply) VNSTRING(MM7_5, "ReadReplyReq",MM7_TAG_ReadReplyReq) VNSTRING(MM7_5, "ReadReplyRsp",MM7_TAG_ReadReplyRsp) VNSTRING(MM7_5, "Recipient",MM7_TAG_Recipient) diff --git a/mbuni/mmlib/mms_util.c b/mbuni/mmlib/mms_util.c index 76f7cd2..776e233 100644 --- a/mbuni/mmlib/mms_util.c +++ b/mbuni/mmlib/mms_util.c @@ -830,3 +830,124 @@ MIMEEntity *mime_entity_duplicate(MIMEEntity *m) return mx; } + +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; + for (i = 0, n = list_len(l); i= 1 && + octstr_get_cstr(s)[0] == '+') + i++; + for ( cs = octstr_get_cstr(s); i0) + 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")); +} diff --git a/mbuni/mmlib/mms_util.h b/mbuni/mmlib/mms_util.h index 9c52667..49d40cc 100644 --- a/mbuni/mmlib/mms_util.h +++ b/mbuni/mmlib/mms_util.h @@ -19,7 +19,7 @@ #include "config.h" #include "mms_strings.h" #include "mms_msg.h" - +#include "mms_mm7soap.h" #include "mms_mmbox.h" @@ -49,6 +49,7 @@ /* Message location flags: Used to distinguish fetch-urls */ enum mms_loc_t {MMS_LOC_MMBOX = 1, MMS_LOC_MQUEUE=2}; + extern int mms_load_core_settings(CfgGroup *cgrp); extern Octstr *mms_maketransid(char *qf, Octstr *mmscname); @@ -124,4 +125,22 @@ int _mms_gw_isprint(int c); /* Special form of cfg_get which returns zero-length string when there is nothing. */ Octstr *_mms_cfg_getx(CfgGroup *grp, Octstr *item); + +/* Get envelope data from message headers. */ +void mms_collect_envdata_from_msgheaders(List *mh, List **xto, + Octstr **subject, + Octstr **otransid, time_t *expiryt, + time_t *deliveryt, long default_msgexpiry); + +/* Simple hash function */ +unsigned long _mshash(char *s); + +/* Tell us whether address is a phone number. */ +int isphonenum(Octstr *s); +/* Fixup an address: Add type, etc. */ +void _mms_fixup_address(Octstr *address); +#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 */ #endif diff --git a/mbuni/mmsbox/Makefile b/mbuni/mmsbox/Makefile index 9aa2a41..24ab473 100644 --- a/mbuni/mmsbox/Makefile +++ b/mbuni/mmsbox/Makefile @@ -51,7 +51,8 @@ CONFIG_CLEAN_FILES = am__installdirs = "$(DESTDIR)$(bindir)" binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) PROGRAMS = $(bin_PROGRAMS) -am_mmsbox_OBJECTS = mmsbox.$(OBJEXT) mmsbox_cfg.$(OBJEXT) +am_mmsbox_OBJECTS = mmsbox.$(OBJEXT) mmsbox_cfg.$(OBJEXT) \ + dlr.$(OBJEXT) bearerbox.$(OBJEXT) mmsbox_OBJECTS = $(am_mmsbox_OBJECTS) mmsbox_LDADD = $(LDADD) DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) @@ -81,7 +82,7 @@ AUTOMAKE = ${SHELL} /Users/bagyenda/src/mbuni/missing --run automake-1.9 AWK = gawk CC = gcc CCDEPMODE = depmode=gcc3 -CFLAGS = -I./../mmlib -g -O2 -DDARWIN=1 -I/sw/include -I/usr/local/include/kannel -DDARWIN=1 -I/sw/include/libxml2 -I/sw/include -I/sw/include +CFLAGS = -I./../mmlib -g -Wall -O2 -DDARWIN=1 -I/sw/include -I/usr/local/include/kannel -DDARWIN=1 -I/sw/include/libxml2 -I/sw/include -I/sw/include CPP = gcc -E CPPFLAGS = CXX = g++ @@ -169,7 +170,7 @@ sbindir = ${exec_prefix}/sbin sharedstatedir = ${prefix}/com sysconfdir = ${prefix}/etc target_alias = -mmsbox_SOURCES = mmsbox.c mmsbox_cfg.c +mmsbox_SOURCES = mmsbox.c mmsbox_cfg.c dlr.c bearerbox.c all: all-am .SUFFIXES: @@ -241,6 +242,8 @@ mostlyclean-compile: distclean-compile: -rm -f *.tab.c +include ./$(DEPDIR)/bearerbox.Po +include ./$(DEPDIR)/dlr.Po include ./$(DEPDIR)/mmsbox.Po include ./$(DEPDIR)/mmsbox_cfg.Po diff --git a/mbuni/mmsbox/Makefile.am b/mbuni/mmsbox/Makefile.am index 0f9ec42..2a295df 100644 --- a/mbuni/mmsbox/Makefile.am +++ b/mbuni/mmsbox/Makefile.am @@ -1,3 +1,3 @@ bin_PROGRAMS = mmsbox -mmsbox_SOURCES = mmsbox.c mmsbox_cfg.c +mmsbox_SOURCES = mmsbox.c mmsbox_cfg.c dlr.c bearerbox.c diff --git a/mbuni/mmsbox/bearerbox.c b/mbuni/mmsbox/bearerbox.c new file mode 100644 index 0000000..350e148 --- /dev/null +++ b/mbuni/mmsbox/bearerbox.c @@ -0,0 +1,833 @@ +/* + * Mbuni - Open Source MMS Gateway + * + * MMSC handler functions: Receive and send MMS messages to MMSCs + * + * Copyright (C) 2003 - 2005, Digital Solutions Ltd. - http://www.dsmagic.com + * + * Paul Bagyenda + * + * This program is free software, distributed under the terms of + * the GNU General Public License, with a few exceptions granted (see LICENSE) + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "mmsbox.h" +#include "mms_queue.h" + +#include "mmsbox.h" + +typedef struct MmsHTTPClientInfo { + HTTPClient *client; + Octstr *ua; + Octstr *ip; + List *headers; + Octstr *url; + Octstr *body; + List *cgivars; + MmscGrp *m; +} MmsHTTPClientInfo; + +static void free_clientInfo(MmsHTTPClientInfo *h, int freeh); + +static int auth_check(Octstr *user, Octstr *pass, List *headers) +{ + int i, res = -1; + Octstr *v = http_header_value(headers, octstr_imm("Authorization")); + Octstr *p = NULL, *q = NULL; + if (!v || + octstr_search(v, octstr_imm("Basic "), 0) != 0) + goto done; + p = octstr_copy(v, sizeof "Basic", octstr_len(v)); + octstr_base64_to_binary(p); + + i = octstr_search_char(p, ':', 0); + q = octstr_copy(p, i+1, octstr_len(p)); + octstr_delete(p, i, octstr_len(p)); + + /* p = user, q = pass. */ + + if (octstr_compare(user, p) != 0 || + octstr_compare(pass, q) != 0) + res = -1; + else + res = 0; +done: + if (v) + octstr_destroy(v); + if (p) + octstr_destroy(p); + if (q) + octstr_destroy(q); + return res; +} + +static int send_report(Octstr *from, char *report_type, Octstr *status, Octstr *msgid, Octstr *mmc_id) +{ + + Octstr *url = mms_dlr_url_get(msgid, report_type, mmc_id); + List *rh, *rph = NULL; + Octstr *furl = NULL, *rb = NULL; + + if (!url) + return 0; + + rh = http_create_empty_headers(); + + http_header_add(rh, "X-Mbuni-Report-Type", report_type); + http_header_add(rh, "X-Mbuni-MM-Status", octstr_get_cstr(status)); + http_header_add(rh, "X-Mbuni-Message-ID", octstr_get_cstr(msgid)); + http_header_add(rh, "X-Mbuni-MMSC-ID", octstr_get_cstr(mmc_id)); + http_header_add(rh, "X-Mbuni-From", octstr_get_cstr(from)); + + http_get_real(HTTP_METHOD_GET, url, rh, &furl, &rph, &rb); + + if (furl) + octstr_destroy(furl); + if (rb) + octstr_destroy(rb); + octstr_destroy(url); + + if (rph) + http_destroy_headers(rph); + http_destroy_headers(rh); + + /* At what point do we delete it? For now, when we get a read report, + * and also when we get a delivery report that is not 'deferred' + */ + if (strcmp(report_type, "read-report") == 0 || + octstr_case_compare(status, octstr_imm("Deferred")) != 0) + mms_dlr_url_remove(msgid, report_type, mmc_id); + return 0; +} + +/* These functions are very similar to those in mmsproxy */ +static void mm7soap_receive(MmsHTTPClientInfo *h) +{ + + MSoapMsg_t *mreq = NULL, *mresp = NULL; + int hstatus = HTTP_OK; + List *rh = NULL; + Octstr *reply_body = NULL, *value; + + List *to = NULL; + Octstr *from = NULL, *subject = NULL, *vasid = NULL, *msgid = NULL; + time_t expiryt = -1, delivert = -1; + MmsMsg *m = NULL; + int status = 1000; + unsigned char *msgtype = (unsigned char *)""; + Octstr *qf = NULL; + + + if (h->body) + mreq = mm7_parse_soap(h->headers, h->body); + if (mreq) + msgtype = mms_mm7tag_to_cstr(mm7_msgtype(mreq)); + debug("mmsbox.mm7sendinterface", 0, + " --> Enterred mm7dispatch interface, mreq=%s mtype = %s <-- ", + mreq ? "Ok" : "Null", + mreq ? (char *)msgtype : "Null"); + + if (!mreq) { + mresp = mm7_make_resp(NULL, MM7_SOAP_FORMAT_CORRUPT, NULL); + goto done; + } + + mm7_get_envelope(mreq, &from, &to, &subject, &vasid, &expiryt, &delivert); + + if (!from) + from = octstr_imm("anon@anon"); + + switch (mm7_msgtype(mreq)) { + case MM7_TAG_DeliverReq: + m = mm7_soap_to_mmsmsg(mreq, from); + if (m) { + Octstr *value; + int dlr; + + value = mms_get_header_value(m, octstr_imm("X-Mms-Delivery-Report")); + if (value && + octstr_case_compare(value, octstr_imm("Yes")) == 0) + dlr = 1; + else + dlr = 0; + + if (delivert < 0) + delivert = time(NULL); + + if (expiryt < 0) + expiryt = time(NULL) + DEFAULT_EXPIRE; + + qf = mms_queue_add(from, to, subject, + h->m->id, NULL, + delivert, expiryt, m, NULL, + NULL, NULL, + NULL, NULL, + dlr, + octstr_get_cstr(incoming_qdir), + octstr_imm(MM_NAME)); + msgid = mms_maketransid(octstr_get_cstr(qf), octstr_imm(MM_NAME)); + mms_log("Received", from, to, -1, msgid, NULL, h->m->id, "MMSBox", h->ua, NULL); + + octstr_destroy(value); + } else + status = 4000; + mresp = mm7_make_resp(mreq, status, msgid); + break; + + case MM7_TAG_DeliveryReportReq: + msgid = mm7_soap_header_value(mreq, octstr_imm("MessageID")); + value = mm7_soap_header_value(mreq, octstr_imm("MMStatus")); + + send_report(from, "delivery-report", value, msgid, h->m->id); + + if (value) + octstr_destroy(value); + mms_log("DeliveryReport", + from, NULL, -1, msgid, NULL, h->m->id, "MMSBox", h->ua, NULL); + mresp = mm7_make_resp(mreq, status, NULL); + break; + + case MM7_TAG_ReadReplyReq: + msgid = mm7_soap_header_value(mreq, octstr_imm("MessageID")); + value = mm7_soap_header_value(mreq, octstr_imm("MMStatus")); + + send_report(from, "read-report", value, msgid, h->m->id); + + if (value) + octstr_destroy(value); + mms_log("ReadReport", + from, NULL, -1, msgid, NULL, h->m->id, "MMSBox", h->ua, NULL); + mresp = mm7_make_resp(mreq, status, NULL); + break; + + default: + mresp = mm7_make_resp(mreq, MM7_SOAP_UNSUPPORTED_OPERATION, NULL); + break; + } + + done: + + if (mresp && mm7_soapmsg_to_httpmsg(mresp, &rh, &reply_body) == 0) + http_send_reply(h->client, hstatus, rh, reply_body); + else + http_close_client(h->client); + + debug("mmsbox.mm7sendinterface", 0, + " --> leaving mm7dispatch interface, mresp=%s, body=%s <-- ", + mresp ? "ok" : "(null)", + reply_body ? "ok" : "(null)"); + + + if (from) + octstr_destroy(from); + + if (subject) + octstr_destroy(subject); + if (vasid) + octstr_destroy(vasid); + if (msgid) + octstr_destroy(msgid); + + if (qf) + octstr_destroy(qf); + if (m) + mms_destroy(m); + if (rh) + http_destroy_headers(rh); + if (reply_body) + octstr_destroy(reply_body); + + if (mresp) + mm7_soap_destroy(mresp); + if (mreq) + mm7_soap_destroy(mreq); + + if (to) + list_destroy(to, (list_item_destructor_t *)octstr_destroy); + +} + +static void mm7eaif_receive(MmsHTTPClientInfo *h) +{ + MmsMsg *m = NULL; + List *mh = NULL; + int hstatus = HTTP_NO_CONTENT; + List *rh = http_create_empty_headers(); + Octstr *reply_body = NULL, *value, *value2; + + List *to = list_create(), *hto = NULL; + Octstr *subject = NULL, *otransid = NULL, *msgid = NULL; + Octstr *hfrom = NULL; + time_t expiryt = -1, deliveryt = -1; + Octstr *qf = NULL; + int msize = h->body ? octstr_len(h->body) : 0; + int dlr; + int mtype; + + debug("mmsbox.mm7eaif.sendinterface", 0, + " --> Enterred eaif send interface, blen=%d <--- ", + msize); + + hfrom = http_header_value(h->headers, octstr_imm("X-NOKIA-MMSC-From")); + if (!h->body || /* A body is required, and must parse */ + (m = mms_frombinary(h->body, hfrom ? hfrom : octstr_imm("anon@anon"))) == NULL) { + http_header_add(rh, "Content-Type", "text/plain"); + hstatus = HTTP_BAD_REQUEST; + reply_body = octstr_format("Unexpected MMS message, no body?"); + + goto done; + } + + /* XXXX handle delivery reports differently. */ + mtype = mms_messagetype(m); + mh = mms_message_headers(m); + /* Now get sender and receiver data. + * for now we ignore adaptation flags. + */ + mms_collect_envdata_from_msgheaders(mh, &to, &subject, + &otransid, &expiryt, &deliveryt, + DEFAULT_EXPIRE); + + + if ((hto = http_header_find_all(h->headers, "X-NOKIA-MMSC-To")) != NULL && + list_len(hto) > 0) { /* To address is in headers. */ + int i, n; + + if (to) + list_destroy(to, (list_item_destructor_t *)octstr_destroy); + to = list_create(); + for (i = 0, n = list_len(hto); i < n; i++) { + Octstr *h = NULL, *v = NULL; + List *l; + int j, m; + + http_header_get(hto,i, &h, &v); + l = http_header_split_value(v); + + for (j = 0, m = list_len(l); j < m; j++) + list_append(to, list_get(l, j)); + + list_destroy(l, NULL); + if (h) octstr_destroy(h); + if (v) octstr_destroy(v); + } + + } + + switch(mtype) { + case MMS_MSGTYPE_SEND_REQ: + + /* Get Message ID */ + if ((msgid = http_header_value(h->headers, octstr_imm("X-NOKIA-MMSC-Message-Id"))) == NULL) + 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; + if (value) + 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"); + + /* Save it, put message id in header, return. */ + qf = mms_queue_add(hfrom, to, subject, + h->m->id, NULL, deliveryt, expiryt, m, NULL, + NULL, NULL, + NULL, NULL, + dlr, + octstr_get_cstr(incoming_qdir), + octstr_imm(MM_NAME)); + + if (qf) { + /* Log to access log */ + mms_log("Received", hfrom, to, msize, msgid, NULL, h->m->id, "MMSBox", h->ua, NULL); + + octstr_destroy(qf); + hstatus = HTTP_NO_CONTENT; + } else + hstatus = HTTP_INTERNAL_SERVER_ERROR; + break; + case MMS_MSGTYPE_DELIVERY_IND: + value = http_header_value(mh, octstr_imm("X-Mms-Status")); + value2 = http_header_value(mh, octstr_imm("Message-ID")); + send_report(hfrom, "delivery-report", value, value2, h->m->id); + + if (value) + octstr_destroy(value); + if (value2) + octstr_destroy(value2); + break; + + case MMS_MSGTYPE_READ_ORIG_IND: + value = http_header_value(mh, octstr_imm("X-Mms-Read-Status")); + value2 = http_header_value(mh, octstr_imm("Message-ID")); + send_report(hfrom, "read-report", value, value2, h->m->id); + + if (value) + octstr_destroy(value); + if (value2) + octstr_destroy(value2); + break; + } + + done: + http_header_add(rh, "X-NOKIA-MMSC-Version", EAIF_VERSION); + + http_send_reply(h->client, hstatus, rh, octstr_imm("")); + + if (hto) + http_destroy_headers(hto); + if (to) + list_destroy(to, (list_item_destructor_t *)octstr_destroy); + if (hfrom) + octstr_destroy(hfrom); + if (subject) + octstr_destroy(subject); + if (otransid) + octstr_destroy(otransid); + if (msgid) + octstr_destroy(msgid); + if (mh) + http_destroy_headers(mh); + + if (m) mms_destroy(m); +} + + +void mmsc_receive_func(MmscGrp *m) +{ + + MmsHTTPClientInfo h = {NULL}; + + h.m = m; + while(rstop == 0 && + (h.client = http_accept_request(m->incoming.port, + &h.ip, &h.url, &h.headers, + &h.body, &h.cgivars)) != NULL) + if (is_allowed_ip(m->incoming.deny_ip, m->incoming.allow_ip, h.ip)) { + + h.ua = http_header_value(h.headers, octstr_imm("User-Agent")); + debug("mmsbox", 0, + " MM7 Incoming, ip=%s, mmsc id=%s ", + h.ip ? octstr_get_cstr(h.ip) : "", + octstr_get_cstr(m->id)); + + /* Dump headers, url etc. */ +#if 1 + http_header_dump(h.headers); + if (h.body) octstr_dump(h.body, 0); + if (h.ip) octstr_dump(h.ip, 0); +#endif + if (auth_check(m->incoming.user, + m->incoming.pass, + h.headers) != 0) { /* Ask it to authenticate... */ + List *hh = http_create_empty_headers(); + http_header_add(hh, "WWW-Authenticate", + "Basic realm=\"" MM_NAME "\""); + http_send_reply(h.client, HTTP_UNAUTHORIZED, hh, + octstr_imm("")); + http_destroy_headers(hh); + } else if (m->type == SOAP_MMSC) + mm7soap_receive(&h); + else + mm7eaif_receive(&h); + free_clientInfo(&h, 0); + } else { + free_clientInfo(&h, 0); + http_close_client(h.client); + } + + debug("proxy", 0, "MMSBox: MM7 Shutting down..."); +} + +static void free_clientInfo(MmsHTTPClientInfo *h, int freeh) +{ + + debug("free info", 0, + " entered free_clientinfo %d, ip=%d", freeh, (int)h->ip); + + if (h->ip) + octstr_destroy(h->ip); + + + if (h->url) + octstr_destroy(h->url); + if (h->ua) octstr_destroy(h->ua); + + + if (h->body) octstr_destroy(h->body); + + if (h->cgivars) + http_destroy_cgiargs(h->cgivars); + + if (h->headers) + http_destroy_headers(h->headers); + + if (freeh) + gw_free(h); + + debug("free info", 0, + " left free_clientinfo"); +} + + + +/* XXX Returns msgid in mmsc or NULL if error. Caller uses this for DLR issues. + * Caller must make sure throughput issues + * are observed! + * Don't remove from queue on fail, just leave it to expire. + */ +static Octstr *mm7soap_send(MmscGrp *mmc, Octstr *from, Octstr *to, Octstr *msgId, + char *vasid, + MmsMsg *m, Octstr **error) +{ + Octstr *ret = NULL; + int mtype = mms_messagetype(m); + int hstatus = HTTP_OK, tstatus; + List *xto = list_create(); + MSoapMsg_t *mreq = NULL, *mresp = NULL; + List *rh = NULL, *ph = NULL; + Octstr *body = NULL, *rbody = NULL, *url = NULL; + Octstr *s; + + info(0, "MMSBox: Send[soap] to MMSC[%s], msg type [%s], from %s, to %s", + mmc->id ? octstr_get_cstr(mmc->id) : "", + mms_message_type_to_cstr(mtype), + octstr_get_cstr(from), octstr_get_cstr(to)); + + list_append(xto, to); + + if ((mreq = mm7_mmsmsg_to_soap(m, from, xto, msgId, + NULL, + 1, octstr_get_cstr(mmc->id), vasid)) == NULL) { + *error = octstr_format("Failed to convert Msg[%s] 2 SOAP message!", + mms_message_type_to_cstr(mtype)); + goto done1; + } + + if (mm7_soapmsg_to_httpmsg(mreq, &rh, &body) < 0) { + *error = octstr_format("Failed to convert SOAP message 2 HTTP Msg!"); + goto done1; + } + + hstatus = mmsbox_http_fetch_content(HTTP_METHOD_POST, mmc->mmsc_url, rh, body, &ph,&rbody); + if (hstatus != HTTP_OK) { + *error = octstr_format("Failed to contact MMC[url=%s] => HTTP returned status = %d!", + octstr_get_cstr(mmc->mmsc_url), hstatus); + goto done1; + } + + if ((mresp = mm7_parse_soap(ph, rbody)) == NULL) { + *error = octstr_format("Failed to parse MMSC[url=%s, id=%s] response!", + octstr_get_cstr(mmc->mmsc_url), + octstr_get_cstr(mmc->id)); + goto done1; + } + + /* Now look at response code and use it to tell you what you want. */ + if ((s = mm7_soap_header_value(mresp, octstr_imm("StatusCode"))) != NULL) { + tstatus = atoi(octstr_get_cstr(s)); + octstr_destroy(s); + } else + tstatus = MM7_SOAP_FORMAT_CORRUPT; + + if (!MM7_SOAP_STATUS_OK(tstatus)) { + Octstr *detail = mm7_soap_header_value(mresp, octstr_imm("Details")); + ret = NULL; + info(0, "Send to MMSC[%s], failed, code=[%d=>%s], detail=%s", + mmc ? octstr_get_cstr(mmc->id) : "", + tstatus, mms_soap_status_to_cstr(tstatus), + detail ? octstr_get_cstr(detail) : ""); + *error = octstr_format("Failed to deliver to MMC[url=%s, id=%s], status=[%d=>%s]!", + octstr_get_cstr(mmc->mmsc_url), + octstr_get_cstr(mmc->id), + tstatus, + mms_soap_status_to_cstr(tstatus)); + + if (detail) + octstr_destroy(detail); + + } else + ret = mm7_soap_header_value(mresp, octstr_imm("MessageID")); + + info(0, "Sent to MMC[%s], code=[%d=>%s]", octstr_get_cstr(mmc->id), + tstatus, mms_soap_status_to_cstr(tstatus)); + done1: + + if (mreq) + mm7_soap_destroy(mreq); + if (mresp) + mm7_soap_destroy(mresp); + if (rh) + http_destroy_headers(rh); + if (body) + octstr_destroy(body); + if (ph) + http_destroy_headers(ph); + if (rbody) + octstr_destroy(rbody); + if (url) + octstr_destroy(url); + + list_destroy(xto, NULL); + + return ret; +} + +static Octstr *mm7eaif_send(MmscGrp *mmc, Octstr *from, Octstr *to, + char *vasid, + MmsMsg *m, Octstr **error) +{ + Octstr *ret = NULL; + int mtype = mms_messagetype(m); + int hstatus = HTTP_OK; + List *rh = http_create_empty_headers(), *ph = NULL; + Octstr *body = NULL, *rbody = NULL, *url = NULL; + char *msgtype; + + + info(0, "MMSBox: Send [eaif] to MMC[%s], msg type [%s], from %s, to %s", + mmc ? octstr_get_cstr(mmc->id) : "", + mms_message_type_to_cstr(mtype), + octstr_get_cstr(from), octstr_get_cstr(to)); + + http_header_add(rh, "X-NOKIA-MMSC-To", octstr_get_cstr(to)); + http_header_add(rh, "X-NOKIA-MMSC-From", octstr_get_cstr(from)); + http_header_add(rh, "X-NOKIA-MMSC-Version", EAIF_VERSION); + + if (mtype == MMS_MSGTYPE_SEND_REQ) + msgtype = "MultiMediaMessage"; + else if (mtype == MMS_MSGTYPE_DELIVERY_IND) + msgtype = "DeliveryReport"; + else + msgtype = "ReadReply"; + http_header_add(rh, "X-NOKIA-MMSC-Message-Type", msgtype); + http_header_add(rh, "Content-Type", "application/vnd.wap.mms-message"); + + body = mms_tobinary(m); + + hstatus = mmsbox_http_fetch_content(HTTP_METHOD_POST, mmc->mmsc_url, rh, body, &ph, &rbody); + + if (http_status_class(hstatus) != HTTP_STATUS_SUCCESSFUL) { + *error = octstr_format("Failed to contact MMC[url=%s] => HTTP returned status = %d !", + octstr_get_cstr(mmc->mmsc_url), hstatus); + } else + info(0, "Sent to MMC[%s], code=[%d]", octstr_get_cstr(mmc->id), hstatus); + + if (hstatus < 0) + ret = NULL; + else { + hstatus = http_status_class(hstatus); + if (hstatus == HTTP_STATUS_SERVER_ERROR) + ret = NULL; + else + ret = http_header_value(ph, octstr_imm("X-Nokia-MMSC-Message-Id")); + } + + if (rh) + http_destroy_headers(rh); + if (body) + octstr_destroy(body); + if (ph) + http_destroy_headers(ph); + if (rbody) + octstr_destroy(rbody); + if (url) + octstr_destroy(url); + + + return ret; +} + + +static int mms_sendtommsc(MmscGrp *mmc, Octstr *from, Octstr *to, Octstr *msgid, + char *vasid, + MmsMsg *m, + Octstr *dlr_url, + Octstr *rr_url, + Octstr **err) +{ + Octstr *id = NULL; + + + mutex_lock(mmc->mutex); { /* Grab a lock on it. */ + if (mmc->type == SOAP_MMSC) + id = mm7soap_send(mmc, from, to, msgid, vasid, m, err); + else if (mmc->type == EAIF_MMSC) + id = mm7eaif_send(mmc, from, to, vasid, m, err); + else + error(0, "MMC[%s] of unknown type, can't send!", + mmc->id ? octstr_get_cstr(mmc->id) : ""); + + if (id && mmc->throughput > 0) + gwthread_sleep(1.0/mmc->throughput); + + } mutex_unlock(mmc->mutex); /* release lock */ + + if (id) { + if (dlr_url) /* remember the url's for reporting purposes. */ + mms_dlr_url_put(id, "delivery-report", mmc->id, dlr_url); + if (rr_url) + mms_dlr_url_put(id, "read-report", mmc->id, rr_url); + + octstr_destroy(id); + return MMS_SEND_OK; + } else + return MMS_SEND_ERROR_TRANSIENT; /* don't kill entry, wait a little. */ +} + +/* Get the MMC that should handler this recipient. */ +static MmscGrp *get_handler_mmc(Octstr *id, Octstr *to) +{ + MmscGrp *mmc = NULL; + int i, j, n; + Octstr *phonenum = NULL; + + if (id) + for (i = 0, n = list_len(mmscs); i < n; i++) + if ((mmc = list_get(mmscs, i)) != NULL && + mmc->id && octstr_compare(mmc->id, id) == 0) + return mmc; + + if (octstr_search_char(to, '@', 0) > 0 || + octstr_case_search(to, octstr_imm("/TYPE=IPv"), 0) > 0) /* For emails, or ip take first mmsc. */ + return list_get(mmscs, 0); + + j = octstr_case_search(to, octstr_imm("/TYPE=PLMN"), 0); + + if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == octstr_len(to)) + phonenum = octstr_copy(to, 0, j); + else + phonenum = octstr_duplicate(to); + + normalize_number(octstr_get_cstr(unified_prefix), &phonenum); + + for (i = 0, n = list_len(mmscs); i < n; i++) + if ((mmc = list_get(mmscs, i)) != NULL && + does_prefix_match(mmc->allowed_prefix, phonenum) && + !does_prefix_match(mmc->denied_prefix, phonenum)) + return mmc; + + if (phonenum) + octstr_destroy(phonenum); + return NULL; +} + +static int sendMsg(MmsEnvelope *e) +{ + MmsMsg *msg = NULL; + int i, n; + + msg = mms_queue_getdata(e); + + for (i = 0, n = list_len(e->to); ito, i); + Octstr *err = NULL; + time_t tnow = time(NULL); + MmscGrp *mmc = NULL; + + if (!to || !to->process) + continue; + + if (e->expiryt != 0 && /* Handle message expiry. */ + e->expiryt < tnow) { + err = octstr_format("MMSC error: Message expired while sending to %S!", to->rcpt); + res = MMS_SEND_ERROR_FATAL; + + goto done; + } else if (e->attempts >= mmsbox_maxsendattempts) { + err = octstr_format("MMSBox error: Failed to deliver to " + "%S after %ld attempts. (max attempts allowed is %ld)!", + to->rcpt, e->attempts, + mmsbox_maxsendattempts); + res = MMS_SEND_ERROR_FATAL; + goto done; + } + + if ((mmc = get_handler_mmc(e->viaproxy, to->rcpt)) == NULL) { + err = octstr_format("MMSBox error: Failed to deliver to " + "%S. Don't know how to route!", + to->rcpt); + res = MMS_SEND_ERROR_TRANSIENT; + goto done; + } + + res = mms_sendtommsc(mmc, e->from, to->rcpt, + e->msgId, + e->vasid ? octstr_get_cstr(e->vasid) : NULL, + msg, + e->url1, e->url2, + &err); + + done: + if (res == MMS_SEND_OK) + to->process = 0; + else if (mmc) + send_report(to->rcpt, "delivery-report", + (e->expiryt != 0 && e->expiryt < tnow) ? + octstr_imm("Expired") : octstr_imm("Rejected"), + e->msgId, mmc->id); + if (res == MMS_SEND_ERROR_FATAL) + to->process = 0; /* No more attempts. */ + + info(0, "%s MMSBox Outgoing Queue MMS Send: From %s, to %s, msgsize=%ld: err=%s", + SEND_ERROR_STR(res), + octstr_get_cstr(e->from), octstr_get_cstr(to->rcpt), e->msize, + err ? octstr_get_cstr(err) : "(null)"); + + + e->lasttry = tnow; + if (mms_queue_update(e) == 1) { + e = NULL; + break; /* Queue entry gone. */ + } + + } + + if (msg) + mms_destroy(msg); + + if (e) { /* Update the queue if it is still valid (e.g. recipients not handled) + * XXX can this happen here??... + */ + e->lasttry = time(NULL); + e->attempts++; /* Update count of number of delivery attempts. */ + e->sendt = e->lasttry + mmsbox_send_back_off * e->attempts; + + if (mms_queue_update(e) != 1) + mms_queue_free_env(e); + } + + return 1; /* always delete queue entry. */ +} + +void mmsbox_outgoing_queue_runner(int *rstop) +{ + mms_queue_run(octstr_get_cstr(outgoing_qdir), + sendMsg, queue_interval, maxthreads, rstop); +} diff --git a/mbuni/mmsbox/dlr.c b/mbuni/mmsbox/dlr.c new file mode 100644 index 0000000..fe69131 --- /dev/null +++ b/mbuni/mmsbox/dlr.c @@ -0,0 +1,118 @@ +/* + * Mbuni - Open Source MMS Gateway + * + * MMSBox Dlr: Dlr storage for MMSBox + * + * Copyright (C) 2003 - 2005, Digital Solutions Ltd. - http://www.dsmagic.com + * + * Paul Bagyenda + * + * This program is free software, distributed under the terms of + * the GNU General Public License, with a few exceptions granted (see LICENSE) + */ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include "mmsbox.h" +#include "mms_queue.h" + +#define MAXTRIES 10 +static int dlr_entry_fname(char *msgid, char *rtype, Octstr *mmc_id, Octstr **efname) +{ + char d1[2], d2[3], fbuf[512], *p; + unsigned long h = _mshash(msgid); + Octstr *t, *s; + int i, fd; + + /* Make toplevel dir. */ + d1[0] = _TT[h%_TTSIZE]; + d1[1] = '\0'; + + /* Then lower level. */ + h /= _TTSIZE; + d2[0] = _TT[h%_TTSIZE]; + h /= _TTSIZE; + d2[1] = _TT[h%_TTSIZE]; + d2[2] = '\0'; + + /* Try and create the next level dir (first level was created by root_init) */ + sprintf(fbuf, "%s/%s/%s", octstr_get_cstr(dlr_dir), d1, d2); + if (mkdir(fbuf, + S_IRWXU|S_IRWXG) < 0 && + errno != EEXIST) { + error(0, "mmsbox: failed to create dir [%s] " + "while initialising dlr dir for %s: %s!", + fbuf, msgid, strerror(errno)); + return -1; + } + + t = octstr_format("%S-%s_%s", mmc_id, msgid, rtype); /* Put mmc id into name. */ + + octstr_replace(t, octstr_imm("/"), octstr_imm("$")); /* XXX safe in all cases?? */ + s = octstr_format("%s/%S", fbuf, t); + octstr_destroy(t); + + + p = octstr_get_cstr(s); + i = 0; + do + if ((fd = open(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)) < 0) { + error(0, "Failed to open DLR URL store file [%s], error: %s!", + p, strerror(errno)); + break; + } else if (mm_lockfile(fd, p, 1) != 0) { + close(fd); + fd = -1; + } + while (i++ < MAXTRIES && fd < 0); + + if (efname) + *efname = s; + else + octstr_destroy(s); + + return fd; +} + +void mms_dlr_url_put(Octstr *msgid, char *rtype, Octstr *mmc_id, Octstr *dlr_url) +{ + int fd = dlr_entry_fname(octstr_get_cstr(msgid), rtype, mmc_id, NULL); + + if (fd >= 0) { + octstr_write_data(dlr_url, fd, 0); + close(fd); + } +} + +Octstr *mms_dlr_url_get(Octstr *msgid, char *rtype, Octstr *mmc_id) +{ + int fd = dlr_entry_fname(octstr_get_cstr(msgid), rtype, mmc_id, NULL); + FILE *f; + + if (fd >= 0 && (f = fdopen(fd, "r+")) != NULL) { + Octstr *s = octstr_read_pipe(f); + + fclose(f); + return s; + } else if (fd >= 0) + close(fd); + return NULL; +} + +void mms_dlr_url_remove(Octstr *msgid, char *rtype, Octstr *mmc_id) +{ + Octstr *fname = NULL; + int fd = dlr_entry_fname(octstr_get_cstr(msgid), rtype, mmc_id, &fname); + + if (fname) + unlink(octstr_get_cstr(fname)); + if (fd >= 0) + close(fd); +} diff --git a/mbuni/mmsbox/mmsbox.c b/mbuni/mmsbox/mmsbox.c index 4ea4d93..9003ea5 100644 --- a/mbuni/mmsbox/mmsbox.c +++ b/mbuni/mmsbox/mmsbox.c @@ -14,10 +14,13 @@ #include #include #include +#include +#include +#include "mms_queue.h" +#include "mms_uaprof.h" +#include "mmsbox.h" -#include "mmsbox_cfg.h" - -static int rstop = 0; +int rstop = 0; static void quit_now(int notused) { rstop = 1; @@ -25,11 +28,375 @@ static void quit_now(int notused) /* Close all MMSC http ports, kill all MMSC threads, kill sendmms port... */ } +static MIMEEntity *find_textpart(MIMEEntity *m) +{ + Octstr *ctype = NULL, *params = NULL; + MIMEEntity *res = NULL; + + if (!m) return NULL; + + get_content_type(m->headers, &ctype, ¶ms); + + if (ctype && octstr_str_compare(ctype, "text/plain") == 0) { + res = m; + goto done; + } + + if (m->multiparts) { + int i, n = list_len(m->multiparts); + for (i = 0; i < n; i++) + if ((res = find_textpart(list_get(m->multiparts, i))) != NULL) + goto done; + } +done: + if (ctype) + octstr_destroy(ctype); + + if (res) { /* We got it! Convert charset if needed. */ + List *params_h = get_value_parameters(params); + Octstr *charset = http_header_value(params_h, octstr_imm("charset")); + + if (charset == NULL || + octstr_str_compare(charset, "unknown") == 0) { + if (charset) octstr_destroy(charset); + charset = octstr_imm(DEFAULT_CHARSET); + } + + if (octstr_case_compare(charset, octstr_imm(DEFAULT_CHARSET)) != 0) + charset_convert(m->body, DEFAULT_CHARSET, octstr_get_cstr(charset)); /* XXX error ignored? */ + http_destroy_headers(params_h); + octstr_destroy(charset); + } + + if (params) + octstr_destroy(params); + return res; +} +/* Gets the keyword, if any, from the text part of the message. + * converts charset as needed. + */ +static Octstr *get_keyword(MIMEEntity *me) +{ + + MIMEEntity *t = find_textpart(me); + Octstr *txt = t ? t->body : NULL; + List *l = t ? octstr_split_words(txt) : NULL; + Octstr *keyword = l ? list_get(l, 0) : NULL; + + + if (keyword) + keyword = octstr_duplicate(keyword); + if (l) + list_destroy(l, (list_item_destructor_t *)octstr_destroy); + + return keyword; +} + +static MmsService *get_service(Octstr *keyword, Octstr *mmc_id) +{ + int i, n; + + for (i = 0, n = list_len(mms_services); i < n; i++) { + MmsService *ms = list_get(mms_services,i); + + /* Check that mmc_id is allowed: + * denied list is not null and we are on it, or allowed list is not null and we + * are *not* on it. + */ + if (ms->denied_mmscs && + list_search(ms->denied_mmscs, mmc_id, (list_item_matches_t *)octstr_compare) != NULL) + continue; + + if (ms->allowed_mmscs && + list_search(ms->allowed_mmscs, mmc_id, (list_item_matches_t *)octstr_compare) == NULL) + continue; + + if (keyword == NULL || + list_search(ms->keywords, keyword, + (list_item_matches_t *)octstr_case_compare) != NULL) + return ms; + } + + return NULL; +} + +static void add_all_matching_parts(MIMEEntity *plist, MmsServiceUrlParam *pm, + MIMEEntity *me, MmsMsg *msg, int lev) +{ + int i, n; + + Octstr *data = NULL, *ctype = NULL, *xctype = NULL, *params = NULL; + + if (pm->type == WHOLE_BINARY && lev == 0) { + data = mms_tobinary(msg); + ctype = octstr_imm("application/vnd.wap.mms-message"); + } + + if (me->multiparts && list_len(me->multiparts) > 0) { + for (i = 0, n = list_len(me->multiparts); i < n; i++) + add_all_matching_parts(plist, pm, + list_get(me->multiparts, i), msg, lev+1); + goto done; + } + + get_content_type(me->headers, &xctype, ¶ms); + +#define BEGINSWITH(s, prefix) (octstr_case_search(s, octstr_imm(prefix),0) == 0) +#define TYPE_MATCH(typ, prefix) ((pm->type) == (typ) && \ + BEGINSWITH(xctype, prefix)) + + if (xctype) + if (TYPE_MATCH(IMAGE_PART,"image/") || + TYPE_MATCH(VIDEO_PART,"video/") || + TYPE_MATCH(TEXT_PART,"text/") || + TYPE_MATCH(SMIL_PART,"application/smil") || + pm->type == ANY_PART || /* Skip top-level for 'any' parts. */ + (pm->type == OTHER_PART && + (!BEGINSWITH(xctype, "text/") && + !BEGINSWITH(xctype, "video/") && + !BEGINSWITH(xctype, "image/") && + !BEGINSWITH(xctype, "application/smil")))) { + + ctype = http_header_value(me->headers, octstr_imm("Content-Type")); + data = me->body ? octstr_duplicate(me->body) : octstr_create(""); + } + +done: + + if (ctype) { + MIMEEntity *p = mime_entity_create(); + Octstr *cd = octstr_format("form-data; name=\"%S\"", pm->name); + + http_header_add(p->headers, "Content-Type", octstr_get_cstr(ctype)); + http_header_add(p->headers, "Content-Disposition", octstr_get_cstr(cd)); + + p->body = data; + + base64_mimeparts(p); + list_append(plist->multiparts, p); + + octstr_destroy(ctype); + octstr_destroy(cd); + + } + if (xctype) + octstr_destroy(xctype); + if (params) + octstr_destroy(params); + +} + +enum _xurltype {FILE_TYPE, URL_TYPE}; +static Octstr *url_path_prefix(Octstr *url, int type); +static Octstr *filename2content_type(char *fname); +static int make_and_queue_msg(Octstr *data, Octstr *ctype, List *reply_headers, + Octstr *base_url, int type, MmsEnvelope *e, + Octstr *svc_name, Octstr *faked_sender, + int accept_x_headers, Octstr **err); +static int fetch_serviceurl(MmsEnvelope *e, + MmsService *ms, MmsMsg *m, + MIMEEntity *msg, + Octstr **err) +{ + List *rh, *rph = NULL; + Octstr *body = NULL, *rb = NULL; + Octstr *ctype = NULL, *params = NULL; + int i, n, method, typ = FILE_TYPE; + FILE *fp = NULL; + + int res = -1; + + switch (ms->type) { + case TRANS_TYPE_GET_URL: + case TRANS_TYPE_POST_URL: + rh = http_create_empty_headers(); + + http_header_add(rh, "User-Agent", MM_NAME "/" GW_VERSION); + /* Put in some useful headers. */ + if (e->msgId) + http_header_add(rh, "X-Mbuni-Message-ID", octstr_get_cstr(e->msgId)); + if (e->fromproxy) + http_header_add(rh, "X-Mbuni-MMSC-ID", octstr_get_cstr(e->fromproxy)); + if (e->from) + http_header_add(rh, "X-Mbuni-From", octstr_get_cstr(e->from)); + + if (e->subject) + http_header_add(rh, "X-Mbuni-Subject", octstr_get_cstr(e->subject)); + for (i = 0, n = list_len(e->to); i < n; i++) { + MmsEnvelopeTo *r = list_get(e->to, i); + if (r && r->rcpt) + http_header_add(rh, "X-Mbuni-To", octstr_get_cstr(r->rcpt)); + } + if (ms->type == TRANS_TYPE_POST_URL) { /* Put in the parameters. */ + MIMEEntity *x = mime_entity_create(); + + http_header_add(rh, "Content-Type", "multipart/form-data"); + + http_destroy_headers(x->headers); + x->headers = rh; + for (i = 0, n = list_len(ms->params); i < n; i++) { + MmsServiceUrlParam *p = list_get(ms->params, i); + add_all_matching_parts(x, p, msg, m, 0); + } + + mime_entity_body_and_headers(x, &body, &rh); + mime_entity_destroy(x); + + method = HTTP_METHOD_POST; + } else + method = HTTP_METHOD_GET; + + typ = URL_TYPE; + if (mmsbox_http_fetch_content(method, ms->url, rh, body, &rph, &rb) == HTTP_OK) + get_content_type(rph, &ctype, ¶ms); + else + *err = octstr_format("MMSBox: Failed to fetch content for Service %S, url %S!", + ms->name, ms->url); + http_destroy_headers(rh); + if (body) + octstr_destroy(body); + break; + case TRANS_TYPE_FILE: + case TRANS_TYPE_EXEC: + fp = (ms->type == TRANS_TYPE_EXEC) ? + popen(octstr_get_cstr(ms->url), "r") : + fopen(octstr_get_cstr(ms->url), "r"); + rb = octstr_read_pipe(fp); + + if (ms->type == TRANS_TYPE_EXEC) { + ctype = octstr_imm("application/smil"); + pclose(fp); + } else { + fclose(fp); + ctype = filename2content_type(octstr_get_cstr(ms->url)); + } + + if (!rb) + *err = octstr_format("MMSBox: Failed to fetch content for Service %S, file/path = %S!", + ms->name, ms->url); + typ = FILE_TYPE; + break; + case TRANS_TYPE_TEXT: + rb = octstr_duplicate(ms->url); + ctype = octstr_imm("text/plain"); + typ = URL_TYPE; + break; + + default: + *err = octstr_format(0, "MMSBOX: Unknown Service type for service %S!", ms->name); + break; + } + + /* If we have the content, make the message and write it to out-going. */ + if (!ctype || !rb) + goto done; + else { + Octstr *base_url = url_path_prefix(ms->url, typ); + res = make_and_queue_msg(rb, ctype, rph, base_url, + typ, e, ms->name, ms->faked_sender, + ms->accept_x_headers, err); + + if (base_url) + octstr_destroy(base_url); + } + +done: + if (ctype) + octstr_destroy(ctype); + if (rb) + octstr_destroy(rb); + if (rph) + http_destroy_headers(rph); + if (params) + octstr_destroy(params); + return res; +} + +static int mmsbox_service_dispatch(MmsEnvelope *e) +{ + MmsMsg *msg = NULL; + MIMEEntity *me = NULL; + int i, n, res = 0; + time_t tnow = time(NULL); + Octstr *err = NULL, *keyword = NULL; + MmsService *ms; + + gw_assert(e->msgtype == MMS_MSGTYPE_SEND_REQ); + + if ((msg = mms_queue_getdata(e)) == NULL) { + err = octstr_format("Failed to read message for queue entry %s!", + e->xqfname); + res = -1; + goto done; + } else if (e->expiryt != 0 && /* Handle message expiry. */ + e->expiryt < tnow) { + err = octstr_format("Queue entry [msgid=%S,mmc_id=%S] " + "expired while sending to service!", e->msgId, e->fromproxy); + res = -1; + + goto done; + } else if (e->attempts >= mmsbox_maxsendattempts) { + err = octstr_format("Failed to deliver [msgid=%S,mmc_id=%S] " + "after %ld attempts. (max attempts allowed is %ld)!", + e->msgId, e->fromproxy, e->attempts, + mmsbox_maxsendattempts); + res = -1; + goto done; + } + + me = mms_tomime(msg, 0); + keyword = get_keyword(me); + + ms = get_service(keyword, e->fromproxy); + + if (!ms) { + err = octstr_format("No Service to handle %S (keyword %S)!", + e->msgId, keyword ? octstr_imm("") : keyword); + res = -1; + goto done; + } + + e->_x = ms; /* Remember it for later. */ + + res = fetch_serviceurl(e, ms, msg, me, &err); +done: + + if (err) { + error(0, "MMSBox error: %s", octstr_get_cstr(err)); + octstr_destroy(err); + } + if (res == -1 || res == 0) /* Fatal error, or success delete queue entry. */ + for (i = 0, n = list_len(e->to); i < n; i++) { + MmsEnvelopeTo *r = list_get(e->to,i); + if (r) + r->process = 0; + } + else { /* Not succeeded so we need to wait a bit and try later. */ + e->lasttry = time(NULL); + e->attempts++; /* Update count of number of delivery attempts. */ + e->sendt = e->lasttry + mmsbox_send_back_off * e->attempts; + } + + if (mms_queue_update(e) != 1) + mms_queue_free_env(e); + + if (keyword) + octstr_destroy(keyword); + if (msg) + mms_destroy(msg); + if (me) + mime_entity_destroy(me); + return 1; +} + +static void sendmms_func(void *unused); int main(int argc, char *argv[]) { Octstr *fname; int cfidx; Cfg *cfg; + + long qthread = 0, sthread = 0; mms_lib_init(); @@ -53,13 +420,603 @@ int main(int argc, char *argv[]) info(0, " " MM_NAME " MMSBox version %s starting", MMSC_VERSION); - mms_load_mmsbox_settings(cfg,NULL); + mms_load_mmsbox_settings(cfg,(gwthread_func_t *)mmsc_receive_func); cfg_destroy(cfg); signal(SIGHUP, quit_now); signal(SIGTERM, quit_now); signal(SIGPIPE,SIG_IGN); /* Ignore pipe errors. They kill us sometimes for nothing*/ + + /* Start out-going queue thread. */ + qthread = gwthread_create((gwthread_func_t *)mmsbox_outgoing_queue_runner, &rstop); + + /* Start sendmms port */ + + if (sendmms_port.port > 0) + sthread = gwthread_create((gwthread_func_t *)sendmms_func, NULL); + + + mms_queue_run(octstr_get_cstr(incoming_qdir), + mmsbox_service_dispatch, + queue_interval, maxthreads, &rstop); + + /* Wait for the sender thread, then quit. */ + gwthread_join(qthread); /* Wait for it to die... */ + + if (sendmms_port.port > 0) + gwthread_join(sthread); + sleep(2); return 0; } + +int mmsbox_http_fetch_content(int method, Octstr *url, List *request_headers, + Octstr *body, List **reply_headers, Octstr **reply_body) +{ + HTTPCaller *c = http_caller_create(); + int status = 0; + Octstr *furl = NULL; + + http_start_request(c, method, url, request_headers, body, 1, NULL, NULL); + + if (http_receive_result(c, &status, &furl, reply_headers, reply_body) == NULL) + status = -1; + + if (furl) + octstr_destroy(furl); + http_caller_destroy(c); + return status; +} + +/* Mapping file extensions to content types. */ +static struct { + char *ctype, *file_ext; +} exts[] = { + {"text/plain", "txt"}, + {"image/jpeg", "jpg"}, + {"image/jpeg", "jpeg"}, + {"image/png", "png"}, + {"image/tiff", "tiff"}, + {"image/gif", "gif"}, + {"image/bmp", "bmp"}, + {"image/vnd.wap.wbmp", "wbmp"}, + {"image/x-bmp", "bmp"}, + {"image/x-wmf", "bmp"}, + {"image/vnd.wap.wpng", "png"}, + {"image/x-up-wpng", "png"}, + {"audio/mpeg", "mp3"}, + {"audio/wav", "wav"}, + {"audio/x-wav", "wav"}, + {"audio/basic", "au"}, + {"audio/amr", "amr"}, + {"audio/x-amr", "amr"}, + {"audio/amr-wb", "amr"}, + {"audio/midi", "mid"}, + {"audio/sp-midi", "mid"}, + {"application/smil", "smil"}, + {NULL, NULL} +}; + +static Octstr *filename2content_type(char *fname) +{ + char *p = strrchr(fname, '.'); + int i; + + if (p) + for (i = 0; exts[i].file_ext; i++) + if (strcasecmp(p+1, exts[i].file_ext) == 0) + return octstr_imm(exts[i].ctype); + + return octstr_imm("application/octet-stream"); +} + +/* Return the prefix part of a url or file. */ +static Octstr *url_path_prefix(Octstr *url, int type) +{ + int i, j, len = octstr_len(url); + char *p = octstr_get_cstr(url); + + /* Set lower/upper limit of search. */ + if (type == URL_TYPE) { /* then skip first slashes. */ + char *x; + i = octstr_search(url, octstr_imm("://"),0); + if (i > 0) + i += 3; + else + i = 0; + x = rindex(p, '#'); /* look for fragment if any. */ + + if (x) + j = x - p - 1; + else + j = len - 1; + } else { + i = 0; + j = len - 1; + } + + /* Now search backwards for the last '/'. + * if you don't find one, set to end of string. + */ + + for (;j > i; j--) + if (p[j] == '/') + break; + if (j <= i) + j = len; + + return octstr_copy(url, 0, j); +} + +/* Get's just the host:port part, leaving out UrI */ +static Octstr *get_toplevel_url(Octstr *url) +{ + int i, len = octstr_len(url); + char *p = octstr_get_cstr(url); + + i = octstr_search(url, octstr_imm("://"),0); + + if (i > 0) + i += 3; + else + i = 0; + + for ( ; i < len; i++) + if (p[i] == '/') + break; + + return octstr_copy(url, 0, i); +} + +/* little dirty method to see if file begins with url scheme. */ +static int has_url_scheme(char *url) +{ + char *p = strstr(url, "://"); + + if (!p) + return 0; + for (p -= 1; p >= url; p--) + if (!isalpha(*p)) + return 0; + return 1; +} + +static int add_msg_part(MIMEEntity *res, xmlNodePtr node, Octstr *base_url, + Octstr *top_url, + int type, MmsEnvelope *e) +{ + Octstr *curl = NULL, *ctype = NULL, *body = NULL; + char *src = NULL; + int isurl, slash_prefix; + MmsService *ms = e->_x; + static int cntr; /* For generating cids */ + + /* For each node in the smil doc, if it has an src attribute, then: + * - if our type of base_url is FILE *and the src attribute does not look + * like a url, then file the file referenced, load it into the message and go + * - if our type is URL and the url scheme is http/https (or has no scheme) + * then fetch it and put into message. + */ + + if (!node || node->type != XML_ELEMENT_NODE || + (src = (char *)xmlGetProp(node, (unsigned char *)"src")) == NULL) + return 0; /* Nothing to do. */ + + if (src[0] == '\\') { /* User can escape url to prevent substitution. */ + xmlSetProp(node, (xmlChar *)"src", (xmlChar *)(src + 1)); + goto done; + } + + isurl = has_url_scheme(src); + slash_prefix = (src[0] == '/'); + + if (isurl && strstr(src, "http") != 0) /* Only http and https allowed! */ + goto done; + + if (isurl) + ctype = octstr_create(src); + else if (slash_prefix) { + if (type == URL_TYPE) + curl = octstr_format("%S%s", + top_url, src); + else + curl = octstr_create(src); + } else + curl = octstr_format("%S/%s",base_url, src); + + isurl |= (type == URL_TYPE); /* From now on, this flag tells us whether we are fetching a url.*/ + + if (isurl) { + List *rh = http_create_empty_headers(), *rph = NULL; + + http_header_add(rh, "User-Agent", MM_NAME "/" GW_VERSION); + if (mmsbox_http_fetch_content(HTTP_METHOD_POST, curl, rh, NULL, &rph, &body) == HTTP_OK) + ctype = http_header_value(rph, octstr_imm("Content-Type")); + else + error(0, "MMSBOX: Failed to load url %s within SMIL content from service %s!", + octstr_get_cstr(curl), octstr_get_cstr(ms->name)); + if (rph) + http_destroy_headers(rph); + http_destroy_headers(rh); + } else { + body = octstr_read_file(octstr_get_cstr(curl)); + ctype = filename2content_type(src); + } + + if (ctype && body) { /* If we got it, put it in. */ + Octstr *attr = octstr_format("cid:%06d", ++cntr); + char *p = octstr_get_cstr(attr) + 4; + Octstr *cid_header_val = octstr_format("<%s>", p); + MIMEEntity *x = mime_entity_create(); + + http_header_add(x->headers, "Content-Type", octstr_get_cstr(ctype)); + http_header_add(x->headers, "Content-ID", octstr_get_cstr(cid_header_val)); + x->body = body; + + list_append(res->multiparts, x); + + xmlSetProp(node, (xmlChar *)"src", (xmlChar *)octstr_get_cstr(attr)); + + octstr_destroy(attr); + octstr_destroy(cid_header_val); + } + +done: + if (curl) + octstr_destroy(curl); + if (ctype) + octstr_destroy(ctype); + xmlFree(src); + return 0; +} + +/* Traverse the tree doing the above. */ +static void add_msg_parts(MIMEEntity *res, xmlNodePtr node, Octstr *base_url, + Octstr *top_url, + int type, MmsEnvelope *e) +{ + xmlNodePtr n; + /* Do all the children recursively, then come back and do parent. */ + for (n = node; n; n = n->next) + if (n->type != XML_COMMENT_NODE) { + add_msg_part(res, n, base_url, top_url, type, e); + add_msg_parts(res, n->xmlChildrenNode, base_url, top_url, type, e); + } +} + +/* Given content, make a message. We'll also use this for send-mms-user! */ +static int make_and_queue_msg(Octstr *data, Octstr *ctype, List *reply_headers, + Octstr *base_url, int type, MmsEnvelope *e, + Octstr *svc_name, Octstr *faked_sender, + int accept_x_headers, Octstr **err) +{ + Octstr *from = NULL, *subject = NULL, *turl = get_toplevel_url(base_url); + Octstr *dlr_url = NULL, *rr_url = NULL, *mmc = NULL; + MmsMsg *m = NULL; + MIMEEntity *me = mime_entity_create(); + + time_t expiryt = 0; + Octstr *x; + List *xto = list_create();; + int i, n, res = -1; + + gw_assert(svc_name); + + /* Get the from address. */ + if (faked_sender) + from = octstr_duplicate(faked_sender); + else if (accept_x_headers && reply_headers && + (from = http_header_value(reply_headers, octstr_imm("X-Mbuni-From"))) != NULL) + (void)0; /* all done above. */ + else { + /* get first recipient, set that as sender. */ + MmsEnvelopeTo *r = (e) ? list_get(e->to, 0) : NULL; + if (r) + from = octstr_duplicate(r->rcpt); + else + from = octstr_imm("anon@anon"); + } + + /* start with the easy one... */ + if (octstr_case_compare(ctype, octstr_imm("application/vnd.wap.mms-message")) == 0) { + m = mms_frombinary(data, from); + goto done; /* all done! */ + } else if (octstr_case_compare(ctype, octstr_imm("application/smil")) == 0) { + xmlDocPtr smil; + xmlChar *buf = NULL; + int bsize = 0; + + /* This is the hard bit! */ + http_header_add(me->headers, "Content-Type", "multipart/related; " + "type=\"application/smil\"; start=\"\""); + + /* Parse the smil as XML. */ + smil = xmlParseMemory(octstr_get_cstr(data), octstr_len(data)); + if (!smil || !smil->xmlChildrenNode) { + *err = octstr_format("MMSBox: Error parsing SMIL response from service[%s], " + " msgid %s!", octstr_get_cstr(svc_name), + (e && e->msgId) ? octstr_get_cstr(e->msgId) : "(none)"); + goto done; + } + + add_msg_parts(me, smil->xmlChildrenNode, base_url, turl, type, e); + + /* SMIL has been modified, convert it to text, put it in. */ + xmlDocDumpFormatMemory(smil, &buf, &bsize, 1); + xmlFreeDoc(smil); + if (buf) { + MIMEEntity *sm = mime_entity_create(); + + http_header_add(sm->headers, "Content-Type", "application/smil"); + http_header_add(sm->headers, "Content-ID", ""); + sm->body = octstr_create_from_data((char *)buf, bsize); + list_append(me->multiparts, sm); + me->start = sm; + xmlFree(buf); + } else { + *err = octstr_format("MMSBox: Error writing converted SMIL " + "for response from service[%s], " + " msgid %s!", + octstr_get_cstr(svc_name), + (e && e->msgId) ? octstr_get_cstr(e->msgId) : "(none)"); + goto done; + } + } else { /* all others, make the message as-is and hope for the best! */ + http_header_add(me->headers, "Content-Type", octstr_get_cstr(ctype)); + + me->body = octstr_duplicate(data); + } + + /* Get headers needed, if we are allowed to do so. */ + if (accept_x_headers && reply_headers) { + Octstr *x = NULL; + List *l = NULL; + subject = http_header_value(reply_headers, octstr_imm("X-Mbuni-Subject")); + + if ((x = http_header_value(reply_headers, octstr_imm("X-Mbuni-Expiry"))) != NULL) + expiryt = date_parse_http(x); + + if ((l = http_header_find_all(reply_headers, "X-Mbuni-To")) != NULL) { + int i, n; + for (i = 0, n = list_len(l); ifrom) + list_append(xto, octstr_duplicate(e->from)); + + if (!subject && e && e->subject) + subject = octstr_duplicate(e->subject); + + if (!mmc && e) + mmc = e->fromproxy; + + /* Add some nice headers. */ + http_header_add(me->headers, "From", octstr_get_cstr(from)); + + for (i = 0, n = list_len(xto); i < n; i++) { + Octstr *v, *h; + http_header_get(xto, i, &h, &v); + http_header_add(me->headers, "To", octstr_get_cstr(v)); + octstr_destroy(h); + octstr_destroy(v); + } + + if (dlr_url) + http_header_add(me->headers, "X-Mms-Delivery-Report", "Yes"); + if (rr_url) + http_header_add(me->headers, "X-Mms-Read-Report", "Yes"); + if (subject) + http_header_add(me->headers, "Subject", octstr_get_cstr(subject)); + if (expiryt > 0) { + Octstr *x = date_format_http(expiryt); + http_header_add(me->headers, "X-Mms-Expiry", octstr_get_cstr(x)); + octstr_destroy(x); + } + + if (me) + m = mms_frommime(me); + if (!m) { + *err = octstr_format("MMSBox: Failed to convert Mms Message from service %s!", + octstr_get_cstr(svc_name)); + goto done; + } + /* Write to queue. */ + x = mms_queue_add(from, xto, subject, + e ? e->fromproxy : NULL, + mmc, + time(NULL), expiryt, m, NULL, + NULL, svc_name, + dlr_url, rr_url, + (dlr_url != NULL), + octstr_get_cstr(outgoing_qdir), + octstr_imm(MM_NAME)); + info(0, "MMSBox: Queued message from service [%s] to outgoing: %s", + octstr_get_cstr(svc_name), octstr_get_cstr(x)); + octstr_destroy(x); + res = 0; +done: + + if (dlr_url) + octstr_destroy(dlr_url); + + if (rr_url) + octstr_destroy(rr_url); + + if (from) + octstr_destroy(from); + if (subject) + octstr_destroy(subject); + if (me) + mime_entity_destroy(me); + if (m) + mms_destroy(m); + if (xto) + list_destroy(xto, (list_item_destructor_t *)octstr_destroy); + + return res; +} + + +static SendMmsUser *auth_user(Octstr *user, Octstr *pass) +{ + int i, n; + SendMmsUser *u = NULL; + for (i = 0, n = list_len(sendmms_users); i < n; i++) + if ((u = list_get(sendmms_users, i)) != NULL && + octstr_compare(u->user, user) == 0 && + octstr_compare(u->pass, pass) == 0) + return u; + return NULL; +} + +static void sendmms_func(void *unused) +{ + HTTPClient *client = NULL; + Octstr *ip = NULL, *url = NULL; + Octstr *body = NULL; + List *cgivars = NULL, *h = NULL; + + while (!rstop && + (client = http_accept_request(sendmms_port.port, + &ip, &url, &h, &body, &cgivars)) != NULL) { + SendMmsUser *u = NULL; + List *hh = http_create_empty_headers(); + Octstr *username = http_cgi_variable(cgivars, "username"); + Octstr *password = http_cgi_variable(cgivars, "password"); + Octstr *err = NULL; + + if ((u = auth_user(username, password)) != NULL && + is_allowed_ip(sendmms_port.deny_ip, sendmms_port.allow_ip, ip)) { + Octstr *data, *ctype = NULL, *mmc, *to, *from, *dlr_url; + Octstr *rr_url, *subject = NULL; + List *lto = NULL, *rh = http_create_empty_headers(); + Octstr *rb = NULL, *base_url = octstr_imm("http://localhost"); + int i, n, res = 0; + + if ((data = http_cgi_variable(cgivars, "text")) != NULL) { /* text. */ + Octstr *charset = http_cgi_variable(cgivars, "charset"); + + ctype = octstr_format("text/plain"); + if (charset) { + octstr_format_append(ctype, "; charset=%S", charset); + octstr_destroy(charset); + } + } else if ((data = http_cgi_variable(cgivars, "smil")) != NULL) /* smil. */ + ctype = octstr_imm("application/smil"); + else + rb = octstr_imm("Missing content"); + + if ((from = http_cgi_variable(cgivars, "from")) == NULL && !u->faked_sender) + rb = octstr_imm("Missing Sender address"); + + dlr_url = http_cgi_variable(cgivars, "dlr_url"); + rr_url = http_cgi_variable(cgivars, "rr_url"); + mmc = http_cgi_variable(cgivars, "mmsc"); + subject = http_cgi_variable(cgivars, "subject"); + + if ((to = http_cgi_variable(cgivars, "to")) == NULL) + rb = octstr_imm("Missing recipient!"); + else + lto = octstr_split_words(to); + + /* Build the fake reply headers. */ + if (ctype) + http_header_add(rh, "Content-Type", octstr_get_cstr(ctype)); + + if (from) { + http_header_add(rh, "X-Mbuni-From", octstr_get_cstr(from)); + octstr_destroy(from); + } + + if (lto) { + for (i = 0, n = list_len(lto); i < n; i++) { + Octstr *x = list_get(lto, i); + _mms_fixup_address(x); + http_header_add(rh, "X-Mbuni-To", octstr_get_cstr(x)); + } + list_destroy(lto, (list_item_destructor_t *)octstr_destroy); + } + + if (dlr_url) { + http_header_add(rh, "X-Mbuni-DLR-Url", octstr_get_cstr(dlr_url)); + octstr_destroy(dlr_url); + } + + if (rr_url) { + http_header_add(rh, "X-Mbuni-RR-Url", octstr_get_cstr(rr_url)); + octstr_destroy(rr_url); + } + + if (mmc) { + http_header_add(rh, "X-Mbuni-MMSC", octstr_get_cstr(mmc)); + octstr_destroy(mmc); + } + + if (subject) { + http_header_add(rh, "X-Mbuni-Subject", octstr_get_cstr(subject)); + octstr_destroy(subject); + } + + + /* Requests to make_and_queue below can block, but for now we don't care. */ + if (ctype && data) { + res = make_and_queue_msg(data, ctype, rh, base_url, URL_TYPE, NULL, + octstr_imm("sendmms-user"), u->faked_sender, + 1, &err); + + http_destroy_headers(rh); + if (res < 0) + rb = octstr_imm("Error in message conversion"); + } else if (!rb) + rb = octstr_imm("Failed to send message"); + + http_send_reply(client, HTTP_BAD_REQUEST, hh, rb); + + info(0, "MMSBox.mmssend: u=%s, %s", + u ? octstr_get_cstr(u->user) : "none", + (res == 0) ? "Sent" : "Not Sent"); + octstr_destroy(base_url); + if (data) + octstr_destroy(data); + if (ctype) + octstr_destroy(ctype); + } else { + http_send_reply(client, HTTP_UNAUTHORIZED, hh, + octstr_imm("Authentication failed")); + err = octstr_format("MMSBox: SendMMS, Authentication failed, " + "username=%s, password=%s!", + username ? octstr_get_cstr(username) : "(null)", + password ? octstr_get_cstr(password) : "(null)"); + } + + if (err) { + error(0, "%s", octstr_get_cstr(err)); + octstr_destroy(err); + } + + /* Free the ip and other stuff here. */ + if (username) + octstr_destroy(username); + if (password) + octstr_destroy(password); + octstr_destroy(ip); + if (body) octstr_destroy(body); + octstr_destroy(url); + http_destroy_cgiargs(cgivars); + http_destroy_headers(h); + } + +} diff --git a/mbuni/mmsbox/mmsbox_cfg.c b/mbuni/mmsbox/mmsbox_cfg.c index be31268..0ad156f 100644 --- a/mbuni/mmsbox/mmsbox_cfg.c +++ b/mbuni/mmsbox/mmsbox_cfg.c @@ -1,7 +1,7 @@ /* * Mbuni - Open Source MMS Gateway * - * MMSC CFG: MMC configuration and misc. functions + * MMSBox CFG: MMBox configuration and misc. functions * * Copyright (C) 2003 - 2005, Digital Solutions Ltd. - http://www.dsmagic.com * @@ -26,14 +26,18 @@ List *sendmms_users = NULL; /* list of SendMmsUser structs */ List *mms_services = NULL; /* list of MMS Services */ List *mmscs = NULL; -Octstr *incoming_qdir, *outgoing_qdir; +Octstr *incoming_qdir, *outgoing_qdir, *dlr_dir; +long mmsbox_maxsendattempts, mmsbox_send_back_off; +long queue_interval, maxthreads; +Octstr *unified_prefix; + struct SendMmsPortInfo sendmms_port; int mms_load_mmsbox_settings(Cfg *cfg, gwthread_func_t *mmsc_handler_func) { CfgGroup *grp = cfg_get_single_group(cfg, octstr_imm("mmsbox")); CfgGroup *cgrp = cfg_get_single_group(cfg, octstr_imm("core")); - Octstr *gdir; + Octstr *gdir, *s; int send_port_ssl = 0; List *l; int i, n; @@ -52,11 +56,12 @@ int mms_load_mmsbox_settings(Cfg *cfg, gwthread_func_t *mmsc_handler_func) if (mkdir(octstr_get_cstr(gdir), S_IRWXU|S_IRWXG) < 0 && errno != EEXIST) - panic(0, "Failed to create queue directory: %s - %s!", + panic(0, "Failed to create MMSBox storage directory: %s - %s!", octstr_get_cstr(gdir), strerror(errno)); incoming_qdir = octstr_format("%S/mmsbox_incoming", gdir); outgoing_qdir = octstr_format("%S/mmsbox_outgoing", gdir); + dlr_dir = octstr_format("%S/mmsbox_dlr", gdir); if (mms_init_queuedir(incoming_qdir) < 0) panic(0, "Failed to initialise incoming queue directory: %s - %s!", @@ -65,6 +70,31 @@ int mms_load_mmsbox_settings(Cfg *cfg, gwthread_func_t *mmsc_handler_func) if (mms_init_queuedir(outgoing_qdir) < 0) panic(0, "Failed to initialise outgoing queue directory: %s - %s!", octstr_get_cstr(outgoing_qdir), strerror(errno)); + + if (mms_init_queuedir(dlr_dir) < 0) + panic(0, "Failed to initialise dlr storage directory: %s - %s!", + octstr_get_cstr(dlr_dir), strerror(errno)); + + if (cfg_get_integer(&mmsbox_maxsendattempts, grp, + octstr_imm("maximum-send-attempts")) < 0) + mmsbox_maxsendattempts = MAXQTRIES; + + if (cfg_get_integer(&mmsbox_send_back_off, grp, + octstr_imm("send-attempt-back-off")) == -1) + mmsbox_send_back_off = BACKOFF_FACTOR; + + + if (cfg_get_integer(&maxthreads, grp, octstr_imm("max-send-threads")) == -1) + maxthreads = 10; + + s = _mms_cfg_getx(grp, octstr_imm("queue-run-interval")); + if (!s || (queue_interval = atof(octstr_get_cstr(s))) <= 0) + queue_interval = QUEUERUN_INTERVAL; + + if (s) + octstr_destroy(s); + + unified_prefix = _mms_cfg_getx(grp, octstr_imm("unified-prefix")); cfg_get_integer(&sendmms_port.port, grp, octstr_imm("sendmms-port")); #ifdef HAVE_LIBSSL @@ -90,6 +120,8 @@ int mms_load_mmsbox_settings(Cfg *cfg, gwthread_func_t *mmsc_handler_func) u->user = _mms_cfg_getx(x, octstr_imm("username")); u->pass = _mms_cfg_getx(x, octstr_imm("password")); u->faked_sender = _mms_cfg_getx(x, octstr_imm("faked-sender")); + u->dlr_url = _mms_cfg_getx(x, octstr_imm("delivery-report-url")); + u->rr_url = _mms_cfg_getx(x, octstr_imm("read-report-url")); list_append(sendmms_users, u); } list_destroy(l, NULL); @@ -107,6 +139,12 @@ int mms_load_mmsbox_settings(Cfg *cfg, gwthread_func_t *mmsc_handler_func) m->id = _mms_cfg_getx(x, octstr_imm("id")); m->mmsc_url = _mms_cfg_getx(x, octstr_imm("mmsc-url")); + m->allowed_prefix = _mms_cfg_getx(x, octstr_imm("allowed-prefix")); + m->denied_prefix = _mms_cfg_getx(x, octstr_imm("denied-prefix")); + + m->incoming.allow_ip = cfg_get(x, octstr_imm("allow-ip")); + m->incoming.deny_ip = cfg_get(x, octstr_imm("deny-ip")); + m->incoming.user = _mms_cfg_getx(x, octstr_imm("incoming-username")); m->incoming.pass = _mms_cfg_getx(x, octstr_imm("incoming-password")); cfg_get_integer(&m->incoming.port, x, octstr_imm("incoming-port")); @@ -135,14 +173,15 @@ int mms_load_mmsbox_settings(Cfg *cfg, gwthread_func_t *mmsc_handler_func) m->incoming.port = 0; /* so we don't listen on it. */ } - if (mmsc_handler_func) { /* Only start threads if func passed. */ + if (mmsc_handler_func && m->incoming.port > 0) { /* Only start threads if func passed and ... */ if ((m->threadid = gwthread_create(mmsc_handler_func, m)) < 0) error(0, "MMSBox: Failed to start MMSC handler thread for MMSC[%s]: %s!", octstr_get_cstr(m->id), strerror(errno)); } else m->threadid = -1; - list_append(mmscs, m); - + + m->mutex = mutex_create(); + list_append(mmscs, m); } list_destroy(l, NULL); @@ -178,6 +217,12 @@ int mms_load_mmsbox_settings(Cfg *cfg, gwthread_func_t *mmsc_handler_func) octstr_destroy(s); } else m->allowed_mmscs = NULL; /* means allow all. */ + + if ((s = cfg_get(x, octstr_imm("denied-mmscs"))) != NULL) { + m->denied_mmscs = octstr_split(s, octstr_imm(";")); + octstr_destroy(s); + } else + m->denied_mmscs = NULL; /* means allow all. */ /* Get key words. Start with aliases to make life easier. */ if ((s = cfg_get(x, octstr_imm("aliases"))) != NULL) { diff --git a/mbuni/mmsbox/mmsbox_cfg.h b/mbuni/mmsbox/mmsbox_cfg.h index 80f464d..7e8237a 100644 --- a/mbuni/mmsbox/mmsbox_cfg.h +++ b/mbuni/mmsbox/mmsbox_cfg.h @@ -19,18 +19,23 @@ typedef struct MmscGrp { Octstr *mmsc_url; /* URL at which MMSC can be reached. */ struct { Octstr *user, *pass; + Octstr *allow_ip; + Octstr *deny_ip; long port; } incoming; /* user, pass, port (and whether SSL) that MMSC uses to connect to us. */ + Octstr *allowed_prefix, *denied_prefix; enum {UNKNOWN_MMSC, SOAP_MMSC, EAIF_MMSC} type; /* type of connection. */ long throughput; /* Max send rate. */ long threadid; /* handler thread. */ + + Mutex *mutex; } MmscGrp; typedef struct MmsServiceUrlParam { Octstr *name; enum {NO_PART, IMAGE_PART, VIDEO_PART, TEXT_PART, SMIL_PART , OTHER_PART, - ANY_PART } type; + ANY_PART, WHOLE_BINARY} type; Octstr *value; /* for generic value (type == NO_PART), * or for value that follows spec (e.g. %Tisatest is allowed) */ } MmsServiceUrlParam; @@ -44,23 +49,28 @@ typedef struct MmsService { List *keywords; /* List of keywords matched. */ enum {TRANS_TYPE_GET_URL, TRANS_TYPE_POST_URL, TRANS_TYPE_FILE, TRANS_TYPE_EXEC, TRANS_TYPE_TEXT} type; - Octstr *url; + Octstr *url; /* The value. */ List *params; /* of MmsServiceUrlParam */ Octstr *faked_sender; List *allowed_mmscs; /* List of MMSCs allowed to access this service (by ID). */ + List *denied_mmscs; /* List of MMSCs allowed to access this service (by ID). */ } MmsService; typedef struct SendMmsUser { Octstr *user, *pass; Octstr *faked_sender; + Octstr *dlr_url, *rr_url; } SendMmsUser; /* Basic settings for the mmsbox. */ extern List *sendmms_users; /* list of SendMmsUser structs */ extern List *mms_services; /* list of MMS Services */ -extern List *mmscs; -extern Octstr *incoming_qdir, *outgoing_qdir; +extern List *mmscs; /* MMSC list. Perhaps turn into a Dict instead? */ +extern Octstr *incoming_qdir, *outgoing_qdir, *dlr_dir; +extern Octstr *unified_prefix; +extern long mmsbox_maxsendattempts, mmsbox_send_back_off; +extern long queue_interval, maxthreads; extern struct SendMmsPortInfo { long port; /* Might be ssl-ed. */ Octstr *allow_ip; diff --git a/mbuni/mmsc/mmsc_cfg.c b/mbuni/mmsc/mmsc_cfg.c index 1b1f297..2dcdfb0 100644 --- a/mbuni/mmsc/mmsc_cfg.c +++ b/mbuni/mmsc/mmsc_cfg.c @@ -23,10 +23,6 @@ #include "mmsc_cfg.h" #include "mms_queue.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. */ @@ -154,6 +150,9 @@ MmscSettings *mms_load_mmsc_settings(Cfg *cfg, List **proxyrelays) s = _mms_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 (s) + octstr_destroy(s); if (cfg_get_integer(&m->send_back_off, grp, octstr_imm("send-attempt-back-off")) == -1) m->send_back_off = BACKOFF_FACTOR; diff --git a/mbuni/mmsc/mmsfromemail.c b/mbuni/mmsc/mmsfromemail.c index 3cb124a..eea9fba 100644 --- a/mbuni/mmsc/mmsfromemail.c +++ b/mbuni/mmsc/mmsfromemail.c @@ -24,7 +24,7 @@ static Octstr *xproxy; enum {TPLMN, TEMAIL, TOTHER} ttype; static int find_own(int i, int argc, char *argv[]); -static int isphonenum(Octstr *s); + static void fixup_recipient(void); static void fixup_sender(void); @@ -144,6 +144,7 @@ int main(int argc, char *argv[]) qf = mms_queue_add(xfrom, lto, NULL, xproxy, NULL, 0, time(NULL) + settings->default_msgexpiry, msg, NULL, NULL, NULL, + NULL, NULL, dlr, octstr_get_cstr(settings->global_queuedir), settings->host_alias); @@ -174,6 +175,7 @@ int main(int argc, char *argv[]) 0, time(NULL) + settings->default_msgexpiry, mresp, NULL, NULL, NULL, + NULL, NULL, 0, octstr_get_cstr(settings->global_queuedir), settings->host_alias); @@ -243,7 +245,8 @@ int main(int argc, char *argv[]) qf = mms_queue_add(xfrom, lto, NULL, xproxy, NULL, 0, time(NULL) + settings->default_msgexpiry, msg, NULL, - NULL, NULL, + NULL, NULL, + NULL, NULL, 0, octstr_get_cstr(settings->global_queuedir), settings->host_alias); @@ -280,6 +283,7 @@ int main(int argc, char *argv[]) xproxy, NULL, 0, time(NULL) + settings->default_msgexpiry, msg, NULL, NULL, NULL, + NULL, NULL, 0, octstr_get_cstr(settings->global_queuedir), settings->host_alias); @@ -335,19 +339,6 @@ static int find_own(int i, int argc, char *argv[]) return -1; } -static 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); ifromproxy, tnow, tnow+settings->default_msgexpiry, m, NULL, NULL, NULL, + NULL, NULL, 0, qdir, settings->host_alias); @@ -393,6 +394,7 @@ int mms_sendtomobile(Octstr *from, Octstr *to, ret = mms_queue_add(from, l, subject, fromproxy, NULL, 0, expires, m, x, NULL, NULL, + NULL, NULL, dlr, mobile_qdir, settings->host_alias); octstr_destroy(x); @@ -432,6 +434,7 @@ static int mms_sendtoproxy(Octstr *from, Octstr *to, Octstr *ret; list_append(l, to); ret = mms_queue_add(from, l, subject, NULL, proxy, 0, expires, msg,NULL, + NULL, NULL, NULL, NULL, dlr, mm4_qdir, settings->host_alias); @@ -489,7 +492,8 @@ static int mm7soap_send(MmsVasp *vasp, Octstr *from, Octstr *to, Octstr *msgId, list_append(xto, to); - if ((mreq = mm7_mmsmsg_to_soap(m, from, xto, msgId, settings->host_alias)) == NULL) { + if ((mreq = mm7_mmsmsg_to_soap(m, from, xto, msgId, settings->host_alias, + 0, NULL, NULL)) == NULL) { *error = octstr_format("Failed to convert Msg[%s] 2 SOAP message!", mms_message_type_to_cstr(mtype)); goto done1; diff --git a/mbuni/mmsc/mmsmobilesender.c b/mbuni/mmsc/mmsmobilesender.c index a7d4a54..961ae4b 100644 --- a/mbuni/mmsc/mmsmobilesender.c +++ b/mbuni/mmsc/mmsmobilesender.c @@ -412,6 +412,7 @@ static int sendNotify(MmsEnvelope *e) NULL, fromproxy, tnow, tnow+settings->default_msgexpiry, m, NULL, NULL, NULL, + NULL, NULL, 0, octstr_get_cstr(settings->mm1_queuedir), settings->host_alias); diff --git a/mbuni/mmsc/mmsproxy.c b/mbuni/mmsc/mmsproxy.c index dc267cf..c484c88 100644 --- a/mbuni/mmsc/mmsproxy.c +++ b/mbuni/mmsc/mmsproxy.c @@ -23,18 +23,6 @@ #include "mms_mm7soap.h" -static Cfg *cfg; -static List *proxyrelays; -static MmscSettings *settings; - -static int rstop = 0; -static void quit_now(int notused) -{ - rstop = 1; - if (settings) - http_close_port(settings->port); -} - typedef struct MmsHTTPClientInfo { HTTPClient *client; Octstr *ua; @@ -49,6 +37,18 @@ typedef struct MmsHTTPClientInfo { MmsVasp *vasp; } MmsHTTPClientInfo; +static Cfg *cfg; +static List *proxyrelays; +static MmscSettings *settings; + +static int rstop = 0; +static void quit_now(int notused) +{ + rstop = 1; + if (settings) + http_close_port(settings->port); +} + static void free_clientInfo(MmsHTTPClientInfo *h, int freeh); static void fetchmms_proxy(MmsHTTPClientInfo *h); static void sendmms_proxy(MmsHTTPClientInfo *h); @@ -418,78 +418,6 @@ void fetchmms_proxy(MmsHTTPClientInfo *h) } /* Make list of recipients and also sender. */ -static void collect_senddata(List *mh, List **xto, - Octstr **subject, - Octstr **otransid, time_t *expiryt, time_t *deliveryt) -{ - - Octstr *s; - List *l = http_header_find_all(mh, "To"); - if (l) { - int i, n; - for (i = 0, n = list_len(l); idefault_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")); - -} static void sendmms_proxy(MmsHTTPClientInfo *h) { @@ -556,7 +484,8 @@ static void sendmms_proxy(MmsHTTPClientInfo *h) Octstr *sdf = NULL; - collect_senddata(mh, &to, &subject, &otransid, &expiryt, &deliveryt); + mms_collect_envdata_from_msgheaders(mh, &to, &subject, &otransid, &expiryt, + &deliveryt, settings->default_msgexpiry); if (!h->client_addr) { mresp = mms_sendconf("Error-sending-address-unresolved", "None", octstr_get_cstr(otransid),0, @@ -609,6 +538,7 @@ static void sendmms_proxy(MmsHTTPClientInfo *h) qf = mms_queue_add(from, to, subject, NULL, NULL, deliveryt, expiryt, m, NULL, NULL, NULL, + NULL, NULL, dlr, octstr_get_cstr(settings->global_queuedir), settings->host_alias); @@ -689,7 +619,8 @@ static void sendmms_proxy(MmsHTTPClientInfo *h) Octstr *sdf = NULL; - collect_senddata(mh, &to, &subject, &otransid, &expiryt, &deliveryt); + mms_collect_envdata_from_msgheaders(mh, &to, &subject, &otransid, &expiryt, + &deliveryt, settings->default_msgexpiry); if (!h->client_addr) { mresp = mms_sendconf("Error-sending-address-unresolved", "None", octstr_get_cstr(otransid),1, @@ -799,6 +730,7 @@ static void sendmms_proxy(MmsHTTPClientInfo *h) qf2 = mms_queue_add(from, to, subject, NULL, NULL, deliveryt, expiryt, mfwd, NULL, NULL, NULL, + NULL, NULL, dlr, octstr_get_cstr(settings->global_queuedir), settings->host_alias); @@ -886,6 +818,7 @@ static void sendmms_proxy(MmsHTTPClientInfo *h) time(NULL) + settings->default_msgexpiry, mrep, NULL, NULL, NULL, + NULL, NULL, 0, octstr_get_cstr(settings->global_queuedir), settings->host_alias); @@ -1005,6 +938,7 @@ static void sendmms_proxy(MmsHTTPClientInfo *h) x = mms_queue_add(settings->system_user, l, NULL, NULL, NULL, 0, time(NULL) + settings->default_msgexpiry, mrpt, NULL, NULL, NULL, + NULL, NULL, 0, octstr_get_cstr(settings->global_queuedir), settings->host_alias); @@ -1050,12 +984,14 @@ static void sendmms_proxy(MmsHTTPClientInfo *h) if (mms_convert_readrec2readorig(m) < 0) goto mdone2; - collect_senddata(mh, &to, NULL, NULL, NULL, NULL); + mms_collect_envdata_from_msgheaders(mh, &to, NULL, NULL, NULL, NULL, + settings->default_msgexpiry); x = mms_queue_add(from, to, NULL, NULL, NULL, time(NULL), time(NULL) + settings->default_msgexpiry, m, NULL, NULL, NULL, + NULL, NULL, 0, octstr_get_cstr(settings->global_queuedir), settings->host_alias); @@ -1664,7 +1600,9 @@ static void mm7soap_dispatch(MmsHTTPClientInfo *h) qf = mms_queue_add(from ? from : sender, to, subject, NULL, NULL, delivert, expiryt, m, NULL, - h->vasp->id, vasid, dlr, + h->vasp->id, vasid, + NULL, NULL, + dlr, octstr_get_cstr(settings->global_queuedir), settings->host_alias); msgid = mms_maketransid(octstr_get_cstr(qf), settings->host_alias); @@ -1857,7 +1795,8 @@ static void mm7eaif_dispatch(MmsHTTPClientInfo *h) /* Now get sender and receiver data. * for now we ignore adaptation flags. */ - collect_senddata(mh, &to, &subject, &otransid, &expiryt, &deliveryt); + mms_collect_envdata_from_msgheaders(mh, &to, &subject, &otransid, &expiryt, + &deliveryt, settings->default_msgexpiry); if ((hto = http_header_find_all(h->headers, "X-NOKIA-MMSC-To")) != NULL && @@ -1912,6 +1851,7 @@ static void mm7eaif_dispatch(MmsHTTPClientInfo *h) qf = mms_queue_add(hfrom, to, subject, NULL, NULL, deliveryt, expiryt, m, NULL, NULL, NULL, + NULL, NULL, dlr, octstr_get_cstr(settings->global_queuedir), settings->host_alias); @@ -1955,7 +1895,7 @@ static void mm7eaif_dispatch(MmsHTTPClientInfo *h) static void mm7proxy(void *unused) { - MmsHTTPClientInfo h = {NULL}; + MmsHTTPClientInfo h = {NULL}; while(rstop == 0 && (h.client = http_accept_request(settings->mm7port, &h.ip, &h.url, &h.headers, diff --git a/mbuni/mmsc/mmssend.c b/mbuni/mmsc/mmssend.c index a9040f8..bef3c6f 100644 --- a/mbuni/mmsc/mmssend.c +++ b/mbuni/mmsc/mmssend.c @@ -137,6 +137,7 @@ int main(int argc, char *argv[]) time(NULL) + settings->default_msgexpiry, m, NULL, NULL, NULL, + NULL, NULL, 0, octstr_get_cstr(settings->global_queuedir), settings->host_alias);