📄 smsc_at.c
字号:
message->sms.pid = pid; /* deal with the user data -- 7 or 8 bit encoded */ tmpstr = octstr_copy(pdu, pos, len); if (message->sms.coding == DC_8BIT || message->sms.coding == DC_UCS2) { text = octstr_duplicate(tmpstr); } else { int offset = 0; text = octstr_create(""); if (udhi && message->sms.coding == DC_7BIT) { int nbits; nbits = (udhlen + 1) * 8; /* fill bits for UDH to septet boundary */ offset = (((nbits / 7) + 1) * 7 - nbits) % 7; } at2_decode7bituncompressed(tmpstr, len, text, offset); } message->sms.sender = origin; if (octstr_len(privdata->my_number)) { message->sms.receiver = octstr_duplicate(privdata->my_number); } else { /* Put a dummy address in the receiver for now (SMSC requires one) */ message->sms.receiver = octstr_create_from_data("1234", 4); } if (udhi) { message->sms.udhdata = udh; } message->sms.msgdata = text; message->sms.time = stime; /* cleanup */ octstr_destroy(pdu); octstr_destroy(tmpstr); return message; msg_error: error(1,"AT2[%s]: Invalid DELIVER-SMS pdu !", octstr_get_cstr(privdata->name)); O_DESTROY(udh); O_DESTROY(origin); O_DESTROY(text); O_DESTROY(pdu); return NULL;}Msg *at2_pdu_decode_report_sm(Octstr *data, PrivAT2data *privdata){ Msg* dlrmsg = NULL; Octstr *pdu, *msg_id, *tmpstr = NULL, *receiver = NULL; int type, tp_mr, len, ntype, pos; /* * parse the PDU. */ /* convert the pdu to binary format for ease of processing */ pdu = at2_convertpdu(data); /* Message reference */ tp_mr = octstr_get_char(pdu,1); msg_id = octstr_format("%d",tp_mr); debug("bb.smsc.at2",0,"AT2[%s]: got STATUS-REPORT for message <%d>:", octstr_get_cstr(privdata->name), tp_mr); /* reciver address */ len = octstr_get_char(pdu, 2); ntype = octstr_get_char(pdu, 3); pos = 4; if ((ntype & 0xD0) == 0xD0) { /* Alphanumeric sender */ receiver = octstr_create(""); tmpstr = octstr_copy(pdu, pos, (len+1)/2); at2_decode7bituncompressed(tmpstr, (((len - 1) * 4 - 3) / 7) + 1, receiver, 0); octstr_destroy(tmpstr); debug("bb.smsc.at2", 0, "AT2[%s]: Alphanumeric receiver <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(receiver)); pos += (len + 1) / 2; } else { int i; receiver = octstr_create(""); if ((ntype & 0x90) == 0x90) { /* International number */ octstr_append_char(receiver, '+'); } for (i = 0; i < len; i += 2, pos++) { octstr_append_char(receiver, (octstr_get_char(pdu, pos) & 15) + 48); if (i + 1 < len) octstr_append_char(receiver, (octstr_get_char(pdu, pos) >> 4) + 48); } debug("bb.smsc.at2", 0, "AT2[%s]: Numeric receiver %s <%s>", octstr_get_cstr(privdata->name), ((ntype & 0x90) == 0x90 ? "(international)" : ""), octstr_get_cstr(receiver)); } pos += 14; /* skip time stamps for now */ if ((type = octstr_get_char(pdu, pos)) == -1 ) { error(1,"AT2[%s]: STATUS-REPORT pdu too short to have TP-Status field !", octstr_get_cstr(privdata->name)); goto error; } /* check DLR type: * 3GPP TS 23.040 defines this a bit mapped field with lots of options * most of which are not really intersting to us, as we are only interested * in one of three conditions : failed, held in SC for delivery later, or delivered successfuly * and here's how I suggest to test it (read the 3GPP reference for further detailes) - * we'll test the 6th and 5th bits (7th bit when set making all other values 'reseved' so I want to test it). */ type = type & 0xE0; /* filter out everything but the 7th, 6th and 5th bits */ switch (type) { case 0x00: /* 0 0 : success class */ type = DLR_SUCCESS; tmpstr = octstr_create("Success"); break; case 0x20: /* 0 1 : buffered class (temporary error) */ type = DLR_BUFFERED; tmpstr = octstr_create("Buffered"); break; case 0x40: case 0x60: default: /* 1 0 : failed class */ /* 1 1 : failed class (actually, temporary error but timed out) */ /* and any other value (can't think of any) is considered failure */ type = DLR_FAIL; tmpstr = octstr_create("Failed"); break; } /* Actually, the above implementation is not correct, as the reference says that implementations should consider * any "reserved" values to be "failure", but most reserved values fall into one of the three categories. it will catch * "reserved" values where the first 3 MSBits are not set as "Success" which may not be correct. */ if ((dlrmsg = dlr_find(privdata->conn->id, msg_id, receiver, type)) == NULL) { debug("bb.smsc.at2",1,"AT2[%s]: Received delivery notification but can't find that ID in the DLR storage", octstr_get_cstr(privdata->name)); goto error; } /* Beware DLR URL is now in msg->sms.dlr_url given by dlr_find() */ dlrmsg->sms.msgdata = octstr_duplicate(tmpstr); error: O_DESTROY(tmpstr); O_DESTROY(pdu); O_DESTROY(receiver); O_DESTROY(msg_id); return dlrmsg;}Octstr *at2_convertpdu(Octstr *pdutext){ Octstr *pdu; int i; int len = octstr_len(pdutext); pdu = octstr_create(""); for (i = 0; i < len; i += 2) { octstr_append_char(pdu, at2_hexchar(octstr_get_char(pdutext, i)) * 16 + at2_hexchar(octstr_get_char(pdutext, i + 1))); } return pdu;}int at2_rmask[8] = { 0, 1, 3, 7, 15, 31, 63, 127 };int at2_lmask[8] = { 0, 128, 192, 224, 240, 248, 252, 254 };void at2_decode7bituncompressed(Octstr *input, int len, Octstr *decoded, int offset){ unsigned char septet, octet, prevoctet; int i; int r = 1; int c = 7; int pos = 0; /* Shift the buffer offset bits to the left */ if (offset > 0) { unsigned char *ip; for (i = 0, ip = octstr_get_cstr(input); i < octstr_len(input); i++) { if (i == octstr_len(input) - 1) *ip = *ip >> offset; else *ip = (*ip >> offset) | (*(ip + 1) << (8 - offset)); ip++; } } octet = octstr_get_char(input, pos); prevoctet = 0; for (i = 0; i < len; i++) { septet = ((octet & at2_rmask[c]) << (r - 1)) + prevoctet; octstr_append_char(decoded, septet); prevoctet = (octet & at2_lmask[r]) >> c; /* When r=7 we have a full character in prevoctet */ if ((r == 7) && (i < len - 1)) { i++; octstr_append_char(decoded, prevoctet); prevoctet = 0; } r = (r > 6) ? 1 : r + 1; c = (c < 2) ? 7 : c - 1; pos++; octet = octstr_get_char(input, pos); } charset_gsm_to_latin1(decoded);}void at2_send_messages(PrivAT2data *privdata){ Msg *msg; do { if (privdata->modem->enable_mms && list_len(privdata->outgoing_queue) > 1) at2_send_modem_command(privdata, "AT+CMMS=2", 0, 0); if ((msg = list_extract_first(privdata->outgoing_queue))) at2_send_one_message(privdata, msg); } while (msg);}void at2_send_one_message(PrivAT2data *privdata, Msg *msg){ unsigned char command[500]; int ret = -1; char sc[3]; int retries = RETRY_SEND; if (octstr_len(privdata->my_number)) { octstr_destroy(msg->sms.sender); msg->sms.sender = octstr_duplicate(privdata->my_number); } /* * The standard says you should be prepending the PDU with 00 to indicate * to use the default SC. Some older modems dont expect this so it can be * disabled * NB: This extra padding is not counted in the CMGS byte count */ sc[0] = '\0'; if (!privdata->modem->no_smsc) strcpy(sc, "00"); if (msg_type(msg) == sms) { Octstr* pdu; if ((pdu = at2_pdu_encode(msg, privdata)) == NULL) { error(2, "AT2[%s]: Error encoding PDU!",octstr_get_cstr(privdata->name)); return; } ret = -99; retries = RETRY_SEND; while ((ret != 0) && (retries-- > 0)) { int msg_id = -1; /* * send the initial command and then wait for > */ sprintf(command, "AT+CMGS=%ld", octstr_len(pdu) / 2); ret = at2_send_modem_command(privdata, command, 5, 1); debug("bb.smsc.at2", 0, "AT2[%s]: send command status: %d", octstr_get_cstr(privdata->name), ret); if (ret != 1) /* > only! */ continue; /* * ok the > has been see now so we can send the PDU now and a * control Z but no CR or LF */ sprintf(command, "%s%s", sc, octstr_get_cstr(pdu)); at2_write(privdata, command); at2_write_ctrlz(privdata); /* 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; /* store DLR message if needed for SMSC generated delivery reports */ if (DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask)) { 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(privdata->conn->id, dlrmsgid, msg); O_DESTROY(dlrmsgid); } } bb_smscconn_sent(privdata->conn, msg, NULL); } if (ret != 0) { /* * 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, octstr_create("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 > 0 ? 1 : 0) << 7) /* TP-RP */ | ((octstr_len(msg->sms.udhdata) ? 1 : 0) << 6) /* TP-UDHI */ | ((DLR_IS_ENABLED_DEVICE(msg->sms.dlr_mask) ? 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 == -1 ? 0 : msg->sms.pid) ); /* protocol identifier */ octstr_append_char(buffer, fields_to_dcs(msg, /* data coding scheme */ (msg->sms.alt_dcs != -1 ? msg->sms.alt_dcs : privdata->conn->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 >= 0) { 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(privda
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -