diff --git a/mbuni/ChangeLog b/mbuni/ChangeLog index a93f90f..51f4b00 100644 --- a/mbuni/ChangeLog +++ b/mbuni/ChangeLog @@ -1,3 +1,5 @@ +2010-12-09 P. A. Bagyenda + * Changes to mmsbox to allow it send multiple recipients per MM7 transaction 2010-11-30 P. A. Bagyenda * Minor fix in RFC 2047 text handling 2010-11-29 P. A. Bagyenda diff --git a/mbuni/doc/userguide.shtml b/mbuni/doc/userguide.shtml index 38cf2d5..1d0f94c 100644 --- a/mbuni/doc/userguide.shtml +++ b/mbuni/doc/userguide.shtml @@ -2755,6 +2755,22 @@ string + + + max-recipients + + + Number + + + Maximum number of recipients per transaction for this MMSC + (ignored for custom MMSC type). This controls how many To + addresses are included in each send transaction. Default is + 1. Note that failure of of the MMSC to accept any of the + recipients can result in the entire send request being retried. + + + reroute diff --git a/mbuni/mmlib/mms_cfg.def b/mbuni/mmlib/mms_cfg.def index a79cd9e..8eededd 100644 --- a/mbuni/mmlib/mms_cfg.def +++ b/mbuni/mmlib/mms_cfg.def @@ -194,6 +194,8 @@ MULTI_GROUP(mmsc, OCTSTR(default-vasid) OCTSTR(maximum-request-size) OCTSTR(strip-domain) + + OCTSTR(max-recipients) ) MULTI_GROUP(mms-service, diff --git a/mbuni/mmlib/mms_util.c b/mbuni/mmlib/mms_util.c index ddee217..46c79ea 100644 --- a/mbuni/mmlib/mms_util.c +++ b/mbuni/mmlib/mms_util.c @@ -529,7 +529,7 @@ static void addmmscname(Octstr *s, Octstr *myhostname) } -static int send2email(Octstr *to, Octstr *from, Octstr *subject, +static int send2email(List *xto, Octstr *from, Octstr *subject, Octstr *msgid, MIMEEntity *m, int append_hostname, Octstr **error, char *sendmail_cmd, Octstr *myhostname, @@ -543,9 +543,10 @@ static int send2email(Octstr *to, Octstr *from, Octstr *subject, Octstr *cmd = octstr_create(""); List *headers = mime_entity_headers(m); /* we don't want the mime version header removed. */ + Octstr *to = NULL; - fname[0] = 0; - + /* Make to address */ + if (append_hostname) { /* Add our hostname to all phone numbers. */ List *l = http_create_empty_headers(); Octstr *xfrom = http_header_value(headers, octstr_imm("From")); @@ -607,11 +608,7 @@ static int send2email(Octstr *to, Octstr *from, Octstr *subject, s = mime_entity_to_octstr(m); if (relay_host && relay_port > 0) { - List *lto = gwlist_create(); - gwlist_append(lto, octstr_duplicate(to)); - - ret = smtp_send(octstr_get_cstr(relay_host), relay_port, from, lto, s); - gwlist_destroy(lto, (void *)octstr_destroy); + ret = smtp_send(octstr_get_cstr(relay_host), relay_port, from, xto, s); goto done; } /* @@ -621,7 +618,8 @@ static int send2email(Octstr *to, Octstr *from, Octstr *subject, * s - subject * m - message id */ - + + LINEARISE_STR_LIST(to,xto," "); i = 0; for (;;) { Octstr *tmp; @@ -678,7 +676,8 @@ static int send2email(Octstr *to, Octstr *from, Octstr *subject, } i += 2; } - + + if ((fd = mkstemp(fname)) < 0) { *error = octstr_format("mkstemp: Failed to create temporary file: %s", strerror(errno)); @@ -721,6 +720,7 @@ done: http_destroy_headers(headers); octstr_destroy(cmd); octstr_destroy(s); + octstr_destroy(to); return ret; } @@ -804,11 +804,14 @@ int mm_send_to_email(Octstr *to, Octstr *from, Octstr *subject, char *sendmail_cmd, Octstr *myhostname, Octstr *relay_host, int relay_port) { - return send2email(to,from,subject,msgid,m,append_hostname,error,sendmail_cmd,myhostname, relay_host, relay_port); + List *lto = gwlist_create_ex(to); + int ret = send2email(lto,from,subject,msgid,m,append_hostname,error,sendmail_cmd,myhostname, relay_host, relay_port); + gwlist_destroy(lto, NULL); + return ret; } /* Send this message to email recipient. */ -int mms_sendtoemail(Octstr *from, Octstr *to, +int mms_sendtoemail(Octstr *from, List *lto, Octstr *subject, Octstr *msgid, MmsMsg *msg, int dlr, Octstr **error, char *sendmail_cmd, @@ -823,14 +826,19 @@ int mms_sendtoemail(Octstr *from, Octstr *to, MIMEEntity *m = NULL; List *headers = NULL; List *newhdrs = http_create_empty_headers(); - int ret = 0, mtype; + int ret = 0, mtype; + Octstr *to; gw_assert(msg); mtype = mms_messagetype(msg); + /* Make 'to' header field in case we need it. */ + LINEARISE_STR_LIST(to, lto, ", "); + if (!to || octstr_search_char(to, '@', 0) < 0) { *error = octstr_format("Invalid email address %S!", to); + octstr_destroy(to); return MMS_SEND_ERROR_FATAL; } @@ -840,6 +848,7 @@ int mms_sendtoemail(Octstr *from, Octstr *to, m == NULL) { mms_warning(0, "send2email", NULL, "Failed to format message (msg=%s,ret=%d)", m ? "OK" : "Not transformed",ret); + octstr_destroy(to); return -ret; } @@ -855,8 +864,10 @@ int mms_sendtoemail(Octstr *from, Octstr *to, http_header_add(newhdrs, "Subject", subject ? octstr_get_cstr(subject) : "MMS Message"); http_header_remove_all(headers, "From"); http_header_add(newhdrs, "From", octstr_get_cstr(from)); +#if 0 /* Should we reveal recipients ?? */ http_header_remove_all(headers, "To"); http_header_add(newhdrs, "To", octstr_get_cstr(to)); +#endif http_header_add(newhdrs, "Message-ID", msgid ? octstr_get_cstr(msgid) : ""); http_header_add(newhdrs, "MIME-Version", "1.0"); } else { @@ -947,9 +958,9 @@ int mms_sendtoemail(Octstr *from, Octstr *to, done: http_destroy_headers(headers); http_destroy_headers(newhdrs); - + octstr_destroy(to); if (ret == 0) - ret = send2email(to, + ret = send2email(lto, from, subject, msgid, m, mm4 == 0, error, sendmail_cmd, myhostname, relay_host, relay_port); mime_entity_destroy(m); @@ -2535,3 +2546,16 @@ Octstr *pack_rfc2047_text(Octstr *in, int charset_mib_enum) octstr_append_cstr(xs, "?="); return xs; } + +List *gwlist_create_ex_real(const char *file, const char *func, int line,...) +{ + va_list ap; + List *l = gwlist_create(); + void *v; + + va_start(ap, line); + + while ((v = va_arg(ap, void *)) != NULL) + gwlist_append(l, v); + return l; +} diff --git a/mbuni/mmlib/mms_util.h b/mbuni/mmlib/mms_util.h index 99b4cc3..f51495c 100644 --- a/mbuni/mmlib/mms_util.h +++ b/mbuni/mmlib/mms_util.h @@ -108,7 +108,7 @@ void base64_mimeparts(MIMEEntity *m, int all); /* Send this message to email recipient: Returns 0 on success 1 or 2 on profile error * (negate to get right one), -ve on some other error */ -int mms_sendtoemail(Octstr *from, Octstr *to, +int mms_sendtoemail(Octstr *from, List *lto, Octstr *subject, Octstr *msgid, MmsMsg *msg, int dlr, Octstr **error, char *sendmail_cmd, Octstr *myhostname, @@ -266,8 +266,24 @@ Octstr *parse_rfc2047_text(Octstr *in, int *mibenum); #define QUEUERUN_INTERVAL 1*60 /* 1 minutes. */ #define DEFAULT_EXPIRE 3600*24*7 /* One week */ +#define DEFAULT_SIMUL_RCPTS 10 + #define HTTP_REPLACE_HEADER(hdr, hname, value) do { \ http_header_remove_all((hdr), (hname)); \ http_header_add((hdr), (hname), (value)); \ } while (0) + +List *gwlist_create_ex_real(const char *file, const char *func, int line,...); + +#define gwlist_create_ex(...) gwlist_create_ex_real(__FILE__,__FUNCTION__,__LINE__, __VA_ARGS__, NULL) + +#define LINEARISE_STR_LIST(res,lst,sep) do { \ + Octstr *__res; \ + int __i; \ + for (__res = octstr_create(""), __i = 0; __i < gwlist_len(lst); __i++) \ + octstr_format_append(__res, "%s%S", \ + octstr_len(__res) == 0 ? "" : (sep), gwlist_get((lst), __i)); \ + (res) = __res; \ + } while (0) + #endif diff --git a/mbuni/mmsbox/bearerbox.c b/mbuni/mmsbox/bearerbox.c index b77b978..633f114 100644 --- a/mbuni/mmsbox/bearerbox.c +++ b/mbuni/mmsbox/bearerbox.c @@ -555,8 +555,7 @@ static int mm7eaif_receive(MmsBoxHTTPClientInfo *h) strip_prefixes); - if ((hto = http_header_find_all(h->headers, "X-NOKIA-MMSC-To")) != NULL && - gwlist_len(hto) > 0) { /* To address is in headers. */ + if ((hto = http_header_find_all(h->headers, "X-NOKIA-MMSC-To")) != NULL && gwlist_len(hto) > 0) { /* To address is in headers. */ int i, n; gwlist_destroy(to, (gwlist_item_destructor_t *)octstr_destroy); @@ -1137,7 +1136,7 @@ void mmsc_receive_func(MmscGrp *m) * are observed! * Don't remove from queue on fail, just leave it to expire. */ -static Octstr *mm7soap_send(MmscGrp *mmc, Octstr *from, Octstr *to, +static Octstr *mm7soap_send(MmscGrp *mmc, Octstr *from, List *lto, Octstr *transid, Octstr *linkedid, char *vasid, @@ -1149,14 +1148,16 @@ static Octstr *mm7soap_send(MmscGrp *mmc, Octstr *from, Octstr *to, { List *hdrs = e ? e->hdrs : NULL; Octstr *ret = NULL; - int mtype = mms_messagetype(m); + int mtype = mms_messagetype(m); int hstatus = HTTP_OK, tstatus = -1; - List *xto = gwlist_create(); MSoapMsg_t *mreq = NULL, *mresp = NULL; List *rh = NULL, *ph = NULL; Octstr *body = NULL, *rbody = NULL, *url = NULL; Octstr *s, *r, *status_details = NULL; char *xvasid = vasid ? vasid : (mmc->default_vasid ? octstr_get_cstr(mmc->default_vasid) : NULL); + Octstr *to; + + LINEARISE_STR_LIST(to,lto,", "); if (e == NULL || mmc == NULL) goto done1; @@ -1165,10 +1166,9 @@ static Octstr *mm7soap_send(MmscGrp *mmc, Octstr *from, Octstr *to, mms_message_type_to_cstr(mtype), octstr_get_cstr(from), octstr_get_cstr(to)); - gwlist_append(xto, to); if ((mreq = mm7_mmsmsg_to_soap(m, (mmc == NULL || mmc->no_senderaddress == 0) ? from : NULL, - xto, transid, + lto, transid, service_code, linkedid, 1, octstr_get_cstr(mmc->vasp_id), xvasid, NULL, 0,/* UA N/A on this side. */ @@ -1291,13 +1291,13 @@ done1: http_destroy_headers(ph); octstr_destroy(rbody); octstr_destroy(url); - gwlist_destroy(xto, NULL); + octstr_destroy(to); octstr_destroy(status_details); return ret; } -static Octstr *mm7eaif_send(MmscGrp *mmc, Octstr *from, Octstr *to, +static Octstr *mm7eaif_send(MmscGrp *mmc, Octstr *from, List *lto, Octstr *transid, char *vasid, MmsEnvelope *e, @@ -1312,8 +1312,10 @@ static Octstr *mm7eaif_send(MmscGrp *mmc, Octstr *from, Octstr *to, Octstr *body = NULL, *rbody = NULL, *xver = NULL; char *msgtype; MmsMsg *mresp = NULL; - int mresp_type = -1; + int mresp_type = -1, i; + Octstr *to; + LINEARISE_STR_LIST(to,lto,", "); if (e == NULL || mmc == NULL) goto done; @@ -1323,7 +1325,10 @@ static Octstr *mm7eaif_send(MmscGrp *mmc, Octstr *from, Octstr *to, octstr_get_cstr(from), octstr_get_cstr(to)); http_header_remove_all(rh, "X-Mms-Allow-Adaptations"); - http_header_add(rh, "X-NOKIA-MMSC-To", octstr_get_cstr(to)); + for (i = 0; i < gwlist_len(lto); i++) { + Octstr *to = gwlist_get(lto, i); + http_header_add(rh, "X-NOKIA-MMSC-To", octstr_get_cstr(to)); + } http_header_add(rh, "X-NOKIA-MMSC-From", octstr_get_cstr(from)); xver = octstr_format(EAIF_VERSION, mmc->ver.major, mmc->ver.minor1); @@ -1347,7 +1352,9 @@ static Octstr *mm7eaif_send(MmscGrp *mmc, Octstr *from, Octstr *to, /* Patch the message FROM and TO fields. */ mms_replace_header_value(m, "From", octstr_get_cstr(from)); +#if 0 mms_replace_header_value(m, "To", octstr_get_cstr(to)); +#endif mms_replace_header_value(m,"X-Mms-Transaction-ID", transid ? octstr_get_cstr(transid) : "000"); body = mms_tobinary(m); @@ -1411,7 +1418,7 @@ done: octstr_destroy(body); http_destroy_headers(ph); octstr_destroy(rbody); - + octstr_destroy(to); octstr_destroy(resp); octstr_destroy(xver); return ret; @@ -1420,7 +1427,7 @@ done: static Octstr *mm7http_send(MmscGrp *mmc, MmsEnvelope *e, - Octstr *from, Octstr *to, + Octstr *from, List *lto, MmsMsg *m, Octstr **error, int *retry) { @@ -1434,6 +1441,9 @@ static Octstr *mm7http_send(MmscGrp *mmc, MIMEEntity *form_data = make_multipart_formdata(); Octstr *transid = e ? octstr_create(e->xqfname) : NULL; int mm7type = mm7_msgtype_to_soaptype(mtype,1); + Octstr *to; + + LINEARISE_STR_LIST(to,lto," "); if (e == NULL || mmc == NULL) goto done; @@ -1448,7 +1458,6 @@ static Octstr *mm7http_send(MmscGrp *mmc, add_multipart_form_field(form_data, "from", "text/plain", NULL, from); add_multipart_form_field(form_data, "mms", "application/vnd.wap.mms-message", NULL, mms); - mmsbox_event_cb(mmc->id, mm7type, 0, octstr_imm("1.0"), 0, octstr_len(mms), e->attempts, from, to, NULL, transid, hdrs, NULL); @@ -1490,14 +1499,15 @@ done: octstr_destroy(mms); mime_entity_destroy(form_data); octstr_destroy(transid); - + octstr_destroy(to); + return ret; } -static int mms_sendtommsc(MmscGrp *mmc, MmsEnvelope *e, Octstr *to, +static int mms_sendtommsc(MmscGrp *mmc, MmsEnvelope *e, + List *lto, /* Of Octstr * */ Octstr *orig_transid, - MmsMsg *m, Octstr **new_msgid, List **errhdrs) @@ -1517,15 +1527,17 @@ static int mms_sendtommsc(MmscGrp *mmc, MmsEnvelope *e, Octstr *to, mutex_lock(mmc->mutex); { /* Grab a lock on it. */ Octstr *err = NULL; if (mmc->type == SOAP_MMSC) - id = mm7soap_send(mmc, from, to, transid, linkedid, vasid, service_code, e, m, &err, errhdrs, &retry); + id = mm7soap_send(mmc, from, lto, transid, linkedid, vasid, service_code, e, m, &err, errhdrs, &retry); else if (mmc->type == EAIF_MMSC) - id = mm7eaif_send(mmc, from, to, transid, vasid, e, m, &err, &retry); + id = mm7eaif_send(mmc, from, lto, transid, vasid, e, m, &err, &retry); else if (mmc->type == HTTP_MMSC) - id = mm7http_send(mmc,e, from, to, m, &err, &retry); - else if (mmc->type == CUSTOM_MMSC && mmc->started) + id = mm7http_send(mmc,e, from, lto, m, &err, &retry); + else if (mmc->type == CUSTOM_MMSC && mmc->started) { + Octstr *to = gwlist_get(lto, 0); /* XXX Send one at a time*/ id = mmc->fns->send_msg(mmc->data, from, to, transid, linkedid, vasid, service_code, m, hdrs, &err, &retry); + } #if 0 else if (mmc->type == MM4_MMSC && mmc->started) (void )0; /* Already sent above */ @@ -1562,208 +1574,314 @@ static int mms_sendtommsc(MmscGrp *mmc, MmsEnvelope *e, Octstr *to, return ret; } +typedef struct MRcpt_t { + int smtp_flag; + MmscGrp *mmc; + List *rto; /* List of envelope */ +} MRcpt_t; + +static int cmp_mrcpt(struct MRcpt_t *m, MmscGrp *mmc) +{ + + if (mmc == NULL && m->smtp_flag) + return 1; + else + return (mmc && mmc->id && m->mmc && m->mmc->id) && (octstr_case_compare(m->mmc->id, mmc->id) == 0); +} + +static void process_send_res(MmsEnvelope *e, MmsMsg *msg, + MmsEnvelopeTo *to, MmscGrp *mmc, + int res, Octstr *err, List *errl, Octstr *new_msgid, + int first_one) +{ + time_t tnow = time(NULL); + if (res == MMS_SEND_OK || res == MMS_SEND_QUEUED) { + to->process = 0; + + if (e->msgtype == MMS_MSGTYPE_SEND_REQ || + e->msgtype == MMS_MSGTYPE_RETRIEVE_CONF) /* queue dlr as needed. */ + queue_dlr(mmc, e->from, to->rcpt, new_msgid, octstr_imm("Forwarded"), "MM7-Out", errl); + } else if (res == MMS_SEND_ERROR_FATAL && mmc) { + if (e->msgtype == MMS_MSGTYPE_SEND_REQ || + e->msgtype == MMS_MSGTYPE_RETRIEVE_CONF) /* queue dlr as needed. */ + queue_dlr(mmc, e->from, to->rcpt, e->msgId, + (e->expiryt != 0 && e->expiryt < tnow) ? + octstr_imm("Expired") : octstr_imm("Rejected"), + "MM7-Out", errl); + } + + if (mmc) { + if (first_one) { + if (res == MMS_SEND_OK || res == MMS_SEND_QUEUED) + mmc->mt_pdus++; + else + mmc->mt_errors++; + } + mmc->last_pdu = time(NULL); + return_mmsc_conn(mmc); /* important. */ + } + + if (res == MMS_SEND_ERROR_FATAL) + to->process = 0; /* No more attempts. */ + + + /* handle CDR */ + if (res == MMS_SEND_OK || res == MMS_SEND_QUEUED || res == MMS_SEND_ERROR_FATAL) { + Octstr *mclass = mms_get_header_value(msg, octstr_imm("X-Mms-Message-Class")); + Octstr *prio = mms_get_header_value(msg, octstr_imm("X-Mms-Priority")); + Octstr *mstatus = mms_get_header_value(msg, octstr_imm("X-Mms-Status")); + + /* Do CDR */ + cdrfs->logcdr(e->created, + octstr_get_cstr(e->from), + octstr_get_cstr(to->rcpt), + octstr_get_cstr(e->msgId), + mmc ? octstr_get_cstr(mmc->id) : NULL, /* Should we touch mmc here? XXX */ + e->src_interface, + "MM7", + e->msize, + (char *)mms_message_type_to_cstr(e->msgtype), + + prio ? octstr_get_cstr(prio) : NULL, + mclass ? octstr_get_cstr(mclass) : NULL, + res == MMS_SEND_ERROR_FATAL ? "dropped" : (mstatus ? octstr_get_cstr(mstatus) : "sent"), + e->dlr, + 0); + + octstr_destroy(mclass); + octstr_destroy(prio); + octstr_destroy(mstatus); + } + + if (err == NULL) + mms_info(0, "MM7", NULL, "%s MMSBox Outgoing Queue MMS Send: From %s, to %s, msgsize=%ld: msgid=[%s]", + SEND_ERROR_STR(res), + octstr_get_cstr(e->from), octstr_get_cstr(to->rcpt), e->msize, + new_msgid ? octstr_get_cstr(new_msgid) : "N/A"); + else + mms_error_ex("MT", 0, + "MM7", NULL, + "%s MMSBox Outgoing Queue MMS Send: From %s, to %s, msgsize=%ld: %s", + SEND_ERROR_STR(res), + octstr_get_cstr(e->from), octstr_get_cstr(to->rcpt), e->msize, octstr_get_cstr(err)); +} + +/* Make a list of recpients up to max_rcpt */ +static inline List *make_srcpt_list(List *rto, int max_rcpt) +{ + List *l = gwlist_create(); + MmsEnvelopeTo *xto; + while ((max_rcpt > 0) && (xto = gwlist_extract_first(rto)) != NULL) { + gwlist_append(l, xto); + max_rcpt--; + } + + if (gwlist_len(l) == 0) { + gwlist_destroy(l, NULL); + l = NULL; + } + return l; +} static int sendMsg(MmsEnvelope *e) { MmsMsg *msg = NULL; int i, n; Octstr *otransid = e->hdrs ? http_header_value(e->hdrs, octstr_imm("X-Mbuni-TransactionID")) : NULL; - + MmscGrp _mmc_smtp = {.max_recipients = DEFAULT_SIMUL_RCPTS, .mutex = mutex_create()}; + MRcpt_t smtp_h = {.mmc = &_mmc_smtp, .smtp_flag = 1, .rto = gwlist_create()}; /* Signals that recipient is on other end of smtp pipe */ + List *mlist = NULL; /* List of MMScs */ + MmsEnvelopeTo *to; + time_t tnow = time(NULL); + if ((msg = qfs->mms_queue_getdata(e)) == NULL) { mms_error(0, "MM7", NULL, "MMSBox queue error: Failed to load message for queue id [%s]!", e->xqfname); MMSC_ISSUE_ALARM(NULL, MMSBOX_ALARM_RETRIEVE_MMS_ERROR, 4); goto done2; } else MMSC_CLEAR_ALARM(NULL, MMSBOX_ALARM_RETRIEVE_MMS_ERROR); + + mlist = gwlist_create_ex(&smtp_h); + + /* First split by mmc */ + for (i = 0, n = gwlist_len(e->to); ito, i)) != NULL && to->process && to->rcpt) { + Octstr *x, *err = NULL; + int is_email = (octstr_search_char(to->rcpt, '@', 0) > 0); + Octstr *requested_mmsc = NULL; + MmscGrp *mmc = NULL; + int res = MMS_SEND_OK; + MRcpt_t *m; + + 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_route; + } else if (e->attempts >= maxsendattempts) { + err = octstr_format("MMSBox error: Failed to deliver to " + "%S after %ld attempts. (max attempts allowed is %ld)!", + to->rcpt, e->attempts, + maxsendattempts); + res = MMS_SEND_ERROR_FATAL; + goto done_route; + } + + x = octstr_format("X-Mbuni-Via-%d", i); + requested_mmsc = e->hdrs ? http_header_value(e->hdrs, x) : NULL; + octstr_destroy(x); + + + if ((mmc = get_handler_mmc(requested_mmsc ? requested_mmsc : e->viaproxy, to->rcpt, e->from)) == NULL && + !is_email) { + 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_route; + } + + + /* We know how to route: If mmc is null at this point, means mm4 recipient. */ + if ((m = gwlist_search(mlist, mmc, (void *)cmp_mrcpt)) == NULL) { /* A new route, add recipient zone */ + m = gw_malloc(sizeof *m); + m->smtp_flag = 0; + m->mmc = mmc; + m->rto = gwlist_create(); + + gwlist_append(mlist, m); + } + + gwlist_append(m->rto, to); /* Record route. */ + + done_route: + if (res != MMS_SEND_OK) + process_send_res(e, msg, to, mmc, res, err, NULL, NULL, 0); + octstr_destroy(err); + octstr_destroy(requested_mmsc); + } - for (i = 0, n = gwlist_len(e->to); ito, i); - Octstr *err = NULL, *x; - time_t tnow = time(NULL); - MmscGrp *mmc = NULL; - Octstr *new_msgid = NULL; - List *errl = NULL; - int is_email = 0; - Octstr *requested_mmsc = 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 >= maxsendattempts) { - err = octstr_format("MMSBox error: Failed to deliver to " - "%S after %ld attempts. (max attempts allowed is %ld)!", - to->rcpt, e->attempts, - maxsendattempts); - res = MMS_SEND_ERROR_FATAL; - goto done; - } + for (i = 0, n = gwlist_len(mlist); immc->max_recipients; + List *lto; - is_email = (octstr_search_char(to->rcpt, '@', 0) > 0); - - x = octstr_format("X-Mbuni-Via-%d", i); - requested_mmsc = e->hdrs ? http_header_value(e->hdrs, x) : NULL; - octstr_destroy(x); - if ((mmc = get_handler_mmc(requested_mmsc ? requested_mmsc : e->viaproxy, to->rcpt, e->from)) == NULL && - !is_email) { - 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; - } - - if (is_email || (mmc->type == MM4_MMSC && mmc->started)) { /* Handle MM4 recipient here as well */ - int j = octstr_case_search(e->from, octstr_imm("/TYPE=PLMN"), 0); - int k = octstr_case_search(e->from, octstr_imm("/TYPE=IPv"), 0); - int len = octstr_len(e->from); - Octstr *pfrom, *xto; + /* Hive off maxrcpt each time and send. */ + while (e != NULL && (lto = make_srcpt_list(m->rto, maxrcpt)) != NULL) { + MmscGrp *mmc = m->mmc; + Octstr *err = NULL; + Octstr *new_msgid = NULL; + List *errl = NULL; + int j, res = MMS_SEND_OK; + int is_email = m->smtp_flag; + int is_mm4 = (mmc && mmc->type == MM4_MMSC && mmc->started); + List *xto = gwlist_create(); + Octstr *zto = NULL; - - if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == len) - pfrom = octstr_copy(e->from, 0, j); - else if (k > 0 && k + sizeof "/TYPE=IPv" == len) - pfrom = octstr_copy(e->from, 0, k); - else - pfrom = octstr_duplicate(e->from); - - if (!is_email) - xto = octstr_format("%S@%S", to->rcpt, - mmc && octstr_str_compare(mmc->mmsc_url, "*") != 0 ? mmc->mmsc_url : - octstr_imm("unknown")); - else - xto = octstr_duplicate(to->rcpt); - - if (octstr_search_char(e->from, '@', 0) < 0) - octstr_format_append(pfrom,"@%S", myhostname); - - res = mms_sendtoemail(pfrom, xto, - e->subject ? e->subject : octstr_imm(""), - e->msgId, msg, 0, &err, octstr_get_cstr(sendmail_cmd), - myhostname, 0, 0, - "", - "", 0, - e->xqfname, - e->hdrs, smtp_relay.host, smtp_relay.port); - if (res == MMS_SEND_OK || res == MMS_SEND_QUEUED) { - new_msgid = e->msgId ? octstr_duplicate(e->msgId) : octstr_create("00001"); /* Fake it */ - mmsbox_event_cb(NULL, MM7_TAG_SubmitReq, 1, octstr_imm("1.0"), 200, - mms_msgsize(msg), e->attempts, pfrom, - to->rcpt,NULL, NULL, e->hdrs, NULL); + /* Make recipient list */ + for (j = 0; j < gwlist_len(lto); j++) { + MmsEnvelopeTo *to = gwlist_get(lto, j); + Octstr *x = octstr_duplicate(to->rcpt); + int is_email = (octstr_search_char(to->rcpt, '@', 0) > 0); + if (is_mm4 && !is_email) /* Add host name of recipient domain */ + octstr_format_append(x, "@%S", + mmc && octstr_str_compare(mmc->mmsc_url, "*") != 0 ? mmc->mmsc_url : + octstr_imm("unknown")); + gwlist_append(xto, x); } - octstr_destroy(pfrom); - octstr_destroy(xto); - } else { - res = mms_sendtommsc(mmc, e, - to->rcpt, - otransid, - msg, - &new_msgid, - &errl); - if (errl) - err = http_header_value(errl, octstr_imm("X-Mbuni-Error")); - if (new_msgid && e->hdrs) { /* Record it */ - Octstr *x = octstr_format("X-Mbuni-Received-Message-Id-%d", i); + + LINEARISE_STR_LIST(zto,xto,", "); + if (is_mm4 || is_email) { /* Handle mm4 as well */ + int j = octstr_case_search(e->from, octstr_imm("/TYPE=PLMN"), 0); + int k = octstr_case_search(e->from, octstr_imm("/TYPE=IPv"), 0); + int len = octstr_len(e->from); + Octstr *pfrom; - http_header_remove_all(e->hdrs, octstr_get_cstr(x)); - http_header_add(e->hdrs, octstr_get_cstr(x), octstr_get_cstr(new_msgid)); - octstr_destroy(x); + if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == len) + pfrom = octstr_copy(e->from, 0, j); + else if (k > 0 && k + sizeof "/TYPE=IPv" == len) + pfrom = octstr_copy(e->from, 0, k); + else + pfrom = octstr_duplicate(e->from); + + if (octstr_search_char(e->from, '@', 0) < 0) + octstr_format_append(pfrom,"@%S", myhostname); + + res = mms_sendtoemail(pfrom, xto, + e->subject ? e->subject : octstr_imm(""), + e->msgId, msg, 0, &err, octstr_get_cstr(sendmail_cmd), + myhostname, 0, 0, + "", + "", 0, + e->xqfname, + e->hdrs, smtp_relay.host, smtp_relay.port); + if (res == MMS_SEND_OK || res == MMS_SEND_QUEUED) { + new_msgid = e->msgId ? octstr_duplicate(e->msgId) : octstr_create("00001"); /* Fake it */ + mmsbox_event_cb(NULL, MM7_TAG_SubmitReq, 1, octstr_imm("1.0"), 200, + mms_msgsize(msg), e->attempts, pfrom, + zto,NULL, NULL, e->hdrs, NULL); + } + octstr_destroy(pfrom); + } else { + res = mms_sendtommsc(mmc, e, + xto, + otransid, + msg, + &new_msgid, + &errl); + if (errl) + err = http_header_value(errl, octstr_imm("X-Mbuni-Error")); + if (new_msgid && e->hdrs) { /* Record it */ + Octstr *x = octstr_format("X-Mbuni-Received-Message-Id-%d", i); + + http_header_remove_all(e->hdrs, octstr_get_cstr(x)); + http_header_add(e->hdrs, octstr_get_cstr(x), octstr_get_cstr(new_msgid)); + + octstr_destroy(x); + } } - } - done: - if (res == MMS_SEND_OK || res == MMS_SEND_QUEUED) { - to->process = 0; + /* For each recipient, process result */ + for (j = 0; j < gwlist_len(lto); j++) { + MmsEnvelopeTo *to = gwlist_get(lto, j); + + process_send_res(e, msg, to, mmc, res, err, errl, new_msgid, j == 0); + + } + octstr_destroy(zto); + gwlist_destroy(xto, (void *)octstr_destroy); + octstr_destroy(new_msgid); + octstr_destroy(err); + http_destroy_headers(errl); - if (e->msgtype == MMS_MSGTYPE_SEND_REQ || - e->msgtype == MMS_MSGTYPE_RETRIEVE_CONF) /* queue dlr as needed. */ - queue_dlr(mmc, e->from, to->rcpt, new_msgid, octstr_imm("Forwarded"), "MM7-Out", errl); - } else if (res == MMS_SEND_ERROR_FATAL && mmc) { - if (e->msgtype == MMS_MSGTYPE_SEND_REQ || - e->msgtype == MMS_MSGTYPE_RETRIEVE_CONF) /* queue dlr as needed. */ - queue_dlr(mmc, e->from, to->rcpt, e->msgId, - (e->expiryt != 0 && e->expiryt < tnow) ? - octstr_imm("Expired") : octstr_imm("Rejected"), - "MM7-Out", errl); + e->lasttry = tnow; + if (qfs->mms_queue_update(e) == 1) { + e = NULL; + break; /* Queue entry gone. */ + } + gwlist_destroy(lto, NULL); } - if (mmc) { - if (res == MMS_SEND_OK || res == MMS_SEND_QUEUED) - mmc->mt_pdus++; - else - mmc->mt_errors++; - mmc->last_pdu = time(NULL); - return_mmsc_conn(mmc); /* important. */ - } - - if (res == MMS_SEND_ERROR_FATAL) - to->process = 0; /* No more attempts. */ - - - /* handle CDR */ - if (res == MMS_SEND_OK || res == MMS_SEND_QUEUED || res == MMS_SEND_ERROR_FATAL) { - Octstr *mclass = mms_get_header_value(msg, octstr_imm("X-Mms-Message-Class")); - Octstr *prio = mms_get_header_value(msg, octstr_imm("X-Mms-Priority")); - Octstr *mstatus = mms_get_header_value(msg, octstr_imm("X-Mms-Status")); - - /* Do CDR */ - cdrfs->logcdr(e->created, - octstr_get_cstr(e->from), - octstr_get_cstr(to->rcpt), - octstr_get_cstr(e->msgId), - mmc ? octstr_get_cstr(mmc->id) : NULL, /* Should we touch mmc here? XXX */ - e->src_interface, - "MM7", - e->msize, - (char *)mms_message_type_to_cstr(e->msgtype), - - prio ? octstr_get_cstr(prio) : NULL, - mclass ? octstr_get_cstr(mclass) : NULL, - res == MMS_SEND_ERROR_FATAL ? "dropped" : (mstatus ? octstr_get_cstr(mstatus) : "sent"), - e->dlr, - 0); - - octstr_destroy(mclass); - octstr_destroy(prio); - octstr_destroy(mstatus); - } - - if (err == NULL) - mms_info(0, "MM7", NULL, "%s MMSBox Outgoing Queue MMS Send: From %s, to %s, msgsize=%ld: msgid=[%s]", - SEND_ERROR_STR(res), - octstr_get_cstr(e->from), octstr_get_cstr(to->rcpt), e->msize, - new_msgid ? octstr_get_cstr(new_msgid) : "N/A"); - else - mms_error_ex("MT", 0, - "MM7", NULL, - "%s MMSBox Outgoing Queue MMS Send: From %s, to %s, msgsize=%ld: %s", - SEND_ERROR_STR(res), - octstr_get_cstr(e->from), octstr_get_cstr(to->rcpt), e->msize, octstr_get_cstr(err)); - - octstr_destroy(new_msgid); - octstr_destroy(err); - http_destroy_headers(errl); - - octstr_destroy(requested_mmsc); - e->lasttry = tnow; - if (qfs->mms_queue_update(e) == 1) { - e = NULL; - break; /* Queue entry gone. */ - } } done2: mms_destroy(msg); octstr_destroy(otransid); + /* Clear out mlist: */ + for (i = 0; i < gwlist_len(mlist); i++) { + MRcpt_t *m = gwlist_get(mlist, i); + + gwlist_destroy(m->rto, NULL); /* Clear list */ + if (m != &smtp_h) + gw_free(m); + else + mutex_destroy(smtp_h.mmc->mutex); + } + gwlist_destroy(mlist, NULL); + if (e) { /* Update the queue if it is still valid (e.g. recipients not handled) * XXX can this happen here??... */ diff --git a/mbuni/mmsbox/mmsbox_cfg.c b/mbuni/mmsbox/mmsbox_cfg.c index 4d365e9..11a05eb 100644 --- a/mbuni/mmsbox/mmsbox_cfg.c +++ b/mbuni/mmsbox/mmsbox_cfg.c @@ -663,6 +663,10 @@ static MmscGrp *start_mmsc_from_conf(mCfg *cfg, mCfgGrp *x, List *warnings, List if (mms_cfg_get_bool(cfg, x, octstr_imm("strip-domain"), &m->strip_domain) < 0) m->strip_domain = 1; + if (mms_cfg_get_int(cfg,x, octstr_imm("max-recipients"), &m->max_recipients) < 0 || + m->max_recipients <= 0) + m->max_recipients = 1; + if (mms_cfg_get_int(cfg,x, octstr_imm("maximum-request-size"), &m->max_pkt_size) < 0 || m->max_pkt_size <= 0) m->max_pkt_size = DEFAULT_MAX_PKT_SIZE; @@ -700,9 +704,13 @@ static MmscGrp *start_mmsc_from_conf(mCfg *cfg, mCfgGrp *x, List *warnings, List m->settings = _mms_cfg_getx(cfg, x, octstr_imm("custom-settings")); /* also load the libary. */ if ((m->fns = _mms_load_module(cfg, x, "mmsc-library", "mmsc_funcs", NULL)) == NULL) { - mms_error(0, "mmsbox", NULL, "failed to load MMSC libary functions from module!"); m->fns = &dummy_mmsc_funcs; + panic(errno, "failed to load MMSC libary functions from module, mmsc id <%s>!", + octstr_get_cstr(m->id)); } + m->max_recipients = 1; + mms_info(0, "mmsbox", NULL,"Loaded MMSC[%s], max recipients per transaction forced to 1", + octstr_get_cstr(m->id)); } else WARNING("MMSBox: Unknown MMSC type [%s]!", octstr_get_cstr(type)); @@ -977,14 +985,12 @@ void mmsbox_settings_cleanup(void) } void return_mmsc_conn(MmscGrp *m) -{ - +{ if (m) MMSBOX_MMSC_UNMARK_INUSE(m); /* Vital! */ /* now try and delete as many to-be-deleted mmc as possible */ - delete_stale_mmsc(0); - + delete_stale_mmsc(0); } /* handle message routing. */ diff --git a/mbuni/mmsbox/mmsbox_cfg.h b/mbuni/mmsbox/mmsbox_cfg.h index f05c697..5fc91da 100644 --- a/mbuni/mmsbox/mmsbox_cfg.h +++ b/mbuni/mmsbox/mmsbox_cfg.h @@ -82,6 +82,8 @@ typedef struct MmscGrp { long max_pkt_size; int strip_domain; /* MM4 only */ + + long max_recipients; /* Max recpients per transaction */ } MmscGrp; #define DEFAULT_MAX_PKT_SIZE 1024*1024 diff --git a/mbuni/mmsc/mmsglobalsender.c b/mbuni/mmsc/mmsglobalsender.c index ede4d0c..39ca39d 100644 --- a/mbuni/mmsc/mmsglobalsender.c +++ b/mbuni/mmsc/mmsglobalsender.c @@ -181,14 +181,17 @@ static int sendMsg(MmsEnvelope *e) e->msgId, e->hdrs, msg, &err); - else - res = mms_sendtoemail(pfrom, to->rcpt, + else { + List *lto = gwlist_create_ex(to->rcpt); + res = mms_sendtoemail(pfrom, lto, e->subject ? e->subject : settings->mms_email_subject, e->msgId, msg, 0, &err, sendmail_cmd, settings->hostname, 1, 1, octstr_get_cstr(settings->mms_email_txt), octstr_get_cstr(settings->mms_email_html), 0, e->xqfname, e->hdrs, settings->smtp_relay, settings->smtp_port); + gwlist_destroy(lto, NULL); + } if (res == MMS_SEND_QUEUED) res = MMS_SEND_OK; /* queued to email treated same as sent. * XXX - this means DLR requests for emailed messages not supported! @@ -575,6 +578,7 @@ static int mms_sendtoproxy(Octstr *from, Octstr *to, { Octstr *pto, *pfrom; + List *lto; int x = MMS_SEND_ERROR_FATAL; Octstr *xtransid; /* We make a fake transaction ID that includes 'to' field. */ @@ -596,7 +600,8 @@ static int mms_sendtoproxy(Octstr *from, Octstr *to, pfrom = from; xtransid = octstr_format("%S-%s", to,transid); - x = mms_sendtoemail(from, pto, + lto = gwlist_create_ex(pto); + x = mms_sendtoemail(from, lto, subject ? subject : settings->mms_email_subject, msgid, msg, dlr, error, proxy_sendmail_cmd ? octstr_get_cstr(proxy_sendmail_cmd) : sendmail_cmd, @@ -612,7 +617,8 @@ static int mms_sendtoproxy(Octstr *from, Octstr *to, -1, msgid, NULL, proxy, "MM4", NULL,NULL); octstr_destroy(pto); if (pfrom != from) - octstr_destroy(pfrom); + octstr_destroy(pfrom); + gwlist_destroy(lto, NULL); return x; }