📄 smsc_at2.c
字号:
/* wait 20 secs for modem command */ ret = at2_wait_modem_command(privdata, 20, 0, &msg_id); debug("bb.smsc.at2", 0, "AT2[%s]: send command status: %d", octstr_get_cstr(privdata->name), ret); if (ret != 0) /* OK only */ continue; /* gen DLR_SMSC_SUCCESS */ if (msg->sms.dlr_mask & DLR_SMSC_SUCCESS) { Msg* dlrmsg; dlrmsg = msg_create(sms); dlrmsg->sms.id = msg->sms.id; dlrmsg->sms.service = octstr_duplicate(msg->sms.service); dlrmsg->sms.dlr_mask = DLR_SMSC_SUCCESS; dlrmsg->sms.sms_type = report; dlrmsg->sms.smsc_id = octstr_duplicate(privdata->conn->id); dlrmsg->sms.sender = octstr_duplicate(msg->sms.receiver); dlrmsg->sms.receiver = octstr_duplicate(msg->sms.sender); dlrmsg->sms.msgdata = octstr_create("ACK"); dlrmsg->sms.dlr_url = octstr_duplicate(msg->sms.dlr_url); time(&dlrmsg->sms.time); debug("bb.smsc.at2",0,"AT2[%s]: sending DLR type ACK", octstr_get_cstr(privdata->name)); bb_smscconn_receive(privdata->conn, dlrmsg); } /* store DLR message if needed for SMSC generated delivery reports */ if (msg->sms.dlr_mask & (DLR_SUCCESS | DLR_FAIL | DLR_BUFFERED)) { if (msg_id == -1) error(0,"AT2[%s]: delivery notification requested, but I have no message ID!", octstr_get_cstr(privdata->name)); else { Octstr *dlrmsgid = octstr_format("%d", msg_id); dlr_add(octstr_get_cstr(privdata->conn->id), octstr_get_cstr(dlrmsgid), octstr_get_cstr(msg->sms.sender), octstr_get_cstr(msg->sms.receiver), octstr_get_cstr(msg->sms.service), octstr_get_cstr(msg->sms.dlr_url), msg->sms.dlr_mask); O_DESTROY(dlrmsgid); } } counter_increase(privdata->conn->sent); bb_smscconn_sent(privdata->conn, msg); } if (ret != 0) { /* gen DLR_SMSC_FAIL */ if (msg->sms.dlr_mask & DLR_SMSC_FAIL) { Msg* dlrmsg; dlrmsg = msg_create(sms); dlrmsg->sms.service = octstr_duplicate(msg->sms.service); dlrmsg->sms.dlr_mask = DLR_SMSC_FAIL; dlrmsg->sms.sms_type = report; dlrmsg->sms.smsc_id = octstr_duplicate(privdata->conn->id); dlrmsg->sms.sender = octstr_duplicate(msg->sms.receiver); dlrmsg->sms.receiver = octstr_duplicate(msg->sms.sender); dlrmsg->sms.msgdata = octstr_create("NACK"); dlrmsg->sms.dlr_url = octstr_duplicate(msg->sms.dlr_url); time(&dlrmsg->sms.time); debug("bb.smsc.at2",0,"AT2[%s]: sending DLR type NACK", octstr_get_cstr(privdata->name)); bb_smscconn_receive(privdata->conn, dlrmsg); } /* * no need to do counter_increase(privdata->conn->failed) here, * since bb_smscconn_send_failed() will inc the counter on * SMSCCONN_FAILED_MALFORMED */ bb_smscconn_send_failed(privdata->conn, msg, SMSCCONN_FAILED_MALFORMED); } O_DESTROY(pdu); }}Octstr* at2_pdu_encode(Msg *msg, PrivAT2data *privdata){ /* * Message coding is done as a binary octet string, * as per 3GPP TS 23.040 specification (GSM 03.40), */ Octstr *pdu = NULL, *temp = NULL, *buffer = octstr_create(""); int len, setvalidity = 0; /* * message type SUBMIT , bit mapped : * bit7 .. bit0 * TP-RP , TP-UDHI, TP-SRR, TP-VPF(4), TP-VPF(3), TP-RD, TP-MTI(1), TP-MTI(0) */ octstr_append_char(buffer, ((msg->sms.rpi ? 1 : 0) << 7) /* TP-RP */ | ((octstr_len(msg->sms.udhdata) ? 1 : 0) << 6) /* TP-UDHI */ | (((msg->sms.dlr_mask & (DLR_SUCCESS | DLR_FAIL | DLR_BUFFERED)) ? 1 : 0) << 5) /* TP-SRR */ | 16 /* TP-VP(Rel)*/ | 1 /* TP-MTI: SUBMIT_SM */ ); /* message reference (0 for now) */ octstr_append_char(buffer, 0); /* destination address */ if ((temp = at2_format_address_field(msg->sms.receiver)) == NULL) goto error; octstr_append(buffer, temp); O_DESTROY(temp); octstr_append_char(buffer, msg->sms.pid); /* protocol identifier */ octstr_append_char(buffer, fields_to_dcs(msg, /* data coding scheme */ (msg->sms.alt_dcs ? 2 - msg->sms.alt_dcs : privdata->alt_dcs))); /* * Validity-Period (TP-VP) * see GSM 03.40 section 9.2.3.12 * defaults to 24 hours = 167 if not set */ if ( msg->sms.validity) { if (msg->sms.validity > 635040) setvalidity = 255; if (msg->sms.validity >= 50400 && msg->sms.validity <= 635040) setvalidity = (msg->sms.validity - 1) / 7 / 24 / 60 + 192 + 1; if (msg->sms.validity > 43200 && msg->sms.validity < 50400) setvalidity = 197; if (msg->sms.validity >= 2880 && msg->sms.validity <= 43200) setvalidity = (msg->sms.validity - 1) / 24 / 60 + 166 + 1; if (msg->sms.validity > 1440 && msg->sms.validity < 2880) setvalidity = 168; if (msg->sms.validity >= 750 && msg->sms.validity <= 1440) setvalidity = (msg->sms.validity - 720 - 1) / 30 + 143 + 1; if (msg->sms.validity > 720 && msg->sms.validity < 750) setvalidity = 144; if (msg->sms.validity >= 5 && msg->sms.validity <= 720) setvalidity = (msg->sms.validity - 1) / 5 - 1 + 1; if (msg->sms.validity < 5) setvalidity = 0; } else setvalidity = (privdata->validityperiod != NULL ? atoi(octstr_get_cstr(privdata->validityperiod)) : 167); if (setvalidity >= 0 && setvalidity <= 143) debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %d minutes", octstr_get_cstr(privdata->name), (setvalidity + 1)*5); else if (setvalidity >= 144 && setvalidity <= 167) debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %3.1f hours", octstr_get_cstr(privdata->name), ((float)(setvalidity - 143) / 2) + 12); else if (setvalidity >= 168 && setvalidity <= 196) debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %d days", octstr_get_cstr(privdata->name), (setvalidity - 166)); else debug("bb.smsc.at2", 0, "AT2[%s]: TP-Validity-Period: %d weeks", octstr_get_cstr(privdata->name), (setvalidity - 192)); octstr_append_char(buffer, setvalidity); /* user data length - include length of UDH if it exists */ len = sms_msgdata_len(msg); if (octstr_len(msg->sms.udhdata)) { if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) { len += octstr_len(msg->sms.udhdata); if (len > SMS_8BIT_MAX_LEN) { /* truncate user data to allow UDH to fit */ octstr_delete(msg->sms.msgdata, SMS_8BIT_MAX_LEN - octstr_len(msg->sms.udhdata), 9999); len = SMS_8BIT_MAX_LEN; } } else { /* * The reason we branch here is because UDH data length is determined * in septets if we are in GSM coding, otherwise it's in octets. Adding 6 * will ensure that for an octet length of 0, we get septet length 0, * and for octet length 1 we get septet length 2. */ int temp_len; len += (temp_len = (((8 * octstr_len(msg->sms.udhdata)) + 6) / 7)); if (len > SMS_7BIT_MAX_LEN) { /* truncate user data to allow UDH to fit */ octstr_delete(msg->sms.msgdata, SMS_7BIT_MAX_LEN - temp_len, 9999); len = SMS_7BIT_MAX_LEN; } } } octstr_append_char(buffer,len); if (octstr_len(msg->sms.udhdata)) /* udh */ octstr_append(buffer, msg->sms.udhdata); /* user data */ if (msg->sms.coding == DC_8BIT || msg->sms.coding == DC_UCS2) { octstr_append(buffer, msg->sms.msgdata); } else { int offset = 0; /* * calculate the number of fill bits needed to align * the 7bit encoded user data on septet boundry */ if (octstr_len(msg->sms.udhdata)) { /* Have UDH */ int nbits = octstr_len(msg->sms.udhdata) * 8; /* Includes UDH length byte */ offset = (((nbits / 7) + 1) * 7 - nbits) % 7; /* Fill bits */ } charset_latin1_to_gsm(msg->sms.msgdata); if ((temp = at2_encode7bituncompressed(msg->sms.msgdata, offset)) != NULL) octstr_append(buffer, temp); O_DESTROY(temp); } /* convert PDU to HEX representation suitable for the AT2 command set */ pdu = at2_encode8bituncompressed(buffer); O_DESTROY(buffer); return pdu;error: O_DESTROY(temp); O_DESTROY(buffer); O_DESTROY(pdu); return NULL;}Octstr* at2_encode7bituncompressed(Octstr *source, int offset){ int LSBmask[8] = { 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F }; int MSBmask[8] = { 0x00, 0x40, 0x60, 0x70, 0x78, 0x7C, 0x7E, 0x7F }; int destRemain = (int)ceil ((octstr_len(source) * 7.0) / 8.0); int i = (offset?8-offset:7), iStore = offset; int posT, posS; Octstr *target = octstr_create(""); int target_chr = 0, source_chr; /* start packing the septet stream into an octet stream */ for (posS = 0, posT = 0; (source_chr = octstr_get_char(source, posS++)) != -1;) { /* grab least significant bits from current septet and store them packed to the right */ target_chr |= (source_chr & LSBmask[i]) << iStore; /* store current byte if last command filled it */ if (iStore != 0) { destRemain--; octstr_append_char(target, target_chr); target_chr = 0; } /* grab most significant bits from current septet and store them packed to the left */ target_chr |= (source_chr & MSBmask[7 - i]) >> (8 - iStore) % 8; /* advance target bit index by 7 ( modulo 8 addition ) */ iStore = (--iStore < 0 ? 7 : iStore); if (iStore != 0) /* if just finished packing 8 septets (into 7 octets) don't advance mask index */ i = (++i > 7 ? 1 : i); } /* don't forget to pack the leftovers ;-) */ if (destRemain > 0) octstr_append_char(target, target_chr); return target;}Octstr* at2_encode8bituncompressed(Octstr *input){ int len, i; Octstr* out = octstr_create(""); len = octstr_len(input); for (i = 0; i < len; i++) { /* each character is encoded in its hex representation (2 chars) */ octstr_append_char(out, at2_numtext( (octstr_get_char(input, i) & 0xF0) >> 4)); octstr_append_char(out, at2_numtext( (octstr_get_char(input, i) & 0x0F))); } return out;}int at2_numtext(int num){ return (num > 9) ? (num + 55) : (num + 48);}int at2_detect_speed(PrivAT2data *privdata){ int i;#ifdef B57600 int autospeeds[] = { 57600, 38400, 19200, 9600 };#else int autospeeds[] = { 38400, 19200, 9600 };#endif debug("bb.smsc.at2", 0, "AT2[%s]: detecting modem speed. ", octstr_get_cstr(privdata->name)); for (i = 0; i < (sizeof(autospeeds) / sizeof(int)); i++) { if(at2_test_speed(privdata, autospeeds[i]) == 0) { privdata->speed = autospeeds[i]; break; } } if (privdata->speed == 0) { info(0, "AT2[%s]: cannot detect speed", octstr_get_cstr(privdata->name)); return -1; } info(0, "AT2[%s]: detect speed is %ld", octstr_get_cstr(privdata->name), privdata->speed); return 0;}int at2_test_speed(PrivAT2data *privdata, long speed) { int res; if (at2_open_device1(privdata) == -1) return -1; at2_set_speed(privdata, speed); /* send a return so the modem can detect the speed */ res = at2_send_modem_command(privdata, "", 1, 0); res = at2_send_modem_command(privdata, "AT", 0, 0); if (res != 0) res = at2_send_modem_command(privdata, "AT", 0, 0); if (res != 0) res = at2_send_modem_command(privdata, "AT", 0, 0); at2_close_device(privdata); return res;}int at2_detect_modem_type(PrivAT2data *privdata){ int res; ModemDef *modem; int i; debug("bb.smsc.at2", 0, "AT2[%s]: detecting modem type", octstr_get_cstr(privdata->name)); if (at2_open_device1(privdata) == -1) return -1; at2_set_speed(privdata, privdata->speed); /* send a return so the modem can detect the speed */ res = at2_send_modem_command(privdata, "", 1, 0); res = at2_send_modem_command(privdata, "AT", 0, 0); if (at2_send_modem_command(privdata, "AT&F", 0, 0) == -1) return -1; if (at2_send_modem_command(privdata, "ATE0", 0, 0) == -1) return -1; at2_flush_buffer(privdata); if (at2_send_modem_command(privdata, "ATI", 0, 0) == -1) return -1; /* we try to detect the modem automatically */ i = 1; while ((modem = at2_read_modems(privdata, privdata->configfile, NULL, i++)) != NULL) { if (octstr_len(modem->detect_string) == 0) { at2_destroy_modem(modem); continue; } /* debug("bb.smsc.at2",0,"AT2[%s]: searching for %s", octstr_get_cstr(privdata->name), octstr_get_cstr(modem->name)); */ if (octstr_search(privdata->lines, modem->detect_string, 0) != -1) { if (octstr_len(modem->detect_string2) == 0) { debug("bb.smsc.at2", 0, "AT2[%s]: found string <%s>, using modem definition <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(modem->detect_string), octstr_get_cstr(modem->name)); privdata->modem = modem; break; } else { if (octstr_search(privdata->lines, modem->detect_string2, 0) != -1) { debug("bb.smsc.at2", 0, "AT2[%s]: found string <%s> plus <%s>, using modem " "definition <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(modem->detect_string), octstr_get_cstr(modem->detect_string2), octstr_get_cstr(modem->name)); privdata->modem = modem; break; } } } } if (privdata->modem == NULL) { debug("bb.smsc.at2", 0, "AT2[%s]: Cannot detect modem, using generic", octstr_get_cstr(privdata->name)); if ((modem = at2_read_modems(privdata, privdata->configfile, octstr_imm("generic"), 0)) == NULL) { panic(0, "AT2[%s]: Cannot detect modem and generic not found", octstr_get_cstr(privdata->name)); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -