/* * Mbuni - Open Source MMS Gateway * * MMSC handler functions: Receive and send MMS messages to MMSCs * * Copyright (C) 2003 - 2008, 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" #define MOD_SUBJECT(msg, mmc,xfrom) do { \ if ((mmc)->reroute_mod_subject) { \ Octstr *s = mms_get_header_value((msg),octstr_imm("Subject")); \ Octstr *f = octstr_duplicate(xfrom); \ int _i; \ if (s == NULL) s = octstr_create(""); \ if ((_i = octstr_search(f, octstr_imm("/TYPE="), 0)) >= 0) \ octstr_delete(f, _i, octstr_len(f)); \ octstr_format_append(s, " (from %S)", (f)); \ mms_replace_header_value((msg), "Subject", octstr_get_cstr(s)); \ octstr_destroy(s); octstr_destroy(f); \ } \ } while(0) static int auth_check(Octstr *user, Octstr *pass, List *headers, int *has_auth_hdr) { int i, res = -1; Octstr *v = http_header_value(headers, octstr_imm("Authorization")); Octstr *p = NULL, *q = NULL; *has_auth_hdr = (v != NULL); if (octstr_len(user) == 0) { res = 0; goto done; } 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: octstr_destroy(v); octstr_destroy(p); octstr_destroy(q); return res; } static int mmsbox_send_report(Octstr *from, char *report_type, Octstr *dlr_url, Octstr *status, Octstr *msgid, Octstr *orig_msgid, Octstr *mmc_id, Octstr *mmc_gid, Octstr *orig_transid, Octstr *uaprof, time_t uaprof_tstamp) { Octstr *url = NULL; List *rh = NULL, *rph = NULL; Octstr *rb = NULL; Octstr *xtransid = NULL; if (dlr_url) url = octstr_duplicate(dlr_url); else mms_dlr_url_get(msgid, report_type, mmc_gid, &url, &xtransid); if (octstr_len(url) == 0) { if (url) mms_info(0, "MM7", NULL, "Sending delivery-report skipped: `url' is empty, `group_id'=[%s], `msgid'=[%s]", octstr_get_cstr(mmc_gid), octstr_get_cstr(msgid)); goto done; } else if (octstr_search(url, octstr_imm("msgid:"), 0) == 0) /* a fake one, skip it. */ goto done; 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-MMSC-ID", octstr_get_cstr(mmc_id)); http_header_add(rh, "X-Mbuni-MMSC-GID", octstr_get_cstr(mmc_gid)); http_header_add(rh, "X-Mbuni-From", octstr_get_cstr(from)); if (xtransid || orig_transid) http_header_add(rh, "X-Mbuni-TransactionID", octstr_get_cstr(xtransid ? xtransid : orig_transid)); if (msgid) http_header_add(rh, "X-Mbuni-Message-ID", octstr_get_cstr(msgid)); if (orig_msgid) http_header_add(rh, "X-Mbuni-Orig-Message-ID", octstr_get_cstr(orig_msgid)); if (uaprof) { Octstr *sx = date_format_http(uaprof_tstamp); http_header_add(rh, "X-Mbuni-UAProf", octstr_get_cstr(uaprof)); http_header_add(rh, "X-Mbuni-Timestamp", octstr_get_cstr(sx)); octstr_destroy(sx); } mms_url_fetch_content(HTTP_METHOD_GET, url, rh, octstr_imm(""), &rph, &rb); /* 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' or sent or forwarded */ if (strcmp(report_type, "read-report") == 0 || (octstr_case_compare(status, octstr_imm("Deferred")) != 0 && octstr_case_compare(status, octstr_imm("Forwarded")) != 0)) mms_dlr_url_remove(msgid, report_type, mmc_gid); done: octstr_destroy(rb); octstr_destroy(url); octstr_destroy(xtransid); http_destroy_headers(rph); http_destroy_headers(rh); return 0; } static void fixup_relayed_report(MmsMsg *m, MmscGrp *mmc, char *rtype) { Octstr *value = mms_get_header_value(m, octstr_imm("Message-ID")); Octstr *newmsgid = NULL, *transid = NULL; /* Firstly, take care to look for the record we saved, and re-write the MessageID. */ if (value && mms_dlr_url_get(value, rtype, mmc->group_id, &newmsgid, &transid) == 0) { int x = octstr_search_char(newmsgid, ':', 0); if (x>=0) octstr_delete(newmsgid, 0, x+1); mms_replace_header_value(m, "Message-ID", octstr_get_cstr(newmsgid)); /* Add it back as original. */ mms_replace_header_value(m, "X-Mbuni-Orig-Message-ID", octstr_get_cstr(value)); mms_dlr_url_remove(value, "delivery-report", mmc->group_id); } octstr_destroy(newmsgid); octstr_destroy(transid); octstr_destroy(value); } /* These functions are very similar to those in mmsproxy */ static int mm7soap_receive(MmsBoxHTTPClientInfo *h) { MSoapMsg_t *mreq = NULL, *mresp = NULL; int hstatus = HTTP_OK; List *rh = NULL; Octstr *reply_body = NULL; List *to = NULL; Octstr *from = NULL, *subject = NULL, *vasid = NULL, *msgid = NULL, *uaprof = NULL; time_t expiryt = -1, delivert = -1, uaprof_tstamp = -1; MmsMsg *m = NULL; int status = 1000; unsigned char *msgtype = (unsigned char *)""; Octstr *qf = NULL, *mmc_id = NULL, *qdir = 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,1); status = 4000; goto done; } mm7_get_envelope(mreq, &from, &to, &subject, &vasid, &expiryt, &delivert, &uaprof, &uaprof_tstamp); if (!from) from = octstr_imm("anon@anon"); qdir = get_mmsbox_queue_dir(from, to, h->m, &mmc_id); /* get routing info. */ switch (mm7_msgtype(mreq)) { case MM7_TAG_DeliverReq: m = mm7_soap_to_mmsmsg(mreq, from); if (m) { /* Store linked id so we use it in response. */ Octstr *linkedid = mm7_soap_header_value(mreq, octstr_imm("LinkedID")); List *qh = http_create_empty_headers(); int dlr; Octstr *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; if (uaprof) { Octstr *sx = date_format_http(uaprof_tstamp); http_header_add(qh, "X-Mbuni-UAProf", octstr_get_cstr(uaprof)); http_header_add(qh, "X-Mbuni-Timestamp", octstr_get_cstr(sx)); octstr_destroy(sx); } MOD_SUBJECT(m, h->m, from); qf = qfs->mms_queue_add(from, to, subject, h->m->id, mmc_id, delivert, expiryt, m, linkedid, NULL, NULL, NULL, NULL, qh, dlr, octstr_get_cstr(qdir), "MM7/SOAP-IN", NULL); msgid = mms_make_msgid(octstr_get_cstr(qf), NULL); mms_log("Received", from, to, -1, msgid, NULL, h->m->id, "MMSBox", h->ua, NULL); octstr_destroy(linkedid); octstr_destroy(value); http_destroy_headers(qh); } else { mms_error(0, "MM7", h->m->id, "Failed to convert received MM7/SOAP DeliverReq message from mmc=%s to MMS Message!", octstr_get_cstr(h->m->id)); status = 4000; } mresp = mm7_make_resp(mreq, status, NULL,1); break; case MM7_TAG_DeliveryReportReq: if (mmc_id != NULL) { /* internal routing. */ m = mm7_soap_to_mmsmsg(mreq, from); if (m) { fixup_relayed_report(m, h->m, "delivery-report"); /* fix it up if it is relayed. */ qf = qfs->mms_queue_add(from, to, NULL, h->m->id, mmc_id, 0, time(NULL) + default_msgexpiry, m, NULL, NULL, NULL, NULL, NULL, NULL, 0, octstr_get_cstr(qdir), "MM7/SOAP-IN", NULL); } else qf = NULL; if (qf) /* Log to access log */ mms_log("Received DLR", from, to, -1, NULL, NULL, h->m->id, "MMSBox", h->ua, NULL); else status = 4000; } else { Octstr *desc = mm7_soap_header_value(mreq, octstr_imm("StatusText")); Octstr *value = mm7_soap_header_value(mreq, octstr_imm("MMStatus")); msgid = mm7_soap_header_value(mreq, octstr_imm("MessageID")); mms_info(0, "MM7", h->m->id, "Sending delivery-report [FROM:%s] [VALUE:%s] [DESC:%s] [MSGID:%s]", octstr_get_cstr(from), octstr_get_cstr(value), octstr_get_cstr(desc), octstr_get_cstr(h->m->id)); mmsbox_send_report(from, "delivery-report", NULL, value, msgid, NULL, h->m->id, h->m->group_id, NULL, uaprof, uaprof_tstamp); mms_log("DeliveryReport", from, NULL, -1, msgid, value, h->m->id, "MMSBox", h->ua, NULL); octstr_destroy(desc); octstr_destroy(value); } mresp = mm7_make_resp(mreq, status, NULL,1); break; case MM7_TAG_ReadReplyReq: if (mmc_id != NULL) { /* internal routing. */ m = mm7_soap_to_mmsmsg(mreq, from); if (m) { fixup_relayed_report(m, h->m, "read-report"); /* fix it up if it is relayed. */ qf = qfs->mms_queue_add(from, to, NULL, h->m->id, mmc_id, 0, time(NULL) + default_msgexpiry, m, NULL, NULL, NULL, NULL, NULL, NULL, 0, octstr_get_cstr(qdir), "MM7/SOAP-IN", NULL); } else qf = NULL; if (qf) /* Log to access log */ mms_log("Received RR", from, to, -1, NULL, NULL, h->m->id, "MMSBox", h->ua, NULL); else status = 4000; } else { Octstr *value = mm7_soap_header_value(mreq, octstr_imm("MMStatus")); msgid = mm7_soap_header_value(mreq, octstr_imm("MessageID")); mmsbox_send_report(from, "read-report", NULL, value, msgid, NULL, h->m->id, h->m->group_id, NULL, uaprof, uaprof_tstamp); 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,1); break; default: mresp = mm7_make_resp(mreq, MM7_SOAP_UNSUPPORTED_OPERATION, NULL,1); status = MM7_SOAP_UNSUPPORTED_OPERATION; break; } done: if (mresp && mm7_soapmsg_to_httpmsg(mresp, &h->m->ver, &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], mm7_status=[%d] <-- ", mresp ? "ok" : "(null)", reply_body ? "ok" : "(null)", status); octstr_destroy(from); octstr_destroy(subject); octstr_destroy(vasid); octstr_destroy(msgid); octstr_destroy(qf); octstr_destroy(uaprof); mms_destroy(m); http_destroy_headers(rh); octstr_destroy(reply_body); mm7_soap_destroy(mresp); mm7_soap_destroy(mreq); gwlist_destroy(to, (gwlist_item_destructor_t *)octstr_destroy); octstr_destroy(mmc_id); return MM7_SOAP_STATUS_OK(status) ? 0 : -1; } /* Helper func to avoid code duplication below. */ static void handle_report_dispatch(MmscGrp *m, Octstr *hfrom, char *rtype, List *mh, Octstr *status_hdr) { Octstr *value = http_header_value(mh, status_hdr); Octstr *value2 = http_header_value(mh, octstr_imm("Message-ID")); Octstr *value3 = http_header_value(mh, octstr_imm("X-Mbuni-Orig-Message-ID")); mmsbox_send_report(hfrom, rtype, NULL, value, value2, value3, m->id, m->group_id, NULL, NULL, -1); octstr_destroy(value); octstr_destroy(value2); octstr_destroy(value3); } /* helper function for queueing delivery reports. */ static int queue_dlr(MmscGrp *mmc, Octstr *from, Octstr *to, Octstr *msgid, Octstr *status, char *interf) { Octstr *mmc_id = NULL, *qdir; MmsMsg *m = mms_deliveryreport(msgid, from, to, time(NULL), status); List *lto = gwlist_create(); int ret; gwlist_append(lto, octstr_duplicate(to)); qdir = get_mmsbox_queue_dir(from, lto, mmc, &mmc_id); /* get routing info. */ if (mmc_id != NULL) { /* internal routing. */ Octstr *qf; fixup_relayed_report(m, mmc, "delivery-report"); /* fix it up if it is relayed. */ qf = qfs->mms_queue_add(from, lto, NULL, mmc->id, mmc_id, 0, time(NULL) + default_msgexpiry, m, NULL, NULL, NULL, NULL, NULL, NULL, 0, octstr_get_cstr(qdir), interf, NULL); if (qf) { /* Log to access log */ mms_log("Received DLR", from, lto, -1, NULL, NULL, mmc->id, "MMSBox", NULL, NULL); ret = 0; } else ret = -1; octstr_destroy(qf); } else { List *mh = mms_message_headers(m); handle_report_dispatch(mmc, from, "delivery-report", mh, octstr_imm("X-Mms-Status")); http_destroy_headers(mh); ret = 0; } gwlist_destroy(lto, (void *)octstr_destroy); octstr_destroy(mmc_id); mms_destroy(m); return ret; } static int mm7eaif_receive(MmsBoxHTTPClientInfo *h) { MmsMsg *m = NULL; List *mh = NULL; int hstatus = HTTP_NO_CONTENT; List *rh = http_create_empty_headers(); Octstr *reply_body = NULL, *value; List *to = gwlist_create(), *hto = NULL; Octstr *subject = NULL, *otransid = NULL, *msgid = NULL; Octstr *hfrom = NULL; time_t expiryt = -1, deliveryt = -1; Octstr *qf = NULL, *xver, *mmc_id = NULL, *qdir = 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, octstr_get_cstr(unified_prefix), strip_prefixes); 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); to = gwlist_create(); for (i = 0, n = gwlist_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 = gwlist_len(l); j < m; j++) gwlist_append(to, gwlist_get(l, j)); gwlist_destroy(l, NULL); octstr_destroy(h); octstr_destroy(v); } } qdir = get_mmsbox_queue_dir(hfrom, to, h->m, &mmc_id); /* get routing info. */ switch(mtype) { case MMS_MSGTYPE_SEND_REQ: case MMS_MSGTYPE_RETRIEVE_CONF: /* 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")); else mms_replace_header_value(m, "Message-ID", octstr_get_cstr(msgid)); /* replace it in the message.*/ value = http_header_value(mh, octstr_imm("X-Mms-Delivery-Report")); if (value && octstr_case_compare(value, octstr_imm("Yes")) == 0) dlr = 1; else dlr = 0; octstr_destroy(value); if (deliveryt < 0) deliveryt = time(NULL); if (expiryt < 0) expiryt = time(NULL) + DEFAULT_EXPIRE; if (hfrom == NULL) hfrom = http_header_value(mh, octstr_imm("From")); mms_remove_headers(m, "Bcc"); mms_remove_headers(m, "X-Mms-Delivery-Time"); mms_remove_headers(m, "X-Mms-Expiry"); mms_remove_headers(m, "X-Mms-Sender-Visibility"); MOD_SUBJECT(m, h->m, hfrom); /* Save it, put message id in header, return. */ qf = qfs->mms_queue_add(hfrom, to, subject, h->m->id, mmc_id, deliveryt, expiryt, m, NULL, NULL, NULL, NULL, NULL, NULL, dlr, octstr_get_cstr(qdir), "MM7/EAIF-IN", NULL); if (qf) { /* Log to access log */ mms_log("Received", hfrom, to, msize, msgid, NULL, h->m->id, "MMSBox", h->ua, NULL); hstatus = HTTP_NO_CONTENT; } else hstatus = HTTP_INTERNAL_SERVER_ERROR; break; case MMS_MSGTYPE_DELIVERY_IND: if (mmc_id != NULL) { /* internal routing. */ fixup_relayed_report(m, h->m, "delivery-report"); /* fix it up if it is relayed. */ qf = qfs->mms_queue_add(hfrom, to, NULL, h->m->id, mmc_id, 0, time(NULL) + default_msgexpiry, m, NULL, NULL, NULL, NULL, NULL, NULL, 0, octstr_get_cstr(qdir), "MM7/EAIF-IN", NULL); if (qf) { /* Log to access log */ mms_log("DeliveryReport", hfrom, to, -1, NULL, NULL, h->m->id, "MMSBox", h->ua, NULL); hstatus = HTTP_NO_CONTENT; } else hstatus = HTTP_INTERNAL_SERVER_ERROR; } else handle_report_dispatch(h->m, hfrom, "delivery-report", mh, octstr_imm("X-Mms-Status")); break; case MMS_MSGTYPE_READ_ORIG_IND: if (mmc_id != NULL) { /* internal routing. */ fixup_relayed_report(m, h->m, "read-report"); /* fix it up if it is relayed. */ qf = qfs->mms_queue_add(hfrom, to, NULL, h->m->id, mmc_id, 0, time(NULL) + default_msgexpiry, m, NULL, NULL, NULL, NULL, NULL, NULL, 0, octstr_get_cstr(qdir), "MM7/EAIF-IN", NULL); if (qf) { /* Log to access log */ mms_log("Received RR", hfrom, to, -1, NULL, NULL, h->m->id, "MMSBox", h->ua, NULL); hstatus = HTTP_NO_CONTENT; } else hstatus = HTTP_INTERNAL_SERVER_ERROR; } else handle_report_dispatch(h->m, hfrom, "read-report", mh, octstr_imm("X-Mms-Read-Status")); break; } done: xver = octstr_format(EAIF_VERSION, h->m->ver.major, h->m->ver.minor1); http_header_add(rh, "X-NOKIA-MMSC-Version", octstr_get_cstr(xver)); octstr_destroy(xver); http_send_reply(h->client, hstatus, rh, octstr_imm("")); http_destroy_headers(hto); gwlist_destroy(to, (gwlist_item_destructor_t *)octstr_destroy); octstr_destroy(hfrom); octstr_destroy(subject); octstr_destroy(otransid); octstr_destroy(msgid); octstr_destroy(qf); octstr_destroy(mmc_id); http_destroy_headers(mh); mms_destroy(m); return http_status_class(hstatus) == HTTP_STATUS_SUCCESSFUL ? 0 : -1; } static int mm7http_receive(MmsBoxHTTPClientInfo *h) { MmsMsg *m = NULL; List *mh = NULL; int hstatus = HTTP_OK; List *rh = http_create_empty_headers(); Octstr *reply_body = NULL, *value; List *to = NULL; Octstr *hto = NULL, *subject = NULL, *msgid = NULL; Octstr *hfrom = NULL, *body, *rr_uri = NULL, *dlr_uri = NULL; time_t expiryt = -1, deliveryt = -1; Octstr *qf = NULL, *mmc_id = NULL, *qdir = NULL, *s; int msize; int dlr, rr; int mtype; List *cgivars_ctypes = NULL, *rqh = http_create_empty_headers(); parse_cgivars(h->headers, h->body, &h->cgivars, &cgivars_ctypes); hfrom = http_cgi_variable(h->cgivars, "from"); hto = http_cgi_variable(h->cgivars, "to"); body = http_cgi_variable(h->cgivars, "mms"); msize = octstr_len(body); debug("mmsbox.mm7http.sendinterface", 0, " --> Enterred http-mmsc send interface, blen=[%d] <--- ", msize); if (hto == NULL) { http_header_add(rh, "Content-Type", "text/plain"); hstatus = HTTP_BAD_REQUEST; reply_body = octstr_format("Missing 'to' argument"); goto done; } else if (hfrom == NULL) { http_header_add(rh, "Content-Type", "text/plain"); hstatus = HTTP_BAD_REQUEST; reply_body = octstr_format("Missing 'from' argument"); goto done; } else if (body == NULL || /* A message is required, and must parse */ (m = mms_frombinary(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 content?"); goto done; } to = octstr_split_words(hto); mtype = mms_messagetype(m); mh = mms_message_headers(m); /* find interesting headers. */ subject = http_header_value(mh, octstr_imm("Subject")); /* Find expiry and delivery times */ if ((s = http_header_value(mh, octstr_imm("X-Mms-Expiry"))) != NULL) { expiryt = date_parse_http(s); octstr_destroy(s); } else expiryt = time(NULL) + DEFAULT_EXPIRE; if ((s = http_header_value(mh, octstr_imm("X-Mms-Delivery-Time"))) != NULL) { deliveryt = date_parse_http(s); octstr_destroy(s); } else deliveryt = 0; qdir = get_mmsbox_queue_dir(hfrom, to, h->m, &mmc_id); /* get routing info. */ switch(mtype) { case MMS_MSGTYPE_SEND_REQ: case MMS_MSGTYPE_RETRIEVE_CONF: /* Get/make a Message ID */ if ((msgid = mms_get_header_value(m, octstr_imm("Message-ID"))) == NULL) { /* Make a message id for it directly. We need it below. */ msgid = mms_make_msgid(NULL, NULL); mms_replace_header_value(m, "Message-ID", octstr_get_cstr(msgid)); } if ((value = http_header_value(mh, octstr_imm("X-Mms-Delivery-Report"))) != NULL && octstr_case_compare(value, octstr_imm("Yes")) == 0) dlr = 1; else dlr = 0; octstr_destroy(value); if ((value = http_header_value(mh, octstr_imm("X-Mms-Read-Report"))) != NULL && octstr_case_compare(value, octstr_imm("Yes")) == 0) rr = 1; else rr = 0; octstr_destroy(value); if (deliveryt < 0) deliveryt = time(NULL); if (expiryt < 0) expiryt = time(NULL) + DEFAULT_EXPIRE; 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"); MOD_SUBJECT(m, h->m, hfrom); if (qdir == outgoing_qdir) { /* We need to remember the old message ID so we can re-write it * if a DLR is relayed backwards. */ Octstr *t = mms_maketransid(NULL, octstr_imm(MM_NAME)); /* make a fake transaction id so dlr works*/ http_header_add(rqh, "X-Mbuni-TransactionID", octstr_get_cstr(t)); if (dlr) dlr_uri = octstr_format("msgid:%S", msgid); if (rr) rr_uri = octstr_format("msgid:%S", msgid); octstr_destroy(t); } /* Save it, put message id in header, return. */ qf = qfs->mms_queue_add(hfrom, to, subject, h->m->id, mmc_id, deliveryt, expiryt, m, NULL, NULL, NULL, dlr_uri, rr_uri, rqh, dlr, octstr_get_cstr(qdir), "MM7/HTTP-IN", NULL); if (qf) { /* Log to access log */ mms_log("Received", hfrom, to, msize, msgid, NULL, h->m->id, "MMSBox", h->ua, NULL); hstatus = HTTP_OK; } else hstatus = HTTP_INTERNAL_SERVER_ERROR; break; case MMS_MSGTYPE_DELIVERY_IND: if (mmc_id != NULL) { /* internal routing. */ fixup_relayed_report(m, h->m, "delivery-report"); /* fix it up if it is relayed. */ qf = qfs->mms_queue_add(hfrom, to, NULL, h->m->id, mmc_id, 0, time(NULL) + default_msgexpiry, m, NULL, NULL, NULL, NULL, NULL, rqh, 0, octstr_get_cstr(qdir), "MM7/HTTP-IN", NULL); if (qf) { /* Log to access log */ mms_log("DeliveryReport", hfrom, to, -1, NULL, NULL, h->m->id, "MMSBox", h->ua, NULL); hstatus = HTTP_OK; } else hstatus = HTTP_INTERNAL_SERVER_ERROR; } else handle_report_dispatch(h->m, hfrom, "delivery-report", mh, octstr_imm("X-Mms-Status")); break; case MMS_MSGTYPE_READ_ORIG_IND: if (mmc_id != NULL) { /* internal routing. */ fixup_relayed_report(m, h->m, "read-report"); /* fix it up if it is relayed. */ qf = qfs->mms_queue_add(hfrom, to, NULL, h->m->id, mmc_id, 0, time(NULL) + default_msgexpiry, m, NULL, NULL, NULL, NULL, NULL, rqh, 0, octstr_get_cstr(qdir), "MM7/HTTP-IN", NULL); if (qf) { /* Log to access log */ mms_log("Received RR", hfrom, to, -1, NULL, NULL, h->m->id, "MMSBox", h->ua, NULL); hstatus = HTTP_NO_CONTENT; } else hstatus = HTTP_INTERNAL_SERVER_ERROR; } else handle_report_dispatch(h->m, hfrom, "read-report", mh, octstr_imm("X-Mms-Read-Status")); break; } done: http_header_add(rh, "X-Mbuni-Version", VERSION); http_send_reply(h->client, hstatus, rh, msgid ? msgid : (qf ? qf : octstr_imm(""))); gwlist_destroy(to, (gwlist_item_destructor_t *)octstr_destroy); octstr_destroy(subject); octstr_destroy(qf); octstr_destroy(mmc_id); octstr_destroy(msgid); http_destroy_headers(mh); http_destroy_headers(rh); http_destroy_headers(rqh); if (m) mms_destroy(m); http_destroy_cgiargs(cgivars_ctypes); return http_status_class(hstatus) == HTTP_STATUS_SUCCESSFUL ? 0 : -1; } static void dispatch_mm7_recv(List *rl) { MmsBoxHTTPClientInfo *h; while ((h = gwlist_consume(rl)) != NULL) { int ret = -1, has_auth = 0; MmscGrp *m = h->m; if (auth_check(m->incoming.user, m->incoming.pass, h->headers, &has_auth) != 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("Authentication failed")); http_destroy_headers(hh); if (!has_auth) mms_info_ex("auth",0, "MM7", m->id, "Auth failed, incoming connection, MMC group=[%s]", m->id ? octstr_get_cstr(m->id) : "(none)"); else mms_error_ex("auth",0, "MM7", m->id, "Auth failed, incoming connection, MMC group=[%s]", m->id ? octstr_get_cstr(m->id) : "(none)"); } else if (h->m->type == SOAP_MMSC) ret = mm7soap_receive(h); else if (h->m->type == EAIF_MMSC) ret = mm7eaif_receive(h); else ret = mm7http_receive(h); h->m->last_pdu = time(NULL); if (ret == 0) h->m->mo_pdus++; else h->m->mo_errors++; free_mmsbox_http_clientInfo(h, 1); } } void mmsc_receive_func(MmscGrp *m) { int i; MmsBoxHTTPClientInfo h = {NULL}; List *mmsc_incoming_reqs = gwlist_create(); long *thids = gw_malloc((maxthreads + 1)*sizeof thids[0]); gwlist_add_producer(mmsc_incoming_reqs); for (i = 0; iincoming.port, &h.ip, &h.url, &h.headers, &h.body, &h.cgivars)) != NULL) if (is_allowed_ip(m->incoming.allow_ip, m->incoming.deny_ip, h.ip)) { MmsBoxHTTPClientInfo *hx = gw_malloc(sizeof hx[0]); h.ua = http_header_value(h.headers, octstr_imm("User-Agent")); *hx = h; debug("mmsbox", 0, " MM7 Incoming, IP=[%s], MMSC=[%s], dest_port=[%ld] ", h.ip ? octstr_get_cstr(h.ip) : "", octstr_get_cstr(m->id), m->incoming.port); /* Dump headers, url etc. */ #if 0 http_header_dump(h.headers); if (h.body) octstr_dump(h.body, 0); if (h.ip) octstr_dump(h.ip, 0); #endif gwlist_produce(mmsc_incoming_reqs, hx); } else { h.ua = http_header_value(h.headers, octstr_imm("User-Agent")); mms_error_ex("auth",0, "MM7", m->id, "HTTP: Incoming IP denied MMSC[%s] ip=[%s], ua=[%s], disconnected", m->id ? octstr_get_cstr(m->id) : "(none)", h.ip ? octstr_get_cstr(h.ip) : "(none)", h.ua ? octstr_get_cstr(h.ua) : "(none)"); http_send_reply(h.client, HTTP_FORBIDDEN, NULL, octstr_imm("Access denied.")); free_mmsbox_http_clientInfo(&h, 0); } debug("proxy", 0, "MMSBox: MM7 receiver [mmc=%s] Shutting down...", octstr_get_cstr(m->id)); gwlist_remove_producer(mmsc_incoming_reqs); for (i = 0; i= 0) gwthread_join(thids[i]); gwlist_destroy(mmsc_incoming_reqs, NULL); gw_free(thids); debug("proxy", 0, "MMSBox: MM7 receiver [mmc=%s] Shutting down complete.", octstr_get_cstr(m->id)); } /* 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 *transid, Octstr *linkedid, char *vasid, Octstr *service_code, List *hdrs, MmsMsg *m, Octstr **error, int *retry) { Octstr *ret = NULL; 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, *distrib = NULL; char *xvasid = vasid ? vasid : (mmc->default_vasid ? octstr_get_cstr(mmc->default_vasid) : NULL); mms_info(0, "MM7", mmc->id, "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)); gwlist_append(xto, to); if (hdrs) distrib = http_header_value(hdrs, octstr_imm("X-Mbuni-DistributionIndicator")); if ((mreq = mm7_mmsmsg_to_soap(m, (mmc == NULL || mmc->no_senderaddress == 0) ? from : NULL, xto, transid, service_code, linkedid, 1, octstr_get_cstr(mmc->vasp_id), xvasid, NULL, 0,/* UA N/A on this side. */ distrib)) == NULL) { *error = octstr_format("Failed to convert Msg[%S] 2 SOAP message!", mms_message_type_to_string(mtype)); goto done1; } if (mm7_soapmsg_to_httpmsg(mreq, &mmc->ver, &rh, &body) < 0) { *error = octstr_format("Failed to convert SOAP message to HTTP Msg!"); goto done1; } if (hdrs) http_header_combine(rh, hdrs); /* If specified, then update and pass on. */ hstatus = mmsbox_url_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]!", 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!", mmc->mmsc_url, 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 if ((s = mm7_soap_header_value(mresp, octstr_imm("faultstring"))) != NULL) { tstatus = atoi(octstr_get_cstr(s)); octstr_destroy(s); } else tstatus = MM7_SOAP_FORMAT_CORRUPT; if (!MM7_SOAP_STATUS_OK(tstatus) && tstatus != MM7_SOAP_COMMAND_REJECTED) { Octstr *detail = mm7_soap_header_value(mresp, octstr_imm("Details")); char *tmp = (char *)mms_soap_status_to_cstr(tstatus); if (detail == NULL) detail = mm7_soap_header_value(mresp, octstr_imm("faultcode")); ret = NULL; mms_info(0, "MM7", mmc->id, "Send to MMSC[%s], failed, code=[%d=>%s], detail=[%s]", mmc ? octstr_get_cstr(mmc->id) : "", tstatus, tmp ? tmp : "", detail ? octstr_get_cstr(detail) : ""); *error = octstr_format("Failed to deliver to MMC[url=%S, id=%S], status=[%d=>%s]!", mmc->mmsc_url, mmc->id, tstatus, tmp ? tmp : ""); octstr_destroy(detail); } else { ret = mm7_soap_header_value(mresp, octstr_imm("MessageID")); mms_info(0, "MM7", NULL, "Sent to MMC[%s], code=[%d=>%s], msgid=[%s]", octstr_get_cstr(mmc->id), tstatus, mms_soap_status_to_cstr(tstatus), ret ? octstr_get_cstr(ret) : "(none)"); } if (ret) mms_log2("Sent", from, to, -1, ret, NULL, mmc->id, "MMSBox", NULL, NULL); done1: *retry = (ret == NULL && (!MM7_SOAP_CLIENT_ERROR(tstatus) || tstatus < 0)); mm7_soap_destroy(mreq); mm7_soap_destroy(mresp); http_destroy_headers(rh); octstr_destroy(body); http_destroy_headers(ph); octstr_destroy(rbody); octstr_destroy(url); octstr_destroy(distrib); gwlist_destroy(xto, NULL); return ret; } static Octstr *mm7eaif_send(MmscGrp *mmc, Octstr *from, Octstr *to, Octstr *transid, char *vasid, List *hdrs, MmsMsg *m, Octstr **error, int *retry) { Octstr *ret = NULL, *resp = 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, *xver; char *msgtype; mms_info(0, "MM7", mmc->id, "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_remove_all(rh, "X-Mms-Allow-Adaptations"); 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); http_header_add(rh, "X-NOKIA-MMSC-Version", octstr_get_cstr(xver)); octstr_destroy(xver); if (mtype == MMS_MSGTYPE_SEND_REQ || mtype == MMS_MSGTYPE_RETRIEVE_CONF) { msgtype = "MultiMediaMessage"; mms_make_sendreq(m); /* ensure it is a sendreq. */ } else if (mtype == MMS_MSGTYPE_DELIVERY_IND) msgtype = "DeliveryReport"; else msgtype = "ReadReply"; http_header_add(rh, "X-NOKIA-MMSC-Message-Type", msgtype); if (hdrs) http_header_combine(rh, hdrs); /* If specified, then update and pass on. */ http_header_add(rh, "Content-Type", "application/vnd.wap.mms-message"); /* Patch the message FROM and TO fields. */ mms_replace_header_value(m, "From", octstr_get_cstr(from)); mms_replace_header_value(m, "To", octstr_get_cstr(to)); mms_replace_header_value(m,"X-Mms-Transaction-ID", transid ? octstr_get_cstr(transid) : "000"); body = mms_tobinary(m); hstatus = mmsbox_url_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 !", mmc->mmsc_url, hstatus); } else { MmsMsg *mresp = rbody ? mms_frombinary(rbody, octstr_imm("anon@anon")) : NULL; resp = octstr_imm("Ok"); if (mresp && mms_messagetype(mresp) == MMS_MSGTYPE_SEND_CONF) resp = mms_get_header_value(mresp, octstr_imm("X-Mms-Response-Status")); if (octstr_case_compare(resp, octstr_imm("ok")) != 0) hstatus = HTTP_STATUS_SERVER_ERROR; /* error. */ else if (mresp) ret = mms_get_header_value(mresp, octstr_imm("Message-ID")); mms_destroy(mresp); } if (hstatus < 0) ret = NULL; else { hstatus = http_status_class(hstatus); if (hstatus == HTTP_STATUS_SERVER_ERROR || hstatus == HTTP_STATUS_CLIENT_ERROR) ret = NULL; else if (!ret) ret = http_header_value(ph, octstr_imm("X-Nokia-MMSC-Message-Id")); } *retry = (ret == NULL && (hstatus == HTTP_STATUS_SERVER_ERROR || hstatus < 0)); if (ret) mms_log2("Sent", from, to, -1, ret, NULL, mmc->id, "MMSBox", NULL, NULL); #if 0 mms_info(0, "MM7", mmc->id,"Sent to MMC[%s], code=[%d], resp=[%s] msgid [%s]", octstr_get_cstr(mmc->id), hstatus, resp ? octstr_get_cstr(resp) : "(none)", ret ? octstr_get_cstr(ret) : "(none)"); #endif http_destroy_headers(rh); octstr_destroy(body); http_destroy_headers(ph); octstr_destroy(rbody); octstr_destroy(url); octstr_destroy(resp); return ret; } static Octstr *mm7http_send(MmscGrp *mmc, Octstr *from, Octstr *to, MmsMsg *m, Octstr **error, int *retry) { Octstr *ret = NULL; int mtype = mms_messagetype(m); int hstatus = HTTP_OK; List *rh, *ph = NULL; Octstr *body = NULL, *rbody = NULL; Octstr *mms; MIMEEntity *form_data = make_multipart_formdata(); mms_info(0, "MM7", mmc->id, "MMSBox: Send [http] 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)); mms = mms_tobinary(m); add_multipart_form_field(form_data, "to", "text/plain", NULL, to); 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); rh = mime_entity_headers(form_data); body = mime_entity_body(form_data); hstatus = mmsbox_url_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 !", mmc->mmsc_url, hstatus); } else { ret = rbody ? octstr_duplicate(rbody) : NULL; if (ret) octstr_strip_blanks(ret); } *retry = (ret == NULL && (http_status_class(hstatus) == HTTP_STATUS_SERVER_ERROR || hstatus < 0)); if (ret) mms_log2("Sent", from, to, -1, ret, NULL, mmc->id, "MMSBox", NULL, NULL); http_destroy_headers(rh); octstr_destroy(body); http_destroy_headers(ph); octstr_destroy(rbody); octstr_destroy(mms); mime_entity_destroy(form_data); return ret; } static int mms_sendtommsc(MmscGrp *mmc, Octstr *from, Octstr *to, Octstr *transid, Octstr *orig_transid, Octstr *linkedid, char *vasid, Octstr *service_code, MmsMsg *m, Octstr *dlr_url, Octstr *rr_url, List *hdrs, Octstr **new_msgid, Octstr **err) { Octstr *id = NULL, *groupid = NULL; int ret = 0, retry = 0; double throughput = 0; mutex_lock(mmc->mutex); { /* Grab a lock on it. */ if (mmc->type == SOAP_MMSC) id = mm7soap_send(mmc, from, to, transid, linkedid, vasid, service_code, hdrs, m, err, &retry); else if (mmc->type == EAIF_MMSC) id = mm7eaif_send(mmc, from, to, transid, vasid, hdrs, m, err, &retry); else if (mmc->type == HTTP_MMSC) id = mm7http_send(mmc, from, to, m, err, &retry); else if (mmc->type == CUSTOM_MMSC && mmc->custom_started) id = mmc->fns->send_msg(mmc->data, from, to, transid, linkedid, vasid, service_code, m, hdrs, err, &retry); else mms_error_ex("MT", 0, "MM7", mmc->id, "MMC[%s] of unknown type, can't send!", mmc->id ? octstr_get_cstr(mmc->id) : ""); throughput = mmc->throughput; groupid = mmc->group_id ? octstr_duplicate(mmc->group_id) : NULL; } 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", groupid, dlr_url, orig_transid); if (rr_url) mms_dlr_url_put(id, "read-report", groupid, rr_url, orig_transid); ret = MMS_SEND_OK; } else ret = retry ? MMS_SEND_ERROR_TRANSIENT : MMS_SEND_ERROR_FATAL; *new_msgid = id; octstr_destroy(groupid); if (throughput > 0) gwthread_sleep(1.0/throughput); return ret; } 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; 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); goto done2; } for (i = 0, n = gwlist_len(e->to); ito, i); Octstr *err = NULL; time_t tnow = time(NULL); MmscGrp *mmc = NULL; Octstr *new_msgid = 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, e->from)) == 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; } if (octstr_search_char(to->rcpt, '@', 0) > 0) { 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; 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, to->rcpt, e->subject ? e->subject : octstr_imm(""), e->msgId, msg, 0, &err, octstr_get_cstr(sendmail_cmd), myhostname, 0, 0, "", "", 0, e->xqfname, e->hdrs); octstr_destroy(pfrom); } else res = mms_sendtommsc(mmc, e->from, to->rcpt, e->msgId, otransid, e->token, /* token = linkedid */ e->vasid ? octstr_get_cstr(e->vasid) : NULL, e->vaspid, msg, e->url1, e->url2, e->hdrs, &new_msgid, &err); if (res == MMS_SEND_OK) mmc->mt_pdus++; else mmc->mt_errors++; mmc->last_pdu = time(NULL); return_mmsc_conn(mmc); /* important. */ done: 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"); #if 0 mmsbox_send_report(to->rcpt, "delivery-report", e->url1, octstr_imm("Forwarded"), new_msgid, NULL, mmc->id, mmc->group_id, otransid, NULL, -1); #endif } 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"); #if 0 mmsbox_send_report(to->rcpt, "delivery-report", e->url1, (e->expiryt != 0 && e->expiryt < tnow) ? octstr_imm("Expired") : octstr_imm("Rejected"), e->msgId, NULL, mmc->id, mmc->group_id, otransid, NULL, -1); #endif } 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) { /* 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), NULL, NULL, /* XXX will add these later. */ res == MMS_SEND_ERROR_FATAL ? "dropped" : "sent", e->dlr, 0); } 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) : NULL); 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); e->lasttry = tnow; if (qfs->mms_queue_update(e) == 1) { e = NULL; break; /* Queue entry gone. */ } } done2: mms_destroy(msg); octstr_destroy(otransid); 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 (qfs->mms_queue_update(e) != 1) qfs->mms_queue_free_env(e); } return 1; /* always delete queue entry. */ } void mmsbox_outgoing_queue_runner(int *rstop) { qfs->mms_queue_run(octstr_get_cstr(outgoing_qdir), sendMsg, queue_interval, maxthreads, rstop); }