/* * 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 "mms_util.h" static MmsBoxSettings *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 int isphonenum(Octstr *s); static void fixup_recipient(void); static void fixup_sender(void); static Cfg *cfg; static List *proxyrelays; int main(int argc, char *argv[]) { int cfidx; Octstr *fname; CfgGroup *grp; Octstr *log, *alog; long loglevel; MIMEEntity *mm; MmsMsg *msg; Octstr *email; 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 = cfg_create(fname); if (cfg_read(cfg) == -1) 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); grp = cfg_get_single_group(cfg, octstr_imm("core")); log = cfg_get(grp, octstr_imm("log-file")); if (log != NULL) { if (cfg_get_integer(&loglevel, grp, octstr_imm("log-level")) == -1) loglevel = 0; log_open(octstr_get_cstr(log), loglevel, GW_NON_EXCL); octstr_destroy(log); } /* Get access log and open it. */ alog = cfg_get(grp, octstr_imm("access-log")); if (alog) { alog_open(octstr_get_cstr(alog), 1, 1); octstr_destroy(alog); } /* Load proxy relays. */ proxyrelays = mms_proxy_relays(cfg); /* Load settings. */ settings = mms_load_mmsbox_settings(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 && !does_prefix_match(settings->email2mmsrelay_prefixes, xto))) { error(0, " Not allowed to send to this recipient %s!", xto ? octstr_get_cstr(xto) : "(null)"); return -1; } email = octstr_read_pipe(stdin); if (!email || octstr_len(email) == 0) { error(0, "Empty email message!"); return -1; } if ((mm = mime_octstr_to_entity(email)) == NULL) { error(0, "Unable to decode mime entity!"); return -1; } octstr_destroy(email); /* Take the entity, recode it --> remove base64 stuff, split headers. */ unbase64_mimeparts(mm); unpack_mimeheaders(mm); /* Now convert from mime to MMS message. */ msg = mms_frommime(mm); mime_entity_destroy(mm); if (!msg) { error(0, "Unable to create MM!"); return -1; } switch(mms_messagetype(msg)) { case MMS_MSGTYPE_SEND_REQ: if (ttype != TPLMN ||/* We only send to phones from this interface */ !does_prefix_match(settings->email2mmsrelay_prefixes, xto)) { error(0, "Not allowed to send to %s!", octstr_get_cstr(xto)); } else { List *lto = list_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"); list_append(lto, xto); if (dreport && octstr_case_compare(dreport, octstr_imm("Yes")) == 0) dlr = 1; else dlr = 0; qf = mms_queue_add(xfrom, lto, msgid, NULL, xproxy, NULL, 0, time(NULL) + settings->default_msgexpiry, msg, NULL, dlr, octstr_get_cstr(settings->global_queuedir)); 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 = list_create(); list_append(xlto, rto); qf = mms_queue_add(settings->system_user, xlto, msgid, NULL, xproxy, NULL, 0, time(NULL) + settings->default_msgexpiry, mresp, NULL, 0, octstr_get_cstr(settings->global_queuedir)); list_destroy(xlto, (list_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); list_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 = list_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 */ !does_prefix_match(settings->email2mmsrelay_prefixes, xto)) { error(0, "Not allowed to send to %s!", octstr_get_cstr(xto)); } else { List *lto = list_create(); Octstr *qf; Octstr *msgid = mms_get_header_value(msg, octstr_imm("Message-ID")); octstr_format_append(xto, "/TYPE=PLMN"); list_append(lto, xto); qf = mms_queue_add(xfrom, lto, msgid, NULL, xproxy, NULL, 0, time(NULL) + settings->default_msgexpiry, msg, NULL, 0, octstr_get_cstr(settings->global_queuedir)); list_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); } octstr_destroy(msgid); list_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 */ !does_prefix_match(settings->email2mmsrelay_prefixes, xto)) { error(0, "Not allowed to send to %s!", octstr_get_cstr(xto)); } else { List *lto = list_create(); Octstr *qf; Octstr *msgid = mms_get_header_value(msg, octstr_imm("Message-ID")); octstr_format_append(xto, "/TYPE=PLMN"); list_append(lto, xto); qf = mms_queue_add(xfrom, lto, msgid, NULL, xproxy, NULL, 0, time(NULL) + settings->default_msgexpiry, msg, NULL,0, octstr_get_cstr(settings->global_queuedir)); list_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); } octstr_destroy(msgid); list_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); 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 int isphonenum(Octstr *s) { int i = 0, n = octstr_len(s); char *cs; if (s && octstr_len(s) >= 1 && octstr_get_cstr(s)[0] == '+') i++; for ( cs = octstr_get_cstr(s); i0) 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")); }