📄 smsc_at2.c
字号:
break; /* Add other message types here: */ } return msg;}Msg *at2_pdu_decode_deliver_sm(Octstr *data, PrivAT2data *privdata){ int len, pos, i, ntype; int udhi, dcs, udhlen, pid; Octstr *origin = NULL; Octstr *udh = NULL; Octstr *text = NULL, *tmpstr; Octstr *pdu = NULL; Msg *message = NULL; struct universaltime mtime; /* time structure */ long stime; /* time in seconds */ int timezone; /* timezone in 15 minutes jumps from GMT */ /* * Note: some parts of the PDU are not decoded because they are * not needed for the Msg type. */ /* convert the pdu to binary format for ease of processing */ pdu = at2_convertpdu(data); /* UDH Indicator */ udhi = (octstr_get_char(pdu, 0) & 64) >> 6; /* originating address */ len = octstr_get_char(pdu, 1); ntype = octstr_get_char(pdu, 2); pos = 3; if ((ntype & 0xD0) == 0xD0) { /* Alphanumeric sender */ origin = octstr_create(""); tmpstr = octstr_copy(pdu, 3, len); at2_decode7bituncompressed(tmpstr, (((len - 1) * 4 - 3) / 7) + 1, origin, 0); octstr_destroy(tmpstr); debug("bb.smsc.at2", 0, "AT2[%s]: Alphanumeric sender <%s>", octstr_get_cstr(privdata->name), octstr_get_cstr(origin)); pos += (len + 1) / 2; } else { origin = octstr_create(""); if ((ntype & 0x90) == 0x90) { /* International number */ octstr_append_char(origin, '+'); } for (i = 0; i < len; i += 2, pos++) { octstr_append_char(origin, (octstr_get_char(pdu, pos) & 15) + 48); if (i + 1 < len) octstr_append_char(origin, (octstr_get_char(pdu, pos) >> 4) + 48); } debug("bb.smsc.at2", 0, "AT2[%s]: Numeric sender %s <%s>", octstr_get_cstr(privdata->name), ((ntype & 0x90) == 0x90 ? "(international)" : ""), octstr_get_cstr(origin)); } /* PID */ pid = octstr_get_char(pdu, pos); pos++; /* DCS */ dcs = octstr_get_char(pdu, pos); pos++; /* get the timestamp */ mtime.year = swap_nibbles(octstr_get_char(pdu, pos)); pos++; mtime.year += (mtime.year < 70 ? 2000 : 1900); mtime.month = swap_nibbles(octstr_get_char(pdu, pos)) ; pos++; mtime.day = swap_nibbles(octstr_get_char(pdu, pos)); pos++; mtime.hour = swap_nibbles(octstr_get_char(pdu, pos)); pos++; mtime.minute = swap_nibbles(octstr_get_char(pdu, pos)); pos++; mtime.second = swap_nibbles(octstr_get_char(pdu, pos)); pos++; /* * time zone: * * time zone is "swapped nibble", with the MSB as the sign (1 is negative). */ timezone = swap_nibbles(octstr_get_char(pdu, pos)); pos++; timezone = ((timezone >> 7) ? -1 : 1) * (timezone & 127); /* * Ok, that was the time zone as read from the PDU. Now how to interpert it? * All the handsets I tested send the timestamp of their local time and the * timezone as GMT+0. I assume that the timestamp is the handset's local time, * so we need to apply the timezone in reverse to get GM time: */ /* * time in PDU is handset's local time and timezone is handset's time zone * difference from GMT */ mtime.hour -= timezone / 4; mtime.minute -= 15 * (timezone % 4); stime = date_convert_universal(&mtime); /* get data length */ len = octstr_get_char(pdu, pos); pos++; /* if there is a UDH */ udhlen = 0; if (udhi) { udhlen = octstr_get_char(pdu, pos); pos++; udh = octstr_copy(pdu, pos, udhlen); pos += udhlen; len -= udhlen + 1; } /* build the message */ message = msg_create(sms); if (!dcs_to_fields(&message, dcs)) { /* XXX Should reject this message? */ debug("bb.smsc.at2", 0, "AT2[%s]: Invalid DCS", octstr_get_cstr(privdata->name)); dcs_to_fields(&message, 0); } 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 *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(octstr_get_cstr(privdata->conn->id), octstr_get_cstr(msg_id), octstr_get_cstr(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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -