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 sendNotify(MmsEnvelope *e) { Octstr *to; MmsMsg *msg, *smsg = NULL; MmsEnvelopeTo *xto = gwlist_get(e->to, 0); Octstr *err = NULL; time_t tnow = time(NULL); int j, k, len; Octstr *phonenum = NULL, *rcpt_ip = NULL, *msgId, *from, *fromproxy; int mtype, msize; int res = MMS_SEND_OK, dlr; time_t expiryt; char *prov_notify_event = NULL; char *rtype = NULL; if (e->lastaccess != 0) { /* This message has been fetched at least once, no more signals. */ e->sendt = e->expiryt + 3600*24*30*12; info(0, "MM1: Message [ID: %s] fetched/touched at least once. Skipping", e->xqfname); return settings->qfs->mms_queue_update(e); } if (!xto) { error(0, "mobilesender: Queue entry %s with no recipients!", e->xqfname); return 0; } msg = settings->qfs->mms_queue_getdata(e); to = octstr_duplicate(xto->rcpt); expiryt = e->expiryt; msgId = e->msgId ? octstr_duplicate(e->msgId) : NULL; from = octstr_duplicate(e->from); fromproxy = e->fromproxy ? octstr_duplicate(e->fromproxy) : NULL; msize = e->msize; dlr = e->dlr; if (e->expiryt != 0 && /* Handle message expiry. */ e->expiryt < tnow) { err = octstr_format("MMSC error: Message expired while sending to %S!", to); res = MMS_SEND_ERROR_FATAL; prov_notify_event = "failedfetch"; rtype = "Expired"; goto done; } else if (e->attempts >= settings->maxsendattempts) { err = octstr_format("MMSC error: Failed to deliver to %S after %ld attempts!", to, e->attempts); res = MMS_SEND_ERROR_FATAL; prov_notify_event = "failedfetch"; rtype = "Expired"; goto done; } j = octstr_case_search(to, octstr_imm("/TYPE=PLMN"), 0); k = octstr_case_search(to, octstr_imm("/TYPE=IPv"), 0); len = octstr_len(to); if (j > 0 && j - 1 + sizeof "/TYPE=PLMN" == len) { /* A proper number. */ phonenum = octstr_copy(to, 0, j); #if 0 normalize_number(octstr_get_cstr(settings->unified_prefix), &phonenum); #else mms_normalize_phonenum(&phonenum, octstr_get_cstr(settings->unified_prefix), settings->strip_prefixes); #endif } else if (k > 0 && k + sizeof "/TYPE=IPv" == len) rcpt_ip = octstr_copy(to, 0, k); else { /* We only handle phone numbers here. */ err = octstr_format("Unexpected recipient %s in MT queue!", octstr_get_cstr(to)); res = MMS_SEND_ERROR_FATAL; goto done; } mtype = mms_messagetype(msg); /* For phone, getting here means the message can be delivered. So: * - Check whether the recipient is provisioned, if not, wait (script called will queue creation req) * - If the recipient can't take MMS, then send SMS. */ /* We handle two types of requests: send and delivery/read notifications. * other types of messages cannot possibly be in this queue! */ if (mtype == MMS_MSGTYPE_SEND_REQ || mtype == MMS_MSGTYPE_RETRIEVE_CONF) { Octstr *url, *transid; if (phonenum) { int send_ind = mms_ind_send(settings->prov_getstatus, phonenum); if (send_ind < 0 && settings->notify_unprovisioned) send_ind = 0; if (send_ind < 0) { /* That is, recipient is not (yet) provisioned. */ res = MMS_SEND_ERROR_TRANSIENT; err = octstr_format("%S is not provisioned for MMS reception, delivery deferred!", phonenum); /* Do not increase delivery attempts counter. */ e->lasttry = tnow; e->sendt = e->lasttry + settings->send_back_off * (1 + e->attempts); if (settings->qfs->mms_queue_update(e) == 1) e = NULL; /* Queue entry gone. */ else settings->qfs->mms_queue_free_env(e); goto done; } else if (send_ind == 0) { /* provisioned but does not support */ Octstr *s = octstr_format(octstr_get_cstr(settings->mms_notify_txt), from); if (settings->notify_unprovisioned && s && octstr_len(s) > 0) { /* Only send if the string was set. */ List *pheaders; Octstr *sto = octstr_duplicate(phonenum); octstr_url_encode(s); octstr_url_encode(sto); url = octstr_format("%S&text=%S&to=%S",settings->sendsms_url,s, sto); pheaders = http_create_empty_headers(); http_header_add(pheaders, "Connection", "close"); http_header_add(pheaders, "User-Agent", MM_NAME "/" VERSION); http_start_request(httpcaller, HTTP_METHOD_GET, url, pheaders, NULL, 0, &edummy, NULL); http_destroy_headers(pheaders); octstr_destroy(url); octstr_destroy(sto); } else if (s) octstr_destroy(s); res = MMS_SEND_OK; err = octstr_imm("No MMS Ind support, sent SMS instead"); xto->process = 0; /* No more processing. */ if (settings->qfs->mms_queue_update(e) == 1) e = NULL; else settings->qfs->mms_queue_free_env(e); goto done; } } /* To get here means we can send Ind. */ url = mms_makefetchurl(e->xqfname, e->token, MMS_LOC_MQUEUE, phonenum ? phonenum : to, settings); info(0, "Preparing to notify client to fetch message at URL: %s", octstr_get_cstr(url)); transid = mms_maketransid(e->xqfname, settings->host_alias); smsg = mms_notification(msg, e->msize, url, transid, e->expiryt ? e->expiryt : tnow + settings->default_msgexpiry, settings->optimize_notification_size); octstr_destroy(transid); octstr_destroy(url); } else if (mtype == MMS_MSGTYPE_DELIVERY_IND || mtype == MMS_MSGTYPE_READ_ORIG_IND) smsg = msg; else { error(0, "Unexpected message type %s for %s found in MT queue!", mms_message_type_to_cstr(mtype), octstr_get_cstr(to)); res = MMS_SEND_ERROR_FATAL; goto done; } if (smsg) start_push(phonenum ? phonenum : rcpt_ip, phonenum ? 1 : 0, e, smsg); /* Send the message. * Don't touch 'e' after this point! * It may be freed by receive thread. */ if (smsg != msg && smsg) mms_destroy(smsg); done: if (err != NULL && res != MMS_SEND_ERROR_TRANSIENT) { /* If there was a report request and this is a legit error * queue it. */ if (dlr) { MmsMsg *m = mms_deliveryreport(msgId, to, tnow, rtype ? octstr_imm(rtype) : octstr_imm("Indeterminate")); List *l = gwlist_create(); Octstr *res; gwlist_append(l, from); /* Add to queue, switch via proxy to be from proxy. */ res = settings->qfs->mms_queue_add(to ? to : settings->system_user, l, err, NULL, fromproxy, tnow, tnow+settings->default_msgexpiry, m, NULL, NULL, NULL, NULL, NULL, NULL, 0, octstr_get_cstr(settings->mm1_queuedir), "MM2", settings->host_alias); gwlist_destroy(l, NULL); mms_destroy(m); octstr_destroy(res); } } /* Write to log */ info(0, "%s Mobile Queue MMS Send Notify: From=%s, to=%s, msgsize=%d, reason=%s", SEND_ERROR_STR(res), octstr_get_cstr(from), octstr_get_cstr(to), msize, err ? octstr_get_cstr(err) : ""); if (res == MMS_SEND_ERROR_FATAL) { xto->process = 0; /* No more attempts to deliver, delete this. */ if (settings->qfs->mms_queue_update(e) == 1) e = NULL; /* Queue entry gone. */ else settings->qfs->mms_queue_free_env(e); } /* Else queue will be updated/freed elsewhere. */ if (prov_notify_event) notify_prov_server(octstr_get_cstr(settings->prov_notify), to ? octstr_get_cstr(to) : "unknown", prov_notify_event, rtype ? rtype : "", e ? e->msgId : NULL, NULL, NULL); if (msg) mms_destroy(msg); octstr_destroy(phonenum); octstr_destroy(rcpt_ip); octstr_destroy(to); octstr_destroy(msgId); octstr_destroy(fromproxy); octstr_destroy(from); octstr_destroy(err); return 1; }
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); i<n; i++) { int res = MMS_SEND_OK; MmsEnvelopeTo *to = gwlist_get(e->to, i); Octstr *err = NULL; time_t tnow = time(NULL); MmscGrp *mmc = NULL; Octstr *new_msgid = NULL; List *errl = NULL; int is_email = 0; 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; } is_email = (octstr_search_char(to->rcpt, '@', 0) > 0); if ((mmc = get_handler_mmc(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) { 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, to->rcpt, otransid, msg, &new_msgid, &errl); if (errl) err = http_header_value(errl, octstr_imm("X-Mbuni-Error")); } if (mmc) { 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", 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 (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); 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. */ }
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, *xver = NULL; 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(resp); return ret; }
/* 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, List **errl, 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; 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 ((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. */ hdrs)) == 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; } if (errl) { /* Pick up status stuff -- for DLR */ if (*errl == NULL) *errl = http_create_empty_headers(); if ((s = mm7_soap_header_value(mresp, octstr_imm("StatusText"))) != NULL) { http_header_add(*errl, "X-Mbuni-StatusText", octstr_get_cstr(s)); octstr_destroy(s); } if ((s = mm7_soap_header_value(mresp, octstr_imm("Details"))) != NULL) { http_header_add(*errl, "X-Mbuni-StatusDetails", octstr_get_cstr(s)); octstr_destroy(s); } } /* 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); gwlist_destroy(xto, NULL); return ret; }
/* * Attempt to read an envelope from queue file: * - opens and locks the file. * - if the lock succeeds, check that file hasn't changed since opening. If it has * return NULL (i.e. file is being processed elsewhere -- race condition), otherwise read it. * - If should block is 1, then does a potentially blocking attempt to lock the file. */ static MmsEnvelope *mms_queue_readenvelope(char *qf, char *mms_queuedir, int shouldblock) { Octstr *fname; int fd; Octstr *qdata, *s; ParseContext *p; MmsEnvelope *e; int okfile = 0; char subdir[64]; char realqf[QFNAMEMAX]; char xqf[QFNAMEMAX+64]; struct qfile_t *qfs; get_subdir(qf, subdir, realqf); /* break it down... */ fname = octstr_format( "%.128s/%s%s", mms_queuedir, subdir, realqf); strncpy(xqf, octstr_get_cstr(fname), sizeof xqf); #ifdef SunOS if ((fd = open(octstr_get_cstr(fname), O_RDWR)) < 0) { #else if ((fd = open(octstr_get_cstr(fname), O_RDONLY)) < 0) { #endif debug("",0,"mms_queue_readenvelope: could not open file %s", octstr_get_cstr(fname)); octstr_destroy(fname); return NULL; } else if (mm_lockfile(fd, octstr_get_cstr(fname), shouldblock) != 0) { debug("",0,"mms_queue_readenvelope: could not lock file %s", octstr_get_cstr(fname)); unlock_and_close(fd); octstr_destroy(fname); return NULL; } debug("",0,"locked and opened file: %s", octstr_get_cstr(fname)); e = mms_queue_create_envelope(NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, qf, NULL, sizeof (struct qfile_t), NULL); qfs = e->qfs_data; qfs->fd = fd; strncpy(qfs->name, realqf, sizeof qfs->name); strncpy(qfs->subdir, subdir, sizeof qfs->subdir); strncpy(qfs->dir, mms_queuedir, sizeof qfs->dir); qdata = octstr_read_file(octstr_get_cstr(fname)); octstr_destroy(fname); if (qdata == NULL) qdata = octstr_imm(""); p = parse_context_create(qdata); for (s = parse_get_line(p); s; s = parse_get_line(p)) { char *line = octstr_get_cstr(s); int ch = line[0]; char *res = line + 1; char *ptmp; switch (ch) { Octstr *t; MmsEnvelopeTo *to; case 'T': t = octstr_create(res); e->msgtype = mms_string_to_message_type(t); octstr_destroy(t); if (e->msgtype < 0) { e->msgtype = 0; error(0, "mms_queueread: Unknown MMS message type (%s) in file %s, skipped!\n", res, xqf); } break; case 'I': e->msgId = octstr_create(res); break; case 'i': strncpy(e->src_interface, res, sizeof e->src_interface); break; case 'F': e->from = octstr_create(res); if (mms_validate_address(e->from) != 0) { warning(0, "mms_queueread: Mal-formed address [%s] in file %s! " "Attempting fixup.", res, xqf); _mms_fixup_address(&e->from, NULL, NULL, 1); } break; case 'R': t = octstr_create(res); if (mms_validate_address(t) != 0) { warning(0, "mms_queueread: Mal-formed address [%s] in file %s! " "Attempting fixup.", res, xqf); _mms_fixup_address(&t, NULL, NULL, 1); } to = gw_malloc(sizeof *to); to->rcpt = t; to->process = 1; gwlist_append(e->to, to); break; case 'C': e->created = atol(res); break; case 'L': e->lasttry = atol(res); break; case 'D': e->sendt = atol(res); break; case 'X': e->expiryt = atol(res); break; case 'N': e->attempts = atol(res); break; case 'P': e->fromproxy = octstr_create(res); break; case 'M': e->mdata = octstr_create(res); break; case 'p': e->viaproxy = octstr_create(res); break; case 'S': e->msize = atol(res); break; case 's': e->subject = octstr_create(res); break; case 't': e->token = octstr_create(res); break; case 'f': e->lastaccess = atol(res); break; case 'b': e->bill.billed = 1; e->bill.amt = atof(res); break; case 'r': e->dlr = 1; break; case 'V': e->vaspid = octstr_create(res); break; 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 'H': if (e->hdrs == NULL) e->hdrs = http_create_empty_headers(); if ((ptmp = index(res, ':')) == NULL) error(0, "Incorrectly formatted line %s in queue file %s!", line, xqf); else { char *value = ptmp + 1; char hname[512]; int xlen = (ptmp - res < sizeof hname) ? ptmp - res : -1 + sizeof hname; strncpy(hname, res, xlen); hname[xlen] = 0; /* terminate it. */ http_header_add(e->hdrs, hname, value); } break; case '.': okfile = 1; break; default: error(0, "Unknown QF header %c in file %s!", ch, xqf); break; } octstr_destroy(s); if (okfile) break; /* We are done. */ } parse_context_destroy(p); octstr_destroy(qdata); /* We should properly validate the queue file here. */ if (!okfile) { free_envelope(e,0); e = NULL; error(0, "Corrupt queue control file: %s", xqf); } return e; } /* Updates envelope to queue file: * - opens temp file * - writes output to temp file, if not new else writes directly. * - renames temp file to queue file (if not new) * This function doesn't check that this envelope is useless (i.e. no recipients) * - If function returns -1, caller should check errno for error. */ static int writeenvelope(MmsEnvelope *e, int newenv) { Octstr *tfname = NULL; char *s; char buf[512]; int fd; int i, n; int res = 0; struct qfile_t *qfs = e ? e->qfs_data : NULL; gw_assert(e); if (newenv) fd = qfs->fd; else { tfname = octstr_format( "%s/%s%c%s.%d", qfs->dir, qfs->subdir, MTF, qfs->name + 1, random()); fd = open(octstr_get_cstr(tfname), O_RDWR|O_CREAT|O_EXCL, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP); if (fd < 0 ) { error(0, "mms_queueadd: Failed to open temp file %s: error = %s\n", octstr_get_cstr(tfname), strerror(errno)); res = -1; goto done; } else if (mm_lockfile(fd, octstr_get_cstr(tfname), 0) != 0) { /* Lock it. */ error(0, "mms_queueadd: Failed lock temp file %s: error = %s\n", octstr_get_cstr(tfname), strerror(errno)); res = -1; goto done; } } /* Write out. */ s = (char *)mms_message_type_to_cstr(e->msgtype); if (!s) { error(0, "mms_queuewrite: Unknown MMS message type %d! Skipped\n", e->msgtype); s = ""; } _putline(fd, "T", s); if (e->msgId) _putline(fd, "I", octstr_get_cstr(e->msgId)); if (e->src_interface[0]) _putline(fd, "i", e->src_interface); if (e->from) _putline(fd, "F", octstr_get_cstr(e->from)); if (e->to) n = gwlist_len(e->to); else n = 0; for (i = 0; i < n; i++) { MmsEnvelopeTo *to = gwlist_get(e->to, i); if (to->process) _putline(fd, "R", octstr_get_cstr(to->rcpt)); } /* Output headers if any. */ n = (e->hdrs) ? gwlist_len(e->hdrs) : 0; for (i = 0; i < n; i++) { Octstr *h = NULL, *v = NULL; http_header_get(e->hdrs, i, &h, &v); if (h && v) { Octstr *x = octstr_format("%s:%s", octstr_get_cstr(h), octstr_get_cstr(v)); _putline(fd, "H", octstr_get_cstr(x)); octstr_destroy(x); } if (h) octstr_destroy(h); if (v) octstr_destroy(v); } sprintf(buf, "%ld", e->created); _putline(fd, "C", buf); if (e->lasttry) { sprintf(buf, "%ld", e->lasttry); _putline(fd, "L", buf); } if (e->sendt) { sprintf(buf, "%ld", e->sendt); _putline(fd, "D", buf); } if (e->expiryt) { sprintf(buf, "%ld", e->expiryt); _putline(fd, "X", buf); } if (e->attempts) { sprintf(buf, "%ld", e->attempts); _putline(fd, "N", buf); } if (e->lastaccess) { sprintf(buf, "%ld", e->lastaccess); _putline(fd, "f", buf); } sprintf(buf, "%ld", e->msize); _putline(fd, "S", buf); if (e->fromproxy) _putline(fd, "P", octstr_get_cstr(e->fromproxy)); if (e->mdata) _putline(fd, "M", octstr_get_cstr(e->mdata)); if (e->subject) _putline(fd, "s", octstr_get_cstr(e->subject)); if (e->viaproxy) _putline(fd, "p", octstr_get_cstr(e->viaproxy)); if (e->token) _putline(fd, "t", octstr_get_cstr(e->token)); if (e->vaspid) _putline(fd, "V", octstr_get_cstr(e->vaspid)); 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"); if (e->bill.billed) { sprintf(buf, "%.3f", e->bill.amt); _putline(fd,"b", buf); } _putline(fd, "", "."); fsync(fd); /* Sync data. */ if (!newenv) { /* An update */ Octstr *qfname; qfname = octstr_format("%s/%s%s", qfs->dir, qfs->subdir, qfs->name); if (rename(octstr_get_cstr(tfname), octstr_get_cstr(qfname)) < 0) { error(0, "mms_queuewrite: Failed to rename %s to %s: error = %s\n", octstr_get_cstr(qfname), octstr_get_cstr(tfname), strerror(errno)); unlock_and_close(fd); /* Close new one, keep old one. */ res = -1; } else { /* On success, new descriptor replaces old one and we close old one. */ unlock_and_close(qfs->fd); qfs->fd = fd; } octstr_destroy(qfname); } done: octstr_destroy(tfname); return res; }