📄 smsc_emi2.c
字号:
octstr_append_char(str, dcs); octstr_binary_to_hex(str, 1); octstr_append(emimsg->fields[E50_XSER],str); octstr_destroy(str); } if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) { emimsg->fields[E50_MT] = octstr_create("4"); emimsg->fields[E50_MCLS] = octstr_create("1"); str = octstr_duplicate(msg->sms.msgdata); emimsg->fields[E50_NB] = octstr_format("%04d", 8 * octstr_len(str)); octstr_binary_to_hex(str, 1); emimsg->fields[E50_TMSG] = str; } else { emimsg->fields[E50_MT] = octstr_create("3"); str = octstr_duplicate(msg->sms.msgdata); charset_latin1_to_gsm(str); /* Could still be too long after truncation if there's an UDH part, * but this is only to notice errors elsewhere (should never happen).*/ if (charset_gsm_truncate(str, 160)) error(0, "EMI2[%s]: Message to send is longer " "than 160 gsm characters", octstr_get_cstr(privdata->name)); octstr_binary_to_hex(str, 1); emimsg->fields[E50_AMSG] = str; } if (msg->sms.validity) { tm = gw_localtime(time(NULL) + msg->sms.validity * 60); sprintf(p, "%02d%02d%02d%02d%02d", tm.tm_mday, tm.tm_mon + 1, tm.tm_year % 100, tm.tm_hour, tm.tm_min); str = octstr_create(p); emimsg->fields[E50_VP] = str; } if (msg->sms.deferred) { str = octstr_create("1"); emimsg->fields[E50_DD] = str; tm = gw_localtime(time(NULL) + msg->sms.deferred * 60); sprintf(p, "%02d%02d%02d%02d%02d", tm.tm_mday, tm.tm_mon + 1, tm.tm_year % 100, tm.tm_hour, tm.tm_min); str = octstr_create(p); emimsg->fields[E50_DDT] = str; } /* if delivery reports are asked, lets ask for them too */ /* even the sender might not be interested in delivery or non delivery */ /* we still need them back to clear out the memory after the message */ /* has been delivered or non delivery has been confirmed */ if (msg->sms.dlr_mask & (DLR_SUCCESS | DLR_FAIL | DLR_BUFFERED)) { emimsg->fields[E50_NRQ] = octstr_create("1"); emimsg->fields[E50_NT] = octstr_create(""); octstr_append_decimal(emimsg->fields[E50_NT], 3 + (msg->sms.dlr_mask & DLR_BUFFERED)); if (privdata->npid) emimsg->fields[E50_NPID] = octstr_duplicate(privdata->npid); if (privdata->nadc) emimsg->fields[E50_NADC] = octstr_duplicate(privdata->nadc); } return emimsg;}/* Return -1 if the connection broke, 0 if the request couldn't be handled * (unknown type), or 1 if everything was successful */static int handle_operation(SMSCConn *conn, Connection *server, struct emimsg *emimsg){ struct emimsg *reply; Octstr *tempstr, *xser; int type, len; Msg *msg = NULL; struct universaltime unitime; int st_code; PrivData *privdata = conn->data; switch(emimsg->ot) { case 01: msg = msg_create(sms); if (emimsg->fields[E01_AMSG] == NULL) emimsg->fields[E01_AMSG] = octstr_create(""); else if (octstr_hex_to_binary(emimsg->fields[E01_AMSG]) == -1) warning(0, "EMI2[%s]: Couldn't decode message text", octstr_get_cstr(privdata->name)); if (emimsg->fields[E01_MT] == NULL) { warning(0, "EMI2[%s]: required field MT missing", octstr_get_cstr(privdata->name)); /* This guess could be incorrect, maybe the message should just be dropped */ emimsg->fields[E01_MT] = octstr_create("3"); } if (octstr_get_char(emimsg->fields[E01_MT], 0) == '3') { msg->sms.msgdata = emimsg->fields[E01_AMSG]; emimsg->fields[E01_AMSG] = NULL; /* So it's not freed */ charset_gsm_to_latin1(msg->sms.msgdata); } else { error(0, "EMI2[%s]: MT == %s isn't supported for operation type 01", octstr_get_cstr(privdata->name), octstr_get_cstr(emimsg->fields[E01_MT])); msg->sms.msgdata = octstr_create(""); } msg->sms.sender = octstr_duplicate(emimsg->fields[E01_OADC]); if (msg->sms.sender == NULL) { warning(0, "EMI2[%s]: Empty sender field in received message", octstr_get_cstr(privdata->name)); msg->sms.sender = octstr_create(""); } if(octstr_len(PRIVDATA(conn)->my_number)) { msg->sms.receiver = octstr_duplicate(PRIVDATA(conn)->my_number); } else { msg->sms.receiver = octstr_duplicate(emimsg->fields[E01_ADC]); } if (msg->sms.sender == NULL) { warning(0, "EMI2[%s]: Empty receiver field in received message", octstr_get_cstr(privdata->name)); msg->sms.receiver = octstr_create(""); } /* Operation type 01 doesn't have a time stamp field */ time(&msg->sms.time); msg->sms.smsc_id = octstr_duplicate(conn->id); bb_smscconn_receive(conn, msg); reply = emimsg_create_reply(01, emimsg->trn, 1, privdata->name); if (emi2_emimsg_send(conn, server, reply) < 0) { emimsg_destroy(reply); return -1; } emimsg_destroy(reply); return 1; case 52: msg = msg_create(sms); /* AMSG is the same field as TMSG */ if (emimsg->fields[E50_AMSG] == NULL) emimsg->fields[E50_AMSG] = octstr_create(""); else if (octstr_hex_to_binary(emimsg->fields[E50_AMSG]) == -1) warning(0, "EMI2[%s]: Couldn't decode message text", octstr_get_cstr(privdata->name)); xser = emimsg->fields[E50_XSER]; while (octstr_len(xser) > 0) { tempstr = octstr_copy(xser, 0, 4); if (octstr_hex_to_binary(tempstr) == -1) error(0, "EMI2[%s]: Invalid XSer", octstr_get_cstr(privdata->name)); type = octstr_get_char(tempstr, 0); len = octstr_get_char(tempstr, 1); octstr_destroy(tempstr); if (len < 0) { error(0, "EMI2[%s]: Malformed emi XSer field", octstr_get_cstr(privdata->name)); break; } if (type != 1 && type != 2) warning(0, "EMI2[%s]: Unsupported EMI XSer field %d", octstr_get_cstr(privdata->name), type); else { if (type == 1) { tempstr = octstr_copy(xser, 4, len * 2); if (octstr_hex_to_binary(tempstr) == -1) error(0, "EMI2[%s]: Invalid UDH contents", octstr_get_cstr(privdata->name)); msg->sms.udhdata = tempstr; } if (type == 2) { int dcs; tempstr = octstr_copy(xser, 4, 2); octstr_hex_to_binary(tempstr); dcs = octstr_get_char(tempstr, 0); octstr_destroy(tempstr); if (! dcs_to_fields(&msg, dcs)) { error(0, "EMI2[%s]: invalid dcs received", octstr_get_cstr(privdata->name)); /* XXX Should we discard message ? */ dcs_to_fields(&msg, 0); } } } octstr_delete(xser, 0, 2 * len + 4); } if (emimsg->fields[E50_MT] == NULL) { warning(0, "EMI2[%s]: required field MT missing", octstr_get_cstr(privdata->name)); /* This guess could be incorrect, maybe the message should just be dropped */ emimsg->fields[E50_MT] = octstr_create("3"); } if (octstr_get_char(emimsg->fields[E50_MT], 0) == '3') { msg->sms.msgdata = emimsg->fields[E50_AMSG]; emimsg->fields[E50_AMSG] = NULL; /* So it's not freed */ charset_gsm_to_latin1(msg->sms.msgdata); } else if (octstr_get_char(emimsg->fields[E50_MT], 0) == '4') { msg->sms.msgdata = emimsg->fields[E50_TMSG]; emimsg->fields[E50_TMSG] = NULL; } else { error(0, "EMI2[%s]: MT == %s isn't supported yet", octstr_get_cstr(privdata->name), octstr_get_cstr(emimsg->fields[E50_MT])); msg->sms.msgdata = octstr_create(""); } msg->sms.sender = octstr_duplicate(emimsg->fields[E50_OADC]); if (msg->sms.sender == NULL) { warning(0, "EMI2[%s]: Empty sender field in received message", octstr_get_cstr(privdata->name)); msg->sms.sender = octstr_create(""); } if(octstr_len(PRIVDATA(conn)->my_number)) { msg->sms.receiver = octstr_duplicate(PRIVDATA(conn)->my_number); } else { msg->sms.receiver = octstr_duplicate(emimsg->fields[E50_ADC]); } if (msg->sms.sender == NULL) { warning(0, "EMI2[%s]: Empty receiver field in received message", octstr_get_cstr(privdata->name)); msg->sms.receiver = octstr_create(""); } tempstr = emimsg->fields[E50_SCTS]; /* Just a shorter name */ if (tempstr == NULL) { warning(0, "EMI2[%s]: Received EMI message doesn't have required timestamp", octstr_get_cstr(privdata->name)); goto notime; } if (octstr_len(tempstr) != 12) { warning(0, "EMI2[%s]: EMI SCTS field must have length 12, now %ld", octstr_get_cstr(privdata->name), octstr_len(tempstr)); goto notime; } if (octstr_parse_long(&unitime.second, tempstr, 10, 10) != 12 || (octstr_delete(tempstr, 10, 2), octstr_parse_long(&unitime.minute, tempstr, 8, 10) != 10) || (octstr_delete(tempstr, 8, 2), octstr_parse_long(&unitime.hour, tempstr, 6, 10) != 8) || (octstr_delete(tempstr, 6, 2), octstr_parse_long(&unitime.year, tempstr, 4, 10) != 6) || (octstr_delete(tempstr, 4, 2), octstr_parse_long(&unitime.month, tempstr, 2, 10) != 4) || (octstr_delete(tempstr, 2, 2), octstr_parse_long(&unitime.day, tempstr, 0, 10) != 2)) { error(0, "EMI2[%s]: EMI delivery time stamp looks malformed", octstr_get_cstr(privdata->name)); notime: time(&msg->sms.time); } else { unitime.year += 2000; /* Conversion function expects full year */ unitime.month -= 1; /* conversion function expects 0-based months */ msg->sms.time = date_convert_universal(&unitime); } msg->sms.smsc_id = octstr_duplicate(conn->id); counter_increase(conn->received); bb_smscconn_receive(conn, msg); reply = emimsg_create_reply(52, emimsg->trn, 1, privdata->name); if (emi2_emimsg_send(conn, server, reply) < 0) { emimsg_destroy(reply); return -1; } emimsg_destroy(reply); return 1; case 53: /* delivery notification */ st_code = atoi(octstr_get_cstr(emimsg->fields[E50_DST])); switch(st_code) { case 0: /* delivered */ msg = dlr_find(octstr_get_cstr((conn->id ? conn->id : privdata->name)), octstr_get_cstr(emimsg->fields[E50_SCTS]), /* timestamp */ octstr_get_cstr(emimsg->fields[E50_OADC]), /* destination */ DLR_SUCCESS); break; case 1: /* buffered */ msg = dlr_find(octstr_get_cstr((conn->id ? conn->id : privdata->name)), octstr_get_cstr(emimsg->fields[E50_SCTS]), /* timestamp */ octstr_get_cstr(emimsg->fields[E50_OADC]), /* destination */ DLR_BUFFERED); break; case 2: /* not delivered */ msg = dlr_find(octstr_get_cstr((conn->id ? conn->id : privdata->name)), octstr_get_cstr(emimsg->fields[E50_SCTS]), /* timestamp */ octstr_get_cstr(emimsg->fields[E50_OADC]), /* destination */ DLR_FAIL); break; } if (msg != NULL) { /* * Recode the msg structure with the given msgdata. * Note: the DLR URL is delivered in msg->sms.dlr_url already. */ msg->sms.msgdata = octstr_duplicate(emimsg->fields[E50_AMSG]); octstr_hex_to_binary(msg->sms.msgdata); msg->sms.sms_type = report; bb_smscconn_receive(conn, msg); } reply = emimsg_create_reply(53, emimsg->trn, 1, privdata->name); if (emi2_emimsg_send(conn, server, reply) < 0) { emimsg_destroy(reply); return -1; } emimsg_destroy(reply); return 1; default: error(0, "EMI2[%s]: I don't know how to handle operation type %d", octstr_get_cstr(privdata->name), emimsg->ot); return 0; }}/* * get all unacknowledged messages from the ringbuffer and queue them * for retransmission. */static void clear_sent(PrivData *privdata){ int i; debug("smsc.emi2", 0, "EMI2[%s]: clear_sent called", octstr_get_cstr(privdata->name)); for (i = 0; i < EMI2_MAX_TRN; i++) { if (privdata->slots[i].sendtime && privdata->slots[i].sendtype == 51) list_produce(privdata->outgoing_queue, privdata->slots[i].sendmsg); privdata->slots[i].sendtime = 0; } privdata->unacked = 0;}/* * wait seconds seconds for something to happen (a send SMS request, activity * on the SMSC main connection, an error or timeout) and tell the caller * what happened. */static EMI2Event emi2_wait (SMSCConn *conn, Connection *server, double seconds){ if (emi2_can_send(conn) && list_len(PRIVDATA(conn)->outgoing_queue)) { return EMI2_SENDREQ; } if (server != NULL) { switch (conn_wait(server, seconds)) { case 1: return list_len(PRIVDATA(conn)->outgoing_queue) ? EMI2_SENDREQ : EMI2_TIMEOUT; case 0: return EMI2_SMSCREQ; default: return EMI2_CONNERR; } } else { gwthread_sleep(seconds); return list_len(PRIVDATA(conn)->outgoing_queue) ? EMI2_SENDREQ : EMI2_TIMEOUT; }}/* * obtain the next free TRN. */static int emi2_next_trn (SMSCConn *conn){#define INC_TRN(x) ((x)=((x) + 1) % EMI2_MAX_TRN) int result; while (SLOTBUSY(conn,PRIVDATA(conn)->priv_nexttrn)) INC_TRN(PRIVDATA(conn)->priv_nexttrn); /* pick unused TRN */ result = PRIVDATA(conn)->priv_nexttrn; INC_TRN(PRIVDATA(conn)->priv_nexttrn); return result;#undef INC_TRN}/* * send an EMI type 31 message when required. */static int emi2_keepalive_handling (SMSCConn *conn, Connection *server){ struct emimsg *emimsg; int nexttrn = emi2_next_trn (conn); emimsg = make_emi31(PRIVDATA(conn), nexttrn); if(emimsg) { PRIVDATA(conn)->slots[nexttrn].sendtype= 31; PRIVDATA(conn)->slots[nexttrn].sendtime = time(NULL); PRIVDATA(conn)->unacked++; if (emi2_emimsg_send(conn, server, emimsg) == -1) { emimsg_destroy(emimsg); return -1; } emimsg_destroy(emimsg); } PRIVDATA(conn)->can_write = 0; return 0;}/* * the actual send logic: Send all queued messages in a burst. */static int emi2_do_send (SMSCConn *conn, Connection *server){ struct emimsg *emimsg; Msg *msg; double delay = 0; if (PRIVDATA(conn)->throughput) { delay = 1.0 / PRIVDATA(conn)->throughput; } /* Send messages if there's room in the sending window */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -