/* * Mbuni - Open Source MMS Gateway * * Email2MMS and MM4 (incoming) interface * * Copyright (C) 2003 - 2005, Digital Solutions Ltd. - http://www.dsmagic.com * * Paul Bagyenda * * This program is free software, distributed under the terms of * the GNU General Public License, with a few exceptions granted (see LICENSE) */ #include #include "mms_queue.h" #include "mmsc_cfg.h" static MmscSettings *settings; static Octstr *xfrom; static Octstr *xto; static Octstr *xproxy; enum {TPLMN, TEMAIL, TOTHER} ttype; static int find_own(int i, int argc, char *argv[]); static void fixup_recipient(void); static void fixup_sender(void); static mCfg *cfg; static List *proxyrelays; int main(int argc, char *argv[]) { int cfidx; Octstr *fname; MIMEEntity *mm; MmsMsg *msg; Octstr *email; Octstr *home_mmsc = NULL; List *headers; mms_lib_init(); srandom(time(NULL)); cfidx = get_and_set_debugs(argc, argv, find_own); if (argv[cfidx] == NULL) fname = octstr_imm("mmsc.conf"); else fname = octstr_create(argv[cfidx]); cfg = mms_cfg_read(fname); if (cfg == NULL) panic(0, "Couldn't read configuration from '%s'.", octstr_get_cstr(fname)); octstr_destroy(fname); info(0, "----------------------------------------"); info(0, " MMSC Email2MMS Tool version %s starting", MMSC_VERSION); /* Load settings. */ settings = mms_load_mmsc_settings(cfg, &proxyrelays); mms_cfg_destroy(cfg); if (!settings) panic(0, "No global MMSC configuration!"); if (!xto || !xfrom) panic(0, "usage: %s -f from -t to!", argv[0]); /* normalize recipient address, then if phone number, * check whether we are allowed to process. */ fixup_recipient(); fixup_sender(); if (xto && ttype == TPLMN) /* Get the home mmsc domain for this recipient. */ home_mmsc = settings->mms_resolvefuncs->mms_resolve(xto, settings->mms_resolver_module_data, settings, proxyrelays); if (!xto || (ttype == TPLMN && (!home_mmsc || !is_allowed_host(home_mmsc, settings->email2mmsrelay_hosts)))) { error(0, " Not allowed to send to this recipient %s, resolved mmsc=%s!", xto ? octstr_get_cstr(xto) : "(null)", home_mmsc ? octstr_get_cstr(home_mmsc) : "(null)"); mms_lib_shutdown(); return -1; } email = octstr_read_pipe(stdin); if (!email || octstr_len(email) == 0) { error(0, "Empty email message!"); mms_lib_shutdown(); return -1; } if ((mm = mime_octstr_to_entity(email)) == NULL) { error(0, "Unable to decode mime entity!"); mms_lib_shutdown(); return -1; } octstr_destroy(email); /* Take the entity, recode it --> remove base64 stuff, split headers. */ unbase64_mimeparts(mm); unpack_mimeheaders(mm); /* Delete some headers... */ headers = _x_mime_entity_headers(mm); http_header_remove_all(headers, "Received"); http_header_remove_all(headers, "X-MimeOLE"); http_header_remove_all(headers, "X-Mailer"); mime_replace_headers(mm, headers); http_destroy_headers(headers); /* Now convert from mime to MMS message. */ msg = mms_frommime(mm); mime_entity_destroy(mm); if (!msg) { error(0, "Unable to create MM!"); mms_lib_shutdown(); return -1; } switch(mms_messagetype(msg)) { case MMS_MSGTYPE_SEND_REQ: if (ttype != TPLMN) error(0, "Not allowed to send to non-phone recipient, to=%s!", octstr_get_cstr(xto)); else { List *lto = gwlist_create(); Octstr *qf; Octstr *msgid = mms_get_header_value(msg, octstr_imm("Message-ID")); Octstr *transid = mms_get_header_value(msg, octstr_imm("X-Mms-Transaction-ID")); Octstr *dreport = mms_get_header_value(msg, octstr_imm("X-Mms-Delivery-Report")); char *err; Octstr *rto; int dlr; octstr_format_append(xto, "/TYPE=PLMN"); gwlist_append(lto, xto); if (dreport && octstr_case_compare(dreport, octstr_imm("Yes")) == 0) dlr = 1; else dlr = 0; qf = mms_queue_add(xfrom, lto, NULL, xproxy, NULL, 0, time(NULL) + settings->default_msgexpiry, msg, NULL, NULL, NULL, NULL, NULL, NULL, dlr, octstr_get_cstr(settings->global_queuedir), settings->host_alias); if (qf) { info(0, "Email2MMS Queued message to %s from %s (via %s) => %s", octstr_get_cstr(xto), octstr_get_cstr(xfrom), xproxy ? octstr_get_cstr(xproxy) : "(None)", octstr_get_cstr(qf)); octstr_destroy(qf); /* Queue our response to the chap. */ err = "Ok"; } else err = "Error-transient-failure"; if (xproxy) { MmsMsg *mresp; List *xlto; mresp = mms_sendconf(err, octstr_get_cstr(msgid), transid ? octstr_get_cstr(transid) : "001", 0,MS_1_1); rto = octstr_format("system-user@%S", xproxy); xlto = gwlist_create(); gwlist_append(xlto, rto); qf = mms_queue_add(settings->system_user, xlto, NULL, xproxy, NULL, 0, time(NULL) + settings->default_msgexpiry, mresp, NULL, NULL, NULL, NULL, NULL, NULL, 0, octstr_get_cstr(settings->global_queuedir), settings->host_alias); gwlist_destroy(xlto, (gwlist_item_destructor_t *)octstr_destroy); mms_destroy(mresp); octstr_destroy(qf); } mms_log("Received", xfrom, lto, -1, msgid, NULL, xproxy, xproxy ? "MM4" : "MM3", NULL,NULL); gwlist_destroy(lto,NULL); octstr_destroy(transid); octstr_destroy(msgid); if (dreport) octstr_destroy(dreport); } break; case MMS_MSGTYPE_SEND_CONF: { Octstr *transid = mms_get_header_value(msg, octstr_imm("X-Mms-Transaction-ID")); Octstr *qf = mms_getqf_fromtransid(transid); octstr_destroy(transid); if (qf) { MmsEnvelope *e = mms_queue_readenvelope(octstr_get_cstr(qf), octstr_get_cstr(settings->mm4_queuedir), 1); if (!e) warning(0, "Received confirm MMS but cannot find message %s [%s] in queue!", octstr_get_cstr(transid), octstr_get_cstr(qf)); else { MmsEnvelopeTo *t; int i, n; for (i = 0, n = gwlist_len(e->to); ito, i)) != NULL) t->process = 0; /* Should make it go away. */ mms_queue_update(e); info(0, "Email2MMS received send conf from proxy %s to %s from %s => %s", octstr_get_cstr(xproxy), octstr_get_cstr(xto), octstr_get_cstr(xfrom), octstr_get_cstr(qf)); } } else warning(0, "Received confirm MMS but cannot find message %s in queue!", octstr_get_cstr(transid)); } break; case MMS_MSGTYPE_DELIVERY_IND: if (ttype != TPLMN) /* We only send to phones from this interface */ error(0, "Not allowed to send to %s!", octstr_get_cstr(xto)); else { List *lto = gwlist_create(); Octstr *qf; octstr_format_append(xto, "/TYPE=PLMN"); gwlist_append(lto, xto); qf = mms_queue_add(xfrom, lto, NULL, xproxy, NULL, 0, time(NULL) + settings->default_msgexpiry, msg, NULL, NULL, NULL, NULL, NULL, NULL, 0, octstr_get_cstr(settings->global_queuedir), settings->host_alias); gwlist_destroy(lto, NULL); if (qf) { info(0, "Email2MMS Queued DLR from proxy %s to %s from %s => %s", octstr_get_cstr(xproxy), octstr_get_cstr(xto), octstr_get_cstr(xfrom), octstr_get_cstr(qf)); octstr_destroy(qf); } gwlist_destroy(lto, NULL); } break; case MMS_MSGTYPE_READ_REC_IND: mms_convert_readrec2readorig(msg); /* Fall through. */ case MMS_MSGTYPE_READ_ORIG_IND: if (ttype != TPLMN) /* We only send to phones from this interface */ error(0, "Not allowed to send to %s!", octstr_get_cstr(xto)); else { List *lto = gwlist_create(); Octstr *qf; octstr_format_append(xto, "/TYPE=PLMN"); gwlist_append(lto, xto); qf = mms_queue_add(xfrom, lto, NULL, xproxy, NULL, 0, time(NULL) + settings->default_msgexpiry, msg, NULL, NULL, NULL, NULL, NULL, NULL, 0, octstr_get_cstr(settings->global_queuedir), settings->host_alias); gwlist_destroy(lto, NULL); if (qf) { info(0, "Email2MMS Queued read report from proxy %s to %s from %s => %s", octstr_get_cstr(xproxy), octstr_get_cstr(xto), octstr_get_cstr(xfrom), octstr_get_cstr(qf)); octstr_destroy(qf); } gwlist_destroy(lto, NULL); } default: { int x = mms_messagetype(msg); warning(0, "Unexpected message type: %d=>%s", x, mms_message_type_to_cstr(x)); break; } } mms_destroy(msg); mms_lib_shutdown(); return 0; } static int find_own(int i, int argc, char *argv[]) { if (argv[i][1] == 'f') if (i + 1 < argc) { xfrom = octstr_create(argv[i+1]); return 1; } else return -1; else if (argv[i][1] == 't') /* recipient. */ if (i + 1 < argc) { xto = octstr_create(argv[i+1]); return 1; } else return -1; else if (argv[i][1] == 'p') /* Proxy name if any. */ if (i + 1 < argc) { xproxy = octstr_create(argv[i+1]); return 1; } else return -1; else return -1; } static void fixup_recipient(void) { int i; Octstr *typ = NULL; if (!xto) xto = octstr_imm(""); i = octstr_search_char(xto, '@', 0); if (i>0) octstr_delete(xto, i, octstr_len(xto)); i = octstr_search(xto, octstr_imm("/TYPE="), 0); if (i > 0) { typ = octstr_copy(xto, i+1, octstr_len(xto)); octstr_delete(xto, i, octstr_len(xto)); } if (isphonenum(xto) && (!typ || octstr_str_compare(typ, "TYPE=PLMN") == 0)) { /* A phone number. */ normalize_number(octstr_get_cstr(settings->unified_prefix), &xto); ttype = TPLMN; } else { /* For now everything else is email. */ ttype = TEMAIL; } octstr_destroy(typ); } static void fixup_sender(void) { int i; if (!xfrom) xfrom = octstr_imm(""); i = octstr_search_char(xfrom, '@', 0); if (i>0) return; i = octstr_search(xfrom, octstr_imm("/TYPE="), 0); if (i > 0) return; if (isphonenum(xfrom)) octstr_append(xfrom, octstr_imm("/TYPE=PLMN")); else octstr_append(xfrom, octstr_imm("@unknown")); }